Merge branch 'benchmark-verbosity' into direct-calls
diff --git a/BUILD b/BUILD
index b7044c5..61cb622 100644
--- a/BUILD
+++ b/BUILD
@@ -36,6 +36,8 @@
 
 licenses(["notice"])  # 3-clause BSD
 
+exports_files(["LICENSE"])
+
 package(default_visibility = ["//visibility:public"])
 
 
@@ -49,6 +51,7 @@
     "src/core/lib/support/backoff.h",
     "src/core/lib/support/block_annotate.h",
     "src/core/lib/support/env.h",
+    "src/core/lib/support/mpscq.h",
     "src/core/lib/support/murmur_hash.h",
     "src/core/lib/support/stack_lockfree.h",
     "src/core/lib/support/string.h",
@@ -76,6 +79,7 @@
     "src/core/lib/support/log_linux.c",
     "src/core/lib/support/log_posix.c",
     "src/core/lib/support/log_windows.c",
+    "src/core/lib/support/mpscq.c",
     "src/core/lib/support/murmur_hash.c",
     "src/core/lib/support/slice.c",
     "src/core/lib/support/slice_buffer.c",
@@ -175,6 +179,7 @@
     "src/core/lib/http/httpcli.h",
     "src/core/lib/http/parser.h",
     "src/core/lib/iomgr/closure.h",
+    "src/core/lib/iomgr/combiner.h",
     "src/core/lib/iomgr/endpoint.h",
     "src/core/lib/iomgr/endpoint_pair.h",
     "src/core/lib/iomgr/error.h",
@@ -286,7 +291,6 @@
     "src/core/lib/tsi/transport_security_interface.h",
     "src/core/ext/client_config/client_channel.h",
     "src/core/ext/client_config/client_channel_factory.h",
-    "src/core/ext/client_config/client_config.h",
     "src/core/ext/client_config/connector.h",
     "src/core/ext/client_config/initial_connect_string.h",
     "src/core/ext/client_config/lb_policy.h",
@@ -296,8 +300,8 @@
     "src/core/ext/client_config/resolver.h",
     "src/core/ext/client_config/resolver_factory.h",
     "src/core/ext/client_config/resolver_registry.h",
+    "src/core/ext/client_config/resolver_result.h",
     "src/core/ext/client_config/subchannel.h",
-    "src/core/ext/client_config/subchannel_call_holder.h",
     "src/core/ext/client_config/subchannel_index.h",
     "src/core/ext/client_config/uri_parser.h",
     "src/core/ext/lb_policy/grpclb/grpclb.h",
@@ -310,6 +314,7 @@
     "src/core/ext/census/census_interface.h",
     "src/core/ext/census/census_rpc_stats.h",
     "src/core/ext/census/gen/census.pb.h",
+    "src/core/ext/census/gen/trace_context.pb.h",
     "src/core/ext/census/grpc_filter.h",
     "src/core/ext/census/mlog.h",
     "src/core/ext/census/resource.h",
@@ -330,6 +335,7 @@
     "src/core/lib/http/httpcli.c",
     "src/core/lib/http/parser.c",
     "src/core/lib/iomgr/closure.c",
+    "src/core/lib/iomgr/combiner.c",
     "src/core/lib/iomgr/endpoint.c",
     "src/core/lib/iomgr/endpoint_pair_posix.c",
     "src/core/lib/iomgr/endpoint_pair_windows.c",
@@ -459,7 +465,6 @@
     "src/core/ext/client_config/channel_connectivity.c",
     "src/core/ext/client_config/client_channel.c",
     "src/core/ext/client_config/client_channel_factory.c",
-    "src/core/ext/client_config/client_config.c",
     "src/core/ext/client_config/client_config_plugin.c",
     "src/core/ext/client_config/connector.c",
     "src/core/ext/client_config/default_initial_connect_string.c",
@@ -471,8 +476,8 @@
     "src/core/ext/client_config/resolver.c",
     "src/core/ext/client_config/resolver_factory.c",
     "src/core/ext/client_config/resolver_registry.c",
+    "src/core/ext/client_config/resolver_result.c",
     "src/core/ext/client_config/subchannel.c",
-    "src/core/ext/client_config/subchannel_call_holder.c",
     "src/core/ext/client_config/subchannel_index.c",
     "src/core/ext/client_config/uri_parser.c",
     "src/core/ext/transport/chttp2/server/insecure/server_chttp2.c",
@@ -491,6 +496,7 @@
     "src/core/ext/census/base_resources.c",
     "src/core/ext/census/context.c",
     "src/core/ext/census/gen/census.pb.c",
+    "src/core/ext/census/gen/trace_context.pb.c",
     "src/core/ext/census/grpc_context.c",
     "src/core/ext/census/grpc_filter.c",
     "src/core/ext/census/grpc_plugin.c",
@@ -508,6 +514,7 @@
     "include/grpc/compression.h",
     "include/grpc/grpc.h",
     "include/grpc/grpc_posix.h",
+    "include/grpc/grpc_security_constants.h",
     "include/grpc/status.h",
     "include/grpc/impl/codegen/byte_buffer.h",
     "include/grpc/impl/codegen/byte_buffer_reader.h",
@@ -531,7 +538,6 @@
     "include/grpc/impl/codegen/sync_windows.h",
     "include/grpc/impl/codegen/time.h",
     "include/grpc/grpc_security.h",
-    "include/grpc/grpc_security_constants.h",
     "include/grpc/census.h",
   ],
   includes = [
@@ -570,6 +576,7 @@
     "src/core/lib/http/httpcli.h",
     "src/core/lib/http/parser.h",
     "src/core/lib/iomgr/closure.h",
+    "src/core/lib/iomgr/combiner.h",
     "src/core/lib/iomgr/endpoint.h",
     "src/core/lib/iomgr/endpoint_pair.h",
     "src/core/lib/iomgr/error.h",
@@ -658,7 +665,6 @@
     "src/core/ext/transport/chttp2/alpn/alpn.h",
     "src/core/ext/client_config/client_channel.h",
     "src/core/ext/client_config/client_channel_factory.h",
-    "src/core/ext/client_config/client_config.h",
     "src/core/ext/client_config/connector.h",
     "src/core/ext/client_config/initial_connect_string.h",
     "src/core/ext/client_config/lb_policy.h",
@@ -668,8 +674,8 @@
     "src/core/ext/client_config/resolver.h",
     "src/core/ext/client_config/resolver_factory.h",
     "src/core/ext/client_config/resolver_registry.h",
+    "src/core/ext/client_config/resolver_result.h",
     "src/core/ext/client_config/subchannel.h",
-    "src/core/ext/client_config/subchannel_call_holder.h",
     "src/core/ext/client_config/subchannel_index.h",
     "src/core/ext/client_config/uri_parser.h",
     "src/core/lib/security/context/security_context.h",
@@ -712,6 +718,7 @@
     "src/core/lib/http/httpcli.c",
     "src/core/lib/http/parser.c",
     "src/core/lib/iomgr/closure.c",
+    "src/core/lib/iomgr/combiner.c",
     "src/core/lib/iomgr/endpoint.c",
     "src/core/lib/iomgr/endpoint_pair_posix.c",
     "src/core/lib/iomgr/endpoint_pair_windows.c",
@@ -815,7 +822,6 @@
     "src/core/ext/client_config/channel_connectivity.c",
     "src/core/ext/client_config/client_channel.c",
     "src/core/ext/client_config/client_channel_factory.c",
-    "src/core/ext/client_config/client_config.c",
     "src/core/ext/client_config/client_config_plugin.c",
     "src/core/ext/client_config/connector.c",
     "src/core/ext/client_config/default_initial_connect_string.c",
@@ -827,8 +833,8 @@
     "src/core/ext/client_config/resolver.c",
     "src/core/ext/client_config/resolver_factory.c",
     "src/core/ext/client_config/resolver_registry.c",
+    "src/core/ext/client_config/resolver_result.c",
     "src/core/ext/client_config/subchannel.c",
-    "src/core/ext/client_config/subchannel_call_holder.c",
     "src/core/ext/client_config/subchannel_index.c",
     "src/core/ext/client_config/uri_parser.c",
     "src/core/lib/http/httpcli_security_connector.c",
@@ -867,6 +873,7 @@
     "include/grpc/compression.h",
     "include/grpc/grpc.h",
     "include/grpc/grpc_posix.h",
+    "include/grpc/grpc_security_constants.h",
     "include/grpc/status.h",
     "include/grpc/impl/codegen/byte_buffer.h",
     "include/grpc/impl/codegen/byte_buffer_reader.h",
@@ -891,7 +898,6 @@
     "include/grpc/impl/codegen/time.h",
     "include/grpc/grpc_cronet.h",
     "include/grpc/grpc_security.h",
-    "include/grpc/grpc_security_constants.h",
   ],
   includes = [
     "include",
@@ -924,6 +930,7 @@
     "src/core/lib/http/httpcli.h",
     "src/core/lib/http/parser.h",
     "src/core/lib/iomgr/closure.h",
+    "src/core/lib/iomgr/combiner.h",
     "src/core/lib/iomgr/endpoint.h",
     "src/core/lib/iomgr/endpoint_pair.h",
     "src/core/lib/iomgr/error.h",
@@ -1011,7 +1018,6 @@
     "src/core/ext/transport/chttp2/alpn/alpn.h",
     "src/core/ext/client_config/client_channel.h",
     "src/core/ext/client_config/client_channel_factory.h",
-    "src/core/ext/client_config/client_config.h",
     "src/core/ext/client_config/connector.h",
     "src/core/ext/client_config/initial_connect_string.h",
     "src/core/ext/client_config/lb_policy.h",
@@ -1021,8 +1027,8 @@
     "src/core/ext/client_config/resolver.h",
     "src/core/ext/client_config/resolver_factory.h",
     "src/core/ext/client_config/resolver_registry.h",
+    "src/core/ext/client_config/resolver_result.h",
     "src/core/ext/client_config/subchannel.h",
-    "src/core/ext/client_config/subchannel_call_holder.h",
     "src/core/ext/client_config/subchannel_index.h",
     "src/core/ext/client_config/uri_parser.h",
     "src/core/ext/load_reporting/load_reporting.h",
@@ -1035,6 +1041,7 @@
     "src/core/ext/census/census_interface.h",
     "src/core/ext/census/census_rpc_stats.h",
     "src/core/ext/census/gen/census.pb.h",
+    "src/core/ext/census/gen/trace_context.pb.h",
     "src/core/ext/census/grpc_filter.h",
     "src/core/ext/census/mlog.h",
     "src/core/ext/census/resource.h",
@@ -1056,6 +1063,7 @@
     "src/core/lib/http/httpcli.c",
     "src/core/lib/http/parser.c",
     "src/core/lib/iomgr/closure.c",
+    "src/core/lib/iomgr/combiner.c",
     "src/core/lib/iomgr/endpoint.c",
     "src/core/lib/iomgr/endpoint_pair_posix.c",
     "src/core/lib/iomgr/endpoint_pair_windows.c",
@@ -1159,7 +1167,6 @@
     "src/core/ext/client_config/channel_connectivity.c",
     "src/core/ext/client_config/client_channel.c",
     "src/core/ext/client_config/client_channel_factory.c",
-    "src/core/ext/client_config/client_config.c",
     "src/core/ext/client_config/client_config_plugin.c",
     "src/core/ext/client_config/connector.c",
     "src/core/ext/client_config/default_initial_connect_string.c",
@@ -1171,8 +1178,8 @@
     "src/core/ext/client_config/resolver.c",
     "src/core/ext/client_config/resolver_factory.c",
     "src/core/ext/client_config/resolver_registry.c",
+    "src/core/ext/client_config/resolver_result.c",
     "src/core/ext/client_config/subchannel.c",
-    "src/core/ext/client_config/subchannel_call_holder.c",
     "src/core/ext/client_config/subchannel_index.c",
     "src/core/ext/client_config/uri_parser.c",
     "src/core/ext/resolver/dns/native/dns_resolver.c",
@@ -1187,6 +1194,7 @@
     "src/core/ext/census/base_resources.c",
     "src/core/ext/census/context.c",
     "src/core/ext/census/gen/census.pb.c",
+    "src/core/ext/census/gen/trace_context.pb.c",
     "src/core/ext/census/grpc_context.c",
     "src/core/ext/census/grpc_filter.c",
     "src/core/ext/census/grpc_plugin.c",
@@ -1204,6 +1212,7 @@
     "include/grpc/compression.h",
     "include/grpc/grpc.h",
     "include/grpc/grpc_posix.h",
+    "include/grpc/grpc_security_constants.h",
     "include/grpc/status.h",
     "include/grpc/impl/codegen/byte_buffer.h",
     "include/grpc/impl/codegen/byte_buffer_reader.h",
@@ -1254,6 +1263,86 @@
     "src/cpp/common/channel_filter.h",
     "src/cpp/server/dynamic_thread_pool.h",
     "src/cpp/server/thread_pool_interface.h",
+    "src/core/lib/channel/channel_args.h",
+    "src/core/lib/channel/channel_stack.h",
+    "src/core/lib/channel/channel_stack_builder.h",
+    "src/core/lib/channel/compress_filter.h",
+    "src/core/lib/channel/connected_channel.h",
+    "src/core/lib/channel/context.h",
+    "src/core/lib/channel/handshaker.h",
+    "src/core/lib/channel/http_client_filter.h",
+    "src/core/lib/channel/http_server_filter.h",
+    "src/core/lib/compression/algorithm_metadata.h",
+    "src/core/lib/compression/message_compress.h",
+    "src/core/lib/debug/trace.h",
+    "src/core/lib/http/format_request.h",
+    "src/core/lib/http/httpcli.h",
+    "src/core/lib/http/parser.h",
+    "src/core/lib/iomgr/closure.h",
+    "src/core/lib/iomgr/endpoint.h",
+    "src/core/lib/iomgr/endpoint_pair.h",
+    "src/core/lib/iomgr/error.h",
+    "src/core/lib/iomgr/ev_epoll_linux.h",
+    "src/core/lib/iomgr/ev_poll_and_epoll_posix.h",
+    "src/core/lib/iomgr/ev_poll_posix.h",
+    "src/core/lib/iomgr/ev_posix.h",
+    "src/core/lib/iomgr/exec_ctx.h",
+    "src/core/lib/iomgr/executor.h",
+    "src/core/lib/iomgr/iocp_windows.h",
+    "src/core/lib/iomgr/iomgr.h",
+    "src/core/lib/iomgr/iomgr_internal.h",
+    "src/core/lib/iomgr/iomgr_posix.h",
+    "src/core/lib/iomgr/load_file.h",
+    "src/core/lib/iomgr/network_status_tracker.h",
+    "src/core/lib/iomgr/polling_entity.h",
+    "src/core/lib/iomgr/pollset.h",
+    "src/core/lib/iomgr/pollset_set.h",
+    "src/core/lib/iomgr/pollset_set_windows.h",
+    "src/core/lib/iomgr/pollset_windows.h",
+    "src/core/lib/iomgr/resolve_address.h",
+    "src/core/lib/iomgr/sockaddr.h",
+    "src/core/lib/iomgr/sockaddr_posix.h",
+    "src/core/lib/iomgr/sockaddr_utils.h",
+    "src/core/lib/iomgr/sockaddr_windows.h",
+    "src/core/lib/iomgr/socket_utils_posix.h",
+    "src/core/lib/iomgr/socket_windows.h",
+    "src/core/lib/iomgr/tcp_client.h",
+    "src/core/lib/iomgr/tcp_posix.h",
+    "src/core/lib/iomgr/tcp_server.h",
+    "src/core/lib/iomgr/tcp_windows.h",
+    "src/core/lib/iomgr/time_averaged_stats.h",
+    "src/core/lib/iomgr/timer.h",
+    "src/core/lib/iomgr/timer_heap.h",
+    "src/core/lib/iomgr/udp_server.h",
+    "src/core/lib/iomgr/unix_sockets_posix.h",
+    "src/core/lib/iomgr/wakeup_fd_pipe.h",
+    "src/core/lib/iomgr/wakeup_fd_posix.h",
+    "src/core/lib/iomgr/workqueue.h",
+    "src/core/lib/iomgr/workqueue_posix.h",
+    "src/core/lib/iomgr/workqueue_windows.h",
+    "src/core/lib/json/json.h",
+    "src/core/lib/json/json_common.h",
+    "src/core/lib/json/json_reader.h",
+    "src/core/lib/json/json_writer.h",
+    "src/core/lib/surface/api_trace.h",
+    "src/core/lib/surface/call.h",
+    "src/core/lib/surface/call_test_only.h",
+    "src/core/lib/surface/channel.h",
+    "src/core/lib/surface/channel_init.h",
+    "src/core/lib/surface/channel_stack_type.h",
+    "src/core/lib/surface/completion_queue.h",
+    "src/core/lib/surface/event_string.h",
+    "src/core/lib/surface/init.h",
+    "src/core/lib/surface/lame_client.h",
+    "src/core/lib/surface/server.h",
+    "src/core/lib/transport/byte_stream.h",
+    "src/core/lib/transport/connectivity_state.h",
+    "src/core/lib/transport/metadata.h",
+    "src/core/lib/transport/metadata_batch.h",
+    "src/core/lib/transport/static_metadata.h",
+    "src/core/lib/transport/timeout_encoding.h",
+    "src/core/lib/transport/transport.h",
+    "src/core/lib/transport/transport_impl.h",
     "src/cpp/client/secure_credentials.cc",
     "src/cpp/common/auth_property_iterator.cc",
     "src/cpp/common/secure_auth_context.cc",
@@ -1287,6 +1376,95 @@
     "src/cpp/util/status.cc",
     "src/cpp/util/string_ref.cc",
     "src/cpp/util/time.cc",
+    "src/core/lib/channel/channel_args.c",
+    "src/core/lib/channel/channel_stack.c",
+    "src/core/lib/channel/channel_stack_builder.c",
+    "src/core/lib/channel/compress_filter.c",
+    "src/core/lib/channel/connected_channel.c",
+    "src/core/lib/channel/handshaker.c",
+    "src/core/lib/channel/http_client_filter.c",
+    "src/core/lib/channel/http_server_filter.c",
+    "src/core/lib/compression/compression.c",
+    "src/core/lib/compression/message_compress.c",
+    "src/core/lib/debug/trace.c",
+    "src/core/lib/http/format_request.c",
+    "src/core/lib/http/httpcli.c",
+    "src/core/lib/http/parser.c",
+    "src/core/lib/iomgr/closure.c",
+    "src/core/lib/iomgr/endpoint.c",
+    "src/core/lib/iomgr/endpoint_pair_posix.c",
+    "src/core/lib/iomgr/endpoint_pair_windows.c",
+    "src/core/lib/iomgr/error.c",
+    "src/core/lib/iomgr/ev_epoll_linux.c",
+    "src/core/lib/iomgr/ev_poll_and_epoll_posix.c",
+    "src/core/lib/iomgr/ev_poll_posix.c",
+    "src/core/lib/iomgr/ev_posix.c",
+    "src/core/lib/iomgr/exec_ctx.c",
+    "src/core/lib/iomgr/executor.c",
+    "src/core/lib/iomgr/iocp_windows.c",
+    "src/core/lib/iomgr/iomgr.c",
+    "src/core/lib/iomgr/iomgr_posix.c",
+    "src/core/lib/iomgr/iomgr_windows.c",
+    "src/core/lib/iomgr/load_file.c",
+    "src/core/lib/iomgr/network_status_tracker.c",
+    "src/core/lib/iomgr/polling_entity.c",
+    "src/core/lib/iomgr/pollset_set_windows.c",
+    "src/core/lib/iomgr/pollset_windows.c",
+    "src/core/lib/iomgr/resolve_address_posix.c",
+    "src/core/lib/iomgr/resolve_address_windows.c",
+    "src/core/lib/iomgr/sockaddr_utils.c",
+    "src/core/lib/iomgr/socket_utils_common_posix.c",
+    "src/core/lib/iomgr/socket_utils_linux.c",
+    "src/core/lib/iomgr/socket_utils_posix.c",
+    "src/core/lib/iomgr/socket_windows.c",
+    "src/core/lib/iomgr/tcp_client_posix.c",
+    "src/core/lib/iomgr/tcp_client_windows.c",
+    "src/core/lib/iomgr/tcp_posix.c",
+    "src/core/lib/iomgr/tcp_server_posix.c",
+    "src/core/lib/iomgr/tcp_server_windows.c",
+    "src/core/lib/iomgr/tcp_windows.c",
+    "src/core/lib/iomgr/time_averaged_stats.c",
+    "src/core/lib/iomgr/timer.c",
+    "src/core/lib/iomgr/timer_heap.c",
+    "src/core/lib/iomgr/udp_server.c",
+    "src/core/lib/iomgr/unix_sockets_posix.c",
+    "src/core/lib/iomgr/unix_sockets_posix_noop.c",
+    "src/core/lib/iomgr/wakeup_fd_eventfd.c",
+    "src/core/lib/iomgr/wakeup_fd_nospecial.c",
+    "src/core/lib/iomgr/wakeup_fd_pipe.c",
+    "src/core/lib/iomgr/wakeup_fd_posix.c",
+    "src/core/lib/iomgr/workqueue_posix.c",
+    "src/core/lib/iomgr/workqueue_windows.c",
+    "src/core/lib/json/json.c",
+    "src/core/lib/json/json_reader.c",
+    "src/core/lib/json/json_string.c",
+    "src/core/lib/json/json_writer.c",
+    "src/core/lib/surface/alarm.c",
+    "src/core/lib/surface/api_trace.c",
+    "src/core/lib/surface/byte_buffer.c",
+    "src/core/lib/surface/byte_buffer_reader.c",
+    "src/core/lib/surface/call.c",
+    "src/core/lib/surface/call_details.c",
+    "src/core/lib/surface/call_log_batch.c",
+    "src/core/lib/surface/channel.c",
+    "src/core/lib/surface/channel_init.c",
+    "src/core/lib/surface/channel_ping.c",
+    "src/core/lib/surface/channel_stack_type.c",
+    "src/core/lib/surface/completion_queue.c",
+    "src/core/lib/surface/event_string.c",
+    "src/core/lib/surface/lame_client.c",
+    "src/core/lib/surface/metadata_array.c",
+    "src/core/lib/surface/server.c",
+    "src/core/lib/surface/validate_metadata.c",
+    "src/core/lib/surface/version.c",
+    "src/core/lib/transport/byte_stream.c",
+    "src/core/lib/transport/connectivity_state.c",
+    "src/core/lib/transport/metadata.c",
+    "src/core/lib/transport/metadata_batch.c",
+    "src/core/lib/transport/static_metadata.c",
+    "src/core/lib/transport/timeout_encoding.c",
+    "src/core/lib/transport/transport.c",
+    "src/core/lib/transport/transport_op_string.c",
     "src/cpp/codegen/codegen_init.cc",
   ],
   hdrs = [
@@ -1337,6 +1515,34 @@
     "include/grpc++/support/stub_options.h",
     "include/grpc++/support/sync_stream.h",
     "include/grpc++/support/time.h",
+    "include/grpc/byte_buffer.h",
+    "include/grpc/byte_buffer_reader.h",
+    "include/grpc/compression.h",
+    "include/grpc/grpc.h",
+    "include/grpc/grpc_posix.h",
+    "include/grpc/grpc_security_constants.h",
+    "include/grpc/status.h",
+    "include/grpc/impl/codegen/byte_buffer.h",
+    "include/grpc/impl/codegen/byte_buffer_reader.h",
+    "include/grpc/impl/codegen/compression_types.h",
+    "include/grpc/impl/codegen/connectivity_state.h",
+    "include/grpc/impl/codegen/grpc_types.h",
+    "include/grpc/impl/codegen/propagation_bits.h",
+    "include/grpc/impl/codegen/status.h",
+    "include/grpc/impl/codegen/alloc.h",
+    "include/grpc/impl/codegen/atm.h",
+    "include/grpc/impl/codegen/atm_gcc_atomic.h",
+    "include/grpc/impl/codegen/atm_gcc_sync.h",
+    "include/grpc/impl/codegen/atm_windows.h",
+    "include/grpc/impl/codegen/log.h",
+    "include/grpc/impl/codegen/port_platform.h",
+    "include/grpc/impl/codegen/slice.h",
+    "include/grpc/impl/codegen/slice_buffer.h",
+    "include/grpc/impl/codegen/sync.h",
+    "include/grpc/impl/codegen/sync_generic.h",
+    "include/grpc/impl/codegen/sync_posix.h",
+    "include/grpc/impl/codegen/sync_windows.h",
+    "include/grpc/impl/codegen/time.h",
     "include/grpc++/impl/codegen/async_stream.h",
     "include/grpc++/impl/codegen/async_unary_call.h",
     "include/grpc++/impl/codegen/call.h",
@@ -1367,27 +1573,6 @@
     "include/grpc++/impl/codegen/sync_no_cxx11.h",
     "include/grpc++/impl/codegen/sync_stream.h",
     "include/grpc++/impl/codegen/time.h",
-    "include/grpc/impl/codegen/byte_buffer.h",
-    "include/grpc/impl/codegen/byte_buffer_reader.h",
-    "include/grpc/impl/codegen/compression_types.h",
-    "include/grpc/impl/codegen/connectivity_state.h",
-    "include/grpc/impl/codegen/grpc_types.h",
-    "include/grpc/impl/codegen/propagation_bits.h",
-    "include/grpc/impl/codegen/status.h",
-    "include/grpc/impl/codegen/alloc.h",
-    "include/grpc/impl/codegen/atm.h",
-    "include/grpc/impl/codegen/atm_gcc_atomic.h",
-    "include/grpc/impl/codegen/atm_gcc_sync.h",
-    "include/grpc/impl/codegen/atm_windows.h",
-    "include/grpc/impl/codegen/log.h",
-    "include/grpc/impl/codegen/port_platform.h",
-    "include/grpc/impl/codegen/slice.h",
-    "include/grpc/impl/codegen/slice_buffer.h",
-    "include/grpc/impl/codegen/sync.h",
-    "include/grpc/impl/codegen/sync_generic.h",
-    "include/grpc/impl/codegen/sync_posix.h",
-    "include/grpc/impl/codegen/sync_windows.h",
-    "include/grpc/impl/codegen/time.h",
   ],
   includes = [
     "include",
@@ -1397,6 +1582,7 @@
     "//external:libssl",
     "//external:protobuf_clib",
     ":grpc",
+    ":gpr",
   ],
 )
 
@@ -1487,6 +1673,86 @@
     "src/cpp/common/channel_filter.h",
     "src/cpp/server/dynamic_thread_pool.h",
     "src/cpp/server/thread_pool_interface.h",
+    "src/core/lib/channel/channel_args.h",
+    "src/core/lib/channel/channel_stack.h",
+    "src/core/lib/channel/channel_stack_builder.h",
+    "src/core/lib/channel/compress_filter.h",
+    "src/core/lib/channel/connected_channel.h",
+    "src/core/lib/channel/context.h",
+    "src/core/lib/channel/handshaker.h",
+    "src/core/lib/channel/http_client_filter.h",
+    "src/core/lib/channel/http_server_filter.h",
+    "src/core/lib/compression/algorithm_metadata.h",
+    "src/core/lib/compression/message_compress.h",
+    "src/core/lib/debug/trace.h",
+    "src/core/lib/http/format_request.h",
+    "src/core/lib/http/httpcli.h",
+    "src/core/lib/http/parser.h",
+    "src/core/lib/iomgr/closure.h",
+    "src/core/lib/iomgr/endpoint.h",
+    "src/core/lib/iomgr/endpoint_pair.h",
+    "src/core/lib/iomgr/error.h",
+    "src/core/lib/iomgr/ev_epoll_linux.h",
+    "src/core/lib/iomgr/ev_poll_and_epoll_posix.h",
+    "src/core/lib/iomgr/ev_poll_posix.h",
+    "src/core/lib/iomgr/ev_posix.h",
+    "src/core/lib/iomgr/exec_ctx.h",
+    "src/core/lib/iomgr/executor.h",
+    "src/core/lib/iomgr/iocp_windows.h",
+    "src/core/lib/iomgr/iomgr.h",
+    "src/core/lib/iomgr/iomgr_internal.h",
+    "src/core/lib/iomgr/iomgr_posix.h",
+    "src/core/lib/iomgr/load_file.h",
+    "src/core/lib/iomgr/network_status_tracker.h",
+    "src/core/lib/iomgr/polling_entity.h",
+    "src/core/lib/iomgr/pollset.h",
+    "src/core/lib/iomgr/pollset_set.h",
+    "src/core/lib/iomgr/pollset_set_windows.h",
+    "src/core/lib/iomgr/pollset_windows.h",
+    "src/core/lib/iomgr/resolve_address.h",
+    "src/core/lib/iomgr/sockaddr.h",
+    "src/core/lib/iomgr/sockaddr_posix.h",
+    "src/core/lib/iomgr/sockaddr_utils.h",
+    "src/core/lib/iomgr/sockaddr_windows.h",
+    "src/core/lib/iomgr/socket_utils_posix.h",
+    "src/core/lib/iomgr/socket_windows.h",
+    "src/core/lib/iomgr/tcp_client.h",
+    "src/core/lib/iomgr/tcp_posix.h",
+    "src/core/lib/iomgr/tcp_server.h",
+    "src/core/lib/iomgr/tcp_windows.h",
+    "src/core/lib/iomgr/time_averaged_stats.h",
+    "src/core/lib/iomgr/timer.h",
+    "src/core/lib/iomgr/timer_heap.h",
+    "src/core/lib/iomgr/udp_server.h",
+    "src/core/lib/iomgr/unix_sockets_posix.h",
+    "src/core/lib/iomgr/wakeup_fd_pipe.h",
+    "src/core/lib/iomgr/wakeup_fd_posix.h",
+    "src/core/lib/iomgr/workqueue.h",
+    "src/core/lib/iomgr/workqueue_posix.h",
+    "src/core/lib/iomgr/workqueue_windows.h",
+    "src/core/lib/json/json.h",
+    "src/core/lib/json/json_common.h",
+    "src/core/lib/json/json_reader.h",
+    "src/core/lib/json/json_writer.h",
+    "src/core/lib/surface/api_trace.h",
+    "src/core/lib/surface/call.h",
+    "src/core/lib/surface/call_test_only.h",
+    "src/core/lib/surface/channel.h",
+    "src/core/lib/surface/channel_init.h",
+    "src/core/lib/surface/channel_stack_type.h",
+    "src/core/lib/surface/completion_queue.h",
+    "src/core/lib/surface/event_string.h",
+    "src/core/lib/surface/init.h",
+    "src/core/lib/surface/lame_client.h",
+    "src/core/lib/surface/server.h",
+    "src/core/lib/transport/byte_stream.h",
+    "src/core/lib/transport/connectivity_state.h",
+    "src/core/lib/transport/metadata.h",
+    "src/core/lib/transport/metadata_batch.h",
+    "src/core/lib/transport/static_metadata.h",
+    "src/core/lib/transport/timeout_encoding.h",
+    "src/core/lib/transport/transport.h",
+    "src/core/lib/transport/transport_impl.h",
     "src/cpp/common/insecure_create_auth_context.cc",
     "src/cpp/client/channel.cc",
     "src/cpp/client/client_context.cc",
@@ -1515,6 +1781,95 @@
     "src/cpp/util/status.cc",
     "src/cpp/util/string_ref.cc",
     "src/cpp/util/time.cc",
+    "src/core/lib/channel/channel_args.c",
+    "src/core/lib/channel/channel_stack.c",
+    "src/core/lib/channel/channel_stack_builder.c",
+    "src/core/lib/channel/compress_filter.c",
+    "src/core/lib/channel/connected_channel.c",
+    "src/core/lib/channel/handshaker.c",
+    "src/core/lib/channel/http_client_filter.c",
+    "src/core/lib/channel/http_server_filter.c",
+    "src/core/lib/compression/compression.c",
+    "src/core/lib/compression/message_compress.c",
+    "src/core/lib/debug/trace.c",
+    "src/core/lib/http/format_request.c",
+    "src/core/lib/http/httpcli.c",
+    "src/core/lib/http/parser.c",
+    "src/core/lib/iomgr/closure.c",
+    "src/core/lib/iomgr/endpoint.c",
+    "src/core/lib/iomgr/endpoint_pair_posix.c",
+    "src/core/lib/iomgr/endpoint_pair_windows.c",
+    "src/core/lib/iomgr/error.c",
+    "src/core/lib/iomgr/ev_epoll_linux.c",
+    "src/core/lib/iomgr/ev_poll_and_epoll_posix.c",
+    "src/core/lib/iomgr/ev_poll_posix.c",
+    "src/core/lib/iomgr/ev_posix.c",
+    "src/core/lib/iomgr/exec_ctx.c",
+    "src/core/lib/iomgr/executor.c",
+    "src/core/lib/iomgr/iocp_windows.c",
+    "src/core/lib/iomgr/iomgr.c",
+    "src/core/lib/iomgr/iomgr_posix.c",
+    "src/core/lib/iomgr/iomgr_windows.c",
+    "src/core/lib/iomgr/load_file.c",
+    "src/core/lib/iomgr/network_status_tracker.c",
+    "src/core/lib/iomgr/polling_entity.c",
+    "src/core/lib/iomgr/pollset_set_windows.c",
+    "src/core/lib/iomgr/pollset_windows.c",
+    "src/core/lib/iomgr/resolve_address_posix.c",
+    "src/core/lib/iomgr/resolve_address_windows.c",
+    "src/core/lib/iomgr/sockaddr_utils.c",
+    "src/core/lib/iomgr/socket_utils_common_posix.c",
+    "src/core/lib/iomgr/socket_utils_linux.c",
+    "src/core/lib/iomgr/socket_utils_posix.c",
+    "src/core/lib/iomgr/socket_windows.c",
+    "src/core/lib/iomgr/tcp_client_posix.c",
+    "src/core/lib/iomgr/tcp_client_windows.c",
+    "src/core/lib/iomgr/tcp_posix.c",
+    "src/core/lib/iomgr/tcp_server_posix.c",
+    "src/core/lib/iomgr/tcp_server_windows.c",
+    "src/core/lib/iomgr/tcp_windows.c",
+    "src/core/lib/iomgr/time_averaged_stats.c",
+    "src/core/lib/iomgr/timer.c",
+    "src/core/lib/iomgr/timer_heap.c",
+    "src/core/lib/iomgr/udp_server.c",
+    "src/core/lib/iomgr/unix_sockets_posix.c",
+    "src/core/lib/iomgr/unix_sockets_posix_noop.c",
+    "src/core/lib/iomgr/wakeup_fd_eventfd.c",
+    "src/core/lib/iomgr/wakeup_fd_nospecial.c",
+    "src/core/lib/iomgr/wakeup_fd_pipe.c",
+    "src/core/lib/iomgr/wakeup_fd_posix.c",
+    "src/core/lib/iomgr/workqueue_posix.c",
+    "src/core/lib/iomgr/workqueue_windows.c",
+    "src/core/lib/json/json.c",
+    "src/core/lib/json/json_reader.c",
+    "src/core/lib/json/json_string.c",
+    "src/core/lib/json/json_writer.c",
+    "src/core/lib/surface/alarm.c",
+    "src/core/lib/surface/api_trace.c",
+    "src/core/lib/surface/byte_buffer.c",
+    "src/core/lib/surface/byte_buffer_reader.c",
+    "src/core/lib/surface/call.c",
+    "src/core/lib/surface/call_details.c",
+    "src/core/lib/surface/call_log_batch.c",
+    "src/core/lib/surface/channel.c",
+    "src/core/lib/surface/channel_init.c",
+    "src/core/lib/surface/channel_ping.c",
+    "src/core/lib/surface/channel_stack_type.c",
+    "src/core/lib/surface/completion_queue.c",
+    "src/core/lib/surface/event_string.c",
+    "src/core/lib/surface/lame_client.c",
+    "src/core/lib/surface/metadata_array.c",
+    "src/core/lib/surface/server.c",
+    "src/core/lib/surface/validate_metadata.c",
+    "src/core/lib/surface/version.c",
+    "src/core/lib/transport/byte_stream.c",
+    "src/core/lib/transport/connectivity_state.c",
+    "src/core/lib/transport/metadata.c",
+    "src/core/lib/transport/metadata_batch.c",
+    "src/core/lib/transport/static_metadata.c",
+    "src/core/lib/transport/timeout_encoding.c",
+    "src/core/lib/transport/transport.c",
+    "src/core/lib/transport/transport_op_string.c",
     "src/cpp/codegen/codegen_init.cc",
   ],
   hdrs = [
@@ -1565,6 +1920,34 @@
     "include/grpc++/support/stub_options.h",
     "include/grpc++/support/sync_stream.h",
     "include/grpc++/support/time.h",
+    "include/grpc/byte_buffer.h",
+    "include/grpc/byte_buffer_reader.h",
+    "include/grpc/compression.h",
+    "include/grpc/grpc.h",
+    "include/grpc/grpc_posix.h",
+    "include/grpc/grpc_security_constants.h",
+    "include/grpc/status.h",
+    "include/grpc/impl/codegen/byte_buffer.h",
+    "include/grpc/impl/codegen/byte_buffer_reader.h",
+    "include/grpc/impl/codegen/compression_types.h",
+    "include/grpc/impl/codegen/connectivity_state.h",
+    "include/grpc/impl/codegen/grpc_types.h",
+    "include/grpc/impl/codegen/propagation_bits.h",
+    "include/grpc/impl/codegen/status.h",
+    "include/grpc/impl/codegen/alloc.h",
+    "include/grpc/impl/codegen/atm.h",
+    "include/grpc/impl/codegen/atm_gcc_atomic.h",
+    "include/grpc/impl/codegen/atm_gcc_sync.h",
+    "include/grpc/impl/codegen/atm_windows.h",
+    "include/grpc/impl/codegen/log.h",
+    "include/grpc/impl/codegen/port_platform.h",
+    "include/grpc/impl/codegen/slice.h",
+    "include/grpc/impl/codegen/slice_buffer.h",
+    "include/grpc/impl/codegen/sync.h",
+    "include/grpc/impl/codegen/sync_generic.h",
+    "include/grpc/impl/codegen/sync_posix.h",
+    "include/grpc/impl/codegen/sync_windows.h",
+    "include/grpc/impl/codegen/time.h",
     "include/grpc++/impl/codegen/async_stream.h",
     "include/grpc++/impl/codegen/async_unary_call.h",
     "include/grpc++/impl/codegen/call.h",
@@ -1595,27 +1978,6 @@
     "include/grpc++/impl/codegen/sync_no_cxx11.h",
     "include/grpc++/impl/codegen/sync_stream.h",
     "include/grpc++/impl/codegen/time.h",
-    "include/grpc/impl/codegen/byte_buffer.h",
-    "include/grpc/impl/codegen/byte_buffer_reader.h",
-    "include/grpc/impl/codegen/compression_types.h",
-    "include/grpc/impl/codegen/connectivity_state.h",
-    "include/grpc/impl/codegen/grpc_types.h",
-    "include/grpc/impl/codegen/propagation_bits.h",
-    "include/grpc/impl/codegen/status.h",
-    "include/grpc/impl/codegen/alloc.h",
-    "include/grpc/impl/codegen/atm.h",
-    "include/grpc/impl/codegen/atm_gcc_atomic.h",
-    "include/grpc/impl/codegen/atm_gcc_sync.h",
-    "include/grpc/impl/codegen/atm_windows.h",
-    "include/grpc/impl/codegen/log.h",
-    "include/grpc/impl/codegen/port_platform.h",
-    "include/grpc/impl/codegen/slice.h",
-    "include/grpc/impl/codegen/slice_buffer.h",
-    "include/grpc/impl/codegen/sync.h",
-    "include/grpc/impl/codegen/sync_generic.h",
-    "include/grpc/impl/codegen/sync_posix.h",
-    "include/grpc/impl/codegen/sync_windows.h",
-    "include/grpc/impl/codegen/time.h",
   ],
   includes = [
     "include",
@@ -1625,7 +1987,6 @@
     "//external:protobuf_clib",
     ":gpr",
     ":grpc_unsecure",
-    ":grpc",
   ],
 )
 
@@ -1713,6 +2074,7 @@
     "src/core/lib/support/log_linux.c",
     "src/core/lib/support/log_posix.c",
     "src/core/lib/support/log_windows.c",
+    "src/core/lib/support/mpscq.c",
     "src/core/lib/support/murmur_hash.c",
     "src/core/lib/support/slice.c",
     "src/core/lib/support/slice_buffer.c",
@@ -1786,6 +2148,7 @@
     "src/core/lib/support/backoff.h",
     "src/core/lib/support/block_annotate.h",
     "src/core/lib/support/env.h",
+    "src/core/lib/support/mpscq.h",
     "src/core/lib/support/murmur_hash.h",
     "src/core/lib/support/stack_lockfree.h",
     "src/core/lib/support/string.h",
@@ -1823,6 +2186,7 @@
     "src/core/lib/http/httpcli.c",
     "src/core/lib/http/parser.c",
     "src/core/lib/iomgr/closure.c",
+    "src/core/lib/iomgr/combiner.c",
     "src/core/lib/iomgr/endpoint.c",
     "src/core/lib/iomgr/endpoint_pair_posix.c",
     "src/core/lib/iomgr/endpoint_pair_windows.c",
@@ -1952,7 +2316,6 @@
     "src/core/ext/client_config/channel_connectivity.c",
     "src/core/ext/client_config/client_channel.c",
     "src/core/ext/client_config/client_channel_factory.c",
-    "src/core/ext/client_config/client_config.c",
     "src/core/ext/client_config/client_config_plugin.c",
     "src/core/ext/client_config/connector.c",
     "src/core/ext/client_config/default_initial_connect_string.c",
@@ -1964,8 +2327,8 @@
     "src/core/ext/client_config/resolver.c",
     "src/core/ext/client_config/resolver_factory.c",
     "src/core/ext/client_config/resolver_registry.c",
+    "src/core/ext/client_config/resolver_result.c",
     "src/core/ext/client_config/subchannel.c",
-    "src/core/ext/client_config/subchannel_call_holder.c",
     "src/core/ext/client_config/subchannel_index.c",
     "src/core/ext/client_config/uri_parser.c",
     "src/core/ext/transport/chttp2/server/insecure/server_chttp2.c",
@@ -1984,6 +2347,7 @@
     "src/core/ext/census/base_resources.c",
     "src/core/ext/census/context.c",
     "src/core/ext/census/gen/census.pb.c",
+    "src/core/ext/census/gen/trace_context.pb.c",
     "src/core/ext/census/grpc_context.c",
     "src/core/ext/census/grpc_filter.c",
     "src/core/ext/census/grpc_plugin.c",
@@ -2001,6 +2365,7 @@
     "include/grpc/compression.h",
     "include/grpc/grpc.h",
     "include/grpc/grpc_posix.h",
+    "include/grpc/grpc_security_constants.h",
     "include/grpc/status.h",
     "include/grpc/impl/codegen/byte_buffer.h",
     "include/grpc/impl/codegen/byte_buffer_reader.h",
@@ -2024,7 +2389,6 @@
     "include/grpc/impl/codegen/sync_windows.h",
     "include/grpc/impl/codegen/time.h",
     "include/grpc/grpc_security.h",
-    "include/grpc/grpc_security_constants.h",
     "include/grpc/census.h",
     "src/core/lib/channel/channel_args.h",
     "src/core/lib/channel/channel_stack.h",
@@ -2042,6 +2406,7 @@
     "src/core/lib/http/httpcli.h",
     "src/core/lib/http/parser.h",
     "src/core/lib/iomgr/closure.h",
+    "src/core/lib/iomgr/combiner.h",
     "src/core/lib/iomgr/endpoint.h",
     "src/core/lib/iomgr/endpoint_pair.h",
     "src/core/lib/iomgr/error.h",
@@ -2153,7 +2518,6 @@
     "src/core/lib/tsi/transport_security_interface.h",
     "src/core/ext/client_config/client_channel.h",
     "src/core/ext/client_config/client_channel_factory.h",
-    "src/core/ext/client_config/client_config.h",
     "src/core/ext/client_config/connector.h",
     "src/core/ext/client_config/initial_connect_string.h",
     "src/core/ext/client_config/lb_policy.h",
@@ -2163,8 +2527,8 @@
     "src/core/ext/client_config/resolver.h",
     "src/core/ext/client_config/resolver_factory.h",
     "src/core/ext/client_config/resolver_registry.h",
+    "src/core/ext/client_config/resolver_result.h",
     "src/core/ext/client_config/subchannel.h",
-    "src/core/ext/client_config/subchannel_call_holder.h",
     "src/core/ext/client_config/subchannel_index.h",
     "src/core/ext/client_config/uri_parser.h",
     "src/core/ext/lb_policy/grpclb/grpclb.h",
@@ -2177,6 +2541,7 @@
     "src/core/ext/census/census_interface.h",
     "src/core/ext/census/census_rpc_stats.h",
     "src/core/ext/census/gen/census.pb.h",
+    "src/core/ext/census/gen/trace_context.pb.h",
     "src/core/ext/census/grpc_filter.h",
     "src/core/ext/census/mlog.h",
     "src/core/ext/census/resource.h",
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 5754e6f..a0d174a 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -191,6 +191,7 @@
   src/core/lib/support/log_linux.c
   src/core/lib/support/log_posix.c
   src/core/lib/support/log_windows.c
+  src/core/lib/support/mpscq.c
   src/core/lib/support/murmur_hash.c
   src/core/lib/support/slice.c
   src/core/lib/support/slice_buffer.c
@@ -306,6 +307,7 @@
   src/core/lib/http/httpcli.c
   src/core/lib/http/parser.c
   src/core/lib/iomgr/closure.c
+  src/core/lib/iomgr/combiner.c
   src/core/lib/iomgr/endpoint.c
   src/core/lib/iomgr/endpoint_pair_posix.c
   src/core/lib/iomgr/endpoint_pair_windows.c
@@ -435,7 +437,6 @@
   src/core/ext/client_config/channel_connectivity.c
   src/core/ext/client_config/client_channel.c
   src/core/ext/client_config/client_channel_factory.c
-  src/core/ext/client_config/client_config.c
   src/core/ext/client_config/client_config_plugin.c
   src/core/ext/client_config/connector.c
   src/core/ext/client_config/default_initial_connect_string.c
@@ -447,8 +448,8 @@
   src/core/ext/client_config/resolver.c
   src/core/ext/client_config/resolver_factory.c
   src/core/ext/client_config/resolver_registry.c
+  src/core/ext/client_config/resolver_result.c
   src/core/ext/client_config/subchannel.c
-  src/core/ext/client_config/subchannel_call_holder.c
   src/core/ext/client_config/subchannel_index.c
   src/core/ext/client_config/uri_parser.c
   src/core/ext/transport/chttp2/server/insecure/server_chttp2.c
@@ -470,6 +471,7 @@
   src/core/ext/census/base_resources.c
   src/core/ext/census/context.c
   src/core/ext/census/gen/census.pb.c
+  src/core/ext/census/gen/trace_context.pb.c
   src/core/ext/census/grpc_context.c
   src/core/ext/census/grpc_filter.c
   src/core/ext/census/grpc_plugin.c
@@ -504,6 +506,7 @@
   include/grpc/compression.h
   include/grpc/grpc.h
   include/grpc/grpc_posix.h
+  include/grpc/grpc_security_constants.h
   include/grpc/status.h
   include/grpc/impl/codegen/byte_buffer.h
   include/grpc/impl/codegen/byte_buffer_reader.h
@@ -527,7 +530,6 @@
   include/grpc/impl/codegen/sync_windows.h
   include/grpc/impl/codegen/time.h
   include/grpc/grpc_security.h
-  include/grpc/grpc_security_constants.h
   include/grpc/census.h
 )
   string(REPLACE "include/" "" _path ${_hdr})
@@ -564,6 +566,7 @@
   src/core/lib/http/httpcli.c
   src/core/lib/http/parser.c
   src/core/lib/iomgr/closure.c
+  src/core/lib/iomgr/combiner.c
   src/core/lib/iomgr/endpoint.c
   src/core/lib/iomgr/endpoint_pair_posix.c
   src/core/lib/iomgr/endpoint_pair_windows.c
@@ -667,7 +670,6 @@
   src/core/ext/client_config/channel_connectivity.c
   src/core/ext/client_config/client_channel.c
   src/core/ext/client_config/client_channel_factory.c
-  src/core/ext/client_config/client_config.c
   src/core/ext/client_config/client_config_plugin.c
   src/core/ext/client_config/connector.c
   src/core/ext/client_config/default_initial_connect_string.c
@@ -679,8 +681,8 @@
   src/core/ext/client_config/resolver.c
   src/core/ext/client_config/resolver_factory.c
   src/core/ext/client_config/resolver_registry.c
+  src/core/ext/client_config/resolver_result.c
   src/core/ext/client_config/subchannel.c
-  src/core/ext/client_config/subchannel_call_holder.c
   src/core/ext/client_config/subchannel_index.c
   src/core/ext/client_config/uri_parser.c
   src/core/lib/http/httpcli_security_connector.c
@@ -735,6 +737,7 @@
   include/grpc/compression.h
   include/grpc/grpc.h
   include/grpc/grpc_posix.h
+  include/grpc/grpc_security_constants.h
   include/grpc/status.h
   include/grpc/impl/codegen/byte_buffer.h
   include/grpc/impl/codegen/byte_buffer_reader.h
@@ -759,7 +762,6 @@
   include/grpc/impl/codegen/time.h
   include/grpc/grpc_cronet.h
   include/grpc/grpc_security.h
-  include/grpc/grpc_security_constants.h
 )
   string(REPLACE "include/" "" _path ${_hdr})
   get_filename_component(_path ${_path} PATH)
@@ -796,6 +798,7 @@
   src/core/lib/http/httpcli.c
   src/core/lib/http/parser.c
   src/core/lib/iomgr/closure.c
+  src/core/lib/iomgr/combiner.c
   src/core/lib/iomgr/endpoint.c
   src/core/lib/iomgr/endpoint_pair_posix.c
   src/core/lib/iomgr/endpoint_pair_windows.c
@@ -899,7 +902,6 @@
   src/core/ext/client_config/channel_connectivity.c
   src/core/ext/client_config/client_channel.c
   src/core/ext/client_config/client_channel_factory.c
-  src/core/ext/client_config/client_config.c
   src/core/ext/client_config/client_config_plugin.c
   src/core/ext/client_config/connector.c
   src/core/ext/client_config/default_initial_connect_string.c
@@ -911,8 +913,8 @@
   src/core/ext/client_config/resolver.c
   src/core/ext/client_config/resolver_factory.c
   src/core/ext/client_config/resolver_registry.c
+  src/core/ext/client_config/resolver_result.c
   src/core/ext/client_config/subchannel.c
-  src/core/ext/client_config/subchannel_call_holder.c
   src/core/ext/client_config/subchannel_index.c
   src/core/ext/client_config/uri_parser.c
   src/core/ext/resolver/dns/native/dns_resolver.c
@@ -930,6 +932,7 @@
   src/core/ext/census/base_resources.c
   src/core/ext/census/context.c
   src/core/ext/census/gen/census.pb.c
+  src/core/ext/census/gen/trace_context.pb.c
   src/core/ext/census/grpc_context.c
   src/core/ext/census/grpc_filter.c
   src/core/ext/census/grpc_plugin.c
@@ -962,6 +965,7 @@
   include/grpc/compression.h
   include/grpc/grpc.h
   include/grpc/grpc_posix.h
+  include/grpc/grpc_security_constants.h
   include/grpc/status.h
   include/grpc/impl/codegen/byte_buffer.h
   include/grpc/impl/codegen/byte_buffer_reader.h
@@ -1037,6 +1041,95 @@
   src/cpp/util/status.cc
   src/cpp/util/string_ref.cc
   src/cpp/util/time.cc
+  src/core/lib/channel/channel_args.c
+  src/core/lib/channel/channel_stack.c
+  src/core/lib/channel/channel_stack_builder.c
+  src/core/lib/channel/compress_filter.c
+  src/core/lib/channel/connected_channel.c
+  src/core/lib/channel/handshaker.c
+  src/core/lib/channel/http_client_filter.c
+  src/core/lib/channel/http_server_filter.c
+  src/core/lib/compression/compression.c
+  src/core/lib/compression/message_compress.c
+  src/core/lib/debug/trace.c
+  src/core/lib/http/format_request.c
+  src/core/lib/http/httpcli.c
+  src/core/lib/http/parser.c
+  src/core/lib/iomgr/closure.c
+  src/core/lib/iomgr/endpoint.c
+  src/core/lib/iomgr/endpoint_pair_posix.c
+  src/core/lib/iomgr/endpoint_pair_windows.c
+  src/core/lib/iomgr/error.c
+  src/core/lib/iomgr/ev_epoll_linux.c
+  src/core/lib/iomgr/ev_poll_and_epoll_posix.c
+  src/core/lib/iomgr/ev_poll_posix.c
+  src/core/lib/iomgr/ev_posix.c
+  src/core/lib/iomgr/exec_ctx.c
+  src/core/lib/iomgr/executor.c
+  src/core/lib/iomgr/iocp_windows.c
+  src/core/lib/iomgr/iomgr.c
+  src/core/lib/iomgr/iomgr_posix.c
+  src/core/lib/iomgr/iomgr_windows.c
+  src/core/lib/iomgr/load_file.c
+  src/core/lib/iomgr/network_status_tracker.c
+  src/core/lib/iomgr/polling_entity.c
+  src/core/lib/iomgr/pollset_set_windows.c
+  src/core/lib/iomgr/pollset_windows.c
+  src/core/lib/iomgr/resolve_address_posix.c
+  src/core/lib/iomgr/resolve_address_windows.c
+  src/core/lib/iomgr/sockaddr_utils.c
+  src/core/lib/iomgr/socket_utils_common_posix.c
+  src/core/lib/iomgr/socket_utils_linux.c
+  src/core/lib/iomgr/socket_utils_posix.c
+  src/core/lib/iomgr/socket_windows.c
+  src/core/lib/iomgr/tcp_client_posix.c
+  src/core/lib/iomgr/tcp_client_windows.c
+  src/core/lib/iomgr/tcp_posix.c
+  src/core/lib/iomgr/tcp_server_posix.c
+  src/core/lib/iomgr/tcp_server_windows.c
+  src/core/lib/iomgr/tcp_windows.c
+  src/core/lib/iomgr/time_averaged_stats.c
+  src/core/lib/iomgr/timer.c
+  src/core/lib/iomgr/timer_heap.c
+  src/core/lib/iomgr/udp_server.c
+  src/core/lib/iomgr/unix_sockets_posix.c
+  src/core/lib/iomgr/unix_sockets_posix_noop.c
+  src/core/lib/iomgr/wakeup_fd_eventfd.c
+  src/core/lib/iomgr/wakeup_fd_nospecial.c
+  src/core/lib/iomgr/wakeup_fd_pipe.c
+  src/core/lib/iomgr/wakeup_fd_posix.c
+  src/core/lib/iomgr/workqueue_posix.c
+  src/core/lib/iomgr/workqueue_windows.c
+  src/core/lib/json/json.c
+  src/core/lib/json/json_reader.c
+  src/core/lib/json/json_string.c
+  src/core/lib/json/json_writer.c
+  src/core/lib/surface/alarm.c
+  src/core/lib/surface/api_trace.c
+  src/core/lib/surface/byte_buffer.c
+  src/core/lib/surface/byte_buffer_reader.c
+  src/core/lib/surface/call.c
+  src/core/lib/surface/call_details.c
+  src/core/lib/surface/call_log_batch.c
+  src/core/lib/surface/channel.c
+  src/core/lib/surface/channel_init.c
+  src/core/lib/surface/channel_ping.c
+  src/core/lib/surface/channel_stack_type.c
+  src/core/lib/surface/completion_queue.c
+  src/core/lib/surface/event_string.c
+  src/core/lib/surface/lame_client.c
+  src/core/lib/surface/metadata_array.c
+  src/core/lib/surface/server.c
+  src/core/lib/surface/validate_metadata.c
+  src/core/lib/surface/version.c
+  src/core/lib/transport/byte_stream.c
+  src/core/lib/transport/connectivity_state.c
+  src/core/lib/transport/metadata.c
+  src/core/lib/transport/metadata_batch.c
+  src/core/lib/transport/static_metadata.c
+  src/core/lib/transport/timeout_encoding.c
+  src/core/lib/transport/transport.c
+  src/core/lib/transport/transport_op_string.c
   src/cpp/codegen/codegen_init.cc
 )
 
@@ -1054,6 +1147,7 @@
   ${_gRPC_SSL_LIBRARIES}
   ${_gRPC_PROTOBUF_LIBRARIES}
   grpc
+  gpr
 )
 
 foreach(_hdr
@@ -1104,6 +1198,34 @@
   include/grpc++/support/stub_options.h
   include/grpc++/support/sync_stream.h
   include/grpc++/support/time.h
+  include/grpc/byte_buffer.h
+  include/grpc/byte_buffer_reader.h
+  include/grpc/compression.h
+  include/grpc/grpc.h
+  include/grpc/grpc_posix.h
+  include/grpc/grpc_security_constants.h
+  include/grpc/status.h
+  include/grpc/impl/codegen/byte_buffer.h
+  include/grpc/impl/codegen/byte_buffer_reader.h
+  include/grpc/impl/codegen/compression_types.h
+  include/grpc/impl/codegen/connectivity_state.h
+  include/grpc/impl/codegen/grpc_types.h
+  include/grpc/impl/codegen/propagation_bits.h
+  include/grpc/impl/codegen/status.h
+  include/grpc/impl/codegen/alloc.h
+  include/grpc/impl/codegen/atm.h
+  include/grpc/impl/codegen/atm_gcc_atomic.h
+  include/grpc/impl/codegen/atm_gcc_sync.h
+  include/grpc/impl/codegen/atm_windows.h
+  include/grpc/impl/codegen/log.h
+  include/grpc/impl/codegen/port_platform.h
+  include/grpc/impl/codegen/slice.h
+  include/grpc/impl/codegen/slice_buffer.h
+  include/grpc/impl/codegen/sync.h
+  include/grpc/impl/codegen/sync_generic.h
+  include/grpc/impl/codegen/sync_posix.h
+  include/grpc/impl/codegen/sync_windows.h
+  include/grpc/impl/codegen/time.h
   include/grpc++/impl/codegen/async_stream.h
   include/grpc++/impl/codegen/async_unary_call.h
   include/grpc++/impl/codegen/call.h
@@ -1134,27 +1256,6 @@
   include/grpc++/impl/codegen/sync_no_cxx11.h
   include/grpc++/impl/codegen/sync_stream.h
   include/grpc++/impl/codegen/time.h
-  include/grpc/impl/codegen/byte_buffer.h
-  include/grpc/impl/codegen/byte_buffer_reader.h
-  include/grpc/impl/codegen/compression_types.h
-  include/grpc/impl/codegen/connectivity_state.h
-  include/grpc/impl/codegen/grpc_types.h
-  include/grpc/impl/codegen/propagation_bits.h
-  include/grpc/impl/codegen/status.h
-  include/grpc/impl/codegen/alloc.h
-  include/grpc/impl/codegen/atm.h
-  include/grpc/impl/codegen/atm_gcc_atomic.h
-  include/grpc/impl/codegen/atm_gcc_sync.h
-  include/grpc/impl/codegen/atm_windows.h
-  include/grpc/impl/codegen/log.h
-  include/grpc/impl/codegen/port_platform.h
-  include/grpc/impl/codegen/slice.h
-  include/grpc/impl/codegen/slice_buffer.h
-  include/grpc/impl/codegen/sync.h
-  include/grpc/impl/codegen/sync_generic.h
-  include/grpc/impl/codegen/sync_posix.h
-  include/grpc/impl/codegen/sync_windows.h
-  include/grpc/impl/codegen/time.h
 )
   string(REPLACE "include/" "" _path ${_hdr})
   get_filename_component(_path ${_path} PATH)
@@ -1297,6 +1398,95 @@
   src/cpp/util/status.cc
   src/cpp/util/string_ref.cc
   src/cpp/util/time.cc
+  src/core/lib/channel/channel_args.c
+  src/core/lib/channel/channel_stack.c
+  src/core/lib/channel/channel_stack_builder.c
+  src/core/lib/channel/compress_filter.c
+  src/core/lib/channel/connected_channel.c
+  src/core/lib/channel/handshaker.c
+  src/core/lib/channel/http_client_filter.c
+  src/core/lib/channel/http_server_filter.c
+  src/core/lib/compression/compression.c
+  src/core/lib/compression/message_compress.c
+  src/core/lib/debug/trace.c
+  src/core/lib/http/format_request.c
+  src/core/lib/http/httpcli.c
+  src/core/lib/http/parser.c
+  src/core/lib/iomgr/closure.c
+  src/core/lib/iomgr/endpoint.c
+  src/core/lib/iomgr/endpoint_pair_posix.c
+  src/core/lib/iomgr/endpoint_pair_windows.c
+  src/core/lib/iomgr/error.c
+  src/core/lib/iomgr/ev_epoll_linux.c
+  src/core/lib/iomgr/ev_poll_and_epoll_posix.c
+  src/core/lib/iomgr/ev_poll_posix.c
+  src/core/lib/iomgr/ev_posix.c
+  src/core/lib/iomgr/exec_ctx.c
+  src/core/lib/iomgr/executor.c
+  src/core/lib/iomgr/iocp_windows.c
+  src/core/lib/iomgr/iomgr.c
+  src/core/lib/iomgr/iomgr_posix.c
+  src/core/lib/iomgr/iomgr_windows.c
+  src/core/lib/iomgr/load_file.c
+  src/core/lib/iomgr/network_status_tracker.c
+  src/core/lib/iomgr/polling_entity.c
+  src/core/lib/iomgr/pollset_set_windows.c
+  src/core/lib/iomgr/pollset_windows.c
+  src/core/lib/iomgr/resolve_address_posix.c
+  src/core/lib/iomgr/resolve_address_windows.c
+  src/core/lib/iomgr/sockaddr_utils.c
+  src/core/lib/iomgr/socket_utils_common_posix.c
+  src/core/lib/iomgr/socket_utils_linux.c
+  src/core/lib/iomgr/socket_utils_posix.c
+  src/core/lib/iomgr/socket_windows.c
+  src/core/lib/iomgr/tcp_client_posix.c
+  src/core/lib/iomgr/tcp_client_windows.c
+  src/core/lib/iomgr/tcp_posix.c
+  src/core/lib/iomgr/tcp_server_posix.c
+  src/core/lib/iomgr/tcp_server_windows.c
+  src/core/lib/iomgr/tcp_windows.c
+  src/core/lib/iomgr/time_averaged_stats.c
+  src/core/lib/iomgr/timer.c
+  src/core/lib/iomgr/timer_heap.c
+  src/core/lib/iomgr/udp_server.c
+  src/core/lib/iomgr/unix_sockets_posix.c
+  src/core/lib/iomgr/unix_sockets_posix_noop.c
+  src/core/lib/iomgr/wakeup_fd_eventfd.c
+  src/core/lib/iomgr/wakeup_fd_nospecial.c
+  src/core/lib/iomgr/wakeup_fd_pipe.c
+  src/core/lib/iomgr/wakeup_fd_posix.c
+  src/core/lib/iomgr/workqueue_posix.c
+  src/core/lib/iomgr/workqueue_windows.c
+  src/core/lib/json/json.c
+  src/core/lib/json/json_reader.c
+  src/core/lib/json/json_string.c
+  src/core/lib/json/json_writer.c
+  src/core/lib/surface/alarm.c
+  src/core/lib/surface/api_trace.c
+  src/core/lib/surface/byte_buffer.c
+  src/core/lib/surface/byte_buffer_reader.c
+  src/core/lib/surface/call.c
+  src/core/lib/surface/call_details.c
+  src/core/lib/surface/call_log_batch.c
+  src/core/lib/surface/channel.c
+  src/core/lib/surface/channel_init.c
+  src/core/lib/surface/channel_ping.c
+  src/core/lib/surface/channel_stack_type.c
+  src/core/lib/surface/completion_queue.c
+  src/core/lib/surface/event_string.c
+  src/core/lib/surface/lame_client.c
+  src/core/lib/surface/metadata_array.c
+  src/core/lib/surface/server.c
+  src/core/lib/surface/validate_metadata.c
+  src/core/lib/surface/version.c
+  src/core/lib/transport/byte_stream.c
+  src/core/lib/transport/connectivity_state.c
+  src/core/lib/transport/metadata.c
+  src/core/lib/transport/metadata_batch.c
+  src/core/lib/transport/static_metadata.c
+  src/core/lib/transport/timeout_encoding.c
+  src/core/lib/transport/transport.c
+  src/core/lib/transport/transport_op_string.c
   src/cpp/codegen/codegen_init.cc
 )
 
@@ -1314,7 +1504,6 @@
   ${_gRPC_PROTOBUF_LIBRARIES}
   gpr
   grpc_unsecure
-  grpc
 )
 
 foreach(_hdr
@@ -1365,6 +1554,34 @@
   include/grpc++/support/stub_options.h
   include/grpc++/support/sync_stream.h
   include/grpc++/support/time.h
+  include/grpc/byte_buffer.h
+  include/grpc/byte_buffer_reader.h
+  include/grpc/compression.h
+  include/grpc/grpc.h
+  include/grpc/grpc_posix.h
+  include/grpc/grpc_security_constants.h
+  include/grpc/status.h
+  include/grpc/impl/codegen/byte_buffer.h
+  include/grpc/impl/codegen/byte_buffer_reader.h
+  include/grpc/impl/codegen/compression_types.h
+  include/grpc/impl/codegen/connectivity_state.h
+  include/grpc/impl/codegen/grpc_types.h
+  include/grpc/impl/codegen/propagation_bits.h
+  include/grpc/impl/codegen/status.h
+  include/grpc/impl/codegen/alloc.h
+  include/grpc/impl/codegen/atm.h
+  include/grpc/impl/codegen/atm_gcc_atomic.h
+  include/grpc/impl/codegen/atm_gcc_sync.h
+  include/grpc/impl/codegen/atm_windows.h
+  include/grpc/impl/codegen/log.h
+  include/grpc/impl/codegen/port_platform.h
+  include/grpc/impl/codegen/slice.h
+  include/grpc/impl/codegen/slice_buffer.h
+  include/grpc/impl/codegen/sync.h
+  include/grpc/impl/codegen/sync_generic.h
+  include/grpc/impl/codegen/sync_posix.h
+  include/grpc/impl/codegen/sync_windows.h
+  include/grpc/impl/codegen/time.h
   include/grpc++/impl/codegen/async_stream.h
   include/grpc++/impl/codegen/async_unary_call.h
   include/grpc++/impl/codegen/call.h
@@ -1395,27 +1612,6 @@
   include/grpc++/impl/codegen/sync_no_cxx11.h
   include/grpc++/impl/codegen/sync_stream.h
   include/grpc++/impl/codegen/time.h
-  include/grpc/impl/codegen/byte_buffer.h
-  include/grpc/impl/codegen/byte_buffer_reader.h
-  include/grpc/impl/codegen/compression_types.h
-  include/grpc/impl/codegen/connectivity_state.h
-  include/grpc/impl/codegen/grpc_types.h
-  include/grpc/impl/codegen/propagation_bits.h
-  include/grpc/impl/codegen/status.h
-  include/grpc/impl/codegen/alloc.h
-  include/grpc/impl/codegen/atm.h
-  include/grpc/impl/codegen/atm_gcc_atomic.h
-  include/grpc/impl/codegen/atm_gcc_sync.h
-  include/grpc/impl/codegen/atm_windows.h
-  include/grpc/impl/codegen/log.h
-  include/grpc/impl/codegen/port_platform.h
-  include/grpc/impl/codegen/slice.h
-  include/grpc/impl/codegen/slice_buffer.h
-  include/grpc/impl/codegen/sync.h
-  include/grpc/impl/codegen/sync_generic.h
-  include/grpc/impl/codegen/sync_posix.h
-  include/grpc/impl/codegen/sync_windows.h
-  include/grpc/impl/codegen/time.h
 )
   string(REPLACE "include/" "" _path ${_hdr})
   get_filename_component(_path ${_path} PATH)
diff --git a/Makefile b/Makefile
index 2db87e8..a8e7198 100644
--- a/Makefile
+++ b/Makefile
@@ -492,7 +492,7 @@
 OPENSSL_ALPN_CHECK_CMD = $(PKG_CONFIG) --atleast-version=1.0.2 openssl
 OPENSSL_NPN_CHECK_CMD = $(PKG_CONFIG) --atleast-version=1.0.1 openssl
 ZLIB_CHECK_CMD = $(PKG_CONFIG) --exists zlib
-PROTOBUF_CHECK_CMD = $(PKG_CONFIG) --atleast-version=3.0.0-alpha-3 protobuf
+PROTOBUF_CHECK_CMD = $(PKG_CONFIG) --atleast-version=3.0.0 protobuf
 else # HAS_PKG_CONFIG
 
 ifeq ($(SYSTEM),MINGW32)
@@ -915,6 +915,7 @@
 chttp2_stream_map_test: $(BINDIR)/$(CONFIG)/chttp2_stream_map_test
 chttp2_varint_test: $(BINDIR)/$(CONFIG)/chttp2_varint_test
 client_fuzzer: $(BINDIR)/$(CONFIG)/client_fuzzer
+combiner_test: $(BINDIR)/$(CONFIG)/combiner_test
 compression_test: $(BINDIR)/$(CONFIG)/compression_test
 concurrent_connectivity_test: $(BINDIR)/$(CONFIG)/concurrent_connectivity_test
 dns_resolver_connectivity_test: $(BINDIR)/$(CONFIG)/dns_resolver_connectivity_test
@@ -939,6 +940,7 @@
 gpr_histogram_test: $(BINDIR)/$(CONFIG)/gpr_histogram_test
 gpr_host_port_test: $(BINDIR)/$(CONFIG)/gpr_host_port_test
 gpr_log_test: $(BINDIR)/$(CONFIG)/gpr_log_test
+gpr_mpscq_test: $(BINDIR)/$(CONFIG)/gpr_mpscq_test
 gpr_slice_buffer_test: $(BINDIR)/$(CONFIG)/gpr_slice_buffer_test
 gpr_slice_test: $(BINDIR)/$(CONFIG)/gpr_slice_test
 gpr_stack_lockfree_test: $(BINDIR)/$(CONFIG)/gpr_stack_lockfree_test
@@ -1236,6 +1238,7 @@
   $(BINDIR)/$(CONFIG)/chttp2_status_conversion_test \
   $(BINDIR)/$(CONFIG)/chttp2_stream_map_test \
   $(BINDIR)/$(CONFIG)/chttp2_varint_test \
+  $(BINDIR)/$(CONFIG)/combiner_test \
   $(BINDIR)/$(CONFIG)/compression_test \
   $(BINDIR)/$(CONFIG)/concurrent_connectivity_test \
   $(BINDIR)/$(CONFIG)/dns_resolver_connectivity_test \
@@ -1258,6 +1261,7 @@
   $(BINDIR)/$(CONFIG)/gpr_histogram_test \
   $(BINDIR)/$(CONFIG)/gpr_host_port_test \
   $(BINDIR)/$(CONFIG)/gpr_log_test \
+  $(BINDIR)/$(CONFIG)/gpr_mpscq_test \
   $(BINDIR)/$(CONFIG)/gpr_slice_buffer_test \
   $(BINDIR)/$(CONFIG)/gpr_slice_test \
   $(BINDIR)/$(CONFIG)/gpr_stack_lockfree_test \
@@ -1552,6 +1556,8 @@
 	$(Q) $(BINDIR)/$(CONFIG)/chttp2_stream_map_test || ( echo test chttp2_stream_map_test failed ; exit 1 )
 	$(E) "[RUN]     Testing chttp2_varint_test"
 	$(Q) $(BINDIR)/$(CONFIG)/chttp2_varint_test || ( echo test chttp2_varint_test failed ; exit 1 )
+	$(E) "[RUN]     Testing combiner_test"
+	$(Q) $(BINDIR)/$(CONFIG)/combiner_test || ( echo test combiner_test failed ; exit 1 )
 	$(E) "[RUN]     Testing compression_test"
 	$(Q) $(BINDIR)/$(CONFIG)/compression_test || ( echo test compression_test failed ; exit 1 )
 	$(E) "[RUN]     Testing concurrent_connectivity_test"
@@ -1592,6 +1598,8 @@
 	$(Q) $(BINDIR)/$(CONFIG)/gpr_host_port_test || ( echo test gpr_host_port_test failed ; exit 1 )
 	$(E) "[RUN]     Testing gpr_log_test"
 	$(Q) $(BINDIR)/$(CONFIG)/gpr_log_test || ( echo test gpr_log_test failed ; exit 1 )
+	$(E) "[RUN]     Testing gpr_mpscq_test"
+	$(Q) $(BINDIR)/$(CONFIG)/gpr_mpscq_test || ( echo test gpr_mpscq_test failed ; exit 1 )
 	$(E) "[RUN]     Testing gpr_slice_buffer_test"
 	$(Q) $(BINDIR)/$(CONFIG)/gpr_slice_buffer_test || ( echo test gpr_slice_buffer_test failed ; exit 1 )
 	$(E) "[RUN]     Testing gpr_slice_test"
@@ -2373,6 +2381,7 @@
     src/core/lib/support/log_linux.c \
     src/core/lib/support/log_posix.c \
     src/core/lib/support/log_windows.c \
+    src/core/lib/support/mpscq.c \
     src/core/lib/support/murmur_hash.c \
     src/core/lib/support/slice.c \
     src/core/lib/support/slice_buffer.c \
@@ -2522,6 +2531,7 @@
     src/core/lib/http/httpcli.c \
     src/core/lib/http/parser.c \
     src/core/lib/iomgr/closure.c \
+    src/core/lib/iomgr/combiner.c \
     src/core/lib/iomgr/endpoint.c \
     src/core/lib/iomgr/endpoint_pair_posix.c \
     src/core/lib/iomgr/endpoint_pair_windows.c \
@@ -2651,7 +2661,6 @@
     src/core/ext/client_config/channel_connectivity.c \
     src/core/ext/client_config/client_channel.c \
     src/core/ext/client_config/client_channel_factory.c \
-    src/core/ext/client_config/client_config.c \
     src/core/ext/client_config/client_config_plugin.c \
     src/core/ext/client_config/connector.c \
     src/core/ext/client_config/default_initial_connect_string.c \
@@ -2663,8 +2672,8 @@
     src/core/ext/client_config/resolver.c \
     src/core/ext/client_config/resolver_factory.c \
     src/core/ext/client_config/resolver_registry.c \
+    src/core/ext/client_config/resolver_result.c \
     src/core/ext/client_config/subchannel.c \
-    src/core/ext/client_config/subchannel_call_holder.c \
     src/core/ext/client_config/subchannel_index.c \
     src/core/ext/client_config/uri_parser.c \
     src/core/ext/transport/chttp2/server/insecure/server_chttp2.c \
@@ -2686,6 +2695,7 @@
     src/core/ext/census/base_resources.c \
     src/core/ext/census/context.c \
     src/core/ext/census/gen/census.pb.c \
+    src/core/ext/census/gen/trace_context.pb.c \
     src/core/ext/census/grpc_context.c \
     src/core/ext/census/grpc_filter.c \
     src/core/ext/census/grpc_plugin.c \
@@ -2703,6 +2713,7 @@
     include/grpc/compression.h \
     include/grpc/grpc.h \
     include/grpc/grpc_posix.h \
+    include/grpc/grpc_security_constants.h \
     include/grpc/status.h \
     include/grpc/impl/codegen/byte_buffer.h \
     include/grpc/impl/codegen/byte_buffer_reader.h \
@@ -2726,7 +2737,6 @@
     include/grpc/impl/codegen/sync_windows.h \
     include/grpc/impl/codegen/time.h \
     include/grpc/grpc_security.h \
-    include/grpc/grpc_security_constants.h \
     include/grpc/census.h \
 
 LIBGRPC_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(LIBGRPC_SRC))))
@@ -2798,6 +2808,7 @@
     src/core/lib/http/httpcli.c \
     src/core/lib/http/parser.c \
     src/core/lib/iomgr/closure.c \
+    src/core/lib/iomgr/combiner.c \
     src/core/lib/iomgr/endpoint.c \
     src/core/lib/iomgr/endpoint_pair_posix.c \
     src/core/lib/iomgr/endpoint_pair_windows.c \
@@ -2901,7 +2912,6 @@
     src/core/ext/client_config/channel_connectivity.c \
     src/core/ext/client_config/client_channel.c \
     src/core/ext/client_config/client_channel_factory.c \
-    src/core/ext/client_config/client_config.c \
     src/core/ext/client_config/client_config_plugin.c \
     src/core/ext/client_config/connector.c \
     src/core/ext/client_config/default_initial_connect_string.c \
@@ -2913,8 +2923,8 @@
     src/core/ext/client_config/resolver.c \
     src/core/ext/client_config/resolver_factory.c \
     src/core/ext/client_config/resolver_registry.c \
+    src/core/ext/client_config/resolver_result.c \
     src/core/ext/client_config/subchannel.c \
-    src/core/ext/client_config/subchannel_call_holder.c \
     src/core/ext/client_config/subchannel_index.c \
     src/core/ext/client_config/uri_parser.c \
     src/core/lib/http/httpcli_security_connector.c \
@@ -2953,6 +2963,7 @@
     include/grpc/compression.h \
     include/grpc/grpc.h \
     include/grpc/grpc_posix.h \
+    include/grpc/grpc_security_constants.h \
     include/grpc/status.h \
     include/grpc/impl/codegen/byte_buffer.h \
     include/grpc/impl/codegen/byte_buffer_reader.h \
@@ -2977,7 +2988,6 @@
     include/grpc/impl/codegen/time.h \
     include/grpc/grpc_cronet.h \
     include/grpc/grpc_security.h \
-    include/grpc/grpc_security_constants.h \
 
 LIBGRPC_CRONET_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(LIBGRPC_CRONET_SRC))))
 
@@ -3064,6 +3074,7 @@
     src/core/lib/http/httpcli.c \
     src/core/lib/http/parser.c \
     src/core/lib/iomgr/closure.c \
+    src/core/lib/iomgr/combiner.c \
     src/core/lib/iomgr/endpoint.c \
     src/core/lib/iomgr/endpoint_pair_posix.c \
     src/core/lib/iomgr/endpoint_pair_windows.c \
@@ -3145,6 +3156,7 @@
     include/grpc/compression.h \
     include/grpc/grpc.h \
     include/grpc/grpc_posix.h \
+    include/grpc/grpc_security_constants.h \
     include/grpc/status.h \
     include/grpc/impl/codegen/byte_buffer.h \
     include/grpc/impl/codegen/byte_buffer_reader.h \
@@ -3256,6 +3268,7 @@
     src/core/lib/http/httpcli.c \
     src/core/lib/http/parser.c \
     src/core/lib/iomgr/closure.c \
+    src/core/lib/iomgr/combiner.c \
     src/core/lib/iomgr/endpoint.c \
     src/core/lib/iomgr/endpoint_pair_posix.c \
     src/core/lib/iomgr/endpoint_pair_windows.c \
@@ -3359,7 +3372,6 @@
     src/core/ext/client_config/channel_connectivity.c \
     src/core/ext/client_config/client_channel.c \
     src/core/ext/client_config/client_channel_factory.c \
-    src/core/ext/client_config/client_config.c \
     src/core/ext/client_config/client_config_plugin.c \
     src/core/ext/client_config/connector.c \
     src/core/ext/client_config/default_initial_connect_string.c \
@@ -3371,8 +3383,8 @@
     src/core/ext/client_config/resolver.c \
     src/core/ext/client_config/resolver_factory.c \
     src/core/ext/client_config/resolver_registry.c \
+    src/core/ext/client_config/resolver_result.c \
     src/core/ext/client_config/subchannel.c \
-    src/core/ext/client_config/subchannel_call_holder.c \
     src/core/ext/client_config/subchannel_index.c \
     src/core/ext/client_config/uri_parser.c \
     src/core/ext/resolver/dns/native/dns_resolver.c \
@@ -3390,6 +3402,7 @@
     src/core/ext/census/base_resources.c \
     src/core/ext/census/context.c \
     src/core/ext/census/gen/census.pb.c \
+    src/core/ext/census/gen/trace_context.pb.c \
     src/core/ext/census/grpc_context.c \
     src/core/ext/census/grpc_filter.c \
     src/core/ext/census/grpc_plugin.c \
@@ -3407,6 +3420,7 @@
     include/grpc/compression.h \
     include/grpc/grpc.h \
     include/grpc/grpc_posix.h \
+    include/grpc/grpc_security_constants.h \
     include/grpc/status.h \
     include/grpc/impl/codegen/byte_buffer.h \
     include/grpc/impl/codegen/byte_buffer_reader.h \
@@ -3580,6 +3594,95 @@
     src/cpp/util/status.cc \
     src/cpp/util/string_ref.cc \
     src/cpp/util/time.cc \
+    src/core/lib/channel/channel_args.c \
+    src/core/lib/channel/channel_stack.c \
+    src/core/lib/channel/channel_stack_builder.c \
+    src/core/lib/channel/compress_filter.c \
+    src/core/lib/channel/connected_channel.c \
+    src/core/lib/channel/handshaker.c \
+    src/core/lib/channel/http_client_filter.c \
+    src/core/lib/channel/http_server_filter.c \
+    src/core/lib/compression/compression.c \
+    src/core/lib/compression/message_compress.c \
+    src/core/lib/debug/trace.c \
+    src/core/lib/http/format_request.c \
+    src/core/lib/http/httpcli.c \
+    src/core/lib/http/parser.c \
+    src/core/lib/iomgr/closure.c \
+    src/core/lib/iomgr/endpoint.c \
+    src/core/lib/iomgr/endpoint_pair_posix.c \
+    src/core/lib/iomgr/endpoint_pair_windows.c \
+    src/core/lib/iomgr/error.c \
+    src/core/lib/iomgr/ev_epoll_linux.c \
+    src/core/lib/iomgr/ev_poll_and_epoll_posix.c \
+    src/core/lib/iomgr/ev_poll_posix.c \
+    src/core/lib/iomgr/ev_posix.c \
+    src/core/lib/iomgr/exec_ctx.c \
+    src/core/lib/iomgr/executor.c \
+    src/core/lib/iomgr/iocp_windows.c \
+    src/core/lib/iomgr/iomgr.c \
+    src/core/lib/iomgr/iomgr_posix.c \
+    src/core/lib/iomgr/iomgr_windows.c \
+    src/core/lib/iomgr/load_file.c \
+    src/core/lib/iomgr/network_status_tracker.c \
+    src/core/lib/iomgr/polling_entity.c \
+    src/core/lib/iomgr/pollset_set_windows.c \
+    src/core/lib/iomgr/pollset_windows.c \
+    src/core/lib/iomgr/resolve_address_posix.c \
+    src/core/lib/iomgr/resolve_address_windows.c \
+    src/core/lib/iomgr/sockaddr_utils.c \
+    src/core/lib/iomgr/socket_utils_common_posix.c \
+    src/core/lib/iomgr/socket_utils_linux.c \
+    src/core/lib/iomgr/socket_utils_posix.c \
+    src/core/lib/iomgr/socket_windows.c \
+    src/core/lib/iomgr/tcp_client_posix.c \
+    src/core/lib/iomgr/tcp_client_windows.c \
+    src/core/lib/iomgr/tcp_posix.c \
+    src/core/lib/iomgr/tcp_server_posix.c \
+    src/core/lib/iomgr/tcp_server_windows.c \
+    src/core/lib/iomgr/tcp_windows.c \
+    src/core/lib/iomgr/time_averaged_stats.c \
+    src/core/lib/iomgr/timer.c \
+    src/core/lib/iomgr/timer_heap.c \
+    src/core/lib/iomgr/udp_server.c \
+    src/core/lib/iomgr/unix_sockets_posix.c \
+    src/core/lib/iomgr/unix_sockets_posix_noop.c \
+    src/core/lib/iomgr/wakeup_fd_eventfd.c \
+    src/core/lib/iomgr/wakeup_fd_nospecial.c \
+    src/core/lib/iomgr/wakeup_fd_pipe.c \
+    src/core/lib/iomgr/wakeup_fd_posix.c \
+    src/core/lib/iomgr/workqueue_posix.c \
+    src/core/lib/iomgr/workqueue_windows.c \
+    src/core/lib/json/json.c \
+    src/core/lib/json/json_reader.c \
+    src/core/lib/json/json_string.c \
+    src/core/lib/json/json_writer.c \
+    src/core/lib/surface/alarm.c \
+    src/core/lib/surface/api_trace.c \
+    src/core/lib/surface/byte_buffer.c \
+    src/core/lib/surface/byte_buffer_reader.c \
+    src/core/lib/surface/call.c \
+    src/core/lib/surface/call_details.c \
+    src/core/lib/surface/call_log_batch.c \
+    src/core/lib/surface/channel.c \
+    src/core/lib/surface/channel_init.c \
+    src/core/lib/surface/channel_ping.c \
+    src/core/lib/surface/channel_stack_type.c \
+    src/core/lib/surface/completion_queue.c \
+    src/core/lib/surface/event_string.c \
+    src/core/lib/surface/lame_client.c \
+    src/core/lib/surface/metadata_array.c \
+    src/core/lib/surface/server.c \
+    src/core/lib/surface/validate_metadata.c \
+    src/core/lib/surface/version.c \
+    src/core/lib/transport/byte_stream.c \
+    src/core/lib/transport/connectivity_state.c \
+    src/core/lib/transport/metadata.c \
+    src/core/lib/transport/metadata_batch.c \
+    src/core/lib/transport/static_metadata.c \
+    src/core/lib/transport/timeout_encoding.c \
+    src/core/lib/transport/transport.c \
+    src/core/lib/transport/transport_op_string.c \
     src/cpp/codegen/codegen_init.cc \
 
 PUBLIC_HEADERS_CXX += \
@@ -3630,6 +3733,34 @@
     include/grpc++/support/stub_options.h \
     include/grpc++/support/sync_stream.h \
     include/grpc++/support/time.h \
+    include/grpc/byte_buffer.h \
+    include/grpc/byte_buffer_reader.h \
+    include/grpc/compression.h \
+    include/grpc/grpc.h \
+    include/grpc/grpc_posix.h \
+    include/grpc/grpc_security_constants.h \
+    include/grpc/status.h \
+    include/grpc/impl/codegen/byte_buffer.h \
+    include/grpc/impl/codegen/byte_buffer_reader.h \
+    include/grpc/impl/codegen/compression_types.h \
+    include/grpc/impl/codegen/connectivity_state.h \
+    include/grpc/impl/codegen/grpc_types.h \
+    include/grpc/impl/codegen/propagation_bits.h \
+    include/grpc/impl/codegen/status.h \
+    include/grpc/impl/codegen/alloc.h \
+    include/grpc/impl/codegen/atm.h \
+    include/grpc/impl/codegen/atm_gcc_atomic.h \
+    include/grpc/impl/codegen/atm_gcc_sync.h \
+    include/grpc/impl/codegen/atm_windows.h \
+    include/grpc/impl/codegen/log.h \
+    include/grpc/impl/codegen/port_platform.h \
+    include/grpc/impl/codegen/slice.h \
+    include/grpc/impl/codegen/slice_buffer.h \
+    include/grpc/impl/codegen/sync.h \
+    include/grpc/impl/codegen/sync_generic.h \
+    include/grpc/impl/codegen/sync_posix.h \
+    include/grpc/impl/codegen/sync_windows.h \
+    include/grpc/impl/codegen/time.h \
     include/grpc++/impl/codegen/async_stream.h \
     include/grpc++/impl/codegen/async_unary_call.h \
     include/grpc++/impl/codegen/call.h \
@@ -3660,27 +3791,6 @@
     include/grpc++/impl/codegen/sync_no_cxx11.h \
     include/grpc++/impl/codegen/sync_stream.h \
     include/grpc++/impl/codegen/time.h \
-    include/grpc/impl/codegen/byte_buffer.h \
-    include/grpc/impl/codegen/byte_buffer_reader.h \
-    include/grpc/impl/codegen/compression_types.h \
-    include/grpc/impl/codegen/connectivity_state.h \
-    include/grpc/impl/codegen/grpc_types.h \
-    include/grpc/impl/codegen/propagation_bits.h \
-    include/grpc/impl/codegen/status.h \
-    include/grpc/impl/codegen/alloc.h \
-    include/grpc/impl/codegen/atm.h \
-    include/grpc/impl/codegen/atm_gcc_atomic.h \
-    include/grpc/impl/codegen/atm_gcc_sync.h \
-    include/grpc/impl/codegen/atm_windows.h \
-    include/grpc/impl/codegen/log.h \
-    include/grpc/impl/codegen/port_platform.h \
-    include/grpc/impl/codegen/slice.h \
-    include/grpc/impl/codegen/slice_buffer.h \
-    include/grpc/impl/codegen/sync.h \
-    include/grpc/impl/codegen/sync_generic.h \
-    include/grpc/impl/codegen/sync_posix.h \
-    include/grpc/impl/codegen/sync_windows.h \
-    include/grpc/impl/codegen/time.h \
 
 LIBGRPC++_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(LIBGRPC++_SRC))))
 
@@ -3717,18 +3827,18 @@
 
 
 ifeq ($(SYSTEM),MINGW32)
-$(LIBDIR)/$(CONFIG)/grpc++$(SHARED_VERSION).$(SHARED_EXT): $(LIBGRPC++_OBJS)  $(ZLIB_DEP) $(PROTOBUF_DEP) $(LIBDIR)/$(CONFIG)/grpc.$(SHARED_EXT) $(OPENSSL_DEP)
+$(LIBDIR)/$(CONFIG)/grpc++$(SHARED_VERSION).$(SHARED_EXT): $(LIBGRPC++_OBJS)  $(ZLIB_DEP) $(PROTOBUF_DEP) $(LIBDIR)/$(CONFIG)/grpc.$(SHARED_EXT) $(LIBDIR)/$(CONFIG)/gpr.$(SHARED_EXT) $(OPENSSL_DEP)
 	$(E) "[LD]      Linking $@"
 	$(Q) mkdir -p `dirname $@`
-	$(Q) $(LDXX) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -shared grpc++.def -Wl,--output-def=$(LIBDIR)/$(CONFIG)/grpc++$(SHARED_VERSION).def -Wl,--out-implib=$(LIBDIR)/$(CONFIG)/libgrpc++$(SHARED_VERSION)-dll.a -o $(LIBDIR)/$(CONFIG)/grpc++$(SHARED_VERSION).$(SHARED_EXT) $(LIBGRPC++_OBJS) $(LDLIBS) $(ZLIB_MERGE_LIBS) $(LDLIBSXX) $(LDLIBS_PROTOBUF) -lgrpc-imp
+	$(Q) $(LDXX) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -shared grpc++.def -Wl,--output-def=$(LIBDIR)/$(CONFIG)/grpc++$(SHARED_VERSION).def -Wl,--out-implib=$(LIBDIR)/$(CONFIG)/libgrpc++$(SHARED_VERSION)-dll.a -o $(LIBDIR)/$(CONFIG)/grpc++$(SHARED_VERSION).$(SHARED_EXT) $(LIBGRPC++_OBJS) $(LDLIBS) $(ZLIB_MERGE_LIBS) $(LDLIBSXX) $(LDLIBS_PROTOBUF) -lgrpc-imp -lgpr-imp
 else
-$(LIBDIR)/$(CONFIG)/libgrpc++$(SHARED_VERSION).$(SHARED_EXT): $(LIBGRPC++_OBJS)  $(ZLIB_DEP) $(PROTOBUF_DEP) $(LIBDIR)/$(CONFIG)/libgrpc.$(SHARED_EXT) $(OPENSSL_DEP)
+$(LIBDIR)/$(CONFIG)/libgrpc++$(SHARED_VERSION).$(SHARED_EXT): $(LIBGRPC++_OBJS)  $(ZLIB_DEP) $(PROTOBUF_DEP) $(LIBDIR)/$(CONFIG)/libgrpc.$(SHARED_EXT) $(LIBDIR)/$(CONFIG)/libgpr.$(SHARED_EXT) $(OPENSSL_DEP)
 	$(E) "[LD]      Linking $@"
 	$(Q) mkdir -p `dirname $@`
 ifeq ($(SYSTEM),Darwin)
-	$(Q) $(LDXX) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -install_name $(SHARED_PREFIX)grpc++$(SHARED_VERSION).$(SHARED_EXT) -dynamiclib -o $(LIBDIR)/$(CONFIG)/libgrpc++$(SHARED_VERSION).$(SHARED_EXT) $(LIBGRPC++_OBJS) $(LDLIBS) $(ZLIB_MERGE_LIBS) $(LDLIBSXX) $(LDLIBS_PROTOBUF) -lgrpc
+	$(Q) $(LDXX) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -install_name $(SHARED_PREFIX)grpc++$(SHARED_VERSION).$(SHARED_EXT) -dynamiclib -o $(LIBDIR)/$(CONFIG)/libgrpc++$(SHARED_VERSION).$(SHARED_EXT) $(LIBGRPC++_OBJS) $(LDLIBS) $(ZLIB_MERGE_LIBS) $(LDLIBSXX) $(LDLIBS_PROTOBUF) -lgrpc -lgpr
 else
-	$(Q) $(LDXX) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -shared -Wl,-soname,libgrpc++.so.1 -o $(LIBDIR)/$(CONFIG)/libgrpc++$(SHARED_VERSION).$(SHARED_EXT) $(LIBGRPC++_OBJS) $(LDLIBS) $(ZLIB_MERGE_LIBS) $(LDLIBSXX) $(LDLIBS_PROTOBUF) -lgrpc
+	$(Q) $(LDXX) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -shared -Wl,-soname,libgrpc++.so.1 -o $(LIBDIR)/$(CONFIG)/libgrpc++$(SHARED_VERSION).$(SHARED_EXT) $(LIBGRPC++_OBJS) $(LDLIBS) $(ZLIB_MERGE_LIBS) $(LDLIBSXX) $(LDLIBS_PROTOBUF) -lgrpc -lgpr
 	$(Q) ln -sf $(SHARED_PREFIX)grpc++$(SHARED_VERSION).$(SHARED_EXT) $(LIBDIR)/$(CONFIG)/libgrpc++$(SHARED_VERSION).so.1
 	$(Q) ln -sf $(SHARED_PREFIX)grpc++$(SHARED_VERSION).$(SHARED_EXT) $(LIBDIR)/$(CONFIG)/libgrpc++$(SHARED_VERSION).so
 endif
@@ -4119,6 +4229,95 @@
     src/cpp/util/status.cc \
     src/cpp/util/string_ref.cc \
     src/cpp/util/time.cc \
+    src/core/lib/channel/channel_args.c \
+    src/core/lib/channel/channel_stack.c \
+    src/core/lib/channel/channel_stack_builder.c \
+    src/core/lib/channel/compress_filter.c \
+    src/core/lib/channel/connected_channel.c \
+    src/core/lib/channel/handshaker.c \
+    src/core/lib/channel/http_client_filter.c \
+    src/core/lib/channel/http_server_filter.c \
+    src/core/lib/compression/compression.c \
+    src/core/lib/compression/message_compress.c \
+    src/core/lib/debug/trace.c \
+    src/core/lib/http/format_request.c \
+    src/core/lib/http/httpcli.c \
+    src/core/lib/http/parser.c \
+    src/core/lib/iomgr/closure.c \
+    src/core/lib/iomgr/endpoint.c \
+    src/core/lib/iomgr/endpoint_pair_posix.c \
+    src/core/lib/iomgr/endpoint_pair_windows.c \
+    src/core/lib/iomgr/error.c \
+    src/core/lib/iomgr/ev_epoll_linux.c \
+    src/core/lib/iomgr/ev_poll_and_epoll_posix.c \
+    src/core/lib/iomgr/ev_poll_posix.c \
+    src/core/lib/iomgr/ev_posix.c \
+    src/core/lib/iomgr/exec_ctx.c \
+    src/core/lib/iomgr/executor.c \
+    src/core/lib/iomgr/iocp_windows.c \
+    src/core/lib/iomgr/iomgr.c \
+    src/core/lib/iomgr/iomgr_posix.c \
+    src/core/lib/iomgr/iomgr_windows.c \
+    src/core/lib/iomgr/load_file.c \
+    src/core/lib/iomgr/network_status_tracker.c \
+    src/core/lib/iomgr/polling_entity.c \
+    src/core/lib/iomgr/pollset_set_windows.c \
+    src/core/lib/iomgr/pollset_windows.c \
+    src/core/lib/iomgr/resolve_address_posix.c \
+    src/core/lib/iomgr/resolve_address_windows.c \
+    src/core/lib/iomgr/sockaddr_utils.c \
+    src/core/lib/iomgr/socket_utils_common_posix.c \
+    src/core/lib/iomgr/socket_utils_linux.c \
+    src/core/lib/iomgr/socket_utils_posix.c \
+    src/core/lib/iomgr/socket_windows.c \
+    src/core/lib/iomgr/tcp_client_posix.c \
+    src/core/lib/iomgr/tcp_client_windows.c \
+    src/core/lib/iomgr/tcp_posix.c \
+    src/core/lib/iomgr/tcp_server_posix.c \
+    src/core/lib/iomgr/tcp_server_windows.c \
+    src/core/lib/iomgr/tcp_windows.c \
+    src/core/lib/iomgr/time_averaged_stats.c \
+    src/core/lib/iomgr/timer.c \
+    src/core/lib/iomgr/timer_heap.c \
+    src/core/lib/iomgr/udp_server.c \
+    src/core/lib/iomgr/unix_sockets_posix.c \
+    src/core/lib/iomgr/unix_sockets_posix_noop.c \
+    src/core/lib/iomgr/wakeup_fd_eventfd.c \
+    src/core/lib/iomgr/wakeup_fd_nospecial.c \
+    src/core/lib/iomgr/wakeup_fd_pipe.c \
+    src/core/lib/iomgr/wakeup_fd_posix.c \
+    src/core/lib/iomgr/workqueue_posix.c \
+    src/core/lib/iomgr/workqueue_windows.c \
+    src/core/lib/json/json.c \
+    src/core/lib/json/json_reader.c \
+    src/core/lib/json/json_string.c \
+    src/core/lib/json/json_writer.c \
+    src/core/lib/surface/alarm.c \
+    src/core/lib/surface/api_trace.c \
+    src/core/lib/surface/byte_buffer.c \
+    src/core/lib/surface/byte_buffer_reader.c \
+    src/core/lib/surface/call.c \
+    src/core/lib/surface/call_details.c \
+    src/core/lib/surface/call_log_batch.c \
+    src/core/lib/surface/channel.c \
+    src/core/lib/surface/channel_init.c \
+    src/core/lib/surface/channel_ping.c \
+    src/core/lib/surface/channel_stack_type.c \
+    src/core/lib/surface/completion_queue.c \
+    src/core/lib/surface/event_string.c \
+    src/core/lib/surface/lame_client.c \
+    src/core/lib/surface/metadata_array.c \
+    src/core/lib/surface/server.c \
+    src/core/lib/surface/validate_metadata.c \
+    src/core/lib/surface/version.c \
+    src/core/lib/transport/byte_stream.c \
+    src/core/lib/transport/connectivity_state.c \
+    src/core/lib/transport/metadata.c \
+    src/core/lib/transport/metadata_batch.c \
+    src/core/lib/transport/static_metadata.c \
+    src/core/lib/transport/timeout_encoding.c \
+    src/core/lib/transport/transport.c \
+    src/core/lib/transport/transport_op_string.c \
     src/cpp/codegen/codegen_init.cc \
 
 PUBLIC_HEADERS_CXX += \
@@ -4169,6 +4368,34 @@
     include/grpc++/support/stub_options.h \
     include/grpc++/support/sync_stream.h \
     include/grpc++/support/time.h \
+    include/grpc/byte_buffer.h \
+    include/grpc/byte_buffer_reader.h \
+    include/grpc/compression.h \
+    include/grpc/grpc.h \
+    include/grpc/grpc_posix.h \
+    include/grpc/grpc_security_constants.h \
+    include/grpc/status.h \
+    include/grpc/impl/codegen/byte_buffer.h \
+    include/grpc/impl/codegen/byte_buffer_reader.h \
+    include/grpc/impl/codegen/compression_types.h \
+    include/grpc/impl/codegen/connectivity_state.h \
+    include/grpc/impl/codegen/grpc_types.h \
+    include/grpc/impl/codegen/propagation_bits.h \
+    include/grpc/impl/codegen/status.h \
+    include/grpc/impl/codegen/alloc.h \
+    include/grpc/impl/codegen/atm.h \
+    include/grpc/impl/codegen/atm_gcc_atomic.h \
+    include/grpc/impl/codegen/atm_gcc_sync.h \
+    include/grpc/impl/codegen/atm_windows.h \
+    include/grpc/impl/codegen/log.h \
+    include/grpc/impl/codegen/port_platform.h \
+    include/grpc/impl/codegen/slice.h \
+    include/grpc/impl/codegen/slice_buffer.h \
+    include/grpc/impl/codegen/sync.h \
+    include/grpc/impl/codegen/sync_generic.h \
+    include/grpc/impl/codegen/sync_posix.h \
+    include/grpc/impl/codegen/sync_windows.h \
+    include/grpc/impl/codegen/time.h \
     include/grpc++/impl/codegen/async_stream.h \
     include/grpc++/impl/codegen/async_unary_call.h \
     include/grpc++/impl/codegen/call.h \
@@ -4199,27 +4426,6 @@
     include/grpc++/impl/codegen/sync_no_cxx11.h \
     include/grpc++/impl/codegen/sync_stream.h \
     include/grpc++/impl/codegen/time.h \
-    include/grpc/impl/codegen/byte_buffer.h \
-    include/grpc/impl/codegen/byte_buffer_reader.h \
-    include/grpc/impl/codegen/compression_types.h \
-    include/grpc/impl/codegen/connectivity_state.h \
-    include/grpc/impl/codegen/grpc_types.h \
-    include/grpc/impl/codegen/propagation_bits.h \
-    include/grpc/impl/codegen/status.h \
-    include/grpc/impl/codegen/alloc.h \
-    include/grpc/impl/codegen/atm.h \
-    include/grpc/impl/codegen/atm_gcc_atomic.h \
-    include/grpc/impl/codegen/atm_gcc_sync.h \
-    include/grpc/impl/codegen/atm_windows.h \
-    include/grpc/impl/codegen/log.h \
-    include/grpc/impl/codegen/port_platform.h \
-    include/grpc/impl/codegen/slice.h \
-    include/grpc/impl/codegen/slice_buffer.h \
-    include/grpc/impl/codegen/sync.h \
-    include/grpc/impl/codegen/sync_generic.h \
-    include/grpc/impl/codegen/sync_posix.h \
-    include/grpc/impl/codegen/sync_windows.h \
-    include/grpc/impl/codegen/time.h \
 
 LIBGRPC++_UNSECURE_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(LIBGRPC++_UNSECURE_SRC))))
 
@@ -4246,18 +4452,18 @@
 
 
 ifeq ($(SYSTEM),MINGW32)
-$(LIBDIR)/$(CONFIG)/grpc++_unsecure$(SHARED_VERSION).$(SHARED_EXT): $(LIBGRPC++_UNSECURE_OBJS)  $(ZLIB_DEP) $(PROTOBUF_DEP) $(LIBDIR)/$(CONFIG)/gpr.$(SHARED_EXT) $(LIBDIR)/$(CONFIG)/grpc_unsecure.$(SHARED_EXT) $(LIBDIR)/$(CONFIG)/grpc.$(SHARED_EXT)
+$(LIBDIR)/$(CONFIG)/grpc++_unsecure$(SHARED_VERSION).$(SHARED_EXT): $(LIBGRPC++_UNSECURE_OBJS)  $(ZLIB_DEP) $(PROTOBUF_DEP) $(LIBDIR)/$(CONFIG)/gpr.$(SHARED_EXT) $(LIBDIR)/$(CONFIG)/grpc_unsecure.$(SHARED_EXT)
 	$(E) "[LD]      Linking $@"
 	$(Q) mkdir -p `dirname $@`
-	$(Q) $(LDXX) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -shared grpc++_unsecure.def -Wl,--output-def=$(LIBDIR)/$(CONFIG)/grpc++_unsecure$(SHARED_VERSION).def -Wl,--out-implib=$(LIBDIR)/$(CONFIG)/libgrpc++_unsecure$(SHARED_VERSION)-dll.a -o $(LIBDIR)/$(CONFIG)/grpc++_unsecure$(SHARED_VERSION).$(SHARED_EXT) $(LIBGRPC++_UNSECURE_OBJS) $(LDLIBS) $(ZLIB_MERGE_LIBS) $(LDLIBSXX) $(LDLIBS_PROTOBUF) -lgpr-imp -lgrpc_unsecure-imp -lgrpc-imp
+	$(Q) $(LDXX) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -shared grpc++_unsecure.def -Wl,--output-def=$(LIBDIR)/$(CONFIG)/grpc++_unsecure$(SHARED_VERSION).def -Wl,--out-implib=$(LIBDIR)/$(CONFIG)/libgrpc++_unsecure$(SHARED_VERSION)-dll.a -o $(LIBDIR)/$(CONFIG)/grpc++_unsecure$(SHARED_VERSION).$(SHARED_EXT) $(LIBGRPC++_UNSECURE_OBJS) $(LDLIBS) $(ZLIB_MERGE_LIBS) $(LDLIBSXX) $(LDLIBS_PROTOBUF) -lgpr-imp -lgrpc_unsecure-imp
 else
-$(LIBDIR)/$(CONFIG)/libgrpc++_unsecure$(SHARED_VERSION).$(SHARED_EXT): $(LIBGRPC++_UNSECURE_OBJS)  $(ZLIB_DEP) $(PROTOBUF_DEP) $(LIBDIR)/$(CONFIG)/libgpr.$(SHARED_EXT) $(LIBDIR)/$(CONFIG)/libgrpc_unsecure.$(SHARED_EXT) $(LIBDIR)/$(CONFIG)/libgrpc.$(SHARED_EXT)
+$(LIBDIR)/$(CONFIG)/libgrpc++_unsecure$(SHARED_VERSION).$(SHARED_EXT): $(LIBGRPC++_UNSECURE_OBJS)  $(ZLIB_DEP) $(PROTOBUF_DEP) $(LIBDIR)/$(CONFIG)/libgpr.$(SHARED_EXT) $(LIBDIR)/$(CONFIG)/libgrpc_unsecure.$(SHARED_EXT)
 	$(E) "[LD]      Linking $@"
 	$(Q) mkdir -p `dirname $@`
 ifeq ($(SYSTEM),Darwin)
-	$(Q) $(LDXX) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -install_name $(SHARED_PREFIX)grpc++_unsecure$(SHARED_VERSION).$(SHARED_EXT) -dynamiclib -o $(LIBDIR)/$(CONFIG)/libgrpc++_unsecure$(SHARED_VERSION).$(SHARED_EXT) $(LIBGRPC++_UNSECURE_OBJS) $(LDLIBS) $(ZLIB_MERGE_LIBS) $(LDLIBSXX) $(LDLIBS_PROTOBUF) -lgpr -lgrpc_unsecure -lgrpc
+	$(Q) $(LDXX) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -install_name $(SHARED_PREFIX)grpc++_unsecure$(SHARED_VERSION).$(SHARED_EXT) -dynamiclib -o $(LIBDIR)/$(CONFIG)/libgrpc++_unsecure$(SHARED_VERSION).$(SHARED_EXT) $(LIBGRPC++_UNSECURE_OBJS) $(LDLIBS) $(ZLIB_MERGE_LIBS) $(LDLIBSXX) $(LDLIBS_PROTOBUF) -lgpr -lgrpc_unsecure
 else
-	$(Q) $(LDXX) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -shared -Wl,-soname,libgrpc++_unsecure.so.1 -o $(LIBDIR)/$(CONFIG)/libgrpc++_unsecure$(SHARED_VERSION).$(SHARED_EXT) $(LIBGRPC++_UNSECURE_OBJS) $(LDLIBS) $(ZLIB_MERGE_LIBS) $(LDLIBSXX) $(LDLIBS_PROTOBUF) -lgpr -lgrpc_unsecure -lgrpc
+	$(Q) $(LDXX) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -shared -Wl,-soname,libgrpc++_unsecure.so.1 -o $(LIBDIR)/$(CONFIG)/libgrpc++_unsecure$(SHARED_VERSION).$(SHARED_EXT) $(LIBGRPC++_UNSECURE_OBJS) $(LDLIBS) $(ZLIB_MERGE_LIBS) $(LDLIBSXX) $(LDLIBS_PROTOBUF) -lgpr -lgrpc_unsecure
 	$(Q) ln -sf $(SHARED_PREFIX)grpc++_unsecure$(SHARED_VERSION).$(SHARED_EXT) $(LIBDIR)/$(CONFIG)/libgrpc++_unsecure$(SHARED_VERSION).so.1
 	$(Q) ln -sf $(SHARED_PREFIX)grpc++_unsecure$(SHARED_VERSION).$(SHARED_EXT) $(LIBDIR)/$(CONFIG)/libgrpc++_unsecure$(SHARED_VERSION).so
 endif
@@ -6576,6 +6782,7 @@
     test/core/end2end/tests/max_message_length.c \
     test/core/end2end/tests/negative_deadline.c \
     test/core/end2end/tests/network_status_change.c \
+    test/core/end2end/tests/no_logging.c \
     test/core/end2end/tests/no_op.c \
     test/core/end2end/tests/payload.c \
     test/core/end2end/tests/ping.c \
@@ -6656,6 +6863,7 @@
     test/core/end2end/tests/max_message_length.c \
     test/core/end2end/tests/negative_deadline.c \
     test/core/end2end/tests/network_status_change.c \
+    test/core/end2end/tests/no_logging.c \
     test/core/end2end/tests/no_op.c \
     test/core/end2end/tests/payload.c \
     test/core/end2end/tests/ping.c \
@@ -7210,6 +7418,38 @@
 endif
 
 
+COMBINER_TEST_SRC = \
+    test/core/iomgr/combiner_test.c \
+
+COMBINER_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(COMBINER_TEST_SRC))))
+ifeq ($(NO_SECURE),true)
+
+# You can't build secure targets if you don't have OpenSSL.
+
+$(BINDIR)/$(CONFIG)/combiner_test: openssl_dep_error
+
+else
+
+
+
+$(BINDIR)/$(CONFIG)/combiner_test: $(COMBINER_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
+	$(E) "[LD]      Linking $@"
+	$(Q) mkdir -p `dirname $@`
+	$(Q) $(LD) $(LDFLAGS) $(COMBINER_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBS) $(LDLIBS_SECURE) -o $(BINDIR)/$(CONFIG)/combiner_test
+
+endif
+
+$(OBJDIR)/$(CONFIG)/test/core/iomgr/combiner_test.o:  $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
+
+deps_combiner_test: $(COMBINER_TEST_OBJS:.o=.dep)
+
+ifneq ($(NO_SECURE),true)
+ifneq ($(NO_DEPS),true)
+-include $(COMBINER_TEST_OBJS:.o=.dep)
+endif
+endif
+
+
 COMPRESSION_TEST_SRC = \
     test/core/compression/compression_test.c \
 
@@ -7978,6 +8218,38 @@
 endif
 
 
+GPR_MPSCQ_TEST_SRC = \
+    test/core/support/mpscq_test.c \
+
+GPR_MPSCQ_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(GPR_MPSCQ_TEST_SRC))))
+ifeq ($(NO_SECURE),true)
+
+# You can't build secure targets if you don't have OpenSSL.
+
+$(BINDIR)/$(CONFIG)/gpr_mpscq_test: openssl_dep_error
+
+else
+
+
+
+$(BINDIR)/$(CONFIG)/gpr_mpscq_test: $(GPR_MPSCQ_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
+	$(E) "[LD]      Linking $@"
+	$(Q) mkdir -p `dirname $@`
+	$(Q) $(LD) $(LDFLAGS) $(GPR_MPSCQ_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBS) $(LDLIBS_SECURE) -o $(BINDIR)/$(CONFIG)/gpr_mpscq_test
+
+endif
+
+$(OBJDIR)/$(CONFIG)/test/core/support/mpscq_test.o:  $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
+
+deps_gpr_mpscq_test: $(GPR_MPSCQ_TEST_OBJS:.o=.dep)
+
+ifneq ($(NO_SECURE),true)
+ifneq ($(NO_DEPS),true)
+-include $(GPR_MPSCQ_TEST_OBJS:.o=.dep)
+endif
+endif
+
+
 GPR_SLICE_BUFFER_TEST_SRC = \
     test/core/support/slice_buffer_test.c \
 
diff --git a/PYTHON-MANIFEST.in b/PYTHON-MANIFEST.in
index 96bcdb5..adeb390 100644
--- a/PYTHON-MANIFEST.in
+++ b/PYTHON-MANIFEST.in
@@ -7,7 +7,7 @@
 graft third_party/boringssl
 graft third_party/nanopb
 graft third_party/zlib
-include src/python/grpcio/_unixccompiler_patch.py
+include src/python/grpcio/_spawn_patch.py
 include src/python/grpcio/commands.py
 include src/python/grpcio/grpc_version.py
 include src/python/grpcio/grpc_core_dependencies.py
diff --git a/README.md b/README.md
index 3283517..e9b0454 100644
--- a/README.md
+++ b/README.md
@@ -23,16 +23,16 @@
 
 Libraries in different languages are in different states of development. We are seeking contributions for all of these libraries.
 
-| Language                | Source                              | Status                           |
-|-------------------------|-------------------------------------|----------------------------------|
-| Shared C [core library] | [src/core] (src/core)               | Beta - the surface API is stable |
-| C++                     | [src/cpp] (src/cpp)                 | Beta - the surface API is stable |
-| Ruby                    | [src/ruby] (src/ruby)               | Beta - the surface API is stable |
-| NodeJS                  | [src/node] (src/node)               | Beta - the surface API is stable |
-| Python                  | [src/python] (src/python)           | Beta - the surface API is stable |
-| PHP                     | [src/php] (src/php)                 | Beta - the surface API is stable |
-| C#                      | [src/csharp] (src/csharp)           | Beta - the surface API is stable |
-| Objective-C             | [src/objective-c] (src/objective-c) | Beta - the surface API is stable |
+| Language                | Source                              | Status  |
+|-------------------------|-------------------------------------|---------|
+| Shared C [core library] | [src/core] (src/core)               | 1.0     |
+| C++                     | [src/cpp] (src/cpp)                 | 1.0     |
+| Ruby                    | [src/ruby] (src/ruby)               | 1.0     |
+| NodeJS                  | [src/node] (src/node)               | 1.0     |
+| Python                  | [src/python] (src/python)           | 1.0     |
+| PHP                     | [src/php] (src/php)                 | 1.0     |
+| C#                      | [src/csharp] (src/csharp)           | 1.0     |
+| Objective-C             | [src/objective-c] (src/objective-c) | 1.0     |
 
 <small>
 Java source code is in the [grpc-java] (http://github.com/grpc/grpc-java) repository.
diff --git a/binding.gyp b/binding.gyp
index 17dbfc0..67bf1cb 100644
--- a/binding.gyp
+++ b/binding.gyp
@@ -515,6 +515,7 @@
         'src/core/lib/support/log_linux.c',
         'src/core/lib/support/log_posix.c',
         'src/core/lib/support/log_windows.c',
+        'src/core/lib/support/mpscq.c',
         'src/core/lib/support/murmur_hash.c',
         'src/core/lib/support/slice.c',
         'src/core/lib/support/slice_buffer.c',
@@ -578,6 +579,7 @@
         'src/core/lib/http/httpcli.c',
         'src/core/lib/http/parser.c',
         'src/core/lib/iomgr/closure.c',
+        'src/core/lib/iomgr/combiner.c',
         'src/core/lib/iomgr/endpoint.c',
         'src/core/lib/iomgr/endpoint_pair_posix.c',
         'src/core/lib/iomgr/endpoint_pair_windows.c',
@@ -707,7 +709,6 @@
         'src/core/ext/client_config/channel_connectivity.c',
         'src/core/ext/client_config/client_channel.c',
         'src/core/ext/client_config/client_channel_factory.c',
-        'src/core/ext/client_config/client_config.c',
         'src/core/ext/client_config/client_config_plugin.c',
         'src/core/ext/client_config/connector.c',
         'src/core/ext/client_config/default_initial_connect_string.c',
@@ -719,8 +720,8 @@
         'src/core/ext/client_config/resolver.c',
         'src/core/ext/client_config/resolver_factory.c',
         'src/core/ext/client_config/resolver_registry.c',
+        'src/core/ext/client_config/resolver_result.c',
         'src/core/ext/client_config/subchannel.c',
-        'src/core/ext/client_config/subchannel_call_holder.c',
         'src/core/ext/client_config/subchannel_index.c',
         'src/core/ext/client_config/uri_parser.c',
         'src/core/ext/transport/chttp2/server/insecure/server_chttp2.c',
@@ -742,6 +743,7 @@
         'src/core/ext/census/base_resources.c',
         'src/core/ext/census/context.c',
         'src/core/ext/census/gen/census.pb.c',
+        'src/core/ext/census/gen/trace_context.pb.c',
         'src/core/ext/census/grpc_context.c',
         'src/core/ext/census/grpc_filter.c',
         'src/core/ext/census/grpc_plugin.c',
diff --git a/build.yaml b/build.yaml
index 2f57859..7484b5d 100644
--- a/build.yaml
+++ b/build.yaml
@@ -2,11 +2,17 @@
 '#2': It is used among other things to generate all of our project files.
 '#3': Please refer to the templates directory for more information.
 settings:
-  '#1': The public version number of the library.
-  '#2': Master always has a "-dev" suffix
-  '#3': Use "-preN" suffixes to identify pre-release versions
-  '#4': Per-language overrides are possible with (eg) ruby_version tag here
-  '#5': See the expand_version.py for all the quirks here
+  '#01': The public version number of the library.
+  '#02': ===
+  '#03': Please update the 'g_stands_for' field periodically with a new g word
+  '#04': not listed in doc/g_stands_for.md - and update that document to list the
+  '#05': new word.
+  '#06': ===
+  '#07': Master always has a "-dev" suffix
+  '#08': Use "-preN" suffixes to identify pre-release versions
+  '#09': Per-language overrides are possible with (eg) ruby_version tag here
+  '#10': See the expand_version.py for all the quirks here
+  g_stands_for: good
   version: 1.1.0-dev
 filegroups:
 - name: census
@@ -18,6 +24,7 @@
   - src/core/ext/census/census_interface.h
   - src/core/ext/census/census_rpc_stats.h
   - src/core/ext/census/gen/census.pb.h
+  - src/core/ext/census/gen/trace_context.pb.h
   - src/core/ext/census/grpc_filter.h
   - src/core/ext/census/mlog.h
   - src/core/ext/census/resource.h
@@ -26,6 +33,7 @@
   - src/core/ext/census/base_resources.c
   - src/core/ext/census/context.c
   - src/core/ext/census/gen/census.pb.c
+  - src/core/ext/census/gen/trace_context.pb.c
   - src/core/ext/census/grpc_context.c
   - src/core/ext/census/grpc_filter.c
   - src/core/ext/census/grpc_plugin.c
@@ -74,6 +82,7 @@
   - src/core/lib/support/backoff.h
   - src/core/lib/support/block_annotate.h
   - src/core/lib/support/env.h
+  - src/core/lib/support/mpscq.h
   - src/core/lib/support/murmur_hash.h
   - src/core/lib/support/stack_lockfree.h
   - src/core/lib/support/string.h
@@ -102,6 +111,7 @@
   - src/core/lib/support/log_linux.c
   - src/core/lib/support/log_posix.c
   - src/core/lib/support/log_windows.c
+  - src/core/lib/support/mpscq.c
   - src/core/lib/support/murmur_hash.c
   - src/core/lib/support/slice.c
   - src/core/lib/support/slice_buffer.c
@@ -152,6 +162,7 @@
   - include/grpc/compression.h
   - include/grpc/grpc.h
   - include/grpc/grpc_posix.h
+  - include/grpc/grpc_security_constants.h
   - include/grpc/status.h
   headers:
   - src/core/lib/channel/channel_args.h
@@ -170,6 +181,7 @@
   - src/core/lib/http/httpcli.h
   - src/core/lib/http/parser.h
   - src/core/lib/iomgr/closure.h
+  - src/core/lib/iomgr/combiner.h
   - src/core/lib/iomgr/endpoint.h
   - src/core/lib/iomgr/endpoint_pair.h
   - src/core/lib/iomgr/error.h
@@ -250,6 +262,7 @@
   - src/core/lib/http/httpcli.c
   - src/core/lib/http/parser.c
   - src/core/lib/iomgr/closure.c
+  - src/core/lib/iomgr/combiner.c
   - src/core/lib/iomgr/endpoint.c
   - src/core/lib/iomgr/endpoint_pair_posix.c
   - src/core/lib/iomgr/endpoint_pair_windows.c
@@ -332,7 +345,6 @@
   headers:
   - src/core/ext/client_config/client_channel.h
   - src/core/ext/client_config/client_channel_factory.h
-  - src/core/ext/client_config/client_config.h
   - src/core/ext/client_config/connector.h
   - src/core/ext/client_config/initial_connect_string.h
   - src/core/ext/client_config/lb_policy.h
@@ -342,15 +354,14 @@
   - src/core/ext/client_config/resolver.h
   - src/core/ext/client_config/resolver_factory.h
   - src/core/ext/client_config/resolver_registry.h
+  - src/core/ext/client_config/resolver_result.h
   - src/core/ext/client_config/subchannel.h
-  - src/core/ext/client_config/subchannel_call_holder.h
   - src/core/ext/client_config/subchannel_index.h
   - src/core/ext/client_config/uri_parser.h
   src:
   - src/core/ext/client_config/channel_connectivity.c
   - src/core/ext/client_config/client_channel.c
   - src/core/ext/client_config/client_channel_factory.c
-  - src/core/ext/client_config/client_config.c
   - src/core/ext/client_config/client_config_plugin.c
   - src/core/ext/client_config/connector.c
   - src/core/ext/client_config/default_initial_connect_string.c
@@ -362,8 +373,8 @@
   - src/core/ext/client_config/resolver.c
   - src/core/ext/client_config/resolver_factory.c
   - src/core/ext/client_config/resolver_registry.c
+  - src/core/ext/client_config/resolver_result.c
   - src/core/ext/client_config/subchannel.c
-  - src/core/ext/client_config/subchannel_call_holder.c
   - src/core/ext/client_config/subchannel_index.c
   - src/core/ext/client_config/uri_parser.c
   plugin: grpc_client_config
@@ -435,7 +446,6 @@
 - name: grpc_secure
   public_headers:
   - include/grpc/grpc_security.h
-  - include/grpc/grpc_security_constants.h
   headers:
   - src/core/lib/security/context/security_context.h
   - src/core/lib/security/credentials/composite/composite_credentials.h
@@ -723,9 +733,8 @@
   - src/cpp/util/status.cc
   - src/cpp/util/string_ref.cc
   - src/cpp/util/time.cc
-  deps:
-  - grpc
   uses:
+  - grpc_base
   - grpc++_codegen_base
 - name: grpc++_codegen_base
   language: c++
@@ -1399,6 +1408,17 @@
   - test/core/end2end/fuzzers/client_fuzzer_corpus
   dict: test/core/end2end/fuzzers/hpack.dictionary
   maxlen: 2048
+- name: combiner_test
+  cpu_cost: 30
+  build: test
+  language: c
+  src:
+  - test/core/iomgr/combiner_test.c
+  deps:
+  - grpc_test_util
+  - grpc
+  - gpr_test_util
+  - gpr
 - name: compression_test
   build: test
   language: c
@@ -1650,6 +1670,15 @@
   deps:
   - gpr_test_util
   - gpr
+- name: gpr_mpscq_test
+  cpu_cost: 30
+  build: test
+  language: c
+  src:
+  - test/core/support/mpscq_test.c
+  deps:
+  - gpr_test_util
+  - gpr
 - name: gpr_slice_buffer_test
   build: test
   language: c
diff --git a/config.m4 b/config.m4
index b37658d..ab3c69d 100644
--- a/config.m4
+++ b/config.m4
@@ -56,6 +56,7 @@
     src/core/lib/support/log_linux.c \
     src/core/lib/support/log_posix.c \
     src/core/lib/support/log_windows.c \
+    src/core/lib/support/mpscq.c \
     src/core/lib/support/murmur_hash.c \
     src/core/lib/support/slice.c \
     src/core/lib/support/slice_buffer.c \
@@ -97,6 +98,7 @@
     src/core/lib/http/httpcli.c \
     src/core/lib/http/parser.c \
     src/core/lib/iomgr/closure.c \
+    src/core/lib/iomgr/combiner.c \
     src/core/lib/iomgr/endpoint.c \
     src/core/lib/iomgr/endpoint_pair_posix.c \
     src/core/lib/iomgr/endpoint_pair_windows.c \
@@ -226,7 +228,6 @@
     src/core/ext/client_config/channel_connectivity.c \
     src/core/ext/client_config/client_channel.c \
     src/core/ext/client_config/client_channel_factory.c \
-    src/core/ext/client_config/client_config.c \
     src/core/ext/client_config/client_config_plugin.c \
     src/core/ext/client_config/connector.c \
     src/core/ext/client_config/default_initial_connect_string.c \
@@ -238,8 +239,8 @@
     src/core/ext/client_config/resolver.c \
     src/core/ext/client_config/resolver_factory.c \
     src/core/ext/client_config/resolver_registry.c \
+    src/core/ext/client_config/resolver_result.c \
     src/core/ext/client_config/subchannel.c \
-    src/core/ext/client_config/subchannel_call_holder.c \
     src/core/ext/client_config/subchannel_index.c \
     src/core/ext/client_config/uri_parser.c \
     src/core/ext/transport/chttp2/server/insecure/server_chttp2.c \
@@ -261,6 +262,7 @@
     src/core/ext/census/base_resources.c \
     src/core/ext/census/context.c \
     src/core/ext/census/gen/census.pb.c \
+    src/core/ext/census/gen/trace_context.pb.c \
     src/core/ext/census/grpc_context.c \
     src/core/ext/census/grpc_filter.c \
     src/core/ext/census/grpc_plugin.c \
diff --git a/doc/PROTOCOL-HTTP2.md b/doc/PROTOCOL-HTTP2.md
index 31d694b..df7585d 100644
--- a/doc/PROTOCOL-HTTP2.md
+++ b/doc/PROTOCOL-HTTP2.md
@@ -98,8 +98,11 @@
 * **Trailers-Only** → HTTP-Status Content-Type Trailers
 * **Trailers** → Status [Status-Message] \*Custom-Metadata
 * **HTTP-Status** → ":status 200"
-* **Status** → "grpc-status" <status-code-as-ASCII-string>
-* **Status-Message** → "grpc-message" <descriptive text for status as ASCII string>
+* **Status** → "grpc-status" 1\*DIGIT ; 0-9
+* **Status-Message** → "grpc-message" Percent-Encoded
+* **Percent-Encoded** → 1\*(Percent-Byte-Unencoded / Percent-Byte-Encoded)
+* **Percent-Byte-Unencoded** → 1\*( %x20-%x24 / %x26-%x7E ) ; space and VCHAR, except %
+* **Percent-Byte-Encoded** → "%" 2HEXDIGIT ; 0-9 A-F
 
 **Response-Headers** & **Trailers-Only** are each delivered in a single HTTP2 HEADERS frame block. Most responses are expected to have both headers and trailers but **Trailers-Only** is permitted for calls that produce an immediate error. Status must be sent in **Trailers** even if the status code is OK.
 
@@ -110,6 +113,21 @@
 Clients may limit the size of **Response-Headers**, **Trailers**, and
 **Trailers-Only**, with a default of 8 KiB each suggested.
 
+The value portion of **Status** is a decimal-encoded integer as an ASCII string,
+without any leading zeros.
+
+The value portion of **Status-Message** is conceptually a Unicode string
+description of the error, physically encoded as UTF-8 followed by
+percent-encoding. Percent-encoding is specified in [RFC 3986
+§2.1](https://tools.ietf.org/html/rfc3986#section-2.1), although the form used
+here has different restricted characters. When decoding invalid values,
+implementations MUST NOT error or throw away the message. At worst, the
+implementation can abort decoding the status message altogether such that the
+user would received the raw percent-encoded form. Alternatively, the
+implementation can decode valid portions while leaving broken %-encodings as-is
+or replacing them with a replacement character (e.g., '?' or the Unicode
+replacement character).
+
 ####Example
 
 Sample unary-call showing HTTP2 framing sequence
diff --git a/doc/fail_fast.md b/doc/fail_fast.md
index 3ed4297..2dd5561 100644
--- a/doc/fail_fast.md
+++ b/doc/fail_fast.md
@@ -1,15 +1 @@
-gRPC Fail Fast Semantics
-========================
-
-Fail fast requests allow terminating requests (with status UNAVAILABLE) prior
-to the deadline of the request being met.
-
-gRPC implementations of fail fast can terminate requests whenever a channel is
-in the TRANSIENT_FAILURE or SHUTDOWN states. If the channel is in any other
-state (CONNECTING, READY, or IDLE) the request should not be terminated.
-
-Fail fast SHOULD be the default for gRPC implementations, with an option to
-switch to non fail fast.
-
-The opposite of fail fast is 'ignore connectivity'.
-
+Moved to wait-for-ready.md
diff --git a/doc/g_stands_for.md b/doc/g_stands_for.md
new file mode 100644
index 0000000..52f8eae
--- /dev/null
+++ b/doc/g_stands_for.md
@@ -0,0 +1,8 @@
+Each version of gRPC gets a new description of what the 'g' stands for, since
+we've never really been able to figure it out.
+
+Below is a list of already-used definitions (that should not be repeated in the
+future), and the corresponding version numbers that used them:
+
+- 1.0 'g' stands for 'gRPC'
+- 1.1 'g' stands for 'good'
diff --git a/doc/wait-for-ready.md b/doc/wait-for-ready.md
new file mode 100644
index 0000000..fd42604
--- /dev/null
+++ b/doc/wait-for-ready.md
@@ -0,0 +1,14 @@
+gRPC Wait for Ready Semantics
+=============================
+
+If an RPC is issued but the channel is in `TRANSIENT_FAILURE` or `SHUTDOWN`
+states, the RPC is unable to be transmited promptly. By default, gRPC
+implementations SHOULD fail such RPCs immediately. This is known as "fail fast,"
+but usage of the term is historical. RPCs SHOULD NOT fail as a result of the
+channel being in other states (`CONNECTING`, `READY`, or `IDLE`).
+
+gRPC implementations MAY provide a per-RPC option to not fail RPCs as a result
+of the channel being in `TRANSIENT_FAILURE` state. Instead, the implementation
+queues the RPCs until the channel is `READY`. This is known as "wait for ready."
+The RPCs SHOULD still fail before `READY` if there are unrelated reasons, such
+as the channel is `SHUTDOWN` or the RPC's deadline is reached.
diff --git a/examples/objective-c/auth_sample/AuthTestService.podspec b/examples/objective-c/auth_sample/AuthTestService.podspec
index afccf08..59fbb5f 100644
--- a/examples/objective-c/auth_sample/AuthTestService.podspec
+++ b/examples/objective-c/auth_sample/AuthTestService.podspec
@@ -14,7 +14,7 @@
   src = "../../protos"
 
   # Run protoc with the Objective-C and gRPC plugins to generate protocol messages and gRPC clients.
-  s.dependency "!ProtoCompiler-gRPCPlugin", "~> 1.0.0-pre1.2"
+  s.dependency "!ProtoCompiler-gRPCPlugin", "~> 1.0"
 
   # Pods directory corresponding to this app's Podfile, relative to the location of this podspec.
   pods_root = 'Pods'
@@ -45,10 +45,6 @@
     ms.requires_arc = false
     # The generated files depend on the protobuf runtime.
     ms.dependency "Protobuf"
-    # This is needed by all pods that depend on Protobuf:
-    ms.pod_target_xcconfig = {
-      'GCC_PREPROCESSOR_DEFINITIONS' => '$(inherited) GPB_USE_PROTOBUF_FRAMEWORK_IMPORTS=1',
-    }
   end
 
   # Files generated by the gRPC plugin
@@ -60,4 +56,11 @@
     ss.dependency "gRPC-ProtoRPC"
     ss.dependency "#{s.name}/Messages"
   end
+
+  s.pod_target_xcconfig = {
+    # This is needed by all pods that depend on Protobuf:
+    'GCC_PREPROCESSOR_DEFINITIONS' => '$(inherited) GPB_USE_PROTOBUF_FRAMEWORK_IMPORTS=1',
+    # This is needed by all pods that depend on gRPC-RxLibrary:
+    'CLANG_ALLOW_NON_MODULAR_INCLUDES_IN_FRAMEWORK_MODULES' => 'YES',
+  }
 end
diff --git a/examples/objective-c/helloworld/HelloWorld.podspec b/examples/objective-c/helloworld/HelloWorld.podspec
index 9f07bd6..96a8e2e 100644
--- a/examples/objective-c/helloworld/HelloWorld.podspec
+++ b/examples/objective-c/helloworld/HelloWorld.podspec
@@ -14,7 +14,7 @@
   src = "../../protos"
 
   # Run protoc with the Objective-C and gRPC plugins to generate protocol messages and gRPC clients.
-  s.dependency "!ProtoCompiler-gRPCPlugin", "~> 1.0.0-pre1.2"
+  s.dependency "!ProtoCompiler-gRPCPlugin", "~> 1.0"
 
   # Pods directory corresponding to this app's Podfile, relative to the location of this podspec.
   pods_root = 'Pods'
@@ -45,10 +45,6 @@
     ms.requires_arc = false
     # The generated files depend on the protobuf runtime.
     ms.dependency "Protobuf"
-    # This is needed by all pods that depend on Protobuf:
-    ms.pod_target_xcconfig = {
-      'GCC_PREPROCESSOR_DEFINITIONS' => '$(inherited) GPB_USE_PROTOBUF_FRAMEWORK_IMPORTS=1',
-    }
   end
 
   # Files generated by the gRPC plugin
@@ -60,4 +56,11 @@
     ss.dependency "gRPC-ProtoRPC"
     ss.dependency "#{s.name}/Messages"
   end
+
+  s.pod_target_xcconfig = {
+    # This is needed by all pods that depend on Protobuf:
+    'GCC_PREPROCESSOR_DEFINITIONS' => '$(inherited) GPB_USE_PROTOBUF_FRAMEWORK_IMPORTS=1',
+    # This is needed by all pods that depend on gRPC-RxLibrary:
+    'CLANG_ALLOW_NON_MODULAR_INCLUDES_IN_FRAMEWORK_MODULES' => 'YES',
+  }
 end
diff --git a/examples/objective-c/route_guide/RouteGuide.podspec b/examples/objective-c/route_guide/RouteGuide.podspec
index 7e7e01d..768b5bf 100644
--- a/examples/objective-c/route_guide/RouteGuide.podspec
+++ b/examples/objective-c/route_guide/RouteGuide.podspec
@@ -14,7 +14,7 @@
   src = "../../protos"
 
   # Run protoc with the Objective-C and gRPC plugins to generate protocol messages and gRPC clients.
-  s.dependency "!ProtoCompiler-gRPCPlugin", "~> 1.0.0-pre1.2"
+  s.dependency "!ProtoCompiler-gRPCPlugin", "~> 1.0"
 
   # Pods directory corresponding to this app's Podfile, relative to the location of this podspec.
   pods_root = 'Pods'
@@ -45,10 +45,6 @@
     ms.requires_arc = false
     # The generated files depend on the protobuf runtime.
     ms.dependency "Protobuf"
-    # This is needed by all pods that depend on Protobuf:
-    ms.pod_target_xcconfig = {
-      'GCC_PREPROCESSOR_DEFINITIONS' => '$(inherited) GPB_USE_PROTOBUF_FRAMEWORK_IMPORTS=1',
-    }
   end
 
   # Files generated by the gRPC plugin
@@ -60,4 +56,11 @@
     ss.dependency "gRPC-ProtoRPC"
     ss.dependency "#{s.name}/Messages"
   end
+
+  s.pod_target_xcconfig = {
+    # This is needed by all pods that depend on Protobuf:
+    'GCC_PREPROCESSOR_DEFINITIONS' => '$(inherited) GPB_USE_PROTOBUF_FRAMEWORK_IMPORTS=1',
+    # This is needed by all pods that depend on gRPC-RxLibrary:
+    'CLANG_ALLOW_NON_MODULAR_INCLUDES_IN_FRAMEWORK_MODULES' => 'YES',
+  }
 end
diff --git a/examples/php/composer.json b/examples/php/composer.json
index d40b5db..e6409f8 100644
--- a/examples/php/composer.json
+++ b/examples/php/composer.json
@@ -1,8 +1,7 @@
 {
   "name": "grpc/grpc-demo",
   "description": "gRPC example for PHP",
-  "minimum-stability": "dev",
   "require": {
-    "grpc/grpc": "v0.15.2"
+    "grpc/grpc": "v1.0.0"
   }
 }
diff --git a/examples/php/run_greeter_client.sh b/examples/php/run_greeter_client.sh
index 1a6e9ee..4d0be4f2 100755
--- a/examples/php/run_greeter_client.sh
+++ b/examples/php/run_greeter_client.sh
@@ -30,5 +30,5 @@
 
 set -e
 cd $(dirname $0)
-php $extension_dir -d extension=grpc.so -d max_execution_time=300 \
+php -d extension=grpc.so -d max_execution_time=300 \
   greeter_client.php $1
diff --git a/gRPC-Core.podspec b/gRPC-Core.podspec
index 200f9c2..1fc1170 100644
--- a/gRPC-Core.podspec
+++ b/gRPC-Core.podspec
@@ -35,7 +35,7 @@
 
 Pod::Spec.new do |s|
   s.name     = 'gRPC-Core'
-  version = '1.0.0-pre1'
+  version = '1.0.0'
   s.version  = version
   s.summary  = 'Core cross-platform gRPC library, written in C'
   s.homepage = 'http://www.grpc.io'
@@ -44,7 +44,7 @@
 
   s.source = {
     :git => 'https://github.com/grpc/grpc.git',
-    :tag => "objective-c-v#{version}",
+    :tag => "v#{version}",
     # TODO(jcanizales): Depend explicitly on the nanopb pod, and disable submodules.
     :submodules => true,
   }
@@ -163,6 +163,7 @@
                       'include/grpc/compression.h',
                       'include/grpc/grpc.h',
                       'include/grpc/grpc_posix.h',
+                      'include/grpc/grpc_security_constants.h',
                       'include/grpc/status.h',
                       'include/grpc/impl/codegen/byte_buffer.h',
                       'include/grpc/impl/codegen/byte_buffer_reader.h',
@@ -186,20 +187,20 @@
                       'include/grpc/impl/codegen/sync_windows.h',
                       'include/grpc/impl/codegen/time.h',
                       'include/grpc/grpc_security.h',
-                      'include/grpc/grpc_security_constants.h',
                       'include/grpc/census.h'
   end
   s.subspec 'Implementation' do |ss|
     ss.header_mappings_dir = '.'
     ss.libraries = 'z'
     ss.dependency "#{s.name}/Interface", version
-    ss.dependency 'BoringSSL', '~> 5.0'
+    ss.dependency 'BoringSSL', '~> 6.0'
 
     # To save you from scrolling, this is the last part of the podspec.
     ss.source_files = 'src/core/lib/profiling/timers.h',
                       'src/core/lib/support/backoff.h',
                       'src/core/lib/support/block_annotate.h',
                       'src/core/lib/support/env.h',
+                      'src/core/lib/support/mpscq.h',
                       'src/core/lib/support/murmur_hash.h',
                       'src/core/lib/support/stack_lockfree.h',
                       'src/core/lib/support/string.h',
@@ -227,6 +228,7 @@
                       'src/core/lib/support/log_linux.c',
                       'src/core/lib/support/log_posix.c',
                       'src/core/lib/support/log_windows.c',
+                      'src/core/lib/support/mpscq.c',
                       'src/core/lib/support/murmur_hash.c',
                       'src/core/lib/support/slice.c',
                       'src/core/lib/support/slice_buffer.c',
@@ -268,6 +270,7 @@
                       'src/core/lib/http/httpcli.h',
                       'src/core/lib/http/parser.h',
                       'src/core/lib/iomgr/closure.h',
+                      'src/core/lib/iomgr/combiner.h',
                       'src/core/lib/iomgr/endpoint.h',
                       'src/core/lib/iomgr/endpoint_pair.h',
                       'src/core/lib/iomgr/error.h',
@@ -379,7 +382,6 @@
                       'src/core/lib/tsi/transport_security_interface.h',
                       'src/core/ext/client_config/client_channel.h',
                       'src/core/ext/client_config/client_channel_factory.h',
-                      'src/core/ext/client_config/client_config.h',
                       'src/core/ext/client_config/connector.h',
                       'src/core/ext/client_config/initial_connect_string.h',
                       'src/core/ext/client_config/lb_policy.h',
@@ -389,8 +391,8 @@
                       'src/core/ext/client_config/resolver.h',
                       'src/core/ext/client_config/resolver_factory.h',
                       'src/core/ext/client_config/resolver_registry.h',
+                      'src/core/ext/client_config/resolver_result.h',
                       'src/core/ext/client_config/subchannel.h',
-                      'src/core/ext/client_config/subchannel_call_holder.h',
                       'src/core/ext/client_config/subchannel_index.h',
                       'src/core/ext/client_config/uri_parser.h',
                       'src/core/ext/lb_policy/grpclb/grpclb.h',
@@ -407,6 +409,7 @@
                       'src/core/ext/census/census_interface.h',
                       'src/core/ext/census/census_rpc_stats.h',
                       'src/core/ext/census/gen/census.pb.h',
+                      'src/core/ext/census/gen/trace_context.pb.h',
                       'src/core/ext/census/grpc_filter.h',
                       'src/core/ext/census/mlog.h',
                       'src/core/ext/census/resource.h',
@@ -427,6 +430,7 @@
                       'src/core/lib/http/httpcli.c',
                       'src/core/lib/http/parser.c',
                       'src/core/lib/iomgr/closure.c',
+                      'src/core/lib/iomgr/combiner.c',
                       'src/core/lib/iomgr/endpoint.c',
                       'src/core/lib/iomgr/endpoint_pair_posix.c',
                       'src/core/lib/iomgr/endpoint_pair_windows.c',
@@ -556,7 +560,6 @@
                       'src/core/ext/client_config/channel_connectivity.c',
                       'src/core/ext/client_config/client_channel.c',
                       'src/core/ext/client_config/client_channel_factory.c',
-                      'src/core/ext/client_config/client_config.c',
                       'src/core/ext/client_config/client_config_plugin.c',
                       'src/core/ext/client_config/connector.c',
                       'src/core/ext/client_config/default_initial_connect_string.c',
@@ -568,8 +571,8 @@
                       'src/core/ext/client_config/resolver.c',
                       'src/core/ext/client_config/resolver_factory.c',
                       'src/core/ext/client_config/resolver_registry.c',
+                      'src/core/ext/client_config/resolver_result.c',
                       'src/core/ext/client_config/subchannel.c',
-                      'src/core/ext/client_config/subchannel_call_holder.c',
                       'src/core/ext/client_config/subchannel_index.c',
                       'src/core/ext/client_config/uri_parser.c',
                       'src/core/ext/transport/chttp2/server/insecure/server_chttp2.c',
@@ -591,6 +594,7 @@
                       'src/core/ext/census/base_resources.c',
                       'src/core/ext/census/context.c',
                       'src/core/ext/census/gen/census.pb.c',
+                      'src/core/ext/census/gen/trace_context.pb.c',
                       'src/core/ext/census/grpc_context.c',
                       'src/core/ext/census/grpc_filter.c',
                       'src/core/ext/census/grpc_plugin.c',
@@ -606,6 +610,7 @@
                               'src/core/lib/support/backoff.h',
                               'src/core/lib/support/block_annotate.h',
                               'src/core/lib/support/env.h',
+                              'src/core/lib/support/mpscq.h',
                               'src/core/lib/support/murmur_hash.h',
                               'src/core/lib/support/stack_lockfree.h',
                               'src/core/lib/support/string.h',
@@ -629,6 +634,7 @@
                               'src/core/lib/http/httpcli.h',
                               'src/core/lib/http/parser.h',
                               'src/core/lib/iomgr/closure.h',
+                              'src/core/lib/iomgr/combiner.h',
                               'src/core/lib/iomgr/endpoint.h',
                               'src/core/lib/iomgr/endpoint_pair.h',
                               'src/core/lib/iomgr/error.h',
@@ -740,7 +746,6 @@
                               'src/core/lib/tsi/transport_security_interface.h',
                               'src/core/ext/client_config/client_channel.h',
                               'src/core/ext/client_config/client_channel_factory.h',
-                              'src/core/ext/client_config/client_config.h',
                               'src/core/ext/client_config/connector.h',
                               'src/core/ext/client_config/initial_connect_string.h',
                               'src/core/ext/client_config/lb_policy.h',
@@ -750,8 +755,8 @@
                               'src/core/ext/client_config/resolver.h',
                               'src/core/ext/client_config/resolver_factory.h',
                               'src/core/ext/client_config/resolver_registry.h',
+                              'src/core/ext/client_config/resolver_result.h',
                               'src/core/ext/client_config/subchannel.h',
-                              'src/core/ext/client_config/subchannel_call_holder.h',
                               'src/core/ext/client_config/subchannel_index.h',
                               'src/core/ext/client_config/uri_parser.h',
                               'src/core/ext/lb_policy/grpclb/grpclb.h',
@@ -768,6 +773,7 @@
                               'src/core/ext/census/census_interface.h',
                               'src/core/ext/census/census_rpc_stats.h',
                               'src/core/ext/census/gen/census.pb.h',
+                              'src/core/ext/census/gen/trace_context.pb.h',
                               'src/core/ext/census/grpc_filter.h',
                               'src/core/ext/census/mlog.h',
                               'src/core/ext/census/resource.h',
diff --git a/gRPC-ProtoRPC.podspec b/gRPC-ProtoRPC.podspec
index f3a8343..f6426fb 100644
--- a/gRPC-ProtoRPC.podspec
+++ b/gRPC-ProtoRPC.podspec
@@ -30,7 +30,7 @@
 
 Pod::Spec.new do |s|
   s.name     = 'gRPC-ProtoRPC'
-  version = '1.0.0-pre1'
+  version = '1.0.0'
   s.version  = version
   s.summary  = 'RPC library for Protocol Buffers, based on gRPC'
   s.homepage = 'http://www.grpc.io'
@@ -39,7 +39,7 @@
 
   s.source = {
     :git => 'https://github.com/grpc/grpc.git',
-    :tag => "objective-c-v#{version}",
+    :tag => "v#{version}",
   }
 
   s.ios.deployment_target = '7.1'
@@ -56,8 +56,10 @@
   s.dependency 'gRPC', version
   s.dependency 'gRPC-RxLibrary', version
   s.dependency 'Protobuf', '~> 3.0'
-  # This is needed by all pods that depend on Protobuf:
   s.pod_target_xcconfig = {
+    # This is needed by all pods that depend on Protobuf:
     'GCC_PREPROCESSOR_DEFINITIONS' => '$(inherited) GPB_USE_PROTOBUF_FRAMEWORK_IMPORTS=1',
+    # This is needed by all pods that depend on gRPC-RxLibrary:
+    'CLANG_ALLOW_NON_MODULAR_INCLUDES_IN_FRAMEWORK_MODULES' => 'YES',
   }
 end
diff --git a/gRPC-RxLibrary.podspec b/gRPC-RxLibrary.podspec
index 9936d52..3168434 100644
--- a/gRPC-RxLibrary.podspec
+++ b/gRPC-RxLibrary.podspec
@@ -30,7 +30,7 @@
 
 Pod::Spec.new do |s|
   s.name     = 'gRPC-RxLibrary'
-  version = '1.0.0-pre1'
+  version = '1.0.0'
   s.version  = version
   s.summary  = 'Reactive Extensions library for iOS/OSX.'
   s.homepage = 'http://www.grpc.io'
@@ -39,7 +39,7 @@
 
   s.source = {
     :git => 'https://github.com/grpc/grpc.git',
-    :tag => "objective-c-v#{version}",
+    :tag => "v#{version}",
   }
 
   s.ios.deployment_target = '7.1'
diff --git a/gRPC.podspec b/gRPC.podspec
index 3f6da3b..9a47934 100644
--- a/gRPC.podspec
+++ b/gRPC.podspec
@@ -30,7 +30,7 @@
 
 Pod::Spec.new do |s|
   s.name     = 'gRPC'
-  version = '1.0.0-pre1'
+  version = '1.0.0'
   s.version  = version
   s.summary  = 'gRPC client library for iOS/OSX'
   s.homepage = 'http://www.grpc.io'
@@ -39,7 +39,7 @@
 
   s.source = {
     :git => 'https://github.com/grpc/grpc.git',
-    :tag => "objective-c-v#{version}",
+    :tag => "v#{version}",
   }
 
   s.ios.deployment_target = '7.1'
@@ -59,4 +59,9 @@
 
   # Certificates, to be able to establish TLS connections:
   s.resource_bundles = { 'gRPCCertificates' => ['etc/roots.pem'] }
+
+  s.pod_target_xcconfig = {
+    # This is needed by all pods that depend on gRPC-RxLibrary:
+    'CLANG_ALLOW_NON_MODULAR_INCLUDES_IN_FRAMEWORK_MODULES' => 'YES',
+  }
 end
diff --git a/grpc.def b/grpc.def
index e2255df..d6ddd33 100644
--- a/grpc.def
+++ b/grpc.def
@@ -42,6 +42,7 @@
     grpc_init
     grpc_shutdown
     grpc_version_string
+    grpc_g_stands_for
     grpc_completion_queue_create
     grpc_completion_queue_next
     grpc_completion_queue_pluck
diff --git a/grpc.gemspec b/grpc.gemspec
index a7516a3..3a023c2 100755
--- a/grpc.gemspec
+++ b/grpc.gemspec
@@ -89,6 +89,7 @@
   s.files += %w( src/core/lib/support/backoff.h )
   s.files += %w( src/core/lib/support/block_annotate.h )
   s.files += %w( src/core/lib/support/env.h )
+  s.files += %w( src/core/lib/support/mpscq.h )
   s.files += %w( src/core/lib/support/murmur_hash.h )
   s.files += %w( src/core/lib/support/stack_lockfree.h )
   s.files += %w( src/core/lib/support/string.h )
@@ -116,6 +117,7 @@
   s.files += %w( src/core/lib/support/log_linux.c )
   s.files += %w( src/core/lib/support/log_posix.c )
   s.files += %w( src/core/lib/support/log_windows.c )
+  s.files += %w( src/core/lib/support/mpscq.c )
   s.files += %w( src/core/lib/support/murmur_hash.c )
   s.files += %w( src/core/lib/support/slice.c )
   s.files += %w( src/core/lib/support/slice_buffer.c )
@@ -146,6 +148,7 @@
   s.files += %w( include/grpc/compression.h )
   s.files += %w( include/grpc/grpc.h )
   s.files += %w( include/grpc/grpc_posix.h )
+  s.files += %w( include/grpc/grpc_security_constants.h )
   s.files += %w( include/grpc/status.h )
   s.files += %w( include/grpc/impl/codegen/byte_buffer.h )
   s.files += %w( include/grpc/impl/codegen/byte_buffer_reader.h )
@@ -169,7 +172,6 @@
   s.files += %w( include/grpc/impl/codegen/sync_windows.h )
   s.files += %w( include/grpc/impl/codegen/time.h )
   s.files += %w( include/grpc/grpc_security.h )
-  s.files += %w( include/grpc/grpc_security_constants.h )
   s.files += %w( include/grpc/census.h )
   s.files += %w( src/core/lib/channel/channel_args.h )
   s.files += %w( src/core/lib/channel/channel_stack.h )
@@ -187,6 +189,7 @@
   s.files += %w( src/core/lib/http/httpcli.h )
   s.files += %w( src/core/lib/http/parser.h )
   s.files += %w( src/core/lib/iomgr/closure.h )
+  s.files += %w( src/core/lib/iomgr/combiner.h )
   s.files += %w( src/core/lib/iomgr/endpoint.h )
   s.files += %w( src/core/lib/iomgr/endpoint_pair.h )
   s.files += %w( src/core/lib/iomgr/error.h )
@@ -298,7 +301,6 @@
   s.files += %w( src/core/lib/tsi/transport_security_interface.h )
   s.files += %w( src/core/ext/client_config/client_channel.h )
   s.files += %w( src/core/ext/client_config/client_channel_factory.h )
-  s.files += %w( src/core/ext/client_config/client_config.h )
   s.files += %w( src/core/ext/client_config/connector.h )
   s.files += %w( src/core/ext/client_config/initial_connect_string.h )
   s.files += %w( src/core/ext/client_config/lb_policy.h )
@@ -308,8 +310,8 @@
   s.files += %w( src/core/ext/client_config/resolver.h )
   s.files += %w( src/core/ext/client_config/resolver_factory.h )
   s.files += %w( src/core/ext/client_config/resolver_registry.h )
+  s.files += %w( src/core/ext/client_config/resolver_result.h )
   s.files += %w( src/core/ext/client_config/subchannel.h )
-  s.files += %w( src/core/ext/client_config/subchannel_call_holder.h )
   s.files += %w( src/core/ext/client_config/subchannel_index.h )
   s.files += %w( src/core/ext/client_config/uri_parser.h )
   s.files += %w( src/core/ext/lb_policy/grpclb/grpclb.h )
@@ -326,6 +328,7 @@
   s.files += %w( src/core/ext/census/census_interface.h )
   s.files += %w( src/core/ext/census/census_rpc_stats.h )
   s.files += %w( src/core/ext/census/gen/census.pb.h )
+  s.files += %w( src/core/ext/census/gen/trace_context.pb.h )
   s.files += %w( src/core/ext/census/grpc_filter.h )
   s.files += %w( src/core/ext/census/mlog.h )
   s.files += %w( src/core/ext/census/resource.h )
@@ -346,6 +349,7 @@
   s.files += %w( src/core/lib/http/httpcli.c )
   s.files += %w( src/core/lib/http/parser.c )
   s.files += %w( src/core/lib/iomgr/closure.c )
+  s.files += %w( src/core/lib/iomgr/combiner.c )
   s.files += %w( src/core/lib/iomgr/endpoint.c )
   s.files += %w( src/core/lib/iomgr/endpoint_pair_posix.c )
   s.files += %w( src/core/lib/iomgr/endpoint_pair_windows.c )
@@ -475,7 +479,6 @@
   s.files += %w( src/core/ext/client_config/channel_connectivity.c )
   s.files += %w( src/core/ext/client_config/client_channel.c )
   s.files += %w( src/core/ext/client_config/client_channel_factory.c )
-  s.files += %w( src/core/ext/client_config/client_config.c )
   s.files += %w( src/core/ext/client_config/client_config_plugin.c )
   s.files += %w( src/core/ext/client_config/connector.c )
   s.files += %w( src/core/ext/client_config/default_initial_connect_string.c )
@@ -487,8 +490,8 @@
   s.files += %w( src/core/ext/client_config/resolver.c )
   s.files += %w( src/core/ext/client_config/resolver_factory.c )
   s.files += %w( src/core/ext/client_config/resolver_registry.c )
+  s.files += %w( src/core/ext/client_config/resolver_result.c )
   s.files += %w( src/core/ext/client_config/subchannel.c )
-  s.files += %w( src/core/ext/client_config/subchannel_call_holder.c )
   s.files += %w( src/core/ext/client_config/subchannel_index.c )
   s.files += %w( src/core/ext/client_config/uri_parser.c )
   s.files += %w( src/core/ext/transport/chttp2/server/insecure/server_chttp2.c )
@@ -510,6 +513,7 @@
   s.files += %w( src/core/ext/census/base_resources.c )
   s.files += %w( src/core/ext/census/context.c )
   s.files += %w( src/core/ext/census/gen/census.pb.c )
+  s.files += %w( src/core/ext/census/gen/trace_context.pb.c )
   s.files += %w( src/core/ext/census/grpc_context.c )
   s.files += %w( src/core/ext/census/grpc_filter.c )
   s.files += %w( src/core/ext/census/grpc_plugin.c )
diff --git a/include/grpc++/create_channel.h b/include/grpc++/create_channel.h
index e9ccb51..0537695 100644
--- a/include/grpc++/create_channel.h
+++ b/include/grpc++/create_channel.h
@@ -48,7 +48,6 @@
 /// \param target The URI of the endpoint to connect to.
 /// \param creds Credentials to use for the created channel. If it does not hold
 /// an object or is invalid, a lame channel is returned.
-/// \param args Options for channel creation.
 std::shared_ptr<Channel> CreateChannel(
     const grpc::string& target,
     const std::shared_ptr<ChannelCredentials>& creds);
diff --git a/include/grpc++/grpc++.h b/include/grpc++/grpc++.h
index ef07e19..afb1c55 100644
--- a/include/grpc++/grpc++.h
+++ b/include/grpc++/grpc++.h
@@ -51,6 +51,9 @@
 #ifndef GRPCXX_GRPCXX_H
 #define GRPCXX_GRPCXX_H
 
+// Pragma for http://include-what-you-use.org/ tool, tells that following
+// headers are not private for grpc++.h and are part of its interface.
+// IWYU pragma: begin_exports
 #include <grpc/grpc.h>
 
 #include <grpc++/channel.h>
@@ -62,5 +65,6 @@
 #include <grpc++/server_builder.h>
 #include <grpc++/server_context.h>
 #include <grpc++/server_posix.h>
+// IWYU pragma: end_exports
 
 #endif  // GRPCXX_GRPCXX_H
diff --git a/include/grpc++/impl/codegen/client_context.h b/include/grpc++/impl/codegen/client_context.h
index 012bcc2..d77ca4c 100644
--- a/include/grpc++/impl/codegen/client_context.h
+++ b/include/grpc++/impl/codegen/client_context.h
@@ -271,7 +271,7 @@
 
   /// Set \a algorithm to be the compression algorithm used for the client call.
   ///
-  /// \param algorith The compression algorithm used for the client call.
+  /// \param algorithm The compression algorithm used for the client call.
   void set_compression_algorithm(grpc_compression_algorithm algorithm);
 
   /// Return the peer uri in a string.
@@ -307,6 +307,10 @@
   };
   static void SetGlobalCallbacks(GlobalCallbacks* callbacks);
 
+  // Should be used for framework-level extensions only.
+  // Applications never need to call this method.
+  grpc_call* c_call() { return call_; }
+
  private:
   // Disallow copy and assign.
   ClientContext(const ClientContext&);
diff --git a/include/grpc++/impl/codegen/server_context.h b/include/grpc++/impl/codegen/server_context.h
index 08212af..c9d1f4d 100644
--- a/include/grpc++/impl/codegen/server_context.h
+++ b/include/grpc++/impl/codegen/server_context.h
@@ -166,6 +166,10 @@
     async_notify_when_done_tag_ = tag;
   }
 
+  // Should be used for framework-level extensions only.
+  // Applications never need to call this method.
+  grpc_call* c_call() { return call_; }
+
  private:
   friend class ::grpc::testing::InteropServerContextInspector;
   friend class ::grpc::ServerInterface;
diff --git a/include/grpc++/impl/codegen/sync_stream.h b/include/grpc++/impl/codegen/sync_stream.h
index b2b9727..7601cea 100644
--- a/include/grpc++/impl/codegen/sync_stream.h
+++ b/include/grpc++/impl/codegen/sync_stream.h
@@ -64,6 +64,15 @@
   virtual Status Finish() = 0;
 };
 
+/// Common interface for all synchronous server side streaming.
+class ServerStreamingInterface {
+ public:
+  virtual ~ServerStreamingInterface() {}
+
+  /// Blocking send initial metadata to client.
+  virtual void SendInitialMetadata() = 0;
+};
+
 /// An interface that yields a sequence of messages of type \a R.
 template <class R>
 class ReaderInterface {
@@ -336,12 +345,17 @@
   Call call_;
 };
 
+/// Server-side interface for streaming reads of message of type \a R.
 template <class R>
-class ServerReader GRPC_FINAL : public ReaderInterface<R> {
+class ServerReaderInterface : public ServerStreamingInterface,
+                              public ReaderInterface<R> {};
+
+template <class R>
+class ServerReader GRPC_FINAL : public ServerReaderInterface<R> {
  public:
   ServerReader(Call* call, ServerContext* ctx) : call_(call), ctx_(ctx) {}
 
-  void SendInitialMetadata() {
+  void SendInitialMetadata() GRPC_OVERRIDE {
     GPR_CODEGEN_ASSERT(!ctx_->sent_initial_metadata_);
 
     CallOpSet<CallOpSendInitialMetadata> ops;
@@ -367,12 +381,17 @@
   ServerContext* const ctx_;
 };
 
+/// Server-side interface for streaming writes of message of type \a W.
 template <class W>
-class ServerWriter GRPC_FINAL : public WriterInterface<W> {
+class ServerWriterInterface : public ServerStreamingInterface,
+                              public WriterInterface<W> {};
+
+template <class W>
+class ServerWriter GRPC_FINAL : public ServerWriterInterface<W> {
  public:
   ServerWriter(Call* call, ServerContext* ctx) : call_(call), ctx_(ctx) {}
 
-  void SendInitialMetadata() {
+  void SendInitialMetadata() GRPC_OVERRIDE {
     GPR_CODEGEN_ASSERT(!ctx_->sent_initial_metadata_);
 
     CallOpSet<CallOpSendInitialMetadata> ops;
@@ -411,12 +430,16 @@
 
 /// Server-side interface for bi-directional streaming.
 template <class W, class R>
-class ServerReaderWriter GRPC_FINAL : public WriterInterface<W>,
-                                      public ReaderInterface<R> {
+class ServerReaderWriterInterface : public ServerStreamingInterface,
+                                    public WriterInterface<W>,
+                                    public ReaderInterface<R> {};
+
+template <class W, class R>
+class ServerReaderWriter GRPC_FINAL : public ServerReaderWriterInterface<W, R> {
  public:
   ServerReaderWriter(Call* call, ServerContext* ctx) : call_(call), ctx_(ctx) {}
 
-  void SendInitialMetadata() {
+  void SendInitialMetadata() GRPC_OVERRIDE {
     GPR_CODEGEN_ASSERT(!ctx_->sent_initial_metadata_);
 
     CallOpSet<CallOpSendInitialMetadata> ops;
diff --git a/include/grpc++/impl/server_builder_plugin.h b/include/grpc++/impl/server_builder_plugin.h
index 1e157ef..61632e3 100644
--- a/include/grpc++/impl/server_builder_plugin.h
+++ b/include/grpc++/impl/server_builder_plugin.h
@@ -41,6 +41,7 @@
 namespace grpc {
 
 class ServerInitializer;
+class ChannelArguments;
 
 class ServerBuilderPlugin {
  public:
@@ -58,6 +59,10 @@
   // ServerBuilderOption::UpdatePlugins
   virtual void ChangeArguments(const grpc::string& name, void* value) = 0;
 
+  // UpdateChannelArguments will be called in ServerBuilder::BuildAndStart(),
+  // before the Server instance is created.
+  virtual void UpdateChannelArguments(ChannelArguments* args) {}
+
   virtual bool has_sync_methods() const { return false; }
   virtual bool has_async_methods() const { return false; }
 };
diff --git a/include/grpc/grpc.h b/include/grpc/grpc.h
index 4ca018e..587d86c 100644
--- a/include/grpc/grpc.h
+++ b/include/grpc/grpc.h
@@ -90,6 +90,9 @@
 /** Return a string representing the current version of grpc */
 GRPCAPI const char *grpc_version_string(void);
 
+/** Return a string specifying what the 'g' in gRPC stands for */
+GRPCAPI const char *grpc_g_stands_for(void);
+
 /** Create a completion queue */
 GRPCAPI grpc_completion_queue *grpc_completion_queue_create(void *reserved);
 
diff --git a/include/grpc/impl/codegen/atm.h b/include/grpc/impl/codegen/atm.h
index 5589d5d..ae00fb0 100644
--- a/include/grpc/impl/codegen/atm.h
+++ b/include/grpc/impl/codegen/atm.h
@@ -75,6 +75,9 @@
    int gpr_atm_no_barrier_cas(gpr_atm *p, gpr_atm o, gpr_atm n);
    int gpr_atm_acq_cas(gpr_atm *p, gpr_atm o, gpr_atm n);
    int gpr_atm_rel_cas(gpr_atm *p, gpr_atm o, gpr_atm n);
+
+   // Atomically, set *p=n and return the old value of *p
+   gpr_atm gpr_atm_full_xchg(gpr_atm *p, gpr_atm n);
 */
 
 #include <grpc/impl/codegen/port_platform.h>
diff --git a/include/grpc/impl/codegen/atm_gcc_atomic.h b/include/grpc/impl/codegen/atm_gcc_atomic.h
index 8caf7ed..7d4ae98 100644
--- a/include/grpc/impl/codegen/atm_gcc_atomic.h
+++ b/include/grpc/impl/codegen/atm_gcc_atomic.h
@@ -69,4 +69,6 @@
                                      __ATOMIC_RELAXED);
 }
 
+#define gpr_atm_full_xchg(p, n) __atomic_exchange_n((p), (n), __ATOMIC_ACQ_REL)
+
 #endif /* GRPC_IMPL_CODEGEN_ATM_GCC_ATOMIC_H */
diff --git a/include/grpc/impl/codegen/atm_gcc_sync.h b/include/grpc/impl/codegen/atm_gcc_sync.h
index 915b09f..9aa2b43 100644
--- a/include/grpc/impl/codegen/atm_gcc_sync.h
+++ b/include/grpc/impl/codegen/atm_gcc_sync.h
@@ -84,4 +84,12 @@
 #define gpr_atm_acq_cas(p, o, n) (__sync_bool_compare_and_swap((p), (o), (n)))
 #define gpr_atm_rel_cas(p, o, n) gpr_atm_acq_cas((p), (o), (n))
 
+static __inline gpr_atm gpr_atm_full_xchg(gpr_atm *p, gpr_atm n) {
+  gpr_atm cur;
+  do {
+    cur = gpr_atm_acq_load(p);
+  } while (!gpr_atm_rel_cas(p, cur, n));
+  return cur;
+}
+
 #endif /* GRPC_IMPL_CODEGEN_ATM_GCC_SYNC_H */
diff --git a/include/grpc/impl/codegen/atm_windows.h b/include/grpc/impl/codegen/atm_windows.h
index d5fa8c0..0ab70b9 100644
--- a/include/grpc/impl/codegen/atm_windows.h
+++ b/include/grpc/impl/codegen/atm_windows.h
@@ -122,4 +122,8 @@
   return old;
 }
 
+static __inline gpr_atm gpr_atm_full_xchg(gpr_atm *p, gpr_atm n) {
+  return (gpr_atm)InterlockedExchangePointer((PVOID *)p, (PVOID)n);
+}
+
 #endif /* GRPC_IMPL_CODEGEN_ATM_WINDOWS_H */
diff --git a/include/grpc/impl/codegen/grpc_types.h b/include/grpc/impl/codegen/grpc_types.h
index e5a8288..b3372d7 100644
--- a/include/grpc/impl/codegen/grpc_types.h
+++ b/include/grpc/impl/codegen/grpc_types.h
@@ -222,10 +222,14 @@
 #define GRPC_INITIAL_METADATA_IDEMPOTENT_REQUEST (0x00000010u)
 /** Signal that the call should not return UNAVAILABLE before it has started */
 #define GRPC_INITIAL_METADATA_IGNORE_CONNECTIVITY (0x00000020u)
+/** Signal that the call is cacheable. GRPC is free to use GET verb */
+#define GRPC_INITIAL_METADATA_CACHEABLE_REQUEST (0x00000040u)
+
 /** Mask of all valid flags */
-#define GRPC_INITIAL_METADATA_USED_MASK       \
-  (GRPC_INITIAL_METADATA_IDEMPOTENT_REQUEST | \
-   GRPC_INITIAL_METADATA_IGNORE_CONNECTIVITY)
+#define GRPC_INITIAL_METADATA_USED_MASK        \
+  (GRPC_INITIAL_METADATA_IDEMPOTENT_REQUEST |  \
+   GRPC_INITIAL_METADATA_IGNORE_CONNECTIVITY | \
+   GRPC_INITIAL_METADATA_CACHEABLE_REQUEST)
 
 /** A single metadata element */
 typedef struct grpc_metadata {
diff --git a/package.xml b/package.xml
index 890cf32..fed30e9 100644
--- a/package.xml
+++ b/package.xml
@@ -10,11 +10,11 @@
   <email>grpc-packages@google.com</email>
   <active>yes</active>
  </lead>
- <date>2016-08-09</date>
+ <date>2016-08-22</date>
  <time>16:06:07</time>
  <version>
-  <release>1.1.0</release>
-  <api>1.1.0</api>
+  <release>1.1.0dev</release>
+  <api>1.1.0dev</api>
  </version>
  <stability>
   <release>stable</release>
@@ -22,7 +22,7 @@
  </stability>
  <license>BSD</license>
  <notes>
-- Fixed Ubuntu compile error #7571, #7642
+- Reject metadata keys which are not legal #7881
  </notes>
  <contents>
   <dir baseinstalldir="/" name="/">
@@ -97,6 +97,7 @@
     <file baseinstalldir="/" name="src/core/lib/support/backoff.h" role="src" />
     <file baseinstalldir="/" name="src/core/lib/support/block_annotate.h" role="src" />
     <file baseinstalldir="/" name="src/core/lib/support/env.h" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/support/mpscq.h" role="src" />
     <file baseinstalldir="/" name="src/core/lib/support/murmur_hash.h" role="src" />
     <file baseinstalldir="/" name="src/core/lib/support/stack_lockfree.h" role="src" />
     <file baseinstalldir="/" name="src/core/lib/support/string.h" role="src" />
@@ -124,6 +125,7 @@
     <file baseinstalldir="/" name="src/core/lib/support/log_linux.c" role="src" />
     <file baseinstalldir="/" name="src/core/lib/support/log_posix.c" role="src" />
     <file baseinstalldir="/" name="src/core/lib/support/log_windows.c" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/support/mpscq.c" role="src" />
     <file baseinstalldir="/" name="src/core/lib/support/murmur_hash.c" role="src" />
     <file baseinstalldir="/" name="src/core/lib/support/slice.c" role="src" />
     <file baseinstalldir="/" name="src/core/lib/support/slice_buffer.c" role="src" />
@@ -154,6 +156,7 @@
     <file baseinstalldir="/" name="include/grpc/compression.h" role="src" />
     <file baseinstalldir="/" name="include/grpc/grpc.h" role="src" />
     <file baseinstalldir="/" name="include/grpc/grpc_posix.h" role="src" />
+    <file baseinstalldir="/" name="include/grpc/grpc_security_constants.h" role="src" />
     <file baseinstalldir="/" name="include/grpc/status.h" role="src" />
     <file baseinstalldir="/" name="include/grpc/impl/codegen/byte_buffer.h" role="src" />
     <file baseinstalldir="/" name="include/grpc/impl/codegen/byte_buffer_reader.h" role="src" />
@@ -177,7 +180,6 @@
     <file baseinstalldir="/" name="include/grpc/impl/codegen/sync_windows.h" role="src" />
     <file baseinstalldir="/" name="include/grpc/impl/codegen/time.h" role="src" />
     <file baseinstalldir="/" name="include/grpc/grpc_security.h" role="src" />
-    <file baseinstalldir="/" name="include/grpc/grpc_security_constants.h" role="src" />
     <file baseinstalldir="/" name="include/grpc/census.h" role="src" />
     <file baseinstalldir="/" name="src/core/lib/channel/channel_args.h" role="src" />
     <file baseinstalldir="/" name="src/core/lib/channel/channel_stack.h" role="src" />
@@ -195,6 +197,7 @@
     <file baseinstalldir="/" name="src/core/lib/http/httpcli.h" role="src" />
     <file baseinstalldir="/" name="src/core/lib/http/parser.h" role="src" />
     <file baseinstalldir="/" name="src/core/lib/iomgr/closure.h" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/iomgr/combiner.h" role="src" />
     <file baseinstalldir="/" name="src/core/lib/iomgr/endpoint.h" role="src" />
     <file baseinstalldir="/" name="src/core/lib/iomgr/endpoint_pair.h" role="src" />
     <file baseinstalldir="/" name="src/core/lib/iomgr/error.h" role="src" />
@@ -306,7 +309,6 @@
     <file baseinstalldir="/" name="src/core/lib/tsi/transport_security_interface.h" role="src" />
     <file baseinstalldir="/" name="src/core/ext/client_config/client_channel.h" role="src" />
     <file baseinstalldir="/" name="src/core/ext/client_config/client_channel_factory.h" role="src" />
-    <file baseinstalldir="/" name="src/core/ext/client_config/client_config.h" role="src" />
     <file baseinstalldir="/" name="src/core/ext/client_config/connector.h" role="src" />
     <file baseinstalldir="/" name="src/core/ext/client_config/initial_connect_string.h" role="src" />
     <file baseinstalldir="/" name="src/core/ext/client_config/lb_policy.h" role="src" />
@@ -316,8 +318,8 @@
     <file baseinstalldir="/" name="src/core/ext/client_config/resolver.h" role="src" />
     <file baseinstalldir="/" name="src/core/ext/client_config/resolver_factory.h" role="src" />
     <file baseinstalldir="/" name="src/core/ext/client_config/resolver_registry.h" role="src" />
+    <file baseinstalldir="/" name="src/core/ext/client_config/resolver_result.h" role="src" />
     <file baseinstalldir="/" name="src/core/ext/client_config/subchannel.h" role="src" />
-    <file baseinstalldir="/" name="src/core/ext/client_config/subchannel_call_holder.h" role="src" />
     <file baseinstalldir="/" name="src/core/ext/client_config/subchannel_index.h" role="src" />
     <file baseinstalldir="/" name="src/core/ext/client_config/uri_parser.h" role="src" />
     <file baseinstalldir="/" name="src/core/ext/lb_policy/grpclb/grpclb.h" role="src" />
@@ -334,6 +336,7 @@
     <file baseinstalldir="/" name="src/core/ext/census/census_interface.h" role="src" />
     <file baseinstalldir="/" name="src/core/ext/census/census_rpc_stats.h" role="src" />
     <file baseinstalldir="/" name="src/core/ext/census/gen/census.pb.h" role="src" />
+    <file baseinstalldir="/" name="src/core/ext/census/gen/trace_context.pb.h" role="src" />
     <file baseinstalldir="/" name="src/core/ext/census/grpc_filter.h" role="src" />
     <file baseinstalldir="/" name="src/core/ext/census/mlog.h" role="src" />
     <file baseinstalldir="/" name="src/core/ext/census/resource.h" role="src" />
@@ -354,6 +357,7 @@
     <file baseinstalldir="/" name="src/core/lib/http/httpcli.c" role="src" />
     <file baseinstalldir="/" name="src/core/lib/http/parser.c" role="src" />
     <file baseinstalldir="/" name="src/core/lib/iomgr/closure.c" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/iomgr/combiner.c" role="src" />
     <file baseinstalldir="/" name="src/core/lib/iomgr/endpoint.c" role="src" />
     <file baseinstalldir="/" name="src/core/lib/iomgr/endpoint_pair_posix.c" role="src" />
     <file baseinstalldir="/" name="src/core/lib/iomgr/endpoint_pair_windows.c" role="src" />
@@ -483,7 +487,6 @@
     <file baseinstalldir="/" name="src/core/ext/client_config/channel_connectivity.c" role="src" />
     <file baseinstalldir="/" name="src/core/ext/client_config/client_channel.c" role="src" />
     <file baseinstalldir="/" name="src/core/ext/client_config/client_channel_factory.c" role="src" />
-    <file baseinstalldir="/" name="src/core/ext/client_config/client_config.c" role="src" />
     <file baseinstalldir="/" name="src/core/ext/client_config/client_config_plugin.c" role="src" />
     <file baseinstalldir="/" name="src/core/ext/client_config/connector.c" role="src" />
     <file baseinstalldir="/" name="src/core/ext/client_config/default_initial_connect_string.c" role="src" />
@@ -495,8 +498,8 @@
     <file baseinstalldir="/" name="src/core/ext/client_config/resolver.c" role="src" />
     <file baseinstalldir="/" name="src/core/ext/client_config/resolver_factory.c" role="src" />
     <file baseinstalldir="/" name="src/core/ext/client_config/resolver_registry.c" role="src" />
+    <file baseinstalldir="/" name="src/core/ext/client_config/resolver_result.c" role="src" />
     <file baseinstalldir="/" name="src/core/ext/client_config/subchannel.c" role="src" />
-    <file baseinstalldir="/" name="src/core/ext/client_config/subchannel_call_holder.c" role="src" />
     <file baseinstalldir="/" name="src/core/ext/client_config/subchannel_index.c" role="src" />
     <file baseinstalldir="/" name="src/core/ext/client_config/uri_parser.c" role="src" />
     <file baseinstalldir="/" name="src/core/ext/transport/chttp2/server/insecure/server_chttp2.c" role="src" />
@@ -518,6 +521,7 @@
     <file baseinstalldir="/" name="src/core/ext/census/base_resources.c" role="src" />
     <file baseinstalldir="/" name="src/core/ext/census/context.c" role="src" />
     <file baseinstalldir="/" name="src/core/ext/census/gen/census.pb.c" role="src" />
+    <file baseinstalldir="/" name="src/core/ext/census/gen/trace_context.pb.c" role="src" />
     <file baseinstalldir="/" name="src/core/ext/census/grpc_context.c" role="src" />
     <file baseinstalldir="/" name="src/core/ext/census/grpc_filter.c" role="src" />
     <file baseinstalldir="/" name="src/core/ext/census/grpc_plugin.c" role="src" />
@@ -1154,5 +1158,35 @@
 - Fixed Ubuntu compile error #7571, #7642
    </notes>
   </release>
+  <release>
+   <version>
+    <release>1.0.0</release>
+    <api>1.0.0</api>
+   </version>
+   <stability>
+    <release>stable</release>
+    <api>stable</api>
+   </stability>
+   <date>2016-08-18</date>
+   <license>BSD</license>
+   <notes>
+- gRPC 1.0.0 release
+   </notes>
+  </release>
+  <release>
+   <version>
+    <release>1.1.0dev</release>
+    <api>1.1.0dev</api>
+   </version>
+   <stability>
+    <release>stable</release>
+    <api>stable</api>
+   </stability>
+   <date>2016-08-22</date>
+   <license>BSD</license>
+   <notes>
+- Reject metadata keys which are not legal #7881
+   </notes>
+  </release>
  </changelog>
 </package>
diff --git a/setup.py b/setup.py
index fb9537f..f728095 100644
--- a/setup.py
+++ b/setup.py
@@ -28,7 +28,7 @@
 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 """A setup module for the GRPC Python package."""
-
+from distutils import cygwinccompiler
 from distutils import extension as _extension
 from distutils import util
 import os
@@ -58,14 +58,12 @@
 sys.path.insert(0, os.path.abspath(PYTHON_STEM))
 
 # Break import-style to ensure we can actually find our in-repo dependencies.
-import _unixccompiler_patch
+import _spawn_patch
 import commands
 import grpc_core_dependencies
 import grpc_version
 
-if 'win32' in sys.platform:
-  _unixccompiler_patch.monkeypatch_unix_compiler()
-
+_spawn_patch.monkeypatch_spawn()
 
 LICENSE = '3-clause BSD'
 
@@ -91,8 +89,8 @@
 EXTRA_ENV_COMPILE_ARGS = os.environ.get('GRPC_PYTHON_CFLAGS', None)
 EXTRA_ENV_LINK_ARGS = os.environ.get('GRPC_PYTHON_LDFLAGS', None)
 if EXTRA_ENV_COMPILE_ARGS is None:
-  EXTRA_ENV_COMPILE_ARGS = '-fno-wrapv'
-  if 'win32' in sys.platform:
+  EXTRA_ENV_COMPILE_ARGS = ''
+  if 'win32' in sys.platform and sys.version_info < (3, 5):
     # We use define flags here and don't directly add to DEFINE_MACROS below to
     # ensure that the expert user/builder has a way of turning it off (via the
     # envvars) without adding yet more GRPC-specific envvars.
@@ -102,21 +100,21 @@
     else:
       EXTRA_ENV_COMPILE_ARGS += ' -D_ftime=_ftime64 -D_timeb=__timeb64'
   elif "linux" in sys.platform or "darwin" in sys.platform:
-    EXTRA_ENV_COMPILE_ARGS += ' -fvisibility=hidden'
+    EXTRA_ENV_COMPILE_ARGS += ' -fvisibility=hidden -fno-wrapv'
 if EXTRA_ENV_LINK_ARGS is None:
-  EXTRA_ENV_LINK_ARGS = '-lpthread'
-  if 'win32' in sys.platform:
-    # TODO(atash) check if this is actually safe to just import and call on
-    # non-Windows (to avoid breaking import style)
-    from distutils.cygwinccompiler import get_msvcr
-    msvcr = get_msvcr()[0]
+  EXTRA_ENV_LINK_ARGS = ''
+  if "linux" in sys.platform or "darwin" in sys.platform:
+    EXTRA_ENV_LINK_ARGS += ' -lpthread'
+  elif "win32" in sys.platform and sys.version_info < (3, 5):
+    msvcr = cygwinccompiler.get_msvcr()[0]
     # TODO(atash) sift through the GCC specs to see if libstdc++ can have any
     # influence on the linkage outcome on MinGW for non-C++ programs.
     EXTRA_ENV_LINK_ARGS += (
         ' -static-libgcc -static-libstdc++ -mcrtdll={msvcr} '
         '-static'.format(msvcr=msvcr))
-  elif "linux" in sys.platform:
+  if "linux" in sys.platform:
     EXTRA_ENV_LINK_ARGS += ' -Wl,-wrap,memcpy'
+
 EXTRA_COMPILE_ARGS = shlex.split(EXTRA_ENV_COMPILE_ARGS)
 EXTRA_LINK_ARGS = shlex.split(EXTRA_ENV_LINK_ARGS)
 
@@ -137,15 +135,19 @@
 if not "win32" in sys.platform:
   EXTENSION_LIBRARIES += ('m',)
 if "win32" in sys.platform:
-  EXTENSION_LIBRARIES += ('ws2_32',)
+  EXTENSION_LIBRARIES += ('advapi32', 'ws2_32',)
 
 DEFINE_MACROS = (
     ('OPENSSL_NO_ASM', 1), ('_WIN32_WINNT', 0x600),
     ('GPR_BACKWARDS_COMPATIBILITY_MODE', 1),)
 if "win32" in sys.platform:
-  DEFINE_MACROS += (('OPENSSL_WINDOWS', 1), ('WIN32_LEAN_AND_MEAN', 1),)
+  DEFINE_MACROS += (('WIN32_LEAN_AND_MEAN', 1),)
   if '64bit' in platform.architecture()[0]:
     DEFINE_MACROS += (('MS_WIN64', 1),)
+  elif sys.version_info >= (3, 5):
+    # For some reason, this is needed to get access to inet_pton/inet_ntop
+    # on msvc, but only for 32 bits
+    DEFINE_MACROS += (('NTDDI_VERSION', 0x06000000),)
 
 LDFLAGS = tuple(EXTRA_LINK_ARGS)
 CFLAGS = tuple(EXTRA_COMPILE_ARGS)
@@ -154,7 +156,6 @@
   pymodinit = '__attribute__((visibility ("default"))) {}'.format(pymodinit_type)
   DEFINE_MACROS += (('PyMODINIT_FUNC', pymodinit),)
 
-
 # By default, Python3 distutils enforces compatibility of
 # c plugins (.so files) with the OSX version Python3 was built with.
 # For Python3.4, this is OSX 10.6, but we need Thread Local Support (__thread)
diff --git a/src/core/ext/census/gen/README.md b/src/core/ext/census/gen/README.md
index 72bef65..fdbac10 100644
--- a/src/core/ext/census/gen/README.md
+++ b/src/core/ext/census/gen/README.md
@@ -4,3 +4,7 @@
 * census.pb.{h,c} - Generated from src/core/ext/census/census.proto, using the
   script `tools/codegen/core/gen_nano_proto.sh src/proto/census/census.proto
   $PWD/src/core/ext/census/gen src/core/ext/census/gen`
+* trace_context.pb.{h,c} - Generated from
+  src/core/ext/census/trace_context.proto, using the script
+  `tools/codegen/core/gen_nano_proto.sh src/proto/census/trace_context.proto
+  $PWD/src/core/ext/census/gen src/core/ext/census/gen`
diff --git a/src/core/ext/census/gen/trace_context.pb.c b/src/core/ext/census/gen/trace_context.pb.c
new file mode 100644
index 0000000..c8aea32
--- /dev/null
+++ b/src/core/ext/census/gen/trace_context.pb.c
@@ -0,0 +1,81 @@
+/*
+ *
+ * Copyright 2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+/* Automatically generated nanopb constant definitions */
+/* Generated by nanopb-0.3.5-dev */
+
+#include "src/core/ext/census/gen/trace_context.pb.h"
+
+#if PB_PROTO_HEADER_VERSION != 30
+#error Regenerate this file with the current version of nanopb generator.
+#endif
+
+
+
+const pb_field_t google_trace_TraceId_fields[3] = {
+    PB_FIELD(  1, FIXED64 , OPTIONAL, STATIC  , FIRST, google_trace_TraceId, hi, hi, 0),
+    PB_FIELD(  2, FIXED64 , OPTIONAL, STATIC  , OTHER, google_trace_TraceId, lo, hi, 0),
+    PB_LAST_FIELD
+};
+
+const pb_field_t google_trace_TraceContext_fields[4] = {
+    PB_FIELD(  1, MESSAGE , OPTIONAL, STATIC  , FIRST, google_trace_TraceContext, trace_id, trace_id, &google_trace_TraceId_fields),
+    PB_FIELD(  2, FIXED64 , OPTIONAL, STATIC  , OTHER, google_trace_TraceContext, span_id, trace_id, 0),
+    PB_FIELD(  3, BOOL    , OPTIONAL, STATIC  , OTHER, google_trace_TraceContext, is_sampled, span_id, 0),
+    PB_LAST_FIELD
+};
+
+
+/* Check that field information fits in pb_field_t */
+#if !defined(PB_FIELD_32BIT)
+/* If you get an error here, it means that you need to define PB_FIELD_32BIT
+ * compile-time option. You can do that in pb.h or on compiler command line.
+ * 
+ * The reason you need to do this is that some of your messages contain tag
+ * numbers or field sizes that are larger than what can fit in 8 or 16 bit
+ * field descriptors.
+ */
+PB_STATIC_ASSERT((pb_membersize(google_trace_TraceContext, trace_id) < 65536), YOU_MUST_DEFINE_PB_FIELD_32BIT_FOR_MESSAGES_google_trace_TraceId_google_trace_TraceContext)
+#endif
+
+#if !defined(PB_FIELD_16BIT) && !defined(PB_FIELD_32BIT)
+/* If you get an error here, it means that you need to define PB_FIELD_16BIT
+ * compile-time option. You can do that in pb.h or on compiler command line.
+ * 
+ * The reason you need to do this is that some of your messages contain tag
+ * numbers or field sizes that are larger than what can fit in the default
+ * 8 bit descriptors.
+ */
+PB_STATIC_ASSERT((pb_membersize(google_trace_TraceContext, trace_id) < 256), YOU_MUST_DEFINE_PB_FIELD_16BIT_FOR_MESSAGES_google_trace_TraceId_google_trace_TraceContext)
+#endif
+
+
diff --git a/src/core/ext/census/gen/trace_context.pb.h b/src/core/ext/census/gen/trace_context.pb.h
new file mode 100644
index 0000000..263c4c5
--- /dev/null
+++ b/src/core/ext/census/gen/trace_context.pb.h
@@ -0,0 +1,99 @@
+/*
+ *
+ * Copyright 2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+/* Automatically generated nanopb header */
+/* Generated by nanopb-0.3.5-dev */
+
+#ifndef GRPC_CORE_EXT_CENSUS_GEN_TRACE_CONTEXT_PB_H
+#define GRPC_CORE_EXT_CENSUS_GEN_TRACE_CONTEXT_PB_H
+#include "third_party/nanopb/pb.h"
+#if PB_PROTO_HEADER_VERSION != 30
+#error Regenerate this file with the current version of nanopb generator.
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Struct definitions */
+typedef struct _google_trace_TraceId {
+    bool has_hi;
+    uint64_t hi;
+    bool has_lo;
+    uint64_t lo;
+} google_trace_TraceId;
+
+typedef struct _google_trace_TraceContext {
+    bool has_trace_id;
+    google_trace_TraceId trace_id;
+    bool has_span_id;
+    uint64_t span_id;
+    bool has_is_sampled;
+    bool is_sampled;
+} google_trace_TraceContext;
+
+/* Default values for struct fields */
+
+/* Initializer values for message structs */
+#define google_trace_TraceId_init_default        {false, 0, false, 0}
+#define google_trace_TraceContext_init_default   {false, google_trace_TraceId_init_default, false, 0, false, 0}
+#define google_trace_TraceId_init_zero           {false, 0, false, 0}
+#define google_trace_TraceContext_init_zero      {false, google_trace_TraceId_init_zero, false, 0, false, 0}
+
+/* Field tags (for use in manual encoding/decoding) */
+#define google_trace_TraceId_hi_tag              1
+#define google_trace_TraceId_lo_tag              2
+#define google_trace_TraceContext_trace_id_tag   1
+#define google_trace_TraceContext_span_id_tag    2
+#define google_trace_TraceContext_is_sampled_tag 3
+
+/* Struct field encoding specification for nanopb */
+extern const pb_field_t google_trace_TraceId_fields[3];
+extern const pb_field_t google_trace_TraceContext_fields[4];
+
+/* Maximum encoded size of messages (where known) */
+#define google_trace_TraceId_size                18
+#define google_trace_TraceContext_size           31
+
+/* Message IDs (where set with "msgid" option) */
+#ifdef PB_MSGID
+
+#define TRACE_CONTEXT_MESSAGES \
+
+
+#endif
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif
diff --git a/src/core/ext/client_config/README.md b/src/core/ext/client_config/README.md
index 7024fd5..eda01e3 100644
--- a/src/core/ext/client_config/README.md
+++ b/src/core/ext/client_config/README.md
@@ -12,7 +12,7 @@
 - a load balancing policy to decide which server to send a request to
 - a set of filters to mutate outgoing requests (say, by adding metadata)
 
-The resolver provides this data as a stream of grpc_client_config objects to
+The resolver provides this data as a stream of grpc_resolver_result objects to
 the channel. We represent configuration as a stream so that it can be changed
 by the resolver during execution, by reacting to external events (such as a
 new configuration file being pushed to some store).
@@ -22,7 +22,7 @@
 --------------
 
 Load balancing configuration is provided by a grpc_lb_policy object, stored as
-part of grpc_client_config.
+part of grpc_resolver_result.
 
 The primary job of the load balancing policies is to pick a target server given only the
 initial metadata for a request. It does this by providing a grpc_subchannel
diff --git a/src/core/ext/client_config/client_channel.c b/src/core/ext/client_config/client_channel.c
index 2c0c4ab..be333f4 100644
--- a/src/core/ext/client_config/client_channel.c
+++ b/src/core/ext/client_config/client_channel.c
@@ -33,6 +33,7 @@
 
 #include "src/core/ext/client_config/client_channel.h"
 
+#include <stdbool.h>
 #include <stdio.h>
 #include <string.h>
 
@@ -41,10 +42,11 @@
 #include <grpc/support/sync.h>
 #include <grpc/support/useful.h>
 
-#include "src/core/ext/client_config/subchannel_call_holder.h"
+#include "src/core/ext/client_config/subchannel.h"
 #include "src/core/lib/channel/channel_args.h"
 #include "src/core/lib/channel/connected_channel.h"
 #include "src/core/lib/iomgr/iomgr.h"
+#include "src/core/lib/iomgr/polling_entity.h"
 #include "src/core/lib/profiling/timers.h"
 #include "src/core/lib/support/string.h"
 #include "src/core/lib/surface/channel.h"
@@ -52,30 +54,31 @@
 
 /* Client channel implementation */
 
-typedef grpc_subchannel_call_holder call_data;
+/*************************************************************************
+ * CHANNEL-WIDE FUNCTIONS
+ */
 
 typedef struct client_channel_channel_data {
   /** resolver for this channel */
   grpc_resolver *resolver;
   /** have we started resolving this channel */
-  int started_resolving;
+  bool started_resolving;
 
   /** mutex protecting client configuration, including all
       variables below in this data structure */
-  gpr_mu mu_config;
-  /** currently active load balancer - guarded by mu_config */
+  gpr_mu mu;
+  /** currently active load balancer - guarded by mu */
   grpc_lb_policy *lb_policy;
-  /** incoming configuration - set by resolver.next
-      guarded by mu_config */
-  grpc_client_config *incoming_configuration;
+  /** incoming resolver result - set by resolver.next(), guarded by mu */
+  grpc_resolver_result *resolver_result;
   /** a list of closures that are all waiting for config to come in */
   grpc_closure_list waiting_for_config_closures;
   /** resolver callback */
-  grpc_closure on_config_changed;
+  grpc_closure on_resolver_result_changed;
   /** connectivity state being tracked */
   grpc_connectivity_state_tracker state_tracker;
   /** when an lb_policy arrives, should we try to exit idle */
-  int exit_idle_when_lb_policy_arrives;
+  bool exit_idle_when_lb_policy_arrives;
   /** owning stack */
   grpc_channel_stack *owning_stack;
   /** interested parties (owned) */
@@ -83,10 +86,8 @@
 } channel_data;
 
 /** We create one watcher for each new lb_policy that is returned from a
-   resolver,
-    to watch for state changes from the lb_policy. When a state change is seen,
-   we
-    update the channel, and create a new watcher */
+    resolver, to watch for state changes from the lb_policy. When a state
+    change is seen, we update the channel, and create a new watcher. */
 typedef struct {
   channel_data *chand;
   grpc_closure on_changed;
@@ -94,22 +95,6 @@
   grpc_lb_policy *lb_policy;
 } lb_policy_connectivity_watcher;
 
-typedef struct {
-  grpc_closure closure;
-  grpc_call_element *elem;
-} waiting_call;
-
-static char *cc_get_peer(grpc_exec_ctx *exec_ctx, grpc_call_element *elem) {
-  return grpc_subchannel_call_holder_get_peer(exec_ctx, elem->call_data);
-}
-
-static void cc_start_transport_stream_op(grpc_exec_ctx *exec_ctx,
-                                         grpc_call_element *elem,
-                                         grpc_transport_stream_op *op) {
-  GRPC_CALL_LOG_OP(GPR_INFO, elem, op);
-  grpc_subchannel_call_holder_perform_op(exec_ctx, elem->call_data, op);
-}
-
 static void watch_lb_policy(grpc_exec_ctx *exec_ctx, channel_data *chand,
                             grpc_lb_policy *lb_policy,
                             grpc_connectivity_state current_state);
@@ -156,9 +141,9 @@
                                        grpc_error *error) {
   lb_policy_connectivity_watcher *w = arg;
 
-  gpr_mu_lock(&w->chand->mu_config);
+  gpr_mu_lock(&w->chand->mu);
   on_lb_policy_state_changed_locked(exec_ctx, w, error);
-  gpr_mu_unlock(&w->chand->mu_config);
+  gpr_mu_unlock(&w->chand->mu);
 
   GRPC_CHANNEL_STACK_UNREF(exec_ctx, w->chand->owning_stack, "watch_lb_policy");
   gpr_free(w);
@@ -178,17 +163,17 @@
                                         &w->on_changed);
 }
 
-static void cc_on_config_changed(grpc_exec_ctx *exec_ctx, void *arg,
-                                 grpc_error *error) {
+static void on_resolver_result_changed(grpc_exec_ctx *exec_ctx, void *arg,
+                                       grpc_error *error) {
   channel_data *chand = arg;
   grpc_lb_policy *lb_policy = NULL;
   grpc_lb_policy *old_lb_policy;
   grpc_connectivity_state state = GRPC_CHANNEL_TRANSIENT_FAILURE;
-  int exit_idle = 0;
+  bool exit_idle = false;
   grpc_error *state_error = GRPC_ERROR_CREATE("No load balancing policy");
 
-  if (chand->incoming_configuration != NULL) {
-    lb_policy = grpc_client_config_get_lb_policy(chand->incoming_configuration);
+  if (chand->resolver_result != NULL) {
+    lb_policy = grpc_resolver_result_get_lb_policy(chand->resolver_result);
     if (lb_policy != NULL) {
       GRPC_LB_POLICY_REF(lb_policy, "channel");
       GRPC_LB_POLICY_REF(lb_policy, "config_change");
@@ -197,17 +182,17 @@
           grpc_lb_policy_check_connectivity(exec_ctx, lb_policy, &state_error);
     }
 
-    grpc_client_config_unref(exec_ctx, chand->incoming_configuration);
+    grpc_resolver_result_unref(exec_ctx, chand->resolver_result);
   }
 
-  chand->incoming_configuration = NULL;
+  chand->resolver_result = NULL;
 
   if (lb_policy != NULL) {
     grpc_pollset_set_add_pollset_set(exec_ctx, lb_policy->interested_parties,
                                      chand->interested_parties);
   }
 
-  gpr_mu_lock(&chand->mu_config);
+  gpr_mu_lock(&chand->mu);
   old_lb_policy = chand->lb_policy;
   chand->lb_policy = lb_policy;
   if (lb_policy != NULL) {
@@ -222,8 +207,8 @@
   }
   if (lb_policy != NULL && chand->exit_idle_when_lb_policy_arrives) {
     GRPC_LB_POLICY_REF(lb_policy, "exit_idle");
-    exit_idle = 1;
-    chand->exit_idle_when_lb_policy_arrives = 0;
+    exit_idle = true;
+    chand->exit_idle_when_lb_policy_arrives = false;
   }
 
   if (error == GRPC_ERROR_NONE && chand->resolver) {
@@ -233,10 +218,9 @@
       watch_lb_policy(exec_ctx, chand, lb_policy, state);
     }
     GRPC_CHANNEL_STACK_REF(chand->owning_stack, "resolver");
-    grpc_resolver_next(exec_ctx, chand->resolver,
-                       &chand->incoming_configuration,
-                       &chand->on_config_changed);
-    gpr_mu_unlock(&chand->mu_config);
+    grpc_resolver_next(exec_ctx, chand->resolver, &chand->resolver_result,
+                       &chand->on_resolver_result_changed);
+    gpr_mu_unlock(&chand->mu);
   } else {
     if (chand->resolver != NULL) {
       grpc_resolver_shutdown(exec_ctx, chand->resolver);
@@ -249,7 +233,7 @@
         GRPC_ERROR_CREATE_REFERENCING("Got config after disconnection", refs,
                                       GPR_ARRAY_SIZE(refs)),
         "resolver_gone");
-    gpr_mu_unlock(&chand->mu_config);
+    gpr_mu_unlock(&chand->mu);
   }
 
   if (exit_idle) {
@@ -284,7 +268,7 @@
                                  op->bind_pollset);
   }
 
-  gpr_mu_lock(&chand->mu_config);
+  gpr_mu_lock(&chand->mu);
   if (op->on_connectivity_state_change != NULL) {
     grpc_connectivity_state_notify_on_state_change(
         exec_ctx, &chand->state_tracker, op->connectivity_state,
@@ -329,7 +313,193 @@
     }
     GRPC_ERROR_UNREF(op->disconnect_with_error);
   }
-  gpr_mu_unlock(&chand->mu_config);
+  gpr_mu_unlock(&chand->mu);
+}
+
+/* Constructor for channel_data */
+static void cc_init_channel_elem(grpc_exec_ctx *exec_ctx,
+                                 grpc_channel_element *elem,
+                                 grpc_channel_element_args *args) {
+  channel_data *chand = elem->channel_data;
+
+  memset(chand, 0, sizeof(*chand));
+
+  GPR_ASSERT(args->is_last);
+  GPR_ASSERT(elem->filter == &grpc_client_channel_filter);
+
+  gpr_mu_init(&chand->mu);
+  grpc_closure_init(&chand->on_resolver_result_changed,
+                    on_resolver_result_changed, chand);
+  chand->owning_stack = args->channel_stack;
+
+  grpc_connectivity_state_init(&chand->state_tracker, GRPC_CHANNEL_IDLE,
+                               "client_channel");
+  chand->interested_parties = grpc_pollset_set_create();
+}
+
+/* Destructor for channel_data */
+static void cc_destroy_channel_elem(grpc_exec_ctx *exec_ctx,
+                                    grpc_channel_element *elem) {
+  channel_data *chand = elem->channel_data;
+
+  if (chand->resolver != NULL) {
+    grpc_resolver_shutdown(exec_ctx, chand->resolver);
+    GRPC_RESOLVER_UNREF(exec_ctx, chand->resolver, "channel");
+  }
+  if (chand->lb_policy != NULL) {
+    grpc_pollset_set_del_pollset_set(exec_ctx,
+                                     chand->lb_policy->interested_parties,
+                                     chand->interested_parties);
+    GRPC_LB_POLICY_UNREF(exec_ctx, chand->lb_policy, "channel");
+  }
+  grpc_connectivity_state_destroy(exec_ctx, &chand->state_tracker);
+  grpc_pollset_set_destroy(chand->interested_parties);
+  gpr_mu_destroy(&chand->mu);
+}
+
+/*************************************************************************
+ * PER-CALL FUNCTIONS
+ */
+
+#define GET_CALL(call_data) \
+  ((grpc_subchannel_call *)(gpr_atm_acq_load(&(call_data)->subchannel_call)))
+
+#define CANCELLED_CALL ((grpc_subchannel_call *)1)
+
+typedef enum {
+  GRPC_SUBCHANNEL_CALL_HOLDER_NOT_CREATING,
+  GRPC_SUBCHANNEL_CALL_HOLDER_PICKING_SUBCHANNEL
+} subchannel_creation_phase;
+
+/** Call data.  Holds a pointer to grpc_subchannel_call and the
+    associated machinery to create such a pointer.
+    Handles queueing of stream ops until a call object is ready, waiting
+    for initial metadata before trying to create a call object,
+    and handling cancellation gracefully. */
+typedef struct client_channel_call_data {
+  /** either 0 for no call, 1 for cancelled, or a pointer to a
+      grpc_subchannel_call */
+  gpr_atm subchannel_call;
+
+  gpr_mu mu;
+
+  subchannel_creation_phase creation_phase;
+  grpc_connected_subchannel *connected_subchannel;
+  grpc_polling_entity *pollent;
+
+  grpc_transport_stream_op **waiting_ops;
+  size_t waiting_ops_count;
+  size_t waiting_ops_capacity;
+
+  grpc_closure next_step;
+
+  grpc_call_stack *owning_call;
+} call_data;
+
+static void add_waiting_locked(call_data *calld, grpc_transport_stream_op *op) {
+  GPR_TIMER_BEGIN("add_waiting_locked", 0);
+  if (calld->waiting_ops_count == calld->waiting_ops_capacity) {
+    calld->waiting_ops_capacity = GPR_MAX(3, 2 * calld->waiting_ops_capacity);
+    calld->waiting_ops =
+        gpr_realloc(calld->waiting_ops,
+                    calld->waiting_ops_capacity * sizeof(*calld->waiting_ops));
+  }
+  calld->waiting_ops[calld->waiting_ops_count++] = op;
+  GPR_TIMER_END("add_waiting_locked", 0);
+}
+
+static void fail_locked(grpc_exec_ctx *exec_ctx, call_data *calld,
+                        grpc_error *error) {
+  size_t i;
+  for (i = 0; i < calld->waiting_ops_count; i++) {
+    grpc_transport_stream_op_finish_with_failure(
+        exec_ctx, calld->waiting_ops[i], GRPC_ERROR_REF(error));
+  }
+  calld->waiting_ops_count = 0;
+  GRPC_ERROR_UNREF(error);
+}
+
+typedef struct {
+  grpc_transport_stream_op **ops;
+  size_t nops;
+  grpc_subchannel_call *call;
+} retry_ops_args;
+
+static void retry_ops(grpc_exec_ctx *exec_ctx, void *args, grpc_error *error) {
+  retry_ops_args *a = args;
+  size_t i;
+  for (i = 0; i < a->nops; i++) {
+    grpc_subchannel_call_process_op(exec_ctx, a->call, a->ops[i]);
+  }
+  GRPC_SUBCHANNEL_CALL_UNREF(exec_ctx, a->call, "retry_ops");
+  gpr_free(a->ops);
+  gpr_free(a);
+}
+
+static void retry_waiting_locked(grpc_exec_ctx *exec_ctx, call_data *calld) {
+  if (calld->waiting_ops_count == 0) {
+    return;
+  }
+
+  retry_ops_args *a = gpr_malloc(sizeof(*a));
+  a->ops = calld->waiting_ops;
+  a->nops = calld->waiting_ops_count;
+  a->call = GET_CALL(calld);
+  if (a->call == CANCELLED_CALL) {
+    gpr_free(a);
+    fail_locked(exec_ctx, calld, GRPC_ERROR_CANCELLED);
+    return;
+  }
+  calld->waiting_ops = NULL;
+  calld->waiting_ops_count = 0;
+  calld->waiting_ops_capacity = 0;
+  GRPC_SUBCHANNEL_CALL_REF(a->call, "retry_ops");
+  grpc_exec_ctx_sched(exec_ctx, grpc_closure_create(retry_ops, a),
+                      GRPC_ERROR_NONE, NULL);
+}
+
+static void subchannel_ready(grpc_exec_ctx *exec_ctx, void *arg,
+                             grpc_error *error) {
+  call_data *calld = arg;
+  gpr_mu_lock(&calld->mu);
+  GPR_ASSERT(calld->creation_phase ==
+             GRPC_SUBCHANNEL_CALL_HOLDER_PICKING_SUBCHANNEL);
+  calld->creation_phase = GRPC_SUBCHANNEL_CALL_HOLDER_NOT_CREATING;
+  if (calld->connected_subchannel == NULL) {
+    gpr_atm_no_barrier_store(&calld->subchannel_call, 1);
+    fail_locked(exec_ctx, calld, GRPC_ERROR_CREATE_REFERENCING(
+                                     "Failed to create subchannel", &error, 1));
+  } else if (1 == gpr_atm_acq_load(&calld->subchannel_call)) {
+    /* already cancelled before subchannel became ready */
+    fail_locked(exec_ctx, calld,
+                GRPC_ERROR_CREATE_REFERENCING(
+                    "Cancelled before creating subchannel", &error, 1));
+  } else {
+    grpc_subchannel_call *subchannel_call = NULL;
+    grpc_error *new_error = grpc_connected_subchannel_create_call(
+        exec_ctx, calld->connected_subchannel, calld->pollent,
+        &subchannel_call);
+    if (new_error != GRPC_ERROR_NONE) {
+      new_error = grpc_error_add_child(new_error, error);
+      subchannel_call = CANCELLED_CALL;
+      fail_locked(exec_ctx, calld, new_error);
+    }
+    gpr_atm_rel_store(&calld->subchannel_call,
+                      (gpr_atm)(uintptr_t)subchannel_call);
+    retry_waiting_locked(exec_ctx, calld);
+  }
+  gpr_mu_unlock(&calld->mu);
+  GRPC_CALL_STACK_UNREF(exec_ctx, calld->owning_call, "pick_subchannel");
+}
+
+static char *cc_get_peer(grpc_exec_ctx *exec_ctx, grpc_call_element *elem) {
+  call_data *calld = elem->call_data;
+  grpc_subchannel_call *subchannel_call = GET_CALL(calld);
+  if (subchannel_call == NULL || subchannel_call == CANCELLED_CALL) {
+    return NULL;
+  } else {
+    return grpc_subchannel_call_get_peer(exec_ctx, subchannel_call);
+  }
 }
 
 typedef struct {
@@ -341,11 +511,11 @@
   grpc_closure closure;
 } continue_picking_args;
 
-static int cc_pick_subchannel(grpc_exec_ctx *exec_ctx, void *arg,
-                              grpc_metadata_batch *initial_metadata,
-                              uint32_t initial_metadata_flags,
-                              grpc_connected_subchannel **connected_subchannel,
-                              grpc_closure *on_ready);
+static bool pick_subchannel(grpc_exec_ctx *exec_ctx, grpc_call_element *elem,
+                            grpc_metadata_batch *initial_metadata,
+                            uint32_t initial_metadata_flags,
+                            grpc_connected_subchannel **connected_subchannel,
+                            grpc_closure *on_ready);
 
 static void continue_picking(grpc_exec_ctx *exec_ctx, void *arg,
                              grpc_error *error) {
@@ -354,22 +524,21 @@
     /* cancelled, do nothing */
   } else if (error != GRPC_ERROR_NONE) {
     grpc_exec_ctx_sched(exec_ctx, cpa->on_ready, GRPC_ERROR_REF(error), NULL);
-  } else if (cc_pick_subchannel(exec_ctx, cpa->elem, cpa->initial_metadata,
-                                cpa->initial_metadata_flags,
-                                cpa->connected_subchannel, cpa->on_ready)) {
+  } else if (pick_subchannel(exec_ctx, cpa->elem, cpa->initial_metadata,
+                             cpa->initial_metadata_flags,
+                             cpa->connected_subchannel, cpa->on_ready)) {
     grpc_exec_ctx_sched(exec_ctx, cpa->on_ready, GRPC_ERROR_NONE, NULL);
   }
   gpr_free(cpa);
 }
 
-static int cc_pick_subchannel(grpc_exec_ctx *exec_ctx, void *elemp,
-                              grpc_metadata_batch *initial_metadata,
-                              uint32_t initial_metadata_flags,
-                              grpc_connected_subchannel **connected_subchannel,
-                              grpc_closure *on_ready) {
-  GPR_TIMER_BEGIN("cc_pick_subchannel", 0);
+static bool pick_subchannel(grpc_exec_ctx *exec_ctx, grpc_call_element *elem,
+                            grpc_metadata_batch *initial_metadata,
+                            uint32_t initial_metadata_flags,
+                            grpc_connected_subchannel **connected_subchannel,
+                            grpc_closure *on_ready) {
+  GPR_TIMER_BEGIN("pick_subchannel", 0);
 
-  grpc_call_element *elem = elemp;
   channel_data *chand = elem->channel_data;
   call_data *calld = elem->call_data;
   continue_picking_args *cpa;
@@ -377,7 +546,7 @@
 
   GPR_ASSERT(connected_subchannel);
 
-  gpr_mu_lock(&chand->mu_config);
+  gpr_mu_lock(&chand->mu);
   if (initial_metadata == NULL) {
     if (chand->lb_policy != NULL) {
       grpc_lb_policy_cancel_pick(exec_ctx, chand->lb_policy,
@@ -392,28 +561,27 @@
                             GRPC_ERROR_CREATE("Pick cancelled"), NULL);
       }
     }
-    gpr_mu_unlock(&chand->mu_config);
-    GPR_TIMER_END("cc_pick_subchannel", 0);
-    return 1;
+    gpr_mu_unlock(&chand->mu);
+    GPR_TIMER_END("pick_subchannel", 0);
+    return true;
   }
   if (chand->lb_policy != NULL) {
     grpc_lb_policy *lb_policy = chand->lb_policy;
     int r;
-    GRPC_LB_POLICY_REF(lb_policy, "cc_pick_subchannel");
-    gpr_mu_unlock(&chand->mu_config);
+    GRPC_LB_POLICY_REF(lb_policy, "pick_subchannel");
+    gpr_mu_unlock(&chand->mu);
     r = grpc_lb_policy_pick(exec_ctx, lb_policy, calld->pollent,
                             initial_metadata, initial_metadata_flags,
                             connected_subchannel, on_ready);
-    GRPC_LB_POLICY_UNREF(exec_ctx, lb_policy, "cc_pick_subchannel");
-    GPR_TIMER_END("cc_pick_subchannel", 0);
+    GRPC_LB_POLICY_UNREF(exec_ctx, lb_policy, "pick_subchannel");
+    GPR_TIMER_END("pick_subchannel", 0);
     return r;
   }
   if (chand->resolver != NULL && !chand->started_resolving) {
-    chand->started_resolving = 1;
+    chand->started_resolving = true;
     GRPC_CHANNEL_STACK_REF(chand->owning_stack, "resolver");
-    grpc_resolver_next(exec_ctx, chand->resolver,
-                       &chand->incoming_configuration,
-                       &chand->on_config_changed);
+    grpc_resolver_next(exec_ctx, chand->resolver, &chand->resolver_result,
+                       &chand->on_resolver_result_changed);
   }
   if (chand->resolver != NULL) {
     cpa = gpr_malloc(sizeof(*cpa));
@@ -429,69 +597,147 @@
     grpc_exec_ctx_sched(exec_ctx, on_ready, GRPC_ERROR_CREATE("Disconnected"),
                         NULL);
   }
-  gpr_mu_unlock(&chand->mu_config);
+  gpr_mu_unlock(&chand->mu);
 
-  GPR_TIMER_END("cc_pick_subchannel", 0);
-  return 0;
+  GPR_TIMER_END("pick_subchannel", 0);
+  return false;
+}
+
+// The logic here is fairly complicated, due to (a) the fact that we
+// need to handle the case where we receive the send op before the
+// initial metadata op, and (b) the need for efficiency, especially in
+// the streaming case.
+// TODO(ctiller): Explain this more thoroughly.
+static void cc_start_transport_stream_op(grpc_exec_ctx *exec_ctx,
+                                         grpc_call_element *elem,
+                                         grpc_transport_stream_op *op) {
+  call_data *calld = elem->call_data;
+  GRPC_CALL_LOG_OP(GPR_INFO, elem, op);
+  /* try to (atomically) get the call */
+  grpc_subchannel_call *call = GET_CALL(calld);
+  GPR_TIMER_BEGIN("cc_start_transport_stream_op", 0);
+  if (call == CANCELLED_CALL) {
+    grpc_transport_stream_op_finish_with_failure(exec_ctx, op,
+                                                 GRPC_ERROR_CANCELLED);
+    GPR_TIMER_END("cc_start_transport_stream_op", 0);
+    return;
+  }
+  if (call != NULL) {
+    grpc_subchannel_call_process_op(exec_ctx, call, op);
+    GPR_TIMER_END("cc_start_transport_stream_op", 0);
+    return;
+  }
+  /* we failed; lock and figure out what to do */
+  gpr_mu_lock(&calld->mu);
+retry:
+  /* need to recheck that another thread hasn't set the call */
+  call = GET_CALL(calld);
+  if (call == CANCELLED_CALL) {
+    gpr_mu_unlock(&calld->mu);
+    grpc_transport_stream_op_finish_with_failure(exec_ctx, op,
+                                                 GRPC_ERROR_CANCELLED);
+    GPR_TIMER_END("cc_start_transport_stream_op", 0);
+    return;
+  }
+  if (call != NULL) {
+    gpr_mu_unlock(&calld->mu);
+    grpc_subchannel_call_process_op(exec_ctx, call, op);
+    GPR_TIMER_END("cc_start_transport_stream_op", 0);
+    return;
+  }
+  /* if this is a cancellation, then we can raise our cancelled flag */
+  if (op->cancel_error != GRPC_ERROR_NONE) {
+    if (!gpr_atm_rel_cas(&calld->subchannel_call, 0,
+                         (gpr_atm)(uintptr_t)CANCELLED_CALL)) {
+      goto retry;
+    } else {
+      switch (calld->creation_phase) {
+        case GRPC_SUBCHANNEL_CALL_HOLDER_NOT_CREATING:
+          fail_locked(exec_ctx, calld, GRPC_ERROR_REF(op->cancel_error));
+          break;
+        case GRPC_SUBCHANNEL_CALL_HOLDER_PICKING_SUBCHANNEL:
+          pick_subchannel(exec_ctx, elem, NULL, 0, &calld->connected_subchannel,
+                          NULL);
+          break;
+      }
+      gpr_mu_unlock(&calld->mu);
+      grpc_transport_stream_op_finish_with_failure(exec_ctx, op,
+                                                   GRPC_ERROR_CANCELLED);
+      GPR_TIMER_END("cc_start_transport_stream_op", 0);
+      return;
+    }
+  }
+  /* if we don't have a subchannel, try to get one */
+  if (calld->creation_phase == GRPC_SUBCHANNEL_CALL_HOLDER_NOT_CREATING &&
+      calld->connected_subchannel == NULL &&
+      op->send_initial_metadata != NULL) {
+    calld->creation_phase = GRPC_SUBCHANNEL_CALL_HOLDER_PICKING_SUBCHANNEL;
+    grpc_closure_init(&calld->next_step, subchannel_ready, calld);
+    GRPC_CALL_STACK_REF(calld->owning_call, "pick_subchannel");
+    if (pick_subchannel(exec_ctx, elem, op->send_initial_metadata,
+                        op->send_initial_metadata_flags,
+                        &calld->connected_subchannel, &calld->next_step)) {
+      calld->creation_phase = GRPC_SUBCHANNEL_CALL_HOLDER_NOT_CREATING;
+      GRPC_CALL_STACK_UNREF(exec_ctx, calld->owning_call, "pick_subchannel");
+    }
+  }
+  /* if we've got a subchannel, then let's ask it to create a call */
+  if (calld->creation_phase == GRPC_SUBCHANNEL_CALL_HOLDER_NOT_CREATING &&
+      calld->connected_subchannel != NULL) {
+    grpc_subchannel_call *subchannel_call = NULL;
+    grpc_error *error = grpc_connected_subchannel_create_call(
+        exec_ctx, calld->connected_subchannel, calld->pollent,
+        &subchannel_call);
+    if (error != GRPC_ERROR_NONE) {
+      subchannel_call = CANCELLED_CALL;
+      fail_locked(exec_ctx, calld, GRPC_ERROR_REF(error));
+      grpc_transport_stream_op_finish_with_failure(exec_ctx, op, error);
+    }
+    gpr_atm_rel_store(&calld->subchannel_call,
+                      (gpr_atm)(uintptr_t)subchannel_call);
+    retry_waiting_locked(exec_ctx, calld);
+    goto retry;
+  }
+  /* nothing to be done but wait */
+  add_waiting_locked(calld, op);
+  gpr_mu_unlock(&calld->mu);
+  GPR_TIMER_END("cc_start_transport_stream_op", 0);
 }
 
 /* Constructor for call_data */
-static grpc_error *init_call_elem(grpc_exec_ctx *exec_ctx,
-                                  grpc_call_element *elem,
-                                  grpc_call_element_args *args) {
-  grpc_subchannel_call_holder_init(elem->call_data, cc_pick_subchannel, elem,
-                                   args->call_stack);
+static grpc_error *cc_init_call_elem(grpc_exec_ctx *exec_ctx,
+                                     grpc_call_element *elem,
+                                     grpc_call_element_args *args) {
+  call_data *calld = elem->call_data;
+  gpr_atm_rel_store(&calld->subchannel_call, 0);
+  gpr_mu_init(&calld->mu);
+  calld->connected_subchannel = NULL;
+  calld->waiting_ops = NULL;
+  calld->waiting_ops_count = 0;
+  calld->waiting_ops_capacity = 0;
+  calld->creation_phase = GRPC_SUBCHANNEL_CALL_HOLDER_NOT_CREATING;
+  calld->owning_call = args->call_stack;
+  calld->pollent = NULL;
   return GRPC_ERROR_NONE;
 }
 
 /* Destructor for call_data */
-static void destroy_call_elem(grpc_exec_ctx *exec_ctx, grpc_call_element *elem,
-                              const grpc_call_final_info *final_info,
-                              void *and_free_memory) {
-  grpc_subchannel_call_holder_destroy(exec_ctx, elem->call_data);
+static void cc_destroy_call_elem(grpc_exec_ctx *exec_ctx,
+                                 grpc_call_element *elem,
+                                 const grpc_call_final_info *final_info,
+                                 void *and_free_memory) {
+  call_data *calld = elem->call_data;
+  grpc_subchannel_call *call = GET_CALL(calld);
+  if (call != NULL && call != CANCELLED_CALL) {
+    GRPC_SUBCHANNEL_CALL_UNREF(exec_ctx, call, "client_channel_destroy_call");
+  }
+  GPR_ASSERT(calld->creation_phase == GRPC_SUBCHANNEL_CALL_HOLDER_NOT_CREATING);
+  gpr_mu_destroy(&calld->mu);
+  GPR_ASSERT(calld->waiting_ops_count == 0);
+  gpr_free(calld->waiting_ops);
   gpr_free(and_free_memory);
 }
 
-/* Constructor for channel_data */
-static void init_channel_elem(grpc_exec_ctx *exec_ctx,
-                              grpc_channel_element *elem,
-                              grpc_channel_element_args *args) {
-  channel_data *chand = elem->channel_data;
-
-  memset(chand, 0, sizeof(*chand));
-
-  GPR_ASSERT(args->is_last);
-  GPR_ASSERT(elem->filter == &grpc_client_channel_filter);
-
-  gpr_mu_init(&chand->mu_config);
-  grpc_closure_init(&chand->on_config_changed, cc_on_config_changed, chand);
-  chand->owning_stack = args->channel_stack;
-
-  grpc_connectivity_state_init(&chand->state_tracker, GRPC_CHANNEL_IDLE,
-                               "client_channel");
-  chand->interested_parties = grpc_pollset_set_create();
-}
-
-/* Destructor for channel_data */
-static void destroy_channel_elem(grpc_exec_ctx *exec_ctx,
-                                 grpc_channel_element *elem) {
-  channel_data *chand = elem->channel_data;
-
-  if (chand->resolver != NULL) {
-    grpc_resolver_shutdown(exec_ctx, chand->resolver);
-    GRPC_RESOLVER_UNREF(exec_ctx, chand->resolver, "channel");
-  }
-  if (chand->lb_policy != NULL) {
-    grpc_pollset_set_del_pollset_set(exec_ctx,
-                                     chand->lb_policy->interested_parties,
-                                     chand->interested_parties);
-    GRPC_LB_POLICY_UNREF(exec_ctx, chand->lb_policy, "channel");
-  }
-  grpc_connectivity_state_destroy(exec_ctx, &chand->state_tracker);
-  grpc_pollset_set_destroy(chand->interested_parties);
-  gpr_mu_destroy(&chand->mu_config);
-}
-
 static void cc_set_pollset_or_pollset_set(grpc_exec_ctx *exec_ctx,
                                           grpc_call_element *elem,
                                           grpc_polling_entity *pollent) {
@@ -499,16 +745,20 @@
   calld->pollent = pollent;
 }
 
+/*************************************************************************
+ * EXPORTED SYMBOLS
+ */
+
 const grpc_channel_filter grpc_client_channel_filter = {
     cc_start_transport_stream_op,
     cc_start_transport_op,
     sizeof(call_data),
-    init_call_elem,
+    cc_init_call_elem,
     cc_set_pollset_or_pollset_set,
-    destroy_call_elem,
+    cc_destroy_call_elem,
     sizeof(channel_data),
-    init_channel_elem,
-    destroy_channel_elem,
+    cc_init_channel_elem,
+    cc_destroy_channel_elem,
     cc_get_peer,
     "client-channel",
 };
@@ -519,41 +769,40 @@
   /* post construction initialization: set the transport setup pointer */
   grpc_channel_element *elem = grpc_channel_stack_last_element(channel_stack);
   channel_data *chand = elem->channel_data;
-  gpr_mu_lock(&chand->mu_config);
+  gpr_mu_lock(&chand->mu);
   GPR_ASSERT(!chand->resolver);
   chand->resolver = resolver;
   GRPC_RESOLVER_REF(resolver, "channel");
   if (!grpc_closure_list_empty(chand->waiting_for_config_closures) ||
       chand->exit_idle_when_lb_policy_arrives) {
-    chand->started_resolving = 1;
+    chand->started_resolving = true;
     GRPC_CHANNEL_STACK_REF(chand->owning_stack, "resolver");
-    grpc_resolver_next(exec_ctx, resolver, &chand->incoming_configuration,
-                       &chand->on_config_changed);
+    grpc_resolver_next(exec_ctx, resolver, &chand->resolver_result,
+                       &chand->on_resolver_result_changed);
   }
-  gpr_mu_unlock(&chand->mu_config);
+  gpr_mu_unlock(&chand->mu);
 }
 
 grpc_connectivity_state grpc_client_channel_check_connectivity_state(
     grpc_exec_ctx *exec_ctx, grpc_channel_element *elem, int try_to_connect) {
   channel_data *chand = elem->channel_data;
   grpc_connectivity_state out;
-  gpr_mu_lock(&chand->mu_config);
+  gpr_mu_lock(&chand->mu);
   out = grpc_connectivity_state_check(&chand->state_tracker, NULL);
   if (out == GRPC_CHANNEL_IDLE && try_to_connect) {
     if (chand->lb_policy != NULL) {
       grpc_lb_policy_exit_idle(exec_ctx, chand->lb_policy);
     } else {
-      chand->exit_idle_when_lb_policy_arrives = 1;
+      chand->exit_idle_when_lb_policy_arrives = true;
       if (!chand->started_resolving && chand->resolver != NULL) {
         GRPC_CHANNEL_STACK_REF(chand->owning_stack, "resolver");
-        chand->started_resolving = 1;
-        grpc_resolver_next(exec_ctx, chand->resolver,
-                           &chand->incoming_configuration,
-                           &chand->on_config_changed);
+        chand->started_resolving = true;
+        grpc_resolver_next(exec_ctx, chand->resolver, &chand->resolver_result,
+                           &chand->on_resolver_result_changed);
       }
     }
   }
-  gpr_mu_unlock(&chand->mu_config);
+  gpr_mu_unlock(&chand->mu);
   return out;
 }
 
@@ -588,8 +837,8 @@
   grpc_closure_init(&w->my_closure, on_external_watch_complete, w);
   GRPC_CHANNEL_STACK_REF(w->chand->owning_stack,
                          "external_connectivity_watcher");
-  gpr_mu_lock(&chand->mu_config);
+  gpr_mu_lock(&chand->mu);
   grpc_connectivity_state_notify_on_state_change(
       exec_ctx, &chand->state_tracker, state, &w->my_closure);
-  gpr_mu_unlock(&chand->mu_config);
+  gpr_mu_unlock(&chand->mu);
 }
diff --git a/src/core/ext/client_config/lb_policy_factory.h b/src/core/ext/client_config/lb_policy_factory.h
index 1c89b28..da1de35 100644
--- a/src/core/ext/client_config/lb_policy_factory.h
+++ b/src/core/ext/client_config/lb_policy_factory.h
@@ -43,8 +43,6 @@
 typedef struct grpc_lb_policy_factory grpc_lb_policy_factory;
 typedef struct grpc_lb_policy_factory_vtable grpc_lb_policy_factory_vtable;
 
-/** grpc_lb_policy provides grpc_client_config objects to grpc_channel
-    objects */
 struct grpc_lb_policy_factory {
   const grpc_lb_policy_factory_vtable *vtable;
 };
diff --git a/src/core/ext/client_config/resolver.c b/src/core/ext/client_config/resolver.c
index eb00445..7534ea6 100644
--- a/src/core/ext/client_config/resolver.c
+++ b/src/core/ext/client_config/resolver.c
@@ -76,7 +76,7 @@
 }
 
 void grpc_resolver_next(grpc_exec_ctx *exec_ctx, grpc_resolver *resolver,
-                        grpc_client_config **target_config,
+                        grpc_resolver_result **result,
                         grpc_closure *on_complete) {
-  resolver->vtable->next(exec_ctx, resolver, target_config, on_complete);
+  resolver->vtable->next(exec_ctx, resolver, result, on_complete);
 }
diff --git a/src/core/ext/client_config/resolver.h b/src/core/ext/client_config/resolver.h
index 6ecb5d2..88ac262 100644
--- a/src/core/ext/client_config/resolver.h
+++ b/src/core/ext/client_config/resolver.h
@@ -34,14 +34,14 @@
 #ifndef GRPC_CORE_EXT_CLIENT_CONFIG_RESOLVER_H
 #define GRPC_CORE_EXT_CLIENT_CONFIG_RESOLVER_H
 
-#include "src/core/ext/client_config/client_config.h"
+#include "src/core/ext/client_config/resolver_result.h"
 #include "src/core/ext/client_config/subchannel.h"
 #include "src/core/lib/iomgr/iomgr.h"
 
 typedef struct grpc_resolver grpc_resolver;
 typedef struct grpc_resolver_vtable grpc_resolver_vtable;
 
-/** grpc_resolver provides grpc_client_config objects to grpc_channel
+/** grpc_resolver provides grpc_resolver_result objects to grpc_channel
     objects */
 struct grpc_resolver {
   const grpc_resolver_vtable *vtable;
@@ -53,7 +53,7 @@
   void (*shutdown)(grpc_exec_ctx *exec_ctx, grpc_resolver *resolver);
   void (*channel_saw_error)(grpc_exec_ctx *exec_ctx, grpc_resolver *resolver);
   void (*next)(grpc_exec_ctx *exec_ctx, grpc_resolver *resolver,
-               grpc_client_config **target_config, grpc_closure *on_complete);
+               grpc_resolver_result **result, grpc_closure *on_complete);
 };
 
 #ifdef GRPC_RESOLVER_REFCOUNT_DEBUG
@@ -82,13 +82,13 @@
                                      grpc_resolver *resolver);
 
 /** Get the next client config. Called by the channel to fetch a new
-    configuration. Expected to set *target_config with a new configuration,
+    configuration. Expected to set *result with a new configuration,
     and then schedule on_complete for execution.
 
-    If resolution is fatally broken, set *target_config to NULL and
+    If resolution is fatally broken, set *result to NULL and
     schedule on_complete. */
 void grpc_resolver_next(grpc_exec_ctx *exec_ctx, grpc_resolver *resolver,
-                        grpc_client_config **target_config,
+                        grpc_resolver_result **result,
                         grpc_closure *on_complete);
 
 #endif /* GRPC_CORE_EXT_CLIENT_CONFIG_RESOLVER_H */
diff --git a/src/core/ext/client_config/resolver_factory.h b/src/core/ext/client_config/resolver_factory.h
index 4eb6979..f69bf79 100644
--- a/src/core/ext/client_config/resolver_factory.h
+++ b/src/core/ext/client_config/resolver_factory.h
@@ -41,7 +41,7 @@
 typedef struct grpc_resolver_factory grpc_resolver_factory;
 typedef struct grpc_resolver_factory_vtable grpc_resolver_factory_vtable;
 
-/** grpc_resolver provides grpc_client_config objects to grpc_channel
+/** grpc_resolver provides grpc_resolver_result objects to grpc_channel
     objects */
 struct grpc_resolver_factory {
   const grpc_resolver_factory_vtable *vtable;
diff --git a/src/core/ext/client_config/client_config.c b/src/core/ext/client_config/resolver_result.c
similarity index 72%
rename from src/core/ext/client_config/client_config.c
rename to src/core/ext/client_config/resolver_result.c
index f9b8e68..c6c4166 100644
--- a/src/core/ext/client_config/client_config.c
+++ b/src/core/ext/client_config/resolver_result.c
@@ -31,44 +31,45 @@
  *
  */
 
-#include "src/core/ext/client_config/client_config.h"
+#include "src/core/ext/client_config/resolver_result.h"
 
 #include <string.h>
 
 #include <grpc/support/alloc.h>
 
-struct grpc_client_config {
+struct grpc_resolver_result {
   gpr_refcount refs;
   grpc_lb_policy *lb_policy;
 };
 
-grpc_client_config *grpc_client_config_create() {
-  grpc_client_config *c = gpr_malloc(sizeof(*c));
+grpc_resolver_result *grpc_resolver_result_create() {
+  grpc_resolver_result *c = gpr_malloc(sizeof(*c));
   memset(c, 0, sizeof(*c));
   gpr_ref_init(&c->refs, 1);
   return c;
 }
 
-void grpc_client_config_ref(grpc_client_config *c) { gpr_ref(&c->refs); }
+void grpc_resolver_result_ref(grpc_resolver_result *c) { gpr_ref(&c->refs); }
 
-void grpc_client_config_unref(grpc_exec_ctx *exec_ctx, grpc_client_config *c) {
+void grpc_resolver_result_unref(grpc_exec_ctx *exec_ctx,
+                                grpc_resolver_result *c) {
   if (gpr_unref(&c->refs)) {
     if (c->lb_policy != NULL) {
-      GRPC_LB_POLICY_UNREF(exec_ctx, c->lb_policy, "client_config");
+      GRPC_LB_POLICY_UNREF(exec_ctx, c->lb_policy, "resolver_result");
     }
     gpr_free(c);
   }
 }
 
-void grpc_client_config_set_lb_policy(grpc_client_config *c,
-                                      grpc_lb_policy *lb_policy) {
+void grpc_resolver_result_set_lb_policy(grpc_resolver_result *c,
+                                        grpc_lb_policy *lb_policy) {
   GPR_ASSERT(c->lb_policy == NULL);
   if (lb_policy) {
-    GRPC_LB_POLICY_REF(lb_policy, "client_config");
+    GRPC_LB_POLICY_REF(lb_policy, "resolver_result");
   }
   c->lb_policy = lb_policy;
 }
 
-grpc_lb_policy *grpc_client_config_get_lb_policy(grpc_client_config *c) {
+grpc_lb_policy *grpc_resolver_result_get_lb_policy(grpc_resolver_result *c) {
   return c->lb_policy;
 }
diff --git a/src/core/ext/client_config/client_config.h b/src/core/ext/client_config/resolver_result.h
similarity index 67%
rename from src/core/ext/client_config/client_config.h
rename to src/core/ext/client_config/resolver_result.h
index a6290cb..402f7db 100644
--- a/src/core/ext/client_config/client_config.h
+++ b/src/core/ext/client_config/resolver_result.h
@@ -31,23 +31,22 @@
  *
  */
 
-#ifndef GRPC_CORE_EXT_CLIENT_CONFIG_CLIENT_CONFIG_H
-#define GRPC_CORE_EXT_CLIENT_CONFIG_CLIENT_CONFIG_H
+#ifndef GRPC_CORE_EXT_CLIENT_CONFIG_RESOLVER_RESULT_H
+#define GRPC_CORE_EXT_CLIENT_CONFIG_RESOLVER_RESULT_H
 
 #include "src/core/ext/client_config/lb_policy.h"
 
-/** Total configuration for a client. Provided, and updated, by
-    grpc_resolver */
-typedef struct grpc_client_config grpc_client_config;
+/** Results reported from a grpc_resolver. */
+typedef struct grpc_resolver_result grpc_resolver_result;
 
-grpc_client_config *grpc_client_config_create();
-void grpc_client_config_ref(grpc_client_config *client_config);
-void grpc_client_config_unref(grpc_exec_ctx *exec_ctx,
-                              grpc_client_config *client_config);
+grpc_resolver_result *grpc_resolver_result_create();
+void grpc_resolver_result_ref(grpc_resolver_result *client_config);
+void grpc_resolver_result_unref(grpc_exec_ctx *exec_ctx,
+                                grpc_resolver_result *client_config);
 
-void grpc_client_config_set_lb_policy(grpc_client_config *client_config,
-                                      grpc_lb_policy *lb_policy);
-grpc_lb_policy *grpc_client_config_get_lb_policy(
-    grpc_client_config *client_config);
+void grpc_resolver_result_set_lb_policy(grpc_resolver_result *client_config,
+                                        grpc_lb_policy *lb_policy);
+grpc_lb_policy *grpc_resolver_result_get_lb_policy(
+    grpc_resolver_result *client_config);
 
-#endif /* GRPC_CORE_EXT_CLIENT_CONFIG_CLIENT_CONFIG_H */
+#endif /* GRPC_CORE_EXT_CLIENT_CONFIG_RESOLVER_RESULT_H */
diff --git a/src/core/ext/client_config/subchannel.c b/src/core/ext/client_config/subchannel.c
index df35904..e622862 100644
--- a/src/core/ext/client_config/subchannel.c
+++ b/src/core/ext/client_config/subchannel.c
@@ -219,8 +219,8 @@
                             : gpr_atm_no_barrier_fetch_add(&c->ref_pair, delta);
 #ifdef GRPC_STREAM_REFCOUNT_DEBUG
   gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG,
-          "SUBCHANNEL: %p % 12s 0x%08x -> 0x%08x [%s]", c, purpose, old_val,
-          old_val + delta, reason);
+          "SUBCHANNEL: %p %s 0x%08" PRIxPTR " -> 0x%08" PRIxPTR " [%s]", c,
+          purpose, old_val, old_val + delta, reason);
 #endif
   return old_val;
 }
@@ -504,14 +504,13 @@
                                           grpc_pollset_set *interested_parties,
                                           grpc_connectivity_state *state,
                                           grpc_closure *closure) {
-  grpc_transport_op op;
+  grpc_transport_op *op = grpc_make_transport_op(NULL);
   grpc_channel_element *elem;
-  memset(&op, 0, sizeof(op));
-  op.connectivity_state = state;
-  op.on_connectivity_state_change = closure;
-  op.bind_pollset_set = interested_parties;
+  op->connectivity_state = state;
+  op->on_connectivity_state_change = closure;
+  op->bind_pollset_set = interested_parties;
   elem = grpc_channel_stack_element(CHANNEL_STACK_FROM_CONNECTION(con), 0);
-  elem->filter->start_transport_op(exec_ctx, elem, &op);
+  elem->filter->start_transport_op(exec_ctx, elem, op);
 }
 
 void grpc_connected_subchannel_notify_on_state_change(
@@ -525,12 +524,11 @@
 void grpc_connected_subchannel_ping(grpc_exec_ctx *exec_ctx,
                                     grpc_connected_subchannel *con,
                                     grpc_closure *closure) {
-  grpc_transport_op op;
+  grpc_transport_op *op = grpc_make_transport_op(NULL);
   grpc_channel_element *elem;
-  memset(&op, 0, sizeof(op));
-  op.send_ping = closure;
+  op->send_ping = closure;
   elem = grpc_channel_stack_element(CHANNEL_STACK_FROM_CONNECTION(con), 0);
-  elem->filter->start_transport_op(exec_ctx, elem, &op);
+  elem->filter->start_transport_op(exec_ctx, elem, op);
 }
 
 static void publish_transport_locked(grpc_exec_ctx *exec_ctx,
diff --git a/src/core/ext/client_config/subchannel_call_holder.c b/src/core/ext/client_config/subchannel_call_holder.c
deleted file mode 100644
index be6d054..0000000
--- a/src/core/ext/client_config/subchannel_call_holder.c
+++ /dev/null
@@ -1,292 +0,0 @@
-/*
- *
- * Copyright 2015, Google Inc.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- *     * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *     * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#include "src/core/ext/client_config/subchannel_call_holder.h"
-
-#include <grpc/support/alloc.h>
-
-#include "src/core/lib/profiling/timers.h"
-
-#define GET_CALL(holder) \
-  ((grpc_subchannel_call *)(gpr_atm_acq_load(&(holder)->subchannel_call)))
-
-#define CANCELLED_CALL ((grpc_subchannel_call *)1)
-
-static void subchannel_ready(grpc_exec_ctx *exec_ctx, void *holder,
-                             grpc_error *error);
-static void retry_ops(grpc_exec_ctx *exec_ctx, void *retry_ops_args,
-                      grpc_error *error);
-
-static void add_waiting_locked(grpc_subchannel_call_holder *holder,
-                               grpc_transport_stream_op *op);
-static void fail_locked(grpc_exec_ctx *exec_ctx,
-                        grpc_subchannel_call_holder *holder, grpc_error *error);
-static void retry_waiting_locked(grpc_exec_ctx *exec_ctx,
-                                 grpc_subchannel_call_holder *holder);
-
-void grpc_subchannel_call_holder_init(
-    grpc_subchannel_call_holder *holder,
-    grpc_subchannel_call_holder_pick_subchannel pick_subchannel,
-    void *pick_subchannel_arg, grpc_call_stack *owning_call) {
-  gpr_atm_rel_store(&holder->subchannel_call, 0);
-  holder->pick_subchannel = pick_subchannel;
-  holder->pick_subchannel_arg = pick_subchannel_arg;
-  gpr_mu_init(&holder->mu);
-  holder->connected_subchannel = NULL;
-  holder->waiting_ops = NULL;
-  holder->waiting_ops_count = 0;
-  holder->waiting_ops_capacity = 0;
-  holder->creation_phase = GRPC_SUBCHANNEL_CALL_HOLDER_NOT_CREATING;
-  holder->owning_call = owning_call;
-  holder->pollent = NULL;
-}
-
-void grpc_subchannel_call_holder_destroy(grpc_exec_ctx *exec_ctx,
-                                         grpc_subchannel_call_holder *holder) {
-  grpc_subchannel_call *call = GET_CALL(holder);
-  if (call != NULL && call != CANCELLED_CALL) {
-    GRPC_SUBCHANNEL_CALL_UNREF(exec_ctx, call, "holder");
-  }
-  GPR_ASSERT(holder->creation_phase ==
-             GRPC_SUBCHANNEL_CALL_HOLDER_NOT_CREATING);
-  gpr_mu_destroy(&holder->mu);
-  GPR_ASSERT(holder->waiting_ops_count == 0);
-  gpr_free(holder->waiting_ops);
-}
-
-// The logic here is fairly complicated, due to (a) the fact that we
-// need to handle the case where we receive the send op before the
-// initial metadata op, and (b) the need for efficiency, especially in
-// the streaming case.
-// TODO(ctiller): Explain this more thoroughly.
-void grpc_subchannel_call_holder_perform_op(grpc_exec_ctx *exec_ctx,
-                                            grpc_subchannel_call_holder *holder,
-                                            grpc_transport_stream_op *op) {
-  /* try to (atomically) get the call */
-  grpc_subchannel_call *call = GET_CALL(holder);
-  GPR_TIMER_BEGIN("grpc_subchannel_call_holder_perform_op", 0);
-  if (call == CANCELLED_CALL) {
-    grpc_transport_stream_op_finish_with_failure(exec_ctx, op,
-                                                 GRPC_ERROR_CANCELLED);
-    GPR_TIMER_END("grpc_subchannel_call_holder_perform_op", 0);
-    return;
-  }
-  if (call != NULL) {
-    grpc_subchannel_call_process_op(exec_ctx, call, op);
-    GPR_TIMER_END("grpc_subchannel_call_holder_perform_op", 0);
-    return;
-  }
-  /* we failed; lock and figure out what to do */
-  gpr_mu_lock(&holder->mu);
-retry:
-  /* need to recheck that another thread hasn't set the call */
-  call = GET_CALL(holder);
-  if (call == CANCELLED_CALL) {
-    gpr_mu_unlock(&holder->mu);
-    grpc_transport_stream_op_finish_with_failure(exec_ctx, op,
-                                                 GRPC_ERROR_CANCELLED);
-    GPR_TIMER_END("grpc_subchannel_call_holder_perform_op", 0);
-    return;
-  }
-  if (call != NULL) {
-    gpr_mu_unlock(&holder->mu);
-    grpc_subchannel_call_process_op(exec_ctx, call, op);
-    GPR_TIMER_END("grpc_subchannel_call_holder_perform_op", 0);
-    return;
-  }
-  /* if this is a cancellation, then we can raise our cancelled flag */
-  if (op->cancel_error != GRPC_ERROR_NONE) {
-    if (!gpr_atm_rel_cas(&holder->subchannel_call, 0,
-                         (gpr_atm)(uintptr_t)CANCELLED_CALL)) {
-      goto retry;
-    } else {
-      switch (holder->creation_phase) {
-        case GRPC_SUBCHANNEL_CALL_HOLDER_NOT_CREATING:
-          fail_locked(exec_ctx, holder, GRPC_ERROR_REF(op->cancel_error));
-          break;
-        case GRPC_SUBCHANNEL_CALL_HOLDER_PICKING_SUBCHANNEL:
-          holder->pick_subchannel(exec_ctx, holder->pick_subchannel_arg, NULL,
-                                  0, &holder->connected_subchannel, NULL);
-          break;
-      }
-      gpr_mu_unlock(&holder->mu);
-      grpc_transport_stream_op_finish_with_failure(exec_ctx, op,
-                                                   GRPC_ERROR_CANCELLED);
-      GPR_TIMER_END("grpc_subchannel_call_holder_perform_op", 0);
-      return;
-    }
-  }
-  /* if we don't have a subchannel, try to get one */
-  if (holder->creation_phase == GRPC_SUBCHANNEL_CALL_HOLDER_NOT_CREATING &&
-      holder->connected_subchannel == NULL &&
-      op->send_initial_metadata != NULL) {
-    holder->creation_phase = GRPC_SUBCHANNEL_CALL_HOLDER_PICKING_SUBCHANNEL;
-    grpc_closure_init(&holder->next_step, subchannel_ready, holder);
-    GRPC_CALL_STACK_REF(holder->owning_call, "pick_subchannel");
-    if (holder->pick_subchannel(
-            exec_ctx, holder->pick_subchannel_arg, op->send_initial_metadata,
-            op->send_initial_metadata_flags, &holder->connected_subchannel,
-            &holder->next_step)) {
-      holder->creation_phase = GRPC_SUBCHANNEL_CALL_HOLDER_NOT_CREATING;
-      GRPC_CALL_STACK_UNREF(exec_ctx, holder->owning_call, "pick_subchannel");
-    }
-  }
-  /* if we've got a subchannel, then let's ask it to create a call */
-  if (holder->creation_phase == GRPC_SUBCHANNEL_CALL_HOLDER_NOT_CREATING &&
-      holder->connected_subchannel != NULL) {
-    grpc_subchannel_call *subchannel_call = NULL;
-    grpc_error *error = grpc_connected_subchannel_create_call(
-        exec_ctx, holder->connected_subchannel, holder->pollent,
-        &subchannel_call);
-    if (error != GRPC_ERROR_NONE) {
-      subchannel_call = CANCELLED_CALL;
-      fail_locked(exec_ctx, holder, GRPC_ERROR_REF(error));
-      grpc_transport_stream_op_finish_with_failure(exec_ctx, op, error);
-    }
-    gpr_atm_rel_store(&holder->subchannel_call,
-                      (gpr_atm)(uintptr_t)subchannel_call);
-    retry_waiting_locked(exec_ctx, holder);
-    goto retry;
-  }
-  /* nothing to be done but wait */
-  add_waiting_locked(holder, op);
-  gpr_mu_unlock(&holder->mu);
-  GPR_TIMER_END("grpc_subchannel_call_holder_perform_op", 0);
-}
-
-static void subchannel_ready(grpc_exec_ctx *exec_ctx, void *arg,
-                             grpc_error *error) {
-  grpc_subchannel_call_holder *holder = arg;
-  gpr_mu_lock(&holder->mu);
-  GPR_ASSERT(holder->creation_phase ==
-             GRPC_SUBCHANNEL_CALL_HOLDER_PICKING_SUBCHANNEL);
-  holder->creation_phase = GRPC_SUBCHANNEL_CALL_HOLDER_NOT_CREATING;
-  if (holder->connected_subchannel == NULL) {
-    gpr_atm_no_barrier_store(&holder->subchannel_call, 1);
-    fail_locked(exec_ctx, holder,
-                GRPC_ERROR_CREATE_REFERENCING("Failed to create subchannel",
-                                              &error, 1));
-  } else if (1 == gpr_atm_acq_load(&holder->subchannel_call)) {
-    /* already cancelled before subchannel became ready */
-    fail_locked(exec_ctx, holder,
-                GRPC_ERROR_CREATE_REFERENCING(
-                    "Cancelled before creating subchannel", &error, 1));
-  } else {
-    grpc_subchannel_call *subchannel_call = NULL;
-    grpc_error *new_error = grpc_connected_subchannel_create_call(
-        exec_ctx, holder->connected_subchannel, holder->pollent,
-        &subchannel_call);
-    if (new_error != GRPC_ERROR_NONE) {
-      new_error = grpc_error_add_child(new_error, error);
-      subchannel_call = CANCELLED_CALL;
-      fail_locked(exec_ctx, holder, new_error);
-    }
-    gpr_atm_rel_store(&holder->subchannel_call,
-                      (gpr_atm)(uintptr_t)subchannel_call);
-    retry_waiting_locked(exec_ctx, holder);
-  }
-  gpr_mu_unlock(&holder->mu);
-  GRPC_CALL_STACK_UNREF(exec_ctx, holder->owning_call, "pick_subchannel");
-}
-
-typedef struct {
-  grpc_transport_stream_op *ops;
-  size_t nops;
-  grpc_subchannel_call *call;
-} retry_ops_args;
-
-static void retry_waiting_locked(grpc_exec_ctx *exec_ctx,
-                                 grpc_subchannel_call_holder *holder) {
-  retry_ops_args *a = gpr_malloc(sizeof(*a));
-  a->ops = holder->waiting_ops;
-  a->nops = holder->waiting_ops_count;
-  a->call = GET_CALL(holder);
-  if (a->call == CANCELLED_CALL) {
-    gpr_free(a);
-    fail_locked(exec_ctx, holder, GRPC_ERROR_CANCELLED);
-    return;
-  }
-  holder->waiting_ops = NULL;
-  holder->waiting_ops_count = 0;
-  holder->waiting_ops_capacity = 0;
-  GRPC_SUBCHANNEL_CALL_REF(a->call, "retry_ops");
-  grpc_exec_ctx_sched(exec_ctx, grpc_closure_create(retry_ops, a),
-                      GRPC_ERROR_NONE, NULL);
-}
-
-static void retry_ops(grpc_exec_ctx *exec_ctx, void *args, grpc_error *error) {
-  retry_ops_args *a = args;
-  size_t i;
-  for (i = 0; i < a->nops; i++) {
-    grpc_subchannel_call_process_op(exec_ctx, a->call, &a->ops[i]);
-  }
-  GRPC_SUBCHANNEL_CALL_UNREF(exec_ctx, a->call, "retry_ops");
-  gpr_free(a->ops);
-  gpr_free(a);
-}
-
-static void add_waiting_locked(grpc_subchannel_call_holder *holder,
-                               grpc_transport_stream_op *op) {
-  GPR_TIMER_BEGIN("add_waiting_locked", 0);
-  if (holder->waiting_ops_count == holder->waiting_ops_capacity) {
-    holder->waiting_ops_capacity = GPR_MAX(3, 2 * holder->waiting_ops_capacity);
-    holder->waiting_ops =
-        gpr_realloc(holder->waiting_ops, holder->waiting_ops_capacity *
-                                             sizeof(*holder->waiting_ops));
-  }
-  holder->waiting_ops[holder->waiting_ops_count++] = *op;
-  GPR_TIMER_END("add_waiting_locked", 0);
-}
-
-static void fail_locked(grpc_exec_ctx *exec_ctx,
-                        grpc_subchannel_call_holder *holder,
-                        grpc_error *error) {
-  size_t i;
-  for (i = 0; i < holder->waiting_ops_count; i++) {
-    grpc_transport_stream_op_finish_with_failure(
-        exec_ctx, &holder->waiting_ops[i], GRPC_ERROR_REF(error));
-  }
-  holder->waiting_ops_count = 0;
-  GRPC_ERROR_UNREF(error);
-}
-
-char *grpc_subchannel_call_holder_get_peer(
-    grpc_exec_ctx *exec_ctx, grpc_subchannel_call_holder *holder) {
-  grpc_subchannel_call *subchannel_call = GET_CALL(holder);
-
-  if (subchannel_call == NULL || subchannel_call == CANCELLED_CALL) {
-    return NULL;
-  } else {
-    return grpc_subchannel_call_get_peer(exec_ctx, subchannel_call);
-  }
-}
diff --git a/src/core/ext/client_config/subchannel_call_holder.h b/src/core/ext/client_config/subchannel_call_holder.h
deleted file mode 100644
index 8d2deb0..0000000
--- a/src/core/ext/client_config/subchannel_call_holder.h
+++ /dev/null
@@ -1,99 +0,0 @@
-/*
- *
- * Copyright 2015, Google Inc.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- *     * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *     * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#ifndef GRPC_CORE_EXT_CLIENT_CONFIG_SUBCHANNEL_CALL_HOLDER_H
-#define GRPC_CORE_EXT_CLIENT_CONFIG_SUBCHANNEL_CALL_HOLDER_H
-
-#include "src/core/ext/client_config/subchannel.h"
-#include "src/core/lib/iomgr/polling_entity.h"
-
-/** Pick a subchannel for grpc_subchannel_call_holder;
-    Return 1 if subchannel is available immediately (in which case on_ready
-    should not be called), or 0 otherwise (in which case on_ready should be
-    called when the subchannel is available) */
-typedef int (*grpc_subchannel_call_holder_pick_subchannel)(
-    grpc_exec_ctx *exec_ctx, void *arg, grpc_metadata_batch *initial_metadata,
-    uint32_t initial_metadata_flags,
-    grpc_connected_subchannel **connected_subchannel, grpc_closure *on_ready);
-
-typedef enum {
-  GRPC_SUBCHANNEL_CALL_HOLDER_NOT_CREATING,
-  GRPC_SUBCHANNEL_CALL_HOLDER_PICKING_SUBCHANNEL
-} grpc_subchannel_call_holder_creation_phase;
-
-/** Wrapper for holding a pointer to grpc_subchannel_call, and the
-    associated machinery to create such a pointer.
-    Handles queueing of stream ops until a call object is ready, waiting
-    for initial metadata before trying to create a call object,
-    and handling cancellation gracefully.
-
-    The channel filter uses this as their call_data. */
-typedef struct grpc_subchannel_call_holder {
-  /** either 0 for no call, 1 for cancelled, or a pointer to a
-      grpc_subchannel_call */
-  gpr_atm subchannel_call;
-  /** Helper function to choose the subchannel on which to create
-      the call object. Channel filter delegates to the load
-      balancing policy (once it's ready). */
-  grpc_subchannel_call_holder_pick_subchannel pick_subchannel;
-  void *pick_subchannel_arg;
-
-  gpr_mu mu;
-
-  grpc_subchannel_call_holder_creation_phase creation_phase;
-  grpc_connected_subchannel *connected_subchannel;
-  grpc_polling_entity *pollent;
-
-  grpc_transport_stream_op *waiting_ops;
-  size_t waiting_ops_count;
-  size_t waiting_ops_capacity;
-
-  grpc_closure next_step;
-
-  grpc_call_stack *owning_call;
-} grpc_subchannel_call_holder;
-
-void grpc_subchannel_call_holder_init(
-    grpc_subchannel_call_holder *holder,
-    grpc_subchannel_call_holder_pick_subchannel pick_subchannel,
-    void *pick_subchannel_arg, grpc_call_stack *owning_call);
-void grpc_subchannel_call_holder_destroy(grpc_exec_ctx *exec_ctx,
-                                         grpc_subchannel_call_holder *holder);
-
-void grpc_subchannel_call_holder_perform_op(grpc_exec_ctx *exec_ctx,
-                                            grpc_subchannel_call_holder *holder,
-                                            grpc_transport_stream_op *op);
-char *grpc_subchannel_call_holder_get_peer(grpc_exec_ctx *exec_ctx,
-                                           grpc_subchannel_call_holder *holder);
-
-#endif /* GRPC_CORE_EXT_CLIENT_CONFIG_SUBCHANNEL_CALL_HOLDER_H */
diff --git a/src/core/ext/resolver/dns/native/dns_resolver.c b/src/core/ext/resolver/dns/native/dns_resolver.c
index 31ac968..79682e7 100644
--- a/src/core/ext/resolver/dns/native/dns_resolver.c
+++ b/src/core/ext/resolver/dns/native/dns_resolver.c
@@ -67,16 +67,16 @@
   gpr_mu mu;
   /** are we currently resolving? */
   int resolving;
-  /** which version of resolved_config have we published? */
+  /** which version of the result have we published? */
   int published_version;
-  /** which version of resolved_config is current? */
+  /** which version of the result is current? */
   int resolved_version;
   /** pending next completion, or NULL */
   grpc_closure *next_completion;
-  /** target config address for next completion */
-  grpc_client_config **target_config;
-  /** current (fully resolved) config */
-  grpc_client_config *resolved_config;
+  /** target result address for next completion */
+  grpc_resolver_result **target_result;
+  /** current (fully resolved) result */
+  grpc_resolver_result *resolved_result;
   /** retry timer */
   bool have_retry_timer;
   grpc_timer retry_timer;
@@ -97,7 +97,7 @@
 static void dns_shutdown(grpc_exec_ctx *exec_ctx, grpc_resolver *r);
 static void dns_channel_saw_error(grpc_exec_ctx *exec_ctx, grpc_resolver *r);
 static void dns_next(grpc_exec_ctx *exec_ctx, grpc_resolver *r,
-                     grpc_client_config **target_config,
+                     grpc_resolver_result **target_result,
                      grpc_closure *on_complete);
 
 static const grpc_resolver_vtable dns_resolver_vtable = {
@@ -110,7 +110,7 @@
     grpc_timer_cancel(exec_ctx, &r->retry_timer);
   }
   if (r->next_completion != NULL) {
-    *r->target_config = NULL;
+    *r->target_result = NULL;
     grpc_exec_ctx_sched(exec_ctx, r->next_completion,
                         GRPC_ERROR_CREATE("Resolver Shutdown"), NULL);
     r->next_completion = NULL;
@@ -130,13 +130,13 @@
 }
 
 static void dns_next(grpc_exec_ctx *exec_ctx, grpc_resolver *resolver,
-                     grpc_client_config **target_config,
+                     grpc_resolver_result **target_result,
                      grpc_closure *on_complete) {
   dns_resolver *r = (dns_resolver *)resolver;
   gpr_mu_lock(&r->mu);
   GPR_ASSERT(!r->next_completion);
   r->next_completion = on_complete;
-  r->target_config = target_config;
+  r->target_result = target_result;
   if (r->resolved_version == 0 && !r->resolving) {
     gpr_backoff_reset(&r->backoff_state);
     dns_start_resolving_locked(exec_ctx, r);
@@ -165,7 +165,7 @@
 static void dns_on_resolved(grpc_exec_ctx *exec_ctx, void *arg,
                             grpc_error *error) {
   dns_resolver *r = arg;
-  grpc_client_config *config = NULL;
+  grpc_resolver_result *result = NULL;
   grpc_lb_policy *lb_policy;
   gpr_mu_lock(&r->mu);
   GPR_ASSERT(r->resolving);
@@ -173,14 +173,14 @@
   grpc_resolved_addresses *addresses = r->addresses;
   if (addresses != NULL) {
     grpc_lb_policy_args lb_policy_args;
-    config = grpc_client_config_create();
+    result = grpc_resolver_result_create();
     memset(&lb_policy_args, 0, sizeof(lb_policy_args));
     lb_policy_args.addresses = addresses;
     lb_policy_args.client_channel_factory = r->client_channel_factory;
     lb_policy =
         grpc_lb_policy_create(exec_ctx, r->lb_policy_name, &lb_policy_args);
     if (lb_policy != NULL) {
-      grpc_client_config_set_lb_policy(config, lb_policy);
+      grpc_resolver_result_set_lb_policy(result, lb_policy);
       GRPC_LB_POLICY_UNREF(exec_ctx, lb_policy, "construction");
     }
     grpc_resolved_addresses_destroy(addresses);
@@ -203,10 +203,10 @@
     grpc_timer_init(exec_ctx, &r->retry_timer, next_try, dns_on_retry_timer, r,
                     now);
   }
-  if (r->resolved_config) {
-    grpc_client_config_unref(exec_ctx, r->resolved_config);
+  if (r->resolved_result) {
+    grpc_resolver_result_unref(exec_ctx, r->resolved_result);
   }
-  r->resolved_config = config;
+  r->resolved_result = result;
   r->resolved_version++;
   dns_maybe_finish_next_locked(exec_ctx, r);
   gpr_mu_unlock(&r->mu);
@@ -228,9 +228,9 @@
                                          dns_resolver *r) {
   if (r->next_completion != NULL &&
       r->resolved_version != r->published_version) {
-    *r->target_config = r->resolved_config;
-    if (r->resolved_config) {
-      grpc_client_config_ref(r->resolved_config);
+    *r->target_result = r->resolved_result;
+    if (r->resolved_result) {
+      grpc_resolver_result_ref(r->resolved_result);
     }
     grpc_exec_ctx_sched(exec_ctx, r->next_completion, GRPC_ERROR_NONE, NULL);
     r->next_completion = NULL;
@@ -241,8 +241,8 @@
 static void dns_destroy(grpc_exec_ctx *exec_ctx, grpc_resolver *gr) {
   dns_resolver *r = (dns_resolver *)gr;
   gpr_mu_destroy(&r->mu);
-  if (r->resolved_config) {
-    grpc_client_config_unref(exec_ctx, r->resolved_config);
+  if (r->resolved_result) {
+    grpc_resolver_result_unref(exec_ctx, r->resolved_result);
   }
   grpc_client_channel_factory_unref(exec_ctx, r->client_channel_factory);
   gpr_free(r->name);
diff --git a/src/core/ext/resolver/sockaddr/sockaddr_resolver.c b/src/core/ext/resolver/sockaddr/sockaddr_resolver.c
index 1f7cce2..3807522 100644
--- a/src/core/ext/resolver/sockaddr/sockaddr_resolver.c
+++ b/src/core/ext/resolver/sockaddr/sockaddr_resolver.c
@@ -66,8 +66,8 @@
   int published;
   /** pending next completion, or NULL */
   grpc_closure *next_completion;
-  /** target config address for next completion */
-  grpc_client_config **target_config;
+  /** target result address for next completion */
+  grpc_resolver_result **target_result;
 } sockaddr_resolver;
 
 static void sockaddr_destroy(grpc_exec_ctx *exec_ctx, grpc_resolver *r);
@@ -79,7 +79,7 @@
 static void sockaddr_channel_saw_error(grpc_exec_ctx *exec_ctx,
                                        grpc_resolver *r);
 static void sockaddr_next(grpc_exec_ctx *exec_ctx, grpc_resolver *r,
-                          grpc_client_config **target_config,
+                          grpc_resolver_result **target_result,
                           grpc_closure *on_complete);
 
 static const grpc_resolver_vtable sockaddr_resolver_vtable = {
@@ -91,7 +91,7 @@
   sockaddr_resolver *r = (sockaddr_resolver *)resolver;
   gpr_mu_lock(&r->mu);
   if (r->next_completion != NULL) {
-    *r->target_config = NULL;
+    *r->target_result = NULL;
     grpc_exec_ctx_sched(exec_ctx, r->next_completion, GRPC_ERROR_NONE, NULL);
     r->next_completion = NULL;
   }
@@ -108,13 +108,13 @@
 }
 
 static void sockaddr_next(grpc_exec_ctx *exec_ctx, grpc_resolver *resolver,
-                          grpc_client_config **target_config,
+                          grpc_resolver_result **target_result,
                           grpc_closure *on_complete) {
   sockaddr_resolver *r = (sockaddr_resolver *)resolver;
   gpr_mu_lock(&r->mu);
   GPR_ASSERT(!r->next_completion);
   r->next_completion = on_complete;
-  r->target_config = target_config;
+  r->target_result = target_result;
   sockaddr_maybe_finish_next_locked(exec_ctx, r);
   gpr_mu_unlock(&r->mu);
 }
@@ -122,17 +122,17 @@
 static void sockaddr_maybe_finish_next_locked(grpc_exec_ctx *exec_ctx,
                                               sockaddr_resolver *r) {
   if (r->next_completion != NULL && !r->published) {
-    grpc_client_config *cfg = grpc_client_config_create();
+    grpc_resolver_result *result = grpc_resolver_result_create();
     grpc_lb_policy_args lb_policy_args;
     memset(&lb_policy_args, 0, sizeof(lb_policy_args));
     lb_policy_args.addresses = r->addresses;
     lb_policy_args.client_channel_factory = r->client_channel_factory;
     grpc_lb_policy *lb_policy =
         grpc_lb_policy_create(exec_ctx, r->lb_policy_name, &lb_policy_args);
-    grpc_client_config_set_lb_policy(cfg, lb_policy);
+    grpc_resolver_result_set_lb_policy(result, lb_policy);
     GRPC_LB_POLICY_UNREF(exec_ctx, lb_policy, "sockaddr");
     r->published = 1;
-    *r->target_config = cfg;
+    *r->target_result = result;
     grpc_exec_ctx_sched(exec_ctx, r->next_completion, GRPC_ERROR_NONE, NULL);
     r->next_completion = NULL;
   }
diff --git a/src/core/ext/transport/chttp2/transport/chttp2_plugin.c b/src/core/ext/transport/chttp2/transport/chttp2_plugin.c
index 7d5279b..bd87253 100644
--- a/src/core/ext/transport/chttp2/transport/chttp2_plugin.c
+++ b/src/core/ext/transport/chttp2/transport/chttp2_plugin.c
@@ -36,14 +36,11 @@
 #include "src/core/lib/debug/trace.h"
 #include "src/core/lib/transport/metadata.h"
 
-extern int grpc_http_write_state_trace;
-
 void grpc_chttp2_plugin_init(void) {
   grpc_chttp2_base64_encode_and_huffman_compress =
       grpc_chttp2_base64_encode_and_huffman_compress_impl;
   grpc_register_tracer("http", &grpc_http_trace);
   grpc_register_tracer("flowctl", &grpc_flowctl_trace);
-  grpc_register_tracer("http_write_state", &grpc_http_write_state_trace);
 }
 
 void grpc_chttp2_plugin_shutdown(void) {}
diff --git a/src/core/ext/transport/chttp2/transport/chttp2_transport.c b/src/core/ext/transport/chttp2/transport/chttp2_transport.c
index 0e8dfb7..986f089 100644
--- a/src/core/ext/transport/chttp2/transport/chttp2_transport.c
+++ b/src/core/ext/transport/chttp2/transport/chttp2_transport.c
@@ -63,40 +63,27 @@
 #define MAX_CLIENT_STREAM_ID 0x7fffffffu
 int grpc_http_trace = 0;
 int grpc_flowctl_trace = 0;
-int grpc_http_write_state_trace = 0;
-
-#define TRANSPORT_FROM_WRITING(tw)                                        \
-  ((grpc_chttp2_transport *)((char *)(tw)-offsetof(grpc_chttp2_transport, \
-                                                   writing)))
-
-#define TRANSPORT_FROM_PARSING(tp)                                        \
-  ((grpc_chttp2_transport *)((char *)(tp)-offsetof(grpc_chttp2_transport, \
-                                                   parsing)))
-
-#define TRANSPORT_FROM_GLOBAL(tg)                                         \
-  ((grpc_chttp2_transport *)((char *)(tg)-offsetof(grpc_chttp2_transport, \
-                                                   global)))
-
-#define STREAM_FROM_GLOBAL(sg) \
-  ((grpc_chttp2_stream *)((char *)(sg)-offsetof(grpc_chttp2_stream, global)))
-
-#define STREAM_FROM_PARSING(sg) \
-  ((grpc_chttp2_stream *)((char *)(sg)-offsetof(grpc_chttp2_stream, parsing)))
 
 static const grpc_transport_vtable vtable;
 
 /* forward declarations of various callbacks that we'll build closures around */
-static void writing_action(grpc_exec_ctx *exec_ctx, void *t, grpc_error *error);
-static void reading_action(grpc_exec_ctx *exec_ctx, void *t, grpc_error *error);
-static void parsing_action(grpc_exec_ctx *exec_ctx, void *t, grpc_error *error);
-static void initiate_writing(grpc_exec_ctx *exec_ctx, void *t,
+static void write_action_begin_locked(grpc_exec_ctx *exec_ctx, void *t,
+                                      grpc_error *error);
+static void write_action(grpc_exec_ctx *exec_ctx, void *t, grpc_error *error);
+static void write_action_end(grpc_exec_ctx *exec_ctx, void *t,
                              grpc_error *error);
+static void write_action_end_locked(grpc_exec_ctx *exec_ctx, void *t,
+                                    grpc_error *error);
 
-static void start_writing(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t);
-static void end_waiting_for_write(grpc_exec_ctx *exec_ctx,
-                                  grpc_chttp2_transport *t, grpc_error *error,
-                                  const char *reason);
+static void read_action_begin(grpc_exec_ctx *exec_ctx, void *t,
+                              grpc_error *error);
+static void read_action_locked(grpc_exec_ctx *exec_ctx, void *t,
+                               grpc_error *error);
 
+static void complete_fetch_locked(grpc_exec_ctx *exec_ctx, void *gs,
+                                  grpc_error *error);
+static void complete_fetch(grpc_exec_ctx *exec_ctx, void *gs,
+                           grpc_error *error);
 /** Set a transport level setting, and push it to our peer */
 static void push_setting(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t,
                          grpc_chttp2_setting_id id, uint32_t value);
@@ -105,56 +92,28 @@
 static void drop_connection(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t,
                             grpc_error *error);
 
-/** Perform a transport_op */
-static void perform_stream_op_locked(grpc_exec_ctx *exec_ctx,
-                                     grpc_chttp2_transport *t,
-                                     grpc_chttp2_stream *s, void *transport_op);
-
-/** Cancel a stream: coming from the transport API */
-static void cancel_from_api(grpc_exec_ctx *exec_ctx,
-                            grpc_chttp2_transport_global *transport_global,
-                            grpc_chttp2_stream_global *stream_global,
-                            grpc_error *error);
-
-static void close_from_api(grpc_exec_ctx *exec_ctx,
-                           grpc_chttp2_transport_global *transport_global,
-                           grpc_chttp2_stream_global *stream_global,
-                           grpc_error *error);
-
-/** Add endpoint from this transport to pollset */
-static void add_to_pollset_locked(grpc_exec_ctx *exec_ctx,
-                                  grpc_chttp2_transport *t,
-                                  grpc_chttp2_stream *s_ignored, void *pollset);
-static void add_to_pollset_set_locked(grpc_exec_ctx *exec_ctx,
-                                      grpc_chttp2_transport *t,
-                                      grpc_chttp2_stream *s_ignored,
-                                      void *pollset_set);
+static void close_from_api(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t,
+                           grpc_chttp2_stream *s, grpc_error *error);
 
 /** Start new streams that have been created if we can */
-static void maybe_start_some_streams(
-    grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_global *transport_global);
+static void maybe_start_some_streams(grpc_exec_ctx *exec_ctx,
+                                     grpc_chttp2_transport *t);
 
-static void finish_global_actions(grpc_exec_ctx *exec_ctx,
-                                  grpc_chttp2_transport *t);
+static void connectivity_state_set(grpc_exec_ctx *exec_ctx,
+                                   grpc_chttp2_transport *t,
+                                   grpc_connectivity_state state,
+                                   grpc_error *error, const char *reason);
 
-static void connectivity_state_set(
-    grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_global *transport_global,
-    grpc_connectivity_state state, grpc_error *error, const char *reason);
-
-static void check_read_ops(grpc_exec_ctx *exec_ctx,
-                           grpc_chttp2_transport_global *transport_global);
-
-static void incoming_byte_stream_update_flow_control(
-    grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_global *transport_global,
-    grpc_chttp2_stream_global *stream_global, size_t max_size_hint,
-    size_t have_already);
+static void incoming_byte_stream_update_flow_control(grpc_exec_ctx *exec_ctx,
+                                                     grpc_chttp2_transport *t,
+                                                     grpc_chttp2_stream *s,
+                                                     size_t max_size_hint,
+                                                     size_t have_already);
 static void incoming_byte_stream_destroy_locked(grpc_exec_ctx *exec_ctx,
-                                                grpc_chttp2_transport *t,
-                                                grpc_chttp2_stream *s,
-                                                void *byte_stream);
+                                                void *byte_stream,
+                                                grpc_error *error_ignored);
 static void fail_pending_writes(grpc_exec_ctx *exec_ctx,
-                                grpc_chttp2_transport_global *transport_global,
-                                grpc_chttp2_stream_global *stream_global,
+                                grpc_chttp2_transport *t, grpc_chttp2_stream *s,
                                 grpc_error *error);
 
 /*******************************************************************************
@@ -165,39 +124,33 @@
                                grpc_chttp2_transport *t) {
   size_t i;
 
-  gpr_mu_lock(&t->executor.mu);
+  grpc_endpoint_destroy(exec_ctx, t->ep);
 
-  GPR_ASSERT(t->ep == NULL);
+  gpr_slice_buffer_destroy(&t->qbuf);
 
-  gpr_slice_buffer_destroy(&t->global.qbuf);
+  gpr_slice_buffer_destroy(&t->outbuf);
+  grpc_chttp2_hpack_compressor_destroy(&t->hpack_compressor);
 
-  gpr_slice_buffer_destroy(&t->writing.outbuf);
-  grpc_chttp2_hpack_compressor_destroy(&t->writing.hpack_compressor);
-
-  gpr_slice_buffer_destroy(&t->parsing.qbuf);
   gpr_slice_buffer_destroy(&t->read_buffer);
-  grpc_chttp2_hpack_parser_destroy(&t->parsing.hpack_parser);
-  grpc_chttp2_goaway_parser_destroy(&t->parsing.goaway_parser);
+  grpc_chttp2_hpack_parser_destroy(&t->hpack_parser);
+  grpc_chttp2_goaway_parser_destroy(&t->goaway_parser);
 
   for (i = 0; i < STREAM_LIST_COUNT; i++) {
     GPR_ASSERT(t->lists[i].head == NULL);
     GPR_ASSERT(t->lists[i].tail == NULL);
   }
 
-  GPR_ASSERT(grpc_chttp2_stream_map_size(&t->parsing_stream_map) == 0);
-  GPR_ASSERT(grpc_chttp2_stream_map_size(&t->new_stream_map) == 0);
+  GPR_ASSERT(grpc_chttp2_stream_map_size(&t->stream_map) == 0);
 
-  grpc_chttp2_stream_map_destroy(&t->parsing_stream_map);
-  grpc_chttp2_stream_map_destroy(&t->new_stream_map);
+  grpc_chttp2_stream_map_destroy(&t->stream_map);
   grpc_connectivity_state_destroy(exec_ctx, &t->channel_callback.state_tracker);
 
-  gpr_mu_unlock(&t->executor.mu);
-  gpr_mu_destroy(&t->executor.mu);
+  grpc_combiner_destroy(exec_ctx, t->combiner);
 
   /* callback remaining pings: they're not allowed to call into the transpot,
      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;
+  while (t->pings.next != &t->pings) {
+    grpc_chttp2_outstanding_ping *ping = t->pings.next;
     grpc_exec_ctx_sched(exec_ctx, ping->on_recv,
                         GRPC_ERROR_CREATE("Transport closed"), NULL);
     ping->next->prev = ping->prev;
@@ -205,37 +158,40 @@
     gpr_free(ping);
   }
 
+  while (t->write_cb_pool) {
+    grpc_chttp2_write_cb *next = t->write_cb_pool->next;
+    gpr_free(t->write_cb_pool);
+    t->write_cb_pool = next;
+  }
+
   gpr_free(t->peer_string);
   gpr_free(t);
 }
 
-/*#define REFCOUNTING_DEBUG 1*/
-#ifdef REFCOUNTING_DEBUG
-#define REF_TRANSPORT(t, r) ref_transport(t, r, __FILE__, __LINE__)
-#define UNREF_TRANSPORT(cl, t, r) unref_transport(cl, t, r, __FILE__, __LINE__)
-static void unref_transport(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t,
-                            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);
+#ifdef GRPC_CHTTP2_REFCOUNTING_DEBUG
+void grpc_chttp2_unref_transport(grpc_exec_ctx *exec_ctx,
+                                 grpc_chttp2_transport *t, const char *reason,
+                                 const char *file, int line) {
+  gpr_log(GPR_DEBUG, "chttp2:unref:%p %" PRIdPTR "->%" PRIdPTR " %s [%s:%d]", t,
+          t->refs.count, t->refs.count - 1, reason, file, line);
   if (!gpr_unref(&t->refs)) return;
   destruct_transport(exec_ctx, t);
 }
 
-static void ref_transport(grpc_chttp2_transport *t, const char *reason,
-                          const char *file, int line) {
-  gpr_log(GPR_DEBUG, "chttp2:  ref:%p %d->%d %s [%s:%d]", t, t->refs.count,
-          t->refs.count + 1, reason, file, line);
+void grpc_chttp2_ref_transport(grpc_chttp2_transport *t, const char *reason,
+                               const char *file, int line) {
+  gpr_log(GPR_DEBUG, "chttp2:  ref:%p %" PRIdPTR "->%" PRIdPTR " %s [%s:%d]", t,
+          t->refs.count, t->refs.count + 1, reason, file, line);
   gpr_ref(&t->refs);
 }
 #else
-#define REF_TRANSPORT(t, r) ref_transport(t)
-#define UNREF_TRANSPORT(cl, t, r) unref_transport(cl, t)
-static void unref_transport(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t) {
+void grpc_chttp2_unref_transport(grpc_exec_ctx *exec_ctx,
+                                 grpc_chttp2_transport *t) {
   if (!gpr_unref(&t->refs)) return;
   destruct_transport(exec_ctx, t);
 }
 
-static void ref_transport(grpc_chttp2_transport *t) { gpr_ref(&t->refs); }
+void grpc_chttp2_ref_transport(grpc_chttp2_transport *t) { gpr_ref(&t->refs); }
 #endif
 
 static void init_transport(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t,
@@ -251,74 +207,67 @@
 
   t->base.vtable = &vtable;
   t->ep = ep;
-  /* one ref is for destroy, the other for when ep becomes NULL */
-  gpr_ref_init(&t->refs, 2);
-  /* ref is dropped at transport close() */
-  gpr_ref_init(&t->shutdown_ep_refs, 1);
-  gpr_mu_init(&t->executor.mu);
+  /* one ref is for destroy */
+  gpr_ref_init(&t->refs, 1);
+  t->combiner = grpc_combiner_create(grpc_endpoint_get_workqueue(ep));
   t->peer_string = grpc_endpoint_get_peer(ep);
   t->endpoint_reading = 1;
-  t->global.next_stream_id = is_client ? 1 : 2;
-  t->global.is_client = is_client;
-  t->writing.outgoing_window = DEFAULT_WINDOW;
-  t->parsing.incoming_window = DEFAULT_WINDOW;
-  t->global.stream_lookahead = DEFAULT_WINDOW;
-  t->global.connection_window_target = DEFAULT_CONNECTION_WINDOW_TARGET;
-  t->global.ping_counter = 1;
-  t->global.pings.next = t->global.pings.prev = &t->global.pings;
-  t->parsing.is_client = is_client;
-  t->parsing.deframe_state =
-      is_client ? GRPC_DTS_FH_0 : GRPC_DTS_CLIENT_PREFIX_0;
-  t->parsing.is_first_frame = true;
-  t->writing.is_client = is_client;
+  t->next_stream_id = is_client ? 1 : 2;
+  t->is_client = is_client;
+  t->outgoing_window = DEFAULT_WINDOW;
+  t->incoming_window = DEFAULT_WINDOW;
+  t->stream_lookahead = DEFAULT_WINDOW;
+  t->connection_window_target = DEFAULT_CONNECTION_WINDOW_TARGET;
+  t->ping_counter = 1;
+  t->pings.next = t->pings.prev = &t->pings;
+  t->deframe_state = is_client ? GRPC_DTS_FH_0 : GRPC_DTS_CLIENT_PREFIX_0;
+  t->is_first_frame = true;
   grpc_connectivity_state_init(
       &t->channel_callback.state_tracker, GRPC_CHANNEL_READY,
       is_client ? "client_transport" : "server_transport");
 
-  gpr_slice_buffer_init(&t->global.qbuf);
+  gpr_slice_buffer_init(&t->qbuf);
 
-  gpr_slice_buffer_init(&t->writing.outbuf);
-  grpc_chttp2_hpack_compressor_init(&t->writing.hpack_compressor);
-  grpc_closure_init(&t->writing_action, writing_action, t);
-  grpc_closure_init(&t->reading_action, reading_action, t);
-  grpc_closure_init(&t->parsing_action, parsing_action, t);
-  grpc_closure_init(&t->initiate_writing, initiate_writing, t);
+  gpr_slice_buffer_init(&t->outbuf);
+  grpc_chttp2_hpack_compressor_init(&t->hpack_compressor);
 
-  gpr_slice_buffer_init(&t->parsing.qbuf);
-  grpc_chttp2_goaway_parser_init(&t->parsing.goaway_parser);
-  grpc_chttp2_hpack_parser_init(&t->parsing.hpack_parser);
+  grpc_closure_init(&t->write_action_begin_locked, write_action_begin_locked,
+                    t);
+  grpc_closure_init(&t->write_action, write_action, t);
+  grpc_closure_init(&t->write_action_end, write_action_end, t);
+  grpc_closure_init(&t->write_action_end_locked, write_action_end_locked, t);
+  grpc_closure_init(&t->read_action_begin, read_action_begin, t);
+  grpc_closure_init(&t->read_action_locked, read_action_locked, t);
 
-  grpc_closure_init(&t->writing.done_cb, grpc_chttp2_terminate_writing,
-                    &t->writing);
+  grpc_chttp2_goaway_parser_init(&t->goaway_parser);
+  grpc_chttp2_hpack_parser_init(&t->hpack_parser);
+
   gpr_slice_buffer_init(&t->read_buffer);
 
-  if (is_client) {
-    gpr_slice_buffer_add(
-        &t->global.qbuf,
-        gpr_slice_from_copied_string(GRPC_CHTTP2_CLIENT_CONNECT_STRING));
-    grpc_chttp2_initiate_write(exec_ctx, &t->global, false, "initial_write");
-  }
   /* 8 is a random stab in the dark as to a good initial size: it's small enough
      that it shouldn't waste memory for infrequently used connections, yet
      large enough that the exponential growth should happen nicely when it's
      needed.
      TODO(ctiller): tune this */
-  grpc_chttp2_stream_map_init(&t->parsing_stream_map, 8);
-  grpc_chttp2_stream_map_init(&t->new_stream_map, 8);
+  grpc_chttp2_stream_map_init(&t->stream_map, 8);
 
   /* copy in initial settings to all setting sets */
   for (i = 0; i < GRPC_CHTTP2_NUM_SETTINGS; i++) {
-    t->parsing.settings[i] = grpc_chttp2_settings_parameters[i].default_value;
     for (j = 0; j < GRPC_NUM_SETTING_SETS; j++) {
-      t->global.settings[j][i] =
-          grpc_chttp2_settings_parameters[i].default_value;
+      t->settings[j][i] = grpc_chttp2_settings_parameters[i].default_value;
     }
   }
-  t->global.dirtied_local_settings = 1;
+  t->dirtied_local_settings = 1;
   /* Hack: it's common for implementations to assume 65536 bytes initial send
      window -- this should by rights be 0 */
-  t->global.force_send_settings = 1 << GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE;
-  t->global.sent_local_settings = 0;
+  t->force_send_settings = 1 << GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE;
+  t->sent_local_settings = 0;
+
+  if (is_client) {
+    gpr_slice_buffer_add(&t->outbuf, gpr_slice_from_copied_string(
+                                         GRPC_CHTTP2_CLIENT_CONNECT_STRING));
+    grpc_chttp2_initiate_write(exec_ctx, t, false, "initial_write");
+  }
 
   /* configure http2 the way we like it */
   if (is_client) {
@@ -349,15 +298,13 @@
         if (channel_args->args[i].type != GRPC_ARG_INTEGER) {
           gpr_log(GPR_ERROR, "%s: must be an integer",
                   GRPC_ARG_HTTP2_INITIAL_SEQUENCE_NUMBER);
-        } else if ((t->global.next_stream_id & 1) !=
+        } else if ((t->next_stream_id & 1) !=
                    (channel_args->args[i].value.integer & 1)) {
           gpr_log(GPR_ERROR, "%s: low bit must be %d on %s",
-                  GRPC_ARG_HTTP2_INITIAL_SEQUENCE_NUMBER,
-                  t->global.next_stream_id & 1,
+                  GRPC_ARG_HTTP2_INITIAL_SEQUENCE_NUMBER, t->next_stream_id & 1,
                   is_client ? "client" : "server");
         } else {
-          t->global.next_stream_id =
-              (uint32_t)channel_args->args[i].value.integer;
+          t->next_stream_id = (uint32_t)channel_args->args[i].value.integer;
         }
       } else if (0 == strcmp(channel_args->args[i].key,
                              GRPC_ARG_HTTP2_STREAM_LOOKAHEAD_BYTES)) {
@@ -368,8 +315,7 @@
           gpr_log(GPR_ERROR, "%s: must be at least 5",
                   GRPC_ARG_HTTP2_STREAM_LOOKAHEAD_BYTES);
         } else {
-          t->global.stream_lookahead =
-              (uint32_t)channel_args->args[i].value.integer;
+          t->stream_lookahead = (uint32_t)channel_args->args[i].value.integer;
         }
       } else if (0 == strcmp(channel_args->args[i].key,
                              GRPC_ARG_HTTP2_HPACK_TABLE_SIZE_DECODER)) {
@@ -393,7 +339,7 @@
                   GRPC_ARG_HTTP2_HPACK_TABLE_SIZE_ENCODER);
         } else {
           grpc_chttp2_hpack_compressor_set_max_usable_size(
-              &t->writing.hpack_compressor,
+              &t->hpack_compressor,
               (uint32_t)channel_args->args[i].value.integer);
         }
       } else if (0 == strcmp(channel_args->args[i].key,
@@ -411,505 +357,321 @@
       }
     }
   }
+
+  grpc_chttp2_initiate_write(exec_ctx, t, false, "init");
 }
 
-static void destroy_transport_locked(grpc_exec_ctx *exec_ctx,
-                                     grpc_chttp2_transport *t,
-                                     grpc_chttp2_stream *s_ignored,
-                                     void *arg_ignored) {
+static void destroy_transport_locked(grpc_exec_ctx *exec_ctx, void *tp,
+                                     grpc_error *error) {
+  grpc_chttp2_transport *t = tp;
   t->destroying = 1;
   drop_connection(exec_ctx, t, GRPC_ERROR_CREATE("Transport destroyed"));
+  GRPC_CHTTP2_UNREF_TRANSPORT(exec_ctx, t, "destroy");
 }
 
 static void destroy_transport(grpc_exec_ctx *exec_ctx, grpc_transport *gt) {
   grpc_chttp2_transport *t = (grpc_chttp2_transport *)gt;
-  grpc_chttp2_run_with_global_lock(exec_ctx, t, NULL, destroy_transport_locked,
-                                   NULL, 0);
-  UNREF_TRANSPORT(exec_ctx, t, "destroy");
-}
-
-/** block grpc_endpoint_shutdown being called until a paired
-    allow_endpoint_shutdown is made */
-static void prevent_endpoint_shutdown(grpc_chttp2_transport *t) {
-  GPR_ASSERT(t->ep);
-  gpr_ref(&t->shutdown_ep_refs);
-}
-
-static void allow_endpoint_shutdown_locked(grpc_exec_ctx *exec_ctx,
-                                           grpc_chttp2_transport *t) {
-  if (gpr_unref(&t->shutdown_ep_refs)) {
-    if (t->ep) {
-      grpc_endpoint_shutdown(exec_ctx, t->ep);
-    }
-  }
-}
-
-static void destroy_endpoint(grpc_exec_ctx *exec_ctx,
-                             grpc_chttp2_transport *t) {
-  grpc_endpoint_destroy(exec_ctx, t->ep);
-  t->ep = NULL;
-  /* safe because we'll still have the ref for write */
-  UNREF_TRANSPORT(exec_ctx, t, "disconnect");
+  grpc_combiner_execute(exec_ctx, t->combiner,
+                        grpc_closure_create(destroy_transport_locked, t),
+                        GRPC_ERROR_NONE, false);
 }
 
 static void close_transport_locked(grpc_exec_ctx *exec_ctx,
                                    grpc_chttp2_transport *t,
                                    grpc_error *error) {
   if (!t->closed) {
-    if (grpc_http_write_state_trace) {
-      gpr_log(GPR_DEBUG, "W:%p close transport", t);
-    }
     t->closed = 1;
-    connectivity_state_set(exec_ctx, &t->global, GRPC_CHANNEL_SHUTDOWN,
+    connectivity_state_set(exec_ctx, t, GRPC_CHANNEL_SHUTDOWN,
                            GRPC_ERROR_REF(error), "close_transport");
-    if (t->ep) {
-      allow_endpoint_shutdown_locked(exec_ctx, t);
-    }
+    grpc_endpoint_shutdown(exec_ctx, t->ep);
 
     /* flush writable stream list to avoid dangling references */
-    grpc_chttp2_stream_global *stream_global;
-    grpc_chttp2_stream_writing *stream_writing;
-    while (grpc_chttp2_list_pop_writable_stream(
-        &t->global, &t->writing, &stream_global, &stream_writing)) {
-      GRPC_CHTTP2_STREAM_UNREF(exec_ctx, stream_global, "chttp2_writing");
+    grpc_chttp2_stream *s;
+    while (grpc_chttp2_list_pop_writable_stream(t, &s)) {
+      GRPC_CHTTP2_STREAM_UNREF(exec_ctx, s, "chttp2_writing:close");
     }
   }
   GRPC_ERROR_UNREF(error);
 }
 
 #ifdef GRPC_STREAM_REFCOUNT_DEBUG
-void grpc_chttp2_stream_ref(grpc_chttp2_stream_global *stream_global,
-                            const char *reason) {
-  grpc_stream_ref(STREAM_FROM_GLOBAL(stream_global)->refcount, reason);
+void grpc_chttp2_stream_ref(grpc_chttp2_stream *s, const char *reason) {
+  grpc_stream_ref(s->refcount, reason);
 }
-void grpc_chttp2_stream_unref(grpc_exec_ctx *exec_ctx,
-                              grpc_chttp2_stream_global *stream_global,
+void grpc_chttp2_stream_unref(grpc_exec_ctx *exec_ctx, grpc_chttp2_stream *s,
                               const char *reason) {
-  grpc_stream_unref(exec_ctx, STREAM_FROM_GLOBAL(stream_global)->refcount,
-                    reason);
+  grpc_stream_unref(exec_ctx, s->refcount, reason);
 }
 #else
-void grpc_chttp2_stream_ref(grpc_chttp2_stream_global *stream_global) {
-  grpc_stream_ref(STREAM_FROM_GLOBAL(stream_global)->refcount);
+void grpc_chttp2_stream_ref(grpc_chttp2_stream *s) {
+  grpc_stream_ref(s->refcount);
 }
-void grpc_chttp2_stream_unref(grpc_exec_ctx *exec_ctx,
-                              grpc_chttp2_stream_global *stream_global) {
-  grpc_stream_unref(exec_ctx, STREAM_FROM_GLOBAL(stream_global)->refcount);
+void grpc_chttp2_stream_unref(grpc_exec_ctx *exec_ctx, grpc_chttp2_stream *s) {
+  grpc_stream_unref(exec_ctx, s->refcount);
 }
 #endif
 
-static void finish_init_stream_locked(grpc_exec_ctx *exec_ctx,
-                                      grpc_chttp2_transport *t,
-                                      grpc_chttp2_stream *s,
-                                      void *arg_ignored) {
-  grpc_chttp2_register_stream(t, s);
-}
-
 static int init_stream(grpc_exec_ctx *exec_ctx, grpc_transport *gt,
                        grpc_stream *gs, grpc_stream_refcount *refcount,
                        const void *server_data) {
+  GPR_TIMER_BEGIN("init_stream", 0);
   grpc_chttp2_transport *t = (grpc_chttp2_transport *)gt;
   grpc_chttp2_stream *s = (grpc_chttp2_stream *)gs;
 
   memset(s, 0, sizeof(*s));
 
+  s->t = t;
   s->refcount = refcount;
   /* We reserve one 'active stream' that's dropped when the stream is
      read-closed. The others are for incoming_byte_streams that are actively
      reading */
-  gpr_ref_init(&s->global.active_streams, 1);
-  GRPC_CHTTP2_STREAM_REF(&s->global, "chttp2");
+  gpr_ref_init(&s->active_streams, 1);
+  GRPC_CHTTP2_STREAM_REF(s, "chttp2");
 
-  grpc_chttp2_incoming_metadata_buffer_init(&s->parsing.metadata_buffer[0]);
-  grpc_chttp2_incoming_metadata_buffer_init(&s->parsing.metadata_buffer[1]);
-  grpc_chttp2_incoming_metadata_buffer_init(
-      &s->global.received_initial_metadata);
-  grpc_chttp2_incoming_metadata_buffer_init(
-      &s->global.received_trailing_metadata);
-  grpc_chttp2_data_parser_init(&s->parsing.data_parser);
-  gpr_slice_buffer_init(&s->writing.flow_controlled_buffer);
-  s->global.deadline = gpr_inf_future(GPR_CLOCK_MONOTONIC);
+  grpc_chttp2_incoming_metadata_buffer_init(&s->metadata_buffer[0]);
+  grpc_chttp2_incoming_metadata_buffer_init(&s->metadata_buffer[1]);
+  grpc_chttp2_data_parser_init(&s->data_parser);
+  gpr_slice_buffer_init(&s->flow_controlled_buffer);
+  s->deadline = gpr_inf_future(GPR_CLOCK_MONOTONIC);
+  grpc_closure_init(&s->complete_fetch, complete_fetch, s);
+  grpc_closure_init(&s->complete_fetch_locked, complete_fetch_locked, s);
 
-  REF_TRANSPORT(t, "stream");
+  GRPC_CHTTP2_REF_TRANSPORT(t, "stream");
 
   if (server_data) {
-    GPR_ASSERT(t->executor.parsing_active);
-    s->global.id = (uint32_t)(uintptr_t)server_data;
-    s->parsing.id = s->global.id;
-    s->global.outgoing_window =
-        t->global.settings[GRPC_PEER_SETTINGS]
-                          [GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE];
-    s->parsing.incoming_window = s->global.max_recv_bytes =
-        t->global.settings[GRPC_SENT_SETTINGS]
-                          [GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE];
+    s->id = (uint32_t)(uintptr_t)server_data;
+    s->outgoing_window = t->settings[GRPC_PEER_SETTINGS]
+                                    [GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE];
+    s->incoming_window = s->max_recv_bytes =
+        t->settings[GRPC_SENT_SETTINGS]
+                   [GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE];
     *t->accepting_stream = s;
-    grpc_chttp2_stream_map_add(&t->parsing_stream_map, s->global.id, s);
-    s->global.in_stream_map = true;
+    grpc_chttp2_stream_map_add(&t->stream_map, s->id, s);
   }
 
-  grpc_chttp2_run_with_global_lock(exec_ctx, t, s, finish_init_stream_locked,
-                                   NULL, 0);
+  GPR_TIMER_END("init_stream", 0);
 
   return 0;
 }
 
-static void destroy_stream_locked(grpc_exec_ctx *exec_ctx,
-                                  grpc_chttp2_transport *t,
-                                  grpc_chttp2_stream *s, void *arg) {
+static void destroy_stream_locked(grpc_exec_ctx *exec_ctx, void *sp,
+                                  grpc_error *error) {
   grpc_byte_stream *bs;
+  grpc_chttp2_stream *s = sp;
+  grpc_chttp2_transport *t = s->t;
 
   GPR_TIMER_BEGIN("destroy_stream", 0);
 
-  GPR_ASSERT((s->global.write_closed && s->global.read_closed) ||
-             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(
-        exec_ctx, t,
-        GRPC_ERROR_CREATE("Last stream closed after sending goaway"));
-  }
-  if (!t->executor.parsing_active && s->global.id) {
-    GPR_ASSERT(grpc_chttp2_stream_map_find(&t->parsing_stream_map,
-                                           s->global.id) == NULL);
+  GPR_ASSERT((s->write_closed && s->read_closed) || s->id == 0);
+  if (s->id != 0) {
+    GPR_ASSERT(grpc_chttp2_stream_map_find(&t->stream_map, s->id) == NULL);
   }
 
-  while (
-      (bs = grpc_chttp2_incoming_frame_queue_pop(&s->global.incoming_frames))) {
-    incoming_byte_stream_destroy_locked(exec_ctx, NULL, NULL, bs);
+  while ((bs = grpc_chttp2_incoming_frame_queue_pop(&s->incoming_frames))) {
+    incoming_byte_stream_destroy_locked(exec_ctx, bs, GRPC_ERROR_NONE);
   }
 
-  grpc_chttp2_list_remove_unannounced_incoming_window_available(&t->global,
-                                                                &s->global);
-  grpc_chttp2_list_remove_stalled_by_transport(&t->global, &s->global);
-  grpc_chttp2_list_remove_check_read_ops(&t->global, &s->global);
+  grpc_chttp2_list_remove_stalled_by_transport(t, s);
 
   for (int i = 0; i < STREAM_LIST_COUNT; i++) {
     if (s->included[i]) {
       gpr_log(GPR_ERROR, "%s stream %d still included in list %d",
-              t->global.is_client ? "client" : "server", s->global.id, i);
+              t->is_client ? "client" : "server", s->id, i);
       abort();
     }
   }
 
-  GPR_ASSERT(s->global.send_initial_metadata_finished == NULL);
-  GPR_ASSERT(s->global.send_message_finished == NULL);
-  GPR_ASSERT(s->global.send_trailing_metadata_finished == NULL);
-  GPR_ASSERT(s->global.recv_initial_metadata_ready == NULL);
-  GPR_ASSERT(s->global.recv_message_ready == NULL);
-  GPR_ASSERT(s->global.recv_trailing_metadata_finished == NULL);
-  grpc_chttp2_data_parser_destroy(exec_ctx, &s->parsing.data_parser);
-  grpc_chttp2_incoming_metadata_buffer_destroy(&s->parsing.metadata_buffer[0]);
-  grpc_chttp2_incoming_metadata_buffer_destroy(&s->parsing.metadata_buffer[1]);
-  grpc_chttp2_incoming_metadata_buffer_destroy(
-      &s->global.received_initial_metadata);
-  grpc_chttp2_incoming_metadata_buffer_destroy(
-      &s->global.received_trailing_metadata);
-  gpr_slice_buffer_destroy(&s->writing.flow_controlled_buffer);
-  GRPC_ERROR_UNREF(s->global.read_closed_error);
-  GRPC_ERROR_UNREF(s->global.write_closed_error);
+  GPR_ASSERT(s->send_initial_metadata_finished == NULL);
+  GPR_ASSERT(s->fetching_send_message == NULL);
+  GPR_ASSERT(s->send_trailing_metadata_finished == NULL);
+  GPR_ASSERT(s->recv_initial_metadata_ready == NULL);
+  GPR_ASSERT(s->recv_message_ready == NULL);
+  GPR_ASSERT(s->recv_trailing_metadata_finished == NULL);
+  grpc_chttp2_data_parser_destroy(exec_ctx, &s->data_parser);
+  grpc_chttp2_incoming_metadata_buffer_destroy(&s->metadata_buffer[0]);
+  grpc_chttp2_incoming_metadata_buffer_destroy(&s->metadata_buffer[1]);
+  gpr_slice_buffer_destroy(&s->flow_controlled_buffer);
+  GRPC_ERROR_UNREF(s->read_closed_error);
+  GRPC_ERROR_UNREF(s->write_closed_error);
 
-  UNREF_TRANSPORT(exec_ctx, t, "stream");
+  GRPC_CHTTP2_UNREF_TRANSPORT(exec_ctx, t, "stream");
 
   GPR_TIMER_END("destroy_stream", 0);
 
-  gpr_free(arg);
+  gpr_free(s->destroy_stream_arg);
 }
 
 static void destroy_stream(grpc_exec_ctx *exec_ctx, grpc_transport *gt,
                            grpc_stream *gs, void *and_free_memory) {
+  GPR_TIMER_BEGIN("destroy_stream", 0);
   grpc_chttp2_transport *t = (grpc_chttp2_transport *)gt;
   grpc_chttp2_stream *s = (grpc_chttp2_stream *)gs;
 
-  grpc_chttp2_run_with_global_lock(exec_ctx, t, s, destroy_stream_locked,
-                                   and_free_memory, 0);
+  s->destroy_stream_arg = and_free_memory;
+  grpc_closure_init(&s->destroy_stream, destroy_stream_locked, s);
+  grpc_combiner_execute(exec_ctx, t->combiner, &s->destroy_stream,
+                        GRPC_ERROR_NONE, false);
+  GPR_TIMER_END("destroy_stream", 0);
 }
 
-grpc_chttp2_stream_parsing *grpc_chttp2_parsing_lookup_stream(
-    grpc_chttp2_transport_parsing *transport_parsing, uint32_t id) {
-  grpc_chttp2_transport *t = TRANSPORT_FROM_PARSING(transport_parsing);
-  grpc_chttp2_stream *s =
-      grpc_chttp2_stream_map_find(&t->parsing_stream_map, id);
-  return s ? &s->parsing : NULL;
+grpc_chttp2_stream *grpc_chttp2_parsing_lookup_stream(grpc_chttp2_transport *t,
+                                                      uint32_t id) {
+  return grpc_chttp2_stream_map_find(&t->stream_map, id);
 }
 
-grpc_chttp2_stream_parsing *grpc_chttp2_parsing_accept_stream(
-    grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_parsing *transport_parsing,
-    uint32_t id) {
+grpc_chttp2_stream *grpc_chttp2_parsing_accept_stream(grpc_exec_ctx *exec_ctx,
+                                                      grpc_chttp2_transport *t,
+                                                      uint32_t id) {
   grpc_chttp2_stream *accepting;
-  grpc_chttp2_transport *t = TRANSPORT_FROM_PARSING(transport_parsing);
   GPR_ASSERT(t->accepting_stream == NULL);
   t->accepting_stream = &accepting;
   t->channel_callback.accept_stream(exec_ctx,
                                     t->channel_callback.accept_stream_user_data,
                                     &t->base, (void *)(uintptr_t)id);
   t->accepting_stream = NULL;
-  return &accepting->parsing;
-}
-
-/*******************************************************************************
- * LOCK MANAGEMENT
- */
-
-static const char *write_state_name(grpc_chttp2_write_state state) {
-  switch (state) {
-    case GRPC_CHTTP2_WRITING_INACTIVE:
-      return "INACTIVE";
-    case GRPC_CHTTP2_WRITE_REQUESTED_NO_POLLER:
-      return "REQUESTED[p=0]";
-    case GRPC_CHTTP2_WRITE_REQUESTED_WITH_POLLER:
-      return "REQUESTED[p=1]";
-    case GRPC_CHTTP2_WRITE_SCHEDULED:
-      return "SCHEDULED";
-    case GRPC_CHTTP2_WRITING:
-      return "WRITING";
-    case GRPC_CHTTP2_WRITING_STALE_WITH_POLLER:
-      return "WRITING[p=1]";
-    case GRPC_CHTTP2_WRITING_STALE_NO_POLLER:
-      return "WRITING[p=0]";
-  }
-  GPR_UNREACHABLE_CODE(return "UNKNOWN");
-}
-
-static void set_write_state(grpc_chttp2_transport *t,
-                            grpc_chttp2_write_state state, const char *reason) {
-  if (grpc_http_write_state_trace) {
-    gpr_log(GPR_DEBUG, "W:%p %s -> %s because %s", t,
-            write_state_name(t->executor.write_state), write_state_name(state),
-            reason);
-  }
-  t->executor.write_state = state;
-}
-
-static void finish_global_actions(grpc_exec_ctx *exec_ctx,
-                                  grpc_chttp2_transport *t) {
-  grpc_chttp2_executor_action_header *hdr;
-  grpc_chttp2_executor_action_header *next;
-
-  GPR_TIMER_BEGIN("finish_global_actions", 0);
-
-  for (;;) {
-    check_read_ops(exec_ctx, &t->global);
-
-    gpr_mu_lock(&t->executor.mu);
-    if (t->executor.pending_actions_head != NULL) {
-      hdr = t->executor.pending_actions_head;
-      t->executor.pending_actions_head = t->executor.pending_actions_tail =
-          NULL;
-      gpr_mu_unlock(&t->executor.mu);
-      while (hdr != NULL) {
-        GPR_TIMER_BEGIN("chttp2:locked_action", 0);
-        hdr->action(exec_ctx, t, hdr->stream, hdr->arg);
-        GPR_TIMER_END("chttp2:locked_action", 0);
-        next = hdr->next;
-        gpr_free(hdr);
-        UNREF_TRANSPORT(exec_ctx, t, "pending_action");
-        hdr = next;
-      }
-      continue;
-    } else {
-      t->executor.global_active = false;
-      switch (t->executor.write_state) {
-        case GRPC_CHTTP2_WRITE_REQUESTED_WITH_POLLER:
-          set_write_state(t, GRPC_CHTTP2_WRITE_SCHEDULED, "unlocking");
-          REF_TRANSPORT(t, "initiate_writing");
-          gpr_mu_unlock(&t->executor.mu);
-          grpc_exec_ctx_sched(
-              exec_ctx, &t->initiate_writing, GRPC_ERROR_NONE,
-              t->ep != NULL ? grpc_endpoint_get_workqueue(t->ep) : NULL);
-          break;
-        case GRPC_CHTTP2_WRITE_REQUESTED_NO_POLLER:
-          start_writing(exec_ctx, t);
-          gpr_mu_unlock(&t->executor.mu);
-          break;
-        case GRPC_CHTTP2_WRITING_INACTIVE:
-        case GRPC_CHTTP2_WRITING:
-        case GRPC_CHTTP2_WRITING_STALE_WITH_POLLER:
-        case GRPC_CHTTP2_WRITING_STALE_NO_POLLER:
-        case GRPC_CHTTP2_WRITE_SCHEDULED:
-          gpr_mu_unlock(&t->executor.mu);
-          break;
-      }
-    }
-    break;
-  }
-
-  GPR_TIMER_END("finish_global_actions", 0);
-}
-
-void grpc_chttp2_run_with_global_lock(grpc_exec_ctx *exec_ctx,
-                                      grpc_chttp2_transport *t,
-                                      grpc_chttp2_stream *optional_stream,
-                                      grpc_chttp2_locked_action action,
-                                      void *arg, size_t sizeof_arg) {
-  grpc_chttp2_executor_action_header *hdr;
-
-  GPR_TIMER_BEGIN("grpc_chttp2_run_with_global_lock", 0);
-
-  REF_TRANSPORT(t, "run_global");
-  gpr_mu_lock(&t->executor.mu);
-
-  for (;;) {
-    if (!t->executor.global_active) {
-      t->executor.global_active = 1;
-      gpr_mu_unlock(&t->executor.mu);
-
-      GPR_TIMER_BEGIN("chttp2:locked_action", 0);
-      action(exec_ctx, t, optional_stream, arg);
-      GPR_TIMER_END("chttp2:locked_action", 0);
-
-      finish_global_actions(exec_ctx, t);
-    } else {
-      gpr_mu_unlock(&t->executor.mu);
-
-      hdr = gpr_malloc(sizeof(*hdr) + sizeof_arg);
-      hdr->stream = optional_stream;
-      hdr->action = action;
-      if (sizeof_arg == 0) {
-        hdr->arg = arg;
-      } else {
-        hdr->arg = hdr + 1;
-        memcpy(hdr->arg, arg, sizeof_arg);
-      }
-
-      gpr_mu_lock(&t->executor.mu);
-      if (!t->executor.global_active) {
-        /* global lock was released while allocating memory: release & retry */
-        gpr_free(hdr);
-        continue;
-      }
-      hdr->next = NULL;
-      if (t->executor.pending_actions_head != NULL) {
-        t->executor.pending_actions_tail =
-            t->executor.pending_actions_tail->next = hdr;
-      } else {
-        t->executor.pending_actions_tail = t->executor.pending_actions_head =
-            hdr;
-      }
-      REF_TRANSPORT(t, "pending_action");
-      gpr_mu_unlock(&t->executor.mu);
-    }
-    break;
-  }
-
-  UNREF_TRANSPORT(exec_ctx, t, "run_global");
-
-  GPR_TIMER_END("grpc_chttp2_run_with_global_lock", 0);
+  return accepting;
 }
 
 /*******************************************************************************
  * OUTPUT PROCESSING
  */
 
+static const char *write_state_name(grpc_chttp2_write_state st) {
+  switch (st) {
+    case GRPC_CHTTP2_WRITE_STATE_IDLE:
+      return "IDLE";
+    case GRPC_CHTTP2_WRITE_STATE_WRITING:
+      return "WRITING";
+    case GRPC_CHTTP2_WRITE_STATE_WRITING_WITH_MORE:
+      return "WRITING+MORE";
+    case GRPC_CHTTP2_WRITE_STATE_WRITING_WITH_MORE_AND_COVERED_BY_POLLER:
+      return "WRITING+MORE+COVERED";
+  }
+  GPR_UNREACHABLE_CODE(return "UNKNOWN");
+}
+
+static void set_write_state(grpc_chttp2_transport *t,
+                            grpc_chttp2_write_state st) {
+  GRPC_CHTTP2_IF_TRACING(gpr_log(GPR_DEBUG, "W:%p %s state %s -> %s", t,
+                                 t->is_client ? "CLIENT" : "SERVER",
+                                 write_state_name(t->write_state),
+                                 write_state_name(st)));
+  t->write_state = st;
+}
+
 void grpc_chttp2_initiate_write(grpc_exec_ctx *exec_ctx,
-                                grpc_chttp2_transport_global *transport_global,
+                                grpc_chttp2_transport *t,
                                 bool covered_by_poller, const char *reason) {
-  /* Perform state checks, and transition to a scheduled state if appropriate.
-     Each time we finish the global lock execution, we check if we need to
-     write. If we do:
-      - (if there is a poller surrounding the write) schedule
-        initiate_writing, which locks and calls initiate_writing_locked to...
-      - call start_writing, which verifies (under the global lock) that there
-        are things that need to be written by calling
-        grpc_chttp2_unlocking_check_writes, and if so schedules writing_action
-        against the current exec_ctx, to be executed OUTSIDE of the global lock
-      - eventually writing_action results in grpc_chttp2_terminate_writing being
-        called, which re-takes the global lock, updates state, checks if we need
-        to do *another* write immediately, and if so loops back to
-        start_writing.
+  GPR_TIMER_BEGIN("grpc_chttp2_initiate_write", 0);
 
-      Current problems:
-       - too much lock entry/exiting
-       - the writing thread can become stuck indefinitely (punt through the
-         workqueue periodically to fix) */
-
-  grpc_chttp2_transport *t = TRANSPORT_FROM_GLOBAL(transport_global);
-  switch (t->executor.write_state) {
-    case GRPC_CHTTP2_WRITING_INACTIVE:
-      set_write_state(t, covered_by_poller
-                             ? GRPC_CHTTP2_WRITE_REQUESTED_WITH_POLLER
-                             : GRPC_CHTTP2_WRITE_REQUESTED_NO_POLLER,
-                      reason);
+  switch (t->write_state) {
+    case GRPC_CHTTP2_WRITE_STATE_IDLE:
+      set_write_state(t, GRPC_CHTTP2_WRITE_STATE_WRITING);
+      GRPC_CHTTP2_REF_TRANSPORT(t, "writing");
+      grpc_combiner_execute_finally(exec_ctx, t->combiner,
+                                    &t->write_action_begin_locked,
+                                    GRPC_ERROR_NONE, covered_by_poller);
       break;
-    case GRPC_CHTTP2_WRITE_REQUESTED_WITH_POLLER:
-      /* nothing to do: write already requested */
+    case GRPC_CHTTP2_WRITE_STATE_WRITING:
+      set_write_state(
+          t,
+          covered_by_poller
+              ? GRPC_CHTTP2_WRITE_STATE_WRITING_WITH_MORE_AND_COVERED_BY_POLLER
+              : GRPC_CHTTP2_WRITE_STATE_WRITING_WITH_MORE);
       break;
-    case GRPC_CHTTP2_WRITE_REQUESTED_NO_POLLER:
+    case GRPC_CHTTP2_WRITE_STATE_WRITING_WITH_MORE:
       if (covered_by_poller) {
-        /* upgrade to note poller is available to cover the write */
-        set_write_state(t, GRPC_CHTTP2_WRITE_REQUESTED_WITH_POLLER, reason);
+        set_write_state(
+            t, GRPC_CHTTP2_WRITE_STATE_WRITING_WITH_MORE_AND_COVERED_BY_POLLER);
       }
       break;
-    case GRPC_CHTTP2_WRITE_SCHEDULED:
-      /* nothing to do: write already scheduled */
-      break;
-    case GRPC_CHTTP2_WRITING:
-      set_write_state(t,
-                      covered_by_poller ? GRPC_CHTTP2_WRITING_STALE_WITH_POLLER
-                                        : GRPC_CHTTP2_WRITING_STALE_NO_POLLER,
-                      reason);
-      break;
-    case GRPC_CHTTP2_WRITING_STALE_WITH_POLLER:
-      /* nothing to do: write already requested */
-      break;
-    case GRPC_CHTTP2_WRITING_STALE_NO_POLLER:
-      if (covered_by_poller) {
-        /* upgrade to note poller is available to cover the write */
-        set_write_state(t, GRPC_CHTTP2_WRITING_STALE_WITH_POLLER, reason);
-      }
+    case GRPC_CHTTP2_WRITE_STATE_WRITING_WITH_MORE_AND_COVERED_BY_POLLER:
       break;
   }
-}
-
-static void start_writing(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t) {
-  GPR_ASSERT(t->executor.write_state == GRPC_CHTTP2_WRITE_SCHEDULED ||
-             t->executor.write_state == GRPC_CHTTP2_WRITE_REQUESTED_NO_POLLER);
-  if (!t->closed &&
-      grpc_chttp2_unlocking_check_writes(exec_ctx, &t->global, &t->writing)) {
-    set_write_state(t, GRPC_CHTTP2_WRITING, "start_writing");
-    REF_TRANSPORT(t, "writing");
-    prevent_endpoint_shutdown(t);
-    grpc_exec_ctx_sched(exec_ctx, &t->writing_action, GRPC_ERROR_NONE, NULL);
-  } else {
-    if (t->closed) {
-      set_write_state(t, GRPC_CHTTP2_WRITING_INACTIVE,
-                      "start_writing:transport_closed");
-    } else {
-      set_write_state(t, GRPC_CHTTP2_WRITING_INACTIVE,
-                      "start_writing:nothing_to_write");
-    }
-    end_waiting_for_write(exec_ctx, t, GRPC_ERROR_NONE, "Nothing to write");
-    if (t->ep && !t->endpoint_reading) {
-      destroy_endpoint(exec_ctx, t);
-    }
-  }
-}
-
-static void initiate_writing_locked(grpc_exec_ctx *exec_ctx,
-                                    grpc_chttp2_transport *t,
-                                    grpc_chttp2_stream *s_unused,
-                                    void *arg_ignored) {
-  start_writing(exec_ctx, t);
-  UNREF_TRANSPORT(exec_ctx, t, "initiate_writing");
-}
-
-static void initiate_writing(grpc_exec_ctx *exec_ctx, void *arg,
-                             grpc_error *error) {
-  grpc_chttp2_run_with_global_lock(exec_ctx, arg, NULL, initiate_writing_locked,
-                                   NULL, 0);
+  GPR_TIMER_END("grpc_chttp2_initiate_write", 0);
 }
 
 void grpc_chttp2_become_writable(grpc_exec_ctx *exec_ctx,
-                                 grpc_chttp2_transport_global *transport_global,
-                                 grpc_chttp2_stream_global *stream_global,
-                                 bool covered_by_poller, const char *reason) {
-  if (!TRANSPORT_FROM_GLOBAL(transport_global)->closed &&
-      grpc_chttp2_list_add_writable_stream(transport_global, stream_global)) {
-    GRPC_CHTTP2_STREAM_REF(stream_global, "chttp2_writing");
-    grpc_chttp2_initiate_write(exec_ctx, transport_global, covered_by_poller,
-                               reason);
+                                 grpc_chttp2_transport *t,
+                                 grpc_chttp2_stream *s, bool covered_by_poller,
+                                 const char *reason) {
+  if (!t->closed && grpc_chttp2_list_add_writable_stream(t, s)) {
+    GRPC_CHTTP2_STREAM_REF(s, "chttp2_writing:become");
+    grpc_chttp2_initiate_write(exec_ctx, t, covered_by_poller, reason);
   }
 }
 
+static void write_action_begin_locked(grpc_exec_ctx *exec_ctx, void *gt,
+                                      grpc_error *error_ignored) {
+  GPR_TIMER_BEGIN("write_action_begin_locked", 0);
+  grpc_chttp2_transport *t = gt;
+  GPR_ASSERT(t->write_state != GRPC_CHTTP2_WRITE_STATE_IDLE);
+  if (!t->closed && grpc_chttp2_begin_write(exec_ctx, t)) {
+    set_write_state(t, GRPC_CHTTP2_WRITE_STATE_WRITING);
+    grpc_exec_ctx_sched(exec_ctx, &t->write_action, GRPC_ERROR_NONE, NULL);
+  } else {
+    set_write_state(t, GRPC_CHTTP2_WRITE_STATE_IDLE);
+    GRPC_CHTTP2_UNREF_TRANSPORT(exec_ctx, t, "writing");
+  }
+  GPR_TIMER_END("write_action_begin_locked", 0);
+}
+
+static void write_action(grpc_exec_ctx *exec_ctx, void *gt, grpc_error *error) {
+  grpc_chttp2_transport *t = gt;
+  GPR_TIMER_BEGIN("write_action", 0);
+  grpc_endpoint_write(exec_ctx, t->ep, &t->outbuf, &t->write_action_end);
+  GPR_TIMER_END("write_action", 0);
+}
+
+static void write_action_end(grpc_exec_ctx *exec_ctx, void *gt,
+                             grpc_error *error) {
+  grpc_chttp2_transport *t = gt;
+  GPR_TIMER_BEGIN("write_action_end", 0);
+  grpc_combiner_execute(exec_ctx, t->combiner, &t->write_action_end_locked,
+                        GRPC_ERROR_REF(error), false);
+  GPR_TIMER_END("write_action_end", 0);
+}
+
+static void write_action_end_locked(grpc_exec_ctx *exec_ctx, void *tp,
+                                    grpc_error *error) {
+  GPR_TIMER_BEGIN("terminate_writing_with_lock", 0);
+  grpc_chttp2_transport *t = tp;
+
+  if (error != GRPC_ERROR_NONE) {
+    drop_connection(exec_ctx, t, GRPC_ERROR_REF(error));
+  }
+
+  grpc_chttp2_end_write(exec_ctx, t, GRPC_ERROR_REF(error));
+
+  switch (t->write_state) {
+    case GRPC_CHTTP2_WRITE_STATE_IDLE:
+      GPR_UNREACHABLE_CODE(break);
+    case GRPC_CHTTP2_WRITE_STATE_WRITING:
+      GPR_TIMER_MARK("state=writing", 0);
+      set_write_state(t, GRPC_CHTTP2_WRITE_STATE_IDLE);
+      break;
+    case GRPC_CHTTP2_WRITE_STATE_WRITING_WITH_MORE:
+      GPR_TIMER_MARK("state=writing_stale_no_poller", 0);
+      set_write_state(t, GRPC_CHTTP2_WRITE_STATE_WRITING);
+      GRPC_CHTTP2_REF_TRANSPORT(t, "writing");
+      grpc_combiner_execute_finally(exec_ctx, t->combiner,
+                                    &t->write_action_begin_locked,
+                                    GRPC_ERROR_NONE, false);
+      break;
+    case GRPC_CHTTP2_WRITE_STATE_WRITING_WITH_MORE_AND_COVERED_BY_POLLER:
+      GPR_TIMER_MARK("state=writing_stale_with_poller", 0);
+      set_write_state(t, GRPC_CHTTP2_WRITE_STATE_WRITING);
+      GRPC_CHTTP2_REF_TRANSPORT(t, "writing");
+      grpc_combiner_execute_finally(exec_ctx, t->combiner,
+                                    &t->write_action_begin_locked,
+                                    GRPC_ERROR_NONE, true);
+      break;
+  }
+
+  GRPC_CHTTP2_UNREF_TRANSPORT(exec_ctx, t, "writing");
+  GPR_TIMER_END("terminate_writing_with_lock", 0);
+}
+
 static void push_setting(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t,
                          grpc_chttp2_setting_id id, uint32_t value) {
   const grpc_chttp2_setting_parameters *sp =
@@ -919,101 +681,26 @@
     gpr_log(GPR_INFO, "Requested parameter %s clamped from %d to %d", sp->name,
             value, use_value);
   }
-  if (use_value != t->global.settings[GRPC_LOCAL_SETTINGS][id]) {
-    t->global.settings[GRPC_LOCAL_SETTINGS][id] = use_value;
-    t->global.dirtied_local_settings = 1;
-    grpc_chttp2_initiate_write(exec_ctx, &t->global, false, "push_setting");
+  if (use_value != t->settings[GRPC_LOCAL_SETTINGS][id]) {
+    t->settings[GRPC_LOCAL_SETTINGS][id] = use_value;
+    t->dirtied_local_settings = 1;
+    grpc_chttp2_initiate_write(exec_ctx, t, false, "push_setting");
   }
 }
 
-/* error may be GRPC_ERROR_NONE if there is no error allocated yet.
-   In that case, use "reason" as the text for a new error. */
-static void end_waiting_for_write(grpc_exec_ctx *exec_ctx,
-                                  grpc_chttp2_transport *t, grpc_error *error,
-                                  const char *reason) {
-  grpc_chttp2_stream_global *stream_global;
-  while (grpc_chttp2_list_pop_closed_waiting_for_writing(&t->global,
-                                                         &stream_global)) {
-    if (error == GRPC_ERROR_NONE && reason != NULL) {
-      /* create error object. */
-      error = GRPC_ERROR_CREATE(reason);
-    }
-    fail_pending_writes(exec_ctx, &t->global, stream_global,
-                        GRPC_ERROR_REF(error));
-    GRPC_CHTTP2_STREAM_UNREF(exec_ctx, stream_global, "finish_writes");
-  }
-  GRPC_ERROR_UNREF(error);
-}
-
-static void terminate_writing_with_lock(grpc_exec_ctx *exec_ctx,
-                                        grpc_chttp2_transport *t,
-                                        grpc_chttp2_stream *s_ignored,
-                                        void *a) {
-  grpc_error *error = a;
-
-  allow_endpoint_shutdown_locked(exec_ctx, t);
-
-  if (error != GRPC_ERROR_NONE) {
-    drop_connection(exec_ctx, t, GRPC_ERROR_REF(error));
-  }
-
-  grpc_chttp2_cleanup_writing(exec_ctx, &t->global, &t->writing);
-
-  end_waiting_for_write(exec_ctx, t, error, NULL);
-
-  switch (t->executor.write_state) {
-    case GRPC_CHTTP2_WRITING_INACTIVE:
-    case GRPC_CHTTP2_WRITE_REQUESTED_WITH_POLLER:
-    case GRPC_CHTTP2_WRITE_REQUESTED_NO_POLLER:
-    case GRPC_CHTTP2_WRITE_SCHEDULED:
-      GPR_UNREACHABLE_CODE(break);
-    case GRPC_CHTTP2_WRITING:
-      set_write_state(t, GRPC_CHTTP2_WRITING_INACTIVE, "terminate_writing");
-      break;
-    case GRPC_CHTTP2_WRITING_STALE_WITH_POLLER:
-      set_write_state(t, GRPC_CHTTP2_WRITE_REQUESTED_WITH_POLLER,
-                      "terminate_writing");
-      break;
-    case GRPC_CHTTP2_WRITING_STALE_NO_POLLER:
-      set_write_state(t, GRPC_CHTTP2_WRITE_REQUESTED_NO_POLLER,
-                      "terminate_writing");
-      break;
-  }
-
-  if (t->ep && !t->endpoint_reading) {
-    destroy_endpoint(exec_ctx, t);
-  }
-
-  UNREF_TRANSPORT(exec_ctx, t, "writing");
-}
-
-void grpc_chttp2_terminate_writing(grpc_exec_ctx *exec_ctx,
-                                   void *transport_writing, grpc_error *error) {
-  grpc_chttp2_transport *t = TRANSPORT_FROM_WRITING(transport_writing);
-  grpc_chttp2_run_with_global_lock(
-      exec_ctx, t, NULL, terminate_writing_with_lock, GRPC_ERROR_REF(error), 0);
-}
-
-static void writing_action(grpc_exec_ctx *exec_ctx, void *gt,
-                           grpc_error *error) {
-  grpc_chttp2_transport *t = gt;
-  GPR_TIMER_BEGIN("writing_action", 0);
-  grpc_chttp2_perform_writes(exec_ctx, &t->writing, t->ep);
-  GPR_TIMER_END("writing_action", 0);
-}
-
-void grpc_chttp2_add_incoming_goaway(
-    grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_global *transport_global,
-    uint32_t goaway_error, gpr_slice goaway_text) {
+void grpc_chttp2_add_incoming_goaway(grpc_exec_ctx *exec_ctx,
+                                     grpc_chttp2_transport *t,
+                                     uint32_t goaway_error,
+                                     gpr_slice goaway_text) {
   char *msg = gpr_dump_slice(goaway_text, GPR_DUMP_HEX | GPR_DUMP_ASCII);
   GRPC_CHTTP2_IF_TRACING(
       gpr_log(GPR_DEBUG, "got goaway [%d]: %s", goaway_error, msg));
   gpr_slice_unref(goaway_text);
-  transport_global->seen_goaway = 1;
+  t->seen_goaway = 1;
   /* lie: use transient failure from the transport to indicate goaway has been
    * received */
   connectivity_state_set(
-      exec_ctx, transport_global, GRPC_CHANNEL_TRANSIENT_FAILURE,
+      exec_ctx, t, GRPC_CHANNEL_TRANSIENT_FAILURE,
       grpc_error_set_str(
           grpc_error_set_int(GRPC_ERROR_CREATE("GOAWAY received"),
                              GRPC_ERROR_INT_HTTP2_ERROR,
@@ -1023,61 +710,49 @@
   gpr_free(msg);
 }
 
-static void maybe_start_some_streams(
-    grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_global *transport_global) {
-  grpc_chttp2_stream_global *stream_global;
+static void maybe_start_some_streams(grpc_exec_ctx *exec_ctx,
+                                     grpc_chttp2_transport *t) {
+  grpc_chttp2_stream *s;
   uint32_t stream_incoming_window;
   /* start streams where we have free grpc_chttp2_stream ids and free
    * concurrency */
-  while (transport_global->next_stream_id <= MAX_CLIENT_STREAM_ID &&
-         transport_global->concurrent_stream_count <
-             transport_global
-                 ->settings[GRPC_PEER_SETTINGS]
-                           [GRPC_CHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS] &&
-         grpc_chttp2_list_pop_waiting_for_concurrency(transport_global,
-                                                      &stream_global)) {
+  while (t->next_stream_id <= MAX_CLIENT_STREAM_ID &&
+         grpc_chttp2_stream_map_size(&t->stream_map) <
+             t->settings[GRPC_PEER_SETTINGS]
+                        [GRPC_CHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS] &&
+         grpc_chttp2_list_pop_waiting_for_concurrency(t, &s)) {
     /* safe since we can't (legally) be parsing this stream yet */
-    grpc_chttp2_stream_parsing *stream_parsing =
-        &STREAM_FROM_GLOBAL(stream_global)->parsing;
     GRPC_CHTTP2_IF_TRACING(gpr_log(
         GPR_DEBUG, "HTTP:%s: Allocating new grpc_chttp2_stream %p to id %d",
-        transport_global->is_client ? "CLI" : "SVR", stream_global,
-        transport_global->next_stream_id));
+        t->is_client ? "CLI" : "SVR", s, t->next_stream_id));
 
-    GPR_ASSERT(stream_global->id == 0);
-    stream_global->id = stream_parsing->id = transport_global->next_stream_id;
-    transport_global->next_stream_id += 2;
+    GPR_ASSERT(s->id == 0);
+    s->id = t->next_stream_id;
+    t->next_stream_id += 2;
 
-    if (transport_global->next_stream_id >= MAX_CLIENT_STREAM_ID) {
-      connectivity_state_set(
-          exec_ctx, transport_global, GRPC_CHANNEL_TRANSIENT_FAILURE,
-          GRPC_ERROR_CREATE("Stream IDs exhausted"), "no_more_stream_ids");
+    if (t->next_stream_id >= MAX_CLIENT_STREAM_ID) {
+      connectivity_state_set(exec_ctx, t, GRPC_CHANNEL_TRANSIENT_FAILURE,
+                             GRPC_ERROR_CREATE("Stream IDs exhausted"),
+                             "no_more_stream_ids");
     }
 
-    stream_global->outgoing_window =
-        transport_global->settings[GRPC_PEER_SETTINGS]
-                                  [GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE];
-    stream_parsing->incoming_window = stream_incoming_window =
-        transport_global->settings[GRPC_SENT_SETTINGS]
-                                  [GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE];
-    stream_global->max_recv_bytes =
-        GPR_MAX(stream_incoming_window, stream_global->max_recv_bytes);
-    grpc_chttp2_stream_map_add(
-        &TRANSPORT_FROM_GLOBAL(transport_global)->new_stream_map,
-        stream_global->id, STREAM_FROM_GLOBAL(stream_global));
-    stream_global->in_stream_map = true;
-    transport_global->concurrent_stream_count++;
-    grpc_chttp2_become_writable(exec_ctx, transport_global, stream_global, true,
-                                "new_stream");
+    s->outgoing_window = t->settings[GRPC_PEER_SETTINGS]
+                                    [GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE];
+    s->incoming_window = stream_incoming_window =
+        t->settings[GRPC_SENT_SETTINGS]
+                   [GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE];
+    s->max_recv_bytes = GPR_MAX(stream_incoming_window, s->max_recv_bytes);
+    grpc_chttp2_stream_map_add(&t->stream_map, s->id, s);
+    grpc_chttp2_become_writable(exec_ctx, t, s, true, "new_stream");
   }
   /* cancel out streams that will never be started */
-  while (transport_global->next_stream_id >= MAX_CLIENT_STREAM_ID &&
-         grpc_chttp2_list_pop_waiting_for_concurrency(transport_global,
-                                                      &stream_global)) {
-    cancel_from_api(exec_ctx, transport_global, stream_global,
-                    grpc_error_set_int(
-                        GRPC_ERROR_CREATE("Stream IDs exhausted"),
-                        GRPC_ERROR_INT_GRPC_STATUS, GRPC_STATUS_UNAVAILABLE));
+  while (t->next_stream_id >= MAX_CLIENT_STREAM_ID &&
+         grpc_chttp2_list_pop_waiting_for_concurrency(t, &s)) {
+    grpc_chttp2_cancel_stream(
+        exec_ctx, t, s,
+        grpc_error_set_int(GRPC_ERROR_CREATE("Stream IDs exhausted"),
+                           GRPC_ERROR_INT_GRPC_STATUS,
+                           GRPC_STATUS_UNAVAILABLE));
   }
 }
 
@@ -1089,104 +764,188 @@
   return closure;
 }
 
-void grpc_chttp2_complete_closure_step(
-    grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_global *transport_global,
-    grpc_chttp2_stream_global *stream_global, grpc_closure **pclosure,
-    grpc_error *error) {
+static void null_then_run_closure(grpc_exec_ctx *exec_ctx,
+                                  grpc_closure **closure, grpc_error *error) {
+  grpc_closure *c = *closure;
+  *closure = NULL;
+  grpc_closure_run(exec_ctx, c, error);
+}
+
+void grpc_chttp2_complete_closure_step(grpc_exec_ctx *exec_ctx,
+                                       grpc_chttp2_transport *t,
+                                       grpc_chttp2_stream *s,
+                                       grpc_closure **pclosure,
+                                       grpc_error *error, const char *desc) {
   grpc_closure *closure = *pclosure;
+  *pclosure = NULL;
   if (closure == NULL) {
     GRPC_ERROR_UNREF(error);
     return;
   }
   closure->next_data.scratch -= CLOSURE_BARRIER_FIRST_REF_BIT;
   if (error != GRPC_ERROR_NONE) {
-    if (closure->error == GRPC_ERROR_NONE) {
-      closure->error =
+    if (closure->error_data.error == GRPC_ERROR_NONE) {
+      closure->error_data.error =
           GRPC_ERROR_CREATE("Error in HTTP transport completing operation");
-      closure->error = grpc_error_set_str(
-          closure->error, GRPC_ERROR_STR_TARGET_ADDRESS,
-          TRANSPORT_FROM_GLOBAL(transport_global)->peer_string);
+      closure->error_data.error =
+          grpc_error_set_str(closure->error_data.error,
+                             GRPC_ERROR_STR_TARGET_ADDRESS, t->peer_string);
     }
-    closure->error = grpc_error_add_child(closure->error, error);
+    closure->error_data.error =
+        grpc_error_add_child(closure->error_data.error, error);
   }
   if (closure->next_data.scratch < CLOSURE_BARRIER_FIRST_REF_BIT) {
     if (closure->next_data.scratch & CLOSURE_BARRIER_STATS_BIT) {
-      grpc_transport_move_stats(&stream_global->stats,
-                                stream_global->collecting_stats);
-      stream_global->collecting_stats = NULL;
+      grpc_transport_move_stats(&s->stats, s->collecting_stats);
+      s->collecting_stats = NULL;
     }
-    grpc_exec_ctx_sched(exec_ctx, closure, closure->error, NULL);
+    grpc_closure_run(exec_ctx, closure, closure->error_data.error);
   }
-  *pclosure = NULL;
 }
 
-static int contains_non_ok_status(
-    grpc_chttp2_transport_global *transport_global,
-    grpc_metadata_batch *batch) {
+static bool contains_non_ok_status(grpc_metadata_batch *batch) {
   grpc_linked_mdelem *l;
   for (l = batch->list.head; l; l = l->next) {
     if (l->md->key == GRPC_MDSTR_GRPC_STATUS &&
         l->md != GRPC_MDELEM_GRPC_STATUS_0) {
-      return 1;
+      return true;
     }
   }
-  return 0;
+  return false;
+}
+
+static void add_fetched_slice_locked(grpc_exec_ctx *exec_ctx,
+                                     grpc_chttp2_transport *t,
+                                     grpc_chttp2_stream *s);
+
+static void continue_fetching_send_locked(grpc_exec_ctx *exec_ctx,
+                                          grpc_chttp2_transport *t,
+                                          grpc_chttp2_stream *s) {
+  if (s->fetching_send_message == NULL) {
+    /* Stream was cancelled before message fetch completed */
+    abort(); /* TODO(ctiller): what cleanup here? */
+    return;
+  }
+  if (s->fetched_send_message_length == s->fetching_send_message->length) {
+    ssize_t notify_offset = s->fetching_slice_end_offset;
+    if (notify_offset <= 0) {
+      grpc_chttp2_complete_closure_step(
+          exec_ctx, t, s, &s->fetching_send_message_finished, GRPC_ERROR_NONE,
+          "fetching_send_message_finished");
+    } else {
+      grpc_chttp2_write_cb *cb = t->write_cb_pool;
+      if (cb == NULL) {
+        cb = gpr_malloc(sizeof(*cb));
+      } else {
+        t->write_cb_pool = cb->next;
+      }
+      cb->call_at_byte = (size_t)notify_offset;
+      cb->closure = s->fetching_send_message_finished;
+      s->fetching_send_message_finished = NULL;
+      cb->next = s->on_write_finished_cbs;
+      s->on_write_finished_cbs = cb;
+    }
+    s->fetching_send_message = NULL;
+  } else if (grpc_byte_stream_next(exec_ctx, s->fetching_send_message,
+                                   &s->fetching_slice, UINT32_MAX,
+                                   &s->complete_fetch)) {
+    add_fetched_slice_locked(exec_ctx, t, s);
+  }
+}
+
+static void add_fetched_slice_locked(grpc_exec_ctx *exec_ctx,
+                                     grpc_chttp2_transport *t,
+                                     grpc_chttp2_stream *s) {
+  s->fetched_send_message_length +=
+      (uint32_t)GPR_SLICE_LENGTH(s->fetching_slice);
+  gpr_slice_buffer_add(&s->flow_controlled_buffer, s->fetching_slice);
+  if (s->id != 0) {
+    grpc_chttp2_become_writable(exec_ctx, t, s, true, "op.send_message");
+  }
+  continue_fetching_send_locked(exec_ctx, t, s);
+}
+
+static void complete_fetch_locked(grpc_exec_ctx *exec_ctx, void *gs,
+                                  grpc_error *error) {
+  grpc_chttp2_stream *s = gs;
+  grpc_chttp2_transport *t = s->t;
+  if (error == GRPC_ERROR_NONE) {
+    add_fetched_slice_locked(exec_ctx, t, s);
+  } else {
+    /* TODO(ctiller): what to do here */
+    abort();
+  }
+}
+
+static void complete_fetch(grpc_exec_ctx *exec_ctx, void *gs,
+                           grpc_error *error) {
+  grpc_chttp2_stream *s = gs;
+  grpc_chttp2_transport *t = s->t;
+  grpc_combiner_execute(exec_ctx, t->combiner, &s->complete_fetch_locked,
+                        GRPC_ERROR_REF(error),
+                        s->complete_fetch_covered_by_poller);
 }
 
 static void do_nothing(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *error) {}
 
-static void perform_stream_op_locked(grpc_exec_ctx *exec_ctx,
-                                     grpc_chttp2_transport *t,
-                                     grpc_chttp2_stream *s, void *stream_op) {
+static void perform_stream_op_locked(grpc_exec_ctx *exec_ctx, void *stream_op,
+                                     grpc_error *error_ignored) {
   GPR_TIMER_BEGIN("perform_stream_op_locked", 0);
 
   grpc_transport_stream_op *op = stream_op;
-  grpc_chttp2_transport_global *transport_global = &t->global;
-  grpc_chttp2_stream_global *stream_global = &s->global;
+  grpc_chttp2_transport *t = op->transport_private.args[0];
+  grpc_chttp2_stream *s = op->transport_private.args[1];
+
+  if (grpc_http_trace) {
+    char *str = grpc_transport_stream_op_string(op);
+    gpr_log(GPR_DEBUG, "perform_stream_op_locked: %s", str);
+    gpr_free(str);
+  }
 
   grpc_closure *on_complete = op->on_complete;
   if (on_complete == NULL) {
     on_complete = grpc_closure_create(do_nothing, NULL);
   }
+
+  if (grpc_http_trace) {
+    gpr_log(GPR_DEBUG, "  on_complete = %p", on_complete);
+  }
+
   /* use final_data as a barrier until enqueue time; the inital counter is
      dropped at the end of this function */
   on_complete->next_data.scratch = CLOSURE_BARRIER_FIRST_REF_BIT;
-  on_complete->error = GRPC_ERROR_NONE;
+  on_complete->error_data.error = GRPC_ERROR_NONE;
 
   if (op->collect_stats != NULL) {
-    GPR_ASSERT(stream_global->collecting_stats == NULL);
-    stream_global->collecting_stats = op->collect_stats;
+    GPR_ASSERT(s->collecting_stats == NULL);
+    s->collecting_stats = op->collect_stats;
     on_complete->next_data.scratch |= CLOSURE_BARRIER_STATS_BIT;
   }
 
   if (op->cancel_error != GRPC_ERROR_NONE) {
-    cancel_from_api(exec_ctx, transport_global, stream_global,
-                    GRPC_ERROR_REF(op->cancel_error));
+    grpc_chttp2_cancel_stream(exec_ctx, t, s, GRPC_ERROR_REF(op->cancel_error));
   }
 
   if (op->close_error != GRPC_ERROR_NONE) {
-    close_from_api(exec_ctx, transport_global, stream_global,
-                   GRPC_ERROR_REF(op->close_error));
+    close_from_api(exec_ctx, t, s, GRPC_ERROR_REF(op->close_error));
   }
 
   if (op->send_initial_metadata != NULL) {
-    GPR_ASSERT(stream_global->send_initial_metadata_finished == NULL);
-    stream_global->send_initial_metadata_finished =
-        add_closure_barrier(on_complete);
-    stream_global->send_initial_metadata = op->send_initial_metadata;
+    GPR_ASSERT(s->send_initial_metadata_finished == NULL);
+    s->send_initial_metadata_finished = add_closure_barrier(on_complete);
+    s->send_initial_metadata = op->send_initial_metadata;
     const size_t metadata_size =
         grpc_metadata_batch_size(op->send_initial_metadata);
     const size_t metadata_peer_limit =
-        transport_global->settings[GRPC_PEER_SETTINGS]
-                                  [GRPC_CHTTP2_SETTINGS_MAX_HEADER_LIST_SIZE];
-    if (transport_global->is_client) {
-      stream_global->deadline =
-          gpr_time_min(stream_global->deadline,
-                       stream_global->send_initial_metadata->deadline);
+        t->settings[GRPC_PEER_SETTINGS]
+                   [GRPC_CHTTP2_SETTINGS_MAX_HEADER_LIST_SIZE];
+    if (t->is_client) {
+      s->deadline =
+          gpr_time_min(s->deadline, s->send_initial_metadata->deadline);
     }
     if (metadata_size > metadata_peer_limit) {
-      cancel_from_api(
-          exec_ctx, transport_global, stream_global,
+      grpc_chttp2_cancel_stream(
+          exec_ctx, t, s,
           grpc_error_set_int(
               grpc_error_set_int(
                   grpc_error_set_int(
@@ -1196,63 +955,75 @@
                   GRPC_ERROR_INT_LIMIT, (intptr_t)metadata_peer_limit),
               GRPC_ERROR_INT_GRPC_STATUS, GRPC_STATUS_RESOURCE_EXHAUSTED));
     } else {
-      if (contains_non_ok_status(transport_global, op->send_initial_metadata)) {
-        stream_global->seen_error = true;
-        grpc_chttp2_list_add_check_read_ops(transport_global, stream_global);
+      if (contains_non_ok_status(op->send_initial_metadata)) {
+        s->seen_error = true;
       }
-      if (!stream_global->write_closed) {
-        if (transport_global->is_client) {
-          GPR_ASSERT(stream_global->id == 0);
-          grpc_chttp2_list_add_waiting_for_concurrency(transport_global,
-                                                       stream_global);
-          maybe_start_some_streams(exec_ctx, transport_global);
+      if (!s->write_closed) {
+        if (t->is_client) {
+          GPR_ASSERT(s->id == 0);
+          grpc_chttp2_list_add_waiting_for_concurrency(t, s);
+          maybe_start_some_streams(exec_ctx, t);
         } else {
-          GPR_ASSERT(stream_global->id != 0);
-          grpc_chttp2_become_writable(exec_ctx, transport_global, stream_global,
-                                      true, "op.send_initial_metadata");
+          GPR_ASSERT(s->id != 0);
+          grpc_chttp2_become_writable(exec_ctx, t, s, true,
+                                      "op.send_initial_metadata");
         }
       } else {
-        stream_global->send_trailing_metadata = NULL;
+        s->send_trailing_metadata = NULL;
         grpc_chttp2_complete_closure_step(
-            exec_ctx, transport_global, stream_global,
-            &stream_global->send_initial_metadata_finished,
+            exec_ctx, t, s, &s->send_initial_metadata_finished,
             GRPC_ERROR_CREATE(
-                "Attempt to send initial metadata after stream was closed"));
+                "Attempt to send initial metadata after stream was closed"),
+            "send_initial_metadata_finished");
       }
     }
   }
 
   if (op->send_message != NULL) {
-    GPR_ASSERT(stream_global->send_message_finished == NULL);
-    GPR_ASSERT(stream_global->send_message == NULL);
-    stream_global->send_message_finished = add_closure_barrier(on_complete);
-    if (stream_global->write_closed) {
+    s->fetching_send_message_finished = add_closure_barrier(op->on_complete);
+    if (s->write_closed) {
       grpc_chttp2_complete_closure_step(
-          exec_ctx, transport_global, stream_global,
-          &stream_global->send_message_finished,
-          GRPC_ERROR_CREATE("Attempt to send message after stream was closed"));
+          exec_ctx, t, s, &s->fetching_send_message_finished,
+          GRPC_ERROR_CREATE("Attempt to send message after stream was closed"),
+          "fetching_send_message_finished");
     } else {
-      stream_global->send_message = op->send_message;
-      if (stream_global->id != 0) {
-        grpc_chttp2_become_writable(exec_ctx, transport_global, stream_global,
-                                    true, "op.send_message");
+      GPR_ASSERT(s->fetching_send_message == NULL);
+      uint8_t *frame_hdr =
+          gpr_slice_buffer_tiny_add(&s->flow_controlled_buffer, 5);
+      uint32_t flags = op->send_message->flags;
+      frame_hdr[0] = (flags & GRPC_WRITE_INTERNAL_COMPRESS) != 0;
+      size_t len = op->send_message->length;
+      frame_hdr[1] = (uint8_t)(len >> 24);
+      frame_hdr[2] = (uint8_t)(len >> 16);
+      frame_hdr[3] = (uint8_t)(len >> 8);
+      frame_hdr[4] = (uint8_t)(len);
+      s->fetching_send_message = op->send_message;
+      s->fetched_send_message_length = 0;
+      s->fetching_slice_end_offset =
+          (ssize_t)s->flow_controlled_buffer.length + (ssize_t)len;
+      s->complete_fetch_covered_by_poller = op->covered_by_poller;
+      if (flags & GRPC_WRITE_BUFFER_HINT) {
+        s->fetching_slice_end_offset -= 65536;
+      }
+      continue_fetching_send_locked(exec_ctx, t, s);
+      if (s->id != 0) {
+        grpc_chttp2_become_writable(exec_ctx, t, s, true, "op.send_message");
       }
     }
   }
 
   if (op->send_trailing_metadata != NULL) {
-    GPR_ASSERT(stream_global->send_trailing_metadata_finished == NULL);
-    stream_global->send_trailing_metadata_finished =
-        add_closure_barrier(on_complete);
-    stream_global->send_trailing_metadata = op->send_trailing_metadata;
+    GPR_ASSERT(s->send_trailing_metadata_finished == NULL);
+    s->send_trailing_metadata_finished = add_closure_barrier(on_complete);
+    s->send_trailing_metadata = op->send_trailing_metadata;
     const size_t metadata_size =
         grpc_metadata_batch_size(op->send_trailing_metadata);
     const size_t metadata_peer_limit =
-        transport_global->settings[GRPC_PEER_SETTINGS]
-                                  [GRPC_CHTTP2_SETTINGS_MAX_HEADER_LIST_SIZE];
+        t->settings[GRPC_PEER_SETTINGS]
+                   [GRPC_CHTTP2_SETTINGS_MAX_HEADER_LIST_SIZE];
     if (metadata_size > metadata_peer_limit) {
-      cancel_from_api(
-          exec_ctx, transport_global, stream_global,
+      grpc_chttp2_cancel_stream(
+          exec_ctx, t, s,
           grpc_error_set_int(
               grpc_error_set_int(
                   grpc_error_set_int(
@@ -1262,135 +1033,129 @@
                   GRPC_ERROR_INT_LIMIT, (intptr_t)metadata_peer_limit),
               GRPC_ERROR_INT_GRPC_STATUS, GRPC_STATUS_RESOURCE_EXHAUSTED));
     } else {
-      if (contains_non_ok_status(transport_global,
-                                 op->send_trailing_metadata)) {
-        stream_global->seen_error = true;
-        grpc_chttp2_list_add_check_read_ops(transport_global, stream_global);
+      if (contains_non_ok_status(op->send_trailing_metadata)) {
+        s->seen_error = true;
       }
-      if (stream_global->write_closed) {
-        stream_global->send_trailing_metadata = NULL;
+      if (s->write_closed) {
+        s->send_trailing_metadata = NULL;
         grpc_chttp2_complete_closure_step(
-            exec_ctx, transport_global, stream_global,
-            &stream_global->send_trailing_metadata_finished,
+            exec_ctx, t, s, &s->send_trailing_metadata_finished,
             grpc_metadata_batch_is_empty(op->send_trailing_metadata)
                 ? GRPC_ERROR_NONE
                 : GRPC_ERROR_CREATE("Attempt to send trailing metadata after "
-                                    "stream was closed"));
-      } else if (stream_global->id != 0) {
+                                    "stream was closed"),
+            "send_trailing_metadata_finished");
+      } else if (s->id != 0) {
         /* TODO(ctiller): check if there's flow control for any outstanding
            bytes before going writable */
-        grpc_chttp2_become_writable(exec_ctx, transport_global, stream_global,
-                                    true, "op.send_trailing_metadata");
+        grpc_chttp2_become_writable(exec_ctx, t, s, true,
+                                    "op.send_trailing_metadata");
       }
     }
   }
 
   if (op->recv_initial_metadata != NULL) {
-    GPR_ASSERT(stream_global->recv_initial_metadata_ready == NULL);
-    stream_global->recv_initial_metadata_ready =
-        op->recv_initial_metadata_ready;
-    stream_global->recv_initial_metadata = op->recv_initial_metadata;
-    grpc_chttp2_list_add_check_read_ops(transport_global, stream_global);
+    GPR_ASSERT(s->recv_initial_metadata_ready == NULL);
+    s->recv_initial_metadata_ready = op->recv_initial_metadata_ready;
+    s->recv_initial_metadata = op->recv_initial_metadata;
+    grpc_chttp2_maybe_complete_recv_initial_metadata(exec_ctx, t, s);
   }
 
   if (op->recv_message != NULL) {
-    GPR_ASSERT(stream_global->recv_message_ready == NULL);
-    stream_global->recv_message_ready = op->recv_message_ready;
-    stream_global->recv_message = op->recv_message;
-    if (stream_global->id != 0 &&
-        (stream_global->incoming_frames.head == NULL ||
-         stream_global->incoming_frames.head->is_tail)) {
-      incoming_byte_stream_update_flow_control(
-          exec_ctx, transport_global, stream_global,
-          transport_global->stream_lookahead, 0);
+    GPR_ASSERT(s->recv_message_ready == NULL);
+    s->recv_message_ready = op->recv_message_ready;
+    s->recv_message = op->recv_message;
+    if (s->id != 0 &&
+        (s->incoming_frames.head == NULL || s->incoming_frames.head->is_tail)) {
+      incoming_byte_stream_update_flow_control(exec_ctx, t, s,
+                                               t->stream_lookahead, 0);
     }
-    grpc_chttp2_list_add_check_read_ops(transport_global, stream_global);
+    grpc_chttp2_maybe_complete_recv_message(exec_ctx, t, s);
   }
 
   if (op->recv_trailing_metadata != NULL) {
-    GPR_ASSERT(stream_global->recv_trailing_metadata_finished == NULL);
-    stream_global->recv_trailing_metadata_finished =
-        add_closure_barrier(on_complete);
-    stream_global->recv_trailing_metadata = op->recv_trailing_metadata;
-    stream_global->final_metadata_requested = true;
-    grpc_chttp2_list_add_check_read_ops(transport_global, stream_global);
+    GPR_ASSERT(s->recv_trailing_metadata_finished == NULL);
+    s->recv_trailing_metadata_finished = add_closure_barrier(on_complete);
+    s->recv_trailing_metadata = op->recv_trailing_metadata;
+    s->final_metadata_requested = true;
+    grpc_chttp2_maybe_complete_recv_trailing_metadata(exec_ctx, t, s);
   }
 
-  grpc_chttp2_complete_closure_step(exec_ctx, transport_global, stream_global,
-                                    &on_complete, GRPC_ERROR_NONE);
+  grpc_chttp2_complete_closure_step(exec_ctx, t, s, &on_complete,
+                                    GRPC_ERROR_NONE, "op->on_complete");
 
   GPR_TIMER_END("perform_stream_op_locked", 0);
+  GRPC_CHTTP2_STREAM_UNREF(exec_ctx, s, "perform_stream_op");
 }
 
 static void perform_stream_op(grpc_exec_ctx *exec_ctx, grpc_transport *gt,
                               grpc_stream *gs, grpc_transport_stream_op *op) {
+  GPR_TIMER_BEGIN("perform_stream_op", 0);
   grpc_chttp2_transport *t = (grpc_chttp2_transport *)gt;
   grpc_chttp2_stream *s = (grpc_chttp2_stream *)gs;
-  grpc_chttp2_run_with_global_lock(exec_ctx, t, s, perform_stream_op_locked, op,
-                                   sizeof(*op));
+
+  if (grpc_http_trace) {
+    char *str = grpc_transport_stream_op_string(op);
+    gpr_log(GPR_DEBUG, "perform_stream_op: %s", str);
+    gpr_free(str);
+  }
+
+  grpc_closure_init(&op->transport_private.closure, perform_stream_op_locked,
+                    op);
+  op->transport_private.args[0] = gt;
+  op->transport_private.args[1] = gs;
+  GRPC_CHTTP2_STREAM_REF(s, "perform_stream_op");
+  grpc_combiner_execute(exec_ctx, t->combiner, &op->transport_private.closure,
+                        GRPC_ERROR_NONE, op->covered_by_poller);
+  GPR_TIMER_END("perform_stream_op", 0);
 }
 
 static void send_ping_locked(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t,
                              grpc_closure *on_recv) {
   grpc_chttp2_outstanding_ping *p = gpr_malloc(sizeof(*p));
-  p->next = &t->global.pings;
+  p->next = &t->pings;
   p->prev = p->next->prev;
   p->prev->next = p->next->prev = p;
-  p->id[0] = (uint8_t)((t->global.ping_counter >> 56) & 0xff);
-  p->id[1] = (uint8_t)((t->global.ping_counter >> 48) & 0xff);
-  p->id[2] = (uint8_t)((t->global.ping_counter >> 40) & 0xff);
-  p->id[3] = (uint8_t)((t->global.ping_counter >> 32) & 0xff);
-  p->id[4] = (uint8_t)((t->global.ping_counter >> 24) & 0xff);
-  p->id[5] = (uint8_t)((t->global.ping_counter >> 16) & 0xff);
-  p->id[6] = (uint8_t)((t->global.ping_counter >> 8) & 0xff);
-  p->id[7] = (uint8_t)(t->global.ping_counter & 0xff);
+  p->id[0] = (uint8_t)((t->ping_counter >> 56) & 0xff);
+  p->id[1] = (uint8_t)((t->ping_counter >> 48) & 0xff);
+  p->id[2] = (uint8_t)((t->ping_counter >> 40) & 0xff);
+  p->id[3] = (uint8_t)((t->ping_counter >> 32) & 0xff);
+  p->id[4] = (uint8_t)((t->ping_counter >> 24) & 0xff);
+  p->id[5] = (uint8_t)((t->ping_counter >> 16) & 0xff);
+  p->id[6] = (uint8_t)((t->ping_counter >> 8) & 0xff);
+  p->id[7] = (uint8_t)(t->ping_counter & 0xff);
+  t->ping_counter++;
   p->on_recv = on_recv;
-  gpr_slice_buffer_add(&t->global.qbuf, grpc_chttp2_ping_create(0, p->id));
-  grpc_chttp2_initiate_write(exec_ctx, &t->global, true, "send_ping");
+  gpr_slice_buffer_add(&t->qbuf, grpc_chttp2_ping_create(0, p->id));
+  grpc_chttp2_initiate_write(exec_ctx, t, true, "send_ping");
 }
 
-static void ack_ping_locked(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t,
-                            grpc_chttp2_stream *s, void *opaque_8bytes) {
+void grpc_chttp2_ack_ping(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t,
+                          const uint8_t *opaque_8bytes) {
   grpc_chttp2_outstanding_ping *ping;
-  grpc_chttp2_transport_global *transport_global = &t->global;
-  for (ping = transport_global->pings.next; ping != &transport_global->pings;
-       ping = ping->next) {
+  for (ping = t->pings.next; ping != &t->pings; ping = ping->next) {
     if (0 == memcmp(opaque_8bytes, ping->id, 8)) {
       grpc_exec_ctx_sched(exec_ctx, ping->on_recv, GRPC_ERROR_NONE, NULL);
       ping->next->prev = ping->prev;
       ping->prev->next = ping->next;
       gpr_free(ping);
-      break;
+      return;
     }
   }
-}
-
-void grpc_chttp2_ack_ping(grpc_exec_ctx *exec_ctx,
-                          grpc_chttp2_transport_parsing *transport_parsing,
-                          const uint8_t *opaque_8bytes) {
-  grpc_chttp2_run_with_global_lock(
-      exec_ctx, TRANSPORT_FROM_PARSING(transport_parsing), NULL,
-      ack_ping_locked, (void *)opaque_8bytes, 8);
+  char *msg = gpr_dump((const char *)opaque_8bytes, 8, GPR_DUMP_HEX);
+  char *from = grpc_endpoint_get_peer(t->ep);
+  gpr_log(GPR_DEBUG, "Unknown ping response from %s: %s", from, msg);
+  gpr_free(from);
+  gpr_free(msg);
 }
 
 static void perform_transport_op_locked(grpc_exec_ctx *exec_ctx,
-                                        grpc_chttp2_transport *t,
-                                        grpc_chttp2_stream *s_unused,
-                                        void *stream_op) {
+                                        void *stream_op,
+                                        grpc_error *error_ignored) {
   grpc_transport_op *op = stream_op;
+  grpc_chttp2_transport *t = op->transport_private.args[0];
   grpc_error *close_transport = op->disconnect_with_error;
 
-  /* If there's a set_accept_stream ensure that we're not parsing
-     to avoid changing things out from underneath */
-  if (t->executor.parsing_active && op->set_accept_stream) {
-    GPR_ASSERT(t->post_parsing_op == NULL);
-    t->post_parsing_op = gpr_malloc(sizeof(*op));
-    memcpy(t->post_parsing_op, op, sizeof(*op));
-    return;
-  }
-
-  grpc_exec_ctx_sched(exec_ctx, op->on_consumed, GRPC_ERROR_NONE, NULL);
-
   if (op->on_connectivity_state_change != NULL) {
     grpc_connectivity_state_notify_on_state_change(
         exec_ctx, &t->channel_callback.state_tracker, op->connectivity_state,
@@ -1398,15 +1163,15 @@
   }
 
   if (op->send_goaway) {
-    t->global.sent_goaway = 1;
+    t->sent_goaway = 1;
     grpc_chttp2_goaway_append(
-        t->global.last_incoming_stream_id,
+        t->last_incoming_stream_id,
         (uint32_t)grpc_chttp2_grpc_status_to_http2_error(op->goaway_status),
-        gpr_slice_ref(*op->goaway_message), &t->global.qbuf);
-    close_transport = grpc_chttp2_has_streams(t)
-                          ? GRPC_ERROR_NONE
-                          : GRPC_ERROR_CREATE("GOAWAY sent");
-    grpc_chttp2_initiate_write(exec_ctx, &t->global, false, "goaway_sent");
+        gpr_slice_ref(*op->goaway_message), &t->qbuf);
+    close_transport = grpc_chttp2_stream_map_size(&t->stream_map) == 0
+                          ? GRPC_ERROR_CREATE("GOAWAY sent")
+                          : GRPC_ERROR_NONE;
+    grpc_chttp2_initiate_write(exec_ctx, t, false, "goaway_sent");
   }
 
   if (op->set_accept_stream) {
@@ -1416,11 +1181,11 @@
   }
 
   if (op->bind_pollset) {
-    add_to_pollset_locked(exec_ctx, t, NULL, op->bind_pollset);
+    grpc_endpoint_add_to_pollset(exec_ctx, t->ep, op->bind_pollset);
   }
 
   if (op->bind_pollset_set) {
-    add_to_pollset_set_locked(exec_ctx, t, NULL, op->bind_pollset_set);
+    grpc_endpoint_add_to_pollset_set(exec_ctx, t->ep, op->bind_pollset_set);
   }
 
   if (op->send_ping) {
@@ -1430,144 +1195,131 @@
   if (close_transport != GRPC_ERROR_NONE) {
     close_transport_locked(exec_ctx, t, close_transport);
   }
+
+  grpc_closure_run(exec_ctx, op->on_consumed, GRPC_ERROR_NONE);
+
+  GRPC_CHTTP2_UNREF_TRANSPORT(exec_ctx, t, "transport_op");
 }
 
 static void perform_transport_op(grpc_exec_ctx *exec_ctx, grpc_transport *gt,
                                  grpc_transport_op *op) {
   grpc_chttp2_transport *t = (grpc_chttp2_transport *)gt;
-  grpc_chttp2_run_with_global_lock(
-      exec_ctx, t, NULL, perform_transport_op_locked, op, sizeof(*op));
+  char *msg = grpc_transport_op_string(op);
+  gpr_free(msg);
+  op->transport_private.args[0] = gt;
+  grpc_closure_init(&op->transport_private.closure, perform_transport_op_locked,
+                    op);
+  GRPC_CHTTP2_REF_TRANSPORT(t, "transport_op");
+  grpc_combiner_execute(exec_ctx, t->combiner, &op->transport_private.closure,
+                        GRPC_ERROR_NONE, false);
 }
 
 /*******************************************************************************
  * INPUT PROCESSING - GENERAL
  */
 
-static void check_read_ops(grpc_exec_ctx *exec_ctx,
-                           grpc_chttp2_transport_global *transport_global) {
-  grpc_chttp2_stream_global *stream_global;
+void grpc_chttp2_maybe_complete_recv_initial_metadata(grpc_exec_ctx *exec_ctx,
+                                                      grpc_chttp2_transport *t,
+                                                      grpc_chttp2_stream *s) {
   grpc_byte_stream *bs;
-  while (
-      grpc_chttp2_list_pop_check_read_ops(transport_global, &stream_global)) {
-    if (stream_global->recv_initial_metadata_ready != NULL &&
-        stream_global->published_initial_metadata) {
-      if (stream_global->seen_error) {
-        while ((bs = grpc_chttp2_incoming_frame_queue_pop(
-                    &stream_global->incoming_frames)) != NULL) {
-          incoming_byte_stream_destroy_locked(exec_ctx, NULL, NULL, bs);
-        }
-        if (stream_global->exceeded_metadata_size) {
-          cancel_from_api(
-              exec_ctx, transport_global, stream_global,
-              grpc_error_set_int(
-                  GRPC_ERROR_CREATE(
-                      "received initial metadata size exceeds limit"),
-                  GRPC_ERROR_INT_GRPC_STATUS, GRPC_STATUS_RESOURCE_EXHAUSTED));
-        }
-      }
-      grpc_chttp2_incoming_metadata_buffer_publish(
-          &stream_global->received_initial_metadata,
-          stream_global->recv_initial_metadata);
-      grpc_exec_ctx_sched(exec_ctx, stream_global->recv_initial_metadata_ready,
-                          GRPC_ERROR_NONE, NULL);
-      stream_global->recv_initial_metadata_ready = NULL;
-    }
-    if (stream_global->recv_message_ready != NULL) {
-      while (stream_global->final_metadata_requested &&
-             stream_global->seen_error &&
-             (bs = grpc_chttp2_incoming_frame_queue_pop(
-                  &stream_global->incoming_frames)) != NULL) {
-        incoming_byte_stream_destroy_locked(exec_ctx, NULL, NULL, bs);
-      }
-      if (stream_global->incoming_frames.head != NULL) {
-        *stream_global->recv_message = grpc_chttp2_incoming_frame_queue_pop(
-            &stream_global->incoming_frames);
-        GPR_ASSERT(*stream_global->recv_message != NULL);
-        grpc_exec_ctx_sched(exec_ctx, stream_global->recv_message_ready,
-                            GRPC_ERROR_NONE, NULL);
-        stream_global->recv_message_ready = NULL;
-      } else if (stream_global->published_trailing_metadata) {
-        *stream_global->recv_message = NULL;
-        grpc_exec_ctx_sched(exec_ctx, stream_global->recv_message_ready,
-                            GRPC_ERROR_NONE, NULL);
-        stream_global->recv_message_ready = NULL;
+  if (s->recv_initial_metadata_ready != NULL &&
+      s->published_metadata[0] != GRPC_METADATA_NOT_PUBLISHED) {
+    if (s->seen_error) {
+      while ((bs = grpc_chttp2_incoming_frame_queue_pop(&s->incoming_frames)) !=
+             NULL) {
+        gpr_log(GPR_DEBUG, "discard %p", bs);
+        incoming_byte_stream_destroy_locked(exec_ctx, bs, GRPC_ERROR_NONE);
       }
     }
-    if (stream_global->recv_trailing_metadata_finished != NULL &&
-        stream_global->read_closed && stream_global->write_closed) {
-      if (stream_global->seen_error) {
-        while ((bs = grpc_chttp2_incoming_frame_queue_pop(
-                    &stream_global->incoming_frames)) != NULL) {
-          incoming_byte_stream_destroy_locked(exec_ctx, NULL, NULL, bs);
-        }
-        if (stream_global->exceeded_metadata_size) {
-          cancel_from_api(
-              exec_ctx, transport_global, stream_global,
-              grpc_error_set_int(
-                  GRPC_ERROR_CREATE(
-                      "received trailing metadata size exceeds limit"),
-                  GRPC_ERROR_INT_GRPC_STATUS, GRPC_STATUS_RESOURCE_EXHAUSTED));
-        }
-      }
-      if (stream_global->all_incoming_byte_streams_finished) {
-        grpc_chttp2_incoming_metadata_buffer_publish(
-            &stream_global->received_trailing_metadata,
-            stream_global->recv_trailing_metadata);
-        grpc_chttp2_complete_closure_step(
-            exec_ctx, transport_global, stream_global,
-            &stream_global->recv_trailing_metadata_finished, GRPC_ERROR_NONE);
-      }
+    grpc_chttp2_incoming_metadata_buffer_publish(&s->metadata_buffer[0],
+                                                 s->recv_initial_metadata);
+    null_then_run_closure(exec_ctx, &s->recv_initial_metadata_ready,
+                          GRPC_ERROR_NONE);
+  }
+}
+
+void grpc_chttp2_maybe_complete_recv_message(grpc_exec_ctx *exec_ctx,
+                                             grpc_chttp2_transport *t,
+                                             grpc_chttp2_stream *s) {
+  grpc_byte_stream *bs;
+  if (s->recv_message_ready != NULL) {
+    while (s->final_metadata_requested && s->seen_error &&
+           (bs = grpc_chttp2_incoming_frame_queue_pop(&s->incoming_frames)) !=
+               NULL) {
+      gpr_log(GPR_DEBUG, "discard %p", bs);
+      incoming_byte_stream_destroy_locked(exec_ctx, bs, GRPC_ERROR_NONE);
+    }
+    if (s->incoming_frames.head != NULL) {
+      *s->recv_message =
+          grpc_chttp2_incoming_frame_queue_pop(&s->incoming_frames);
+      GPR_ASSERT(*s->recv_message != NULL);
+      null_then_run_closure(exec_ctx, &s->recv_message_ready, GRPC_ERROR_NONE);
+    } else if (s->published_metadata[1] != GRPC_METADATA_NOT_PUBLISHED) {
+      *s->recv_message = NULL;
+      null_then_run_closure(exec_ctx, &s->recv_message_ready, GRPC_ERROR_NONE);
     }
   }
 }
 
-static void decrement_active_streams_locked(
-    grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_global *transport_global,
-    grpc_chttp2_stream_global *stream_global) {
-  if ((stream_global->all_incoming_byte_streams_finished =
-           gpr_unref(&stream_global->active_streams))) {
-    grpc_chttp2_list_add_check_read_ops(transport_global, stream_global);
+void grpc_chttp2_maybe_complete_recv_trailing_metadata(grpc_exec_ctx *exec_ctx,
+                                                       grpc_chttp2_transport *t,
+                                                       grpc_chttp2_stream *s) {
+  grpc_byte_stream *bs;
+  grpc_chttp2_maybe_complete_recv_message(exec_ctx, t, s);
+  if (s->recv_trailing_metadata_finished != NULL && s->read_closed &&
+      s->write_closed) {
+    if (s->seen_error) {
+      while ((bs = grpc_chttp2_incoming_frame_queue_pop(&s->incoming_frames)) !=
+             NULL) {
+        gpr_log(GPR_DEBUG, "discard %p", bs);
+        incoming_byte_stream_destroy_locked(exec_ctx, bs, GRPC_ERROR_NONE);
+      }
+    }
+    if (s->all_incoming_byte_streams_finished &&
+        s->recv_trailing_metadata_finished != NULL) {
+      grpc_chttp2_incoming_metadata_buffer_publish(&s->metadata_buffer[1],
+                                                   s->recv_trailing_metadata);
+      grpc_chttp2_complete_closure_step(
+          exec_ctx, t, s, &s->recv_trailing_metadata_finished, GRPC_ERROR_NONE,
+          "recv_trailing_metadata_finished");
+    }
+  }
+}
+
+static void decrement_active_streams_locked(grpc_exec_ctx *exec_ctx,
+                                            grpc_chttp2_transport *t,
+                                            grpc_chttp2_stream *s) {
+  if ((s->all_incoming_byte_streams_finished = gpr_unref(&s->active_streams))) {
+    grpc_chttp2_maybe_complete_recv_trailing_metadata(exec_ctx, t, s);
   }
 }
 
 static void remove_stream(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t,
                           uint32_t id, grpc_error *error) {
-  size_t new_stream_count;
-  grpc_chttp2_stream *s =
-      grpc_chttp2_stream_map_delete(&t->parsing_stream_map, id);
-  if (!s) {
-    s = grpc_chttp2_stream_map_delete(&t->new_stream_map, id);
-  }
+  grpc_chttp2_stream *s = grpc_chttp2_stream_map_delete(&t->stream_map, id);
   GPR_ASSERT(s);
-  s->global.in_stream_map = false;
-  if (t->parsing.incoming_stream == &s->parsing) {
-    t->parsing.incoming_stream = NULL;
-    grpc_chttp2_parsing_become_skip_parser(exec_ctx, &t->parsing);
+  if (t->incoming_stream == s) {
+    t->incoming_stream = NULL;
+    grpc_chttp2_parsing_become_skip_parser(exec_ctx, t);
   }
-  if (s->parsing.data_parser.parsing_frame != NULL) {
+  if (s->data_parser.parsing_frame != NULL) {
     grpc_chttp2_incoming_byte_stream_finished(
-        exec_ctx, s->parsing.data_parser.parsing_frame, GRPC_ERROR_REF(error),
-        0);
-    s->parsing.data_parser.parsing_frame = NULL;
+        exec_ctx, s->data_parser.parsing_frame, GRPC_ERROR_REF(error));
+    s->data_parser.parsing_frame = NULL;
   }
 
-  if (grpc_chttp2_unregister_stream(t, s) && t->global.sent_goaway) {
+  if (grpc_chttp2_stream_map_size(&t->stream_map) == 0 && t->sent_goaway) {
     close_transport_locked(
         exec_ctx, t, GRPC_ERROR_CREATE_REFERENCING(
                          "Last stream closed after sending GOAWAY", &error, 1));
   }
-  if (grpc_chttp2_list_remove_writable_stream(&t->global, &s->global)) {
-    GRPC_CHTTP2_STREAM_UNREF(exec_ctx, &s->global, "chttp2_writing");
+  if (grpc_chttp2_list_remove_writable_stream(t, s)) {
+    GRPC_CHTTP2_STREAM_UNREF(exec_ctx, s, "chttp2_writing:remove_stream");
   }
 
-  new_stream_count = grpc_chttp2_stream_map_size(&t->parsing_stream_map) +
-                     grpc_chttp2_stream_map_size(&t->new_stream_map);
-  GPR_ASSERT(new_stream_count <= UINT32_MAX);
-  if (new_stream_count != t->global.concurrent_stream_count) {
-    t->global.concurrent_stream_count = (uint32_t)new_stream_count;
-    maybe_start_some_streams(exec_ctx, &t->global);
-  }
   GRPC_ERROR_UNREF(error);
+
+  maybe_start_some_streams(exec_ctx, t);
 }
 
 static void status_codes_from_error(grpc_error *error, gpr_timespec deadline,
@@ -1597,23 +1349,20 @@
   }
 }
 
-static void cancel_from_api(grpc_exec_ctx *exec_ctx,
-                            grpc_chttp2_transport_global *transport_global,
-                            grpc_chttp2_stream_global *stream_global,
-                            grpc_error *due_to_error) {
-  if (!stream_global->read_closed || !stream_global->write_closed) {
+void grpc_chttp2_cancel_stream(grpc_exec_ctx *exec_ctx,
+                               grpc_chttp2_transport *t, grpc_chttp2_stream *s,
+                               grpc_error *due_to_error) {
+  if (!s->read_closed || !s->write_closed) {
     grpc_status_code grpc_status;
     grpc_chttp2_error_code http_error;
-    status_codes_from_error(due_to_error, stream_global->deadline, &http_error,
+    status_codes_from_error(due_to_error, s->deadline, &http_error,
                             &grpc_status);
 
-    if (stream_global->id != 0) {
+    if (s->id != 0) {
       gpr_slice_buffer_add(
-          &transport_global->qbuf,
-          grpc_chttp2_rst_stream_create(stream_global->id, (uint32_t)http_error,
-                                        &stream_global->stats.outgoing));
-      grpc_chttp2_initiate_write(exec_ctx, transport_global, false,
-                                 "rst_stream");
+          &t->qbuf, grpc_chttp2_rst_stream_create(s->id, (uint32_t)http_error,
+                                                  &s->stats.outgoing));
+      grpc_chttp2_initiate_write(exec_ctx, t, false, "rst_stream");
     }
 
     const char *msg =
@@ -1624,25 +1373,20 @@
       msg = grpc_error_string(due_to_error);
     }
     gpr_slice msg_slice = gpr_slice_from_copied_string(msg);
-    grpc_chttp2_fake_status(exec_ctx, transport_global, stream_global,
-                            grpc_status, &msg_slice);
+    grpc_chttp2_fake_status(exec_ctx, t, s, grpc_status, &msg_slice);
     if (free_msg) grpc_error_free_string(msg);
   }
-  if (due_to_error != GRPC_ERROR_NONE && !stream_global->seen_error) {
-    stream_global->seen_error = true;
-    grpc_chttp2_list_add_check_read_ops(transport_global, stream_global);
+  if (due_to_error != GRPC_ERROR_NONE && !s->seen_error) {
+    s->seen_error = true;
   }
-  grpc_chttp2_mark_stream_closed(exec_ctx, transport_global, stream_global, 1,
-                                 1, due_to_error);
+  grpc_chttp2_mark_stream_closed(exec_ctx, t, s, 1, 1, due_to_error);
 }
 
-void grpc_chttp2_fake_status(grpc_exec_ctx *exec_ctx,
-                             grpc_chttp2_transport_global *transport_global,
-                             grpc_chttp2_stream_global *stream_global,
-                             grpc_status_code status, gpr_slice *slice) {
+void grpc_chttp2_fake_status(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t,
+                             grpc_chttp2_stream *s, grpc_status_code status,
+                             gpr_slice *slice) {
   if (status != GRPC_STATUS_OK) {
-    stream_global->seen_error = true;
-    grpc_chttp2_list_add_check_read_ops(transport_global, stream_global);
+    s->seen_error = true;
   }
   /* stream_global->recv_trailing_metadata_finished gives us a
      last chance replacement: we've received trailing metadata,
@@ -1650,23 +1394,24 @@
      to the upper layers - drop what we've got, and then publish
      what we want - which is safe because we haven't told anyone
      about the metadata yet */
-  if (!stream_global->published_trailing_metadata ||
-      stream_global->recv_trailing_metadata_finished != NULL) {
+  if (s->published_metadata[1] == GRPC_METADATA_NOT_PUBLISHED ||
+      s->recv_trailing_metadata_finished != NULL) {
     char status_string[GPR_LTOA_MIN_BUFSIZE];
     gpr_ltoa(status, status_string);
     grpc_chttp2_incoming_metadata_buffer_add(
-        &stream_global->received_trailing_metadata,
+        &s->metadata_buffer[1],
         grpc_mdelem_from_metadata_strings(
             GRPC_MDSTR_GRPC_STATUS, grpc_mdstr_from_string(status_string)));
     if (slice) {
       grpc_chttp2_incoming_metadata_buffer_add(
-          &stream_global->received_trailing_metadata,
+          &s->metadata_buffer[1],
           grpc_mdelem_from_metadata_strings(
               GRPC_MDSTR_GRPC_MESSAGE,
               grpc_mdstr_from_slice(gpr_slice_ref(*slice))));
     }
-    stream_global->published_trailing_metadata = true;
-    grpc_chttp2_list_add_check_read_ops(transport_global, stream_global);
+    gpr_log(GPR_DEBUG, "published_metadata from fake");
+    s->published_metadata[1] = GRPC_METADATA_SYNTHESIZED_FROM_FAKE;
+    grpc_chttp2_maybe_complete_recv_trailing_metadata(exec_ctx, t, s);
   }
   if (slice) {
     gpr_slice_unref(*slice);
@@ -1685,11 +1430,11 @@
 }
 
 static grpc_error *removal_error(grpc_error *extra_error,
-                                 grpc_chttp2_stream_global *stream_global) {
+                                 grpc_chttp2_stream *s) {
   grpc_error *refs[3];
   size_t nrefs = 0;
-  add_error(stream_global->read_closed_error, refs, &nrefs);
-  add_error(stream_global->write_closed_error, refs, &nrefs);
+  add_error(s->read_closed_error, refs, &nrefs);
+  add_error(s->write_closed_error, refs, &nrefs);
   add_error(extra_error, refs, &nrefs);
   grpc_error *error = GRPC_ERROR_NONE;
   if (nrefs > 0) {
@@ -1701,73 +1446,71 @@
 }
 
 static void fail_pending_writes(grpc_exec_ctx *exec_ctx,
-                                grpc_chttp2_transport_global *transport_global,
-                                grpc_chttp2_stream_global *stream_global,
+                                grpc_chttp2_transport *t, grpc_chttp2_stream *s,
                                 grpc_error *error) {
-  error = removal_error(error, stream_global);
-  stream_global->send_message = NULL;
+  error = removal_error(error, s);
+  s->fetching_send_message = NULL;
   grpc_chttp2_complete_closure_step(
-      exec_ctx, transport_global, stream_global,
-      &stream_global->send_initial_metadata_finished, GRPC_ERROR_REF(error));
+      exec_ctx, t, s, &s->send_initial_metadata_finished, GRPC_ERROR_REF(error),
+      "send_initial_metadata_finished");
   grpc_chttp2_complete_closure_step(
-      exec_ctx, transport_global, stream_global,
-      &stream_global->send_trailing_metadata_finished, GRPC_ERROR_REF(error));
-  grpc_chttp2_complete_closure_step(exec_ctx, transport_global, stream_global,
-                                    &stream_global->send_message_finished,
-                                    error);
-}
-
-void grpc_chttp2_mark_stream_closed(
-    grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_global *transport_global,
-    grpc_chttp2_stream_global *stream_global, int close_reads, int close_writes,
-    grpc_error *error) {
-  if (stream_global->read_closed && stream_global->write_closed) {
-    /* already closed */
-    GRPC_ERROR_UNREF(error);
-    return;
-  }
-  grpc_chttp2_list_add_check_read_ops(transport_global, stream_global);
-  if (close_reads && !stream_global->read_closed) {
-    stream_global->read_closed_error = GRPC_ERROR_REF(error);
-    stream_global->read_closed = true;
-    stream_global->published_initial_metadata = true;
-    stream_global->published_trailing_metadata = true;
-    decrement_active_streams_locked(exec_ctx, transport_global, stream_global);
-  }
-  if (close_writes && !stream_global->write_closed) {
-    stream_global->write_closed_error = GRPC_ERROR_REF(error);
-    stream_global->write_closed = true;
-    if (TRANSPORT_FROM_GLOBAL(transport_global)->executor.write_state !=
-        GRPC_CHTTP2_WRITING_INACTIVE) {
-      GRPC_CHTTP2_STREAM_REF(stream_global, "finish_writes");
-      grpc_chttp2_list_add_closed_waiting_for_writing(transport_global,
-                                                      stream_global);
-    } else {
-      fail_pending_writes(exec_ctx, transport_global, stream_global,
-                          GRPC_ERROR_REF(error));
-    }
-  }
-  if (stream_global->read_closed && stream_global->write_closed) {
-    if (stream_global->id != 0 &&
-        TRANSPORT_FROM_GLOBAL(transport_global)->executor.parsing_active) {
-      grpc_chttp2_list_add_closed_waiting_for_parsing(transport_global,
-                                                      stream_global);
-    } else {
-      if (stream_global->id != 0) {
-        remove_stream(exec_ctx, TRANSPORT_FROM_GLOBAL(transport_global),
-                      stream_global->id,
-                      removal_error(GRPC_ERROR_REF(error), stream_global));
-      }
-      GRPC_CHTTP2_STREAM_UNREF(exec_ctx, stream_global, "chttp2");
-    }
+      exec_ctx, t, s, &s->send_trailing_metadata_finished,
+      GRPC_ERROR_REF(error), "send_trailing_metadata_finished");
+  grpc_chttp2_complete_closure_step(
+      exec_ctx, t, s, &s->fetching_send_message_finished, GRPC_ERROR_REF(error),
+      "fetching_send_message_finished");
+  while (s->on_write_finished_cbs) {
+    grpc_chttp2_write_cb *cb = s->on_write_finished_cbs;
+    s->on_write_finished_cbs = cb->next;
+    grpc_chttp2_complete_closure_step(exec_ctx, t, s, &cb->closure,
+                                      GRPC_ERROR_REF(error),
+                                      "on_write_finished_cb");
+    cb->next = t->write_cb_pool;
+    t->write_cb_pool = cb;
   }
   GRPC_ERROR_UNREF(error);
 }
 
-static void close_from_api(grpc_exec_ctx *exec_ctx,
-                           grpc_chttp2_transport_global *transport_global,
-                           grpc_chttp2_stream_global *stream_global,
-                           grpc_error *error) {
+void grpc_chttp2_mark_stream_closed(grpc_exec_ctx *exec_ctx,
+                                    grpc_chttp2_transport *t,
+                                    grpc_chttp2_stream *s, int close_reads,
+                                    int close_writes, grpc_error *error) {
+  if (s->read_closed && s->write_closed) {
+    /* already closed */
+    GRPC_ERROR_UNREF(error);
+    return;
+  }
+  if (close_reads && !s->read_closed) {
+    s->read_closed_error = GRPC_ERROR_REF(error);
+    s->read_closed = true;
+    for (int i = 0; i < 2; i++) {
+      if (s->published_metadata[i] == GRPC_METADATA_NOT_PUBLISHED) {
+        s->published_metadata[i] = GPRC_METADATA_PUBLISHED_AT_CLOSE;
+      }
+    }
+    decrement_active_streams_locked(exec_ctx, t, s);
+    grpc_chttp2_maybe_complete_recv_initial_metadata(exec_ctx, t, s);
+    grpc_chttp2_maybe_complete_recv_message(exec_ctx, t, s);
+    grpc_chttp2_maybe_complete_recv_trailing_metadata(exec_ctx, t, s);
+  }
+  if (close_writes && !s->write_closed) {
+    s->write_closed_error = GRPC_ERROR_REF(error);
+    s->write_closed = true;
+    fail_pending_writes(exec_ctx, t, s, GRPC_ERROR_REF(error));
+    grpc_chttp2_maybe_complete_recv_trailing_metadata(exec_ctx, t, s);
+  }
+  if (s->read_closed && s->write_closed) {
+    if (s->id != 0) {
+      remove_stream(exec_ctx, t, s->id,
+                    removal_error(GRPC_ERROR_REF(error), s));
+    }
+    GRPC_CHTTP2_STREAM_UNREF(exec_ctx, s, "chttp2");
+  }
+  GRPC_ERROR_UNREF(error);
+}
+
+static void close_from_api(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t,
+                           grpc_chttp2_stream *s, grpc_error *error) {
   gpr_slice hdr;
   gpr_slice status_hdr;
   gpr_slice message_pfx;
@@ -1775,16 +1518,17 @@
   uint32_t len = 0;
   grpc_status_code grpc_status;
   grpc_chttp2_error_code http_error;
-  status_codes_from_error(error, stream_global->deadline, &http_error,
-                          &grpc_status);
+  status_codes_from_error(error, s->deadline, &http_error, &grpc_status);
 
   GPR_ASSERT(grpc_status >= 0 && (int)grpc_status < 100);
 
-  if (stream_global->id != 0 && !transport_global->is_client) {
+  if (s->id != 0 && !t->is_client) {
     /* Hand roll a header block.
-       This is unnecessarily ugly - at some point we should find a more elegant
+       This is unnecessarily ugly - at some point we should find a more
+       elegant
        solution.
-       It's complicated by the fact that our send machinery would be dead by the
+       It's complicated by the fact that our send machinery would be dead by
+       the
        time we got around to sending this, so instead we ignore HPACK
        compression
        and just write the uncompressed bytes onto the wire. */
@@ -1849,23 +1593,22 @@
     *p++ = (uint8_t)(len);
     *p++ = GRPC_CHTTP2_FRAME_HEADER;
     *p++ = GRPC_CHTTP2_DATA_FLAG_END_STREAM | GRPC_CHTTP2_DATA_FLAG_END_HEADERS;
-    *p++ = (uint8_t)(stream_global->id >> 24);
-    *p++ = (uint8_t)(stream_global->id >> 16);
-    *p++ = (uint8_t)(stream_global->id >> 8);
-    *p++ = (uint8_t)(stream_global->id);
+    *p++ = (uint8_t)(s->id >> 24);
+    *p++ = (uint8_t)(s->id >> 16);
+    *p++ = (uint8_t)(s->id >> 8);
+    *p++ = (uint8_t)(s->id);
     GPR_ASSERT(p == GPR_SLICE_END_PTR(hdr));
 
-    gpr_slice_buffer_add(&transport_global->qbuf, hdr);
-    gpr_slice_buffer_add(&transport_global->qbuf, status_hdr);
+    gpr_slice_buffer_add(&t->qbuf, hdr);
+    gpr_slice_buffer_add(&t->qbuf, status_hdr);
     if (optional_message) {
-      gpr_slice_buffer_add(&transport_global->qbuf, message_pfx);
-      gpr_slice_buffer_add(&transport_global->qbuf,
+      gpr_slice_buffer_add(&t->qbuf, message_pfx);
+      gpr_slice_buffer_add(&t->qbuf,
                            gpr_slice_from_copied_string(optional_message));
     }
     gpr_slice_buffer_add(
-        &transport_global->qbuf,
-        grpc_chttp2_rst_stream_create(stream_global->id, GRPC_CHTTP2_NO_ERROR,
-                                      &stream_global->stats.outgoing));
+        &t->qbuf, grpc_chttp2_rst_stream_create(s->id, GRPC_CHTTP2_NO_ERROR,
+                                                &s->stats.outgoing));
   }
 
   const char *msg = grpc_error_get_str(error, GRPC_ERROR_STR_GRPC_MESSAGE);
@@ -1875,38 +1618,39 @@
     msg = grpc_error_string(error);
   }
   gpr_slice msg_slice = gpr_slice_from_copied_string(msg);
-  grpc_chttp2_fake_status(exec_ctx, transport_global, stream_global,
-                          grpc_status, &msg_slice);
+  grpc_chttp2_fake_status(exec_ctx, t, s, grpc_status, &msg_slice);
   if (free_msg) grpc_error_free_string(msg);
 
-  grpc_chttp2_mark_stream_closed(exec_ctx, transport_global, stream_global, 1,
-                                 1, error);
-  grpc_chttp2_initiate_write(exec_ctx, transport_global, false,
-                             "close_from_api");
+  grpc_chttp2_mark_stream_closed(exec_ctx, t, s, 1, 1, error);
+  grpc_chttp2_initiate_write(exec_ctx, t, false, "close_from_api");
 }
 
 typedef struct {
   grpc_exec_ctx *exec_ctx;
   grpc_error *error;
+  grpc_chttp2_transport *t;
 } cancel_stream_cb_args;
 
-static void cancel_stream_cb(grpc_chttp2_transport_global *transport_global,
-                             void *user_data,
-                             grpc_chttp2_stream_global *stream_global) {
+static void cancel_stream_cb(void *user_data, uint32_t key, void *stream) {
   cancel_stream_cb_args *args = user_data;
-  cancel_from_api(args->exec_ctx, transport_global, stream_global,
-                  GRPC_ERROR_REF(args->error));
+  grpc_chttp2_stream *s = stream;
+  grpc_chttp2_cancel_stream(args->exec_ctx, args->t, s,
+                            GRPC_ERROR_REF(args->error));
 }
 
 static void end_all_the_calls(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t,
                               grpc_error *error) {
-  cancel_stream_cb_args args = {exec_ctx, error};
-  grpc_chttp2_for_all_streams(&t->global, &args, cancel_stream_cb);
+  cancel_stream_cb_args args = {exec_ctx, error, t};
+  grpc_chttp2_stream_map_for_each(&t->stream_map, cancel_stream_cb, &args);
   GRPC_ERROR_UNREF(error);
 }
 
 static void drop_connection(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t,
                             grpc_error *error) {
+  if (!grpc_error_get_int(error, GRPC_ERROR_INT_GRPC_STATUS, NULL)) {
+    error = grpc_error_set_int(error, GRPC_ERROR_INT_GRPC_STATUS,
+                               GRPC_STATUS_UNAVAILABLE);
+  }
   close_transport_locked(exec_ctx, t, GRPC_ERROR_REF(error));
   end_all_the_calls(exec_ctx, t, error);
 }
@@ -1921,20 +1665,23 @@
   update_global_window_args *a = args;
   grpc_chttp2_transport *t = a->t;
   grpc_chttp2_stream *s = stream;
-  grpc_chttp2_transport_global *transport_global = &t->global;
-  grpc_chttp2_stream_global *stream_global = &s->global;
   int was_zero;
   int is_zero;
-  int64_t initial_window_update = t->parsing.initial_window_update;
+  int64_t initial_window_update = t->initial_window_update;
 
-  was_zero = stream_global->outgoing_window <= 0;
-  GRPC_CHTTP2_FLOW_CREDIT_STREAM("settings", transport_global, stream_global,
-                                 outgoing_window, initial_window_update);
-  is_zero = stream_global->outgoing_window <= 0;
+  if (initial_window_update > 0) {
+    was_zero = s->outgoing_window <= 0;
+    GRPC_CHTTP2_FLOW_CREDIT_STREAM("settings", t, s, outgoing_window,
+                                   initial_window_update);
+    is_zero = s->outgoing_window <= 0;
 
-  if (was_zero && !is_zero) {
-    grpc_chttp2_become_writable(a->exec_ctx, transport_global, stream_global,
-                                true, "update_global_window");
+    if (was_zero && !is_zero) {
+      grpc_chttp2_become_writable(a->exec_ctx, t, s, true,
+                                  "update_global_window");
+    }
+  } else {
+    GRPC_CHTTP2_FLOW_DEBIT_STREAM("settings", t, s, outgoing_window,
+                                  -initial_window_update);
   }
 }
 
@@ -1942,45 +1689,17 @@
  * INPUT PROCESSING - PARSING
  */
 
-static void reading_action_locked(grpc_exec_ctx *exec_ctx,
-                                  grpc_chttp2_transport *t,
-                                  grpc_chttp2_stream *s_unused, void *arg);
-static void parsing_action(grpc_exec_ctx *exec_ctx, void *arg,
-                           grpc_error *error);
-static void post_reading_action_locked(grpc_exec_ctx *exec_ctx,
-                                       grpc_chttp2_transport *t,
-                                       grpc_chttp2_stream *s_unused, void *arg);
-static void post_parse_locked(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t,
-                              grpc_chttp2_stream *s_unused, void *arg);
-
-static void reading_action(grpc_exec_ctx *exec_ctx, void *tp,
-                           grpc_error *error) {
+static void read_action_begin(grpc_exec_ctx *exec_ctx, void *tp,
+                              grpc_error *error) {
   /* Control flow:
      reading_action_locked ->
        (parse_unlocked -> post_parse_locked)? ->
        post_reading_action_locked */
-  grpc_chttp2_run_with_global_lock(exec_ctx, tp, NULL, reading_action_locked,
-                                   GRPC_ERROR_REF(error), 0);
-}
-
-static void reading_action_locked(grpc_exec_ctx *exec_ctx,
-                                  grpc_chttp2_transport *t,
-                                  grpc_chttp2_stream *s_unused, void *arg) {
-  grpc_chttp2_transport_global *transport_global = &t->global;
-  grpc_chttp2_transport_parsing *transport_parsing = &t->parsing;
-  grpc_error *error = arg;
-
-  GPR_ASSERT(!t->executor.parsing_active);
-  if (!t->closed) {
-    t->executor.parsing_active = 1;
-    /* merge stream lists */
-    grpc_chttp2_stream_map_move_into(&t->new_stream_map,
-                                     &t->parsing_stream_map);
-    grpc_chttp2_prepare_to_read(transport_global, transport_parsing);
-    grpc_exec_ctx_sched(exec_ctx, &t->parsing_action, error, NULL);
-  } else {
-    post_reading_action_locked(exec_ctx, t, s_unused, arg);
-  }
+  GPR_TIMER_BEGIN("reading_action", 0);
+  grpc_chttp2_transport *t = tp;
+  grpc_combiner_execute(exec_ctx, t->combiner, &t->read_action_locked,
+                        GRPC_ERROR_REF(error), false);
+  GPR_TIMER_END("reading_action", 0);
 }
 
 static grpc_error *try_http_parsing(grpc_exec_ctx *exec_ctx,
@@ -2010,169 +1729,110 @@
   return error;
 }
 
-static void parsing_action(grpc_exec_ctx *exec_ctx, void *arg,
-                           grpc_error *error) {
-  grpc_chttp2_transport *t = arg;
-  grpc_error *err = GRPC_ERROR_NONE;
-  GPR_TIMER_BEGIN("reading_action.parse", 0);
-  size_t i = 0;
-  grpc_error *errors[3] = {GRPC_ERROR_REF(error), GRPC_ERROR_NONE,
-                           GRPC_ERROR_NONE};
-  for (; i < t->read_buffer.count && errors[1] == GRPC_ERROR_NONE; i++) {
-    errors[1] = grpc_chttp2_perform_read(exec_ctx, &t->parsing,
-                                         t->read_buffer.slices[i]);
-  };
-  if (errors[1] == GRPC_ERROR_NONE) {
-    err = GRPC_ERROR_REF(error);
-  } else {
-    errors[2] = try_http_parsing(exec_ctx, t);
-    err = GRPC_ERROR_CREATE_REFERENCING("Failed parsing HTTP/2", errors,
-                                        GPR_ARRAY_SIZE(errors));
-  }
-  for (i = 0; i < GPR_ARRAY_SIZE(errors); i++) {
-    GRPC_ERROR_UNREF(errors[i]);
-  }
-  GPR_TIMER_END("reading_action.parse", 0);
-  grpc_chttp2_run_with_global_lock(exec_ctx, t, NULL, post_parse_locked, err,
-                                   0);
-}
+static void read_action_locked(grpc_exec_ctx *exec_ctx, void *tp,
+                               grpc_error *error) {
+  GPR_TIMER_BEGIN("reading_action_locked", 0);
 
-static void post_parse_locked(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t,
-                              grpc_chttp2_stream *s_unused, void *arg) {
-  grpc_chttp2_transport_global *transport_global = &t->global;
-  grpc_chttp2_transport_parsing *transport_parsing = &t->parsing;
-  /* copy parsing qbuf to global qbuf */
-  if (t->parsing.qbuf.count > 0) {
-    gpr_slice_buffer_move_into(&t->parsing.qbuf, &t->global.qbuf);
-    grpc_chttp2_initiate_write(exec_ctx, transport_global, false,
-                               "parsing_qbuf");
-  }
-  /* merge stream lists */
-  grpc_chttp2_stream_map_move_into(&t->new_stream_map, &t->parsing_stream_map);
-  transport_global->concurrent_stream_count =
-      (uint32_t)grpc_chttp2_stream_map_size(&t->parsing_stream_map);
-  if (transport_parsing->initial_window_update != 0) {
-    update_global_window_args args = {t, exec_ctx};
-    grpc_chttp2_stream_map_for_each(&t->parsing_stream_map,
-                                    update_global_window, &args);
-    transport_parsing->initial_window_update = 0;
-  }
-  /* handle higher level things */
-  grpc_chttp2_publish_reads(exec_ctx, transport_global, transport_parsing);
-  t->executor.parsing_active = 0;
-  /* handle delayed transport ops (if there is one) */
-  if (t->post_parsing_op) {
-    grpc_transport_op *op = t->post_parsing_op;
-    t->post_parsing_op = NULL;
-    perform_transport_op_locked(exec_ctx, t, NULL, op);
-    gpr_free(op);
-  }
-  /* if a stream is in the stream map, and gets cancelled, we need to
-   * ensure we are not parsing before continuing the cancellation to keep
-   * things in a sane state */
-  grpc_chttp2_stream_global *stream_global;
-  while (grpc_chttp2_list_pop_closed_waiting_for_parsing(transport_global,
-                                                         &stream_global)) {
-    GPR_ASSERT(stream_global->in_stream_map);
-    GPR_ASSERT(stream_global->write_closed);
-    GPR_ASSERT(stream_global->read_closed);
-    remove_stream(exec_ctx, t, stream_global->id,
-                  removal_error(GRPC_ERROR_NONE, stream_global));
-    GRPC_CHTTP2_STREAM_UNREF(exec_ctx, stream_global, "chttp2");
+  grpc_chttp2_transport *t = tp;
+
+  GRPC_ERROR_REF(error);
+
+  if (!t->closed) {
+    GPR_TIMER_BEGIN("reading_action.parse", 0);
+    size_t i = 0;
+    grpc_error *errors[3] = {GRPC_ERROR_REF(error), GRPC_ERROR_NONE,
+                             GRPC_ERROR_NONE};
+    for (; i < t->read_buffer.count && errors[1] == GRPC_ERROR_NONE; i++) {
+      errors[1] =
+          grpc_chttp2_perform_read(exec_ctx, t, t->read_buffer.slices[i]);
+    };
+    if (errors[1] != GRPC_ERROR_NONE) {
+      errors[2] = try_http_parsing(exec_ctx, t);
+      GRPC_ERROR_UNREF(error);
+      error = GRPC_ERROR_CREATE_REFERENCING("Failed parsing HTTP/2", errors,
+                                            GPR_ARRAY_SIZE(errors));
+    }
+    for (i = 0; i < GPR_ARRAY_SIZE(errors); i++) {
+      GRPC_ERROR_UNREF(errors[i]);
+    }
+    GPR_TIMER_END("reading_action.parse", 0);
+
+    GPR_TIMER_BEGIN("post_parse_locked", 0);
+    if (t->initial_window_update != 0) {
+      update_global_window_args args = {t, exec_ctx};
+      grpc_chttp2_stream_map_for_each(&t->stream_map, update_global_window,
+                                      &args);
+      t->initial_window_update = 0;
+    }
+    /* handle higher level things */
+    if (t->incoming_window < t->connection_window_target * 3 / 4) {
+      int64_t announce_bytes = t->connection_window_target - t->incoming_window;
+      GRPC_CHTTP2_FLOW_CREDIT_TRANSPORT("parsed", t, announce_incoming_window,
+                                        announce_bytes);
+      GRPC_CHTTP2_FLOW_CREDIT_TRANSPORT("parsed", t, incoming_window,
+                                        announce_bytes);
+      grpc_chttp2_initiate_write(exec_ctx, t, false, "global incoming window");
+    }
+
+    GPR_TIMER_END("post_parse_locked", 0);
   }
 
-  post_reading_action_locked(exec_ctx, t, s_unused, arg);
-}
-
-static void post_reading_action_locked(grpc_exec_ctx *exec_ctx,
-                                       grpc_chttp2_transport *t,
-                                       grpc_chttp2_stream *s_unused,
-                                       void *arg) {
-  grpc_error *error = arg;
+  GPR_TIMER_BEGIN("post_reading_action_locked", 0);
   bool keep_reading = false;
   if (error == GRPC_ERROR_NONE && t->closed) {
     error = GRPC_ERROR_CREATE("Transport closed");
   }
   if (error != GRPC_ERROR_NONE) {
-    if (!grpc_error_get_int(error, GRPC_ERROR_INT_GRPC_STATUS, NULL)) {
-      error = grpc_error_set_int(error, GRPC_ERROR_INT_GRPC_STATUS,
-                                 GRPC_STATUS_UNAVAILABLE);
-    }
     drop_connection(exec_ctx, t, GRPC_ERROR_REF(error));
     t->endpoint_reading = 0;
-    if (grpc_http_write_state_trace) {
-      gpr_log(GPR_DEBUG, "R:%p -> 0 ws=%s", t,
-              write_state_name(t->executor.write_state));
-    }
-    if (t->executor.write_state == GRPC_CHTTP2_WRITING_INACTIVE && t->ep) {
-      destroy_endpoint(exec_ctx, t);
-    }
   } else if (!t->closed) {
     keep_reading = true;
-    REF_TRANSPORT(t, "keep_reading");
-    prevent_endpoint_shutdown(t);
+    GRPC_CHTTP2_REF_TRANSPORT(t, "keep_reading");
   }
   gpr_slice_buffer_reset_and_unref(&t->read_buffer);
-  GRPC_ERROR_UNREF(error);
 
   if (keep_reading) {
-    grpc_endpoint_read(exec_ctx, t->ep, &t->read_buffer, &t->reading_action);
-    allow_endpoint_shutdown_locked(exec_ctx, t);
-    UNREF_TRANSPORT(exec_ctx, t, "keep_reading");
+    grpc_endpoint_read(exec_ctx, t->ep, &t->read_buffer, &t->read_action_begin);
+    GRPC_CHTTP2_UNREF_TRANSPORT(exec_ctx, t, "keep_reading");
   } else {
-    UNREF_TRANSPORT(exec_ctx, t, "reading_action");
+    GRPC_CHTTP2_UNREF_TRANSPORT(exec_ctx, t, "reading_action");
   }
+
+  GPR_TIMER_END("post_reading_action_locked", 0);
+
+  GRPC_ERROR_UNREF(error);
+
+  GPR_TIMER_END("reading_action_locked", 0);
 }
 
 /*******************************************************************************
  * CALLBACK LOOP
  */
 
-static void connectivity_state_set(
-    grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_global *transport_global,
-    grpc_connectivity_state state, grpc_error *error, const char *reason) {
+static void connectivity_state_set(grpc_exec_ctx *exec_ctx,
+                                   grpc_chttp2_transport *t,
+                                   grpc_connectivity_state state,
+                                   grpc_error *error, const char *reason) {
   GRPC_CHTTP2_IF_TRACING(
       gpr_log(GPR_DEBUG, "set connectivity_state=%d", state));
-  grpc_connectivity_state_set(
-      exec_ctx,
-      &TRANSPORT_FROM_GLOBAL(transport_global)->channel_callback.state_tracker,
-      state, error, reason);
+  grpc_connectivity_state_set(exec_ctx, &t->channel_callback.state_tracker,
+                              state, error, reason);
 }
 
 /*******************************************************************************
  * POLLSET STUFF
  */
 
-static void add_to_pollset_locked(grpc_exec_ctx *exec_ctx,
-                                  grpc_chttp2_transport *t,
-                                  grpc_chttp2_stream *s_unused, void *pollset) {
-  if (t->ep) {
-    grpc_endpoint_add_to_pollset(exec_ctx, t->ep, pollset);
-  }
-}
-
-static void add_to_pollset_set_locked(grpc_exec_ctx *exec_ctx,
-                                      grpc_chttp2_transport *t,
-                                      grpc_chttp2_stream *s_unused,
-                                      void *pollset_set) {
-  if (t->ep) {
-    grpc_endpoint_add_to_pollset_set(exec_ctx, t->ep, pollset_set);
-  }
-}
-
 static void set_pollset(grpc_exec_ctx *exec_ctx, grpc_transport *gt,
                         grpc_stream *gs, grpc_pollset *pollset) {
-  /* TODO(ctiller): keep pollset alive */
-  grpc_chttp2_run_with_global_lock(exec_ctx, (grpc_chttp2_transport *)gt,
-                                   (grpc_chttp2_stream *)gs,
-                                   add_to_pollset_locked, pollset, 0);
+  grpc_chttp2_transport *t = (grpc_chttp2_transport *)gt;
+  grpc_endpoint_add_to_pollset(exec_ctx, t->ep, pollset);
 }
 
 static void set_pollset_set(grpc_exec_ctx *exec_ctx, grpc_transport *gt,
                             grpc_stream *gs, grpc_pollset_set *pollset_set) {
-  grpc_chttp2_run_with_global_lock(exec_ctx, (grpc_chttp2_transport *)gt,
-                                   (grpc_chttp2_stream *)gs,
-                                   add_to_pollset_set_locked, pollset_set, 0);
+  grpc_chttp2_transport *t = (grpc_chttp2_transport *)gt;
+  grpc_endpoint_add_to_pollset_set(exec_ctx, t->ep, pollset_set);
 }
 
 /*******************************************************************************
@@ -2184,19 +1844,21 @@
   if (gpr_unref(&bs->refs)) {
     GRPC_ERROR_UNREF(bs->error);
     gpr_slice_buffer_destroy(&bs->slices);
+    gpr_mu_destroy(&bs->slice_mu);
     gpr_free(bs);
   }
 }
 
-static void incoming_byte_stream_update_flow_control(
-    grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_global *transport_global,
-    grpc_chttp2_stream_global *stream_global, size_t max_size_hint,
-    size_t have_already) {
+static void incoming_byte_stream_update_flow_control(grpc_exec_ctx *exec_ctx,
+                                                     grpc_chttp2_transport *t,
+                                                     grpc_chttp2_stream *s,
+                                                     size_t max_size_hint,
+                                                     size_t have_already) {
   uint32_t max_recv_bytes;
 
   /* clamp max recv hint to an allowable size */
-  if (max_size_hint >= UINT32_MAX - transport_global->stream_lookahead) {
-    max_recv_bytes = UINT32_MAX - transport_global->stream_lookahead;
+  if (max_size_hint >= UINT32_MAX - t->stream_lookahead) {
+    max_recv_bytes = UINT32_MAX - t->stream_lookahead;
   } else {
     max_recv_bytes = (uint32_t)max_size_hint;
   }
@@ -2209,58 +1871,46 @@
   }
 
   /* add some small lookahead to keep pipelines flowing */
-  GPR_ASSERT(max_recv_bytes <= UINT32_MAX - transport_global->stream_lookahead);
-  max_recv_bytes += transport_global->stream_lookahead;
-  if (stream_global->max_recv_bytes < max_recv_bytes) {
-    uint32_t add_max_recv_bytes =
-        max_recv_bytes - stream_global->max_recv_bytes;
-    GRPC_CHTTP2_FLOW_CREDIT_STREAM("op", transport_global, stream_global,
-                                   max_recv_bytes, add_max_recv_bytes);
-    GRPC_CHTTP2_FLOW_CREDIT_STREAM("op", transport_global, stream_global,
-                                   unannounced_incoming_window_for_parse,
+  GPR_ASSERT(max_recv_bytes <= UINT32_MAX - t->stream_lookahead);
+  max_recv_bytes += t->stream_lookahead;
+  if (s->max_recv_bytes < max_recv_bytes) {
+    uint32_t add_max_recv_bytes = max_recv_bytes - s->max_recv_bytes;
+    GRPC_CHTTP2_FLOW_CREDIT_STREAM("op", t, s, max_recv_bytes,
                                    add_max_recv_bytes);
-    GRPC_CHTTP2_FLOW_CREDIT_STREAM("op", transport_global, stream_global,
-                                   unannounced_incoming_window_for_writing,
+    GRPC_CHTTP2_FLOW_CREDIT_STREAM("op", t, s, incoming_window,
                                    add_max_recv_bytes);
-    grpc_chttp2_list_add_unannounced_incoming_window_available(transport_global,
-                                                               stream_global);
-    grpc_chttp2_become_writable(exec_ctx, transport_global, stream_global,
-                                false, "read_incoming_stream");
+    GRPC_CHTTP2_FLOW_CREDIT_STREAM("op", t, s, announce_window,
+                                   add_max_recv_bytes);
+    grpc_chttp2_become_writable(exec_ctx, t, s, true, "read_incoming_stream");
   }
 }
 
-typedef struct {
-  grpc_chttp2_incoming_byte_stream *byte_stream;
-  gpr_slice *slice;
-  size_t max_size_hint;
-  grpc_closure *on_complete;
-} incoming_byte_stream_next_arg;
-
 static void incoming_byte_stream_next_locked(grpc_exec_ctx *exec_ctx,
-                                             grpc_chttp2_transport *t,
-                                             grpc_chttp2_stream *s,
-                                             void *argp) {
-  incoming_byte_stream_next_arg *arg = argp;
-  grpc_chttp2_incoming_byte_stream *bs =
-      (grpc_chttp2_incoming_byte_stream *)arg->byte_stream;
-  grpc_chttp2_transport_global *transport_global = &bs->transport->global;
-  grpc_chttp2_stream_global *stream_global = &bs->stream->global;
+                                             void *argp,
+                                             grpc_error *error_ignored) {
+  grpc_chttp2_incoming_byte_stream *bs = argp;
+  grpc_chttp2_transport *t = bs->transport;
+  grpc_chttp2_stream *s = bs->stream;
 
   if (bs->is_tail) {
-    incoming_byte_stream_update_flow_control(exec_ctx, transport_global,
-                                             stream_global, arg->max_size_hint,
-                                             bs->slices.length);
+    gpr_mu_lock(&bs->slice_mu);
+    size_t cur_length = bs->slices.length;
+    gpr_mu_unlock(&bs->slice_mu);
+    incoming_byte_stream_update_flow_control(
+        exec_ctx, t, s, bs->next_action.max_size_hint, cur_length);
   }
+  gpr_mu_lock(&bs->slice_mu);
   if (bs->slices.count > 0) {
-    *arg->slice = gpr_slice_buffer_take_first(&bs->slices);
-    grpc_exec_ctx_sched(exec_ctx, arg->on_complete, GRPC_ERROR_NONE, NULL);
+    *bs->next_action.slice = gpr_slice_buffer_take_first(&bs->slices);
+    grpc_closure_run(exec_ctx, bs->next_action.on_complete, GRPC_ERROR_NONE);
   } else if (bs->error != GRPC_ERROR_NONE) {
-    grpc_exec_ctx_sched(exec_ctx, arg->on_complete, GRPC_ERROR_REF(bs->error),
-                        NULL);
+    grpc_closure_run(exec_ctx, bs->next_action.on_complete,
+                     GRPC_ERROR_REF(bs->error));
   } else {
-    bs->on_next = arg->on_complete;
-    bs->next = arg->slice;
+    bs->on_next = bs->next_action.on_complete;
+    bs->next = bs->next_action.slice;
   }
+  gpr_mu_unlock(&bs->slice_mu);
   incoming_byte_stream_unref(exec_ctx, bs);
 }
 
@@ -2268,13 +1918,18 @@
                                      grpc_byte_stream *byte_stream,
                                      gpr_slice *slice, size_t max_size_hint,
                                      grpc_closure *on_complete) {
+  GPR_TIMER_BEGIN("incoming_byte_stream_next", 0);
   grpc_chttp2_incoming_byte_stream *bs =
       (grpc_chttp2_incoming_byte_stream *)byte_stream;
-  incoming_byte_stream_next_arg arg = {bs, slice, max_size_hint, on_complete};
   gpr_ref(&bs->refs);
-  grpc_chttp2_run_with_global_lock(exec_ctx, bs->transport, bs->stream,
-                                   incoming_byte_stream_next_locked, &arg,
-                                   sizeof(arg));
+  bs->next_action.slice = slice;
+  bs->next_action.max_size_hint = max_size_hint;
+  bs->next_action.on_complete = on_complete;
+  grpc_closure_init(&bs->next_action.closure, incoming_byte_stream_next_locked,
+                    bs);
+  grpc_combiner_execute(exec_ctx, bs->transport->combiner,
+                        &bs->next_action.closure, GRPC_ERROR_NONE, false);
+  GPR_TIMER_END("incoming_byte_stream_next", 0);
   return 0;
 }
 
@@ -2282,141 +1937,101 @@
                                          grpc_byte_stream *byte_stream);
 
 static void incoming_byte_stream_destroy_locked(grpc_exec_ctx *exec_ctx,
-                                                grpc_chttp2_transport *t,
-                                                grpc_chttp2_stream *s,
-                                                void *byte_stream) {
+                                                void *byte_stream,
+                                                grpc_error *error_ignored) {
   grpc_chttp2_incoming_byte_stream *bs = byte_stream;
   GPR_ASSERT(bs->base.destroy == incoming_byte_stream_destroy);
-  decrement_active_streams_locked(exec_ctx, &bs->transport->global,
-                                  &bs->stream->global);
+  decrement_active_streams_locked(exec_ctx, bs->transport, bs->stream);
   incoming_byte_stream_unref(exec_ctx, bs);
 }
 
 static void incoming_byte_stream_destroy(grpc_exec_ctx *exec_ctx,
                                          grpc_byte_stream *byte_stream) {
+  GPR_TIMER_BEGIN("incoming_byte_stream_destroy", 0);
   grpc_chttp2_incoming_byte_stream *bs =
       (grpc_chttp2_incoming_byte_stream *)byte_stream;
-  grpc_chttp2_run_with_global_lock(exec_ctx, bs->transport, bs->stream,
-                                   incoming_byte_stream_destroy_locked, bs, 0);
+  grpc_closure_init(&bs->destroy_action, incoming_byte_stream_destroy_locked,
+                    bs);
+  grpc_combiner_execute(exec_ctx, bs->transport->combiner, &bs->destroy_action,
+                        GRPC_ERROR_NONE, false);
+  GPR_TIMER_END("incoming_byte_stream_destroy", 0);
 }
 
-typedef struct {
-  grpc_chttp2_incoming_byte_stream *byte_stream;
-  gpr_slice slice;
-} incoming_byte_stream_push_arg;
-
-static void incoming_byte_stream_push_locked(grpc_exec_ctx *exec_ctx,
-                                             grpc_chttp2_transport *t,
-                                             grpc_chttp2_stream *s,
-                                             void *argp) {
-  incoming_byte_stream_push_arg *arg = argp;
-  grpc_chttp2_incoming_byte_stream *bs = arg->byte_stream;
-  if (bs->on_next != NULL) {
-    *bs->next = arg->slice;
-    grpc_exec_ctx_sched(exec_ctx, bs->on_next, GRPC_ERROR_NONE, NULL);
-    bs->on_next = NULL;
-  } else {
-    gpr_slice_buffer_add(&bs->slices, arg->slice);
-  }
-  incoming_byte_stream_unref(exec_ctx, bs);
+static void incoming_byte_stream_publish_error(
+    grpc_exec_ctx *exec_ctx, grpc_chttp2_incoming_byte_stream *bs,
+    grpc_error *error) {
+  GPR_ASSERT(error != GRPC_ERROR_NONE);
+  grpc_exec_ctx_sched(exec_ctx, bs->on_next, GRPC_ERROR_REF(error), NULL);
+  bs->on_next = NULL;
+  GRPC_ERROR_UNREF(bs->error);
+  bs->error = error;
 }
 
 void grpc_chttp2_incoming_byte_stream_push(grpc_exec_ctx *exec_ctx,
                                            grpc_chttp2_incoming_byte_stream *bs,
                                            gpr_slice slice) {
-  incoming_byte_stream_push_arg arg = {bs, slice};
-  gpr_ref(&bs->refs);
-  grpc_chttp2_run_with_global_lock(exec_ctx, bs->transport, bs->stream,
-                                   incoming_byte_stream_push_locked, &arg,
-                                   sizeof(arg));
-}
-
-typedef struct {
-  grpc_chttp2_incoming_byte_stream *bs;
-  grpc_error *error;
-} bs_fail_args;
-
-static bs_fail_args *make_bs_fail_args(grpc_chttp2_incoming_byte_stream *bs,
-                                       grpc_error *error) {
-  bs_fail_args *a = gpr_malloc(sizeof(*a));
-  a->bs = bs;
-  a->error = error;
-  return a;
-}
-
-static void incoming_byte_stream_finished_failed_locked(
-    grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t, grpc_chttp2_stream *s,
-    void *argp) {
-  bs_fail_args *a = argp;
-  grpc_chttp2_incoming_byte_stream *bs = a->bs;
-  grpc_error *error = a->error;
-  gpr_free(a);
-  grpc_exec_ctx_sched(exec_ctx, bs->on_next, GRPC_ERROR_REF(error), NULL);
-  bs->on_next = NULL;
-  GRPC_ERROR_UNREF(bs->error);
-  bs->error = error;
-  incoming_byte_stream_unref(exec_ctx, bs);
-}
-
-static void incoming_byte_stream_finished_ok_locked(grpc_exec_ctx *exec_ctx,
-                                                    grpc_chttp2_transport *t,
-                                                    grpc_chttp2_stream *s,
-                                                    void *argp) {
-  grpc_chttp2_incoming_byte_stream *bs = argp;
-  incoming_byte_stream_unref(exec_ctx, bs);
+  gpr_mu_lock(&bs->slice_mu);
+  if (bs->remaining_bytes < GPR_SLICE_LENGTH(slice)) {
+    incoming_byte_stream_publish_error(
+        exec_ctx, bs, GRPC_ERROR_CREATE("Too many bytes in stream"));
+  } else {
+    bs->remaining_bytes -= (uint32_t)GPR_SLICE_LENGTH(slice);
+    if (bs->on_next != NULL) {
+      *bs->next = slice;
+      grpc_exec_ctx_sched(exec_ctx, bs->on_next, GRPC_ERROR_NONE, NULL);
+      bs->on_next = NULL;
+    } else {
+      gpr_slice_buffer_add(&bs->slices, slice);
+    }
+  }
+  gpr_mu_unlock(&bs->slice_mu);
 }
 
 void grpc_chttp2_incoming_byte_stream_finished(
     grpc_exec_ctx *exec_ctx, grpc_chttp2_incoming_byte_stream *bs,
-    grpc_error *error, int from_parsing_thread) {
-  if (from_parsing_thread) {
-    if (error == GRPC_ERROR_NONE) {
-      grpc_chttp2_run_with_global_lock(exec_ctx, bs->transport, bs->stream,
-                                       incoming_byte_stream_finished_ok_locked,
-                                       bs, 0);
-    } else {
-      grpc_chttp2_run_with_global_lock(
-          exec_ctx, bs->transport, bs->stream,
-          incoming_byte_stream_finished_failed_locked,
-          make_bs_fail_args(bs, error), 0);
+    grpc_error *error) {
+  if (error == GRPC_ERROR_NONE) {
+    gpr_mu_lock(&bs->slice_mu);
+    if (bs->remaining_bytes != 0) {
+      error = GRPC_ERROR_CREATE("Truncated message");
     }
-  } else {
-    if (error == GRPC_ERROR_NONE) {
-      incoming_byte_stream_finished_ok_locked(exec_ctx, bs->transport,
-                                              bs->stream, bs);
-    } else {
-      incoming_byte_stream_finished_failed_locked(
-          exec_ctx, bs->transport, bs->stream, make_bs_fail_args(bs, error));
-    }
+    gpr_mu_unlock(&bs->slice_mu);
   }
+  if (error != GRPC_ERROR_NONE) {
+    incoming_byte_stream_publish_error(exec_ctx, bs, error);
+  }
+  incoming_byte_stream_unref(exec_ctx, bs);
 }
 
 grpc_chttp2_incoming_byte_stream *grpc_chttp2_incoming_byte_stream_create(
-    grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_parsing *transport_parsing,
-    grpc_chttp2_stream_parsing *stream_parsing, uint32_t frame_size,
-    uint32_t flags, grpc_chttp2_incoming_frame_queue *add_to_queue) {
+    grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t, grpc_chttp2_stream *s,
+    uint32_t frame_size, uint32_t flags) {
   grpc_chttp2_incoming_byte_stream *incoming_byte_stream =
       gpr_malloc(sizeof(*incoming_byte_stream));
   incoming_byte_stream->base.length = frame_size;
+  incoming_byte_stream->remaining_bytes = frame_size;
   incoming_byte_stream->base.flags = flags;
   incoming_byte_stream->base.next = incoming_byte_stream_next;
   incoming_byte_stream->base.destroy = incoming_byte_stream_destroy;
+  gpr_mu_init(&incoming_byte_stream->slice_mu);
   gpr_ref_init(&incoming_byte_stream->refs, 2);
   incoming_byte_stream->next_message = NULL;
-  incoming_byte_stream->transport = TRANSPORT_FROM_PARSING(transport_parsing);
-  incoming_byte_stream->stream = STREAM_FROM_PARSING(stream_parsing);
-  gpr_ref(&incoming_byte_stream->stream->global.active_streams);
+  incoming_byte_stream->transport = t;
+  incoming_byte_stream->stream = s;
+  gpr_ref(&incoming_byte_stream->stream->active_streams);
   gpr_slice_buffer_init(&incoming_byte_stream->slices);
   incoming_byte_stream->on_next = NULL;
   incoming_byte_stream->is_tail = 1;
   incoming_byte_stream->error = GRPC_ERROR_NONE;
-  if (add_to_queue->head == NULL) {
-    add_to_queue->head = incoming_byte_stream;
+  grpc_chttp2_incoming_frame_queue *q = &s->incoming_frames;
+  if (q->head == NULL) {
+    q->head = incoming_byte_stream;
   } else {
-    add_to_queue->tail->is_tail = 0;
-    add_to_queue->tail->next_message = incoming_byte_stream;
+    q->tail->is_tail = 0;
+    q->tail->next_message = incoming_byte_stream;
   }
-  add_to_queue->tail = incoming_byte_stream;
+  q->tail = incoming_byte_stream;
+  grpc_chttp2_maybe_complete_recv_message(exec_ctx, t, s);
   return incoming_byte_stream;
 }
 
@@ -2425,67 +2040,49 @@
  */
 
 static char *format_flowctl_context_var(const char *context, const char *var,
-                                        int64_t val, uint32_t id,
-                                        char **scope) {
-  char *underscore_pos;
-  char *buf;
-  char *result;
+                                        int64_t val, uint32_t id) {
+  char *name;
   if (context == NULL) {
-    *scope = NULL;
-    gpr_asprintf(&buf, "%s(%" PRId64 ")", var, val);
-    result = gpr_leftpad(buf, ' ', 60);
-    gpr_free(buf);
-    return result;
+    name = gpr_strdup(var);
+  } else if (0 == strcmp(context, "t")) {
+    GPR_ASSERT(id == 0);
+    gpr_asprintf(&name, "TRANSPORT:%s", var);
+  } else if (0 == strcmp(context, "s")) {
+    GPR_ASSERT(id != 0);
+    gpr_asprintf(&name, "STREAM[%d]:%s", id, var);
+  } else {
+    gpr_asprintf(&name, "BAD_CONTEXT[%s][%d]:%s", context, id, var);
   }
-  underscore_pos = strchr(context, '_');
-  *scope = gpr_strdup(context);
-  (*scope)[underscore_pos - context] = 0;
-  if (id != 0) {
-    char *tmp = *scope;
-    gpr_asprintf(scope, "%s[%d]", tmp, id);
-    gpr_free(tmp);
-  }
-  gpr_asprintf(&buf, "%s.%s(%" PRId64 ")", underscore_pos + 1, var, val);
-  result = gpr_leftpad(buf, ' ', 60);
-  gpr_free(buf);
+  char *name_fld = gpr_leftpad(name, ' ', 64);
+  char *value;
+  gpr_asprintf(&value, "%" PRId64, val);
+  char *value_fld = gpr_leftpad(value, ' ', 8);
+  char *result;
+  gpr_asprintf(&result, "%s %s", name_fld, value_fld);
+  gpr_free(name);
+  gpr_free(name_fld);
+  gpr_free(value);
+  gpr_free(value_fld);
   return result;
 }
 
-static int samestr(char *a, char *b) {
-  if (a == NULL) {
-    return b == NULL;
-  }
-  if (b == NULL) {
-    return 0;
-  }
-  return 0 == strcmp(a, b);
-}
-
 void grpc_chttp2_flowctl_trace(const char *file, int line, const char *phase,
                                grpc_chttp2_flowctl_op op, const char *context1,
                                const char *var1, const char *context2,
                                const char *var2, int is_client,
                                uint32_t stream_id, int64_t val1, int64_t val2) {
-  char *scope1;
-  char *scope2;
   char *tmp_phase;
-  char *tmp_scope1;
-  char *label1 =
-      format_flowctl_context_var(context1, var1, val1, stream_id, &scope1);
-  char *label2 =
-      format_flowctl_context_var(context2, var2, val2, stream_id, &scope2);
+  char *label1 = format_flowctl_context_var(context1, var1, val1, stream_id);
+  char *label2 = format_flowctl_context_var(context2, var2, val2, stream_id);
   char *clisvr = is_client ? "client" : "server";
   char *prefix;
 
   tmp_phase = gpr_leftpad(phase, ' ', 8);
-  tmp_scope1 = gpr_leftpad(scope1, ' ', 11);
-  gpr_asprintf(&prefix, "FLOW %s: %s %s ", tmp_phase, clisvr, scope1);
+  gpr_asprintf(&prefix, "FLOW %s: %s ", tmp_phase, clisvr);
   gpr_free(tmp_phase);
-  gpr_free(tmp_scope1);
 
   switch (op) {
     case GRPC_CHTTP2_FLOWCTL_MOVE:
-      GPR_ASSERT(samestr(scope1, scope2));
       if (val2 != 0) {
         gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG,
                 "%sMOVE   %s <- %s giving %" PRId64, prefix, label1, label2,
@@ -2510,8 +2107,6 @@
       break;
   }
 
-  gpr_free(scope1);
-  gpr_free(scope2);
   gpr_free(label1);
   gpr_free(label2);
   gpr_free(prefix);
@@ -2548,10 +2143,11 @@
                                          grpc_transport *transport,
                                          gpr_slice_buffer *read_buffer) {
   grpc_chttp2_transport *t = (grpc_chttp2_transport *)transport;
-  REF_TRANSPORT(t, "reading_action"); /* matches unref inside reading_action */
+  GRPC_CHTTP2_REF_TRANSPORT(
+      t, "reading_action"); /* matches unref inside reading_action */
   if (read_buffer != NULL) {
     gpr_slice_buffer_move_into(read_buffer, &t->read_buffer);
     gpr_free(read_buffer);
   }
-  reading_action(exec_ctx, t, GRPC_ERROR_NONE);
+  read_action_begin(exec_ctx, t, GRPC_ERROR_NONE);
 }
diff --git a/src/core/ext/transport/chttp2/transport/frame.h b/src/core/ext/transport/chttp2/transport/frame.h
index 7776609..0f1e128 100644
--- a/src/core/ext/transport/chttp2/transport/frame.h
+++ b/src/core/ext/transport/chttp2/transport/frame.h
@@ -40,8 +40,8 @@
 #include "src/core/lib/iomgr/error.h"
 
 /* defined in internal.h */
-typedef struct grpc_chttp2_stream_parsing grpc_chttp2_stream_parsing;
-typedef struct grpc_chttp2_transport_parsing grpc_chttp2_transport_parsing;
+typedef struct grpc_chttp2_stream grpc_chttp2_stream;
+typedef struct grpc_chttp2_transport grpc_chttp2_transport;
 
 #define GRPC_CHTTP2_FRAME_DATA 0
 #define GRPC_CHTTP2_FRAME_HEADER 1
diff --git a/src/core/ext/transport/chttp2/transport/frame_data.c b/src/core/ext/transport/chttp2/transport/frame_data.c
index 9046fbc..8668816 100644
--- a/src/core/ext/transport/chttp2/transport/frame_data.c
+++ b/src/core/ext/transport/chttp2/transport/frame_data.c
@@ -51,16 +51,11 @@
 
 void grpc_chttp2_data_parser_destroy(grpc_exec_ctx *exec_ctx,
                                      grpc_chttp2_data_parser *parser) {
-  grpc_byte_stream *bs;
-  if (parser->parsing_frame) {
+  if (parser->parsing_frame != NULL) {
     grpc_chttp2_incoming_byte_stream_finished(
-        exec_ctx, parser->parsing_frame, GRPC_ERROR_CREATE("Parser destroyed"),
-        1);
+        exec_ctx, parser->parsing_frame, GRPC_ERROR_CREATE("Parser destroyed"));
   }
-  while (
-      (bs = grpc_chttp2_incoming_frame_queue_pop(&parser->incoming_frames))) {
-    grpc_byte_stream_destroy(exec_ctx, bs);
-  }
+  GRPC_ERROR_UNREF(parser->error);
 }
 
 grpc_error *grpc_chttp2_data_parser_begin_frame(grpc_chttp2_data_parser *parser,
@@ -145,22 +140,17 @@
   stats->data_bytes += write_bytes;
 }
 
-grpc_error *grpc_chttp2_data_parser_parse(
-    grpc_exec_ctx *exec_ctx, void *parser,
-    grpc_chttp2_transport_parsing *transport_parsing,
-    grpc_chttp2_stream_parsing *stream_parsing, gpr_slice slice, int is_last) {
+static grpc_error *parse_inner(grpc_exec_ctx *exec_ctx,
+                               grpc_chttp2_data_parser *p,
+                               grpc_chttp2_transport *t, grpc_chttp2_stream *s,
+                               gpr_slice slice) {
   uint8_t *const beg = GPR_SLICE_START_PTR(slice);
   uint8_t *const end = GPR_SLICE_END_PTR(slice);
   uint8_t *cur = beg;
-  grpc_chttp2_data_parser *p = parser;
   uint32_t message_flags;
   grpc_chttp2_incoming_byte_stream *incoming_byte_stream;
   char *msg;
 
-  if (is_last && p->is_last_frame) {
-    stream_parsing->received_close = 1;
-  }
-
   if (cur == end) {
     return GRPC_ERROR_NONE;
   }
@@ -171,7 +161,7 @@
       return GRPC_ERROR_REF(p->error);
     fh_0:
     case GRPC_CHTTP2_DATA_FH_0:
-      stream_parsing->stats.incoming.framing_bytes++;
+      s->stats.incoming.framing_bytes++;
       p->frame_type = *cur;
       switch (p->frame_type) {
         case 0:
@@ -184,7 +174,7 @@
           gpr_asprintf(&msg, "Bad GRPC frame type 0x%02x", p->frame_type);
           p->error = GRPC_ERROR_CREATE(msg);
           p->error = grpc_error_set_int(p->error, GRPC_ERROR_INT_STREAM_ID,
-                                        (intptr_t)stream_parsing->id);
+                                        (intptr_t)s->id);
           gpr_free(msg);
           msg = gpr_dump_slice(slice, GPR_DUMP_HEX | GPR_DUMP_ASCII);
           p->error =
@@ -201,7 +191,7 @@
       }
     /* fallthrough */
     case GRPC_CHTTP2_DATA_FH_1:
-      stream_parsing->stats.incoming.framing_bytes++;
+      s->stats.incoming.framing_bytes++;
       p->frame_size = ((uint32_t)*cur) << 24;
       if (++cur == end) {
         p->state = GRPC_CHTTP2_DATA_FH_2;
@@ -209,7 +199,7 @@
       }
     /* fallthrough */
     case GRPC_CHTTP2_DATA_FH_2:
-      stream_parsing->stats.incoming.framing_bytes++;
+      s->stats.incoming.framing_bytes++;
       p->frame_size |= ((uint32_t)*cur) << 16;
       if (++cur == end) {
         p->state = GRPC_CHTTP2_DATA_FH_3;
@@ -217,7 +207,7 @@
       }
     /* fallthrough */
     case GRPC_CHTTP2_DATA_FH_3:
-      stream_parsing->stats.incoming.framing_bytes++;
+      s->stats.incoming.framing_bytes++;
       p->frame_size |= ((uint32_t)*cur) << 8;
       if (++cur == end) {
         p->state = GRPC_CHTTP2_DATA_FH_4;
@@ -225,7 +215,7 @@
       }
     /* fallthrough */
     case GRPC_CHTTP2_DATA_FH_4:
-      stream_parsing->stats.incoming.framing_bytes++;
+      s->stats.incoming.framing_bytes++;
       p->frame_size |= ((uint32_t)*cur);
       p->state = GRPC_CHTTP2_DATA_FRAME;
       ++cur;
@@ -234,35 +224,32 @@
         message_flags |= GRPC_WRITE_INTERNAL_COMPRESS;
       }
       p->parsing_frame = incoming_byte_stream =
-          grpc_chttp2_incoming_byte_stream_create(
-              exec_ctx, transport_parsing, stream_parsing, p->frame_size,
-              message_flags, &p->incoming_frames);
+          grpc_chttp2_incoming_byte_stream_create(exec_ctx, t, s, p->frame_size,
+                                                  message_flags);
     /* fallthrough */
     case GRPC_CHTTP2_DATA_FRAME:
-      grpc_chttp2_list_add_parsing_seen_stream(transport_parsing,
-                                               stream_parsing);
       if (cur == end) {
         return GRPC_ERROR_NONE;
       }
       uint32_t remaining = (uint32_t)(end - cur);
       if (remaining == p->frame_size) {
-        stream_parsing->stats.incoming.data_bytes += p->frame_size;
+        s->stats.incoming.data_bytes += p->frame_size;
         grpc_chttp2_incoming_byte_stream_push(
             exec_ctx, p->parsing_frame,
             gpr_slice_sub(slice, (size_t)(cur - beg), (size_t)(end - beg)));
         grpc_chttp2_incoming_byte_stream_finished(exec_ctx, p->parsing_frame,
-                                                  GRPC_ERROR_NONE, 1);
+                                                  GRPC_ERROR_NONE);
         p->parsing_frame = NULL;
         p->state = GRPC_CHTTP2_DATA_FH_0;
         return GRPC_ERROR_NONE;
       } else if (remaining > p->frame_size) {
-        stream_parsing->stats.incoming.data_bytes += p->frame_size;
+        s->stats.incoming.data_bytes += p->frame_size;
         grpc_chttp2_incoming_byte_stream_push(
             exec_ctx, p->parsing_frame,
             gpr_slice_sub(slice, (size_t)(cur - beg),
                           (size_t)(cur + p->frame_size - beg)));
         grpc_chttp2_incoming_byte_stream_finished(exec_ctx, p->parsing_frame,
-                                                  GRPC_ERROR_NONE, 1);
+                                                  GRPC_ERROR_NONE);
         p->parsing_frame = NULL;
         cur += p->frame_size;
         goto fh_0; /* loop */
@@ -272,10 +259,25 @@
             exec_ctx, p->parsing_frame,
             gpr_slice_sub(slice, (size_t)(cur - beg), (size_t)(end - beg)));
         p->frame_size -= remaining;
-        stream_parsing->stats.incoming.data_bytes += remaining;
+        s->stats.incoming.data_bytes += remaining;
         return GRPC_ERROR_NONE;
       }
   }
 
   GPR_UNREACHABLE_CODE(return GRPC_ERROR_CREATE("Should never reach here"));
 }
+
+grpc_error *grpc_chttp2_data_parser_parse(grpc_exec_ctx *exec_ctx, void *parser,
+                                          grpc_chttp2_transport *t,
+                                          grpc_chttp2_stream *s,
+                                          gpr_slice slice, int is_last) {
+  grpc_chttp2_data_parser *p = parser;
+  grpc_error *error = parse_inner(exec_ctx, p, t, s, slice);
+
+  if (is_last && p->is_last_frame) {
+    grpc_chttp2_mark_stream_closed(exec_ctx, t, s, true, false,
+                                   GRPC_ERROR_NONE);
+  }
+
+  return error;
+}
diff --git a/src/core/ext/transport/chttp2/transport/frame_data.h b/src/core/ext/transport/chttp2/transport/frame_data.h
index a21a794..eb2d97d 100644
--- a/src/core/ext/transport/chttp2/transport/frame_data.h
+++ b/src/core/ext/transport/chttp2/transport/frame_data.h
@@ -69,7 +69,6 @@
   grpc_error *error;
 
   int is_frame_compressed;
-  grpc_chttp2_incoming_frame_queue incoming_frames;
   grpc_chttp2_incoming_byte_stream *parsing_frame;
 } grpc_chttp2_data_parser;
 
@@ -92,10 +91,10 @@
 
 /* handle a slice of a data frame - is_last indicates the last slice of a
    frame */
-grpc_error *grpc_chttp2_data_parser_parse(
-    grpc_exec_ctx *exec_ctx, void *parser,
-    grpc_chttp2_transport_parsing *transport_parsing,
-    grpc_chttp2_stream_parsing *stream_parsing, gpr_slice slice, int is_last);
+grpc_error *grpc_chttp2_data_parser_parse(grpc_exec_ctx *exec_ctx, void *parser,
+                                          grpc_chttp2_transport *t,
+                                          grpc_chttp2_stream *s,
+                                          gpr_slice slice, int is_last);
 
 void grpc_chttp2_encode_data(uint32_t id, gpr_slice_buffer *inbuf,
                              uint32_t write_bytes, int is_eof,
diff --git a/src/core/ext/transport/chttp2/transport/frame_goaway.c b/src/core/ext/transport/chttp2/transport/frame_goaway.c
index 299e27a..33d2269 100644
--- a/src/core/ext/transport/chttp2/transport/frame_goaway.c
+++ b/src/core/ext/transport/chttp2/transport/frame_goaway.c
@@ -67,10 +67,11 @@
   return GRPC_ERROR_NONE;
 }
 
-grpc_error *grpc_chttp2_goaway_parser_parse(
-    grpc_exec_ctx *exec_ctx, void *parser,
-    grpc_chttp2_transport_parsing *transport_parsing,
-    grpc_chttp2_stream_parsing *stream_parsing, gpr_slice slice, int is_last) {
+grpc_error *grpc_chttp2_goaway_parser_parse(grpc_exec_ctx *exec_ctx,
+                                            void *parser,
+                                            grpc_chttp2_transport *t,
+                                            grpc_chttp2_stream *s,
+                                            gpr_slice slice, int is_last) {
   uint8_t *const beg = GPR_SLICE_START_PTR(slice);
   uint8_t *const end = GPR_SLICE_END_PTR(slice);
   uint8_t *cur = beg;
@@ -148,12 +149,9 @@
       p->debug_pos += (uint32_t)(end - cur);
       p->state = GRPC_CHTTP2_GOAWAY_DEBUG;
       if (is_last) {
-        transport_parsing->goaway_received = 1;
-        transport_parsing->goaway_last_stream_index = p->last_stream_id;
-        gpr_slice_unref(transport_parsing->goaway_text);
-        transport_parsing->goaway_error = (grpc_status_code)p->error_code;
-        transport_parsing->goaway_text =
-            gpr_slice_new(p->debug_data, p->debug_length, gpr_free);
+        grpc_chttp2_add_incoming_goaway(
+            exec_ctx, t, (uint32_t)p->error_code,
+            gpr_slice_new(p->debug_data, p->debug_length, gpr_free));
         p->debug_data = NULL;
       }
       return GRPC_ERROR_NONE;
diff --git a/src/core/ext/transport/chttp2/transport/frame_goaway.h b/src/core/ext/transport/chttp2/transport/frame_goaway.h
index eb43034..355104a 100644
--- a/src/core/ext/transport/chttp2/transport/frame_goaway.h
+++ b/src/core/ext/transport/chttp2/transport/frame_goaway.h
@@ -65,10 +65,11 @@
 void grpc_chttp2_goaway_parser_destroy(grpc_chttp2_goaway_parser *p);
 grpc_error *grpc_chttp2_goaway_parser_begin_frame(
     grpc_chttp2_goaway_parser *parser, uint32_t length, uint8_t flags);
-grpc_error *grpc_chttp2_goaway_parser_parse(
-    grpc_exec_ctx *exec_ctx, void *parser,
-    grpc_chttp2_transport_parsing *transport_parsing,
-    grpc_chttp2_stream_parsing *stream_parsing, gpr_slice slice, int is_last);
+grpc_error *grpc_chttp2_goaway_parser_parse(grpc_exec_ctx *exec_ctx,
+                                            void *parser,
+                                            grpc_chttp2_transport *t,
+                                            grpc_chttp2_stream *s,
+                                            gpr_slice slice, int is_last);
 
 void grpc_chttp2_goaway_append(uint32_t last_stream_id, uint32_t error_code,
                                gpr_slice debug_data,
diff --git a/src/core/ext/transport/chttp2/transport/frame_ping.c b/src/core/ext/transport/chttp2/transport/frame_ping.c
index 1f814ab..624f426 100644
--- a/src/core/ext/transport/chttp2/transport/frame_ping.c
+++ b/src/core/ext/transport/chttp2/transport/frame_ping.c
@@ -73,10 +73,10 @@
   return GRPC_ERROR_NONE;
 }
 
-grpc_error *grpc_chttp2_ping_parser_parse(
-    grpc_exec_ctx *exec_ctx, void *parser,
-    grpc_chttp2_transport_parsing *transport_parsing,
-    grpc_chttp2_stream_parsing *stream_parsing, gpr_slice slice, int is_last) {
+grpc_error *grpc_chttp2_ping_parser_parse(grpc_exec_ctx *exec_ctx, void *parser,
+                                          grpc_chttp2_transport *t,
+                                          grpc_chttp2_stream *s,
+                                          gpr_slice slice, int is_last) {
   uint8_t *const beg = GPR_SLICE_START_PTR(slice);
   uint8_t *const end = GPR_SLICE_END_PTR(slice);
   uint8_t *cur = beg;
@@ -91,10 +91,11 @@
   if (p->byte == 8) {
     GPR_ASSERT(is_last);
     if (p->is_ack) {
-      grpc_chttp2_ack_ping(exec_ctx, transport_parsing, p->opaque_8bytes);
+      grpc_chttp2_ack_ping(exec_ctx, t, p->opaque_8bytes);
     } else {
-      gpr_slice_buffer_add(&transport_parsing->qbuf,
+      gpr_slice_buffer_add(&t->qbuf,
                            grpc_chttp2_ping_create(1, p->opaque_8bytes));
+      grpc_chttp2_initiate_write(exec_ctx, t, false, "ping response");
     }
   }
 
diff --git a/src/core/ext/transport/chttp2/transport/frame_ping.h b/src/core/ext/transport/chttp2/transport/frame_ping.h
index 5a87234..2071f64 100644
--- a/src/core/ext/transport/chttp2/transport/frame_ping.h
+++ b/src/core/ext/transport/chttp2/transport/frame_ping.h
@@ -48,9 +48,9 @@
 
 grpc_error *grpc_chttp2_ping_parser_begin_frame(grpc_chttp2_ping_parser *parser,
                                                 uint32_t length, uint8_t flags);
-grpc_error *grpc_chttp2_ping_parser_parse(
-    grpc_exec_ctx *exec_ctx, void *parser,
-    grpc_chttp2_transport_parsing *transport_parsing,
-    grpc_chttp2_stream_parsing *stream_parsing, gpr_slice slice, int is_last);
+grpc_error *grpc_chttp2_ping_parser_parse(grpc_exec_ctx *exec_ctx, void *parser,
+                                          grpc_chttp2_transport *t,
+                                          grpc_chttp2_stream *s,
+                                          gpr_slice slice, int is_last);
 
 #endif /* GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_FRAME_PING_H */
diff --git a/src/core/ext/transport/chttp2/transport/frame_rst_stream.c b/src/core/ext/transport/chttp2/transport/frame_rst_stream.c
index e3a3c9e..1bb6ed8 100644
--- a/src/core/ext/transport/chttp2/transport/frame_rst_stream.c
+++ b/src/core/ext/transport/chttp2/transport/frame_rst_stream.c
@@ -39,6 +39,8 @@
 #include <grpc/support/string_util.h>
 
 #include "src/core/ext/transport/chttp2/transport/frame.h"
+#include "src/core/ext/transport/chttp2/transport/http2_errors.h"
+#include "src/core/ext/transport/chttp2/transport/status_conversion.h"
 
 gpr_slice grpc_chttp2_rst_stream_create(uint32_t id, uint32_t code,
                                         grpc_transport_one_way_stats *stats) {
@@ -83,10 +85,11 @@
   return GRPC_ERROR_NONE;
 }
 
-grpc_error *grpc_chttp2_rst_stream_parser_parse(
-    grpc_exec_ctx *exec_ctx, void *parser,
-    grpc_chttp2_transport_parsing *transport_parsing,
-    grpc_chttp2_stream_parsing *stream_parsing, gpr_slice slice, int is_last) {
+grpc_error *grpc_chttp2_rst_stream_parser_parse(grpc_exec_ctx *exec_ctx,
+                                                void *parser,
+                                                grpc_chttp2_transport *t,
+                                                grpc_chttp2_stream *s,
+                                                gpr_slice slice, int is_last) {
   uint8_t *const beg = GPR_SLICE_START_PTR(slice);
   uint8_t *const end = GPR_SLICE_END_PTR(slice);
   uint8_t *cur = beg;
@@ -97,19 +100,28 @@
     cur++;
     p->byte++;
   }
-  stream_parsing->stats.incoming.framing_bytes += (uint64_t)(end - cur);
+  s->stats.incoming.framing_bytes += (uint64_t)(end - cur);
 
   if (p->byte == 4) {
     GPR_ASSERT(is_last);
-    stream_parsing->received_close = 1;
-    if (stream_parsing->forced_close_error == GRPC_ERROR_NONE) {
-      stream_parsing->forced_close_error = grpc_error_set_int(
-          GRPC_ERROR_CREATE("RST_STREAM"), GRPC_ERROR_INT_HTTP2_ERROR,
-          (intptr_t)((((uint32_t)p->reason_bytes[0]) << 24) |
-                     (((uint32_t)p->reason_bytes[1]) << 16) |
-                     (((uint32_t)p->reason_bytes[2]) << 8) |
-                     (((uint32_t)p->reason_bytes[3]))));
+    uint32_t reason = (((uint32_t)p->reason_bytes[0]) << 24) |
+                      (((uint32_t)p->reason_bytes[1]) << 16) |
+                      (((uint32_t)p->reason_bytes[2]) << 8) |
+                      (((uint32_t)p->reason_bytes[3]));
+    grpc_error *error = GRPC_ERROR_NONE;
+    if (reason != GRPC_CHTTP2_NO_ERROR) {
+      error = grpc_error_set_int(GRPC_ERROR_CREATE("RST_STREAM"),
+                                 GRPC_ERROR_INT_HTTP2_ERROR, reason);
+      grpc_status_code status_code = grpc_chttp2_http2_error_to_grpc_status(
+          (grpc_chttp2_error_code)reason, s->deadline);
+      char *status_details;
+      gpr_asprintf(&status_details, "Received RST_STREAM with error code %d",
+                   reason);
+      gpr_slice slice_details = gpr_slice_from_copied_string(status_details);
+      gpr_free(status_details);
+      grpc_chttp2_fake_status(exec_ctx, t, s, status_code, &slice_details);
     }
+    grpc_chttp2_mark_stream_closed(exec_ctx, t, s, true, true, error);
   }
 
   return GRPC_ERROR_NONE;
diff --git a/src/core/ext/transport/chttp2/transport/frame_rst_stream.h b/src/core/ext/transport/chttp2/transport/frame_rst_stream.h
index 11cf94f..5a1f578 100644
--- a/src/core/ext/transport/chttp2/transport/frame_rst_stream.h
+++ b/src/core/ext/transport/chttp2/transport/frame_rst_stream.h
@@ -49,9 +49,10 @@
 
 grpc_error *grpc_chttp2_rst_stream_parser_begin_frame(
     grpc_chttp2_rst_stream_parser *parser, uint32_t length, uint8_t flags);
-grpc_error *grpc_chttp2_rst_stream_parser_parse(
-    grpc_exec_ctx *exec_ctx, void *parser,
-    grpc_chttp2_transport_parsing *transport_parsing,
-    grpc_chttp2_stream_parsing *stream_parsing, gpr_slice slice, int is_last);
+grpc_error *grpc_chttp2_rst_stream_parser_parse(grpc_exec_ctx *exec_ctx,
+                                                void *parser,
+                                                grpc_chttp2_transport *t,
+                                                grpc_chttp2_stream *s,
+                                                gpr_slice slice, int is_last);
 
 #endif /* GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_FRAME_RST_STREAM_H */
diff --git a/src/core/ext/transport/chttp2/transport/frame_settings.c b/src/core/ext/transport/chttp2/transport/frame_settings.c
index 04b96c4..fc0383d 100644
--- a/src/core/ext/transport/chttp2/transport/frame_settings.c
+++ b/src/core/ext/transport/chttp2/transport/frame_settings.c
@@ -143,10 +143,10 @@
   }
 }
 
-grpc_error *grpc_chttp2_settings_parser_parse(
-    grpc_exec_ctx *exec_ctx, void *p,
-    grpc_chttp2_transport_parsing *transport_parsing,
-    grpc_chttp2_stream_parsing *stream_parsing, gpr_slice slice, int is_last) {
+grpc_error *grpc_chttp2_settings_parser_parse(grpc_exec_ctx *exec_ctx, void *p,
+                                              grpc_chttp2_transport *t,
+                                              grpc_chttp2_stream *s,
+                                              gpr_slice slice, int is_last) {
   grpc_chttp2_settings_parser *parser = p;
   const uint8_t *cur = GPR_SLICE_START_PTR(slice);
   const uint8_t *end = GPR_SLICE_END_PTR(slice);
@@ -162,11 +162,9 @@
         if (cur == end) {
           parser->state = GRPC_CHTTP2_SPS_ID0;
           if (is_last) {
-            transport_parsing->settings_updated = 1;
             memcpy(parser->target_settings, parser->incoming_settings,
                    GRPC_CHTTP2_NUM_SETTINGS * sizeof(uint32_t));
-            gpr_slice_buffer_add(&transport_parsing->qbuf,
-                                 grpc_chttp2_settings_ack_create());
+            gpr_slice_buffer_add(&t->qbuf, grpc_chttp2_settings_ack_create());
           }
           return GRPC_ERROR_NONE;
         }
@@ -226,9 +224,9 @@
                 break;
               case GRPC_CHTTP2_DISCONNECT_ON_INVALID_VALUE:
                 grpc_chttp2_goaway_append(
-                    transport_parsing->last_incoming_stream_id, sp->error_value,
+                    t->last_incoming_stream_id, sp->error_value,
                     gpr_slice_from_static_string("HTTP2 settings error"),
-                    &transport_parsing->qbuf);
+                    &t->qbuf);
                 gpr_asprintf(&msg, "invalid value %u passed for %s",
                              parser->value, sp->name);
                 grpc_error *err = GRPC_ERROR_CREATE(msg);
@@ -238,18 +236,17 @@
           }
           if (parser->id == GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE &&
               parser->incoming_settings[parser->id] != parser->value) {
-            transport_parsing->initial_window_update =
+            t->initial_window_update =
                 (int64_t)parser->value - parser->incoming_settings[parser->id];
             if (grpc_http_trace) {
               gpr_log(GPR_DEBUG, "adding %d for initial_window change",
-                      (int)transport_parsing->initial_window_update);
+                      (int)t->initial_window_update);
             }
           }
           parser->incoming_settings[parser->id] = parser->value;
           if (grpc_http_trace) {
             gpr_log(GPR_DEBUG, "CHTTP2:%s: got setting %d = %d",
-                    transport_parsing->is_client ? "CLI" : "SVR", parser->id,
-                    parser->value);
+                    t->is_client ? "CLI" : "SVR", parser->id, parser->value);
           }
         } else if (grpc_http_trace) {
           gpr_log(GPR_ERROR, "CHTTP2: Ignoring unknown setting %d (value %d)",
diff --git a/src/core/ext/transport/chttp2/transport/frame_settings.h b/src/core/ext/transport/chttp2/transport/frame_settings.h
index f654c59..4bfa944 100644
--- a/src/core/ext/transport/chttp2/transport/frame_settings.h
+++ b/src/core/ext/transport/chttp2/transport/frame_settings.h
@@ -95,9 +95,10 @@
 grpc_error *grpc_chttp2_settings_parser_begin_frame(
     grpc_chttp2_settings_parser *parser, uint32_t length, uint8_t flags,
     uint32_t *settings);
-grpc_error *grpc_chttp2_settings_parser_parse(
-    grpc_exec_ctx *exec_ctx, void *parser,
-    grpc_chttp2_transport_parsing *transport_parsing,
-    grpc_chttp2_stream_parsing *stream_parsing, gpr_slice slice, int is_last);
+grpc_error *grpc_chttp2_settings_parser_parse(grpc_exec_ctx *exec_ctx,
+                                              void *parser,
+                                              grpc_chttp2_transport *t,
+                                              grpc_chttp2_stream *s,
+                                              gpr_slice slice, int is_last);
 
 #endif /* GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_FRAME_SETTINGS_H */
diff --git a/src/core/ext/transport/chttp2/transport/frame_window_update.c b/src/core/ext/transport/chttp2/transport/frame_window_update.c
index 3cf848f..418166a 100644
--- a/src/core/ext/transport/chttp2/transport/frame_window_update.c
+++ b/src/core/ext/transport/chttp2/transport/frame_window_update.c
@@ -80,9 +80,8 @@
 }
 
 grpc_error *grpc_chttp2_window_update_parser_parse(
-    grpc_exec_ctx *exec_ctx, void *parser,
-    grpc_chttp2_transport_parsing *transport_parsing,
-    grpc_chttp2_stream_parsing *stream_parsing, gpr_slice slice, int is_last) {
+    grpc_exec_ctx *exec_ctx, void *parser, grpc_chttp2_transport *t,
+    grpc_chttp2_stream *s, gpr_slice slice, int is_last) {
   uint8_t *const beg = GPR_SLICE_START_PTR(slice);
   uint8_t *const end = GPR_SLICE_END_PTR(slice);
   uint8_t *cur = beg;
@@ -94,8 +93,8 @@
     p->byte++;
   }
 
-  if (stream_parsing != NULL) {
-    stream_parsing->stats.incoming.framing_bytes += (uint32_t)(end - cur);
+  if (s != NULL) {
+    s->stats.incoming.framing_bytes += (uint32_t)(end - cur);
   }
 
   if (p->byte == 4) {
@@ -109,17 +108,26 @@
     }
     GPR_ASSERT(is_last);
 
-    if (transport_parsing->incoming_stream_id != 0) {
-      if (stream_parsing != NULL) {
-        GRPC_CHTTP2_FLOW_CREDIT_STREAM("parse", transport_parsing,
-                                       stream_parsing, outgoing_window,
+    if (t->incoming_stream_id != 0) {
+      if (s != NULL) {
+        bool was_zero = s->outgoing_window <= 0;
+        GRPC_CHTTP2_FLOW_CREDIT_STREAM("parse", t, s, outgoing_window,
                                        received_update);
-        grpc_chttp2_list_add_parsing_seen_stream(transport_parsing,
-                                                 stream_parsing);
+        bool is_zero = s->outgoing_window <= 0;
+        if (was_zero && !is_zero) {
+          grpc_chttp2_become_writable(exec_ctx, t, s, false,
+                                      "stream.read_flow_control");
+        }
       }
     } else {
-      GRPC_CHTTP2_FLOW_CREDIT_TRANSPORT("parse", transport_parsing,
-                                        outgoing_window, received_update);
+      bool was_zero = t->outgoing_window <= 0;
+      GRPC_CHTTP2_FLOW_CREDIT_TRANSPORT("parse", t, outgoing_window,
+                                        received_update);
+      bool is_zero = t->outgoing_window <= 0;
+      if (was_zero && !is_zero) {
+        grpc_chttp2_initiate_write(exec_ctx, t, false,
+                                   "new_global_flow_control");
+      }
     }
   }
 
diff --git a/src/core/ext/transport/chttp2/transport/frame_window_update.h b/src/core/ext/transport/chttp2/transport/frame_window_update.h
index 1bcbbf9..6e62f31 100644
--- a/src/core/ext/transport/chttp2/transport/frame_window_update.h
+++ b/src/core/ext/transport/chttp2/transport/frame_window_update.h
@@ -51,8 +51,7 @@
 grpc_error *grpc_chttp2_window_update_parser_begin_frame(
     grpc_chttp2_window_update_parser *parser, uint32_t length, uint8_t flags);
 grpc_error *grpc_chttp2_window_update_parser_parse(
-    grpc_exec_ctx *exec_ctx, void *parser,
-    grpc_chttp2_transport_parsing *transport_parsing,
-    grpc_chttp2_stream_parsing *stream_parsing, gpr_slice slice, int is_last);
+    grpc_exec_ctx *exec_ctx, void *parser, grpc_chttp2_transport *t,
+    grpc_chttp2_stream *s, gpr_slice slice, int is_last);
 
 #endif /* GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_FRAME_WINDOW_UPDATE_H */
diff --git a/src/core/ext/transport/chttp2/transport/hpack_parser.c b/src/core/ext/transport/chttp2/transport/hpack_parser.c
index 522455f..8180f78 100644
--- a/src/core/ext/transport/chttp2/transport/hpack_parser.c
+++ b/src/core/ext/transport/chttp2/transport/hpack_parser.c
@@ -78,69 +78,96 @@
    a set of indirect jumps, and so not waste stack space. */
 
 /* forward declarations for parsing states */
-static grpc_error *parse_begin(grpc_chttp2_hpack_parser *p, const uint8_t *cur,
+static grpc_error *parse_begin(grpc_exec_ctx *exec_ctx,
+                               grpc_chttp2_hpack_parser *p, const uint8_t *cur,
                                const uint8_t *end);
-static grpc_error *parse_error(grpc_chttp2_hpack_parser *p, const uint8_t *cur,
+static grpc_error *parse_error(grpc_exec_ctx *exec_ctx,
+                               grpc_chttp2_hpack_parser *p, const uint8_t *cur,
                                const uint8_t *end, grpc_error *error);
-static grpc_error *still_parse_error(grpc_chttp2_hpack_parser *p,
+static grpc_error *still_parse_error(grpc_exec_ctx *exec_ctx,
+                                     grpc_chttp2_hpack_parser *p,
                                      const uint8_t *cur, const uint8_t *end);
-static grpc_error *parse_illegal_op(grpc_chttp2_hpack_parser *p,
+static grpc_error *parse_illegal_op(grpc_exec_ctx *exec_ctx,
+                                    grpc_chttp2_hpack_parser *p,
                                     const uint8_t *cur, const uint8_t *end);
 
-static grpc_error *parse_string_prefix(grpc_chttp2_hpack_parser *p,
+static grpc_error *parse_string_prefix(grpc_exec_ctx *exec_ctx,
+                                       grpc_chttp2_hpack_parser *p,
                                        const uint8_t *cur, const uint8_t *end);
-static grpc_error *parse_key_string(grpc_chttp2_hpack_parser *p,
+static grpc_error *parse_key_string(grpc_exec_ctx *exec_ctx,
+                                    grpc_chttp2_hpack_parser *p,
                                     const uint8_t *cur, const uint8_t *end);
 static grpc_error *parse_value_string_with_indexed_key(
-    grpc_chttp2_hpack_parser *p, const uint8_t *cur, const uint8_t *end);
+    grpc_exec_ctx *exec_ctx, grpc_chttp2_hpack_parser *p, const uint8_t *cur,
+    const uint8_t *end);
 static grpc_error *parse_value_string_with_literal_key(
-    grpc_chttp2_hpack_parser *p, const uint8_t *cur, const uint8_t *end);
+    grpc_exec_ctx *exec_ctx, grpc_chttp2_hpack_parser *p, const uint8_t *cur,
+    const uint8_t *end);
 
-static grpc_error *parse_value0(grpc_chttp2_hpack_parser *p, const uint8_t *cur,
+static grpc_error *parse_value0(grpc_exec_ctx *exec_ctx,
+                                grpc_chttp2_hpack_parser *p, const uint8_t *cur,
                                 const uint8_t *end);
-static grpc_error *parse_value1(grpc_chttp2_hpack_parser *p, const uint8_t *cur,
+static grpc_error *parse_value1(grpc_exec_ctx *exec_ctx,
+                                grpc_chttp2_hpack_parser *p, const uint8_t *cur,
                                 const uint8_t *end);
-static grpc_error *parse_value2(grpc_chttp2_hpack_parser *p, const uint8_t *cur,
+static grpc_error *parse_value2(grpc_exec_ctx *exec_ctx,
+                                grpc_chttp2_hpack_parser *p, const uint8_t *cur,
                                 const uint8_t *end);
-static grpc_error *parse_value3(grpc_chttp2_hpack_parser *p, const uint8_t *cur,
+static grpc_error *parse_value3(grpc_exec_ctx *exec_ctx,
+                                grpc_chttp2_hpack_parser *p, const uint8_t *cur,
                                 const uint8_t *end);
-static grpc_error *parse_value4(grpc_chttp2_hpack_parser *p, const uint8_t *cur,
+static grpc_error *parse_value4(grpc_exec_ctx *exec_ctx,
+                                grpc_chttp2_hpack_parser *p, const uint8_t *cur,
                                 const uint8_t *end);
-static grpc_error *parse_value5up(grpc_chttp2_hpack_parser *p,
+static grpc_error *parse_value5up(grpc_exec_ctx *exec_ctx,
+                                  grpc_chttp2_hpack_parser *p,
                                   const uint8_t *cur, const uint8_t *end);
 
-static grpc_error *parse_indexed_field(grpc_chttp2_hpack_parser *p,
+static grpc_error *parse_indexed_field(grpc_exec_ctx *exec_ctx,
+                                       grpc_chttp2_hpack_parser *p,
                                        const uint8_t *cur, const uint8_t *end);
-static grpc_error *parse_indexed_field_x(grpc_chttp2_hpack_parser *p,
+static grpc_error *parse_indexed_field_x(grpc_exec_ctx *exec_ctx,
+                                         grpc_chttp2_hpack_parser *p,
                                          const uint8_t *cur,
                                          const uint8_t *end);
-static grpc_error *parse_lithdr_incidx(grpc_chttp2_hpack_parser *p,
+static grpc_error *parse_lithdr_incidx(grpc_exec_ctx *exec_ctx,
+                                       grpc_chttp2_hpack_parser *p,
                                        const uint8_t *cur, const uint8_t *end);
-static grpc_error *parse_lithdr_incidx_x(grpc_chttp2_hpack_parser *p,
+static grpc_error *parse_lithdr_incidx_x(grpc_exec_ctx *exec_ctx,
+                                         grpc_chttp2_hpack_parser *p,
                                          const uint8_t *cur,
                                          const uint8_t *end);
-static grpc_error *parse_lithdr_incidx_v(grpc_chttp2_hpack_parser *p,
+static grpc_error *parse_lithdr_incidx_v(grpc_exec_ctx *exec_ctx,
+                                         grpc_chttp2_hpack_parser *p,
                                          const uint8_t *cur,
                                          const uint8_t *end);
-static grpc_error *parse_lithdr_notidx(grpc_chttp2_hpack_parser *p,
+static grpc_error *parse_lithdr_notidx(grpc_exec_ctx *exec_ctx,
+                                       grpc_chttp2_hpack_parser *p,
                                        const uint8_t *cur, const uint8_t *end);
-static grpc_error *parse_lithdr_notidx_x(grpc_chttp2_hpack_parser *p,
+static grpc_error *parse_lithdr_notidx_x(grpc_exec_ctx *exec_ctx,
+                                         grpc_chttp2_hpack_parser *p,
                                          const uint8_t *cur,
                                          const uint8_t *end);
-static grpc_error *parse_lithdr_notidx_v(grpc_chttp2_hpack_parser *p,
+static grpc_error *parse_lithdr_notidx_v(grpc_exec_ctx *exec_ctx,
+                                         grpc_chttp2_hpack_parser *p,
                                          const uint8_t *cur,
                                          const uint8_t *end);
-static grpc_error *parse_lithdr_nvridx(grpc_chttp2_hpack_parser *p,
+static grpc_error *parse_lithdr_nvridx(grpc_exec_ctx *exec_ctx,
+                                       grpc_chttp2_hpack_parser *p,
                                        const uint8_t *cur, const uint8_t *end);
-static grpc_error *parse_lithdr_nvridx_x(grpc_chttp2_hpack_parser *p,
+static grpc_error *parse_lithdr_nvridx_x(grpc_exec_ctx *exec_ctx,
+                                         grpc_chttp2_hpack_parser *p,
                                          const uint8_t *cur,
                                          const uint8_t *end);
-static grpc_error *parse_lithdr_nvridx_v(grpc_chttp2_hpack_parser *p,
+static grpc_error *parse_lithdr_nvridx_v(grpc_exec_ctx *exec_ctx,
+                                         grpc_chttp2_hpack_parser *p,
                                          const uint8_t *cur,
                                          const uint8_t *end);
-static grpc_error *parse_max_tbl_size(grpc_chttp2_hpack_parser *p,
+static grpc_error *parse_max_tbl_size(grpc_exec_ctx *exec_ctx,
+                                      grpc_chttp2_hpack_parser *p,
                                       const uint8_t *cur, const uint8_t *end);
-static grpc_error *parse_max_tbl_size_x(grpc_chttp2_hpack_parser *p,
+static grpc_error *parse_max_tbl_size_x(grpc_exec_ctx *exec_ctx,
+                                        grpc_chttp2_hpack_parser *p,
                                         const uint8_t *cur, const uint8_t *end);
 
 /* we translate the first byte of a hpack field into one of these decoding
@@ -639,8 +666,8 @@
 };
 
 /* emission helpers */
-static grpc_error *on_hdr(grpc_chttp2_hpack_parser *p, grpc_mdelem *md,
-                          int add_to_table) {
+static grpc_error *on_hdr(grpc_exec_ctx *exec_ctx, grpc_chttp2_hpack_parser *p,
+                          grpc_mdelem *md, int add_to_table) {
   if (add_to_table) {
     grpc_error *err = grpc_chttp2_hptbl_add(&p->table, md);
     if (err != GRPC_ERROR_NONE) return err;
@@ -649,7 +676,7 @@
     GRPC_MDELEM_UNREF(md);
     return GRPC_ERROR_CREATE("on_header callback not set");
   }
-  p->on_header(p->on_header_user_data, md);
+  p->on_header(exec_ctx, p->on_header_user_data, md);
   return GRPC_ERROR_NONE;
 }
 
@@ -661,78 +688,86 @@
 }
 
 /* jump to the next state */
-static grpc_error *parse_next(grpc_chttp2_hpack_parser *p, const uint8_t *cur,
+static grpc_error *parse_next(grpc_exec_ctx *exec_ctx,
+                              grpc_chttp2_hpack_parser *p, const uint8_t *cur,
                               const uint8_t *end) {
   p->state = *p->next_state++;
-  return p->state(p, cur, end);
+  return p->state(exec_ctx, p, cur, end);
 }
 
 /* begin parsing a header: all functionality is encoded into lookup tables
    above */
-static grpc_error *parse_begin(grpc_chttp2_hpack_parser *p, const uint8_t *cur,
+static grpc_error *parse_begin(grpc_exec_ctx *exec_ctx,
+                               grpc_chttp2_hpack_parser *p, const uint8_t *cur,
                                const uint8_t *end) {
   if (cur == end) {
     p->state = parse_begin;
     return GRPC_ERROR_NONE;
   }
 
-  return first_byte_action[first_byte_lut[*cur]](p, cur, end);
+  return first_byte_action[first_byte_lut[*cur]](exec_ctx, p, cur, end);
 }
 
 /* stream dependency and prioritization data: we just skip it */
-static grpc_error *parse_stream_weight(grpc_chttp2_hpack_parser *p,
+static grpc_error *parse_stream_weight(grpc_exec_ctx *exec_ctx,
+                                       grpc_chttp2_hpack_parser *p,
                                        const uint8_t *cur, const uint8_t *end) {
   if (cur == end) {
     p->state = parse_stream_weight;
     return GRPC_ERROR_NONE;
   }
 
-  return p->after_prioritization(p, cur + 1, end);
+  return p->after_prioritization(exec_ctx, p, cur + 1, end);
 }
 
-static grpc_error *parse_stream_dep3(grpc_chttp2_hpack_parser *p,
+static grpc_error *parse_stream_dep3(grpc_exec_ctx *exec_ctx,
+                                     grpc_chttp2_hpack_parser *p,
                                      const uint8_t *cur, const uint8_t *end) {
   if (cur == end) {
     p->state = parse_stream_dep3;
     return GRPC_ERROR_NONE;
   }
 
-  return parse_stream_weight(p, cur + 1, end);
+  return parse_stream_weight(exec_ctx, p, cur + 1, end);
 }
 
-static grpc_error *parse_stream_dep2(grpc_chttp2_hpack_parser *p,
+static grpc_error *parse_stream_dep2(grpc_exec_ctx *exec_ctx,
+                                     grpc_chttp2_hpack_parser *p,
                                      const uint8_t *cur, const uint8_t *end) {
   if (cur == end) {
     p->state = parse_stream_dep2;
     return GRPC_ERROR_NONE;
   }
 
-  return parse_stream_dep3(p, cur + 1, end);
+  return parse_stream_dep3(exec_ctx, p, cur + 1, end);
 }
 
-static grpc_error *parse_stream_dep1(grpc_chttp2_hpack_parser *p,
+static grpc_error *parse_stream_dep1(grpc_exec_ctx *exec_ctx,
+                                     grpc_chttp2_hpack_parser *p,
                                      const uint8_t *cur, const uint8_t *end) {
   if (cur == end) {
     p->state = parse_stream_dep1;
     return GRPC_ERROR_NONE;
   }
 
-  return parse_stream_dep2(p, cur + 1, end);
+  return parse_stream_dep2(exec_ctx, p, cur + 1, end);
 }
 
-static grpc_error *parse_stream_dep0(grpc_chttp2_hpack_parser *p,
+static grpc_error *parse_stream_dep0(grpc_exec_ctx *exec_ctx,
+                                     grpc_chttp2_hpack_parser *p,
                                      const uint8_t *cur, const uint8_t *end) {
   if (cur == end) {
     p->state = parse_stream_dep0;
     return GRPC_ERROR_NONE;
   }
 
-  return parse_stream_dep1(p, cur + 1, end);
+  return parse_stream_dep1(exec_ctx, p, cur + 1, end);
 }
 
 /* emit an indexed field; for now just logs it to console; jumps to
    begin the next field on completion */
-static grpc_error *finish_indexed_field(grpc_chttp2_hpack_parser *p,
+static grpc_error *finish_indexed_field(grpc_exec_ctx *exec_ctx,
+                                        grpc_chttp2_hpack_parser *p,
                                         const uint8_t *cur,
                                         const uint8_t *end) {
   grpc_mdelem *md = grpc_chttp2_hptbl_lookup(&p->table, p->index);
@@ -743,21 +778,23 @@
         GRPC_ERROR_INT_SIZE, (intptr_t)p->table.num_ents);
   }
   GRPC_MDELEM_REF(md);
-  grpc_error *err = on_hdr(p, md, 0);
+  grpc_error *err = on_hdr(exec_ctx, p, md, 0);
   if (err != GRPC_ERROR_NONE) return err;
-  return parse_begin(p, cur, end);
+  return parse_begin(exec_ctx, p, cur, end);
 }
 
 /* parse an indexed field with index < 127 */
-static grpc_error *parse_indexed_field(grpc_chttp2_hpack_parser *p,
+static grpc_error *parse_indexed_field(grpc_exec_ctx *exec_ctx,
+                                       grpc_chttp2_hpack_parser *p,
                                        const uint8_t *cur, const uint8_t *end) {
   p->dynamic_table_update_allowed = 0;
   p->index = (*cur) & 0x7f;
-  return finish_indexed_field(p, cur + 1, end);
+  return finish_indexed_field(exec_ctx, p, cur + 1, end);
 }
 
 /* parse an indexed field with index >= 127 */
-static grpc_error *parse_indexed_field_x(grpc_chttp2_hpack_parser *p,
+static grpc_error *parse_indexed_field_x(grpc_exec_ctx *exec_ctx,
+                                         grpc_chttp2_hpack_parser *p,
                                          const uint8_t *cur,
                                          const uint8_t *end) {
   static const grpc_chttp2_hpack_parser_state and_then[] = {
@@ -766,49 +803,53 @@
   p->next_state = and_then;
   p->index = 0x7f;
   p->parsing.value = &p->index;
-  return parse_value0(p, cur + 1, end);
+  return parse_value0(exec_ctx, p, cur + 1, end);
 }
 
 /* finish a literal header with incremental indexing: just log, and jump to '
    begin */
-static grpc_error *finish_lithdr_incidx(grpc_chttp2_hpack_parser *p,
+static grpc_error *finish_lithdr_incidx(grpc_exec_ctx *exec_ctx,
+                                        grpc_chttp2_hpack_parser *p,
                                         const uint8_t *cur,
                                         const uint8_t *end) {
   grpc_mdelem *md = grpc_chttp2_hptbl_lookup(&p->table, p->index);
   GPR_ASSERT(md != NULL); /* handled in string parsing */
-  grpc_error *err =
-      on_hdr(p, grpc_mdelem_from_metadata_strings(GRPC_MDSTR_REF(md->key),
-                                                  take_string(p, &p->value)),
-             1);
-  if (err != GRPC_ERROR_NONE) return parse_error(p, cur, end, err);
-  return parse_begin(p, cur, end);
+  grpc_error *err = on_hdr(
+      exec_ctx, p, grpc_mdelem_from_metadata_strings(GRPC_MDSTR_REF(md->key),
+                                                     take_string(p, &p->value)),
+      1);
+  if (err != GRPC_ERROR_NONE) return parse_error(exec_ctx, p, cur, end, err);
+  return parse_begin(exec_ctx, p, cur, end);
 }
 
 /* finish a literal header with incremental indexing with no index */
-static grpc_error *finish_lithdr_incidx_v(grpc_chttp2_hpack_parser *p,
+static grpc_error *finish_lithdr_incidx_v(grpc_exec_ctx *exec_ctx,
+                                          grpc_chttp2_hpack_parser *p,
                                           const uint8_t *cur,
                                           const uint8_t *end) {
-  grpc_error *err =
-      on_hdr(p, grpc_mdelem_from_metadata_strings(take_string(p, &p->key),
-                                                  take_string(p, &p->value)),
-             1);
-  if (err != GRPC_ERROR_NONE) return parse_error(p, cur, end, err);
-  return parse_begin(p, cur, end);
+  grpc_error *err = on_hdr(
+      exec_ctx, p, grpc_mdelem_from_metadata_strings(take_string(p, &p->key),
+                                                     take_string(p, &p->value)),
+      1);
+  if (err != GRPC_ERROR_NONE) return parse_error(exec_ctx, p, cur, end, err);
+  return parse_begin(exec_ctx, p, cur, end);
 }
 
 /* parse a literal header with incremental indexing; index < 63 */
-static grpc_error *parse_lithdr_incidx(grpc_chttp2_hpack_parser *p,
+static grpc_error *parse_lithdr_incidx(grpc_exec_ctx *exec_ctx,
+                                       grpc_chttp2_hpack_parser *p,
                                        const uint8_t *cur, const uint8_t *end) {
   static const grpc_chttp2_hpack_parser_state and_then[] = {
       parse_value_string_with_indexed_key, finish_lithdr_incidx};
   p->dynamic_table_update_allowed = 0;
   p->next_state = and_then;
   p->index = (*cur) & 0x3f;
-  return parse_string_prefix(p, cur + 1, end);
+  return parse_string_prefix(exec_ctx, p, cur + 1, end);
 }
 
 /* parse a literal header with incremental indexing; index >= 63 */
-static grpc_error *parse_lithdr_incidx_x(grpc_chttp2_hpack_parser *p,
+static grpc_error *parse_lithdr_incidx_x(grpc_exec_ctx *exec_ctx,
+                                         grpc_chttp2_hpack_parser *p,
                                          const uint8_t *cur,
                                          const uint8_t *end) {
   static const grpc_chttp2_hpack_parser_state and_then[] = {
@@ -818,11 +859,12 @@
   p->next_state = and_then;
   p->index = 0x3f;
   p->parsing.value = &p->index;
-  return parse_value0(p, cur + 1, end);
+  return parse_value0(exec_ctx, p, cur + 1, end);
 }
 
 /* parse a literal header with incremental indexing; index = 0 */
-static grpc_error *parse_lithdr_incidx_v(grpc_chttp2_hpack_parser *p,
+static grpc_error *parse_lithdr_incidx_v(grpc_exec_ctx *exec_ctx,
+                                         grpc_chttp2_hpack_parser *p,
                                          const uint8_t *cur,
                                          const uint8_t *end) {
   static const grpc_chttp2_hpack_parser_state and_then[] = {
@@ -830,48 +872,52 @@
       parse_value_string_with_literal_key, finish_lithdr_incidx_v};
   p->dynamic_table_update_allowed = 0;
   p->next_state = and_then;
-  return parse_string_prefix(p, cur + 1, end);
+  return parse_string_prefix(exec_ctx, p, cur + 1, end);
 }
 
 /* finish a literal header without incremental indexing */
-static grpc_error *finish_lithdr_notidx(grpc_chttp2_hpack_parser *p,
+static grpc_error *finish_lithdr_notidx(grpc_exec_ctx *exec_ctx,
+                                        grpc_chttp2_hpack_parser *p,
                                         const uint8_t *cur,
                                         const uint8_t *end) {
   grpc_mdelem *md = grpc_chttp2_hptbl_lookup(&p->table, p->index);
   GPR_ASSERT(md != NULL); /* handled in string parsing */
-  grpc_error *err =
-      on_hdr(p, grpc_mdelem_from_metadata_strings(GRPC_MDSTR_REF(md->key),
-                                                  take_string(p, &p->value)),
-             0);
-  if (err != GRPC_ERROR_NONE) return parse_error(p, cur, end, err);
-  return parse_begin(p, cur, end);
+  grpc_error *err = on_hdr(
+      exec_ctx, p, grpc_mdelem_from_metadata_strings(GRPC_MDSTR_REF(md->key),
+                                                     take_string(p, &p->value)),
+      0);
+  if (err != GRPC_ERROR_NONE) return parse_error(exec_ctx, p, cur, end, err);
+  return parse_begin(exec_ctx, p, cur, end);
 }
 
 /* finish a literal header without incremental indexing with index = 0 */
-static grpc_error *finish_lithdr_notidx_v(grpc_chttp2_hpack_parser *p,
+static grpc_error *finish_lithdr_notidx_v(grpc_exec_ctx *exec_ctx,
+                                          grpc_chttp2_hpack_parser *p,
                                           const uint8_t *cur,
                                           const uint8_t *end) {
-  grpc_error *err =
-      on_hdr(p, grpc_mdelem_from_metadata_strings(take_string(p, &p->key),
-                                                  take_string(p, &p->value)),
-             0);
-  if (err != GRPC_ERROR_NONE) return parse_error(p, cur, end, err);
-  return parse_begin(p, cur, end);
+  grpc_error *err = on_hdr(
+      exec_ctx, p, grpc_mdelem_from_metadata_strings(take_string(p, &p->key),
+                                                     take_string(p, &p->value)),
+      0);
+  if (err != GRPC_ERROR_NONE) return parse_error(exec_ctx, p, cur, end, err);
+  return parse_begin(exec_ctx, p, cur, end);
 }
 
 /* parse a literal header without incremental indexing; index < 15 */
-static grpc_error *parse_lithdr_notidx(grpc_chttp2_hpack_parser *p,
+static grpc_error *parse_lithdr_notidx(grpc_exec_ctx *exec_ctx,
+                                       grpc_chttp2_hpack_parser *p,
                                        const uint8_t *cur, const uint8_t *end) {
   static const grpc_chttp2_hpack_parser_state and_then[] = {
       parse_value_string_with_indexed_key, finish_lithdr_notidx};
   p->dynamic_table_update_allowed = 0;
   p->next_state = and_then;
   p->index = (*cur) & 0xf;
-  return parse_string_prefix(p, cur + 1, end);
+  return parse_string_prefix(exec_ctx, p, cur + 1, end);
 }
 
 /* parse a literal header without incremental indexing; index >= 15 */
-static grpc_error *parse_lithdr_notidx_x(grpc_chttp2_hpack_parser *p,
+static grpc_error *parse_lithdr_notidx_x(grpc_exec_ctx *exec_ctx,
+                                         grpc_chttp2_hpack_parser *p,
                                          const uint8_t *cur,
                                          const uint8_t *end) {
   static const grpc_chttp2_hpack_parser_state and_then[] = {
@@ -881,11 +927,12 @@
   p->next_state = and_then;
   p->index = 0xf;
   p->parsing.value = &p->index;
-  return parse_value0(p, cur + 1, end);
+  return parse_value0(exec_ctx, p, cur + 1, end);
 }
 
 /* parse a literal header without incremental indexing; index == 0 */
-static grpc_error *parse_lithdr_notidx_v(grpc_chttp2_hpack_parser *p,
+static grpc_error *parse_lithdr_notidx_v(grpc_exec_ctx *exec_ctx,
+                                         grpc_chttp2_hpack_parser *p,
                                          const uint8_t *cur,
                                          const uint8_t *end) {
   static const grpc_chttp2_hpack_parser_state and_then[] = {
@@ -893,48 +940,52 @@
       parse_value_string_with_literal_key, finish_lithdr_notidx_v};
   p->dynamic_table_update_allowed = 0;
   p->next_state = and_then;
-  return parse_string_prefix(p, cur + 1, end);
+  return parse_string_prefix(exec_ctx, p, cur + 1, end);
 }
 
 /* finish a literal header that is never indexed */
-static grpc_error *finish_lithdr_nvridx(grpc_chttp2_hpack_parser *p,
+static grpc_error *finish_lithdr_nvridx(grpc_exec_ctx *exec_ctx,
+                                        grpc_chttp2_hpack_parser *p,
                                         const uint8_t *cur,
                                         const uint8_t *end) {
   grpc_mdelem *md = grpc_chttp2_hptbl_lookup(&p->table, p->index);
   GPR_ASSERT(md != NULL); /* handled in string parsing */
-  grpc_error *err =
-      on_hdr(p, grpc_mdelem_from_metadata_strings(GRPC_MDSTR_REF(md->key),
-                                                  take_string(p, &p->value)),
-             0);
-  if (err != GRPC_ERROR_NONE) return parse_error(p, cur, end, err);
-  return parse_begin(p, cur, end);
+  grpc_error *err = on_hdr(
+      exec_ctx, p, grpc_mdelem_from_metadata_strings(GRPC_MDSTR_REF(md->key),
+                                                     take_string(p, &p->value)),
+      0);
+  if (err != GRPC_ERROR_NONE) return parse_error(exec_ctx, p, cur, end, err);
+  return parse_begin(exec_ctx, p, cur, end);
 }
 
 /* finish a literal header that is never indexed with an extra value */
-static grpc_error *finish_lithdr_nvridx_v(grpc_chttp2_hpack_parser *p,
+static grpc_error *finish_lithdr_nvridx_v(grpc_exec_ctx *exec_ctx,
+                                          grpc_chttp2_hpack_parser *p,
                                           const uint8_t *cur,
                                           const uint8_t *end) {
-  grpc_error *err =
-      on_hdr(p, grpc_mdelem_from_metadata_strings(take_string(p, &p->key),
-                                                  take_string(p, &p->value)),
-             0);
-  if (err != GRPC_ERROR_NONE) return parse_error(p, cur, end, err);
-  return parse_begin(p, cur, end);
+  grpc_error *err = on_hdr(
+      exec_ctx, p, grpc_mdelem_from_metadata_strings(take_string(p, &p->key),
+                                                     take_string(p, &p->value)),
+      0);
+  if (err != GRPC_ERROR_NONE) return parse_error(exec_ctx, p, cur, end, err);
+  return parse_begin(exec_ctx, p, cur, end);
 }
 
 /* parse a literal header that is never indexed; index < 15 */
-static grpc_error *parse_lithdr_nvridx(grpc_chttp2_hpack_parser *p,
+static grpc_error *parse_lithdr_nvridx(grpc_exec_ctx *exec_ctx,
+                                       grpc_chttp2_hpack_parser *p,
                                        const uint8_t *cur, const uint8_t *end) {
   static const grpc_chttp2_hpack_parser_state and_then[] = {
       parse_value_string_with_indexed_key, finish_lithdr_nvridx};
   p->dynamic_table_update_allowed = 0;
   p->next_state = and_then;
   p->index = (*cur) & 0xf;
-  return parse_string_prefix(p, cur + 1, end);
+  return parse_string_prefix(exec_ctx, p, cur + 1, end);
 }
 
 /* parse a literal header that is never indexed; index >= 15 */
-static grpc_error *parse_lithdr_nvridx_x(grpc_chttp2_hpack_parser *p,
+static grpc_error *parse_lithdr_nvridx_x(grpc_exec_ctx *exec_ctx,
+                                         grpc_chttp2_hpack_parser *p,
                                          const uint8_t *cur,
                                          const uint8_t *end) {
   static const grpc_chttp2_hpack_parser_state and_then[] = {
@@ -944,11 +995,12 @@
   p->next_state = and_then;
   p->index = 0xf;
   p->parsing.value = &p->index;
-  return parse_value0(p, cur + 1, end);
+  return parse_value0(exec_ctx, p, cur + 1, end);
 }
 
 /* parse a literal header that is never indexed; index == 0 */
-static grpc_error *parse_lithdr_nvridx_v(grpc_chttp2_hpack_parser *p,
+static grpc_error *parse_lithdr_nvridx_v(grpc_exec_ctx *exec_ctx,
+                                         grpc_chttp2_hpack_parser *p,
                                          const uint8_t *cur,
                                          const uint8_t *end) {
   static const grpc_chttp2_hpack_parser_state and_then[] = {
@@ -956,44 +1008,47 @@
       parse_value_string_with_literal_key, finish_lithdr_nvridx_v};
   p->dynamic_table_update_allowed = 0;
   p->next_state = and_then;
-  return parse_string_prefix(p, cur + 1, end);
+  return parse_string_prefix(exec_ctx, p, cur + 1, end);
 }
 
 /* finish parsing a max table size change */
-static grpc_error *finish_max_tbl_size(grpc_chttp2_hpack_parser *p,
+static grpc_error *finish_max_tbl_size(grpc_exec_ctx *exec_ctx,
+                                       grpc_chttp2_hpack_parser *p,
                                        const uint8_t *cur, const uint8_t *end) {
   if (grpc_http_trace) {
     gpr_log(GPR_INFO, "MAX TABLE SIZE: %d", p->index);
   }
   grpc_error *err =
       grpc_chttp2_hptbl_set_current_table_size(&p->table, p->index);
-  if (err != GRPC_ERROR_NONE) return parse_error(p, cur, end, err);
-  return parse_begin(p, cur, end);
+  if (err != GRPC_ERROR_NONE) return parse_error(exec_ctx, p, cur, end, err);
+  return parse_begin(exec_ctx, p, cur, end);
 }
 
 /* parse a max table size change, max size < 15 */
-static grpc_error *parse_max_tbl_size(grpc_chttp2_hpack_parser *p,
+static grpc_error *parse_max_tbl_size(grpc_exec_ctx *exec_ctx,
+                                      grpc_chttp2_hpack_parser *p,
                                       const uint8_t *cur, const uint8_t *end) {
   if (p->dynamic_table_update_allowed == 0) {
     return parse_error(
-        p, cur, end,
+        exec_ctx, p, cur, end,
         GRPC_ERROR_CREATE(
             "More than two max table size changes in a single frame"));
   }
   p->dynamic_table_update_allowed--;
   p->index = (*cur) & 0x1f;
-  return finish_max_tbl_size(p, cur + 1, end);
+  return finish_max_tbl_size(exec_ctx, p, cur + 1, end);
 }
 
 /* parse a max table size change, max size >= 15 */
-static grpc_error *parse_max_tbl_size_x(grpc_chttp2_hpack_parser *p,
+static grpc_error *parse_max_tbl_size_x(grpc_exec_ctx *exec_ctx,
+                                        grpc_chttp2_hpack_parser *p,
                                         const uint8_t *cur,
                                         const uint8_t *end) {
   static const grpc_chttp2_hpack_parser_state and_then[] = {
       finish_max_tbl_size};
   if (p->dynamic_table_update_allowed == 0) {
     return parse_error(
-        p, cur, end,
+        exec_ctx, p, cur, end,
         GRPC_ERROR_CREATE(
             "More than two max table size changes in a single frame"));
   }
@@ -1001,11 +1056,12 @@
   p->next_state = and_then;
   p->index = 0x1f;
   p->parsing.value = &p->index;
-  return parse_value0(p, cur + 1, end);
+  return parse_value0(exec_ctx, p, cur + 1, end);
 }
 
 /* a parse error: jam the parse state into parse_error, and return error */
-static grpc_error *parse_error(grpc_chttp2_hpack_parser *p, const uint8_t *cur,
+static grpc_error *parse_error(grpc_exec_ctx *exec_ctx,
+                               grpc_chttp2_hpack_parser *p, const uint8_t *cur,
                                const uint8_t *end, grpc_error *err) {
   GPR_ASSERT(err != GRPC_ERROR_NONE);
   if (p->last_error == GRPC_ERROR_NONE) {
@@ -1015,24 +1071,27 @@
   return err;
 }
 
-static grpc_error *still_parse_error(grpc_chttp2_hpack_parser *p,
+static grpc_error *still_parse_error(grpc_exec_ctx *exec_ctx,
+                                     grpc_chttp2_hpack_parser *p,
                                      const uint8_t *cur, const uint8_t *end) {
   return GRPC_ERROR_REF(p->last_error);
 }
 
-static grpc_error *parse_illegal_op(grpc_chttp2_hpack_parser *p,
+static grpc_error *parse_illegal_op(grpc_exec_ctx *exec_ctx,
+                                    grpc_chttp2_hpack_parser *p,
                                     const uint8_t *cur, const uint8_t *end) {
   GPR_ASSERT(cur != end);
   char *msg;
   gpr_asprintf(&msg, "Illegal hpack op code %d", *cur);
   grpc_error *err = GRPC_ERROR_CREATE(msg);
   gpr_free(msg);
-  return parse_error(p, cur, end, err);
+  return parse_error(exec_ctx, p, cur, end, err);
 }
 
 /* parse the 1st byte of a varint into p->parsing.value
    no overflow is possible */
-static grpc_error *parse_value0(grpc_chttp2_hpack_parser *p, const uint8_t *cur,
+static grpc_error *parse_value0(grpc_exec_ctx *exec_ctx,
+                                grpc_chttp2_hpack_parser *p, const uint8_t *cur,
                                 const uint8_t *end) {
   if (cur == end) {
     p->state = parse_value0;
@@ -1042,15 +1101,16 @@
   *p->parsing.value += (*cur) & 0x7f;
 
   if ((*cur) & 0x80) {
-    return parse_value1(p, cur + 1, end);
+    return parse_value1(exec_ctx, p, cur + 1, end);
   } else {
-    return parse_next(p, cur + 1, end);
+    return parse_next(exec_ctx, p, cur + 1, end);
   }
 }
 
 /* parse the 2nd byte of a varint into p->parsing.value
    no overflow is possible */
-static grpc_error *parse_value1(grpc_chttp2_hpack_parser *p, const uint8_t *cur,
+static grpc_error *parse_value1(grpc_exec_ctx *exec_ctx,
+                                grpc_chttp2_hpack_parser *p, const uint8_t *cur,
                                 const uint8_t *end) {
   if (cur == end) {
     p->state = parse_value1;
@@ -1060,15 +1120,16 @@
   *p->parsing.value += (((uint32_t)*cur) & 0x7f) << 7;
 
   if ((*cur) & 0x80) {
-    return parse_value2(p, cur + 1, end);
+    return parse_value2(exec_ctx, p, cur + 1, end);
   } else {
-    return parse_next(p, cur + 1, end);
+    return parse_next(exec_ctx, p, cur + 1, end);
   }
 }
 
 /* parse the 3rd byte of a varint into p->parsing.value
    no overflow is possible */
-static grpc_error *parse_value2(grpc_chttp2_hpack_parser *p, const uint8_t *cur,
+static grpc_error *parse_value2(grpc_exec_ctx *exec_ctx,
+                                grpc_chttp2_hpack_parser *p, const uint8_t *cur,
                                 const uint8_t *end) {
   if (cur == end) {
     p->state = parse_value2;
@@ -1078,15 +1139,16 @@
   *p->parsing.value += (((uint32_t)*cur) & 0x7f) << 14;
 
   if ((*cur) & 0x80) {
-    return parse_value3(p, cur + 1, end);
+    return parse_value3(exec_ctx, p, cur + 1, end);
   } else {
-    return parse_next(p, cur + 1, end);
+    return parse_next(exec_ctx, p, cur + 1, end);
   }
 }
 
 /* parse the 4th byte of a varint into p->parsing.value
    no overflow is possible */
-static grpc_error *parse_value3(grpc_chttp2_hpack_parser *p, const uint8_t *cur,
+static grpc_error *parse_value3(grpc_exec_ctx *exec_ctx,
+                                grpc_chttp2_hpack_parser *p, const uint8_t *cur,
                                 const uint8_t *end) {
   if (cur == end) {
     p->state = parse_value3;
@@ -1096,15 +1158,16 @@
   *p->parsing.value += (((uint32_t)*cur) & 0x7f) << 21;
 
   if ((*cur) & 0x80) {
-    return parse_value4(p, cur + 1, end);
+    return parse_value4(exec_ctx, p, cur + 1, end);
   } else {
-    return parse_next(p, cur + 1, end);
+    return parse_next(exec_ctx, p, cur + 1, end);
   }
 }
 
 /* parse the 5th byte of a varint into p->parsing.value
    depending on the byte, we may overflow, and care must be taken */
-static grpc_error *parse_value4(grpc_chttp2_hpack_parser *p, const uint8_t *cur,
+static grpc_error *parse_value4(grpc_exec_ctx *exec_ctx,
+                                grpc_chttp2_hpack_parser *p, const uint8_t *cur,
                                 const uint8_t *end) {
   uint8_t c;
   uint32_t cur_value;
@@ -1130,9 +1193,9 @@
   *p->parsing.value = cur_value + add_value;
 
   if ((*cur) & 0x80) {
-    return parse_value5up(p, cur + 1, end);
+    return parse_value5up(exec_ctx, p, cur + 1, end);
   } else {
-    return parse_next(p, cur + 1, end);
+    return parse_next(exec_ctx, p, cur + 1, end);
   }
 
 error:
@@ -1142,13 +1205,14 @@
                *p->parsing.value, *cur);
   grpc_error *err = GRPC_ERROR_CREATE(msg);
   gpr_free(msg);
-  return parse_error(p, cur, end, err);
+  return parse_error(exec_ctx, p, cur, end, err);
 }
 
 /* parse any trailing bytes in a varint: it's possible to append an arbitrary
    number of 0x80's and not affect the value - a zero will terminate - and
    anything else will overflow */
-static grpc_error *parse_value5up(grpc_chttp2_hpack_parser *p,
+static grpc_error *parse_value5up(grpc_exec_ctx *exec_ctx,
+                                  grpc_chttp2_hpack_parser *p,
                                   const uint8_t *cur, const uint8_t *end) {
   while (cur != end && *cur == 0x80) {
     ++cur;
@@ -1160,7 +1224,7 @@
   }
 
   if (*cur == 0) {
-    return parse_next(p, cur + 1, end);
+    return parse_next(exec_ctx, p, cur + 1, end);
   }
 
   char *msg;
@@ -1170,11 +1234,12 @@
                *p->parsing.value, *cur);
   grpc_error *err = GRPC_ERROR_CREATE(msg);
   gpr_free(msg);
-  return parse_error(p, cur, end, err);
+  return parse_error(exec_ctx, p, cur, end, err);
 }
 
 /* parse a string prefix */
-static grpc_error *parse_string_prefix(grpc_chttp2_hpack_parser *p,
+static grpc_error *parse_string_prefix(grpc_exec_ctx *exec_ctx,
+                                       grpc_chttp2_hpack_parser *p,
                                        const uint8_t *cur, const uint8_t *end) {
   if (cur == end) {
     p->state = parse_string_prefix;
@@ -1185,9 +1250,9 @@
   p->huff = (*cur) >> 7;
   if (p->strlen == 0x7f) {
     p->parsing.value = &p->strlen;
-    return parse_value0(p, cur + 1, end);
+    return parse_value0(exec_ctx, p, cur + 1, end);
   } else {
-    return parse_next(p, cur + 1, end);
+    return parse_next(exec_ctx, p, cur + 1, end);
   }
 }
 
@@ -1205,7 +1270,8 @@
   str->length += (uint32_t)length;
 }
 
-static grpc_error *append_string(grpc_chttp2_hpack_parser *p,
+static grpc_error *append_string(grpc_exec_ctx *exec_ctx,
+                                 grpc_chttp2_hpack_parser *p,
                                  const uint8_t *cur, const uint8_t *end) {
   grpc_chttp2_hpack_parser_string *str = p->parsing.str;
   uint32_t bits;
@@ -1223,7 +1289,7 @@
       bits = inverse_base64[*cur];
       ++cur;
       if (bits == 255)
-        return parse_error(p, cur, end,
+        return parse_error(exec_ctx, p, cur, end,
                            GRPC_ERROR_CREATE("Illegal base64 character"));
       else if (bits == 64)
         goto b64_byte0;
@@ -1238,7 +1304,7 @@
       bits = inverse_base64[*cur];
       ++cur;
       if (bits == 255)
-        return parse_error(p, cur, end,
+        return parse_error(exec_ctx, p, cur, end,
                            GRPC_ERROR_CREATE("Illegal base64 character"));
       else if (bits == 64)
         goto b64_byte1;
@@ -1253,7 +1319,7 @@
       bits = inverse_base64[*cur];
       ++cur;
       if (bits == 255)
-        return parse_error(p, cur, end,
+        return parse_error(exec_ctx, p, cur, end,
                            GRPC_ERROR_CREATE("Illegal base64 character"));
       else if (bits == 64)
         goto b64_byte2;
@@ -1268,7 +1334,7 @@
       bits = inverse_base64[*cur];
       ++cur;
       if (bits == 255)
-        return parse_error(p, cur, end,
+        return parse_error(exec_ctx, p, cur, end,
                            GRPC_ERROR_CREATE("Illegal base64 character"));
       else if (bits == 64)
         goto b64_byte3;
@@ -1281,11 +1347,12 @@
       goto b64_byte0;
   }
   GPR_UNREACHABLE_CODE(return parse_error(
-      p, cur, end, GRPC_ERROR_CREATE("Should never reach here")));
+      exec_ctx, p, cur, end, GRPC_ERROR_CREATE("Should never reach here")));
 }
 
 /* append a null terminator to a string */
-static grpc_error *finish_str(grpc_chttp2_hpack_parser *p, const uint8_t *cur,
+static grpc_error *finish_str(grpc_exec_ctx *exec_ctx,
+                              grpc_chttp2_hpack_parser *p, const uint8_t *cur,
                               const uint8_t *end) {
   uint8_t terminator = 0;
   uint8_t decoded[2];
@@ -1298,7 +1365,7 @@
       break;
     case B64_BYTE1:
       return parse_error(
-          p, cur, end,
+          exec_ctx, p, cur, end,
           GRPC_ERROR_CREATE("illegal base64 encoding")); /* illegal encoding */
     case B64_BYTE2:
       bits = p->base64_buffer;
@@ -1308,7 +1375,7 @@
                      bits & 0xffff);
         grpc_error *err = GRPC_ERROR_CREATE(msg);
         gpr_free(msg);
-        return parse_error(p, cur, end, err);
+        return parse_error(exec_ctx, p, cur, end, err);
       }
       decoded[0] = (uint8_t)(bits >> 16);
       append_bytes(str, decoded, 1);
@@ -1321,7 +1388,7 @@
                      bits & 0xff);
         grpc_error *err = GRPC_ERROR_CREATE(msg);
         gpr_free(msg);
-        return parse_error(p, cur, end, err);
+        return parse_error(exec_ctx, p, cur, end, err);
       }
       decoded[0] = (uint8_t)(bits >> 16);
       decoded[1] = (uint8_t)(bits >> 8);
@@ -1334,13 +1401,14 @@
 }
 
 /* decode a nibble from a huffman encoded stream */
-static grpc_error *huff_nibble(grpc_chttp2_hpack_parser *p, uint8_t nibble) {
+static grpc_error *huff_nibble(grpc_exec_ctx *exec_ctx,
+                               grpc_chttp2_hpack_parser *p, uint8_t nibble) {
   int16_t emit = emit_sub_tbl[16 * emit_tbl[p->huff_state] + nibble];
   int16_t next = next_sub_tbl[16 * next_tbl[p->huff_state] + nibble];
   if (emit != -1) {
     if (emit >= 0 && emit < 256) {
       uint8_t c = (uint8_t)emit;
-      grpc_error *err = append_string(p, &c, (&c) + 1);
+      grpc_error *err = append_string(exec_ctx, p, &c, (&c) + 1);
       if (err != GRPC_ERROR_NONE) return err;
     } else {
       assert(emit == 256);
@@ -1351,42 +1419,45 @@
 }
 
 /* decode full bytes from a huffman encoded stream */
-static grpc_error *add_huff_bytes(grpc_chttp2_hpack_parser *p,
+static grpc_error *add_huff_bytes(grpc_exec_ctx *exec_ctx,
+                                  grpc_chttp2_hpack_parser *p,
                                   const uint8_t *cur, const uint8_t *end) {
   for (; cur != end; ++cur) {
-    grpc_error *err = huff_nibble(p, *cur >> 4);
-    if (err != GRPC_ERROR_NONE) return parse_error(p, cur, end, err);
-    err = huff_nibble(p, *cur & 0xf);
-    if (err != GRPC_ERROR_NONE) return parse_error(p, cur, end, err);
+    grpc_error *err = huff_nibble(exec_ctx, p, *cur >> 4);
+    if (err != GRPC_ERROR_NONE) return parse_error(exec_ctx, p, cur, end, err);
+    err = huff_nibble(exec_ctx, p, *cur & 0xf);
+    if (err != GRPC_ERROR_NONE) return parse_error(exec_ctx, p, cur, end, err);
   }
   return GRPC_ERROR_NONE;
 }
 
 /* decode some string bytes based on the current decoding mode
    (huffman or not) */
-static grpc_error *add_str_bytes(grpc_chttp2_hpack_parser *p,
+static grpc_error *add_str_bytes(grpc_exec_ctx *exec_ctx,
+                                 grpc_chttp2_hpack_parser *p,
                                  const uint8_t *cur, const uint8_t *end) {
   if (p->huff) {
-    return add_huff_bytes(p, cur, end);
+    return add_huff_bytes(exec_ctx, p, cur, end);
   } else {
-    return append_string(p, cur, end);
+    return append_string(exec_ctx, p, cur, end);
   }
 }
 
 /* parse a string - tries to do large chunks at a time */
-static grpc_error *parse_string(grpc_chttp2_hpack_parser *p, const uint8_t *cur,
+static grpc_error *parse_string(grpc_exec_ctx *exec_ctx,
+                                grpc_chttp2_hpack_parser *p, const uint8_t *cur,
                                 const uint8_t *end) {
   size_t remaining = p->strlen - p->strgot;
   size_t given = (size_t)(end - cur);
   if (remaining <= given) {
-    grpc_error *err = add_str_bytes(p, cur, cur + remaining);
-    if (err != GRPC_ERROR_NONE) return parse_error(p, cur, end, err);
-    err = finish_str(p, cur + remaining, end);
-    if (err != GRPC_ERROR_NONE) return parse_error(p, cur, end, err);
-    return parse_next(p, cur + remaining, end);
+    grpc_error *err = add_str_bytes(exec_ctx, p, cur, cur + remaining);
+    if (err != GRPC_ERROR_NONE) return parse_error(exec_ctx, p, cur, end, err);
+    err = finish_str(exec_ctx, p, cur + remaining, end);
+    if (err != GRPC_ERROR_NONE) return parse_error(exec_ctx, p, cur, end, err);
+    return parse_next(exec_ctx, p, cur + remaining, end);
   } else {
-    grpc_error *err = add_str_bytes(p, cur, cur + given);
-    if (err != GRPC_ERROR_NONE) return parse_error(p, cur, end, err);
+    grpc_error *err = add_str_bytes(exec_ctx, p, cur, cur + given);
+    if (err != GRPC_ERROR_NONE) return parse_error(exec_ctx, p, cur, end, err);
     GPR_ASSERT(given <= UINT32_MAX - p->strgot);
     p->strgot += (uint32_t)given;
     p->state = parse_string;
@@ -1395,7 +1466,8 @@
 }
 
 /* begin parsing a string - performs setup, calls parse_string */
-static grpc_error *begin_parse_string(grpc_chttp2_hpack_parser *p,
+static grpc_error *begin_parse_string(grpc_exec_ctx *exec_ctx,
+                                      grpc_chttp2_hpack_parser *p,
                                       const uint8_t *cur, const uint8_t *end,
                                       uint8_t binary,
                                       grpc_chttp2_hpack_parser_string *str) {
@@ -1404,13 +1476,14 @@
   p->parsing.str = str;
   p->huff_state = 0;
   p->binary = binary;
-  return parse_string(p, cur, end);
+  return parse_string(exec_ctx, p, cur, end);
 }
 
 /* parse the key string */
-static grpc_error *parse_key_string(grpc_chttp2_hpack_parser *p,
+static grpc_error *parse_key_string(grpc_exec_ctx *exec_ctx,
+                                    grpc_chttp2_hpack_parser *p,
                                     const uint8_t *cur, const uint8_t *end) {
-  return begin_parse_string(p, cur, end, NOT_BINARY, &p->key);
+  return begin_parse_string(exec_ctx, p, cur, end, NOT_BINARY, &p->key);
 }
 
 /* check if a key represents a binary header or not */
@@ -1435,24 +1508,27 @@
 }
 
 /* parse the value string */
-static grpc_error *parse_value_string(grpc_chttp2_hpack_parser *p,
+static grpc_error *parse_value_string(grpc_exec_ctx *exec_ctx,
+                                      grpc_chttp2_hpack_parser *p,
                                       const uint8_t *cur, const uint8_t *end,
                                       bool is_binary) {
-  return begin_parse_string(p, cur, end, is_binary ? B64_BYTE0 : NOT_BINARY,
-                            &p->value);
+  return begin_parse_string(exec_ctx, p, cur, end,
+                            is_binary ? B64_BYTE0 : NOT_BINARY, &p->value);
 }
 
 static grpc_error *parse_value_string_with_indexed_key(
-    grpc_chttp2_hpack_parser *p, const uint8_t *cur, const uint8_t *end) {
+    grpc_exec_ctx *exec_ctx, grpc_chttp2_hpack_parser *p, const uint8_t *cur,
+    const uint8_t *end) {
   bool is_binary = false;
   grpc_error *err = is_binary_indexed_header(p, &is_binary);
-  if (err != GRPC_ERROR_NONE) return parse_error(p, cur, end, err);
-  return parse_value_string(p, cur, end, is_binary);
+  if (err != GRPC_ERROR_NONE) return parse_error(exec_ctx, p, cur, end, err);
+  return parse_value_string(exec_ctx, p, cur, end, is_binary);
 }
 
 static grpc_error *parse_value_string_with_literal_key(
-    grpc_chttp2_hpack_parser *p, const uint8_t *cur, const uint8_t *end) {
-  return parse_value_string(p, cur, end, is_binary_literal_header(p));
+    grpc_exec_ctx *exec_ctx, grpc_chttp2_hpack_parser *p, const uint8_t *cur,
+    const uint8_t *end) {
+  return parse_value_string(exec_ctx, p, cur, end, is_binary_literal_header(p));
 }
 
 /* PUBLIC INTERFACE */
@@ -1484,27 +1560,36 @@
   gpr_free(p->value.str);
 }
 
-grpc_error *grpc_chttp2_hpack_parser_parse(grpc_chttp2_hpack_parser *p,
+grpc_error *grpc_chttp2_hpack_parser_parse(grpc_exec_ctx *exec_ctx,
+                                           grpc_chttp2_hpack_parser *p,
                                            const uint8_t *beg,
                                            const uint8_t *end) {
   /* TODO(ctiller): limit the distance of end from beg, and perform multiple
      steps in the event of a large chunk of data to limit
      stack space usage when no tail call optimization is
      available */
-  return p->state(p, beg, end);
+  return p->state(exec_ctx, p, beg, end);
 }
 
-grpc_error *grpc_chttp2_header_parser_parse(
-    grpc_exec_ctx *exec_ctx, void *hpack_parser,
-    grpc_chttp2_transport_parsing *transport_parsing,
-    grpc_chttp2_stream_parsing *stream_parsing, gpr_slice slice, int is_last) {
+typedef void (*maybe_complete_func_type)(grpc_exec_ctx *exec_ctx,
+                                         grpc_chttp2_transport *t,
+                                         grpc_chttp2_stream *s);
+static const maybe_complete_func_type maybe_complete_funcs[] = {
+    grpc_chttp2_maybe_complete_recv_initial_metadata,
+    grpc_chttp2_maybe_complete_recv_trailing_metadata};
+
+grpc_error *grpc_chttp2_header_parser_parse(grpc_exec_ctx *exec_ctx,
+                                            void *hpack_parser,
+                                            grpc_chttp2_transport *t,
+                                            grpc_chttp2_stream *s,
+                                            gpr_slice slice, int is_last) {
   grpc_chttp2_hpack_parser *parser = hpack_parser;
   GPR_TIMER_BEGIN("grpc_chttp2_hpack_parser_parse", 0);
-  if (stream_parsing != NULL) {
-    stream_parsing->stats.incoming.header_bytes += GPR_SLICE_LENGTH(slice);
+  if (s != NULL) {
+    s->stats.incoming.header_bytes += GPR_SLICE_LENGTH(slice);
   }
   grpc_error *error = grpc_chttp2_hpack_parser_parse(
-      parser, GPR_SLICE_START_PTR(slice), GPR_SLICE_END_PTR(slice));
+      exec_ctx, parser, GPR_SLICE_START_PTR(slice), GPR_SLICE_END_PTR(slice));
   if (error != GRPC_ERROR_NONE) {
     GPR_TIMER_END("grpc_chttp2_hpack_parser_parse", 0);
     return error;
@@ -1517,20 +1602,19 @@
     }
     /* need to check for null stream: this can occur if we receive an invalid
        stream id on a header */
-    if (stream_parsing != NULL) {
+    if (s != NULL) {
       if (parser->is_boundary) {
-        if (stream_parsing->header_frames_received ==
-            GPR_ARRAY_SIZE(stream_parsing->got_metadata_on_parse)) {
+        if (s->header_frames_received == GPR_ARRAY_SIZE(s->metadata_buffer)) {
           return GRPC_ERROR_CREATE("Too many trailer frames");
         }
-        stream_parsing
-            ->got_metadata_on_parse[stream_parsing->header_frames_received] = 1;
-        stream_parsing->header_frames_received++;
-        grpc_chttp2_list_add_parsing_seen_stream(transport_parsing,
-                                                 stream_parsing);
+        s->published_metadata[s->header_frames_received] =
+            GRPC_METADATA_PUBLISHED_FROM_WIRE;
+        maybe_complete_funcs[s->header_frames_received](exec_ctx, t, s);
+        s->header_frames_received++;
       }
       if (parser->is_eof) {
-        stream_parsing->received_close = 1;
+        grpc_chttp2_mark_stream_closed(exec_ctx, t, s, true, false,
+                                       GRPC_ERROR_NONE);
       }
     }
     parser->on_header = NULL;
diff --git a/src/core/ext/transport/chttp2/transport/hpack_parser.h b/src/core/ext/transport/chttp2/transport/hpack_parser.h
index 78eb38d..0290c78 100644
--- a/src/core/ext/transport/chttp2/transport/hpack_parser.h
+++ b/src/core/ext/transport/chttp2/transport/hpack_parser.h
@@ -45,7 +45,8 @@
 typedef struct grpc_chttp2_hpack_parser grpc_chttp2_hpack_parser;
 
 typedef grpc_error *(*grpc_chttp2_hpack_parser_state)(
-    grpc_chttp2_hpack_parser *p, const uint8_t *beg, const uint8_t *end);
+    grpc_exec_ctx *exec_ctx, grpc_chttp2_hpack_parser *p, const uint8_t *beg,
+    const uint8_t *end);
 
 typedef struct {
   char *str;
@@ -55,7 +56,7 @@
 
 struct grpc_chttp2_hpack_parser {
   /* user specified callback for each header output */
-  void (*on_header)(void *user_data, grpc_mdelem *md);
+  void (*on_header)(grpc_exec_ctx *exec_ctx, void *user_data, grpc_mdelem *md);
   void *on_header_user_data;
 
   grpc_error *last_error;
@@ -104,15 +105,17 @@
 void grpc_chttp2_hpack_parser_set_has_priority(grpc_chttp2_hpack_parser *p);
 
 /* returns 1 on success, 0 on error */
-grpc_error *grpc_chttp2_hpack_parser_parse(grpc_chttp2_hpack_parser *p,
+grpc_error *grpc_chttp2_hpack_parser_parse(grpc_exec_ctx *exec_ctx,
+                                           grpc_chttp2_hpack_parser *p,
                                            const uint8_t *beg,
                                            const uint8_t *end);
 
 /* wraps grpc_chttp2_hpack_parser_parse to provide a frame level parser for
    the transport */
-grpc_error *grpc_chttp2_header_parser_parse(
-    grpc_exec_ctx *exec_ctx, void *hpack_parser,
-    grpc_chttp2_transport_parsing *transport_parsing,
-    grpc_chttp2_stream_parsing *stream_parsing, gpr_slice slice, int is_last);
+grpc_error *grpc_chttp2_header_parser_parse(grpc_exec_ctx *exec_ctx,
+                                            void *hpack_parser,
+                                            grpc_chttp2_transport *t,
+                                            grpc_chttp2_stream *s,
+                                            gpr_slice slice, int is_last);
 
 #endif /* GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_HPACK_PARSER_H */
diff --git a/src/core/ext/transport/chttp2/transport/internal.h b/src/core/ext/transport/chttp2/transport/internal.h
index e1dcf52..6b3e2ed 100644
--- a/src/core/ext/transport/chttp2/transport/internal.h
+++ b/src/core/ext/transport/chttp2/transport/internal.h
@@ -48,35 +48,30 @@
 #include "src/core/ext/transport/chttp2/transport/hpack_parser.h"
 #include "src/core/ext/transport/chttp2/transport/incoming_metadata.h"
 #include "src/core/ext/transport/chttp2/transport/stream_map.h"
+#include "src/core/lib/iomgr/combiner.h"
 #include "src/core/lib/iomgr/endpoint.h"
 #include "src/core/lib/transport/connectivity_state.h"
 #include "src/core/lib/transport/transport_impl.h"
 
-typedef struct grpc_chttp2_transport grpc_chttp2_transport;
-typedef struct grpc_chttp2_stream grpc_chttp2_stream;
-
 /* streams are kept in various linked lists depending on what things need to
    happen to them... this enum labels each list */
 typedef enum {
-  GRPC_CHTTP2_LIST_ALL_STREAMS,
-  GRPC_CHTTP2_LIST_CHECK_READ_OPS,
-  GRPC_CHTTP2_LIST_UNANNOUNCED_INCOMING_WINDOW_AVAILABLE,
   GRPC_CHTTP2_LIST_WRITABLE,
   GRPC_CHTTP2_LIST_WRITING,
-  GRPC_CHTTP2_LIST_WRITTEN,
-  GRPC_CHTTP2_LIST_PARSING_SEEN,
-  GRPC_CHTTP2_LIST_CLOSED_WAITING_FOR_PARSING,
-  GRPC_CHTTP2_LIST_CLOSED_WAITING_FOR_WRITING,
   GRPC_CHTTP2_LIST_STALLED_BY_TRANSPORT,
-  /* streams waiting for the outgoing window in the writing path, they will be
-   * merged to the stalled list or writable list under transport lock. */
-  GRPC_CHTTP2_LIST_WRITING_STALLED_BY_TRANSPORT,
   /** streams that are waiting to start because there are too many concurrent
       streams on the connection */
   GRPC_CHTTP2_LIST_WAITING_FOR_CONCURRENCY,
   STREAM_LIST_COUNT /* must be last */
 } grpc_chttp2_stream_list_id;
 
+typedef enum {
+  GRPC_CHTTP2_WRITE_STATE_IDLE,
+  GRPC_CHTTP2_WRITE_STATE_WRITING,
+  GRPC_CHTTP2_WRITE_STATE_WRITING_WITH_MORE,
+  GRPC_CHTTP2_WRITE_STATE_WRITING_WITH_MORE_AND_COVERED_BY_POLLER,
+} grpc_chttp2_write_state;
+
 /* deframer state for the overall http2 stream of bytes */
 typedef enum {
   /* prefix: one entry per http2 connection prefix byte */
@@ -151,6 +146,12 @@
   struct grpc_chttp2_outstanding_ping *prev;
 } grpc_chttp2_outstanding_ping;
 
+typedef struct grpc_chttp2_write_cb {
+  size_t call_at_byte;
+  grpc_closure *closure;
+  struct grpc_chttp2_write_cb *next;
+} grpc_chttp2_write_cb;
+
 /* forward declared in frame_data.h */
 struct grpc_chttp2_incoming_byte_stream {
   grpc_byte_stream base;
@@ -160,18 +161,86 @@
 
   grpc_chttp2_transport *transport;
   grpc_chttp2_stream *stream;
-  int is_tail;
+  bool is_tail;
+
+  gpr_mu slice_mu;  // protects slices, on_next
   gpr_slice_buffer slices;
   grpc_closure *on_next;
   gpr_slice *next;
+  uint32_t remaining_bytes;
+
+  struct {
+    grpc_closure closure;
+    gpr_slice *slice;
+    size_t max_size_hint;
+    grpc_closure *on_complete;
+  } next_action;
+  grpc_closure destroy_action;
+  grpc_closure finished_action;
 };
 
-typedef struct {
+struct grpc_chttp2_transport {
+  grpc_transport base; /* must be first */
+  gpr_refcount refs;
+  grpc_endpoint *ep;
+  char *peer_string;
+
+  grpc_combiner *combiner;
+
+  /** write execution state of the transport */
+  grpc_chttp2_write_state write_state;
+
+  /** is the transport destroying itself? */
+  uint8_t destroying;
+  /** has the upper layer closed the transport? */
+  uint8_t closed;
+
+  /** is there a read request to the endpoint outstanding? */
+  uint8_t endpoint_reading;
+
+  /** various lists of streams */
+  grpc_chttp2_stream_list lists[STREAM_LIST_COUNT];
+
+  /** maps stream id to grpc_chttp2_stream objects */
+  grpc_chttp2_stream_map stream_map;
+
+  grpc_closure write_action_begin_locked;
+  grpc_closure write_action;
+  grpc_closure write_action_end;
+  grpc_closure write_action_end_locked;
+
+  grpc_closure read_action_begin;
+  grpc_closure read_action_locked;
+
+  /** incoming read bytes */
+  gpr_slice_buffer read_buffer;
+
+  /** address to place a newly accepted stream - set and unset by
+      grpc_chttp2_parsing_accept_stream; used by init_stream to
+      publish the accepted server stream */
+  grpc_chttp2_stream **accepting_stream;
+
+  struct {
+    /* accept stream callback */
+    void (*accept_stream)(grpc_exec_ctx *exec_ctx, void *user_data,
+                          grpc_transport *transport, const void *server_data);
+    void *accept_stream_user_data;
+
+    /** connectivity tracking */
+    grpc_connectivity_state_tracker state_tracker;
+  } channel_callback;
+
+  /** data to write now */
+  gpr_slice_buffer outbuf;
+  /** hpack encoding */
+  grpc_chttp2_hpack_compressor hpack_compressor;
+  int64_t outgoing_window;
+  /** is this a client? */
+  uint8_t is_client;
+
   /** data to write next write */
   gpr_slice_buffer qbuf;
 
-  /** window available for us to send to peer */
-  int64_t outgoing_window;
   /** window available to announce to peer */
   int64_t announce_incoming_window;
   /** how much window would we like to have for incoming_window */
@@ -182,8 +251,6 @@
   /** have we sent a goaway */
   uint8_t sent_goaway;
 
-  /** is this transport a client? */
-  uint8_t is_client;
   /** are the local settings dirty and need to be sent? */
   uint8_t dirtied_local_settings;
   /** have local settings been sent? */
@@ -208,39 +275,6 @@
   /** next payload for an outgoing ping */
   uint64_t ping_counter;
 
-  /** concurrent stream count: updated when not parsing,
-      so this is a strict over-estimation on the client */
-  uint32_t concurrent_stream_count;
-} grpc_chttp2_transport_global;
-
-typedef struct {
-  /** data to write now */
-  gpr_slice_buffer outbuf;
-  /** hpack encoding */
-  grpc_chttp2_hpack_compressor hpack_compressor;
-  int64_t outgoing_window;
-  /** is this a client? */
-  uint8_t is_client;
-  /** callback for when writing is done */
-  grpc_closure done_cb;
-} grpc_chttp2_transport_writing;
-
-struct grpc_chttp2_transport_parsing {
-  /** is this transport a client? (boolean) */
-  uint8_t is_client;
-
-  /** were settings updated? */
-  uint8_t settings_updated;
-  /** was a settings ack received? */
-  uint8_t settings_ack_received;
-  /** was a goaway frame received? */
-  uint8_t goaway_received;
-
-  /** initial window change */
-  int64_t initial_window_update;
-
-  /** data to write later - after parsing */
-  gpr_slice_buffer qbuf;
   /** parser for headers */
   grpc_chttp2_hpack_parser hpack_parser;
   /** simple one shot parsers */
@@ -253,13 +287,12 @@
   /** parser for goaway frames */
   grpc_chttp2_goaway_parser goaway_parser;
 
+  /** initial window change */
+  int64_t initial_window_update;
+
   /** window available for peer to send to us */
   int64_t incoming_window;
 
-  /** next stream id available at the time of beginning parsing */
-  uint32_t next_stream_id;
-  uint32_t last_incoming_stream_id;
-
   /* deframing */
   grpc_chttp2_deframe_transport_state deframe_state;
   uint8_t incoming_frame_type;
@@ -270,142 +303,38 @@
   uint32_t incoming_frame_size;
   uint32_t incoming_stream_id;
 
-  /* current max frame size */
-  uint32_t max_frame_size;
-
   /* active parser */
   void *parser_data;
-  grpc_chttp2_stream_parsing *incoming_stream;
+  grpc_chttp2_stream *incoming_stream;
   grpc_error *(*parser)(grpc_exec_ctx *exec_ctx, void *parser_user_data,
-                        grpc_chttp2_transport_parsing *transport_parsing,
-                        grpc_chttp2_stream_parsing *stream_parsing,
+                        grpc_chttp2_transport *t, grpc_chttp2_stream *s,
                         gpr_slice slice, int is_last);
 
-  /* received settings */
-  uint32_t settings[GRPC_CHTTP2_NUM_SETTINGS];
-  /* last settings that were sent */
-  uint32_t last_sent_settings[GRPC_CHTTP2_NUM_SETTINGS];
-
   /* goaway data */
   grpc_status_code goaway_error;
   uint32_t goaway_last_stream_index;
   gpr_slice goaway_text;
 
-  int64_t outgoing_window;
+  grpc_chttp2_write_cb *write_cb_pool;
 };
 
-typedef void (*grpc_chttp2_locked_action)(grpc_exec_ctx *ctx,
-                                          grpc_chttp2_transport *t,
-                                          grpc_chttp2_stream *s, void *arg);
-
-typedef struct grpc_chttp2_executor_action_header {
-  grpc_chttp2_stream *stream;
-  grpc_chttp2_locked_action action;
-  struct grpc_chttp2_executor_action_header *next;
-  void *arg;
-} grpc_chttp2_executor_action_header;
-
 typedef enum {
-  /** no writing activity */
-  GRPC_CHTTP2_WRITING_INACTIVE,
-  /** write has been requested, but not scheduled yet */
-  GRPC_CHTTP2_WRITE_REQUESTED_WITH_POLLER,
-  GRPC_CHTTP2_WRITE_REQUESTED_NO_POLLER,
-  /** write has been requested and scheduled against the workqueue */
-  GRPC_CHTTP2_WRITE_SCHEDULED,
-  /** write has been initiated after being reaped from the workqueue */
-  GRPC_CHTTP2_WRITING,
-  /** write has been initiated, AND another write needs to be started once it's
-      done */
-  GRPC_CHTTP2_WRITING_STALE_WITH_POLLER,
-  GRPC_CHTTP2_WRITING_STALE_NO_POLLER,
-} grpc_chttp2_write_state;
+  GRPC_METADATA_NOT_PUBLISHED,
+  GRPC_METADATA_SYNTHESIZED_FROM_FAKE,
+  GRPC_METADATA_PUBLISHED_FROM_WIRE,
+  GPRC_METADATA_PUBLISHED_AT_CLOSE
+} grpc_published_metadata_method;
 
-struct grpc_chttp2_transport {
-  grpc_transport base; /* must be first */
-  gpr_refcount refs;
-  grpc_endpoint *ep;
-  char *peer_string;
+struct grpc_chttp2_stream {
+  grpc_chttp2_transport *t;
+  grpc_stream_refcount *refcount;
 
-  /** when this drops to zero it's safe to shutdown the endpoint */
-  gpr_refcount shutdown_ep_refs;
+  grpc_closure destroy_stream;
+  void *destroy_stream_arg;
 
-  struct {
-    gpr_mu mu;
+  grpc_chttp2_stream_link links[STREAM_LIST_COUNT];
+  uint8_t included[STREAM_LIST_COUNT];
 
-    /** is a thread currently in the global lock */
-    bool global_active;
-    /** is a thread currently parsing */
-    bool parsing_active;
-    /** write execution state of the transport */
-    grpc_chttp2_write_state write_state;
-
-    grpc_chttp2_executor_action_header *pending_actions_head;
-    grpc_chttp2_executor_action_header *pending_actions_tail;
-  } executor;
-
-  /** is the transport destroying itself? */
-  uint8_t destroying;
-  /** has the upper layer closed the transport? */
-  uint8_t closed;
-
-  /** is there a read request to the endpoint outstanding? */
-  uint8_t endpoint_reading;
-
-  /** various lists of streams */
-  grpc_chttp2_stream_list lists[STREAM_LIST_COUNT];
-
-  /** global state for reading/writing */
-  grpc_chttp2_transport_global global;
-  /** state only accessible by the chain of execution that
-      set writing_state >= GRPC_WRITING, and only by the writing closure
-      chain. */
-  grpc_chttp2_transport_writing writing;
-  /** state only accessible by the chain of execution that
-      set parsing_active=1 */
-  grpc_chttp2_transport_parsing parsing;
-
-  /** maps stream id to grpc_chttp2_stream objects;
-      owned by the parsing thread when parsing */
-  grpc_chttp2_stream_map parsing_stream_map;
-
-  /** streams created by the client (possibly during parsing);
-      merged with parsing_stream_map during unlock when no
-      parsing is occurring */
-  grpc_chttp2_stream_map new_stream_map;
-
-  /** closure to execute writing */
-  grpc_closure writing_action;
-  /** closure to start reading from the endpoint */
-  grpc_closure reading_action;
-  /** closure to actually do parsing */
-  grpc_closure parsing_action;
-  /** closure to initiate writing */
-  grpc_closure initiate_writing;
-
-  /** incoming read bytes */
-  gpr_slice_buffer read_buffer;
-
-  /** address to place a newly accepted stream - set and unset by
-      grpc_chttp2_parsing_accept_stream; used by init_stream to
-      publish the accepted server stream */
-  grpc_chttp2_stream **accepting_stream;
-
-  struct {
-    /* accept stream callback */
-    void (*accept_stream)(grpc_exec_ctx *exec_ctx, void *user_data,
-                          grpc_transport *transport, const void *server_data);
-    void *accept_stream_user_data;
-
-    /** connectivity tracking */
-    grpc_connectivity_state_tracker state_tracker;
-  } channel_callback;
-
-  /** Transport op to be applied post-parsing */
-  grpc_transport_op *post_parsing_op;
-};
-
-typedef struct {
   /** HTTP2 stream id for this stream, or zero if one has not been assigned */
   uint32_t id;
 
@@ -415,20 +344,21 @@
       As the upper layer offers more bytes, this value increases.
       As bytes are read, this value decreases. */
   uint32_t max_recv_bytes;
-  /** The number of bytes the upper layer has offered to read but we have
-      not yet announced to HTTP2 flow control.
-      As the upper layers offer to read more bytes, this value increases.
-      As we advertise incoming flow control window, this value decreases. */
-  uint32_t unannounced_incoming_window_for_parse;
-  uint32_t unannounced_incoming_window_for_writing;
   /** things the upper layers would like to send */
   grpc_metadata_batch *send_initial_metadata;
   grpc_closure *send_initial_metadata_finished;
-  grpc_byte_stream *send_message;
-  grpc_closure *send_message_finished;
   grpc_metadata_batch *send_trailing_metadata;
   grpc_closure *send_trailing_metadata_finished;
 
+  grpc_byte_stream *fetching_send_message;
+  uint32_t fetched_send_message_length;
+  gpr_slice fetching_slice;
+  int64_t fetching_slice_end_offset;
+  bool complete_fetch_covered_by_poller;
+  grpc_closure complete_fetch;
+  grpc_closure complete_fetch_locked;
+  grpc_closure *fetching_send_message_finished;
+
   grpc_metadata_batch *recv_initial_metadata;
   grpc_closure *recv_initial_metadata_ready;
   grpc_byte_stream **recv_message;
@@ -448,90 +378,44 @@
   bool read_closed;
   /** Are all published incoming byte streams closed. */
   bool all_incoming_byte_streams_finished;
-  /** Is this stream in the stream map. */
-  bool in_stream_map;
   /** Has this stream seen an error.
       If true, then pending incoming frames can be thrown away. */
   bool seen_error;
-  bool exceeded_metadata_size;
 
   /** the error that resulted in this stream being read-closed */
   grpc_error *read_closed_error;
   /** the error that resulted in this stream being write-closed */
   grpc_error *write_closed_error;
 
-  bool published_initial_metadata;
-  bool published_trailing_metadata;
+  grpc_published_metadata_method published_metadata[2];
   bool final_metadata_requested;
 
-  grpc_chttp2_incoming_metadata_buffer received_initial_metadata;
-  grpc_chttp2_incoming_metadata_buffer received_trailing_metadata;
+  grpc_chttp2_incoming_metadata_buffer metadata_buffer[2];
 
   grpc_chttp2_incoming_frame_queue incoming_frames;
 
   gpr_timespec deadline;
-} grpc_chttp2_stream_global;
 
-typedef struct {
-  /** HTTP2 stream id for this stream, or zero if one has not been assigned */
-  uint32_t id;
-  uint8_t fetching;
-  bool sent_initial_metadata;
-  uint8_t sent_message;
-  uint8_t sent_trailing_metadata;
-  uint8_t read_closed;
-  /** send this initial metadata */
-  grpc_metadata_batch *send_initial_metadata;
-  grpc_byte_stream *send_message;
-  grpc_metadata_batch *send_trailing_metadata;
-  int64_t outgoing_window;
-  /** how much window should we announce? */
-  uint32_t announce_window;
-  gpr_slice_buffer flow_controlled_buffer;
-  gpr_slice fetching_slice;
-  size_t stream_fetched;
-  grpc_closure finished_fetch;
-  /** stats gathered during the write */
-  grpc_transport_one_way_stats stats;
-} grpc_chttp2_stream_writing;
-
-struct grpc_chttp2_stream_parsing {
   /** saw some stream level error */
   grpc_error *forced_close_error;
-  /** HTTP2 stream id for this stream, or zero if one has not been assigned */
-  uint32_t id;
-  /** has this stream received a close */
-  uint8_t received_close;
   /** how many header frames have we received? */
   uint8_t header_frames_received;
-  /** which metadata did we get (on this parse) */
-  uint8_t got_metadata_on_parse[2];
-  /** should we raise the seen_error flag in transport_global */
-  bool seen_error;
-  bool exceeded_metadata_size;
   /** window available for peer to send to us */
   int64_t incoming_window;
   /** parsing state for data frames */
   grpc_chttp2_data_parser data_parser;
-  /** amount of window given */
-  int64_t outgoing_window;
   /** number of bytes received - reset at end of parse thread execution */
   int64_t received_bytes;
-  /** stats gathered during the parse */
-  grpc_transport_stream_stats stats;
 
-  /** incoming metadata */
-  grpc_chttp2_incoming_metadata_buffer metadata_buffer[2];
-};
+  bool sent_initial_metadata;
+  bool sent_trailing_metadata;
+  /** how much window should we announce? */
+  uint32_t announce_window;
+  gpr_slice_buffer flow_controlled_buffer;
 
-struct grpc_chttp2_stream {
-  grpc_stream_refcount *refcount;
-  grpc_chttp2_stream_global global;
-  grpc_chttp2_stream_writing writing;
-  grpc_chttp2_stream_parsing parsing;
-
-  grpc_chttp2_stream_link links[STREAM_LIST_COUNT];
-  uint8_t included[STREAM_LIST_COUNT];
+  grpc_chttp2_write_cb *on_write_finished_cbs;
+  grpc_chttp2_write_cb *finish_after_write;
+  size_t sending_bytes;
 };
 
 /** Transport writing call flow:
@@ -547,168 +431,71 @@
     The actual call chain is documented in the implementation of this function.
     */
 void grpc_chttp2_initiate_write(grpc_exec_ctx *exec_ctx,
-                                grpc_chttp2_transport_global *transport_global,
+                                grpc_chttp2_transport *t,
                                 bool covered_by_poller, const char *reason);
 
 /** Someone is unlocking the transport mutex: check to see if writes
-    are required, and schedule them if so */
-int grpc_chttp2_unlocking_check_writes(grpc_exec_ctx *exec_ctx,
-                                       grpc_chttp2_transport_global *global,
-                                       grpc_chttp2_transport_writing *writing);
-void grpc_chttp2_perform_writes(
-    grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_writing *transport_writing,
-    grpc_endpoint *endpoint);
-void grpc_chttp2_terminate_writing(grpc_exec_ctx *exec_ctx,
-                                   void *transport_writing, grpc_error *error);
-void grpc_chttp2_cleanup_writing(grpc_exec_ctx *exec_ctx,
-                                 grpc_chttp2_transport_global *global,
-                                 grpc_chttp2_transport_writing *writing);
+    are required, and frame them if so */
+bool grpc_chttp2_begin_write(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t);
+void grpc_chttp2_end_write(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t,
+                           grpc_error *error);
 
-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 */
-grpc_error *grpc_chttp2_perform_read(
-    grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_parsing *transport_parsing,
-    gpr_slice slice);
-void grpc_chttp2_publish_reads(grpc_exec_ctx *exec_ctx,
-                               grpc_chttp2_transport_global *global,
-                               grpc_chttp2_transport_parsing *parsing);
+grpc_error *grpc_chttp2_perform_read(grpc_exec_ctx *exec_ctx,
+                                     grpc_chttp2_transport *t, gpr_slice slice);
 
-bool grpc_chttp2_list_add_writable_stream(
-    grpc_chttp2_transport_global *transport_global,
-    grpc_chttp2_stream_global *stream_global);
+bool grpc_chttp2_list_add_writable_stream(grpc_chttp2_transport *t,
+                                          grpc_chttp2_stream *s);
 /** Get a writable stream
     returns non-zero if there was a stream available */
-int grpc_chttp2_list_pop_writable_stream(
-    grpc_chttp2_transport_global *transport_global,
-    grpc_chttp2_transport_writing *transport_writing,
-    grpc_chttp2_stream_global **stream_global,
-    grpc_chttp2_stream_writing **stream_writing);
+int grpc_chttp2_list_pop_writable_stream(grpc_chttp2_transport *t,
+                                         grpc_chttp2_stream **s);
 bool grpc_chttp2_list_remove_writable_stream(
-    grpc_chttp2_transport_global *transport_global,
-    grpc_chttp2_stream_global *stream_global) GRPC_MUST_USE_RESULT;
+    grpc_chttp2_transport *t, grpc_chttp2_stream *s) GRPC_MUST_USE_RESULT;
 
-void grpc_chttp2_list_add_writing_stream(
-    grpc_chttp2_transport_writing *transport_writing,
-    grpc_chttp2_stream_writing *stream_writing);
-int grpc_chttp2_list_have_writing_streams(
-    grpc_chttp2_transport_writing *transport_writing);
-int grpc_chttp2_list_pop_writing_stream(
-    grpc_chttp2_transport_writing *transport_writing,
-    grpc_chttp2_stream_writing **stream_writing);
+bool grpc_chttp2_list_add_writing_stream(grpc_chttp2_transport *t,
+                                         grpc_chttp2_stream *s);
+int grpc_chttp2_list_have_writing_streams(grpc_chttp2_transport *t);
+int grpc_chttp2_list_pop_writing_stream(grpc_chttp2_transport *t,
+                                        grpc_chttp2_stream **s);
 
-void grpc_chttp2_list_add_written_stream(
-    grpc_chttp2_transport_writing *transport_writing,
-    grpc_chttp2_stream_writing *stream_writing);
-int grpc_chttp2_list_pop_written_stream(
-    grpc_chttp2_transport_global *transport_global,
-    grpc_chttp2_transport_writing *transport_writing,
-    grpc_chttp2_stream_global **stream_global,
-    grpc_chttp2_stream_writing **stream_writing);
+void grpc_chttp2_list_add_written_stream(grpc_chttp2_transport *t,
+                                         grpc_chttp2_stream *s);
+int grpc_chttp2_list_pop_written_stream(grpc_chttp2_transport *t,
+                                        grpc_chttp2_stream **s);
 
-void grpc_chttp2_list_add_parsing_seen_stream(
-    grpc_chttp2_transport_parsing *transport_parsing,
-    grpc_chttp2_stream_parsing *stream_parsing);
-int grpc_chttp2_list_pop_parsing_seen_stream(
-    grpc_chttp2_transport_global *transport_global,
-    grpc_chttp2_transport_parsing *transport_parsing,
-    grpc_chttp2_stream_global **stream_global,
-    grpc_chttp2_stream_parsing **stream_parsing);
+void grpc_chttp2_list_add_waiting_for_concurrency(grpc_chttp2_transport *t,
+                                                  grpc_chttp2_stream *s);
+int grpc_chttp2_list_pop_waiting_for_concurrency(grpc_chttp2_transport *t,
+                                                 grpc_chttp2_stream **s);
 
-void grpc_chttp2_list_add_waiting_for_concurrency(
-    grpc_chttp2_transport_global *transport_global,
-    grpc_chttp2_stream_global *stream_global);
-int grpc_chttp2_list_pop_waiting_for_concurrency(
-    grpc_chttp2_transport_global *transport_global,
-    grpc_chttp2_stream_global **stream_global);
+void grpc_chttp2_list_add_stalled_by_transport(grpc_chttp2_transport *t,
+                                               grpc_chttp2_stream *s);
+int grpc_chttp2_list_pop_stalled_by_transport(grpc_chttp2_transport *t,
+                                              grpc_chttp2_stream **s);
+void grpc_chttp2_list_remove_stalled_by_transport(grpc_chttp2_transport *t,
+                                                  grpc_chttp2_stream *s);
 
-void grpc_chttp2_list_add_check_read_ops(
-    grpc_chttp2_transport_global *transport_global,
-    grpc_chttp2_stream_global *stream_global);
-bool grpc_chttp2_list_remove_check_read_ops(
-    grpc_chttp2_transport_global *transport_global,
-    grpc_chttp2_stream_global *stream_global);
-int grpc_chttp2_list_pop_check_read_ops(
-    grpc_chttp2_transport_global *transport_global,
-    grpc_chttp2_stream_global **stream_global);
+grpc_chttp2_stream *grpc_chttp2_parsing_lookup_stream(grpc_chttp2_transport *t,
+                                                      uint32_t id);
+grpc_chttp2_stream *grpc_chttp2_parsing_accept_stream(grpc_exec_ctx *exec_ctx,
+                                                      grpc_chttp2_transport *t,
+                                                      uint32_t id);
 
-void grpc_chttp2_list_add_writing_stalled_by_transport(
-    grpc_chttp2_transport_writing *transport_writing,
-    grpc_chttp2_stream_writing *stream_writing);
-bool grpc_chttp2_list_flush_writing_stalled_by_transport(
-    grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_writing *transport_writing);
+void grpc_chttp2_add_incoming_goaway(grpc_exec_ctx *exec_ctx,
+                                     grpc_chttp2_transport *t,
+                                     uint32_t goaway_error,
+                                     gpr_slice goaway_text);
 
-void grpc_chttp2_list_add_stalled_by_transport(
-    grpc_chttp2_transport_writing *transport_writing,
-    grpc_chttp2_stream_writing *stream_writing);
-int grpc_chttp2_list_pop_stalled_by_transport(
-    grpc_chttp2_transport_global *transport_global,
-    grpc_chttp2_stream_global **stream_global);
-void grpc_chttp2_list_remove_stalled_by_transport(
-    grpc_chttp2_transport_global *transport_global,
-    grpc_chttp2_stream_global *stream_global);
+void grpc_chttp2_parsing_become_skip_parser(grpc_exec_ctx *exec_ctx,
+                                            grpc_chttp2_transport *t);
 
-void grpc_chttp2_list_add_unannounced_incoming_window_available(
-    grpc_chttp2_transport_global *transport_global,
-    grpc_chttp2_stream_global *stream_global);
-void grpc_chttp2_list_remove_unannounced_incoming_window_available(
-    grpc_chttp2_transport_global *transport_global,
-    grpc_chttp2_stream_global *stream_global);
-int grpc_chttp2_list_pop_unannounced_incoming_window_available(
-    grpc_chttp2_transport_global *transport_global,
-    grpc_chttp2_transport_parsing *transport_parsing,
-    grpc_chttp2_stream_global **stream_global,
-    grpc_chttp2_stream_parsing **stream_parsing);
-
-void grpc_chttp2_list_add_closed_waiting_for_parsing(
-    grpc_chttp2_transport_global *transport_global,
-    grpc_chttp2_stream_global *stream_global);
-int grpc_chttp2_list_pop_closed_waiting_for_parsing(
-    grpc_chttp2_transport_global *transport_global,
-    grpc_chttp2_stream_global **stream_global);
-
-void grpc_chttp2_list_add_closed_waiting_for_writing(
-    grpc_chttp2_transport_global *transport_global,
-    grpc_chttp2_stream_global *stream_global);
-int grpc_chttp2_list_pop_closed_waiting_for_writing(
-    grpc_chttp2_transport_global *transport_global,
-    grpc_chttp2_stream_global **stream_global);
-
-grpc_chttp2_stream_parsing *grpc_chttp2_parsing_lookup_stream(
-    grpc_chttp2_transport_parsing *transport_parsing, uint32_t id);
-grpc_chttp2_stream_parsing *grpc_chttp2_parsing_accept_stream(
-    grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_parsing *transport_parsing,
-    uint32_t id);
-
-void grpc_chttp2_add_incoming_goaway(
-    grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_global *transport_global,
-    uint32_t goaway_error, gpr_slice goaway_text);
-
-void grpc_chttp2_register_stream(grpc_chttp2_transport *t,
-                                 grpc_chttp2_stream *s);
-/* returns 1 if this is the last stream, 0 otherwise */
-int grpc_chttp2_unregister_stream(grpc_chttp2_transport *t,
-                                  grpc_chttp2_stream *s) GRPC_MUST_USE_RESULT;
-int grpc_chttp2_has_streams(grpc_chttp2_transport *t);
-void grpc_chttp2_for_all_streams(
-    grpc_chttp2_transport_global *transport_global, void *user_data,
-    void (*cb)(grpc_chttp2_transport_global *transport_global, void *user_data,
-               grpc_chttp2_stream_global *stream_global));
-
-void grpc_chttp2_parsing_become_skip_parser(
-    grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_parsing *transport_parsing);
-
-void grpc_chttp2_complete_closure_step(
-    grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_global *transport_global,
-    grpc_chttp2_stream_global *stream_global, grpc_closure **pclosure,
-    grpc_error *error);
-
-void grpc_chttp2_run_with_global_lock(grpc_exec_ctx *exec_ctx,
-                                      grpc_chttp2_transport *transport,
-                                      grpc_chttp2_stream *optional_stream,
-                                      grpc_chttp2_locked_action action,
-                                      void *arg, size_t sizeof_arg);
+void grpc_chttp2_complete_closure_step(grpc_exec_ctx *exec_ctx,
+                                       grpc_chttp2_transport *t,
+                                       grpc_chttp2_stream *s,
+                                       grpc_closure **pclosure,
+                                       grpc_error *error, const char *desc);
 
 #define GRPC_CHTTP2_CLIENT_CONNECT_STRING "PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n"
 #define GRPC_CHTTP2_CLIENT_CONNECT_STRLEN \
@@ -799,57 +586,83 @@
                                const char *var2, int is_client,
                                uint32_t stream_id, int64_t val1, int64_t val2);
 
-void grpc_chttp2_fake_status(grpc_exec_ctx *exec_ctx,
-                             grpc_chttp2_transport_global *transport_global,
-                             grpc_chttp2_stream_global *stream,
+void grpc_chttp2_fake_status(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t,
+                             grpc_chttp2_stream *stream,
                              grpc_status_code status, gpr_slice *details);
-void grpc_chttp2_mark_stream_closed(
-    grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_global *transport_global,
-    grpc_chttp2_stream_global *stream_global, int close_reads, int close_writes,
-    grpc_error *error);
+void grpc_chttp2_mark_stream_closed(grpc_exec_ctx *exec_ctx,
+                                    grpc_chttp2_transport *t,
+                                    grpc_chttp2_stream *s, int close_reads,
+                                    int close_writes, grpc_error *error);
 void grpc_chttp2_start_writing(grpc_exec_ctx *exec_ctx,
-                               grpc_chttp2_transport_global *transport_global);
+                               grpc_chttp2_transport *t);
 
 #ifdef GRPC_STREAM_REFCOUNT_DEBUG
-#define GRPC_CHTTP2_STREAM_REF(stream_global, reason) \
-  grpc_chttp2_stream_ref(stream_global, reason)
-#define GRPC_CHTTP2_STREAM_UNREF(exec_ctx, stream_global, reason) \
-  grpc_chttp2_stream_unref(exec_ctx, stream_global, reason)
-void grpc_chttp2_stream_ref(grpc_chttp2_stream_global *stream_global,
-                            const char *reason);
-void grpc_chttp2_stream_unref(grpc_exec_ctx *exec_ctx,
-                              grpc_chttp2_stream_global *stream_global,
+#define GRPC_CHTTP2_STREAM_REF(stream, reason) \
+  grpc_chttp2_stream_ref(stream, reason)
+#define GRPC_CHTTP2_STREAM_UNREF(exec_ctx, stream, reason) \
+  grpc_chttp2_stream_unref(exec_ctx, stream, reason)
+void grpc_chttp2_stream_ref(grpc_chttp2_stream *s, const char *reason);
+void grpc_chttp2_stream_unref(grpc_exec_ctx *exec_ctx, grpc_chttp2_stream *s,
                               const char *reason);
 #else
-#define GRPC_CHTTP2_STREAM_REF(stream_global, reason) \
-  grpc_chttp2_stream_ref(stream_global)
-#define GRPC_CHTTP2_STREAM_UNREF(exec_ctx, stream_global, reason) \
-  grpc_chttp2_stream_unref(exec_ctx, stream_global)
-void grpc_chttp2_stream_ref(grpc_chttp2_stream_global *stream_global);
-void grpc_chttp2_stream_unref(grpc_exec_ctx *exec_ctx,
-                              grpc_chttp2_stream_global *stream_global);
+#define GRPC_CHTTP2_STREAM_REF(stream, reason) grpc_chttp2_stream_ref(stream)
+#define GRPC_CHTTP2_STREAM_UNREF(exec_ctx, stream, reason) \
+  grpc_chttp2_stream_unref(exec_ctx, stream)
+void grpc_chttp2_stream_ref(grpc_chttp2_stream *s);
+void grpc_chttp2_stream_unref(grpc_exec_ctx *exec_ctx, grpc_chttp2_stream *s);
+#endif
+
+//#define GRPC_CHTTP2_REFCOUNTING_DEBUG 1
+#ifdef GRPC_CHTTP2_REFCOUNTING_DEBUG
+#define GRPC_CHTTP2_REF_TRANSPORT(t, r) \
+  grpc_chttp2_ref_transport(t, r, __FILE__, __LINE__)
+#define GRPC_CHTTP2_UNREF_TRANSPORT(cl, t, r) \
+  grpc_chttp2_unref_transport(cl, t, r, __FILE__, __LINE__)
+void grpc_chttp2_unref_transport(grpc_exec_ctx *exec_ctx,
+                                 grpc_chttp2_transport *t, const char *reason,
+                                 const char *file, int line);
+void grpc_chttp2_ref_transport(grpc_chttp2_transport *t, const char *reason,
+                               const char *file, int line);
+#else
+#define GRPC_CHTTP2_REF_TRANSPORT(t, r) grpc_chttp2_ref_transport(t)
+#define GRPC_CHTTP2_UNREF_TRANSPORT(cl, t, r) grpc_chttp2_unref_transport(cl, t)
+void grpc_chttp2_unref_transport(grpc_exec_ctx *exec_ctx,
+                                 grpc_chttp2_transport *t);
+void grpc_chttp2_ref_transport(grpc_chttp2_transport *t);
 #endif
 
 grpc_chttp2_incoming_byte_stream *grpc_chttp2_incoming_byte_stream_create(
-    grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_parsing *transport_parsing,
-    grpc_chttp2_stream_parsing *stream_parsing, uint32_t frame_size,
-    uint32_t flags, grpc_chttp2_incoming_frame_queue *add_to_queue);
+    grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t, grpc_chttp2_stream *s,
+    uint32_t frame_size, uint32_t flags);
 void grpc_chttp2_incoming_byte_stream_push(grpc_exec_ctx *exec_ctx,
                                            grpc_chttp2_incoming_byte_stream *bs,
                                            gpr_slice slice);
 void grpc_chttp2_incoming_byte_stream_finished(
     grpc_exec_ctx *exec_ctx, grpc_chttp2_incoming_byte_stream *bs,
-    grpc_error *error, int from_parsing_thread);
+    grpc_error *error);
 
-void grpc_chttp2_ack_ping(grpc_exec_ctx *exec_ctx,
-                          grpc_chttp2_transport_parsing *parsing,
+void grpc_chttp2_ack_ping(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t,
                           const uint8_t *opaque_8bytes);
 
 /** add a ref to the stream and add it to the writable list;
     ref will be dropped in writing.c */
 void grpc_chttp2_become_writable(grpc_exec_ctx *exec_ctx,
-                                 grpc_chttp2_transport_global *transport_global,
-                                 grpc_chttp2_stream_global *stream_global,
-                                 bool covered_by_poller, const char *reason);
+                                 grpc_chttp2_transport *t,
+                                 grpc_chttp2_stream *s, bool covered_by_poller,
+                                 const char *reason);
+
+void grpc_chttp2_cancel_stream(grpc_exec_ctx *exec_ctx,
+                               grpc_chttp2_transport *t, grpc_chttp2_stream *s,
+                               grpc_error *due_to_error);
+
+void grpc_chttp2_maybe_complete_recv_initial_metadata(grpc_exec_ctx *exec_ctx,
+                                                      grpc_chttp2_transport *t,
+                                                      grpc_chttp2_stream *s);
+void grpc_chttp2_maybe_complete_recv_message(grpc_exec_ctx *exec_ctx,
+                                             grpc_chttp2_transport *t,
+                                             grpc_chttp2_stream *s);
+void grpc_chttp2_maybe_complete_recv_trailing_metadata(grpc_exec_ctx *exec_ctx,
+                                                       grpc_chttp2_transport *t,
+                                                       grpc_chttp2_stream *s);
 
 #endif /* GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_INTERNAL_H */
diff --git a/src/core/ext/transport/chttp2/transport/parsing.c b/src/core/ext/transport/chttp2/transport/parsing.c
index 482cd55..aa36f90 100644
--- a/src/core/ext/transport/chttp2/transport/parsing.c
+++ b/src/core/ext/transport/chttp2/transport/parsing.c
@@ -45,223 +45,34 @@
 #include "src/core/lib/transport/static_metadata.h"
 #include "src/core/lib/transport/timeout_encoding.h"
 
-#define TRANSPORT_FROM_PARSING(tp)                                        \
-  ((grpc_chttp2_transport *)((char *)(tp)-offsetof(grpc_chttp2_transport, \
-                                                   parsing)))
+static grpc_error *init_frame_parser(grpc_exec_ctx *exec_ctx,
+                                     grpc_chttp2_transport *t);
+static grpc_error *init_header_frame_parser(grpc_exec_ctx *exec_ctx,
+                                            grpc_chttp2_transport *t,
+                                            int is_continuation);
+static grpc_error *init_data_frame_parser(grpc_exec_ctx *exec_ctx,
+                                          grpc_chttp2_transport *t);
+static grpc_error *init_rst_stream_parser(grpc_exec_ctx *exec_ctx,
+                                          grpc_chttp2_transport *t);
+static grpc_error *init_settings_frame_parser(grpc_exec_ctx *exec_ctx,
+                                              grpc_chttp2_transport *t);
+static grpc_error *init_window_update_frame_parser(grpc_exec_ctx *exec_ctx,
+                                                   grpc_chttp2_transport *t);
+static grpc_error *init_ping_parser(grpc_exec_ctx *exec_ctx,
+                                    grpc_chttp2_transport *t);
+static grpc_error *init_goaway_parser(grpc_exec_ctx *exec_ctx,
+                                      grpc_chttp2_transport *t);
+static grpc_error *init_skip_frame_parser(grpc_exec_ctx *exec_ctx,
+                                          grpc_chttp2_transport *t,
+                                          int is_header);
 
-static grpc_error *init_frame_parser(
-    grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_parsing *transport_parsing);
-static grpc_error *init_header_frame_parser(
-    grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_parsing *transport_parsing,
-    int is_continuation);
-static grpc_error *init_data_frame_parser(
-    grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_parsing *transport_parsing);
-static grpc_error *init_rst_stream_parser(
-    grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_parsing *transport_parsing);
-static grpc_error *init_settings_frame_parser(
-    grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_parsing *transport_parsing);
-static grpc_error *init_window_update_frame_parser(
-    grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_parsing *transport_parsing);
-static grpc_error *init_ping_parser(
-    grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_parsing *transport_parsing);
-static grpc_error *init_goaway_parser(
-    grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_parsing *transport_parsing);
-static grpc_error *init_skip_frame_parser(
-    grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_parsing *transport_parsing,
-    int is_header);
+static grpc_error *parse_frame_slice(grpc_exec_ctx *exec_ctx,
+                                     grpc_chttp2_transport *t, gpr_slice slice,
+                                     int is_last);
 
-static grpc_error *parse_frame_slice(
-    grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_parsing *transport_parsing,
-    gpr_slice slice, int is_last);
-
-void grpc_chttp2_prepare_to_read(
-    grpc_chttp2_transport_global *transport_global,
-    grpc_chttp2_transport_parsing *transport_parsing) {
-  grpc_chttp2_stream_global *stream_global;
-  grpc_chttp2_stream_parsing *stream_parsing;
-
-  GPR_TIMER_BEGIN("grpc_chttp2_prepare_to_read", 0);
-
-  transport_parsing->next_stream_id = transport_global->next_stream_id;
-  memcpy(transport_parsing->last_sent_settings,
-         transport_global->settings[GRPC_SENT_SETTINGS],
-         sizeof(transport_parsing->last_sent_settings));
-  transport_parsing->max_frame_size =
-      transport_global->settings[GRPC_ACKED_SETTINGS]
-                                [GRPC_CHTTP2_SETTINGS_MAX_FRAME_SIZE];
-
-  /* update the parsing view of incoming window */
-  while (grpc_chttp2_list_pop_unannounced_incoming_window_available(
-      transport_global, transport_parsing, &stream_global, &stream_parsing)) {
-    GRPC_CHTTP2_FLOW_MOVE_STREAM("parse", transport_parsing, stream_parsing,
-                                 incoming_window, stream_global,
-                                 unannounced_incoming_window_for_parse);
-  }
-
-  GPR_TIMER_END("grpc_chttp2_prepare_to_read", 0);
-}
-
-void grpc_chttp2_publish_reads(
-    grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_global *transport_global,
-    grpc_chttp2_transport_parsing *transport_parsing) {
-  grpc_chttp2_stream_global *stream_global;
-  grpc_chttp2_stream_parsing *stream_parsing;
-  int was_zero;
-  int is_zero;
-
-  /* transport_parsing->last_incoming_stream_id is used as
-     last-grpc_chttp2_stream-id when
-     sending GOAWAY frame.
-     https://tools.ietf.org/html/draft-ietf-httpbis-http2-17#section-6.8
-     says that last-grpc_chttp2_stream-id is peer-initiated grpc_chttp2_stream
-     ID.  So,
-     since we don't have server pushed streams, client should send
-     GOAWAY last-grpc_chttp2_stream-id=0 in this case. */
-  if (!transport_parsing->is_client) {
-    transport_global->last_incoming_stream_id =
-        transport_parsing->last_incoming_stream_id;
-  }
-
-  /* update global settings */
-  if (transport_parsing->settings_updated) {
-    memcpy(transport_global->settings[GRPC_PEER_SETTINGS],
-           transport_parsing->settings, sizeof(transport_parsing->settings));
-    transport_parsing->settings_updated = 0;
-  }
-
-  /* update settings based on ack if received */
-  if (transport_parsing->settings_ack_received) {
-    memcpy(transport_global->settings[GRPC_ACKED_SETTINGS],
-           transport_global->settings[GRPC_SENT_SETTINGS],
-           GRPC_CHTTP2_NUM_SETTINGS * sizeof(uint32_t));
-    transport_parsing->settings_ack_received = 0;
-    transport_global->sent_local_settings = 0;
-  }
-
-  /* move goaway to the global state if we received one (it will be
-     published later */
-  if (transport_parsing->goaway_received) {
-    grpc_chttp2_add_incoming_goaway(exec_ctx, transport_global,
-                                    (uint32_t)transport_parsing->goaway_error,
-                                    transport_parsing->goaway_text);
-    transport_parsing->goaway_text = gpr_empty_slice();
-    transport_parsing->goaway_received = 0;
-  }
-
-  /* propagate flow control tokens to global state */
-  was_zero = transport_global->outgoing_window <= 0;
-  GRPC_CHTTP2_FLOW_MOVE_TRANSPORT("parsed", transport_global, outgoing_window,
-                                  transport_parsing, outgoing_window);
-  is_zero = transport_global->outgoing_window <= 0;
-  if (was_zero && !is_zero) {
-    grpc_chttp2_initiate_write(exec_ctx, transport_global, false,
-                               "new_global_flow_control");
-  }
-
-  if (transport_parsing->incoming_window <
-      transport_global->connection_window_target * 3 / 4) {
-    int64_t announce_bytes = transport_global->connection_window_target -
-                             transport_parsing->incoming_window;
-    GRPC_CHTTP2_FLOW_CREDIT_TRANSPORT("parsed", transport_global,
-                                      announce_incoming_window, announce_bytes);
-    GRPC_CHTTP2_FLOW_CREDIT_TRANSPORT("parsed", transport_parsing,
-                                      incoming_window, announce_bytes);
-    grpc_chttp2_initiate_write(exec_ctx, transport_global, false,
-                               "global incoming window");
-  }
-
-  /* for each stream that saw an update, fixup global state */
-  while (grpc_chttp2_list_pop_parsing_seen_stream(
-      transport_global, transport_parsing, &stream_global, &stream_parsing)) {
-    if (stream_parsing->seen_error) {
-      stream_global->seen_error = true;
-      stream_global->exceeded_metadata_size =
-          stream_parsing->exceeded_metadata_size;
-      grpc_chttp2_list_add_check_read_ops(transport_global, stream_global);
-    }
-
-    /* flush stats to global stream state */
-    grpc_transport_move_stats(&stream_parsing->stats, &stream_global->stats);
-
-    /* update outgoing flow control window */
-    was_zero = stream_global->outgoing_window <= 0;
-    GRPC_CHTTP2_FLOW_MOVE_STREAM("parsed", transport_global, stream_global,
-                                 outgoing_window, stream_parsing,
-                                 outgoing_window);
-    is_zero = stream_global->outgoing_window <= 0;
-    if (was_zero && !is_zero) {
-      grpc_chttp2_become_writable(exec_ctx, transport_global, stream_global,
-                                  false, "stream.read_flow_control");
-    }
-
-    stream_global->max_recv_bytes -= (uint32_t)GPR_MIN(
-        stream_global->max_recv_bytes, stream_parsing->received_bytes);
-    stream_parsing->received_bytes = 0;
-
-    /* publish incoming stream ops */
-    if (stream_global->incoming_frames.tail != NULL) {
-      stream_global->incoming_frames.tail->is_tail = 0;
-    }
-    if (stream_parsing->data_parser.incoming_frames.head != NULL) {
-      grpc_chttp2_list_add_check_read_ops(transport_global, stream_global);
-    }
-    grpc_chttp2_incoming_frame_queue_merge(
-        &stream_global->incoming_frames,
-        &stream_parsing->data_parser.incoming_frames);
-    if (stream_global->incoming_frames.tail != NULL) {
-      stream_global->incoming_frames.tail->is_tail = 1;
-    }
-
-    if (!stream_global->published_initial_metadata &&
-        stream_parsing->got_metadata_on_parse[0]) {
-      stream_parsing->got_metadata_on_parse[0] = 0;
-      stream_global->published_initial_metadata = 1;
-      GPR_SWAP(grpc_chttp2_incoming_metadata_buffer,
-               stream_parsing->metadata_buffer[0],
-               stream_global->received_initial_metadata);
-      grpc_chttp2_list_add_check_read_ops(transport_global, stream_global);
-    }
-    if (!stream_global->published_trailing_metadata &&
-        stream_parsing->got_metadata_on_parse[1]) {
-      stream_parsing->got_metadata_on_parse[1] = 0;
-      stream_global->published_trailing_metadata = 1;
-      GPR_SWAP(grpc_chttp2_incoming_metadata_buffer,
-               stream_parsing->metadata_buffer[1],
-               stream_global->received_trailing_metadata);
-      grpc_chttp2_list_add_check_read_ops(transport_global, stream_global);
-    }
-
-    if (stream_parsing->forced_close_error != GRPC_ERROR_NONE) {
-      intptr_t reason;
-      bool has_reason = grpc_error_get_int(stream_parsing->forced_close_error,
-                                           GRPC_ERROR_INT_HTTP2_ERROR, &reason);
-      if (has_reason && reason != GRPC_CHTTP2_NO_ERROR) {
-        grpc_status_code status_code =
-            has_reason
-                ? grpc_chttp2_http2_error_to_grpc_status(
-                      (grpc_chttp2_error_code)reason, stream_global->deadline)
-                : GRPC_STATUS_INTERNAL;
-        const char *status_details =
-            grpc_error_string(stream_parsing->forced_close_error);
-        gpr_slice slice_details = gpr_slice_from_copied_string(status_details);
-        grpc_error_free_string(status_details);
-        grpc_chttp2_fake_status(exec_ctx, transport_global, stream_global,
-                                status_code, &slice_details);
-      }
-      grpc_chttp2_mark_stream_closed(exec_ctx, transport_global, stream_global,
-                                     1, 1, stream_parsing->forced_close_error);
-    }
-
-    if (stream_parsing->received_close) {
-      grpc_chttp2_mark_stream_closed(exec_ctx, transport_global, stream_global,
-                                     1, 0, GRPC_ERROR_NONE);
-    }
-  }
-}
-
-grpc_error *grpc_chttp2_perform_read(
-    grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_parsing *transport_parsing,
-    gpr_slice slice) {
+grpc_error *grpc_chttp2_perform_read(grpc_exec_ctx *exec_ctx,
+                                     grpc_chttp2_transport *t,
+                                     gpr_slice slice) {
   uint8_t *beg = GPR_SLICE_START_PTR(slice);
   uint8_t *end = GPR_SLICE_END_PTR(slice);
   uint8_t *cur = beg;
@@ -269,7 +80,7 @@
 
   if (cur == end) return GRPC_ERROR_NONE;
 
-  switch (transport_parsing->deframe_state) {
+  switch (t->deframe_state) {
     case GRPC_DTS_CLIENT_PREFIX_0:
     case GRPC_DTS_CLIENT_PREFIX_1:
     case GRPC_DTS_CLIENT_PREFIX_2:
@@ -294,25 +105,22 @@
     case GRPC_DTS_CLIENT_PREFIX_21:
     case GRPC_DTS_CLIENT_PREFIX_22:
     case GRPC_DTS_CLIENT_PREFIX_23:
-      while (cur != end && transport_parsing->deframe_state != GRPC_DTS_FH_0) {
-        if (*cur != GRPC_CHTTP2_CLIENT_CONNECT_STRING[transport_parsing
-                                                          ->deframe_state]) {
+      while (cur != end && t->deframe_state != GRPC_DTS_FH_0) {
+        if (*cur != GRPC_CHTTP2_CLIENT_CONNECT_STRING[t->deframe_state]) {
           char *msg;
           gpr_asprintf(
               &msg,
               "Connect string mismatch: expected '%c' (%d) got '%c' (%d) "
               "at byte %d",
-              GRPC_CHTTP2_CLIENT_CONNECT_STRING[transport_parsing
-                                                    ->deframe_state],
-              (int)(uint8_t)GRPC_CHTTP2_CLIENT_CONNECT_STRING
-                  [transport_parsing->deframe_state],
-              *cur, (int)*cur, transport_parsing->deframe_state);
+              GRPC_CHTTP2_CLIENT_CONNECT_STRING[t->deframe_state],
+              (int)(uint8_t)GRPC_CHTTP2_CLIENT_CONNECT_STRING[t->deframe_state],
+              *cur, (int)*cur, t->deframe_state);
           err = GRPC_ERROR_CREATE(msg);
           gpr_free(msg);
           return err;
         }
         ++cur;
-        ++transport_parsing->deframe_state;
+        ++t->deframe_state;
       }
       if (cur == end) {
         return GRPC_ERROR_NONE;
@@ -321,100 +129,99 @@
     dts_fh_0:
     case GRPC_DTS_FH_0:
       GPR_ASSERT(cur < end);
-      transport_parsing->incoming_frame_size = ((uint32_t)*cur) << 16;
+      t->incoming_frame_size = ((uint32_t)*cur) << 16;
       if (++cur == end) {
-        transport_parsing->deframe_state = GRPC_DTS_FH_1;
+        t->deframe_state = GRPC_DTS_FH_1;
         return GRPC_ERROR_NONE;
       }
     /* fallthrough */
     case GRPC_DTS_FH_1:
       GPR_ASSERT(cur < end);
-      transport_parsing->incoming_frame_size |= ((uint32_t)*cur) << 8;
+      t->incoming_frame_size |= ((uint32_t)*cur) << 8;
       if (++cur == end) {
-        transport_parsing->deframe_state = GRPC_DTS_FH_2;
+        t->deframe_state = GRPC_DTS_FH_2;
         return GRPC_ERROR_NONE;
       }
     /* fallthrough */
     case GRPC_DTS_FH_2:
       GPR_ASSERT(cur < end);
-      transport_parsing->incoming_frame_size |= *cur;
+      t->incoming_frame_size |= *cur;
       if (++cur == end) {
-        transport_parsing->deframe_state = GRPC_DTS_FH_3;
+        t->deframe_state = GRPC_DTS_FH_3;
         return GRPC_ERROR_NONE;
       }
     /* fallthrough */
     case GRPC_DTS_FH_3:
       GPR_ASSERT(cur < end);
-      transport_parsing->incoming_frame_type = *cur;
+      t->incoming_frame_type = *cur;
       if (++cur == end) {
-        transport_parsing->deframe_state = GRPC_DTS_FH_4;
+        t->deframe_state = GRPC_DTS_FH_4;
         return GRPC_ERROR_NONE;
       }
     /* fallthrough */
     case GRPC_DTS_FH_4:
       GPR_ASSERT(cur < end);
-      transport_parsing->incoming_frame_flags = *cur;
+      t->incoming_frame_flags = *cur;
       if (++cur == end) {
-        transport_parsing->deframe_state = GRPC_DTS_FH_5;
+        t->deframe_state = GRPC_DTS_FH_5;
         return GRPC_ERROR_NONE;
       }
     /* fallthrough */
     case GRPC_DTS_FH_5:
       GPR_ASSERT(cur < end);
-      transport_parsing->incoming_stream_id = (((uint32_t)*cur) & 0x7f) << 24;
+      t->incoming_stream_id = (((uint32_t)*cur) & 0x7f) << 24;
       if (++cur == end) {
-        transport_parsing->deframe_state = GRPC_DTS_FH_6;
+        t->deframe_state = GRPC_DTS_FH_6;
         return GRPC_ERROR_NONE;
       }
     /* fallthrough */
     case GRPC_DTS_FH_6:
       GPR_ASSERT(cur < end);
-      transport_parsing->incoming_stream_id |= ((uint32_t)*cur) << 16;
+      t->incoming_stream_id |= ((uint32_t)*cur) << 16;
       if (++cur == end) {
-        transport_parsing->deframe_state = GRPC_DTS_FH_7;
+        t->deframe_state = GRPC_DTS_FH_7;
         return GRPC_ERROR_NONE;
       }
     /* fallthrough */
     case GRPC_DTS_FH_7:
       GPR_ASSERT(cur < end);
-      transport_parsing->incoming_stream_id |= ((uint32_t)*cur) << 8;
+      t->incoming_stream_id |= ((uint32_t)*cur) << 8;
       if (++cur == end) {
-        transport_parsing->deframe_state = GRPC_DTS_FH_8;
+        t->deframe_state = GRPC_DTS_FH_8;
         return GRPC_ERROR_NONE;
       }
     /* fallthrough */
     case GRPC_DTS_FH_8:
       GPR_ASSERT(cur < end);
-      transport_parsing->incoming_stream_id |= ((uint32_t)*cur);
-      transport_parsing->deframe_state = GRPC_DTS_FRAME;
-      err = init_frame_parser(exec_ctx, transport_parsing);
+      t->incoming_stream_id |= ((uint32_t)*cur);
+      t->deframe_state = GRPC_DTS_FRAME;
+      err = init_frame_parser(exec_ctx, t);
       if (err != GRPC_ERROR_NONE) {
         return err;
       }
-      if (transport_parsing->incoming_stream_id != 0 &&
-          transport_parsing->incoming_stream_id >
-              transport_parsing->last_incoming_stream_id) {
-        transport_parsing->last_incoming_stream_id =
-            transport_parsing->incoming_stream_id;
+      if (t->incoming_stream_id != 0 &&
+          t->incoming_stream_id > t->last_incoming_stream_id) {
+        t->last_incoming_stream_id = t->incoming_stream_id;
       }
-      if (transport_parsing->incoming_frame_size == 0) {
-        err = parse_frame_slice(exec_ctx, transport_parsing, gpr_empty_slice(),
-                                1);
+      if (t->incoming_frame_size == 0) {
+        err = parse_frame_slice(exec_ctx, t, gpr_empty_slice(), 1);
         if (err != GRPC_ERROR_NONE) {
           return err;
         }
-        transport_parsing->incoming_stream = NULL;
+        t->incoming_stream = NULL;
         if (++cur == end) {
-          transport_parsing->deframe_state = GRPC_DTS_FH_0;
+          t->deframe_state = GRPC_DTS_FH_0;
           return GRPC_ERROR_NONE;
         }
         goto dts_fh_0; /* loop */
-      } else if (transport_parsing->incoming_frame_size >
-                 transport_parsing->max_frame_size) {
+      } else if (t->incoming_frame_size >
+                 t->settings[GRPC_ACKED_SETTINGS]
+                            [GRPC_CHTTP2_SETTINGS_MAX_FRAME_SIZE]) {
         char *msg;
         gpr_asprintf(&msg, "Frame size %d is larger than max frame size %d",
-                     transport_parsing->incoming_frame_size,
-                     transport_parsing->max_frame_size);
+                     t->incoming_frame_size,
+                     t->settings[GRPC_ACKED_SETTINGS]
+                                [GRPC_CHTTP2_SETTINGS_MAX_FRAME_SIZE]);
         err = GRPC_ERROR_CREATE(msg);
         gpr_free(msg);
         return err;
@@ -425,41 +232,39 @@
     /* fallthrough */
     case GRPC_DTS_FRAME:
       GPR_ASSERT(cur < end);
-      if ((uint32_t)(end - cur) == transport_parsing->incoming_frame_size) {
-        err = parse_frame_slice(exec_ctx, transport_parsing,
+      if ((uint32_t)(end - cur) == t->incoming_frame_size) {
+        err = parse_frame_slice(exec_ctx, t,
                                 gpr_slice_sub_no_ref(slice, (size_t)(cur - beg),
                                                      (size_t)(end - beg)),
                                 1);
         if (err != GRPC_ERROR_NONE) {
           return err;
         }
-        transport_parsing->deframe_state = GRPC_DTS_FH_0;
-        transport_parsing->incoming_stream = NULL;
+        t->deframe_state = GRPC_DTS_FH_0;
+        t->incoming_stream = NULL;
         return GRPC_ERROR_NONE;
-      } else if ((uint32_t)(end - cur) >
-                 transport_parsing->incoming_frame_size) {
+      } else if ((uint32_t)(end - cur) > t->incoming_frame_size) {
         size_t cur_offset = (size_t)(cur - beg);
         err = parse_frame_slice(
-            exec_ctx, transport_parsing,
-            gpr_slice_sub_no_ref(
-                slice, cur_offset,
-                cur_offset + transport_parsing->incoming_frame_size),
+            exec_ctx, t,
+            gpr_slice_sub_no_ref(slice, cur_offset,
+                                 cur_offset + t->incoming_frame_size),
             1);
         if (err != GRPC_ERROR_NONE) {
           return err;
         }
-        cur += transport_parsing->incoming_frame_size;
-        transport_parsing->incoming_stream = NULL;
+        cur += t->incoming_frame_size;
+        t->incoming_stream = NULL;
         goto dts_fh_0; /* loop */
       } else {
-        err = parse_frame_slice(exec_ctx, transport_parsing,
+        err = parse_frame_slice(exec_ctx, t,
                                 gpr_slice_sub_no_ref(slice, (size_t)(cur - beg),
                                                      (size_t)(end - beg)),
                                 0);
         if (err != GRPC_ERROR_NONE) {
           return err;
         }
-        transport_parsing->incoming_frame_size -= (uint32_t)(end - cur);
+        t->incoming_frame_size -= (uint32_t)(end - cur);
         return GRPC_ERROR_NONE;
       }
       GPR_UNREACHABLE_CODE(return 0);
@@ -468,175 +273,164 @@
   GPR_UNREACHABLE_CODE(return 0);
 }
 
-static grpc_error *init_frame_parser(
-    grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_parsing *transport_parsing) {
-  if (transport_parsing->is_first_frame &&
-      transport_parsing->incoming_frame_type != GRPC_CHTTP2_FRAME_SETTINGS) {
+static grpc_error *init_frame_parser(grpc_exec_ctx *exec_ctx,
+                                     grpc_chttp2_transport *t) {
+  if (t->is_first_frame &&
+      t->incoming_frame_type != GRPC_CHTTP2_FRAME_SETTINGS) {
     char *msg;
     gpr_asprintf(
         &msg, "Expected SETTINGS frame as the first frame, got frame type %d",
-        transport_parsing->incoming_frame_type);
+        t->incoming_frame_type);
     grpc_error *err = GRPC_ERROR_CREATE(msg);
     gpr_free(msg);
     return err;
   }
-  transport_parsing->is_first_frame = false;
-  if (transport_parsing->expect_continuation_stream_id != 0) {
-    if (transport_parsing->incoming_frame_type !=
-        GRPC_CHTTP2_FRAME_CONTINUATION) {
+  t->is_first_frame = false;
+  if (t->expect_continuation_stream_id != 0) {
+    if (t->incoming_frame_type != GRPC_CHTTP2_FRAME_CONTINUATION) {
       char *msg;
       gpr_asprintf(&msg, "Expected CONTINUATION frame, got frame type %02x",
-                   transport_parsing->incoming_frame_type);
+                   t->incoming_frame_type);
       grpc_error *err = GRPC_ERROR_CREATE(msg);
       gpr_free(msg);
       return err;
     }
-    if (transport_parsing->expect_continuation_stream_id !=
-        transport_parsing->incoming_stream_id) {
+    if (t->expect_continuation_stream_id != t->incoming_stream_id) {
       char *msg;
       gpr_asprintf(
           &msg,
           "Expected CONTINUATION frame for grpc_chttp2_stream %08x, got "
           "grpc_chttp2_stream %08x",
-          transport_parsing->expect_continuation_stream_id,
-          transport_parsing->incoming_stream_id);
+          t->expect_continuation_stream_id, t->incoming_stream_id);
       grpc_error *err = GRPC_ERROR_CREATE(msg);
       gpr_free(msg);
       return err;
     }
-    return init_header_frame_parser(exec_ctx, transport_parsing, 1);
+    return init_header_frame_parser(exec_ctx, t, 1);
   }
-  switch (transport_parsing->incoming_frame_type) {
+  switch (t->incoming_frame_type) {
     case GRPC_CHTTP2_FRAME_DATA:
-      return init_data_frame_parser(exec_ctx, transport_parsing);
+      return init_data_frame_parser(exec_ctx, t);
     case GRPC_CHTTP2_FRAME_HEADER:
-      return init_header_frame_parser(exec_ctx, transport_parsing, 0);
+      return init_header_frame_parser(exec_ctx, t, 0);
     case GRPC_CHTTP2_FRAME_CONTINUATION:
       return GRPC_ERROR_CREATE("Unexpected CONTINUATION frame");
     case GRPC_CHTTP2_FRAME_RST_STREAM:
-      return init_rst_stream_parser(exec_ctx, transport_parsing);
+      return init_rst_stream_parser(exec_ctx, t);
     case GRPC_CHTTP2_FRAME_SETTINGS:
-      return init_settings_frame_parser(exec_ctx, transport_parsing);
+      return init_settings_frame_parser(exec_ctx, t);
     case GRPC_CHTTP2_FRAME_WINDOW_UPDATE:
-      return init_window_update_frame_parser(exec_ctx, transport_parsing);
+      return init_window_update_frame_parser(exec_ctx, t);
     case GRPC_CHTTP2_FRAME_PING:
-      return init_ping_parser(exec_ctx, transport_parsing);
+      return init_ping_parser(exec_ctx, t);
     case GRPC_CHTTP2_FRAME_GOAWAY:
-      return init_goaway_parser(exec_ctx, transport_parsing);
+      return init_goaway_parser(exec_ctx, t);
     default:
       if (grpc_http_trace) {
-        gpr_log(GPR_ERROR, "Unknown frame type %02x",
-                transport_parsing->incoming_frame_type);
+        gpr_log(GPR_ERROR, "Unknown frame type %02x", t->incoming_frame_type);
       }
-      return init_skip_frame_parser(exec_ctx, transport_parsing, 0);
+      return init_skip_frame_parser(exec_ctx, t, 0);
   }
 }
 
 static grpc_error *skip_parser(grpc_exec_ctx *exec_ctx, void *parser,
-                               grpc_chttp2_transport_parsing *transport_parsing,
-                               grpc_chttp2_stream_parsing *stream_parsing,
+                               grpc_chttp2_transport *t, grpc_chttp2_stream *s,
                                gpr_slice slice, int is_last) {
   return GRPC_ERROR_NONE;
 }
 
-static void skip_header(void *tp, grpc_mdelem *md) { GRPC_MDELEM_UNREF(md); }
+static void skip_header(grpc_exec_ctx *exec_ctx, void *tp, grpc_mdelem *md) {
+  GRPC_MDELEM_UNREF(md);
+}
 
-static grpc_error *init_skip_frame_parser(
-    grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_parsing *transport_parsing,
-    int is_header) {
+static grpc_error *init_skip_frame_parser(grpc_exec_ctx *exec_ctx,
+                                          grpc_chttp2_transport *t,
+                                          int is_header) {
   if (is_header) {
-    uint8_t is_eoh = transport_parsing->expect_continuation_stream_id != 0;
-    transport_parsing->parser = grpc_chttp2_header_parser_parse;
-    transport_parsing->parser_data = &transport_parsing->hpack_parser;
-    transport_parsing->hpack_parser.on_header = skip_header;
-    transport_parsing->hpack_parser.on_header_user_data = NULL;
-    transport_parsing->hpack_parser.is_boundary = is_eoh;
-    transport_parsing->hpack_parser.is_eof =
-        (uint8_t)(is_eoh ? transport_parsing->header_eof : 0);
+    uint8_t is_eoh = t->expect_continuation_stream_id != 0;
+    t->parser = grpc_chttp2_header_parser_parse;
+    t->parser_data = &t->hpack_parser;
+    t->hpack_parser.on_header = skip_header;
+    t->hpack_parser.on_header_user_data = NULL;
+    t->hpack_parser.is_boundary = is_eoh;
+    t->hpack_parser.is_eof = (uint8_t)(is_eoh ? t->header_eof : 0);
   } else {
-    transport_parsing->parser = skip_parser;
+    t->parser = skip_parser;
   }
   return GRPC_ERROR_NONE;
 }
 
-void grpc_chttp2_parsing_become_skip_parser(
-    grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_parsing *transport_parsing) {
-  init_skip_frame_parser(
-      exec_ctx, transport_parsing,
-      transport_parsing->parser == grpc_chttp2_header_parser_parse);
+void grpc_chttp2_parsing_become_skip_parser(grpc_exec_ctx *exec_ctx,
+                                            grpc_chttp2_transport *t) {
+  init_skip_frame_parser(exec_ctx, t,
+                         t->parser == grpc_chttp2_header_parser_parse);
 }
 
-static grpc_error *update_incoming_window(
-    grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_parsing *transport_parsing,
-    grpc_chttp2_stream_parsing *stream_parsing) {
-  uint32_t incoming_frame_size = transport_parsing->incoming_frame_size;
-  if (incoming_frame_size > transport_parsing->incoming_window) {
+static grpc_error *update_incoming_window(grpc_exec_ctx *exec_ctx,
+                                          grpc_chttp2_transport *t,
+                                          grpc_chttp2_stream *s) {
+  uint32_t incoming_frame_size = t->incoming_frame_size;
+  if (incoming_frame_size > t->incoming_window) {
     char *msg;
     gpr_asprintf(&msg, "frame of size %d overflows incoming window of %" PRId64,
-                 transport_parsing->incoming_frame_size,
-                 transport_parsing->incoming_window);
+                 t->incoming_frame_size, t->incoming_window);
     grpc_error *err = GRPC_ERROR_CREATE(msg);
     gpr_free(msg);
     return err;
   }
 
-  if (incoming_frame_size > stream_parsing->incoming_window) {
+  if (incoming_frame_size > s->incoming_window) {
     char *msg;
     gpr_asprintf(&msg, "frame of size %d overflows incoming window of %" PRId64,
-                 transport_parsing->incoming_frame_size,
-                 stream_parsing->incoming_window);
+                 t->incoming_frame_size, s->incoming_window);
     grpc_error *err = GRPC_ERROR_CREATE(msg);
     gpr_free(msg);
     return err;
   }
 
-  GRPC_CHTTP2_FLOW_DEBIT_TRANSPORT("parse", transport_parsing, incoming_window,
+  GRPC_CHTTP2_FLOW_DEBIT_TRANSPORT("parse", t, incoming_window,
                                    incoming_frame_size);
-  GRPC_CHTTP2_FLOW_DEBIT_STREAM("parse", transport_parsing, stream_parsing,
-                                incoming_window, incoming_frame_size);
-  stream_parsing->received_bytes += incoming_frame_size;
-
-  grpc_chttp2_list_add_parsing_seen_stream(transport_parsing, stream_parsing);
+  GRPC_CHTTP2_FLOW_DEBIT_STREAM("parse", t, s, incoming_window,
+                                incoming_frame_size);
+  s->received_bytes += incoming_frame_size;
+  s->max_recv_bytes -=
+      (uint32_t)GPR_MIN(s->max_recv_bytes, incoming_frame_size);
 
   return GRPC_ERROR_NONE;
 }
 
-static grpc_error *init_data_frame_parser(
-    grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_parsing *transport_parsing) {
-  grpc_chttp2_stream_parsing *stream_parsing =
-      grpc_chttp2_parsing_lookup_stream(transport_parsing,
-                                        transport_parsing->incoming_stream_id);
+static grpc_error *init_data_frame_parser(grpc_exec_ctx *exec_ctx,
+                                          grpc_chttp2_transport *t) {
+  grpc_chttp2_stream *s =
+      grpc_chttp2_parsing_lookup_stream(t, t->incoming_stream_id);
   grpc_error *err = GRPC_ERROR_NONE;
-  if (stream_parsing == NULL) {
-    return init_skip_frame_parser(exec_ctx, transport_parsing, 0);
+  if (s == NULL) {
+    return init_skip_frame_parser(exec_ctx, t, 0);
   }
-  stream_parsing->stats.incoming.framing_bytes += 9;
-  if (stream_parsing->received_close) {
-    return init_skip_frame_parser(exec_ctx, transport_parsing, 0);
+  s->stats.incoming.framing_bytes += 9;
+  if (s->read_closed) {
+    return init_skip_frame_parser(exec_ctx, t, 0);
   }
   if (err == GRPC_ERROR_NONE) {
-    err = update_incoming_window(exec_ctx, transport_parsing, stream_parsing);
+    err = update_incoming_window(exec_ctx, t, s);
   }
   if (err == GRPC_ERROR_NONE) {
-    err = grpc_chttp2_data_parser_begin_frame(
-        &stream_parsing->data_parser, transport_parsing->incoming_frame_flags,
-        stream_parsing->id);
+    err = grpc_chttp2_data_parser_begin_frame(&s->data_parser,
+                                              t->incoming_frame_flags, s->id);
   }
   if (err == GRPC_ERROR_NONE) {
-    transport_parsing->incoming_stream = stream_parsing;
-    transport_parsing->parser = grpc_chttp2_data_parser_parse;
-    transport_parsing->parser_data = &stream_parsing->data_parser;
+    t->incoming_stream = s;
+    t->parser = grpc_chttp2_data_parser_parse;
+    t->parser_data = &s->data_parser;
     return GRPC_ERROR_NONE;
   } else if (grpc_error_get_int(err, GRPC_ERROR_INT_STREAM_ID, NULL)) {
     /* handle stream errors by closing the stream */
-    stream_parsing->received_close = 1;
-    stream_parsing->forced_close_error = err;
+    grpc_chttp2_mark_stream_closed(exec_ctx, t, s, true, false, err);
     gpr_slice_buffer_add(
-        &transport_parsing->qbuf,
-        grpc_chttp2_rst_stream_create(transport_parsing->incoming_stream_id,
-                                      GRPC_CHTTP2_PROTOCOL_ERROR,
-                                      &stream_parsing->stats.outgoing));
-    return init_skip_frame_parser(exec_ctx, transport_parsing, 0);
+        &t->qbuf, grpc_chttp2_rst_stream_create(t->incoming_stream_id,
+                                                GRPC_CHTTP2_PROTOCOL_ERROR,
+                                                &s->stats.outgoing));
+    return init_skip_frame_parser(exec_ctx, t, 0);
   } else {
     return err;
   }
@@ -644,23 +438,22 @@
 
 static void free_timeout(void *p) { gpr_free(p); }
 
-static void on_initial_header(void *tp, grpc_mdelem *md) {
-  grpc_chttp2_transport_parsing *transport_parsing = tp;
-  grpc_chttp2_stream_parsing *stream_parsing =
-      transport_parsing->incoming_stream;
+static void on_initial_header(grpc_exec_ctx *exec_ctx, void *tp,
+                              grpc_mdelem *md) {
+  grpc_chttp2_transport *t = tp;
+  grpc_chttp2_stream *s = t->incoming_stream;
 
   GPR_TIMER_BEGIN("on_initial_header", 0);
 
-  GPR_ASSERT(stream_parsing);
+  GPR_ASSERT(s != NULL);
 
   GRPC_CHTTP2_IF_TRACING(gpr_log(
-      GPR_INFO, "HTTP:%d:HDR:%s: %s: %s", stream_parsing->id,
-      transport_parsing->is_client ? "CLI" : "SVR",
+      GPR_INFO, "HTTP:%d:HDR:%s: %s: %s", s->id, t->is_client ? "CLI" : "SVR",
       grpc_mdstr_as_c_string(md->key), grpc_mdstr_as_c_string(md->value)));
 
   if (md->key == GRPC_MDSTR_GRPC_STATUS && md != GRPC_MDELEM_GRPC_STATUS_0) {
     /* TODO(ctiller): check for a status like " 0" */
-    stream_parsing->seen_error = true;
+    s->seen_error = true;
   }
 
   if (md->key == GRPC_MDSTR_GRPC_TIMEOUT) {
@@ -677,306 +470,267 @@
       grpc_mdelem_set_user_data(md, free_timeout, cached_timeout);
     }
     grpc_chttp2_incoming_metadata_buffer_set_deadline(
-        &stream_parsing->metadata_buffer[0],
+        &s->metadata_buffer[0],
         gpr_time_add(gpr_now(GPR_CLOCK_MONOTONIC), *cached_timeout));
     GRPC_MDELEM_UNREF(md);
   } else {
-    const size_t new_size =
-        stream_parsing->metadata_buffer[0].size + GRPC_MDELEM_LENGTH(md);
-    grpc_chttp2_transport_global *transport_global =
-        &TRANSPORT_FROM_PARSING(transport_parsing)->global;
+    const size_t new_size = s->metadata_buffer[0].size + GRPC_MDELEM_LENGTH(md);
     const size_t metadata_size_limit =
-        transport_global->settings[GRPC_LOCAL_SETTINGS]
-                                  [GRPC_CHTTP2_SETTINGS_MAX_HEADER_LIST_SIZE];
+        t->settings[GRPC_ACKED_SETTINGS]
+                   [GRPC_CHTTP2_SETTINGS_MAX_HEADER_LIST_SIZE];
     if (new_size > metadata_size_limit) {
-      if (!stream_parsing->exceeded_metadata_size) {
-        gpr_log(GPR_DEBUG,
-                "received initial metadata size exceeds limit (%" PRIuPTR
-                " vs. %" PRIuPTR ")",
-                new_size, metadata_size_limit);
-        stream_parsing->seen_error = true;
-        stream_parsing->exceeded_metadata_size = true;
-      }
+      gpr_log(GPR_DEBUG,
+              "received initial metadata size exceeds limit (%" PRIuPTR
+              " vs. %" PRIuPTR ")",
+              new_size, metadata_size_limit);
+      grpc_chttp2_cancel_stream(
+          exec_ctx, t, s,
+          grpc_error_set_int(
+              GRPC_ERROR_CREATE("received initial metadata size exceeds limit"),
+              GRPC_ERROR_INT_GRPC_STATUS, GRPC_STATUS_RESOURCE_EXHAUSTED));
+      grpc_chttp2_parsing_become_skip_parser(exec_ctx, t);
+      s->seen_error = true;
       GRPC_MDELEM_UNREF(md);
     } else {
-      grpc_chttp2_incoming_metadata_buffer_add(
-          &stream_parsing->metadata_buffer[0], md);
+      grpc_chttp2_incoming_metadata_buffer_add(&s->metadata_buffer[0], md);
     }
   }
 
-  grpc_chttp2_list_add_parsing_seen_stream(transport_parsing, stream_parsing);
-
   GPR_TIMER_END("on_initial_header", 0);
 }
 
-static void on_trailing_header(void *tp, grpc_mdelem *md) {
-  grpc_chttp2_transport_parsing *transport_parsing = tp;
-  grpc_chttp2_stream_parsing *stream_parsing =
-      transport_parsing->incoming_stream;
+static void on_trailing_header(grpc_exec_ctx *exec_ctx, void *tp,
+                               grpc_mdelem *md) {
+  grpc_chttp2_transport *t = tp;
+  grpc_chttp2_stream *s = t->incoming_stream;
 
   GPR_TIMER_BEGIN("on_trailing_header", 0);
 
-  GPR_ASSERT(stream_parsing);
+  GPR_ASSERT(s != NULL);
 
   GRPC_CHTTP2_IF_TRACING(gpr_log(
-      GPR_INFO, "HTTP:%d:TRL:%s: %s: %s", stream_parsing->id,
-      transport_parsing->is_client ? "CLI" : "SVR",
+      GPR_INFO, "HTTP:%d:TRL:%s: %s: %s", s->id, t->is_client ? "CLI" : "SVR",
       grpc_mdstr_as_c_string(md->key), grpc_mdstr_as_c_string(md->value)));
 
   if (md->key == GRPC_MDSTR_GRPC_STATUS && md != GRPC_MDELEM_GRPC_STATUS_0) {
     /* TODO(ctiller): check for a status like " 0" */
-    stream_parsing->seen_error = true;
+    s->seen_error = true;
   }
 
-  const size_t new_size =
-      stream_parsing->metadata_buffer[1].size + GRPC_MDELEM_LENGTH(md);
-  grpc_chttp2_transport_global *transport_global =
-      &TRANSPORT_FROM_PARSING(transport_parsing)->global;
+  const size_t new_size = s->metadata_buffer[1].size + GRPC_MDELEM_LENGTH(md);
   const size_t metadata_size_limit =
-      transport_global->settings[GRPC_LOCAL_SETTINGS]
-                                [GRPC_CHTTP2_SETTINGS_MAX_HEADER_LIST_SIZE];
+      t->settings[GRPC_ACKED_SETTINGS]
+                 [GRPC_CHTTP2_SETTINGS_MAX_HEADER_LIST_SIZE];
   if (new_size > metadata_size_limit) {
-    if (!stream_parsing->exceeded_metadata_size) {
-      gpr_log(GPR_DEBUG,
-              "received trailing metadata size exceeds limit (%" PRIuPTR
-              " vs. %" PRIuPTR ")",
-              new_size, metadata_size_limit);
-      stream_parsing->seen_error = true;
-      stream_parsing->exceeded_metadata_size = true;
-    }
+    gpr_log(GPR_DEBUG,
+            "received trailing metadata size exceeds limit (%" PRIuPTR
+            " vs. %" PRIuPTR ")",
+            new_size, metadata_size_limit);
+    grpc_chttp2_cancel_stream(
+        exec_ctx, t, s,
+        grpc_error_set_int(
+            GRPC_ERROR_CREATE("received trailing metadata size exceeds limit"),
+            GRPC_ERROR_INT_GRPC_STATUS, GRPC_STATUS_RESOURCE_EXHAUSTED));
+    grpc_chttp2_parsing_become_skip_parser(exec_ctx, t);
+    s->seen_error = true;
     GRPC_MDELEM_UNREF(md);
   } else {
-    grpc_chttp2_incoming_metadata_buffer_add(
-        &stream_parsing->metadata_buffer[1], md);
+    grpc_chttp2_incoming_metadata_buffer_add(&s->metadata_buffer[1], md);
   }
 
-  grpc_chttp2_list_add_parsing_seen_stream(transport_parsing, stream_parsing);
-
   GPR_TIMER_END("on_trailing_header", 0);
 }
 
-static grpc_error *init_header_frame_parser(
-    grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_parsing *transport_parsing,
-    int is_continuation) {
-  uint8_t is_eoh = (transport_parsing->incoming_frame_flags &
-                    GRPC_CHTTP2_DATA_FLAG_END_HEADERS) != 0;
-  int via_accept = 0;
-  grpc_chttp2_stream_parsing *stream_parsing;
+static grpc_error *init_header_frame_parser(grpc_exec_ctx *exec_ctx,
+                                            grpc_chttp2_transport *t,
+                                            int is_continuation) {
+  uint8_t is_eoh =
+      (t->incoming_frame_flags & GRPC_CHTTP2_DATA_FLAG_END_HEADERS) != 0;
+  grpc_chttp2_stream *s;
 
   /* TODO(ctiller): when to increment header_frames_received? */
 
   if (is_eoh) {
-    transport_parsing->expect_continuation_stream_id = 0;
+    t->expect_continuation_stream_id = 0;
   } else {
-    transport_parsing->expect_continuation_stream_id =
-        transport_parsing->incoming_stream_id;
+    t->expect_continuation_stream_id = t->incoming_stream_id;
   }
 
   if (!is_continuation) {
-    transport_parsing->header_eof = (transport_parsing->incoming_frame_flags &
-                                     GRPC_CHTTP2_DATA_FLAG_END_STREAM) != 0;
+    t->header_eof =
+        (t->incoming_frame_flags & GRPC_CHTTP2_DATA_FLAG_END_STREAM) != 0;
   }
 
   /* could be a new grpc_chttp2_stream or an existing grpc_chttp2_stream */
-  stream_parsing = grpc_chttp2_parsing_lookup_stream(
-      transport_parsing, transport_parsing->incoming_stream_id);
-  if (stream_parsing == NULL) {
+  s = grpc_chttp2_parsing_lookup_stream(t, t->incoming_stream_id);
+  if (s == NULL) {
     if (is_continuation) {
       gpr_log(GPR_ERROR,
               "grpc_chttp2_stream disbanded before CONTINUATION received");
-      return init_skip_frame_parser(exec_ctx, transport_parsing, 1);
+      return init_skip_frame_parser(exec_ctx, t, 1);
     }
-    if (transport_parsing->is_client) {
-      if ((transport_parsing->incoming_stream_id & 1) &&
-          transport_parsing->incoming_stream_id <
-              transport_parsing->next_stream_id) {
+    if (t->is_client) {
+      if ((t->incoming_stream_id & 1) &&
+          t->incoming_stream_id < t->next_stream_id) {
         /* this is an old (probably cancelled) grpc_chttp2_stream */
       } else {
         gpr_log(GPR_ERROR,
                 "ignoring new grpc_chttp2_stream creation on client");
       }
-      return init_skip_frame_parser(exec_ctx, transport_parsing, 1);
-    } else if (transport_parsing->last_incoming_stream_id >
-               transport_parsing->incoming_stream_id) {
+      return init_skip_frame_parser(exec_ctx, t, 1);
+    } else if (t->last_incoming_stream_id > t->incoming_stream_id) {
       gpr_log(GPR_ERROR,
               "ignoring out of order new grpc_chttp2_stream request on server; "
               "last grpc_chttp2_stream "
               "id=%d, new grpc_chttp2_stream id=%d",
-              transport_parsing->last_incoming_stream_id,
-              transport_parsing->incoming_stream_id);
-      return init_skip_frame_parser(exec_ctx, transport_parsing, 1);
-    } else if ((transport_parsing->incoming_stream_id & 1) == 0) {
+              t->last_incoming_stream_id, t->incoming_stream_id);
+      return init_skip_frame_parser(exec_ctx, t, 1);
+    } else if ((t->incoming_stream_id & 1) == 0) {
       gpr_log(GPR_ERROR,
               "ignoring grpc_chttp2_stream with non-client generated index %d",
-              transport_parsing->incoming_stream_id);
-      return init_skip_frame_parser(exec_ctx, transport_parsing, 1);
+              t->incoming_stream_id);
+      return init_skip_frame_parser(exec_ctx, t, 1);
     }
-    stream_parsing = transport_parsing->incoming_stream =
-        grpc_chttp2_parsing_accept_stream(
-            exec_ctx, transport_parsing, transport_parsing->incoming_stream_id);
-    if (stream_parsing == NULL) {
+    s = t->incoming_stream =
+        grpc_chttp2_parsing_accept_stream(exec_ctx, t, t->incoming_stream_id);
+    if (s == NULL) {
       gpr_log(GPR_ERROR, "grpc_chttp2_stream not accepted");
-      return init_skip_frame_parser(exec_ctx, transport_parsing, 1);
+      return init_skip_frame_parser(exec_ctx, t, 1);
     }
-    via_accept = 1;
   } else {
-    transport_parsing->incoming_stream = stream_parsing;
+    t->incoming_stream = s;
   }
-  GPR_ASSERT(stream_parsing != NULL && (via_accept == 0 || via_accept == 1));
-  stream_parsing->stats.incoming.framing_bytes += 9;
-  if (stream_parsing->received_close) {
+  GPR_ASSERT(s != NULL);
+  s->stats.incoming.framing_bytes += 9;
+  if (s->read_closed) {
     gpr_log(GPR_ERROR, "skipping already closed grpc_chttp2_stream header");
-    transport_parsing->incoming_stream = NULL;
-    return init_skip_frame_parser(exec_ctx, transport_parsing, 1);
+    t->incoming_stream = NULL;
+    return init_skip_frame_parser(exec_ctx, t, 1);
   }
-  transport_parsing->parser = grpc_chttp2_header_parser_parse;
-  transport_parsing->parser_data = &transport_parsing->hpack_parser;
-  switch (stream_parsing->header_frames_received) {
+  t->parser = grpc_chttp2_header_parser_parse;
+  t->parser_data = &t->hpack_parser;
+  switch (s->header_frames_received) {
     case 0:
-      transport_parsing->hpack_parser.on_header = on_initial_header;
+      t->hpack_parser.on_header = on_initial_header;
       break;
     case 1:
-      transport_parsing->hpack_parser.on_header = on_trailing_header;
+      t->hpack_parser.on_header = on_trailing_header;
       break;
     case 2:
       gpr_log(GPR_ERROR, "too many header frames received");
-      return init_skip_frame_parser(exec_ctx, transport_parsing, 1);
+      return init_skip_frame_parser(exec_ctx, t, 1);
   }
-  transport_parsing->hpack_parser.on_header_user_data = transport_parsing;
-  transport_parsing->hpack_parser.is_boundary = is_eoh;
-  transport_parsing->hpack_parser.is_eof =
-      (uint8_t)(is_eoh ? transport_parsing->header_eof : 0);
-  if (!is_continuation && (transport_parsing->incoming_frame_flags &
-                           GRPC_CHTTP2_FLAG_HAS_PRIORITY)) {
-    grpc_chttp2_hpack_parser_set_has_priority(&transport_parsing->hpack_parser);
+  t->hpack_parser.on_header_user_data = t;
+  t->hpack_parser.is_boundary = is_eoh;
+  t->hpack_parser.is_eof = (uint8_t)(is_eoh ? t->header_eof : 0);
+  if (!is_continuation &&
+      (t->incoming_frame_flags & GRPC_CHTTP2_FLAG_HAS_PRIORITY)) {
+    grpc_chttp2_hpack_parser_set_has_priority(&t->hpack_parser);
   }
   return GRPC_ERROR_NONE;
 }
 
-static grpc_error *init_window_update_frame_parser(
-    grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_parsing *transport_parsing) {
+static grpc_error *init_window_update_frame_parser(grpc_exec_ctx *exec_ctx,
+                                                   grpc_chttp2_transport *t) {
   grpc_error *err = grpc_chttp2_window_update_parser_begin_frame(
-      &transport_parsing->simple.window_update,
-      transport_parsing->incoming_frame_size,
-      transport_parsing->incoming_frame_flags);
+      &t->simple.window_update, t->incoming_frame_size,
+      t->incoming_frame_flags);
   if (err != GRPC_ERROR_NONE) return err;
-  if (transport_parsing->incoming_stream_id != 0) {
-    grpc_chttp2_stream_parsing *stream_parsing =
-        transport_parsing->incoming_stream = grpc_chttp2_parsing_lookup_stream(
-            transport_parsing, transport_parsing->incoming_stream_id);
-    if (stream_parsing == NULL) {
-      return init_skip_frame_parser(exec_ctx, transport_parsing, 0);
+  if (t->incoming_stream_id != 0) {
+    grpc_chttp2_stream *s = t->incoming_stream =
+        grpc_chttp2_parsing_lookup_stream(t, t->incoming_stream_id);
+    if (s == NULL) {
+      return init_skip_frame_parser(exec_ctx, t, 0);
     }
-    stream_parsing->stats.incoming.framing_bytes += 9;
+    s->stats.incoming.framing_bytes += 9;
   }
-  transport_parsing->parser = grpc_chttp2_window_update_parser_parse;
-  transport_parsing->parser_data = &transport_parsing->simple.window_update;
+  t->parser = grpc_chttp2_window_update_parser_parse;
+  t->parser_data = &t->simple.window_update;
   return GRPC_ERROR_NONE;
 }
 
-static grpc_error *init_ping_parser(
-    grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_parsing *transport_parsing) {
+static grpc_error *init_ping_parser(grpc_exec_ctx *exec_ctx,
+                                    grpc_chttp2_transport *t) {
   grpc_error *err = grpc_chttp2_ping_parser_begin_frame(
-      &transport_parsing->simple.ping, transport_parsing->incoming_frame_size,
-      transport_parsing->incoming_frame_flags);
+      &t->simple.ping, t->incoming_frame_size, t->incoming_frame_flags);
   if (err != GRPC_ERROR_NONE) return err;
-  transport_parsing->parser = grpc_chttp2_ping_parser_parse;
-  transport_parsing->parser_data = &transport_parsing->simple.ping;
+  t->parser = grpc_chttp2_ping_parser_parse;
+  t->parser_data = &t->simple.ping;
   return GRPC_ERROR_NONE;
 }
 
-static grpc_error *init_rst_stream_parser(
-    grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_parsing *transport_parsing) {
+static grpc_error *init_rst_stream_parser(grpc_exec_ctx *exec_ctx,
+                                          grpc_chttp2_transport *t) {
   grpc_error *err = grpc_chttp2_rst_stream_parser_begin_frame(
-      &transport_parsing->simple.rst_stream,
-      transport_parsing->incoming_frame_size,
-      transport_parsing->incoming_frame_flags);
+      &t->simple.rst_stream, t->incoming_frame_size, t->incoming_frame_flags);
   if (err != GRPC_ERROR_NONE) return err;
-  grpc_chttp2_stream_parsing *stream_parsing =
-      transport_parsing->incoming_stream = grpc_chttp2_parsing_lookup_stream(
-          transport_parsing, transport_parsing->incoming_stream_id);
-  if (!transport_parsing->incoming_stream) {
-    return init_skip_frame_parser(exec_ctx, transport_parsing, 0);
+  grpc_chttp2_stream *s = t->incoming_stream =
+      grpc_chttp2_parsing_lookup_stream(t, t->incoming_stream_id);
+  if (!t->incoming_stream) {
+    return init_skip_frame_parser(exec_ctx, t, 0);
   }
-  stream_parsing->stats.incoming.framing_bytes += 9;
-  transport_parsing->parser = grpc_chttp2_rst_stream_parser_parse;
-  transport_parsing->parser_data = &transport_parsing->simple.rst_stream;
+  s->stats.incoming.framing_bytes += 9;
+  t->parser = grpc_chttp2_rst_stream_parser_parse;
+  t->parser_data = &t->simple.rst_stream;
   return GRPC_ERROR_NONE;
 }
 
-static grpc_error *init_goaway_parser(
-    grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_parsing *transport_parsing) {
+static grpc_error *init_goaway_parser(grpc_exec_ctx *exec_ctx,
+                                      grpc_chttp2_transport *t) {
   grpc_error *err = grpc_chttp2_goaway_parser_begin_frame(
-      &transport_parsing->goaway_parser, transport_parsing->incoming_frame_size,
-      transport_parsing->incoming_frame_flags);
+      &t->goaway_parser, t->incoming_frame_size, t->incoming_frame_flags);
   if (err != GRPC_ERROR_NONE) return err;
-  transport_parsing->parser = grpc_chttp2_goaway_parser_parse;
-  transport_parsing->parser_data = &transport_parsing->goaway_parser;
+  t->parser = grpc_chttp2_goaway_parser_parse;
+  t->parser_data = &t->goaway_parser;
   return GRPC_ERROR_NONE;
 }
 
-static grpc_error *init_settings_frame_parser(
-    grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_parsing *transport_parsing) {
-  if (transport_parsing->incoming_stream_id != 0) {
+static grpc_error *init_settings_frame_parser(grpc_exec_ctx *exec_ctx,
+                                              grpc_chttp2_transport *t) {
+  if (t->incoming_stream_id != 0) {
     return GRPC_ERROR_CREATE("Settings frame received for grpc_chttp2_stream");
   }
 
   grpc_error *err = grpc_chttp2_settings_parser_begin_frame(
-      &transport_parsing->simple.settings,
-      transport_parsing->incoming_frame_size,
-      transport_parsing->incoming_frame_flags, transport_parsing->settings);
+      &t->simple.settings, t->incoming_frame_size, t->incoming_frame_flags,
+      t->settings[GRPC_PEER_SETTINGS]);
   if (err != GRPC_ERROR_NONE) {
     return err;
   }
-  if (transport_parsing->incoming_frame_flags & GRPC_CHTTP2_FLAG_ACK) {
-    transport_parsing->settings_ack_received = 1;
+  if (t->incoming_frame_flags & GRPC_CHTTP2_FLAG_ACK) {
+    memcpy(t->settings[GRPC_ACKED_SETTINGS], t->settings[GRPC_SENT_SETTINGS],
+           GRPC_CHTTP2_NUM_SETTINGS * sizeof(uint32_t));
     grpc_chttp2_hptbl_set_max_bytes(
-        &transport_parsing->hpack_parser.table,
-        transport_parsing
-            ->last_sent_settings[GRPC_CHTTP2_SETTINGS_HEADER_TABLE_SIZE]);
-    transport_parsing->max_frame_size =
-        transport_parsing
-            ->last_sent_settings[GRPC_CHTTP2_SETTINGS_MAX_FRAME_SIZE];
+        &t->hpack_parser.table,
+        t->settings[GRPC_ACKED_SETTINGS]
+                   [GRPC_CHTTP2_SETTINGS_HEADER_TABLE_SIZE]);
+    t->sent_local_settings = 0;
   }
-  transport_parsing->parser = grpc_chttp2_settings_parser_parse;
-  transport_parsing->parser_data = &transport_parsing->simple.settings;
+  t->parser = grpc_chttp2_settings_parser_parse;
+  t->parser_data = &t->simple.settings;
   return GRPC_ERROR_NONE;
 }
 
-/*
-static int is_window_update_legal(int64_t window_update, int64_t window) {
-  return window + window_update < MAX_WINDOW;
-}
-*/
-
-static grpc_error *parse_frame_slice(
-    grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_parsing *transport_parsing,
-    gpr_slice slice, int is_last) {
-  grpc_chttp2_stream_parsing *stream_parsing =
-      transport_parsing->incoming_stream;
-  grpc_error *err = transport_parsing->parser(
-      exec_ctx, transport_parsing->parser_data, transport_parsing,
-      stream_parsing, slice, is_last);
+static grpc_error *parse_frame_slice(grpc_exec_ctx *exec_ctx,
+                                     grpc_chttp2_transport *t, gpr_slice slice,
+                                     int is_last) {
+  grpc_chttp2_stream *s = t->incoming_stream;
+  grpc_error *err = t->parser(exec_ctx, t->parser_data, t, s, slice, is_last);
   if (err == GRPC_ERROR_NONE) {
-    if (stream_parsing) {
-      grpc_chttp2_list_add_parsing_seen_stream(transport_parsing,
-                                               stream_parsing);
-    }
-    return GRPC_ERROR_NONE;
+    return err;
   } else if (grpc_error_get_int(err, GRPC_ERROR_INT_STREAM_ID, NULL)) {
     if (grpc_http_trace) {
       const char *msg = grpc_error_string(err);
       gpr_log(GPR_ERROR, "%s", msg);
       grpc_error_free_string(msg);
     }
-    grpc_chttp2_parsing_become_skip_parser(exec_ctx, transport_parsing);
-    if (stream_parsing) {
-      stream_parsing->forced_close_error = err;
+    grpc_chttp2_parsing_become_skip_parser(exec_ctx, t);
+    if (s) {
+      s->forced_close_error = err;
       gpr_slice_buffer_add(
-          &transport_parsing->qbuf,
-          grpc_chttp2_rst_stream_create(transport_parsing->incoming_stream_id,
-                                        GRPC_CHTTP2_PROTOCOL_ERROR,
-                                        &stream_parsing->stats.outgoing));
+          &t->qbuf, grpc_chttp2_rst_stream_create(t->incoming_stream_id,
+                                                  GRPC_CHTTP2_PROTOCOL_ERROR,
+                                                  &s->stats.outgoing));
     } else {
       GRPC_ERROR_UNREF(err);
     }
diff --git a/src/core/ext/transport/chttp2/transport/stream_lists.c b/src/core/ext/transport/chttp2/transport/stream_lists.c
index 2eb5f5f..6d25b3a 100644
--- a/src/core/ext/transport/chttp2/transport/stream_lists.c
+++ b/src/core/ext/transport/chttp2/transport/stream_lists.c
@@ -35,27 +35,6 @@
 
 #include <grpc/support/log.h>
 
-#define TRANSPORT_FROM_GLOBAL(tg)                                         \
-  ((grpc_chttp2_transport *)((char *)(tg)-offsetof(grpc_chttp2_transport, \
-                                                   global)))
-
-#define STREAM_FROM_GLOBAL(sg) \
-  ((grpc_chttp2_stream *)((char *)(sg)-offsetof(grpc_chttp2_stream, global)))
-
-#define TRANSPORT_FROM_WRITING(tw)                                        \
-  ((grpc_chttp2_transport *)((char *)(tw)-offsetof(grpc_chttp2_transport, \
-                                                   writing)))
-
-#define STREAM_FROM_WRITING(sw) \
-  ((grpc_chttp2_stream *)((char *)(sw)-offsetof(grpc_chttp2_stream, writing)))
-
-#define TRANSPORT_FROM_PARSING(tp)                                        \
-  ((grpc_chttp2_transport *)((char *)(tp)-offsetof(grpc_chttp2_transport, \
-                                                   parsing)))
-
-#define STREAM_FROM_PARSING(sp) \
-  ((grpc_chttp2_stream *)((char *)(sp)-offsetof(grpc_chttp2_stream, parsing)))
-
 /* core list management */
 
 static int stream_list_empty(grpc_chttp2_transport *t,
@@ -139,314 +118,57 @@
 
 /* wrappers for specializations */
 
-bool grpc_chttp2_list_add_writable_stream(
-    grpc_chttp2_transport_global *transport_global,
-    grpc_chttp2_stream_global *stream_global) {
-  GPR_ASSERT(stream_global->id != 0);
-  return stream_list_add(TRANSPORT_FROM_GLOBAL(transport_global),
-                         STREAM_FROM_GLOBAL(stream_global),
-                         GRPC_CHTTP2_LIST_WRITABLE);
+bool grpc_chttp2_list_add_writable_stream(grpc_chttp2_transport *t,
+                                          grpc_chttp2_stream *s) {
+  GPR_ASSERT(s->id != 0);
+  return stream_list_add(t, s, GRPC_CHTTP2_LIST_WRITABLE);
 }
 
-int grpc_chttp2_list_pop_writable_stream(
-    grpc_chttp2_transport_global *transport_global,
-    grpc_chttp2_transport_writing *transport_writing,
-    grpc_chttp2_stream_global **stream_global,
-    grpc_chttp2_stream_writing **stream_writing) {
-  grpc_chttp2_stream *stream;
-  int r = stream_list_pop(TRANSPORT_FROM_GLOBAL(transport_global), &stream,
-                          GRPC_CHTTP2_LIST_WRITABLE);
-  if (r != 0) {
-    *stream_global = &stream->global;
-    *stream_writing = &stream->writing;
-  }
-  return r;
+int grpc_chttp2_list_pop_writable_stream(grpc_chttp2_transport *t,
+                                         grpc_chttp2_stream **s) {
+  return stream_list_pop(t, s, GRPC_CHTTP2_LIST_WRITABLE);
 }
 
-bool grpc_chttp2_list_remove_writable_stream(
-    grpc_chttp2_transport_global *transport_global,
-    grpc_chttp2_stream_global *stream_global) {
-  return stream_list_maybe_remove(TRANSPORT_FROM_GLOBAL(transport_global),
-                                  STREAM_FROM_GLOBAL(stream_global),
-                                  GRPC_CHTTP2_LIST_WRITABLE);
+bool grpc_chttp2_list_remove_writable_stream(grpc_chttp2_transport *t,
+                                             grpc_chttp2_stream *s) {
+  return stream_list_maybe_remove(t, s, GRPC_CHTTP2_LIST_WRITABLE);
 }
 
-void grpc_chttp2_list_add_writing_stream(
-    grpc_chttp2_transport_writing *transport_writing,
-    grpc_chttp2_stream_writing *stream_writing) {
-  GPR_ASSERT(stream_list_add(TRANSPORT_FROM_WRITING(transport_writing),
-                             STREAM_FROM_WRITING(stream_writing),
-                             GRPC_CHTTP2_LIST_WRITING));
+bool grpc_chttp2_list_add_writing_stream(grpc_chttp2_transport *t,
+                                         grpc_chttp2_stream *s) {
+  return stream_list_add(t, s, GRPC_CHTTP2_LIST_WRITING);
 }
 
-int grpc_chttp2_list_have_writing_streams(
-    grpc_chttp2_transport_writing *transport_writing) {
-  return !stream_list_empty(TRANSPORT_FROM_WRITING(transport_writing),
-                            GRPC_CHTTP2_LIST_WRITING);
+int grpc_chttp2_list_have_writing_streams(grpc_chttp2_transport *t) {
+  return !stream_list_empty(t, GRPC_CHTTP2_LIST_WRITING);
 }
 
-int grpc_chttp2_list_pop_writing_stream(
-    grpc_chttp2_transport_writing *transport_writing,
-    grpc_chttp2_stream_writing **stream_writing) {
-  grpc_chttp2_stream *stream;
-  int r = stream_list_pop(TRANSPORT_FROM_WRITING(transport_writing), &stream,
-                          GRPC_CHTTP2_LIST_WRITING);
-  if (r != 0) {
-    *stream_writing = &stream->writing;
-  }
-  return r;
+int grpc_chttp2_list_pop_writing_stream(grpc_chttp2_transport *t,
+                                        grpc_chttp2_stream **s) {
+  return stream_list_pop(t, s, GRPC_CHTTP2_LIST_WRITING);
 }
 
-void grpc_chttp2_list_add_written_stream(
-    grpc_chttp2_transport_writing *transport_writing,
-    grpc_chttp2_stream_writing *stream_writing) {
-  stream_list_add(TRANSPORT_FROM_WRITING(transport_writing),
-                  STREAM_FROM_WRITING(stream_writing),
-                  GRPC_CHTTP2_LIST_WRITTEN);
+void grpc_chttp2_list_add_waiting_for_concurrency(grpc_chttp2_transport *t,
+                                                  grpc_chttp2_stream *s) {
+  stream_list_add(t, s, GRPC_CHTTP2_LIST_WAITING_FOR_CONCURRENCY);
 }
 
-int grpc_chttp2_list_pop_written_stream(
-    grpc_chttp2_transport_global *transport_global,
-    grpc_chttp2_transport_writing *transport_writing,
-    grpc_chttp2_stream_global **stream_global,
-    grpc_chttp2_stream_writing **stream_writing) {
-  grpc_chttp2_stream *stream;
-  int r = stream_list_pop(TRANSPORT_FROM_WRITING(transport_writing), &stream,
-                          GRPC_CHTTP2_LIST_WRITTEN);
-  if (r != 0) {
-    *stream_global = &stream->global;
-    *stream_writing = &stream->writing;
-  }
-  return r;
+int grpc_chttp2_list_pop_waiting_for_concurrency(grpc_chttp2_transport *t,
+                                                 grpc_chttp2_stream **s) {
+  return stream_list_pop(t, s, GRPC_CHTTP2_LIST_WAITING_FOR_CONCURRENCY);
 }
 
-void grpc_chttp2_list_add_unannounced_incoming_window_available(
-    grpc_chttp2_transport_global *transport_global,
-    grpc_chttp2_stream_global *stream_global) {
-  GPR_ASSERT(stream_global->id != 0);
-  stream_list_add(TRANSPORT_FROM_GLOBAL(transport_global),
-                  STREAM_FROM_GLOBAL(stream_global),
-                  GRPC_CHTTP2_LIST_UNANNOUNCED_INCOMING_WINDOW_AVAILABLE);
+void grpc_chttp2_list_add_stalled_by_transport(grpc_chttp2_transport *t,
+                                               grpc_chttp2_stream *s) {
+  stream_list_add(t, s, GRPC_CHTTP2_LIST_STALLED_BY_TRANSPORT);
 }
 
-void grpc_chttp2_list_remove_unannounced_incoming_window_available(
-    grpc_chttp2_transport_global *transport_global,
-    grpc_chttp2_stream_global *stream_global) {
-  stream_list_maybe_remove(
-      TRANSPORT_FROM_GLOBAL(transport_global),
-      STREAM_FROM_GLOBAL(stream_global),
-      GRPC_CHTTP2_LIST_UNANNOUNCED_INCOMING_WINDOW_AVAILABLE);
+int grpc_chttp2_list_pop_stalled_by_transport(grpc_chttp2_transport *t,
+                                              grpc_chttp2_stream **s) {
+  return stream_list_pop(t, s, GRPC_CHTTP2_LIST_STALLED_BY_TRANSPORT);
 }
 
-int grpc_chttp2_list_pop_unannounced_incoming_window_available(
-    grpc_chttp2_transport_global *transport_global,
-    grpc_chttp2_transport_parsing *transport_parsing,
-    grpc_chttp2_stream_global **stream_global,
-    grpc_chttp2_stream_parsing **stream_parsing) {
-  grpc_chttp2_stream *stream;
-  int r =
-      stream_list_pop(TRANSPORT_FROM_GLOBAL(transport_global), &stream,
-                      GRPC_CHTTP2_LIST_UNANNOUNCED_INCOMING_WINDOW_AVAILABLE);
-  if (r != 0) {
-    *stream_global = &stream->global;
-    *stream_parsing = &stream->parsing;
-  }
-  return r;
-}
-
-void grpc_chttp2_list_add_parsing_seen_stream(
-    grpc_chttp2_transport_parsing *transport_parsing,
-    grpc_chttp2_stream_parsing *stream_parsing) {
-  stream_list_add(TRANSPORT_FROM_PARSING(transport_parsing),
-                  STREAM_FROM_PARSING(stream_parsing),
-                  GRPC_CHTTP2_LIST_PARSING_SEEN);
-}
-
-int grpc_chttp2_list_pop_parsing_seen_stream(
-    grpc_chttp2_transport_global *transport_global,
-    grpc_chttp2_transport_parsing *transport_parsing,
-    grpc_chttp2_stream_global **stream_global,
-    grpc_chttp2_stream_parsing **stream_parsing) {
-  grpc_chttp2_stream *stream;
-  int r = stream_list_pop(TRANSPORT_FROM_PARSING(transport_parsing), &stream,
-                          GRPC_CHTTP2_LIST_PARSING_SEEN);
-  if (r != 0) {
-    *stream_global = &stream->global;
-    *stream_parsing = &stream->parsing;
-  }
-  return r;
-}
-
-void grpc_chttp2_list_add_waiting_for_concurrency(
-    grpc_chttp2_transport_global *transport_global,
-    grpc_chttp2_stream_global *stream_global) {
-  stream_list_add(TRANSPORT_FROM_GLOBAL(transport_global),
-                  STREAM_FROM_GLOBAL(stream_global),
-                  GRPC_CHTTP2_LIST_WAITING_FOR_CONCURRENCY);
-}
-
-int grpc_chttp2_list_pop_waiting_for_concurrency(
-    grpc_chttp2_transport_global *transport_global,
-    grpc_chttp2_stream_global **stream_global) {
-  grpc_chttp2_stream *stream;
-  int r = stream_list_pop(TRANSPORT_FROM_GLOBAL(transport_global), &stream,
-                          GRPC_CHTTP2_LIST_WAITING_FOR_CONCURRENCY);
-  if (r != 0) {
-    *stream_global = &stream->global;
-  }
-  return r;
-}
-
-void grpc_chttp2_list_add_check_read_ops(
-    grpc_chttp2_transport_global *transport_global,
-    grpc_chttp2_stream_global *stream_global) {
-  stream_list_add(TRANSPORT_FROM_GLOBAL(transport_global),
-                  STREAM_FROM_GLOBAL(stream_global),
-                  GRPC_CHTTP2_LIST_CHECK_READ_OPS);
-}
-
-bool grpc_chttp2_list_remove_check_read_ops(
-    grpc_chttp2_transport_global *transport_global,
-    grpc_chttp2_stream_global *stream_global) {
-  return stream_list_maybe_remove(TRANSPORT_FROM_GLOBAL(transport_global),
-                                  STREAM_FROM_GLOBAL(stream_global),
-                                  GRPC_CHTTP2_LIST_CHECK_READ_OPS);
-}
-
-int grpc_chttp2_list_pop_check_read_ops(
-    grpc_chttp2_transport_global *transport_global,
-    grpc_chttp2_stream_global **stream_global) {
-  grpc_chttp2_stream *stream;
-  int r = stream_list_pop(TRANSPORT_FROM_GLOBAL(transport_global), &stream,
-                          GRPC_CHTTP2_LIST_CHECK_READ_OPS);
-  if (r != 0) {
-    *stream_global = &stream->global;
-  }
-  return r;
-}
-
-void grpc_chttp2_list_add_writing_stalled_by_transport(
-    grpc_chttp2_transport_writing *transport_writing,
-    grpc_chttp2_stream_writing *stream_writing) {
-  grpc_chttp2_stream *stream = STREAM_FROM_WRITING(stream_writing);
-  gpr_log(GPR_DEBUG, "writing stalled %d", stream->global.id);
-  if (!stream->included[GRPC_CHTTP2_LIST_WRITING_STALLED_BY_TRANSPORT]) {
-    GRPC_CHTTP2_STREAM_REF(&stream->global, "chttp2_writing_stalled");
-  }
-  stream_list_add(TRANSPORT_FROM_WRITING(transport_writing), stream,
-                  GRPC_CHTTP2_LIST_WRITING_STALLED_BY_TRANSPORT);
-}
-
-bool grpc_chttp2_list_flush_writing_stalled_by_transport(
-    grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_writing *transport_writing) {
-  grpc_chttp2_stream *stream;
-  bool out = false;
-  grpc_chttp2_transport *transport = TRANSPORT_FROM_WRITING(transport_writing);
-  while (stream_list_pop(transport, &stream,
-                         GRPC_CHTTP2_LIST_WRITING_STALLED_BY_TRANSPORT)) {
-    gpr_log(GPR_DEBUG, "move %d from writing stalled to just stalled",
-            stream->global.id);
-    grpc_chttp2_list_add_stalled_by_transport(transport_writing,
-                                              &stream->writing);
-    GRPC_CHTTP2_STREAM_UNREF(exec_ctx, &stream->global,
-                             "chttp2_writing_stalled");
-    out = true;
-  }
-  return out;
-}
-
-void grpc_chttp2_list_add_stalled_by_transport(
-    grpc_chttp2_transport_writing *transport_writing,
-    grpc_chttp2_stream_writing *stream_writing) {
-  gpr_log(GPR_DEBUG, "stalled %d", stream_writing->id);
-  stream_list_add(TRANSPORT_FROM_WRITING(transport_writing),
-                  STREAM_FROM_WRITING(stream_writing),
-                  GRPC_CHTTP2_LIST_STALLED_BY_TRANSPORT);
-}
-
-int grpc_chttp2_list_pop_stalled_by_transport(
-    grpc_chttp2_transport_global *transport_global,
-    grpc_chttp2_stream_global **stream_global) {
-  grpc_chttp2_stream *stream;
-  int r = stream_list_pop(TRANSPORT_FROM_GLOBAL(transport_global), &stream,
-                          GRPC_CHTTP2_LIST_STALLED_BY_TRANSPORT);
-  if (r != 0) {
-    *stream_global = &stream->global;
-  }
-  return r;
-}
-
-void grpc_chttp2_list_remove_stalled_by_transport(
-    grpc_chttp2_transport_global *transport_global,
-    grpc_chttp2_stream_global *stream_global) {
-  stream_list_maybe_remove(TRANSPORT_FROM_GLOBAL(transport_global),
-                           STREAM_FROM_GLOBAL(stream_global),
-                           GRPC_CHTTP2_LIST_STALLED_BY_TRANSPORT);
-}
-
-void grpc_chttp2_list_add_closed_waiting_for_parsing(
-    grpc_chttp2_transport_global *transport_global,
-    grpc_chttp2_stream_global *stream_global) {
-  stream_list_add(TRANSPORT_FROM_GLOBAL(transport_global),
-                  STREAM_FROM_GLOBAL(stream_global),
-                  GRPC_CHTTP2_LIST_CLOSED_WAITING_FOR_PARSING);
-}
-
-int grpc_chttp2_list_pop_closed_waiting_for_parsing(
-    grpc_chttp2_transport_global *transport_global,
-    grpc_chttp2_stream_global **stream_global) {
-  grpc_chttp2_stream *stream;
-  int r = stream_list_pop(TRANSPORT_FROM_GLOBAL(transport_global), &stream,
-                          GRPC_CHTTP2_LIST_CLOSED_WAITING_FOR_PARSING);
-  if (r != 0) {
-    *stream_global = &stream->global;
-  }
-  return r;
-}
-
-void grpc_chttp2_list_add_closed_waiting_for_writing(
-    grpc_chttp2_transport_global *transport_global,
-    grpc_chttp2_stream_global *stream_global) {
-  stream_list_add(TRANSPORT_FROM_GLOBAL(transport_global),
-                  STREAM_FROM_GLOBAL(stream_global),
-                  GRPC_CHTTP2_LIST_CLOSED_WAITING_FOR_WRITING);
-}
-
-int grpc_chttp2_list_pop_closed_waiting_for_writing(
-    grpc_chttp2_transport_global *transport_global,
-    grpc_chttp2_stream_global **stream_global) {
-  grpc_chttp2_stream *stream;
-  int r = stream_list_pop(TRANSPORT_FROM_GLOBAL(transport_global), &stream,
-                          GRPC_CHTTP2_LIST_CLOSED_WAITING_FOR_WRITING);
-  if (r != 0) {
-    *stream_global = &stream->global;
-  }
-  return r;
-}
-
-void grpc_chttp2_register_stream(grpc_chttp2_transport *t,
-                                 grpc_chttp2_stream *s) {
-  stream_list_add_tail(t, s, GRPC_CHTTP2_LIST_ALL_STREAMS);
-}
-
-int grpc_chttp2_unregister_stream(grpc_chttp2_transport *t,
-                                  grpc_chttp2_stream *s) {
-  stream_list_maybe_remove(t, s, GRPC_CHTTP2_LIST_ALL_STREAMS);
-  return stream_list_empty(t, GRPC_CHTTP2_LIST_ALL_STREAMS);
-}
-
-int grpc_chttp2_has_streams(grpc_chttp2_transport *t) {
-  return !stream_list_empty(t, GRPC_CHTTP2_LIST_ALL_STREAMS);
-}
-
-void grpc_chttp2_for_all_streams(
-    grpc_chttp2_transport_global *transport_global, void *user_data,
-    void (*cb)(grpc_chttp2_transport_global *transport_global, void *user_data,
-               grpc_chttp2_stream_global *stream_global)) {
-  grpc_chttp2_stream *s;
-  grpc_chttp2_transport *t = TRANSPORT_FROM_GLOBAL(transport_global);
-  for (s = t->lists[GRPC_CHTTP2_LIST_ALL_STREAMS].head; s != NULL;
-       s = s->links[GRPC_CHTTP2_LIST_ALL_STREAMS].next) {
-    cb(transport_global, user_data, &s->global);
-  }
+void grpc_chttp2_list_remove_stalled_by_transport(grpc_chttp2_transport *t,
+                                                  grpc_chttp2_stream *s) {
+  stream_list_maybe_remove(t, s, GRPC_CHTTP2_LIST_STALLED_BY_TRANSPORT);
 }
diff --git a/src/core/ext/transport/chttp2/transport/stream_map.c b/src/core/ext/transport/chttp2/transport/stream_map.c
index f70791c..bd07412 100644
--- a/src/core/ext/transport/chttp2/transport/stream_map.c
+++ b/src/core/ext/transport/chttp2/transport/stream_map.c
@@ -77,6 +77,7 @@
 
   GPR_ASSERT(count == 0 || keys[count - 1] < key);
   GPR_ASSERT(value);
+  GPR_ASSERT(grpc_chttp2_stream_map_find(map, key) == NULL);
 
   if (count == capacity) {
     if (map->free > capacity / 4) {
@@ -170,6 +171,7 @@
     if (map->free == map->count) {
       map->free = map->count = 0;
     }
+    GPR_ASSERT(grpc_chttp2_stream_map_find(map, key) == NULL);
   }
   return out;
 }
diff --git a/src/core/ext/transport/chttp2/transport/writing.c b/src/core/ext/transport/chttp2/transport/writing.c
index 8f7a1f5..fbddb34 100644
--- a/src/core/ext/transport/chttp2/transport/writing.c
+++ b/src/core/ext/transport/chttp2/transport/writing.c
@@ -40,340 +40,207 @@
 #include "src/core/ext/transport/chttp2/transport/http2_errors.h"
 #include "src/core/lib/profiling/timers.h"
 
-static void finalize_outbuf(grpc_exec_ctx *exec_ctx,
-                            grpc_chttp2_transport_writing *transport_writing);
+static void add_to_write_list(grpc_chttp2_write_cb **list,
+                              grpc_chttp2_write_cb *cb) {
+  cb->next = *list;
+  *list = cb;
+}
 
-int grpc_chttp2_unlocking_check_writes(
-    grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_global *transport_global,
-    grpc_chttp2_transport_writing *transport_writing) {
-  grpc_chttp2_stream_global *stream_global;
-  grpc_chttp2_stream_writing *stream_writing;
+static void finish_write_cb(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t,
+                            grpc_chttp2_stream *s, grpc_chttp2_write_cb *cb,
+                            grpc_error *error) {
+  grpc_chttp2_complete_closure_step(exec_ctx, t, s, &cb->closure, error, "finish_write_cb");
+  cb->next = t->write_cb_pool;
+  t->write_cb_pool = cb;
+}
 
-  GPR_TIMER_BEGIN("grpc_chttp2_unlocking_check_writes", 0);
+static void update_list(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t,
+                        grpc_chttp2_stream *s, size_t send_bytes,
+                        grpc_chttp2_write_cb **list, grpc_error *error) {
+  grpc_chttp2_write_cb *cb = *list;
+  *list = NULL;
+  while (cb) {
+    grpc_chttp2_write_cb *next = cb->next;
+    if (cb->call_at_byte <= send_bytes) {
+      finish_write_cb(exec_ctx, t, s, cb, GRPC_ERROR_REF(error));
+    } else {
+      cb->call_at_byte -= send_bytes;
+      add_to_write_list(list, cb);
+    }
+    cb = next;
+  }
+}
 
-  /* simple writes are queued to qbuf, and flushed here */
-  gpr_slice_buffer_swap(&transport_global->qbuf, &transport_writing->outbuf);
-  GPR_ASSERT(transport_global->qbuf.count == 0);
+bool grpc_chttp2_begin_write(grpc_exec_ctx *exec_ctx,
+                             grpc_chttp2_transport *t) {
+  grpc_chttp2_stream *s;
 
-  grpc_chttp2_hpack_compressor_set_max_table_size(
-      &transport_writing->hpack_compressor,
-      transport_global->settings[GRPC_PEER_SETTINGS]
-                                [GRPC_CHTTP2_SETTINGS_HEADER_TABLE_SIZE]);
+  GPR_TIMER_BEGIN("grpc_chttp2_begin_write", 0);
 
-  if (transport_global->dirtied_local_settings &&
-      !transport_global->sent_local_settings) {
+  if (t->dirtied_local_settings && !t->sent_local_settings) {
     gpr_slice_buffer_add(
-        &transport_writing->outbuf,
+        &t->outbuf,
         grpc_chttp2_settings_create(
-            transport_global->settings[GRPC_SENT_SETTINGS],
-            transport_global->settings[GRPC_LOCAL_SETTINGS],
-            transport_global->force_send_settings, GRPC_CHTTP2_NUM_SETTINGS));
-    transport_global->force_send_settings = 0;
-    transport_global->dirtied_local_settings = 0;
-    transport_global->sent_local_settings = 1;
+            t->settings[GRPC_SENT_SETTINGS], t->settings[GRPC_LOCAL_SETTINGS],
+            t->force_send_settings, GRPC_CHTTP2_NUM_SETTINGS));
+    t->force_send_settings = 0;
+    t->dirtied_local_settings = 0;
+    t->sent_local_settings = 1;
   }
 
-  GRPC_CHTTP2_FLOW_MOVE_TRANSPORT("write", transport_writing, outgoing_window,
-                                  transport_global, outgoing_window);
-  if (transport_writing->outgoing_window > 0) {
-    while (grpc_chttp2_list_pop_stalled_by_transport(transport_global,
-                                                     &stream_global)) {
-      grpc_chttp2_become_writable(exec_ctx, transport_global, stream_global,
-                                  false, "transport.read_flow_control");
+  /* simple writes are queued to qbuf, and flushed here */
+  gpr_slice_buffer_move_into(&t->qbuf, &t->outbuf);
+  GPR_ASSERT(t->qbuf.count == 0);
+
+  grpc_chttp2_hpack_compressor_set_max_table_size(
+      &t->hpack_compressor,
+      t->settings[GRPC_PEER_SETTINGS][GRPC_CHTTP2_SETTINGS_HEADER_TABLE_SIZE]);
+
+  if (t->outgoing_window > 0) {
+    while (grpc_chttp2_list_pop_stalled_by_transport(t, &s)) {
+      grpc_chttp2_become_writable(exec_ctx, t, s, false,
+                                  "transport.read_flow_control");
     }
   }
 
   /* for each grpc_chttp2_stream that's become writable, frame it's data
      (according to available window sizes) and add to the output buffer */
-  while (grpc_chttp2_list_pop_writable_stream(
-      transport_global, transport_writing, &stream_global, &stream_writing)) {
-    bool sent_initial_metadata = stream_writing->sent_initial_metadata;
-    bool become_writable = false;
+  while (grpc_chttp2_list_pop_writable_stream(t, &s)) {
+    bool sent_initial_metadata = s->sent_initial_metadata;
+    bool now_writing = false;
 
-    stream_writing->id = stream_global->id;
-    stream_writing->read_closed = stream_global->read_closed;
+    GRPC_CHTTP2_IF_TRACING(gpr_log(GPR_DEBUG, "W:%p %s[%d] im-(sent,send)=(%d,%d) announce=%d", t, t->is_client?"CLIENT":"SERVER", s->id, sent_initial_metadata, s->send_initial_metadata!=NULL, s->announce_window));
 
-    GRPC_CHTTP2_FLOW_MOVE_STREAM("write", transport_writing, stream_writing,
-                                 outgoing_window, stream_global,
-                                 outgoing_window);
-
-    if (!sent_initial_metadata && stream_global->send_initial_metadata) {
-      stream_writing->send_initial_metadata =
-          stream_global->send_initial_metadata;
-      stream_global->send_initial_metadata = NULL;
-      become_writable = true;
+    /* send initial metadata if it's available */
+    if (!sent_initial_metadata && s->send_initial_metadata) {
+      grpc_chttp2_encode_header(&t->hpack_compressor, s->id,
+                                s->send_initial_metadata, 0, &s->stats.outgoing,
+                                &t->outbuf);
+      s->send_initial_metadata = NULL;
+      s->sent_initial_metadata = true;
       sent_initial_metadata = true;
+      now_writing = true;
+    }
+    /* send any window updates */
+    if (s->announce_window > 0) {
+      uint32_t announce = s->announce_window;
+      gpr_slice_buffer_add(&t->outbuf,
+                           grpc_chttp2_window_update_create(
+                               s->id, s->announce_window, &s->stats.outgoing));
+      GRPC_CHTTP2_FLOW_DEBIT_STREAM("write", t, s, announce_window, announce);
     }
     if (sent_initial_metadata) {
-      if (stream_global->send_message != NULL) {
-        gpr_slice hdr = gpr_slice_malloc(5);
-        uint8_t *p = GPR_SLICE_START_PTR(hdr);
-        uint32_t len = stream_global->send_message->length;
-        GPR_ASSERT(stream_writing->send_message == NULL);
-        p[0] = (stream_global->send_message->flags &
-                GRPC_WRITE_INTERNAL_COMPRESS) != 0;
-        p[1] = (uint8_t)(len >> 24);
-        p[2] = (uint8_t)(len >> 16);
-        p[3] = (uint8_t)(len >> 8);
-        p[4] = (uint8_t)(len);
-        gpr_slice_buffer_add(&stream_writing->flow_controlled_buffer, hdr);
-        if (stream_global->send_message->length > 0) {
-          stream_writing->send_message = stream_global->send_message;
-        } else {
-          stream_writing->send_message = NULL;
-        }
-        stream_writing->stream_fetched = 0;
-        stream_global->send_message = NULL;
-      }
-      if ((stream_writing->send_message != NULL ||
-           stream_writing->flow_controlled_buffer.length > 0) &&
-          stream_writing->outgoing_window > 0) {
-        if (transport_writing->outgoing_window > 0) {
-          become_writable = true;
-        } else {
-          grpc_chttp2_list_add_stalled_by_transport(transport_writing,
-                                                    stream_writing);
+      /* send any body bytes, if allowed by flow control */
+      if (s->flow_controlled_buffer.length > 0) {
+        uint32_t max_outgoing =
+            (uint32_t)GPR_MIN(GRPC_CHTTP2_MAX_PAYLOAD_LENGTH,
+                              GPR_MIN(s->outgoing_window, t->outgoing_window));
+        if (max_outgoing > 0) {
+          uint32_t send_bytes =
+              (uint32_t)GPR_MIN(max_outgoing, s->flow_controlled_buffer.length);
+          bool is_last_data_frame =
+              s->fetching_send_message == NULL &&
+              send_bytes == s->flow_controlled_buffer.length;
+          bool is_last_frame =
+              is_last_data_frame && s->send_trailing_metadata != NULL &&
+              grpc_metadata_batch_is_empty(s->send_trailing_metadata);
+          grpc_chttp2_encode_data(s->id, &s->flow_controlled_buffer, send_bytes,
+                                  is_last_frame, &s->stats.outgoing,
+                                  &t->outbuf);
+          GRPC_CHTTP2_FLOW_DEBIT_STREAM("write", t, s, outgoing_window,
+                                        send_bytes);
+          GRPC_CHTTP2_FLOW_DEBIT_TRANSPORT("write", t, outgoing_window,
+                                           send_bytes);
+          if (is_last_frame) {
+            s->send_trailing_metadata = NULL;
+            s->sent_trailing_metadata = true;
+            if (!t->is_client && !s->read_closed) {
+              gpr_slice_buffer_add(&t->outbuf, grpc_chttp2_rst_stream_create(
+                                                   s->id, GRPC_CHTTP2_NO_ERROR,
+                                                   &s->stats.outgoing));
+            }
+          }
+          s->sending_bytes += send_bytes;
+          now_writing = true;
+          if (s->flow_controlled_buffer.length > 0) {
+            GRPC_CHTTP2_STREAM_REF(s, "chttp2_writing:fork");
+            grpc_chttp2_list_add_writable_stream(t, s);
+          }
+        } else if (t->outgoing_window == 0) {
+          grpc_chttp2_list_add_stalled_by_transport(t, s);
+          now_writing = true;
         }
       }
-      if (stream_global->send_trailing_metadata) {
-        stream_writing->send_trailing_metadata =
-            stream_global->send_trailing_metadata;
-        stream_global->send_trailing_metadata = NULL;
-        become_writable = true;
+      if (s->send_trailing_metadata != NULL &&
+          s->fetching_send_message == NULL &&
+          s->flow_controlled_buffer.length == 0) {
+        grpc_chttp2_encode_header(&t->hpack_compressor, s->id,
+                                  s->send_trailing_metadata, true,
+                                  &s->stats.outgoing, &t->outbuf);
+        s->send_trailing_metadata = NULL;
+        s->sent_trailing_metadata = true;
+        if (!t->is_client && !s->read_closed) {
+          gpr_slice_buffer_add(
+              &t->outbuf, grpc_chttp2_rst_stream_create(
+                              s->id, GRPC_CHTTP2_NO_ERROR, &s->stats.outgoing));
+        }
+        now_writing = true;
       }
     }
 
-    if (!stream_global->read_closed &&
-        stream_global->unannounced_incoming_window_for_writing > 1024) {
-      GRPC_CHTTP2_FLOW_MOVE_STREAM("write", transport_global, stream_writing,
-                                   announce_window, stream_global,
-                                   unannounced_incoming_window_for_writing);
-      become_writable = true;
-    }
-
-    if (become_writable) {
-      grpc_chttp2_list_add_writing_stream(transport_writing, stream_writing);
+    if (now_writing) {
+      if (!grpc_chttp2_list_add_writing_stream(t, s)) {
+        /* already in writing list: drop ref */
+        GRPC_CHTTP2_STREAM_UNREF(exec_ctx, s, "chttp2_writing:already_writing");
+      }
     } else {
-      GRPC_CHTTP2_STREAM_UNREF(exec_ctx, stream_global, "chttp2_writing");
+      GRPC_CHTTP2_STREAM_UNREF(exec_ctx, s, "chttp2_writing:no_write");
     }
   }
 
   /* if the grpc_chttp2_transport is ready to send a window update, do so here
      also; 3/4 is a magic number that will likely get tuned soon */
-  if (transport_global->announce_incoming_window > 0) {
-    uint32_t announced = (uint32_t)GPR_MIN(
-        transport_global->announce_incoming_window, UINT32_MAX);
-    GRPC_CHTTP2_FLOW_DEBIT_TRANSPORT("write", transport_global,
-                                     announce_incoming_window, announced);
+  if (t->announce_incoming_window > 0) {
+    uint32_t announced =
+        (uint32_t)GPR_MIN(t->announce_incoming_window, UINT32_MAX);
+    GRPC_CHTTP2_FLOW_DEBIT_TRANSPORT("write", t, announce_incoming_window,
+                                     announced);
     grpc_transport_one_way_stats throwaway_stats;
-    gpr_slice_buffer_add(
-        &transport_writing->outbuf,
-        grpc_chttp2_window_update_create(0, announced, &throwaway_stats));
+    gpr_slice_buffer_add(&t->outbuf, grpc_chttp2_window_update_create(
+                                         0, announced, &throwaway_stats));
   }
 
-  GPR_TIMER_END("grpc_chttp2_unlocking_check_writes", 0);
+  GPR_TIMER_END("grpc_chttp2_begin_write", 0);
 
-  return transport_writing->outbuf.count > 0 ||
-         grpc_chttp2_list_have_writing_streams(transport_writing);
+  return t->outbuf.count > 0;
 }
 
-void grpc_chttp2_perform_writes(
-    grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_writing *transport_writing,
-    grpc_endpoint *endpoint) {
-  GPR_ASSERT(transport_writing->outbuf.count > 0 ||
-             grpc_chttp2_list_have_writing_streams(transport_writing));
+void grpc_chttp2_end_write(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t,
+                           grpc_error *error) {
+  GPR_TIMER_BEGIN("grpc_chttp2_end_write", 0);
+  grpc_chttp2_stream *s;
 
-  finalize_outbuf(exec_ctx, transport_writing);
-
-  GPR_ASSERT(endpoint);
-
-  if (transport_writing->outbuf.count > 0) {
-    grpc_endpoint_write(exec_ctx, endpoint, &transport_writing->outbuf,
-                        &transport_writing->done_cb);
-  } else {
-    grpc_exec_ctx_sched(exec_ctx, &transport_writing->done_cb, GRPC_ERROR_NONE,
-                        NULL);
+  while (grpc_chttp2_list_pop_writing_stream(t, &s)) {
+    if (s->sent_initial_metadata) {
+      grpc_chttp2_complete_closure_step(exec_ctx, t, s,
+                                        &s->send_initial_metadata_finished,
+                                        GRPC_ERROR_REF(error), "send_initial_metadata_finished");
+    }
+    if (s->sending_bytes != 0) {
+      update_list(exec_ctx, t, s, s->sending_bytes, &s->on_write_finished_cbs,
+                  GRPC_ERROR_REF(error));
+      s->sending_bytes = 0;
+    }
+    if (s->sent_trailing_metadata) {
+      grpc_chttp2_complete_closure_step(exec_ctx, t, s,
+                                        &s->send_trailing_metadata_finished,
+                                        GRPC_ERROR_REF(error), "send_trailing_metadata_finished");
+      grpc_chttp2_mark_stream_closed(exec_ctx, t, s, !t->is_client, 1,
+                                     GRPC_ERROR_REF(error));
+    }
+    GRPC_CHTTP2_STREAM_UNREF(exec_ctx, s, "chttp2_writing:end");
   }
-}
-
-static void finalize_outbuf(grpc_exec_ctx *exec_ctx,
-                            grpc_chttp2_transport_writing *transport_writing) {
-  grpc_chttp2_stream_writing *stream_writing;
-
-  GPR_TIMER_BEGIN("finalize_outbuf", 0);
-
-  bool is_first_data_frame = true;
-  while (
-      grpc_chttp2_list_pop_writing_stream(transport_writing, &stream_writing)) {
-    uint32_t max_outgoing =
-        (uint32_t)GPR_MIN(GRPC_CHTTP2_MAX_PAYLOAD_LENGTH,
-                          GPR_MIN(stream_writing->outgoing_window,
-                                  transport_writing->outgoing_window));
-    /* send initial metadata if it's available */
-    if (stream_writing->send_initial_metadata != NULL) {
-      grpc_chttp2_encode_header(
-          &transport_writing->hpack_compressor, stream_writing->id,
-          stream_writing->send_initial_metadata, 0, &stream_writing->stats,
-          &transport_writing->outbuf);
-      stream_writing->send_initial_metadata = NULL;
-      stream_writing->sent_initial_metadata = 1;
-    }
-    /* send any window updates */
-    if (stream_writing->announce_window > 0 &&
-        stream_writing->send_initial_metadata == NULL) {
-      uint32_t announce = stream_writing->announce_window;
-      gpr_slice_buffer_add(
-          &transport_writing->outbuf,
-          grpc_chttp2_window_update_create(stream_writing->id,
-                                           stream_writing->announce_window,
-                                           &stream_writing->stats));
-      GRPC_CHTTP2_FLOW_DEBIT_STREAM("write", transport_writing, stream_writing,
-                                    announce_window, announce);
-      stream_writing->announce_window = 0;
-    }
-    /* fetch any body bytes */
-    while (!stream_writing->fetching && stream_writing->send_message &&
-           stream_writing->flow_controlled_buffer.length < max_outgoing &&
-           stream_writing->stream_fetched <
-               stream_writing->send_message->length) {
-      if (grpc_byte_stream_next(exec_ctx, stream_writing->send_message,
-                                &stream_writing->fetching_slice, max_outgoing,
-                                &stream_writing->finished_fetch)) {
-        stream_writing->stream_fetched +=
-            GPR_SLICE_LENGTH(stream_writing->fetching_slice);
-        if (stream_writing->stream_fetched ==
-            stream_writing->send_message->length) {
-          stream_writing->send_message = NULL;
-        }
-        gpr_slice_buffer_add(&stream_writing->flow_controlled_buffer,
-                             stream_writing->fetching_slice);
-      } else {
-        stream_writing->fetching = 1;
-      }
-    }
-    /* send any body bytes */
-    if (stream_writing->flow_controlled_buffer.length > 0) {
-      if (max_outgoing > 0) {
-        uint32_t send_bytes = (uint32_t)GPR_MIN(
-            max_outgoing, stream_writing->flow_controlled_buffer.length);
-        int is_last_data_frame =
-            stream_writing->send_message == NULL &&
-            send_bytes == stream_writing->flow_controlled_buffer.length;
-        int is_last_frame = is_last_data_frame &&
-                            stream_writing->send_trailing_metadata != NULL &&
-                            grpc_metadata_batch_is_empty(
-                                stream_writing->send_trailing_metadata);
-        grpc_chttp2_encode_data(
-            stream_writing->id, &stream_writing->flow_controlled_buffer,
-            send_bytes, is_last_frame, &stream_writing->stats,
-            &transport_writing->outbuf);
-        if (is_first_data_frame) {
-          /* TODO(dgq): this is a hack. It'll be fix in a future refactoring */
-          stream_writing->stats.data_bytes -= 5; /* discount grpc framing */
-          is_first_data_frame = false;
-        }
-        GRPC_CHTTP2_FLOW_DEBIT_STREAM("write", transport_writing,
-                                      stream_writing, outgoing_window,
-                                      send_bytes);
-        GRPC_CHTTP2_FLOW_DEBIT_TRANSPORT("write", transport_writing,
-                                         outgoing_window, send_bytes);
-        if (is_last_frame) {
-          stream_writing->send_trailing_metadata = NULL;
-          stream_writing->sent_trailing_metadata = 1;
-        }
-        if (is_last_data_frame) {
-          GPR_ASSERT(stream_writing->send_message == NULL);
-          stream_writing->sent_message = 1;
-        }
-      } else if (transport_writing->outgoing_window == 0) {
-        grpc_chttp2_list_add_writing_stalled_by_transport(transport_writing,
-                                                          stream_writing);
-        grpc_chttp2_list_add_written_stream(transport_writing, stream_writing);
-      }
-    }
-    /* send trailing metadata if it's available and we're ready for it */
-    if (stream_writing->send_message == NULL &&
-        stream_writing->flow_controlled_buffer.length == 0 &&
-        stream_writing->send_trailing_metadata != NULL) {
-      if (grpc_metadata_batch_is_empty(
-              stream_writing->send_trailing_metadata)) {
-        grpc_chttp2_encode_data(
-            stream_writing->id, &stream_writing->flow_controlled_buffer, 0, 1,
-            &stream_writing->stats, &transport_writing->outbuf);
-      } else {
-        grpc_chttp2_encode_header(
-            &transport_writing->hpack_compressor, stream_writing->id,
-            stream_writing->send_trailing_metadata, 1, &stream_writing->stats,
-            &transport_writing->outbuf);
-      }
-      if (!transport_writing->is_client && !stream_writing->read_closed) {
-        gpr_slice_buffer_add(&transport_writing->outbuf,
-                             grpc_chttp2_rst_stream_create(
-                                 stream_writing->id, GRPC_CHTTP2_NO_ERROR,
-                                 &stream_writing->stats));
-      }
-      stream_writing->send_trailing_metadata = NULL;
-      stream_writing->sent_trailing_metadata = 1;
-    }
-    /* if there's more to write, then loop, otherwise prepare to finish the
-     * write */
-    if ((stream_writing->flow_controlled_buffer.length > 0 ||
-         (stream_writing->send_message && !stream_writing->fetching)) &&
-        stream_writing->outgoing_window > 0) {
-      if (transport_writing->outgoing_window > 0) {
-        grpc_chttp2_list_add_writing_stream(transport_writing, stream_writing);
-      } else {
-        grpc_chttp2_list_add_writing_stalled_by_transport(transport_writing,
-                                                          stream_writing);
-        grpc_chttp2_list_add_written_stream(transport_writing, stream_writing);
-      }
-    } else {
-      grpc_chttp2_list_add_written_stream(transport_writing, stream_writing);
-    }
-  }
-
-  GPR_TIMER_END("finalize_outbuf", 0);
-}
-
-void grpc_chttp2_cleanup_writing(
-    grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_global *transport_global,
-    grpc_chttp2_transport_writing *transport_writing) {
-  grpc_chttp2_stream_writing *stream_writing;
-  grpc_chttp2_stream_global *stream_global;
-
-  if (grpc_chttp2_list_flush_writing_stalled_by_transport(exec_ctx,
-                                                          transport_writing)) {
-    grpc_chttp2_initiate_write(exec_ctx, transport_global, false,
-                               "resume_stalled_stream");
-  }
-
-  while (grpc_chttp2_list_pop_written_stream(
-      transport_global, transport_writing, &stream_global, &stream_writing)) {
-    if (stream_writing->sent_initial_metadata) {
-      grpc_chttp2_complete_closure_step(
-          exec_ctx, transport_global, stream_global,
-          &stream_global->send_initial_metadata_finished, GRPC_ERROR_NONE);
-    }
-    grpc_transport_move_one_way_stats(&stream_writing->stats,
-                                      &stream_global->stats.outgoing);
-    if (stream_writing->sent_message) {
-      GPR_ASSERT(stream_writing->send_message == NULL);
-      grpc_chttp2_complete_closure_step(
-          exec_ctx, transport_global, stream_global,
-          &stream_global->send_message_finished, GRPC_ERROR_NONE);
-      stream_writing->sent_message = 0;
-    }
-    if (stream_writing->sent_trailing_metadata) {
-      grpc_chttp2_complete_closure_step(
-          exec_ctx, transport_global, stream_global,
-          &stream_global->send_trailing_metadata_finished, GRPC_ERROR_NONE);
-    }
-    if (stream_writing->sent_trailing_metadata) {
-      grpc_chttp2_mark_stream_closed(exec_ctx, transport_global, stream_global,
-                                     !transport_global->is_client, 1,
-                                     GRPC_ERROR_NONE);
-    }
-    GRPC_CHTTP2_STREAM_UNREF(exec_ctx, stream_global, "chttp2_writing");
-  }
-  gpr_slice_buffer_reset_and_unref(&transport_writing->outbuf);
+  gpr_slice_buffer_reset_and_unref(&t->outbuf);
+  GRPC_ERROR_UNREF(error);
+  GPR_TIMER_END("grpc_chttp2_end_write", 0);
 }
diff --git a/src/core/lib/channel/channel_stack.c b/src/core/lib/channel/channel_stack.c
index 98f304f..0655b93 100644
--- a/src/core/lib/channel/channel_stack.c
+++ b/src/core/lib/channel/channel_stack.c
@@ -32,6 +32,7 @@
  */
 
 #include "src/core/lib/channel/channel_stack.h"
+#include <grpc/support/alloc.h>
 #include <grpc/support/log.h>
 
 #include <stdlib.h>
@@ -270,21 +271,27 @@
       sizeof(grpc_call_stack)));
 }
 
+static void destroy_op(grpc_exec_ctx *exec_ctx, void *op, grpc_error *error) {
+  gpr_free(op);
+}
+
 void grpc_call_element_send_cancel(grpc_exec_ctx *exec_ctx,
                                    grpc_call_element *cur_elem) {
-  grpc_transport_stream_op op;
-  memset(&op, 0, sizeof(op));
-  op.cancel_error = GRPC_ERROR_CANCELLED;
-  grpc_call_next_op(exec_ctx, cur_elem, &op);
+  grpc_transport_stream_op *op = gpr_malloc(sizeof(*op));
+  memset(op, 0, sizeof(*op));
+  op->cancel_error = GRPC_ERROR_CANCELLED;
+  op->on_complete = grpc_closure_create(destroy_op, op);
+  grpc_call_next_op(exec_ctx, cur_elem, op);
 }
 
 void grpc_call_element_send_cancel_with_message(grpc_exec_ctx *exec_ctx,
                                                 grpc_call_element *cur_elem,
                                                 grpc_status_code status,
                                                 gpr_slice *optional_message) {
-  grpc_transport_stream_op op;
-  memset(&op, 0, sizeof(op));
-  grpc_transport_stream_op_add_cancellation_with_message(&op, status,
+  grpc_transport_stream_op *op = gpr_malloc(sizeof(*op));
+  memset(op, 0, sizeof(*op));
+  op->on_complete = grpc_closure_create(destroy_op, op);
+  grpc_transport_stream_op_add_cancellation_with_message(op, status,
                                                          optional_message);
-  grpc_call_next_op(exec_ctx, cur_elem, &op);
+  grpc_call_next_op(exec_ctx, cur_elem, op);
 }
diff --git a/src/core/lib/channel/compress_filter.c b/src/core/lib/channel/compress_filter.c
index 134180e..0981d59 100644
--- a/src/core/lib/channel/compress_filter.c
+++ b/src/core/lib/channel/compress_filter.c
@@ -60,7 +60,7 @@
   /** If true, contents of \a compression_algorithm are authoritative */
   int has_compression_algorithm;
 
-  grpc_transport_stream_op send_op;
+  grpc_transport_stream_op *send_op;
   uint32_t send_length;
   uint32_t send_flags;
   gpr_slice incoming_slice;
@@ -199,11 +199,11 @@
 
   grpc_slice_buffer_stream_init(&calld->replacement_stream, &calld->slices,
                                 calld->send_flags);
-  calld->send_op.send_message = &calld->replacement_stream.base;
-  calld->post_send = calld->send_op.on_complete;
-  calld->send_op.on_complete = &calld->send_done;
+  calld->send_op->send_message = &calld->replacement_stream.base;
+  calld->post_send = calld->send_op->on_complete;
+  calld->send_op->on_complete = &calld->send_done;
 
-  grpc_call_next_op(exec_ctx, elem, &calld->send_op);
+  grpc_call_next_op(exec_ctx, elem, calld->send_op);
 }
 
 static void got_slice(grpc_exec_ctx *exec_ctx, void *elemp, grpc_error *error) {
@@ -220,7 +220,7 @@
 static void continue_send_message(grpc_exec_ctx *exec_ctx,
                                   grpc_call_element *elem) {
   call_data *calld = elem->call_data;
-  while (grpc_byte_stream_next(exec_ctx, calld->send_op.send_message,
+  while (grpc_byte_stream_next(exec_ctx, calld->send_op->send_message,
                                &calld->incoming_slice, ~(size_t)0,
                                &calld->got_slice)) {
     gpr_slice_buffer_add(&calld->slices, calld->incoming_slice);
@@ -243,7 +243,7 @@
   }
   if (op->send_message != NULL && !skip_compression(elem) &&
       0 == (op->send_message->flags & GRPC_WRITE_NO_COMPRESS)) {
-    calld->send_op = *op;
+    calld->send_op = op;
     calld->send_length = op->send_message->length;
     calld->send_flags = op->send_message->flags;
     continue_send_message(exec_ctx, elem);
diff --git a/src/core/lib/channel/http_client_filter.c b/src/core/lib/channel/http_client_filter.c
index a7a775c..ef68cc8 100644
--- a/src/core/lib/channel/http_client_filter.c
+++ b/src/core/lib/channel/http_client_filter.c
@@ -43,6 +43,9 @@
 #define EXPECTED_CONTENT_TYPE "application/grpc"
 #define EXPECTED_CONTENT_TYPE_LENGTH sizeof(EXPECTED_CONTENT_TYPE) - 1
 
+/* default maximum size of payload eligable for GET request */
+static const size_t kMaxPayloadSizeForGet = 2048;
+
 typedef struct call_data {
   grpc_linked_mdelem method;
   grpc_linked_mdelem scheme;
@@ -50,20 +53,39 @@
   grpc_linked_mdelem te_trailers;
   grpc_linked_mdelem content_type;
   grpc_linked_mdelem user_agent;
+  grpc_linked_mdelem payload_bin;
 
   grpc_metadata_batch *recv_initial_metadata;
+  uint8_t *payload_bytes;
+
+  /* Vars to read data off of send_message */
+  grpc_transport_stream_op send_op;
+  uint32_t send_length;
+  uint32_t send_flags;
+  gpr_slice incoming_slice;
+  grpc_slice_buffer_stream replacement_stream;
+  gpr_slice_buffer slices;
+  /* flag that indicates that all slices of send_messages aren't availble */
+  bool send_message_blocked;
 
   /** Closure to call when finished with the hc_on_recv hook */
   grpc_closure *on_done_recv;
+  grpc_closure *on_complete;
+  grpc_closure *post_send;
+
   /** Receive closures are chained: we inject this closure as the on_done_recv
       up-call on transport_op, and remember to call our on_done_recv member
       after handling it. */
   grpc_closure hc_on_recv;
+  grpc_closure hc_on_complete;
+  grpc_closure got_slice;
+  grpc_closure send_done;
 } call_data;
 
 typedef struct channel_data {
   grpc_mdelem *static_scheme;
   grpc_mdelem *user_agent;
+  size_t max_payload_size_for_get;
 } channel_data;
 
 typedef struct {
@@ -119,6 +141,24 @@
   calld->on_done_recv->cb(exec_ctx, calld->on_done_recv->cb_arg, error);
 }
 
+static void hc_on_complete(grpc_exec_ctx *exec_ctx, void *user_data,
+                           grpc_error *error) {
+  grpc_call_element *elem = user_data;
+  call_data *calld = elem->call_data;
+  if (calld->payload_bytes) {
+    gpr_free(calld->payload_bytes);
+    calld->payload_bytes = NULL;
+  }
+  calld->on_complete->cb(exec_ctx, calld->on_complete->cb_arg, error);
+}
+
+static void send_done(grpc_exec_ctx *exec_ctx, void *elemp, grpc_error *error) {
+  grpc_call_element *elem = elemp;
+  call_data *calld = elem->call_data;
+  gpr_slice_buffer_reset_and_unref(&calld->slices);
+  calld->post_send->cb(exec_ctx, calld->post_send->cb_arg, error);
+}
+
 static grpc_mdelem *client_strip_filter(void *user_data, grpc_mdelem *md) {
   /* eat the things we'd like to set ourselves */
   if (md->key == GRPC_MDSTR_METHOD) return NULL;
@@ -129,22 +169,105 @@
   return md;
 }
 
-static void hc_mutate_op(grpc_call_element *elem,
+static void continue_send_message(grpc_exec_ctx *exec_ctx,
+                                  grpc_call_element *elem) {
+  call_data *calld = elem->call_data;
+  uint8_t *wrptr = calld->payload_bytes;
+  while (grpc_byte_stream_next(exec_ctx, calld->send_op.send_message,
+                               &calld->incoming_slice, ~(size_t)0,
+                               &calld->got_slice)) {
+    memcpy(wrptr, GPR_SLICE_START_PTR(calld->incoming_slice),
+           GPR_SLICE_LENGTH(calld->incoming_slice));
+    wrptr += GPR_SLICE_LENGTH(calld->incoming_slice);
+    gpr_slice_buffer_add(&calld->slices, calld->incoming_slice);
+    if (calld->send_length == calld->slices.length) {
+      calld->send_message_blocked = false;
+      break;
+    }
+  }
+}
+
+static void got_slice(grpc_exec_ctx *exec_ctx, void *elemp, grpc_error *error) {
+  grpc_call_element *elem = elemp;
+  call_data *calld = elem->call_data;
+  calld->send_message_blocked = false;
+  gpr_slice_buffer_add(&calld->slices, calld->incoming_slice);
+  if (calld->send_length == calld->slices.length) {
+    /* Pass down the original send_message op that was blocked.*/
+    grpc_slice_buffer_stream_init(&calld->replacement_stream, &calld->slices,
+                                  calld->send_flags);
+    calld->send_op.send_message = &calld->replacement_stream.base;
+    calld->post_send = calld->send_op.on_complete;
+    calld->send_op.on_complete = &calld->send_done;
+    grpc_call_next_op(exec_ctx, elem, &calld->send_op);
+  } else {
+    continue_send_message(exec_ctx, elem);
+  }
+}
+
+static void hc_mutate_op(grpc_exec_ctx *exec_ctx, grpc_call_element *elem,
                          grpc_transport_stream_op *op) {
   /* grab pointers to our data from the call element */
   call_data *calld = elem->call_data;
   channel_data *channeld = elem->channel_data;
+
   if (op->send_initial_metadata != NULL) {
+    /* Decide which HTTP VERB to use. We use GET if the request is marked
+    cacheable, and the operation contains both initial metadata and send
+    message, and the payload is below the size threshold, and all the data
+    for this request is immediately available. */
+    grpc_mdelem *method = GRPC_MDELEM_METHOD_POST;
+    calld->send_message_blocked = false;
+    if ((op->send_initial_metadata_flags &
+         GRPC_INITIAL_METADATA_CACHEABLE_REQUEST) &&
+        op->send_message != NULL &&
+        op->send_message->length < channeld->max_payload_size_for_get) {
+      method = GRPC_MDELEM_METHOD_GET;
+      calld->send_message_blocked = true;
+    } else if (op->send_initial_metadata_flags &
+               GRPC_INITIAL_METADATA_IDEMPOTENT_REQUEST) {
+      method = GRPC_MDELEM_METHOD_PUT;
+    }
+
+    /* Attempt to read the data from send_message and create a header field. */
+    if (method == GRPC_MDELEM_METHOD_GET) {
+      /* allocate memory to hold the entire payload */
+      calld->payload_bytes = gpr_malloc(op->send_message->length);
+      GPR_ASSERT(calld->payload_bytes);
+
+      /* read slices of send_message and copy into payload_bytes */
+      calld->send_op = *op;
+      calld->send_length = op->send_message->length;
+      calld->send_flags = op->send_message->flags;
+      continue_send_message(exec_ctx, elem);
+
+      if (calld->send_message_blocked == false) {
+        /* when all the send_message data is available, then create a MDELEM and
+        append to headers */
+        grpc_mdelem *payload_bin = grpc_mdelem_from_metadata_strings(
+            GRPC_MDSTR_GRPC_PAYLOAD_BIN,
+            grpc_mdstr_from_buffer(calld->payload_bytes,
+                                   op->send_message->length));
+        grpc_metadata_batch_add_tail(op->send_initial_metadata,
+                                     &calld->payload_bin, payload_bin);
+        calld->on_complete = op->on_complete;
+        op->on_complete = &calld->hc_on_complete;
+        op->send_message = NULL;
+      } else {
+        /* Not all data is available. Fall back to POST. */
+        gpr_log(GPR_DEBUG,
+                "Request is marked Cacheable but not all data is available.\
+                            Falling back to POST");
+        method = GRPC_MDELEM_METHOD_POST;
+      }
+    }
+
     grpc_metadata_batch_filter(op->send_initial_metadata, client_strip_filter,
                                elem);
     /* Send : prefixed headers, which have to be before any application
        layer headers. */
-    grpc_metadata_batch_add_head(
-        op->send_initial_metadata, &calld->method,
-        op->send_initial_metadata_flags &
-                GRPC_INITIAL_METADATA_IDEMPOTENT_REQUEST
-            ? GRPC_MDELEM_METHOD_PUT
-            : GRPC_MDELEM_METHOD_POST);
+    grpc_metadata_batch_add_head(op->send_initial_metadata, &calld->method,
+                                 method);
     grpc_metadata_batch_add_head(op->send_initial_metadata, &calld->scheme,
                                  channeld->static_scheme);
     grpc_metadata_batch_add_tail(op->send_initial_metadata, &calld->te_trailers,
@@ -169,9 +292,16 @@
                                   grpc_transport_stream_op *op) {
   GPR_TIMER_BEGIN("hc_start_transport_op", 0);
   GRPC_CALL_LOG_OP(GPR_INFO, elem, op);
-  hc_mutate_op(elem, op);
+  hc_mutate_op(exec_ctx, elem, op);
   GPR_TIMER_END("hc_start_transport_op", 0);
-  grpc_call_next_op(exec_ctx, elem, op);
+  call_data *calld = elem->call_data;
+  if (op->send_message != NULL && calld->send_message_blocked) {
+    /* Don't forward the op. send_message contains slices that aren't ready
+    yet. The call will be forwarded by the op_complete of slice read call.
+    */
+  } else {
+    grpc_call_next_op(exec_ctx, elem, op);
+  }
 }
 
 /* Constructor for call_data */
@@ -180,14 +310,23 @@
                                   grpc_call_element_args *args) {
   call_data *calld = elem->call_data;
   calld->on_done_recv = NULL;
+  calld->on_complete = NULL;
+  calld->payload_bytes = NULL;
+  gpr_slice_buffer_init(&calld->slices);
   grpc_closure_init(&calld->hc_on_recv, hc_on_recv, elem);
+  grpc_closure_init(&calld->hc_on_complete, hc_on_complete, elem);
+  grpc_closure_init(&calld->got_slice, got_slice, elem);
+  grpc_closure_init(&calld->send_done, send_done, elem);
   return GRPC_ERROR_NONE;
 }
 
 /* Destructor for call_data */
 static void destroy_call_elem(grpc_exec_ctx *exec_ctx, grpc_call_element *elem,
                               const grpc_call_final_info *final_info,
-                              void *ignored) {}
+                              void *ignored) {
+  call_data *calld = elem->call_data;
+  gpr_slice_buffer_destroy(&calld->slices);
+}
 
 static grpc_mdelem *scheme_from_args(const grpc_channel_args *args) {
   unsigned i;
@@ -210,6 +349,22 @@
   return GRPC_MDELEM_SCHEME_HTTP;
 }
 
+static size_t max_payload_size_from_args(const grpc_channel_args *args) {
+  if (args != NULL) {
+    for (size_t i = 0; i < args->num_args; ++i) {
+      if (0 == strcmp(args->args[i].key, GRPC_ARG_MAX_PAYLOAD_SIZE_FOR_GET)) {
+        if (args->args[i].type != GRPC_ARG_INTEGER) {
+          gpr_log(GPR_ERROR, "%s: must be an integer",
+                  GRPC_ARG_MAX_PAYLOAD_SIZE_FOR_GET);
+        } else {
+          return (size_t)args->args[i].value.integer;
+        }
+      }
+    }
+  }
+  return kMaxPayloadSizeForGet;
+}
+
 static grpc_mdstr *user_agent_from_args(const grpc_channel_args *args,
                                         const char *transport_name) {
   gpr_strvec v;
@@ -233,8 +388,9 @@
     }
   }
 
-  gpr_asprintf(&tmp, "%sgrpc-c/%s (%s; %s)", is_first ? "" : " ",
-               grpc_version_string(), GPR_PLATFORM_STRING, transport_name);
+  gpr_asprintf(&tmp, "%sgrpc-c/%s (%s; %s; %s)", is_first ? "" : " ",
+               grpc_version_string(), GPR_PLATFORM_STRING, transport_name,
+               grpc_g_stands_for());
   is_first = 0;
   gpr_strvec_add(&v, tmp);
 
@@ -267,6 +423,8 @@
   GPR_ASSERT(!args->is_last);
   GPR_ASSERT(args->optional_transport != NULL);
   chand->static_scheme = scheme_from_args(args->channel_args);
+  chand->max_payload_size_for_get =
+      max_payload_size_from_args(args->channel_args);
   chand->user_agent = grpc_mdelem_from_metadata_strings(
       GRPC_MDSTR_USER_AGENT,
       user_agent_from_args(args->channel_args,
diff --git a/src/core/lib/channel/http_client_filter.h b/src/core/lib/channel/http_client_filter.h
index 4708117..9e6e106 100644
--- a/src/core/lib/channel/http_client_filter.h
+++ b/src/core/lib/channel/http_client_filter.h
@@ -41,4 +41,7 @@
 /* Channel arg to override the http2 :scheme header */
 #define GRPC_ARG_HTTP2_SCHEME "grpc.http2_scheme"
 
+/* Channel arg to determine maximum size of payload eligable for GET request */
+#define GRPC_ARG_MAX_PAYLOAD_SIZE_FOR_GET "grpc.max_payload_size_for_get"
+
 #endif /* GRPC_CORE_LIB_CHANNEL_HTTP_CLIENT_FILTER_H */
diff --git a/src/core/lib/channel/http_server_filter.c b/src/core/lib/channel/http_server_filter.c
index 5ce51f9..0f2bf97 100644
--- a/src/core/lib/channel/http_server_filter.c
+++ b/src/core/lib/channel/http_server_filter.c
@@ -49,17 +49,32 @@
   uint8_t seen_scheme;
   uint8_t seen_te_trailers;
   uint8_t seen_authority;
+  uint8_t seen_payload_bin;
   grpc_linked_mdelem status;
   grpc_linked_mdelem content_type;
 
+  /* flag to ensure payload_bin is delivered only once */
+  uint8_t payload_bin_delivered;
+
   grpc_metadata_batch *recv_initial_metadata;
   bool *recv_idempotent_request;
+  bool *recv_cacheable_request;
   /** Closure to call when finished with the hs_on_recv hook */
   grpc_closure *on_done_recv;
+  /** Closure to call when we retrieve read message from the payload-bin header
+   */
+  grpc_closure *recv_message_ready;
+  grpc_closure *on_complete;
+  grpc_byte_stream **pp_recv_message;
+  gpr_slice_buffer read_slice_buffer;
+  grpc_slice_buffer_stream read_stream;
+
   /** Receive closures are chained: we inject this closure as the on_done_recv
       up-call on transport_op, and remember to call our on_done_recv member
       after handling it. */
   grpc_closure hs_on_recv;
+  grpc_closure hs_on_complete;
+  grpc_closure hs_recv_message_ready;
 } call_data;
 
 typedef struct channel_data { uint8_t unused; } channel_data;
@@ -76,16 +91,20 @@
 
   /* Check if it is one of the headers we care about. */
   if (md == GRPC_MDELEM_TE_TRAILERS || md == GRPC_MDELEM_METHOD_POST ||
-      md == GRPC_MDELEM_METHOD_PUT || md == GRPC_MDELEM_SCHEME_HTTP ||
-      md == GRPC_MDELEM_SCHEME_HTTPS ||
+      md == GRPC_MDELEM_METHOD_PUT || md == GRPC_MDELEM_METHOD_GET ||
+      md == GRPC_MDELEM_SCHEME_HTTP || md == GRPC_MDELEM_SCHEME_HTTPS ||
       md == GRPC_MDELEM_CONTENT_TYPE_APPLICATION_SLASH_GRPC) {
     /* swallow it */
     if (md == GRPC_MDELEM_METHOD_POST) {
       calld->seen_method = 1;
       *calld->recv_idempotent_request = false;
+      *calld->recv_cacheable_request = false;
     } else if (md == GRPC_MDELEM_METHOD_PUT) {
       calld->seen_method = 1;
       *calld->recv_idempotent_request = true;
+    } else if (md == GRPC_MDELEM_METHOD_GET) {
+      calld->seen_method = 1;
+      *calld->recv_cacheable_request = true;
     } else if (md->key == GRPC_MDSTR_SCHEME) {
       calld->seen_scheme = 1;
     } else if (md == GRPC_MDELEM_TE_TRAILERS) {
@@ -137,6 +156,16 @@
         GRPC_MDSTR_AUTHORITY, GRPC_MDSTR_REF(md->value));
     calld->seen_authority = 1;
     return authority;
+  } else if (md->key == GRPC_MDSTR_GRPC_PAYLOAD_BIN) {
+    /* Retrieve the payload from the value of the 'grpc-internal-payload-bin'
+       header field */
+    calld->seen_payload_bin = 1;
+    gpr_slice_buffer_init(&calld->read_slice_buffer);
+    gpr_slice_buffer_add(&calld->read_slice_buffer,
+                         gpr_slice_ref(md->value->slice));
+    grpc_slice_buffer_stream_init(&calld->read_stream,
+                                  &calld->read_slice_buffer, 0);
+    return NULL;
   } else {
     return md;
   }
@@ -189,6 +218,36 @@
   GRPC_ERROR_UNREF(err);
 }
 
+static void hs_on_complete(grpc_exec_ctx *exec_ctx, void *user_data,
+                           grpc_error *err) {
+  grpc_call_element *elem = user_data;
+  call_data *calld = elem->call_data;
+  /* Call recv_message_ready if we got the payload via the header field */
+  if (calld->seen_payload_bin && calld->recv_message_ready != NULL) {
+    *calld->pp_recv_message = calld->payload_bin_delivered
+                                  ? NULL
+                                  : (grpc_byte_stream *)&calld->read_stream;
+    calld->recv_message_ready->cb(exec_ctx, calld->recv_message_ready->cb_arg,
+                                  err);
+    calld->recv_message_ready = NULL;
+    calld->payload_bin_delivered = true;
+  }
+  calld->on_complete->cb(exec_ctx, calld->on_complete->cb_arg, err);
+}
+
+static void hs_recv_message_ready(grpc_exec_ctx *exec_ctx, void *user_data,
+                                  grpc_error *err) {
+  grpc_call_element *elem = user_data;
+  call_data *calld = elem->call_data;
+  if (calld->seen_payload_bin) {
+    /* do nothing. This is probably a GET request, and payload will be returned
+    in hs_on_complete callback. */
+  } else {
+    calld->recv_message_ready->cb(exec_ctx, calld->recv_message_ready->cb_arg,
+                                  err);
+  }
+}
+
 static void hs_mutate_op(grpc_call_element *elem,
                          grpc_transport_stream_op *op) {
   /* grab pointers to our data from the call element */
@@ -206,11 +265,25 @@
   if (op->recv_initial_metadata) {
     /* substitute our callback for the higher callback */
     GPR_ASSERT(op->recv_idempotent_request != NULL);
+    GPR_ASSERT(op->recv_cacheable_request != NULL);
     calld->recv_initial_metadata = op->recv_initial_metadata;
     calld->recv_idempotent_request = op->recv_idempotent_request;
+    calld->recv_cacheable_request = op->recv_cacheable_request;
     calld->on_done_recv = op->recv_initial_metadata_ready;
     op->recv_initial_metadata_ready = &calld->hs_on_recv;
   }
+
+  if (op->recv_message) {
+    calld->recv_message_ready = op->recv_message_ready;
+    calld->pp_recv_message = op->recv_message;
+    if (op->recv_message_ready) {
+      op->recv_message_ready = &calld->hs_recv_message_ready;
+    }
+    if (op->on_complete) {
+      calld->on_complete = op->on_complete;
+      op->on_complete = &calld->hs_on_complete;
+    }
+  }
 }
 
 static void hs_start_transport_op(grpc_exec_ctx *exec_ctx,
@@ -232,6 +305,8 @@
   /* initialize members */
   memset(calld, 0, sizeof(*calld));
   grpc_closure_init(&calld->hs_on_recv, hs_on_recv, elem);
+  grpc_closure_init(&calld->hs_on_complete, hs_on_complete, elem);
+  grpc_closure_init(&calld->hs_recv_message_ready, hs_recv_message_ready, elem);
   return GRPC_ERROR_NONE;
 }
 
diff --git a/src/core/lib/iomgr/closure.c b/src/core/lib/iomgr/closure.c
index 0b6c3b2..5cbd6bd 100644
--- a/src/core/lib/iomgr/closure.c
+++ b/src/core/lib/iomgr/closure.c
@@ -35,19 +35,25 @@
 
 #include <grpc/support/alloc.h>
 
+#include "src/core/lib/profiling/timers.h"
+
 void grpc_closure_init(grpc_closure *closure, grpc_iomgr_cb_func cb,
                        void *cb_arg) {
   closure->cb = cb;
   closure->cb_arg = cb_arg;
 }
 
+void grpc_closure_list_init(grpc_closure_list *closure_list) {
+  closure_list->head = closure_list->tail = NULL;
+}
+
 void grpc_closure_list_append(grpc_closure_list *closure_list,
                               grpc_closure *closure, grpc_error *error) {
   if (closure == NULL) {
     GRPC_ERROR_UNREF(error);
     return;
   }
-  closure->error = error;
+  closure->error_data.error = error;
   closure->next_data.next = NULL;
   if (closure_list->head == NULL) {
     closure_list->head = closure;
@@ -60,8 +66,8 @@
 void grpc_closure_list_fail_all(grpc_closure_list *list,
                                 grpc_error *forced_failure) {
   for (grpc_closure *c = list->head; c != NULL; c = c->next_data.next) {
-    if (c->error == GRPC_ERROR_NONE) {
-      c->error = GRPC_ERROR_REF(forced_failure);
+    if (c->error_data.error == GRPC_ERROR_NONE) {
+      c->error_data.error = GRPC_ERROR_REF(forced_failure);
     }
   }
   GRPC_ERROR_UNREF(forced_failure);
@@ -106,3 +112,11 @@
   grpc_closure_init(&wc->wrapper, closure_wrapper, wc);
   return &wc->wrapper;
 }
+
+void grpc_closure_run(grpc_exec_ctx *exec_ctx, grpc_closure *c, grpc_error *error) {
+  GPR_TIMER_BEGIN("grpc_closure_run", 0);
+  c->cb(exec_ctx, c->cb_arg, error);
+  GRPC_ERROR_UNREF(error);
+  GPR_TIMER_END("grpc_closure_run", 0);
+}
+
diff --git a/src/core/lib/iomgr/closure.h b/src/core/lib/iomgr/closure.h
index 08e59a1..29ed19c 100644
--- a/src/core/lib/iomgr/closure.h
+++ b/src/core/lib/iomgr/closure.h
@@ -37,6 +37,7 @@
 #include <grpc/support/port_platform.h>
 #include <stdbool.h>
 #include "src/core/lib/iomgr/error.h"
+#include "src/core/lib/support/mpscq.h"
 
 struct grpc_closure;
 typedef struct grpc_closure grpc_closure;
@@ -60,6 +61,14 @@
 
 /** A closure over a grpc_iomgr_cb_func. */
 struct grpc_closure {
+  /** Once queued, next indicates the next queued closure; before then, scratch
+   *  space */
+  union {
+    grpc_closure *next;
+    gpr_mpscq_node atm_next;
+    uintptr_t scratch;
+  } next_data;
+
   /** Bound callback. */
   grpc_iomgr_cb_func cb;
 
@@ -67,14 +76,10 @@
   void *cb_arg;
 
   /** Once queued, the result of the closure. Before then: scratch space */
-  grpc_error *error;
-
-  /** Once queued, next indicates the next queued closure; before then, scratch
-   *  space */
   union {
-    grpc_closure *next;
+    grpc_error *error;
     uintptr_t scratch;
-  } next_data;
+  } error_data;
 };
 
 /** Initializes \a closure with \a cb and \a cb_arg. */
@@ -87,6 +92,8 @@
 #define GRPC_CLOSURE_LIST_INIT \
   { NULL, NULL }
 
+void grpc_closure_list_init(grpc_closure_list *list);
+
 /** add \a closure to the end of \a list
     and set \a closure's result to \a error */
 void grpc_closure_list_append(grpc_closure_list *list, grpc_closure *closure,
@@ -102,4 +109,9 @@
 /** return whether \a list is empty. */
 bool grpc_closure_list_empty(grpc_closure_list list);
 
+/** Run a closure directly. Caller ensures that no locks are being held above.
+ *  Note that calling this at the end of a closure callback function itself is
+ *  by definition safe. */
+void grpc_closure_run(grpc_exec_ctx *exec_ctx, grpc_closure *closure, grpc_error *error);
+
 #endif /* GRPC_CORE_LIB_IOMGR_CLOSURE_H */
diff --git a/src/core/lib/iomgr/combiner.c b/src/core/lib/iomgr/combiner.c
new file mode 100644
index 0000000..b2d6559
--- /dev/null
+++ b/src/core/lib/iomgr/combiner.c
@@ -0,0 +1,312 @@
+/*
+ *
+ * Copyright 2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "src/core/lib/iomgr/combiner.h"
+
+#include <string.h>
+
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+
+#include "src/core/lib/iomgr/workqueue.h"
+#include "src/core/lib/profiling/timers.h"
+
+int grpc_combiner_trace = 0;
+
+#define GRPC_COMBINER_TRACE(fn) \
+  do {                          \
+    if (grpc_combiner_trace) {  \
+      fn;                       \
+    }                           \
+  } while (0)
+
+struct grpc_combiner {
+  grpc_combiner *next_combiner_on_this_exec_ctx;
+  grpc_workqueue *optional_workqueue;
+  gpr_mpscq queue;
+  // state is:
+  // lower bit - zero if orphaned
+  // other bits - number of items queued on the lock
+  gpr_atm state;
+  // number of elements in the list that are covered by a poller: if >0, we can
+  // offload safely
+  gpr_atm covered_by_poller;
+  bool time_to_execute_final_list;
+  bool final_list_covered_by_poller;
+  grpc_closure_list final_list;
+  grpc_closure offload;
+};
+
+static void offload(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *error);
+
+typedef struct {
+  grpc_error *error;
+  bool covered_by_poller;
+} error_data;
+
+static uintptr_t pack_error_data(error_data d) {
+  return ((uintptr_t)d.error) | (d.covered_by_poller ? 1 : 0);
+}
+
+static error_data unpack_error_data(uintptr_t p) {
+  return (error_data){(grpc_error *)(p & ~(uintptr_t)1), p & 1};
+}
+
+static bool is_covered_by_poller(grpc_combiner *lock) {
+  return lock->final_list_covered_by_poller ||
+         gpr_atm_acq_load(&lock->covered_by_poller) > 0;
+}
+
+grpc_combiner *grpc_combiner_create(grpc_workqueue *optional_workqueue) {
+  grpc_combiner *lock = gpr_malloc(sizeof(*lock));
+  lock->next_combiner_on_this_exec_ctx = NULL;
+  lock->time_to_execute_final_list = false;
+  lock->optional_workqueue = optional_workqueue;
+  gpr_atm_no_barrier_store(&lock->state, 1);
+  gpr_atm_no_barrier_store(&lock->covered_by_poller, 0);
+  gpr_mpscq_init(&lock->queue);
+  grpc_closure_list_init(&lock->final_list);
+  grpc_closure_init(&lock->offload, offload, lock);
+  GRPC_COMBINER_TRACE(gpr_log(GPR_DEBUG, "C:%p create", lock));
+  return lock;
+}
+
+static void really_destroy(grpc_exec_ctx *exec_ctx, grpc_combiner *lock) {
+  GRPC_COMBINER_TRACE(gpr_log(GPR_DEBUG, "C:%p really_destroy", lock));
+  GPR_ASSERT(gpr_atm_no_barrier_load(&lock->state) == 0);
+  gpr_mpscq_destroy(&lock->queue);
+  GRPC_WORKQUEUE_UNREF(exec_ctx, lock->optional_workqueue, "combiner");
+  gpr_free(lock);
+}
+
+void grpc_combiner_destroy(grpc_exec_ctx *exec_ctx, grpc_combiner *lock) {
+  gpr_atm old_state = gpr_atm_full_fetch_add(&lock->state, -1);
+  GRPC_COMBINER_TRACE(gpr_log(
+      GPR_DEBUG, "C:%p really_destroy old_state=%" PRIdPTR, lock, old_state));
+  if (old_state == 1) {
+    really_destroy(exec_ctx, lock);
+  }
+}
+
+static void push_last_on_exec_ctx(grpc_exec_ctx *exec_ctx,
+                                  grpc_combiner *lock) {
+  lock->next_combiner_on_this_exec_ctx = NULL;
+  if (exec_ctx->active_combiner == NULL) {
+    exec_ctx->active_combiner = exec_ctx->last_combiner = lock;
+  } else {
+    exec_ctx->last_combiner->next_combiner_on_this_exec_ctx = lock;
+    exec_ctx->last_combiner = lock;
+  }
+}
+
+static void push_first_on_exec_ctx(grpc_exec_ctx *exec_ctx,
+                                   grpc_combiner *lock) {
+  lock->next_combiner_on_this_exec_ctx = exec_ctx->active_combiner;
+  exec_ctx->active_combiner = lock;
+  if (lock->next_combiner_on_this_exec_ctx == NULL) {
+    exec_ctx->last_combiner = lock;
+  }
+}
+
+void grpc_combiner_execute(grpc_exec_ctx *exec_ctx, grpc_combiner *lock,
+                           grpc_closure *cl, grpc_error *error,
+                           bool covered_by_poller) {
+  GRPC_COMBINER_TRACE(gpr_log(GPR_DEBUG,
+                              "C:%p grpc_combiner_execute c=%p cov=%d", lock,
+                              cl, covered_by_poller));
+  GPR_TIMER_BEGIN("combiner.execute", 0);
+  gpr_atm last = gpr_atm_full_fetch_add(&lock->state, 2);
+  GPR_ASSERT(last & 1);  // ensure lock has not been destroyed
+  cl->error_data.scratch =
+      pack_error_data((error_data){error, covered_by_poller});
+  if (covered_by_poller) {
+    gpr_atm_no_barrier_fetch_add(&lock->covered_by_poller, 1);
+  }
+  gpr_mpscq_push(&lock->queue, &cl->next_data.atm_next);
+  if (last == 1) {
+    // code will be written when the exec_ctx calls
+    // grpc_combiner_continue_exec_ctx
+    push_last_on_exec_ctx(exec_ctx, lock);
+  }
+  GPR_TIMER_END("combiner.execute", 0);
+}
+
+static void move_next(grpc_exec_ctx *exec_ctx) {
+  exec_ctx->active_combiner =
+      exec_ctx->active_combiner->next_combiner_on_this_exec_ctx;
+  if (exec_ctx->active_combiner == NULL) {
+    exec_ctx->last_combiner = NULL;
+  }
+}
+
+static void offload(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *error) {
+  grpc_combiner *lock = arg;
+  push_last_on_exec_ctx(exec_ctx, lock);
+}
+
+static void queue_offload(grpc_exec_ctx *exec_ctx, grpc_combiner *lock) {
+  move_next(exec_ctx);
+  grpc_workqueue_enqueue(exec_ctx, lock->optional_workqueue, &lock->offload,
+                         GRPC_ERROR_NONE);
+}
+
+bool grpc_combiner_continue_exec_ctx(grpc_exec_ctx *exec_ctx) {
+  GPR_TIMER_BEGIN("combiner.continue_exec_ctx", 0);
+  grpc_combiner *lock = exec_ctx->active_combiner;
+  if (lock == NULL) {
+    GPR_TIMER_END("combiner.continue_exec_ctx", 0);
+    return false;
+  }
+
+  if (lock->optional_workqueue != NULL &&
+      grpc_exec_ctx_ready_to_finish(exec_ctx) && is_covered_by_poller(lock)) {
+    GPR_TIMER_MARK("offload_from_finished_exec_ctx", 0);
+    // this execution context wants to move on, and we have a workqueue (and
+    // so can help the execution context out): schedule remaining work to be
+    // picked up on the workqueue
+    queue_offload(exec_ctx, lock);
+    GPR_TIMER_END("combiner.continue_exec_ctx", 0);
+    return true;
+  }
+
+  if (!lock->time_to_execute_final_list ||
+      // peek to see if something new has shown up, and execute that with
+      // priority
+      (gpr_atm_acq_load(&lock->state) >> 1) > 1) {
+    gpr_mpscq_node *n = gpr_mpscq_pop(&lock->queue);
+    GRPC_COMBINER_TRACE(
+        gpr_log(GPR_DEBUG, "C:%p maybe_finish_one n=%p", lock, n));
+    if (n == NULL) {
+      // queue is in an inconsistant state: use this as a cue that we should
+      // go off and do something else for a while (and come back later)
+      GPR_TIMER_MARK("delay_busy", 0);
+      if (lock->optional_workqueue != NULL && is_covered_by_poller(lock)) {
+        queue_offload(exec_ctx, lock);
+      }
+      GPR_TIMER_END("combiner.continue_exec_ctx", 0);
+      return true;
+    }
+    GPR_TIMER_BEGIN("combiner.exec1", 0);
+    grpc_closure *cl = (grpc_closure *)n;
+    error_data err = unpack_error_data(cl->error_data.scratch);
+    cl->cb(exec_ctx, cl->cb_arg, err.error);
+    if (err.covered_by_poller) {
+      gpr_atm_no_barrier_fetch_add(&lock->covered_by_poller, -1);
+    }
+    GRPC_ERROR_UNREF(err.error);
+    GPR_TIMER_END("combiner.exec1", 0);
+  } else {
+    grpc_closure *c = lock->final_list.head;
+    GPR_ASSERT(c != NULL);
+    grpc_closure_list_init(&lock->final_list);
+    lock->final_list_covered_by_poller = false;
+    int loops = 0;
+    while (c != NULL) {
+      GPR_TIMER_BEGIN("combiner.exec_1final", 0);
+      GRPC_COMBINER_TRACE(
+          gpr_log(GPR_DEBUG, "C:%p execute_final[%d] c=%p", lock, loops, c));
+      grpc_closure *next = c->next_data.next;
+      grpc_error *error = c->error_data.error;
+      c->cb(exec_ctx, c->cb_arg, error);
+      GRPC_ERROR_UNREF(error);
+      c = next;
+      GPR_TIMER_END("combiner.exec_1final", 0);
+    }
+  }
+
+  GPR_TIMER_MARK("unref", 0);
+  move_next(exec_ctx);
+  lock->time_to_execute_final_list = false;
+  gpr_atm old_state = gpr_atm_full_fetch_add(&lock->state, -2);
+  GRPC_COMBINER_TRACE(
+      gpr_log(GPR_DEBUG, "C:%p finish old_state=%" PRIdPTR, lock, old_state));
+  switch (old_state) {
+    default:
+      // we have multiple queued work items: just continue executing them
+      break;
+    case 5:  // we're down to one queued item: if it's the final list we
+    case 4:  // should do that
+      if (!grpc_closure_list_empty(lock->final_list)) {
+        lock->time_to_execute_final_list = true;
+      }
+      break;
+    case 3:  // had one count, one unorphaned --> unlocked unorphaned
+      GPR_TIMER_END("combiner.continue_exec_ctx", 0);
+      return true;
+    case 2:  // and one count, one orphaned --> unlocked and orphaned
+      really_destroy(exec_ctx, lock);
+      GPR_TIMER_END("combiner.continue_exec_ctx", 0);
+      return true;
+    case 1:
+    case 0:
+      // these values are illegal - representing an already unlocked or
+      // deleted lock
+      GPR_TIMER_END("combiner.continue_exec_ctx", 0);
+      GPR_UNREACHABLE_CODE(return true);
+  }
+  push_first_on_exec_ctx(exec_ctx, lock);
+  GPR_TIMER_END("combiner.continue_exec_ctx", 0);
+  return true;
+}
+
+static void enqueue_finally(grpc_exec_ctx *exec_ctx, void *closure,
+                            grpc_error *error) {
+  grpc_combiner_execute_finally(exec_ctx, exec_ctx->active_combiner, closure,
+                                GRPC_ERROR_REF(error), false);
+}
+
+void grpc_combiner_execute_finally(grpc_exec_ctx *exec_ctx, grpc_combiner *lock,
+                                   grpc_closure *closure, grpc_error *error,
+                                   bool covered_by_poller) {
+  GRPC_COMBINER_TRACE(gpr_log(GPR_DEBUG,
+                              "C:%p grpc_combiner_execute_finally c=%p; ac=%p",
+                              lock, closure, exec_ctx->active_combiner));
+  GPR_TIMER_BEGIN("combiner.execute_finally", 0);
+  if (exec_ctx->active_combiner != lock) {
+    GPR_TIMER_MARK("slowpath", 0);
+    grpc_combiner_execute(exec_ctx, lock,
+                          grpc_closure_create(enqueue_finally, closure), error,
+                          false);
+    GPR_TIMER_END("combiner.execute_finally", 0);
+    return;
+  }
+
+  if (grpc_closure_list_empty(lock->final_list)) {
+    gpr_atm_full_fetch_add(&lock->state, 2);
+  }
+  if (covered_by_poller) {
+    lock->final_list_covered_by_poller = true;
+  }
+  grpc_closure_list_append(&lock->final_list, closure, error);
+  GPR_TIMER_END("combiner.execute_finally", 0);
+}
diff --git a/src/core/lib/iomgr/combiner.h b/src/core/lib/iomgr/combiner.h
new file mode 100644
index 0000000..d04eeed
--- /dev/null
+++ b/src/core/lib/iomgr/combiner.h
@@ -0,0 +1,66 @@
+/*
+ *
+ * Copyright 2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef GRPC_CORE_LIB_IOMGR_COMBINER_H
+#define GRPC_CORE_LIB_IOMGR_COMBINER_H
+
+#include <stddef.h>
+
+#include <grpc/support/atm.h>
+#include "src/core/lib/iomgr/exec_ctx.h"
+#include "src/core/lib/support/mpscq.h"
+
+// Provides serialized access to some resource.
+// Each action queued on a combiner is executed serially in a borrowed thread.
+// The actual thread executing actions may change over time (but there will only
+// every be one at a time).
+
+// Initialize the lock, with an optional workqueue to shift load to when
+// necessary
+grpc_combiner *grpc_combiner_create(grpc_workqueue *optional_workqueue);
+// Destroy the lock
+void grpc_combiner_destroy(grpc_exec_ctx *exec_ctx, grpc_combiner *lock);
+// Execute \a action within the lock.
+void grpc_combiner_execute(grpc_exec_ctx *exec_ctx, grpc_combiner *lock,
+                           grpc_closure *closure, grpc_error *error,
+                           bool covered_by_poller);
+// Execute \a action within the lock just prior to unlocking.
+void grpc_combiner_execute_finally(grpc_exec_ctx *exec_ctx, grpc_combiner *lock,
+                                   grpc_closure *closure, grpc_error *error,
+                                   bool covered_by_poller);
+
+bool grpc_combiner_continue_exec_ctx(grpc_exec_ctx *exec_ctx);
+
+extern int grpc_combiner_trace;
+
+#endif /* GRPC_CORE_LIB_IOMGR_COMBINER_H */
diff --git a/src/core/lib/iomgr/error.c b/src/core/lib/iomgr/error.c
index 149c556..45ef75e 100644
--- a/src/core/lib/iomgr/error.c
+++ b/src/core/lib/iomgr/error.c
@@ -265,7 +265,7 @@
   } else {
     out = gpr_malloc(sizeof(*out));
 #ifdef GRPC_ERROR_REFCOUNT_DEBUG
-    gpr_log(GPR_DEBUG, "%p create copying", out);
+    gpr_log(GPR_DEBUG, "%p create copying %p", out, in);
 #endif
     out->ints = gpr_avl_ref(in->ints);
     out->strs = gpr_avl_ref(in->strs);
@@ -332,7 +332,7 @@
   return new;
 }
 
-static const char *no_error_string = "null";
+static const char *no_error_string = "\"No Error\"";
 static const char *oom_error_string = "\"Out of memory\"";
 static const char *cancelled_error_string = "\"Cancelled\"";
 
diff --git a/src/core/lib/iomgr/error.h b/src/core/lib/iomgr/error.h
index bc77812..2ab3ef9 100644
--- a/src/core/lib/iomgr/error.h
+++ b/src/core/lib/iomgr/error.h
@@ -47,7 +47,8 @@
 ///  if a grpc_error is passed to a grpc_closure callback function (functions
 ///    with the signature:
 ///      void (*f)(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *error))
-///    then those functions do not automatically own a ref to error
+///    then those functions do not own a ref to error (but are free to manually
+///    take a reference).
 ///  if a grpc_error is passed to *ANY OTHER FUNCTION* then that function takes
 ///    ownership of the error
 /// Errors have:
@@ -122,9 +123,13 @@
   GRPC_ERROR_TIME_CREATED,
 } grpc_error_times;
 
+/// The following "special" errors can be propagated without allocating memory.
+/// They are always even so that other code (particularly combiner locks) can
+/// safely use the lower bit for themselves.
+
 #define GRPC_ERROR_NONE ((grpc_error *)NULL)
-#define GRPC_ERROR_OOM ((grpc_error *)1)
-#define GRPC_ERROR_CANCELLED ((grpc_error *)2)
+#define GRPC_ERROR_OOM ((grpc_error *)2)
+#define GRPC_ERROR_CANCELLED ((grpc_error *)4)
 
 const char *grpc_error_string(grpc_error *error);
 void grpc_error_free_string(const char *str);
diff --git a/src/core/lib/iomgr/ev_epoll_linux.c b/src/core/lib/iomgr/ev_epoll_linux.c
index 02bcbaa..740920d 100644
--- a/src/core/lib/iomgr/ev_epoll_linux.c
+++ b/src/core/lib/iomgr/ev_epoll_linux.c
@@ -928,7 +928,8 @@
     fd->polling_island = NULL;
   }
 
-  grpc_exec_ctx_sched(exec_ctx, fd->on_done_closure, error, NULL);
+  grpc_exec_ctx_sched(exec_ctx, fd->on_done_closure, GRPC_ERROR_REF(error),
+                      NULL);
 
   gpr_mu_unlock(&fd->mu);
   UNREF_BY(fd, 2, reason); /* Drop the reference */
@@ -940,6 +941,7 @@
     PI_UNREF(exec_ctx, unref_pi, "fd_orphan");
   }
   GRPC_LOG_IF_ERROR("fd_orphan", GRPC_ERROR_REF(error));
+  GRPC_ERROR_UNREF(error);
 }
 
 static grpc_error *fd_shutdown_error(bool shutdown) {
@@ -1353,8 +1355,10 @@
   gpr_mu_unlock(&pollset->mu);
 
   do {
+    GRPC_SCHEDULING_START_BLOCKING_REGION;
     ep_rv = epoll_pwait(epoll_fd, ep_ev, GRPC_EPOLL_MAX_EVENTS, timeout_ms,
                         sig_mask);
+    GRPC_SCHEDULING_END_BLOCKING_REGION;
     if (ep_rv < 0) {
       if (errno != EINTR) {
         gpr_asprintf(&err_msg,
@@ -1527,6 +1531,8 @@
 
 static void pollset_add_fd(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset,
                            grpc_fd *fd) {
+  GPR_TIMER_BEGIN("pollset_add_fd", 0);
+
   grpc_error *error = GRPC_ERROR_NONE;
 
   gpr_mu_lock(&pollset->mu);
@@ -1639,6 +1645,8 @@
   gpr_mu_unlock(&pollset->mu);
 
   GRPC_LOG_IF_ERROR("pollset_add_fd", error);
+
+  GPR_TIMER_END("pollset_add_fd", 0);
 }
 
 /*******************************************************************************
diff --git a/src/core/lib/iomgr/exec_ctx.c b/src/core/lib/iomgr/exec_ctx.c
index ac7785e..a3c40e8 100644
--- a/src/core/lib/iomgr/exec_ctx.c
+++ b/src/core/lib/iomgr/exec_ctx.c
@@ -37,6 +37,7 @@
 #include <grpc/support/sync.h>
 #include <grpc/support/thd.h>
 
+#include "src/core/lib/iomgr/combiner.h"
 #include "src/core/lib/iomgr/workqueue.h"
 #include "src/core/lib/profiling/timers.h"
 
@@ -60,18 +61,47 @@
 bool grpc_exec_ctx_flush(grpc_exec_ctx *exec_ctx) {
   bool did_something = 0;
   GPR_TIMER_BEGIN("grpc_exec_ctx_flush", 0);
-  while (!grpc_closure_list_empty(exec_ctx->closure_list)) {
-    grpc_closure *c = exec_ctx->closure_list.head;
-    exec_ctx->closure_list.head = exec_ctx->closure_list.tail = NULL;
-    while (c != NULL) {
-      grpc_closure *next = c->next_data.next;
-      grpc_error *error = c->error;
-      did_something = true;
-      GPR_TIMER_BEGIN("grpc_exec_ctx_flush.cb", 0);
+  for (;;) {
+    if (!grpc_closure_list_empty(exec_ctx->closure_list)) {
+      grpc_closure *c = exec_ctx->closure_list.head;
+      exec_ctx->closure_list.head = exec_ctx->closure_list.tail = NULL;
+      while (c != NULL) {
+        grpc_closure *next = c->next_data.next;
+        did_something = true;
+        grpc_closure_run(exec_ctx, c, c->error_data.error);
+        c = next;
+      }
+      continue;
+    }
+    if (grpc_combiner_continue_exec_ctx(exec_ctx)) {
+      continue;
+    }
+    break;
+  }
+  GPR_ASSERT(exec_ctx->active_combiner == NULL);
+  if (exec_ctx->stealing_from_workqueue != NULL) {
+    if (grpc_exec_ctx_ready_to_finish(exec_ctx)) {
+      grpc_workqueue_enqueue(exec_ctx, exec_ctx->stealing_from_workqueue,
+                             exec_ctx->stolen_closure,
+                             exec_ctx->stolen_closure->error_data.error);
+      GRPC_WORKQUEUE_UNREF(exec_ctx, exec_ctx->stealing_from_workqueue,
+                           "exec_ctx_sched");
+      exec_ctx->stealing_from_workqueue = NULL;
+      exec_ctx->stolen_closure = NULL;
+    } else {
+      grpc_closure *c = exec_ctx->stolen_closure;
+      GRPC_WORKQUEUE_UNREF(exec_ctx, exec_ctx->stealing_from_workqueue,
+                           "exec_ctx_sched");
+      exec_ctx->stealing_from_workqueue = NULL;
+      exec_ctx->stolen_closure = NULL;
+      grpc_error *error = c->error_data.error;
+      GPR_TIMER_BEGIN("grpc_exec_ctx_flush.stolen_cb", 0);
       c->cb(exec_ctx, c->cb_arg, error);
       GRPC_ERROR_UNREF(error);
-      GPR_TIMER_END("grpc_exec_ctx_flush.cb", 0);
-      c = next;
+      GPR_TIMER_END("grpc_exec_ctx_flush.stolen_cb", 0);
+      grpc_exec_ctx_flush(exec_ctx);
+      GPR_TIMER_END("grpc_exec_ctx_flush", 0);
+      return true;
     }
   }
   GPR_TIMER_END("grpc_exec_ctx_flush", 0);
@@ -86,12 +116,25 @@
 void grpc_exec_ctx_sched(grpc_exec_ctx *exec_ctx, grpc_closure *closure,
                          grpc_error *error,
                          grpc_workqueue *offload_target_or_null) {
+  GPR_TIMER_BEGIN("grpc_exec_ctx_sched", 0);
   if (offload_target_or_null == NULL) {
     grpc_closure_list_append(&exec_ctx->closure_list, closure, error);
-  } else {
+  } else if (exec_ctx->stealing_from_workqueue == NULL) {
+    exec_ctx->stealing_from_workqueue = offload_target_or_null;
+    closure->error_data.error = error;
+    exec_ctx->stolen_closure = closure;
+  } else if (exec_ctx->stealing_from_workqueue != offload_target_or_null) {
     grpc_workqueue_enqueue(exec_ctx, offload_target_or_null, closure, error);
     GRPC_WORKQUEUE_UNREF(exec_ctx, offload_target_or_null, "exec_ctx_sched");
+  } else { /* stealing_from_workqueue == offload_target_or_null */
+    grpc_workqueue_enqueue(exec_ctx, offload_target_or_null,
+                           exec_ctx->stolen_closure,
+                           exec_ctx->stolen_closure->error_data.error);
+    closure->error_data.error = error;
+    exec_ctx->stolen_closure = closure;
+    GRPC_WORKQUEUE_UNREF(exec_ctx, offload_target_or_null, "exec_ctx_sched");
   }
+  GPR_TIMER_END("grpc_exec_ctx_sched", 0);
 }
 
 void grpc_exec_ctx_enqueue_list(grpc_exec_ctx *exec_ctx,
diff --git a/src/core/lib/iomgr/exec_ctx.h b/src/core/lib/iomgr/exec_ctx.h
index 917f332..91029f5 100644
--- a/src/core/lib/iomgr/exec_ctx.h
+++ b/src/core/lib/iomgr/exec_ctx.h
@@ -40,8 +40,8 @@
 
 /** A workqueue represents a list of work to be executed asynchronously.
     Forward declared here to avoid a circular dependency with workqueue.h. */
-struct grpc_workqueue;
 typedef struct grpc_workqueue grpc_workqueue;
+typedef struct grpc_combiner grpc_combiner;
 
 #ifndef GRPC_EXECUTION_CONTEXT_SANITIZER
 /** Execution context.
@@ -66,13 +66,23 @@
  */
 struct grpc_exec_ctx {
   grpc_closure_list closure_list;
+  grpc_workqueue *stealing_from_workqueue;
+  grpc_closure *stolen_closure;
+  /** currently active combiner: updated only via combiner.c */
+  grpc_combiner *active_combiner;
+  grpc_combiner *last_combiner;
   bool cached_ready_to_finish;
   void *check_ready_to_finish_arg;
   bool (*check_ready_to_finish)(grpc_exec_ctx *exec_ctx, void *arg);
 };
 
+/* initializer for grpc_exec_ctx:
+   prefer to use GRPC_EXEC_CTX_INIT whenever possible */
 #define GRPC_EXEC_CTX_INIT_WITH_FINISH_CHECK(finish_check, finish_check_arg) \
-  { GRPC_CLOSURE_LIST_INIT, false, finish_check_arg, finish_check }
+  {                                                                          \
+    GRPC_CLOSURE_LIST_INIT, NULL, NULL, NULL, NULL, false, finish_check_arg, \
+        finish_check                                                         \
+  }
 #else
 struct grpc_exec_ctx {
   bool cached_ready_to_finish;
@@ -83,8 +93,10 @@
   { false, finish_check_arg, finish_check }
 #endif
 
+/* initialize an execution context at the top level of an API call into grpc
+   (this is safe to use elsewhere, though possibly not as efficient) */
 #define GRPC_EXEC_CTX_INIT \
-  GRPC_EXEC_CTX_INIT_WITH_FINISH_CHECK(grpc_never_ready_to_finish, NULL)
+  GRPC_EXEC_CTX_INIT_WITH_FINISH_CHECK(grpc_always_ready_to_finish, NULL)
 
 /** Flush any work that has been enqueued onto this grpc_exec_ctx.
  *  Caller must guarantee that no interfering locks are held.
diff --git a/src/core/lib/iomgr/tcp_posix.c b/src/core/lib/iomgr/tcp_posix.c
index 974d5ae..00fd776 100644
--- a/src/core/lib/iomgr/tcp_posix.c
+++ b/src/core/lib/iomgr/tcp_posix.c
@@ -177,7 +177,7 @@
 
   tcp->read_cb = NULL;
   tcp->incoming_buffer = NULL;
-  grpc_exec_ctx_sched(exec_ctx, cb, error, NULL);
+  grpc_closure_run(exec_ctx, cb, error);
 }
 
 #define MAX_READ_IOVEC 4
@@ -209,11 +209,11 @@
   msg.msg_controllen = 0;
   msg.msg_flags = 0;
 
-  GPR_TIMER_BEGIN("recvmsg", 1);
+  GPR_TIMER_BEGIN("recvmsg", 0);
   do {
     read_bytes = recvmsg(tcp->fd, &msg, 0);
   } while (read_bytes < 0 && errno == EINTR);
-  GPR_TIMER_END("recvmsg", 0);
+  GPR_TIMER_END("recvmsg", read_bytes >= 0);
 
   if (read_bytes < 0) {
     /* NB: After calling call_read_cb a parallel call of the read handler may
@@ -379,15 +379,21 @@
   }
 
   if (!tcp_flush(tcp, &error)) {
+    if (grpc_tcp_trace) {
+      gpr_log(GPR_DEBUG, "write: delayed");
+    }
     grpc_fd_notify_on_write(exec_ctx, tcp->em_fd, &tcp->write_closure);
   } else {
     cb = tcp->write_cb;
     tcp->write_cb = NULL;
-    GPR_TIMER_BEGIN("tcp_handle_write.cb", 0);
-    cb->cb(exec_ctx, cb->cb_arg, error);
-    GPR_TIMER_END("tcp_handle_write.cb", 0);
+    if (grpc_tcp_trace) {
+      const char *str = grpc_error_string(error);
+      gpr_log(GPR_DEBUG, "write: %s", str);
+      grpc_error_free_string(str);
+    }
+
+    grpc_closure_run(exec_ctx, cb, error);
     TCP_UNREF(exec_ctx, tcp, "write");
-    GRPC_ERROR_UNREF(error);
   }
 }
 
@@ -425,8 +431,16 @@
   if (!tcp_flush(tcp, &error)) {
     TCP_REF(tcp, "write");
     tcp->write_cb = cb;
+    if (grpc_tcp_trace) {
+      gpr_log(GPR_DEBUG, "write: delayed");
+    }
     grpc_fd_notify_on_write(exec_ctx, tcp->em_fd, &tcp->write_closure);
   } else {
+    if (grpc_tcp_trace) {
+      const char *str = grpc_error_string(error);
+      gpr_log(GPR_DEBUG, "write: %s", str);
+      grpc_error_free_string(str);
+    }
     grpc_exec_ctx_sched(exec_ctx, cb, error, NULL);
   }
 
diff --git a/src/core/lib/iomgr/tcp_server_posix.c b/src/core/lib/iomgr/tcp_server_posix.c
index ea8d241..2d3f6cf 100644
--- a/src/core/lib/iomgr/tcp_server_posix.c
+++ b/src/core/lib/iomgr/tcp_server_posix.c
@@ -140,15 +140,17 @@
 };
 
 static gpr_once check_init = GPR_ONCE_INIT;
-static bool has_so_reuseport;
+static bool has_so_reuseport = false;
 
 static void init(void) {
+#ifndef GPR_MANYLINUX1
   int s = socket(AF_INET, SOCK_STREAM, 0);
   if (s >= 0) {
     has_so_reuseport = GRPC_LOG_IF_ERROR("check for SO_REUSEPORT",
                                          grpc_set_socket_reuse_port(s, 1));
     close(s);
   }
+#endif
 }
 
 grpc_error *grpc_tcp_server_create(grpc_closure *shutdown_complete,
diff --git a/src/core/lib/iomgr/workqueue.h b/src/core/lib/iomgr/workqueue.h
index 7156e49..9f95562 100644
--- a/src/core/lib/iomgr/workqueue.h
+++ b/src/core/lib/iomgr/workqueue.h
@@ -50,10 +50,6 @@
 
 /* grpc_workqueue is forward declared in exec_ctx.h */
 
-/* Deprecated: do not use.
-   This has *already* been removed in a future commit. */
-void grpc_workqueue_flush(grpc_exec_ctx *exec_ctx, grpc_workqueue *workqueue);
-
 /* Reference counting functions. Use the macro's always
    (GRPC_WORKQUEUE_{REF,UNREF}).
 
@@ -65,17 +61,17 @@
 //#define GRPC_WORKQUEUE_REFCOUNT_DEBUG
 #ifdef GRPC_WORKQUEUE_REFCOUNT_DEBUG
 #define GRPC_WORKQUEUE_REF(p, r) \
-  (grpc_workqueue_ref((p), __FILE__, __LINE__, (r)), (p))
+  grpc_workqueue_ref((p), __FILE__, __LINE__, (r))
 #define GRPC_WORKQUEUE_UNREF(exec_ctx, p, r) \
   grpc_workqueue_unref((exec_ctx), (p), __FILE__, __LINE__, (r))
-void grpc_workqueue_ref(grpc_workqueue *workqueue, const char *file, int line,
-                        const char *reason);
+grpc_workqueue *grpc_workqueue_ref(grpc_workqueue *workqueue, const char *file,
+                                   int line, const char *reason);
 void grpc_workqueue_unref(grpc_exec_ctx *exec_ctx, grpc_workqueue *workqueue,
                           const char *file, int line, const char *reason);
 #else
-#define GRPC_WORKQUEUE_REF(p, r) (grpc_workqueue_ref((p)), (p))
+#define GRPC_WORKQUEUE_REF(p, r) grpc_workqueue_ref((p))
 #define GRPC_WORKQUEUE_UNREF(cl, p, r) grpc_workqueue_unref((cl), (p))
-void grpc_workqueue_ref(grpc_workqueue *workqueue);
+grpc_workqueue *grpc_workqueue_ref(grpc_workqueue *workqueue);
 void grpc_workqueue_unref(grpc_exec_ctx *exec_ctx, grpc_workqueue *workqueue);
 #endif
 
diff --git a/src/core/lib/iomgr/workqueue_posix.c b/src/core/lib/iomgr/workqueue_posix.c
index e0d6dac..836bb8b 100644
--- a/src/core/lib/iomgr/workqueue_posix.c
+++ b/src/core/lib/iomgr/workqueue_posix.c
@@ -44,6 +44,7 @@
 #include <grpc/support/useful.h>
 
 #include "src/core/lib/iomgr/ev_posix.h"
+#include "src/core/lib/profiling/timers.h"
 
 static void on_readable(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *error);
 
@@ -52,8 +53,7 @@
   char name[32];
   *workqueue = gpr_malloc(sizeof(grpc_workqueue));
   gpr_ref_init(&(*workqueue)->refs, 1);
-  gpr_mu_init(&(*workqueue)->mu);
-  (*workqueue)->closure_list.head = (*workqueue)->closure_list.tail = NULL;
+  gpr_atm_no_barrier_store(&(*workqueue)->state, 1);
   grpc_error *err = grpc_wakeup_fd_init(&(*workqueue)->wakeup_fd);
   if (err != GRPC_ERROR_NONE) {
     gpr_free(*workqueue);
@@ -62,6 +62,7 @@
   sprintf(name, "workqueue:%p", (void *)(*workqueue));
   (*workqueue)->wakeup_read_fd = grpc_fd_create(
       GRPC_WAKEUP_FD_GET_READ_FD(&(*workqueue)->wakeup_fd), name);
+  gpr_mpscq_init(&(*workqueue)->queue);
   grpc_closure_init(&(*workqueue)->read_closure, on_readable, *workqueue);
   grpc_fd_notify_on_read(exec_ctx, (*workqueue)->wakeup_read_fd,
                          &(*workqueue)->read_closure);
@@ -70,82 +71,135 @@
 
 static void workqueue_destroy(grpc_exec_ctx *exec_ctx,
                               grpc_workqueue *workqueue) {
-  grpc_exec_ctx_enqueue_list(exec_ctx, &workqueue->closure_list, NULL);
   grpc_fd_shutdown(exec_ctx, workqueue->wakeup_read_fd);
 }
 
-#ifdef GRPC_WORKQUEUE_REFCOUNT_DEBUG
-void grpc_workqueue_ref(grpc_workqueue *workqueue, const char *file, int line,
-                        const char *reason) {
-  gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG, "WORKQUEUE:%p   ref %d -> %d %s",
-          workqueue, (int)workqueue->refs.count, (int)workqueue->refs.count + 1,
-          reason);
-#else
-void grpc_workqueue_ref(grpc_workqueue *workqueue) {
-#endif
-  gpr_ref(&workqueue->refs);
-}
-
-#ifdef GRPC_WORKQUEUE_REFCOUNT_DEBUG
-void grpc_workqueue_unref(grpc_exec_ctx *exec_ctx, grpc_workqueue *workqueue,
-                          const char *file, int line, const char *reason) {
-  gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG, "WORKQUEUE:%p unref %d -> %d %s",
-          workqueue, (int)workqueue->refs.count, (int)workqueue->refs.count - 1,
-          reason);
-#else
-void grpc_workqueue_unref(grpc_exec_ctx *exec_ctx, grpc_workqueue *workqueue) {
-#endif
-  if (gpr_unref(&workqueue->refs)) {
+static void workqueue_orphan(grpc_exec_ctx *exec_ctx,
+                             grpc_workqueue *workqueue) {
+  gpr_atm last = gpr_atm_full_fetch_add(&workqueue->state, -1);
+  if (last == 1) {
     workqueue_destroy(exec_ctx, workqueue);
   }
 }
 
-void grpc_workqueue_flush(grpc_exec_ctx *exec_ctx, grpc_workqueue *workqueue) {
-  gpr_mu_lock(&workqueue->mu);
-  grpc_exec_ctx_enqueue_list(exec_ctx, &workqueue->closure_list, NULL);
-  gpr_mu_unlock(&workqueue->mu);
+#ifdef GRPC_WORKQUEUE_REFCOUNT_DEBUG
+grpc_workqueue *grpc_workqueue_ref(grpc_workqueue *workqueue, const char *file,
+                                   int line, const char *reason) {
+  if (workqueue == NULL) return NULL;
+  gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG, "WORKQUEUE:%p   ref %d -> %d %s",
+          workqueue, (int)workqueue->refs.count, (int)workqueue->refs.count + 1,
+          reason);
+  gpr_ref(&workqueue->refs);
+  return workqueue;
+}
+#else
+grpc_workqueue *grpc_workqueue_ref(grpc_workqueue *workqueue) {
+  if (workqueue != NULL) {
+    gpr_ref(&workqueue->refs);
+  }
+  return workqueue;
+}
+#endif
+
+#ifdef GRPC_WORKQUEUE_REFCOUNT_DEBUG
+void grpc_workqueue_unref(grpc_exec_ctx *exec_ctx, grpc_workqueue *workqueue,
+                          const char *file, int line, const char *reason) {
+  if (workqueue == NULL) return;
+  gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG, "WORKQUEUE:%p unref %d -> %d %s",
+          workqueue, (int)workqueue->refs.count, (int)workqueue->refs.count - 1,
+          reason);
+  if (gpr_unref(&workqueue->refs)) {
+    workqueue_orphan(exec_ctx, workqueue);
+  }
+}
+#else
+void grpc_workqueue_unref(grpc_exec_ctx *exec_ctx, grpc_workqueue *workqueue) {
+  if (workqueue == NULL) return;
+  if (gpr_unref(&workqueue->refs)) {
+    workqueue_orphan(exec_ctx, workqueue);
+  }
+}
+#endif
+
+static void drain(grpc_exec_ctx *exec_ctx, grpc_workqueue *workqueue) {
+  abort();
+}
+
+static void wakeup(grpc_exec_ctx *exec_ctx, grpc_workqueue *workqueue) {
+  GPR_TIMER_MARK("workqueue.wakeup", 0);
+  grpc_error *err = grpc_wakeup_fd_wakeup(&workqueue->wakeup_fd);
+  if (!GRPC_LOG_IF_ERROR("wakeupfd_wakeup", err)) {
+    drain(exec_ctx, workqueue);
+  }
 }
 
 static void on_readable(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *error) {
+  GPR_TIMER_BEGIN("workqueue.on_readable", 0);
+
   grpc_workqueue *workqueue = arg;
 
   if (error != GRPC_ERROR_NONE) {
-    gpr_mu_destroy(&workqueue->mu);
     /* HACK: let wakeup_fd code know that we stole the fd */
     workqueue->wakeup_fd.read_fd = 0;
     grpc_wakeup_fd_destroy(&workqueue->wakeup_fd);
     grpc_fd_orphan(exec_ctx, workqueue->wakeup_read_fd, NULL, NULL, "destroy");
+    GPR_ASSERT(gpr_atm_no_barrier_load(&workqueue->state) == 0);
     gpr_free(workqueue);
   } else {
-    gpr_mu_lock(&workqueue->mu);
-    grpc_exec_ctx_enqueue_list(exec_ctx, &workqueue->closure_list, NULL);
     error = grpc_wakeup_fd_consume_wakeup(&workqueue->wakeup_fd);
-    gpr_mu_unlock(&workqueue->mu);
-    if (error == GRPC_ERROR_NONE) {
-      grpc_fd_notify_on_read(exec_ctx, workqueue->wakeup_read_fd,
-                             &workqueue->read_closure);
-    } else {
+    if (error != GRPC_ERROR_NONE) {
       /* recurse to get error handling */
       on_readable(exec_ctx, arg, error);
+    } else {
+      gpr_mpscq_node *n = gpr_mpscq_pop(&workqueue->queue);
+      if (n == NULL) {
+        /* try again - queue in an ephemerally inconsistent state */
+        wakeup(exec_ctx, workqueue);
+        grpc_fd_notify_on_read(exec_ctx, workqueue->wakeup_read_fd,
+                               &workqueue->read_closure);
+      } else {
+        gpr_atm last = gpr_atm_full_fetch_add(&workqueue->state, -2);
+        switch (last) {
+          default:
+            // schedule a wakeup since there's more to do
+            wakeup(exec_ctx, workqueue);
+            break;
+          case 3:  // had one count, one unorphaned --> done, unorphaned
+            break;
+          case 2:  // had one count, one orphaned --> done, orphaned
+            workqueue_destroy(exec_ctx, workqueue);
+            break;
+          case 1:
+          case 0:
+            // these values are illegal - representing an already done or
+            // deleted workqueue
+            GPR_UNREACHABLE_CODE(break);
+        }
+        grpc_fd_notify_on_read(exec_ctx, workqueue->wakeup_read_fd,
+                               &workqueue->read_closure);
+        grpc_closure *cl = (grpc_closure *)n;
+        grpc_error *clerr = cl->error_data.error;
+        grpc_closure_run(exec_ctx, cl, clerr);
+      }
     }
   }
+
+  GPR_TIMER_END("workqueue.on_readable", 0);
 }
 
 void grpc_workqueue_enqueue(grpc_exec_ctx *exec_ctx, grpc_workqueue *workqueue,
                             grpc_closure *closure, grpc_error *error) {
-  grpc_error *push_error = GRPC_ERROR_NONE;
-  gpr_mu_lock(&workqueue->mu);
-  if (grpc_closure_list_empty(workqueue->closure_list)) {
-    push_error = grpc_wakeup_fd_wakeup(&workqueue->wakeup_fd);
+  GPR_TIMER_BEGIN("workqueue.enqueue", 0);
+  GRPC_WORKQUEUE_REF(workqueue, "enqueue");
+  gpr_atm last = gpr_atm_full_fetch_add(&workqueue->state, 2);
+  GPR_ASSERT(last & 1);
+  closure->error_data.error = error;
+  gpr_mpscq_push(&workqueue->queue, &closure->next_data.atm_next);
+  if (last == 1) {
+    wakeup(exec_ctx, workqueue);
   }
-  grpc_closure_list_append(&workqueue->closure_list, closure, error);
-  if (push_error != GRPC_ERROR_NONE) {
-    const char *msg = grpc_error_string(push_error);
-    gpr_log(GPR_ERROR, "Failed to push to workqueue: %s", msg);
-    grpc_error_free_string(msg);
-    grpc_exec_ctx_enqueue_list(exec_ctx, &workqueue->closure_list, NULL);
-  }
-  gpr_mu_unlock(&workqueue->mu);
+  GRPC_WORKQUEUE_UNREF(exec_ctx, workqueue, "enqueue");
+  GPR_TIMER_END("workqueue.enqueue", 0);
 }
 
 #endif /* GPR_POSIX_SOCKET */
diff --git a/src/core/lib/iomgr/workqueue_posix.h b/src/core/lib/iomgr/workqueue_posix.h
index 0f26ba5..03ee21c 100644
--- a/src/core/lib/iomgr/workqueue_posix.h
+++ b/src/core/lib/iomgr/workqueue_posix.h
@@ -35,14 +35,17 @@
 #define GRPC_CORE_LIB_IOMGR_WORKQUEUE_POSIX_H
 
 #include "src/core/lib/iomgr/wakeup_fd_posix.h"
+#include "src/core/lib/support/mpscq.h"
 
 struct grpc_fd;
 
 struct grpc_workqueue {
   gpr_refcount refs;
-
-  gpr_mu mu;
-  grpc_closure_list closure_list;
+  gpr_mpscq queue;
+  // state is:
+  // lower bit - zero if orphaned
+  // other bits - number of items enqueued
+  gpr_atm state;
 
   grpc_wakeup_fd wakeup_fd;
   struct grpc_fd *wakeup_read_fd;
diff --git a/src/core/lib/iomgr/workqueue_windows.c b/src/core/lib/iomgr/workqueue_windows.c
index 23e2dea..5c93d3c 100644
--- a/src/core/lib/iomgr/workqueue_windows.c
+++ b/src/core/lib/iomgr/workqueue_windows.c
@@ -42,15 +42,17 @@
 // context, which is at least correct, if not performant or in the spirit of
 // workqueues.
 
-void grpc_workqueue_flush(grpc_exec_ctx *exec_ctx, grpc_workqueue *workqueue) {}
-
 #ifdef GRPC_WORKQUEUE_REFCOUNT_DEBUG
-void grpc_workqueue_ref(grpc_workqueue *workqueue, const char *file, int line,
-                        const char *reason) {}
+grpc_workqueue *grpc_workqueue_ref(grpc_workqueue *workqueue, const char *file,
+                                   int line, const char *reason) {
+  return workqueue;
+}
 void grpc_workqueue_unref(grpc_exec_ctx *exec_ctx, grpc_workqueue *workqueue,
                           const char *file, int line, const char *reason) {}
 #else
-void grpc_workqueue_ref(grpc_workqueue *workqueue) {}
+grpc_workqueue *grpc_workqueue_ref(grpc_workqueue *workqueue) {
+  return workqueue;
+}
 void grpc_workqueue_unref(grpc_exec_ctx *exec_ctx, grpc_workqueue *workqueue) {}
 #endif
 
diff --git a/src/core/lib/profiling/basic_timers.c b/src/core/lib/profiling/basic_timers.c
index 51813d0..bdf9af2 100644
--- a/src/core/lib/profiling/basic_timers.c
+++ b/src/core/lib/profiling/basic_timers.c
@@ -83,6 +83,7 @@
 static gpr_thd_id g_writing_thread;
 static __thread int g_thread_id;
 static int g_next_thread_id;
+static int g_writing_enabled = 1;
 
 static int timer_log_push_back(gpr_timer_log_list *list, gpr_timer_log *log) {
   if (list->head == NULL) {
@@ -177,7 +178,7 @@
   }
 }
 
-static void finish_writing() {
+static void finish_writing(void) {
   pthread_mutex_lock(&g_mu);
   g_shutdown = 1;
   pthread_cond_signal(&g_cv);
@@ -230,6 +231,10 @@
                                int important, const char *file, int line) {
   gpr_timer_entry *entry;
 
+  if (!g_writing_enabled) {
+    return;
+  }
+
   if (g_thread_log == NULL || g_thread_log->num_entries == MAX_COUNT) {
     rotate_log();
   }
@@ -261,6 +266,8 @@
   gpr_timers_log_add(tagstr, END, important, file, line);
 }
 
+void gpr_timer_set_enabled(int enabled) { g_writing_enabled = enabled; }
+
 /* Basic profiler specific API functions. */
 void gpr_timers_global_init(void) {}
 
@@ -272,4 +279,6 @@
 void gpr_timers_global_destroy(void) {}
 
 void gpr_timers_set_log_filename(const char *filename) {}
+
+void gpr_timer_set_enabled(int enabled) {}
 #endif /* GRPC_BASIC_PROFILER */
diff --git a/src/core/lib/profiling/timers.h b/src/core/lib/profiling/timers.h
index c8567e8..ea0cbca 100644
--- a/src/core/lib/profiling/timers.h
+++ b/src/core/lib/profiling/timers.h
@@ -34,6 +34,8 @@
 #ifndef GRPC_CORE_LIB_PROFILING_TIMERS_H
 #define GRPC_CORE_LIB_PROFILING_TIMERS_H
 
+#include <stdio.h>
+
 #ifdef __cplusplus
 extern "C" {
 #endif
@@ -50,18 +52,23 @@
 
 void gpr_timers_set_log_filename(const char *filename);
 
+void gpr_timer_set_enabled(int enabled);
+
 #if !(defined(GRPC_STAP_PROFILER) + defined(GRPC_BASIC_PROFILER))
 /* No profiling. No-op all the things. */
 #define GPR_TIMER_MARK(tag, important) \
   do {                                 \
+    /*printf("- %s\n", tag);*/         \
   } while (0)
 
 #define GPR_TIMER_BEGIN(tag, important) \
   do {                                  \
+    /*printf("%s {\n", tag);*/          \
   } while (0)
 
 #define GPR_TIMER_END(tag, important) \
   do {                                \
+    /*printf("} // %s\n", tag);*/     \
   } while (0)
 
 #else /* at least one profiler requested... */
diff --git a/src/core/lib/security/context/security_context.c b/src/core/lib/security/context/security_context.c
index 127b13e..2204fad 100644
--- a/src/core/lib/security/context/security_context.c
+++ b/src/core/lib/security/context/security_context.c
@@ -99,6 +99,9 @@
   grpc_client_security_context *c = (grpc_client_security_context *)ctx;
   grpc_call_credentials_unref(c->creds);
   GRPC_AUTH_CONTEXT_UNREF(c->auth_context, "client_security_context");
+  if (c->extension.instance != NULL && c->extension.destroy != NULL) {
+    c->extension.destroy(c->extension.instance);
+  }
   gpr_free(ctx);
 }
 
@@ -114,6 +117,9 @@
 void grpc_server_security_context_destroy(void *ctx) {
   grpc_server_security_context *c = (grpc_server_security_context *)ctx;
   GRPC_AUTH_CONTEXT_UNREF(c->auth_context, "server_security_context");
+  if (c->extension.instance != NULL && c->extension.destroy != NULL) {
+    c->extension.destroy(c->extension.instance);
+  }
   gpr_free(ctx);
 }
 
diff --git a/src/core/lib/security/context/security_context.h b/src/core/lib/security/context/security_context.h
index 4e7666d..1e131a0 100644
--- a/src/core/lib/security/context/security_context.h
+++ b/src/core/lib/security/context/security_context.h
@@ -84,6 +84,16 @@
 
 void grpc_auth_property_reset(grpc_auth_property *property);
 
+/* --- grpc_security_context_extension ---
+
+   Extension to the security context that may be set in a filter and accessed
+   later by a higher level method on a grpc_call object. */
+
+typedef struct {
+  void *instance;
+  void (*destroy)(void *);
+} grpc_security_context_extension;
+
 /* --- grpc_client_security_context ---
 
    Internal client-side security context. */
@@ -91,6 +101,7 @@
 typedef struct {
   grpc_call_credentials *creds;
   grpc_auth_context *auth_context;
+  grpc_security_context_extension extension;
 } grpc_client_security_context;
 
 grpc_client_security_context *grpc_client_security_context_create(void);
@@ -102,6 +113,7 @@
 
 typedef struct {
   grpc_auth_context *auth_context;
+  grpc_security_context_extension extension;
 } grpc_server_security_context;
 
 grpc_server_security_context *grpc_server_security_context_create(void);
diff --git a/src/core/lib/security/transport/client_auth_filter.c b/src/core/lib/security/transport/client_auth_filter.c
index 2a1bf4d..b366d14 100644
--- a/src/core/lib/security/transport/client_auth_filter.c
+++ b/src/core/lib/security/transport/client_auth_filter.c
@@ -40,6 +40,7 @@
 #include <grpc/support/string_util.h>
 
 #include "src/core/lib/channel/channel_stack.h"
+#include "src/core/lib/profiling/timers.h"
 #include "src/core/lib/security/context/security_context.h"
 #include "src/core/lib/security/credentials/credentials.h"
 #include "src/core/lib/security/transport/security_connector.h"
@@ -218,6 +219,8 @@
 static void auth_start_transport_op(grpc_exec_ctx *exec_ctx,
                                     grpc_call_element *elem,
                                     grpc_transport_stream_op *op) {
+  GPR_TIMER_BEGIN("auth_start_transport_op", 0);
+
   /* grab pointers to our data from the call element */
   call_data *calld = elem->call_data;
   channel_data *chand = elem->channel_data;
@@ -258,12 +261,14 @@
       grpc_channel_security_connector_check_call_host(
           exec_ctx, chand->security_connector, call_host, chand->auth_context,
           on_host_checked, elem);
+      GPR_TIMER_END("auth_start_transport_op", 0);
       return; /* early exit */
     }
   }
 
   /* pass control down the stack */
   grpc_call_next_op(exec_ctx, elem, op);
+  GPR_TIMER_END("auth_start_transport_op", 0);
 }
 
 /* Constructor for call_data */
diff --git a/src/core/lib/security/transport/secure_endpoint.c b/src/core/lib/security/transport/secure_endpoint.c
index 0169ccd..acb0113 100644
--- a/src/core/lib/security/transport/secure_endpoint.c
+++ b/src/core/lib/security/transport/secure_endpoint.c
@@ -38,6 +38,7 @@
 #include <grpc/support/slice_buffer.h>
 #include <grpc/support/sync.h>
 #include "src/core/lib/debug/trace.h"
+#include "src/core/lib/profiling/timers.h"
 #include "src/core/lib/security/transport/tsi_error.h"
 #include "src/core/lib/support/string.h"
 #include "src/core/lib/tsi/transport_security_interface.h"
@@ -248,6 +249,8 @@
 
 static void endpoint_write(grpc_exec_ctx *exec_ctx, grpc_endpoint *secure_ep,
                            gpr_slice_buffer *slices, grpc_closure *cb) {
+  GPR_TIMER_BEGIN("secure_endpoint.endpoint_write", 0);
+
   unsigned i;
   tsi_result result = TSI_OK;
   secure_endpoint *ep = (secure_endpoint *)secure_ep;
@@ -323,10 +326,12 @@
         exec_ctx, cb,
         grpc_set_tsi_error_result(GRPC_ERROR_CREATE("Wrap failed"), result),
         NULL);
+    GPR_TIMER_END("secure_endpoint.endpoint_write", 0);
     return;
   }
 
   grpc_endpoint_write(exec_ctx, ep->wrapped_ep, &ep->output_buffer, cb);
+  GPR_TIMER_END("secure_endpoint.endpoint_write", 0);
 }
 
 static void endpoint_shutdown(grpc_exec_ctx *exec_ctx,
diff --git a/src/core/lib/security/transport/server_auth_filter.c b/src/core/lib/security/transport/server_auth_filter.c
index def16c8..b2c6815 100644
--- a/src/core/lib/security/transport/server_auth_filter.c
+++ b/src/core/lib/security/transport/server_auth_filter.c
@@ -48,7 +48,7 @@
      up-call on transport_op, and remember to call our on_done_recv member after
      handling it. */
   grpc_closure auth_on_recv;
-  grpc_transport_stream_op transport_op;
+  grpc_transport_stream_op *transport_op;
   grpc_metadata_array md;
   const grpc_metadata *consumed_md;
   size_t num_consumed_md;
@@ -106,6 +106,10 @@
   return md;
 }
 
+static void destroy_op(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *error) {
+  gpr_free(arg);
+}
+
 /* called from application code */
 static void on_md_processing_done(
     void *user_data, const grpc_metadata *consumed_md, size_t num_consumed_md,
@@ -131,21 +135,22 @@
     grpc_exec_ctx_sched(&exec_ctx, calld->on_done_recv, GRPC_ERROR_NONE, NULL);
   } else {
     gpr_slice message;
-    grpc_transport_stream_op close_op;
-    memset(&close_op, 0, sizeof(close_op));
+    grpc_transport_stream_op *close_op = gpr_malloc(sizeof(*close_op));
+    memset(close_op, 0, sizeof(*close_op));
     grpc_metadata_array_destroy(&calld->md);
     error_details = error_details != NULL
                         ? error_details
                         : "Authentication metadata processing failed.";
     message = gpr_slice_from_copied_string(error_details);
-    calld->transport_op.send_initial_metadata = NULL;
-    if (calld->transport_op.send_message != NULL) {
-      grpc_byte_stream_destroy(&exec_ctx, calld->transport_op.send_message);
-      calld->transport_op.send_message = NULL;
+    calld->transport_op->send_initial_metadata = NULL;
+    if (calld->transport_op->send_message != NULL) {
+      grpc_byte_stream_destroy(&exec_ctx, calld->transport_op->send_message);
+      calld->transport_op->send_message = NULL;
     }
-    calld->transport_op.send_trailing_metadata = NULL;
-    grpc_transport_stream_op_add_close(&close_op, status, &message);
-    grpc_call_next_op(&exec_ctx, elem, &close_op);
+    calld->transport_op->send_trailing_metadata = NULL;
+    close_op->on_complete = grpc_closure_create(destroy_op, close_op);
+    grpc_transport_stream_op_add_close(close_op, status, &message);
+    grpc_call_next_op(&exec_ctx, elem, close_op);
     grpc_exec_ctx_sched(&exec_ctx, calld->on_done_recv,
                         grpc_error_set_int(GRPC_ERROR_CREATE(error_details),
                                            GRPC_ERROR_INT_GRPC_STATUS, status),
@@ -182,7 +187,7 @@
     calld->recv_initial_metadata = op->recv_initial_metadata;
     calld->on_done_recv = op->recv_initial_metadata_ready;
     op->recv_initial_metadata_ready = &calld->auth_on_recv;
-    calld->transport_op = *op;
+    calld->transport_op = op;
   }
 }
 
diff --git a/src/core/lib/support/log.c b/src/core/lib/support/log.c
index 899f121..6fbd947 100644
--- a/src/core/lib/support/log.c
+++ b/src/core/lib/support/log.c
@@ -82,11 +82,11 @@
 
   gpr_atm min_severity_to_print = GPR_LOG_SEVERITY_ERROR;
   if (verbosity != NULL) {
-    if (strcmp(verbosity, "DEBUG") == 0) {
+    if (gpr_stricmp(verbosity, "DEBUG") == 0) {
       min_severity_to_print = (gpr_atm)GPR_LOG_SEVERITY_DEBUG;
-    } else if (strcmp(verbosity, "INFO") == 0) {
+    } else if (gpr_stricmp(verbosity, "INFO") == 0) {
       min_severity_to_print = (gpr_atm)GPR_LOG_SEVERITY_INFO;
-    } else if (strcmp(verbosity, "ERROR") == 0) {
+    } else if (gpr_stricmp(verbosity, "ERROR") == 0) {
       min_severity_to_print = (gpr_atm)GPR_LOG_SEVERITY_ERROR;
     }
     gpr_free(verbosity);
diff --git a/src/core/lib/support/mpscq.c b/src/core/lib/support/mpscq.c
new file mode 100644
index 0000000..5b93232
--- /dev/null
+++ b/src/core/lib/support/mpscq.c
@@ -0,0 +1,83 @@
+/*
+ *
+ * Copyright 2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "src/core/lib/support/mpscq.h"
+
+#include <grpc/support/log.h>
+
+void gpr_mpscq_init(gpr_mpscq *q) {
+  gpr_atm_no_barrier_store(&q->head, (gpr_atm)&q->stub);
+  q->tail = &q->stub;
+  gpr_atm_no_barrier_store(&q->stub.next, (gpr_atm)NULL);
+}
+
+void gpr_mpscq_destroy(gpr_mpscq *q) {
+  GPR_ASSERT(gpr_atm_no_barrier_load(&q->head) == (gpr_atm)&q->stub);
+  GPR_ASSERT(q->tail == &q->stub);
+}
+
+void gpr_mpscq_push(gpr_mpscq *q, gpr_mpscq_node *n) {
+  gpr_atm_no_barrier_store(&n->next, (gpr_atm)NULL);
+  gpr_mpscq_node *prev =
+      (gpr_mpscq_node *)gpr_atm_full_xchg(&q->head, (gpr_atm)n);
+  gpr_atm_rel_store(&prev->next, (gpr_atm)n);
+}
+
+gpr_mpscq_node *gpr_mpscq_pop(gpr_mpscq *q) {
+  gpr_mpscq_node *tail = q->tail;
+  gpr_mpscq_node *next = (gpr_mpscq_node *)gpr_atm_acq_load(&tail->next);
+  if (tail == &q->stub) {
+    // indicates the list is actually (ephemerally) empty
+    if (next == NULL) return NULL;
+    q->tail = next;
+    tail = next;
+    next = (gpr_mpscq_node *)gpr_atm_acq_load(&tail->next);
+  }
+  if (next != NULL) {
+    q->tail = next;
+    return tail;
+  }
+  gpr_mpscq_node *head = (gpr_mpscq_node *)gpr_atm_acq_load(&q->head);
+  if (tail != head) {
+    // indicates a retry is in order: we're still adding
+    return NULL;
+  }
+  gpr_mpscq_push(q, &q->stub);
+  next = (gpr_mpscq_node *)gpr_atm_acq_load(&tail->next);
+  if (next != NULL) {
+    q->tail = next;
+    return tail;
+  }
+  // indicates a retry is in order: we're still adding
+  return NULL;
+}
diff --git a/src/core/lib/support/mpscq.h b/src/core/lib/support/mpscq.h
new file mode 100644
index 0000000..977a117
--- /dev/null
+++ b/src/core/lib/support/mpscq.h
@@ -0,0 +1,65 @@
+/*
+ *
+ * Copyright 2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef GRPC_CORE_LIB_SUPPORT_MPSCQ_H
+#define GRPC_CORE_LIB_SUPPORT_MPSCQ_H
+
+#include <grpc/support/atm.h>
+#include <stddef.h>
+
+// Multiple-producer single-consumer lock free queue, based upon the
+// implementation from Dmitry Vyukov here:
+// http://www.1024cores.net/home/lock-free-algorithms/queues/intrusive-mpsc-node-based-queue
+
+// List node (include this in a data structure at the top, and add application
+// fields after it - to simulate inheritance)
+typedef struct gpr_mpscq_node { gpr_atm next; } gpr_mpscq_node;
+
+// Actual queue type
+typedef struct gpr_mpscq {
+  gpr_atm head;
+  // make sure head & tail don't share a cacheline
+  char padding[GPR_CACHELINE_SIZE];
+  gpr_mpscq_node *tail;
+  gpr_mpscq_node stub;
+} gpr_mpscq;
+
+void gpr_mpscq_init(gpr_mpscq *q);
+void gpr_mpscq_destroy(gpr_mpscq *q);
+// Push a node
+void gpr_mpscq_push(gpr_mpscq *q, gpr_mpscq_node *n);
+// Pop a node (returns NULL if no node is ready - which doesn't indicate that
+// the queue is empty!!)
+gpr_mpscq_node *gpr_mpscq_pop(gpr_mpscq *q);
+
+#endif /* GRPC_CORE_LIB_SUPPORT_MPSCQ_H */
diff --git a/src/core/lib/support/string.c b/src/core/lib/support/string.c
index 30c1e67..d17fb9d 100644
--- a/src/core/lib/support/string.c
+++ b/src/core/lib/support/string.c
@@ -304,3 +304,14 @@
 char *gpr_strvec_flatten(gpr_strvec *sv, size_t *final_length) {
   return gpr_strjoin((const char **)sv->strs, sv->count, final_length);
 }
+
+int gpr_stricmp(const char *a, const char *b) {
+  int ca, cb;
+  do {
+    ca = tolower(*a);
+    cb = tolower(*b);
+    ++a;
+    ++b;
+  } while (ca == cb && ca && cb);
+  return ca - cb;
+}
diff --git a/src/core/lib/support/string.h b/src/core/lib/support/string.h
index 2b6bb3e..3aebc08 100644
--- a/src/core/lib/support/string.h
+++ b/src/core/lib/support/string.h
@@ -118,6 +118,8 @@
    total_length as per gpr_strjoin */
 char *gpr_strvec_flatten(gpr_strvec *strs, size_t *total_length);
 
+int gpr_stricmp(const char *a, const char *b);
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/src/core/lib/surface/call.c b/src/core/lib/surface/call.c
index 7726811..97bfd58 100644
--- a/src/core/lib/surface/call.c
+++ b/src/core/lib/surface/call.c
@@ -109,6 +109,10 @@
   uint8_t recv_message;
   uint8_t recv_final_op;
   uint8_t is_notify_tag_closure;
+
+  /* TODO(ctiller): now that this is inlined, figure out how much of the above
+                    state can be eliminated */
+  grpc_transport_stream_op op;
 } batch_control;
 
 struct grpc_call {
@@ -226,33 +230,33 @@
 static void receiving_slice_ready(grpc_exec_ctx *exec_ctx, void *bctlp,
                                   grpc_error *error);
 
-grpc_call *grpc_call_create(
-    grpc_channel *channel, grpc_call *parent_call, uint32_t propagation_mask,
-    grpc_completion_queue *cq, grpc_pollset_set *pollset_set_alternative,
-    const void *server_transport_data, grpc_mdelem **add_initial_metadata,
-    size_t add_initial_metadata_count, gpr_timespec send_deadline) {
+grpc_error *grpc_call_create(const grpc_call_create_args *args,
+                             grpc_call **out_call) {
   size_t i, j;
-  grpc_channel_stack *channel_stack = grpc_channel_get_channel_stack(channel);
+  grpc_channel_stack *channel_stack =
+      grpc_channel_get_channel_stack(args->channel);
   grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
   grpc_call *call;
   GPR_TIMER_BEGIN("grpc_call_create", 0);
-  call = gpr_malloc(sizeof(grpc_call) + channel_stack->call_stack_size);
+  *out_call = call =
+      gpr_malloc(sizeof(grpc_call) + channel_stack->call_stack_size);
   memset(call, 0, sizeof(grpc_call));
   gpr_mu_init(&call->mu);
-  call->channel = channel;
-  call->cq = cq;
-  call->parent = parent_call;
+  call->channel = args->channel;
+  call->cq = args->cq;
+  call->parent = args->parent_call;
   /* Always support no compression */
   GPR_BITSET(&call->encodings_accepted_by_peer, GRPC_COMPRESS_NONE);
-  call->is_client = server_transport_data == NULL;
+  call->is_client = args->server_transport_data == NULL;
   if (call->is_client) {
-    GPR_ASSERT(add_initial_metadata_count < MAX_SEND_EXTRA_METADATA_COUNT);
-    for (i = 0; i < add_initial_metadata_count; i++) {
-      call->send_extra_metadata[i].md = add_initial_metadata[i];
+    GPR_ASSERT(args->add_initial_metadata_count <
+               MAX_SEND_EXTRA_METADATA_COUNT);
+    for (i = 0; i < args->add_initial_metadata_count; i++) {
+      call->send_extra_metadata[i].md = args->add_initial_metadata[i];
     }
-    call->send_extra_metadata_count = (int)add_initial_metadata_count;
+    call->send_extra_metadata_count = (int)args->add_initial_metadata_count;
   } else {
-    GPR_ASSERT(add_initial_metadata_count == 0);
+    GPR_ASSERT(args->add_initial_metadata_count == 0);
     call->send_extra_metadata_count = 0;
   }
   for (i = 0; i < 2; i++) {
@@ -261,78 +265,79 @@
     }
   }
   call->send_deadline =
-      gpr_convert_clock_type(send_deadline, GPR_CLOCK_MONOTONIC);
-  GRPC_CHANNEL_INTERNAL_REF(channel, "call");
+      gpr_convert_clock_type(args->send_deadline, GPR_CLOCK_MONOTONIC);
+  GRPC_CHANNEL_INTERNAL_REF(args->channel, "call");
   /* initial refcount dropped by grpc_call_destroy */
   grpc_error *error = grpc_call_stack_init(
       &exec_ctx, channel_stack, 1, destroy_call, call, call->context,
-      server_transport_data, CALL_STACK_FROM_CALL(call));
+      args->server_transport_data, CALL_STACK_FROM_CALL(call));
   if (error != GRPC_ERROR_NONE) {
     intptr_t status;
-    if (!grpc_error_get_int(error, GRPC_ERROR_INT_GRPC_STATUS, &status))
+    if (!grpc_error_get_int(error, GRPC_ERROR_INT_GRPC_STATUS, &status)) {
       status = GRPC_STATUS_UNKNOWN;
+    }
     const char *error_str =
         grpc_error_get_str(error, GRPC_ERROR_STR_DESCRIPTION);
     close_with_status(&exec_ctx, call, (grpc_status_code)status,
                       error_str == NULL ? "unknown error" : error_str);
-    GRPC_ERROR_UNREF(error);
   }
-  if (cq != NULL) {
+  if (args->cq != NULL) {
     GPR_ASSERT(
-        pollset_set_alternative == NULL &&
+        args->pollset_set_alternative == NULL &&
         "Only one of 'cq' and 'pollset_set_alternative' should be non-NULL.");
-    GRPC_CQ_INTERNAL_REF(cq, "bind");
+    GRPC_CQ_INTERNAL_REF(args->cq, "bind");
     call->pollent =
-        grpc_polling_entity_create_from_pollset(grpc_cq_pollset(cq));
+        grpc_polling_entity_create_from_pollset(grpc_cq_pollset(args->cq));
   }
-  if (pollset_set_alternative != NULL) {
-    call->pollent =
-        grpc_polling_entity_create_from_pollset_set(pollset_set_alternative);
+  if (args->pollset_set_alternative != NULL) {
+    call->pollent = grpc_polling_entity_create_from_pollset_set(
+        args->pollset_set_alternative);
   }
   if (!grpc_polling_entity_is_empty(&call->pollent)) {
     grpc_call_stack_set_pollset_or_pollset_set(
         &exec_ctx, CALL_STACK_FROM_CALL(call), &call->pollent);
   }
-  if (parent_call != NULL) {
-    GRPC_CALL_INTERNAL_REF(parent_call, "child");
+  gpr_timespec send_deadline = args->send_deadline;
+  if (args->parent_call != NULL) {
+    GRPC_CALL_INTERNAL_REF(args->parent_call, "child");
     GPR_ASSERT(call->is_client);
-    GPR_ASSERT(!parent_call->is_client);
+    GPR_ASSERT(!args->parent_call->is_client);
 
-    gpr_mu_lock(&parent_call->mu);
+    gpr_mu_lock(&args->parent_call->mu);
 
-    if (propagation_mask & GRPC_PROPAGATE_DEADLINE) {
+    if (args->propagation_mask & GRPC_PROPAGATE_DEADLINE) {
       send_deadline = gpr_time_min(
           gpr_convert_clock_type(send_deadline,
-                                 parent_call->send_deadline.clock_type),
-          parent_call->send_deadline);
+                                 args->parent_call->send_deadline.clock_type),
+          args->parent_call->send_deadline);
     }
     /* for now GRPC_PROPAGATE_TRACING_CONTEXT *MUST* be passed with
      * GRPC_PROPAGATE_STATS_CONTEXT */
     /* TODO(ctiller): This should change to use the appropriate census start_op
      * call. */
-    if (propagation_mask & GRPC_PROPAGATE_CENSUS_TRACING_CONTEXT) {
-      GPR_ASSERT(propagation_mask & GRPC_PROPAGATE_CENSUS_STATS_CONTEXT);
-      grpc_call_context_set(call, GRPC_CONTEXT_TRACING,
-                            parent_call->context[GRPC_CONTEXT_TRACING].value,
-                            NULL);
+    if (args->propagation_mask & GRPC_PROPAGATE_CENSUS_TRACING_CONTEXT) {
+      GPR_ASSERT(args->propagation_mask & GRPC_PROPAGATE_CENSUS_STATS_CONTEXT);
+      grpc_call_context_set(
+          call, GRPC_CONTEXT_TRACING,
+          args->parent_call->context[GRPC_CONTEXT_TRACING].value, NULL);
     } else {
-      GPR_ASSERT(propagation_mask & GRPC_PROPAGATE_CENSUS_STATS_CONTEXT);
+      GPR_ASSERT(args->propagation_mask & GRPC_PROPAGATE_CENSUS_STATS_CONTEXT);
     }
-    if (propagation_mask & GRPC_PROPAGATE_CANCELLATION) {
+    if (args->propagation_mask & GRPC_PROPAGATE_CANCELLATION) {
       call->cancellation_is_inherited = 1;
     }
 
-    if (parent_call->first_child == NULL) {
-      parent_call->first_child = call;
+    if (args->parent_call->first_child == NULL) {
+      args->parent_call->first_child = call;
       call->sibling_next = call->sibling_prev = call;
     } else {
-      call->sibling_next = parent_call->first_child;
-      call->sibling_prev = parent_call->first_child->sibling_prev;
+      call->sibling_next = args->parent_call->first_child;
+      call->sibling_prev = args->parent_call->first_child->sibling_prev;
       call->sibling_next->sibling_prev = call->sibling_prev->sibling_next =
           call;
     }
 
-    gpr_mu_unlock(&parent_call->mu);
+    gpr_mu_unlock(&args->parent_call->mu);
   }
   if (gpr_time_cmp(send_deadline, gpr_inf_future(send_deadline.clock_type)) !=
       0) {
@@ -340,7 +345,7 @@
   }
   grpc_exec_ctx_finish(&exec_ctx);
   GPR_TIMER_END("grpc_call_create", 0);
-  return call;
+  return error;
 }
 
 void grpc_call_set_completion_queue(grpc_exec_ctx *exec_ctx, grpc_call *call,
@@ -778,6 +783,7 @@
   grpc_error *error;
   grpc_closure *op_closure;
   enum { TC_CANCEL, TC_CLOSE } type;
+  grpc_transport_stream_op op;
 } termination_closure;
 
 static void done_termination(grpc_exec_ctx *exec_ctx, void *tcp,
@@ -797,26 +803,24 @@
 }
 
 static void send_cancel(grpc_exec_ctx *exec_ctx, void *tcp, grpc_error *error) {
-  grpc_transport_stream_op op;
   termination_closure *tc = tcp;
-  memset(&op, 0, sizeof(op));
-  op.cancel_error = tc->error;
+  memset(&tc->op, 0, sizeof(tc->op));
+  tc->op.cancel_error = tc->error;
   /* reuse closure to catch completion */
   grpc_closure_init(&tc->closure, done_termination, tc);
-  op.on_complete = &tc->closure;
-  execute_op(exec_ctx, tc->call, &op);
+  tc->op.on_complete = &tc->closure;
+  execute_op(exec_ctx, tc->call, &tc->op);
 }
 
 static void send_close(grpc_exec_ctx *exec_ctx, void *tcp, grpc_error *error) {
-  grpc_transport_stream_op op;
   termination_closure *tc = tcp;
-  memset(&op, 0, sizeof(op));
-  op.close_error = tc->error;
+  memset(&tc->op, 0, sizeof(tc->op));
+  tc->op.close_error = tc->error;
   /* reuse closure to catch completion */
   grpc_closure_init(&tc->closure, done_termination, tc);
-  tc->op_closure = op.on_complete;
-  op.on_complete = &tc->closure;
-  execute_op(exec_ctx, tc->call, &op);
+  tc->op_closure = tc->op.on_complete;
+  tc->op.on_complete = &tc->closure;
+  execute_op(exec_ctx, tc->call, &tc->op);
 }
 
 static grpc_call_error terminate_with_status(grpc_exec_ctx *exec_ctx,
@@ -1086,9 +1090,14 @@
 static void post_batch_completion(grpc_exec_ctx *exec_ctx,
                                   batch_control *bctl) {
   grpc_call *call = bctl->call;
+  grpc_error *error = bctl->error;
+  if (bctl->recv_final_op) {
+    GRPC_ERROR_UNREF(error);
+    error = GRPC_ERROR_NONE;
+  }
   if (bctl->is_notify_tag_closure) {
     /* unrefs bctl->error */
-    grpc_exec_ctx_sched(exec_ctx, bctl->notify_tag, bctl->error, NULL);
+    grpc_closure_run(exec_ctx, bctl->notify_tag, error);
     gpr_mu_lock(&call->mu);
     bctl->call->used_batches =
         (uint8_t)(bctl->call->used_batches &
@@ -1097,7 +1106,7 @@
     GRPC_CALL_INTERNAL_UNREF(exec_ctx, call, "completion");
   } else {
     /* unrefs bctl->error */
-    grpc_cq_end_op(exec_ctx, bctl->call->cq, bctl->notify_tag, bctl->error,
+    grpc_cq_end_op(exec_ctx, bctl->call->cq, bctl->notify_tag, error,
                    finish_batch_completion, bctl, &bctl->cq_completion);
   }
 }
@@ -1254,6 +1263,14 @@
   }
 }
 
+static void add_batch_error(batch_control *bctl, grpc_error *error) {
+  if (error == GRPC_ERROR_NONE) return;
+  if (bctl->error == GRPC_ERROR_NONE) {
+    bctl->error = GRPC_ERROR_CREATE("Call batch operation failed");
+  }
+  bctl->error = grpc_error_add_child(bctl->error, error);
+}
+
 static void receiving_initial_metadata_ready(grpc_exec_ctx *exec_ctx,
                                              void *bctlp, grpc_error *error) {
   batch_control *bctl = bctlp;
@@ -1261,9 +1278,8 @@
 
   gpr_mu_lock(&call->mu);
 
-  if (error != GRPC_ERROR_NONE) {
-    bctl->error = GRPC_ERROR_REF(error);
-  } else {
+  add_batch_error(bctl, GRPC_ERROR_REF(error));
+  if (error == GRPC_ERROR_NONE) {
     grpc_metadata_batch *md =
         &call->metadata_batch[1 /* is_receiving */][0 /* is_trailing */];
     grpc_metadata_batch_filter(md, recv_initial_filter, call);
@@ -1356,8 +1372,7 @@
     GRPC_ERROR_UNREF(error);
     error = GRPC_ERROR_NONE;
   }
-  GRPC_ERROR_UNREF(bctl->error);
-  bctl->error = GRPC_ERROR_REF(error);
+  add_batch_error(bctl, GRPC_ERROR_REF(error));
   gpr_mu_unlock(&call->mu);
   if (gpr_unref(&bctl->steps_to_complete)) {
     post_batch_completion(exec_ctx, bctl);
@@ -1370,7 +1385,6 @@
                                         grpc_call *call, const grpc_op *ops,
                                         size_t nops, void *notify_tag,
                                         int is_notify_tag_closure) {
-  grpc_transport_stream_op stream_op;
   size_t i;
   const grpc_op *op;
   batch_control *bctl;
@@ -1384,8 +1398,6 @@
 
   GRPC_CALL_LOG_BATCH(GPR_INFO, call, ops, nops, notify_tag);
 
-  memset(&stream_op, 0, sizeof(stream_op));
-
   /* TODO(ctiller): this feels like it could be made lock-free */
   gpr_mu_lock(&call->mu);
   bctl = allocate_batch_control(call);
@@ -1394,6 +1406,10 @@
   bctl->notify_tag = notify_tag;
   bctl->is_notify_tag_closure = (uint8_t)(is_notify_tag_closure != 0);
 
+  grpc_transport_stream_op *stream_op = &bctl->op;
+  memset(stream_op, 0, sizeof(*stream_op));
+  stream_op->covered_by_poller = true;
+
   if (nops == 0) {
     GRPC_CALL_INTERNAL_REF(call, "completion");
     bctl->error = GRPC_ERROR_NONE;
@@ -1471,9 +1487,9 @@
         }
         /* TODO(ctiller): just make these the same variable? */
         call->metadata_batch[0][0].deadline = call->send_deadline;
-        stream_op.send_initial_metadata =
+        stream_op->send_initial_metadata =
             &call->metadata_batch[0 /* is_receiving */][0 /* is_trailing */];
-        stream_op.send_initial_metadata_flags = op->flags;
+        stream_op->send_initial_metadata_flags = op->flags;
         break;
       case GRPC_OP_SEND_MESSAGE:
         if (!are_write_flags_valid(op->flags)) {
@@ -1493,7 +1509,7 @@
         grpc_slice_buffer_stream_init(
             &call->sending_stream,
             &op->data.send_message->data.raw.slice_buffer, op->flags);
-        stream_op.send_message = &call->sending_stream.base;
+        stream_op->send_message = &call->sending_stream.base;
         break;
       case GRPC_OP_SEND_CLOSE_FROM_CLIENT:
         /* Flag validation: currently allow no flags */
@@ -1511,7 +1527,7 @@
         }
         bctl->send_final_op = 1;
         call->sent_final_op = 1;
-        stream_op.send_trailing_metadata =
+        stream_op->send_trailing_metadata =
             &call->metadata_batch[0 /* is_receiving */][1 /* is_trailing */];
         break;
       case GRPC_OP_SEND_STATUS_FROM_SERVER:
@@ -1558,7 +1574,7 @@
           error = GRPC_CALL_ERROR_INVALID_METADATA;
           goto done_with_error;
         }
-        stream_op.send_trailing_metadata =
+        stream_op->send_trailing_metadata =
             &call->metadata_batch[0 /* is_receiving */][1 /* is_trailing */];
         break;
       case GRPC_OP_RECV_INITIAL_METADATA:
@@ -1576,9 +1592,9 @@
         grpc_closure_init(&call->receiving_initial_metadata_ready,
                           receiving_initial_metadata_ready, bctl);
         bctl->recv_initial_metadata = 1;
-        stream_op.recv_initial_metadata =
+        stream_op->recv_initial_metadata =
             &call->metadata_batch[1 /* is_receiving */][0 /* is_trailing */];
-        stream_op.recv_initial_metadata_ready =
+        stream_op->recv_initial_metadata_ready =
             &call->receiving_initial_metadata_ready;
         num_completion_callbacks_needed++;
         break;
@@ -1595,10 +1611,10 @@
         call->receiving_message = 1;
         bctl->recv_message = 1;
         call->receiving_buffer = op->data.recv_message;
-        stream_op.recv_message = &call->receiving_stream;
+        stream_op->recv_message = &call->receiving_stream;
         grpc_closure_init(&call->receiving_stream_ready, receiving_stream_ready,
                           bctl);
-        stream_op.recv_message_ready = &call->receiving_stream_ready;
+        stream_op->recv_message_ready = &call->receiving_stream_ready;
         num_completion_callbacks_needed++;
         break;
       case GRPC_OP_RECV_STATUS_ON_CLIENT:
@@ -1624,9 +1640,9 @@
         call->final_op.client.status_details_capacity =
             op->data.recv_status_on_client.status_details_capacity;
         bctl->recv_final_op = 1;
-        stream_op.recv_trailing_metadata =
+        stream_op->recv_trailing_metadata =
             &call->metadata_batch[1 /* is_receiving */][1 /* is_trailing */];
-        stream_op.collect_stats =
+        stream_op->collect_stats =
             &call->final_info.stats.transport_stream_stats;
         break;
       case GRPC_OP_RECV_CLOSE_ON_SERVER:
@@ -1647,9 +1663,9 @@
         call->final_op.server.cancelled =
             op->data.recv_close_on_server.cancelled;
         bctl->recv_final_op = 1;
-        stream_op.recv_trailing_metadata =
+        stream_op->recv_trailing_metadata =
             &call->metadata_batch[1 /* is_receiving */][1 /* is_trailing */];
-        stream_op.collect_stats =
+        stream_op->collect_stats =
             &call->final_info.stats.transport_stream_stats;
         break;
     }
@@ -1661,12 +1677,12 @@
   }
   gpr_ref_init(&bctl->steps_to_complete, num_completion_callbacks_needed);
 
-  stream_op.context = call->context;
+  stream_op->context = call->context;
   grpc_closure_init(&bctl->finish_batch, finish_batch, bctl);
-  stream_op.on_complete = &bctl->finish_batch;
+  stream_op->on_complete = &bctl->finish_batch;
   gpr_mu_unlock(&call->mu);
 
-  execute_op(exec_ctx, call, &stream_op);
+  execute_op(exec_ctx, call, stream_op);
 
 done:
   GPR_TIMER_END("grpc_call_start_batch", 0);
diff --git a/src/core/lib/surface/call.h b/src/core/lib/surface/call.h
index 3a78fe3..18af41b 100644
--- a/src/core/lib/surface/call.h
+++ b/src/core/lib/surface/call.h
@@ -49,15 +49,29 @@
                                            grpc_call *call, int success,
                                            void *user_data);
 
-grpc_call *grpc_call_create(grpc_channel *channel, grpc_call *parent_call,
-                            uint32_t propagation_mask,
-                            grpc_completion_queue *cq,
-                            /* if not NULL, it'll be used in lieu of \a cq */
-                            grpc_pollset_set *pollset_set_alternative,
-                            const void *server_transport_data,
-                            grpc_mdelem **add_initial_metadata,
-                            size_t add_initial_metadata_count,
-                            gpr_timespec send_deadline);
+typedef struct grpc_call_create_args {
+  grpc_channel *channel;
+
+  grpc_call *parent_call;
+  uint32_t propagation_mask;
+
+  grpc_completion_queue *cq;
+  /* if not NULL, it'll be used in lieu of cq */
+  grpc_pollset_set *pollset_set_alternative;
+
+  const void *server_transport_data;
+
+  grpc_mdelem **add_initial_metadata;
+  size_t add_initial_metadata_count;
+
+  gpr_timespec send_deadline;
+} grpc_call_create_args;
+
+/* Create a new call based on \a args.
+   Regardless of success or failure, always returns a valid new call into *call
+   */
+grpc_error *grpc_call_create(const grpc_call_create_args *args,
+                             grpc_call **call);
 
 void grpc_call_set_completion_queue(grpc_exec_ctx *exec_ctx, grpc_call *call,
                                     grpc_completion_queue *cq);
diff --git a/src/core/lib/surface/channel.c b/src/core/lib/surface/channel.c
index 6d2b1c4..aa8c052 100644
--- a/src/core/lib/surface/channel.c
+++ b/src/core/lib/surface/channel.c
@@ -208,9 +208,21 @@
     send_metadata[num_metadata++] = GRPC_MDELEM_REF(channel->default_authority);
   }
 
-  return grpc_call_create(channel, parent_call, propagation_mask, cq,
-                          pollset_set_alternative, NULL, send_metadata,
-                          num_metadata, deadline);
+  grpc_call_create_args args;
+  memset(&args, 0, sizeof(args));
+  args.channel = channel;
+  args.parent_call = parent_call;
+  args.propagation_mask = propagation_mask;
+  args.cq = cq;
+  args.pollset_set_alternative = pollset_set_alternative;
+  args.server_transport_data = NULL;
+  args.add_initial_metadata = send_metadata;
+  args.add_initial_metadata_count = num_metadata;
+  args.send_deadline = deadline;
+
+  grpc_call *call;
+  GRPC_LOG_IF_ERROR("call_create", grpc_call_create(&args, &call));
+  return call;
 }
 
 grpc_call *grpc_channel_create_call(grpc_channel *channel,
@@ -334,14 +346,13 @@
 }
 
 void grpc_channel_destroy(grpc_channel *channel) {
-  grpc_transport_op op;
+  grpc_transport_op *op = grpc_make_transport_op(NULL);
   grpc_channel_element *elem;
   grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
   GRPC_API_TRACE("grpc_channel_destroy(channel=%p)", 1, (channel));
-  memset(&op, 0, sizeof(op));
-  op.disconnect_with_error = GRPC_ERROR_CREATE("Channel Destroyed");
+  op->disconnect_with_error = GRPC_ERROR_CREATE("Channel Destroyed");
   elem = grpc_channel_stack_element(CHANNEL_STACK_FROM_CHANNEL(channel), 0);
-  elem->filter->start_transport_op(&exec_ctx, elem, &op);
+  elem->filter->start_transport_op(&exec_ctx, elem, op);
 
   GRPC_CHANNEL_INTERNAL_UNREF(&exec_ctx, channel, "channel");
 
diff --git a/src/core/lib/surface/channel_ping.c b/src/core/lib/surface/channel_ping.c
index 9818f9d..0d2f01a 100644
--- a/src/core/lib/surface/channel_ping.c
+++ b/src/core/lib/surface/channel_ping.c
@@ -61,19 +61,20 @@
 
 void grpc_channel_ping(grpc_channel *channel, grpc_completion_queue *cq,
                        void *tag, void *reserved) {
-  grpc_transport_op op;
+  GRPC_API_TRACE("grpc_channel_ping(channel=%p, cq=%p, tag=%p, reserved=%p)", 4,
+                 (channel, cq, tag, reserved));
+  grpc_transport_op *op = grpc_make_transport_op(NULL);
   ping_result *pr = gpr_malloc(sizeof(*pr));
   grpc_channel_element *top_elem =
       grpc_channel_stack_element(grpc_channel_get_channel_stack(channel), 0);
   grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
   GPR_ASSERT(reserved == NULL);
-  memset(&op, 0, sizeof(op));
   pr->tag = tag;
   pr->cq = cq;
   grpc_closure_init(&pr->closure, ping_done, pr);
-  op.send_ping = &pr->closure;
-  op.bind_pollset = grpc_cq_pollset(cq);
+  op->send_ping = &pr->closure;
+  op->bind_pollset = grpc_cq_pollset(cq);
   grpc_cq_begin_op(cq, tag);
-  top_elem->filter->start_transport_op(&exec_ctx, top_elem, &op);
+  top_elem->filter->start_transport_op(&exec_ctx, top_elem, op);
   grpc_exec_ctx_finish(&exec_ctx);
 }
diff --git a/src/core/lib/surface/completion_queue.c b/src/core/lib/surface/completion_queue.c
index 5978884..4e0feb5 100644
--- a/src/core/lib/surface/completion_queue.c
+++ b/src/core/lib/surface/completion_queue.c
@@ -39,6 +39,7 @@
 #include <grpc/support/alloc.h>
 #include <grpc/support/atm.h>
 #include <grpc/support/log.h>
+#include <grpc/support/string_util.h>
 #include <grpc/support/time.h>
 
 #include "src/core/lib/iomgr/pollset.h"
@@ -50,6 +51,9 @@
 #include "src/core/lib/surface/event_string.h"
 
 int grpc_trace_operation_failures;
+#ifndef NDEBUG
+int grpc_trace_pending_tags;
+#endif
 
 typedef struct {
   grpc_pollset_worker **worker;
@@ -67,6 +71,9 @@
   gpr_refcount pending_events;
   /** Once owning_refs drops to zero, we will destroy the cq */
   gpr_refcount owning_refs;
+  /** counter of how many things have ever been queued on this completion queue
+      useful for avoiding locks to check the queue */
+  gpr_atm things_queued_ever;
   /** 0 initially, 1 once we've begun shutting down */
   int shutdown;
   int shutdown_called;
@@ -121,15 +128,6 @@
   }
 }
 
-struct grpc_cq_alarm {
-  grpc_timer alarm;
-  grpc_cq_completion completion;
-  /** completion queue where events about this alarm will be posted */
-  grpc_completion_queue *cq;
-  /** user supplied tag */
-  void *tag;
-};
-
 grpc_completion_queue *grpc_completion_queue_create(void *reserved) {
   grpc_completion_queue *cc;
   GPR_ASSERT(!reserved);
@@ -166,6 +164,7 @@
   cc->is_server_cq = 0;
   cc->is_non_listening_server_cq = 0;
   cc->num_pluckers = 0;
+  gpr_atm_no_barrier_store(&cc->things_queued_ever, 0);
 #ifndef NDEBUG
   cc->outstanding_tag_count = 0;
 #endif
@@ -276,6 +275,7 @@
   GPR_ASSERT(found);
 #endif
   shutdown = gpr_unref(&cc->pending_events);
+  gpr_atm_no_barrier_fetch_add(&cc->things_queued_ever, 1);
   if (!shutdown) {
     cc->completed_tail->next =
         ((uintptr_t)storage) | (1u & (uintptr_t)cc->completed_tail->next);
@@ -313,13 +313,66 @@
   GRPC_ERROR_UNREF(error);
 }
 
+typedef struct {
+  gpr_atm last_seen_things_queued_ever;
+  grpc_completion_queue *cq;
+  gpr_timespec deadline;
+  grpc_cq_completion *stolen_completion;
+  void *tag; /* for pluck */
+  bool first_loop;
+} cq_is_finished_arg;
+
+static bool cq_is_next_finished(grpc_exec_ctx *exec_ctx, void *arg) {
+  cq_is_finished_arg *a = arg;
+  grpc_completion_queue *cq = a->cq;
+  GPR_ASSERT(a->stolen_completion == NULL);
+  gpr_atm current_last_seen_things_queued_ever =
+      gpr_atm_no_barrier_load(&cq->things_queued_ever);
+  if (current_last_seen_things_queued_ever != a->last_seen_things_queued_ever) {
+    gpr_mu_lock(cq->mu);
+    a->last_seen_things_queued_ever =
+        gpr_atm_no_barrier_load(&cq->things_queued_ever);
+    if (cq->completed_tail != &cq->completed_head) {
+      a->stolen_completion = (grpc_cq_completion *)cq->completed_head.next;
+      cq->completed_head.next = a->stolen_completion->next & ~(uintptr_t)1;
+      if (a->stolen_completion == cq->completed_tail) {
+        cq->completed_tail = &cq->completed_head;
+      }
+      gpr_mu_unlock(cq->mu);
+      return true;
+    }
+    gpr_mu_unlock(cq->mu);
+  }
+  return !a->first_loop &&
+         gpr_time_cmp(a->deadline, gpr_now(a->deadline.clock_type)) < 0;
+}
+
+#ifndef NDEBUG
+static void dump_pending_tags(grpc_completion_queue *cc) {
+  if (!grpc_trace_pending_tags) return;
+
+  gpr_strvec v;
+  gpr_strvec_init(&v);
+  gpr_strvec_add(&v, gpr_strdup("PENDING TAGS:"));
+  for (size_t i = 0; i < cc->outstanding_tag_count; i++) {
+    char *s;
+    gpr_asprintf(&s, " %p", cc->outstanding_tags[i]);
+    gpr_strvec_add(&v, s);
+  }
+  char *out = gpr_strvec_flatten(&v, NULL);
+  gpr_strvec_destroy(&v);
+  gpr_log(GPR_DEBUG, "%s", out);
+  gpr_free(out);
+}
+#else
+static void dump_pending_tags(grpc_completion_queue *cc) {}
+#endif
+
 grpc_event grpc_completion_queue_next(grpc_completion_queue *cc,
                                       gpr_timespec deadline, void *reserved) {
   grpc_event ret;
   grpc_pollset_worker *worker = NULL;
-  int first_loop = 1;
   gpr_timespec now;
-  grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
 
   GPR_TIMER_BEGIN("grpc_completion_queue_next", 0);
 
@@ -333,11 +386,33 @@
           reserved));
   GPR_ASSERT(!reserved);
 
+  dump_pending_tags(cc);
+
   deadline = gpr_convert_clock_type(deadline, GPR_CLOCK_MONOTONIC);
 
   GRPC_CQ_INTERNAL_REF(cc, "next");
   gpr_mu_lock(cc->mu);
+  cq_is_finished_arg is_finished_arg = {
+      .last_seen_things_queued_ever =
+          gpr_atm_no_barrier_load(&cc->things_queued_ever),
+      .cq = cc,
+      .deadline = deadline,
+      .stolen_completion = NULL,
+      .tag = NULL,
+      .first_loop = true};
+  grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT_WITH_FINISH_CHECK(
+      cq_is_next_finished, &is_finished_arg);
   for (;;) {
+    if (is_finished_arg.stolen_completion != NULL) {
+      gpr_mu_unlock(cc->mu);
+      grpc_cq_completion *c = is_finished_arg.stolen_completion;
+      is_finished_arg.stolen_completion = NULL;
+      ret.type = GRPC_OP_COMPLETE;
+      ret.success = c->next & 1u;
+      ret.tag = c->tag;
+      c->done(&exec_ctx, c->done_arg, c);
+      break;
+    }
     if (cc->completed_tail != &cc->completed_head) {
       grpc_cq_completion *c = (grpc_cq_completion *)cc->completed_head.next;
       cc->completed_head.next = c->next & ~(uintptr_t)1;
@@ -358,13 +433,13 @@
       break;
     }
     now = gpr_now(GPR_CLOCK_MONOTONIC);
-    if (!first_loop && gpr_time_cmp(now, deadline) >= 0) {
+    if (!is_finished_arg.first_loop && gpr_time_cmp(now, deadline) >= 0) {
       gpr_mu_unlock(cc->mu);
       memset(&ret, 0, sizeof(ret));
       ret.type = GRPC_QUEUE_TIMEOUT;
+      dump_pending_tags(cc);
       break;
     }
-    first_loop = 0;
     /* Check alarms - these are a global resource so we just ping
        each time through on every pollset.
        May update deadline to ensure timely wakeups.
@@ -387,13 +462,16 @@
         GRPC_ERROR_UNREF(err);
         memset(&ret, 0, sizeof(ret));
         ret.type = GRPC_QUEUE_TIMEOUT;
+        dump_pending_tags(cc);
         break;
       }
     }
+    is_finished_arg.first_loop = false;
   }
   GRPC_SURFACE_TRACE_RETURNED_EVENT(cc, &ret);
   GRPC_CQ_INTERNAL_UNREF(cc, "next");
   grpc_exec_ctx_finish(&exec_ctx);
+  GPR_ASSERT(is_finished_arg.stolen_completion == NULL);
 
   GPR_TIMER_END("grpc_completion_queue_next", 0);
 
@@ -424,6 +502,37 @@
   GPR_UNREACHABLE_CODE(return );
 }
 
+static bool cq_is_pluck_finished(grpc_exec_ctx *exec_ctx, void *arg) {
+  cq_is_finished_arg *a = arg;
+  grpc_completion_queue *cq = a->cq;
+  GPR_ASSERT(a->stolen_completion == NULL);
+  gpr_atm current_last_seen_things_queued_ever =
+      gpr_atm_no_barrier_load(&cq->things_queued_ever);
+  if (current_last_seen_things_queued_ever != a->last_seen_things_queued_ever) {
+    gpr_mu_lock(cq->mu);
+    a->last_seen_things_queued_ever =
+        gpr_atm_no_barrier_load(&cq->things_queued_ever);
+    grpc_cq_completion *c;
+    grpc_cq_completion *prev = &cq->completed_head;
+    while ((c = (grpc_cq_completion *)(prev->next & ~(uintptr_t)1)) !=
+           &cq->completed_head) {
+      if (c->tag == a->tag) {
+        prev->next = (prev->next & (uintptr_t)1) | (c->next & ~(uintptr_t)1);
+        if (c == cq->completed_tail) {
+          cq->completed_tail = prev;
+        }
+        gpr_mu_unlock(cq->mu);
+        a->stolen_completion = c;
+        return true;
+      }
+      prev = c;
+    }
+    gpr_mu_unlock(cq->mu);
+  }
+  return !a->first_loop &&
+         gpr_time_cmp(a->deadline, gpr_now(a->deadline.clock_type)) < 0;
+}
+
 grpc_event grpc_completion_queue_pluck(grpc_completion_queue *cc, void *tag,
                                        gpr_timespec deadline, void *reserved) {
   grpc_event ret;
@@ -431,8 +540,6 @@
   grpc_cq_completion *prev;
   grpc_pollset_worker *worker = NULL;
   gpr_timespec now;
-  int first_loop = 1;
-  grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
 
   GPR_TIMER_BEGIN("grpc_completion_queue_pluck", 0);
 
@@ -448,11 +555,33 @@
   }
   GPR_ASSERT(!reserved);
 
+  dump_pending_tags(cc);
+
   deadline = gpr_convert_clock_type(deadline, GPR_CLOCK_MONOTONIC);
 
   GRPC_CQ_INTERNAL_REF(cc, "pluck");
   gpr_mu_lock(cc->mu);
+  cq_is_finished_arg is_finished_arg = {
+      .last_seen_things_queued_ever =
+          gpr_atm_no_barrier_load(&cc->things_queued_ever),
+      .cq = cc,
+      .deadline = deadline,
+      .stolen_completion = NULL,
+      .tag = tag,
+      .first_loop = true};
+  grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT_WITH_FINISH_CHECK(
+      cq_is_pluck_finished, &is_finished_arg);
   for (;;) {
+    if (is_finished_arg.stolen_completion != NULL) {
+      gpr_mu_unlock(cc->mu);
+      c = is_finished_arg.stolen_completion;
+      is_finished_arg.stolen_completion = NULL;
+      ret.type = GRPC_OP_COMPLETE;
+      ret.success = c->next & 1u;
+      ret.tag = c->tag;
+      c->done(&exec_ctx, c->done_arg, c);
+      break;
+    }
     prev = &cc->completed_head;
     while ((c = (grpc_cq_completion *)(prev->next & ~(uintptr_t)1)) !=
            &cc->completed_head) {
@@ -485,17 +614,18 @@
       memset(&ret, 0, sizeof(ret));
       /* TODO(ctiller): should we use a different result here */
       ret.type = GRPC_QUEUE_TIMEOUT;
+      dump_pending_tags(cc);
       break;
     }
     now = gpr_now(GPR_CLOCK_MONOTONIC);
-    if (!first_loop && gpr_time_cmp(now, deadline) >= 0) {
+    if (!is_finished_arg.first_loop && gpr_time_cmp(now, deadline) >= 0) {
       del_plucker(cc, tag, &worker);
       gpr_mu_unlock(cc->mu);
       memset(&ret, 0, sizeof(ret));
       ret.type = GRPC_QUEUE_TIMEOUT;
+      dump_pending_tags(cc);
       break;
     }
-    first_loop = 0;
     /* Check alarms - these are a global resource so we just ping
        each time through on every pollset.
        May update deadline to ensure timely wakeups.
@@ -518,15 +648,18 @@
         GRPC_ERROR_UNREF(err);
         memset(&ret, 0, sizeof(ret));
         ret.type = GRPC_QUEUE_TIMEOUT;
+        dump_pending_tags(cc);
         break;
       }
     }
+    is_finished_arg.first_loop = false;
     del_plucker(cc, tag, &worker);
   }
 done:
   GRPC_SURFACE_TRACE_RETURNED_EVENT(cc, &ret);
   GRPC_CQ_INTERNAL_UNREF(cc, "pluck");
   grpc_exec_ctx_finish(&exec_ctx);
+  GPR_ASSERT(is_finished_arg.stolen_completion == NULL);
 
   GPR_TIMER_END("grpc_completion_queue_pluck", 0);
 
diff --git a/src/core/lib/surface/completion_queue.h b/src/core/lib/surface/completion_queue.h
index 3049284..e9d840d 100644
--- a/src/core/lib/surface/completion_queue.h
+++ b/src/core/lib/surface/completion_queue.h
@@ -44,6 +44,9 @@
 extern int grpc_cq_pluck_trace;
 extern int grpc_cq_event_timeout_trace;
 extern int grpc_trace_operation_failures;
+#ifndef NDEBUG
+extern int grpc_trace_pending_tags;
+#endif
 
 typedef struct grpc_cq_completion {
   /** user supplied tag */
diff --git a/src/core/lib/surface/init.c b/src/core/lib/surface/init.c
index 5397913..ac11125 100644
--- a/src/core/lib/surface/init.c
+++ b/src/core/lib/surface/init.c
@@ -47,6 +47,7 @@
 #include "src/core/lib/channel/http_server_filter.h"
 #include "src/core/lib/debug/trace.h"
 #include "src/core/lib/http/parser.h"
+#include "src/core/lib/iomgr/combiner.h"
 #include "src/core/lib/iomgr/executor.h"
 #include "src/core/lib/iomgr/iomgr.h"
 #include "src/core/lib/profiling/timers.h"
@@ -165,12 +166,16 @@
     grpc_register_tracer("http1", &grpc_http1_trace);
     grpc_register_tracer("compression", &grpc_compression_trace);
     grpc_register_tracer("queue_pluck", &grpc_cq_pluck_trace);
+    grpc_register_tracer("combiner", &grpc_combiner_trace);
     // Default pluck trace to 1
     grpc_cq_pluck_trace = 1;
     grpc_register_tracer("queue_timeout", &grpc_cq_event_timeout_trace);
     // Default timeout trace to 1
     grpc_cq_event_timeout_trace = 1;
     grpc_register_tracer("op_failure", &grpc_trace_operation_failures);
+#ifndef NDEBUG
+    grpc_register_tracer("pending_tags", &grpc_trace_pending_tags);
+#endif
     grpc_security_pre_init();
     grpc_iomgr_init();
     grpc_executor_init();
diff --git a/src/core/lib/surface/lame_client.c b/src/core/lib/surface/lame_client.c
index 19b7836..d32c884 100644
--- a/src/core/lib/surface/lame_client.c
+++ b/src/core/lib/surface/lame_client.c
@@ -97,14 +97,14 @@
     grpc_exec_ctx_sched(exec_ctx, op->on_connectivity_state_change,
                         GRPC_ERROR_NONE, NULL);
   }
-  if (op->on_consumed != NULL) {
-    grpc_exec_ctx_sched(exec_ctx, op->on_consumed, GRPC_ERROR_NONE, NULL);
-  }
   if (op->send_ping != NULL) {
     grpc_exec_ctx_sched(exec_ctx, op->send_ping,
                         GRPC_ERROR_CREATE("lame client channel"), NULL);
   }
   GRPC_ERROR_UNREF(op->disconnect_with_error);
+  if (op->on_consumed != NULL) {
+    grpc_exec_ctx_sched(exec_ctx, op->on_consumed, GRPC_ERROR_NONE, NULL);
+  }
 }
 
 static grpc_error *init_call_elem(grpc_exec_ctx *exec_ctx,
diff --git a/src/core/lib/surface/server.c b/src/core/lib/surface/server.c
index 64afcec..8f9b995 100644
--- a/src/core/lib/surface/server.c
+++ b/src/core/lib/surface/server.c
@@ -149,6 +149,7 @@
 
   grpc_metadata_batch *recv_initial_metadata;
   bool recv_idempotent_request;
+  bool recv_cacheable_request;
   grpc_metadata_array initial_metadata;
 
   request_matcher *request_matcher;
@@ -272,23 +273,21 @@
 }
 
 static void send_shutdown(grpc_exec_ctx *exec_ctx, grpc_channel *channel,
-                          bool send_goaway, grpc_error *send_disconnect) {
-  grpc_transport_op op;
-  struct shutdown_cleanup_args *sc;
+                          int send_goaway, grpc_error *send_disconnect) {
+  struct shutdown_cleanup_args *sc = gpr_malloc(sizeof(*sc));
+  grpc_closure_init(&sc->closure, shutdown_cleanup, sc);
+  grpc_transport_op *op = grpc_make_transport_op(&sc->closure);
   grpc_channel_element *elem;
 
-  memset(&op, 0, sizeof(op));
-  op.send_goaway = send_goaway;
-  sc = gpr_malloc(sizeof(*sc));
+  op->send_goaway = send_goaway;
+  op->set_accept_stream = true;
   sc->slice = gpr_slice_from_copied_string("Server shutdown");
-  op.goaway_message = &sc->slice;
-  op.goaway_status = GRPC_STATUS_OK;
-  op.disconnect_with_error = send_disconnect;
-  grpc_closure_init(&sc->closure, shutdown_cleanup, sc);
-  op.on_consumed = &sc->closure;
+  op->goaway_message = &sc->slice;
+  op->goaway_status = GRPC_STATUS_OK;
+  op->disconnect_with_error = send_disconnect;
 
   elem = grpc_channel_stack_element(grpc_channel_get_channel_stack(channel), 0);
-  elem->filter->start_transport_op(exec_ctx, elem, &op);
+  elem->filter->start_transport_op(exec_ctx, elem, op);
 }
 
 static void channel_broadcaster_shutdown(grpc_exec_ctx *exec_ctx,
@@ -431,7 +430,8 @@
   server_unref(exec_ctx, server);
 }
 
-static void destroy_channel(grpc_exec_ctx *exec_ctx, channel_data *chand) {
+static void destroy_channel(grpc_exec_ctx *exec_ctx, channel_data *chand,
+                            grpc_error *error) {
   if (is_channel_orphaned(chand)) return;
   GPR_ASSERT(chand->server != NULL);
   orphan_channel(chand);
@@ -440,14 +440,19 @@
   chand->finish_destroy_channel_closure.cb = finish_destroy_channel;
   chand->finish_destroy_channel_closure.cb_arg = chand;
 
-  grpc_transport_op op;
-  memset(&op, 0, sizeof(op));
-  op.set_accept_stream = true;
-  op.on_consumed = &chand->finish_destroy_channel_closure;
+  if (error != GRPC_ERROR_NONE) {
+    const char *msg = grpc_error_string(error);
+    gpr_log(GPR_INFO, "Disconnected client: %s", msg);
+    grpc_error_free_string(msg);
+  }
+  GRPC_ERROR_UNREF(error);
+
+  grpc_transport_op *op = grpc_make_transport_op(&chand->finish_destroy_channel_closure);
+  op->set_accept_stream = true;
   grpc_channel_next_op(exec_ctx,
                        grpc_channel_stack_element(
                            grpc_channel_get_channel_stack(chand->channel), 0),
-                       &op);
+                       op);
 }
 
 static void cpstr(char **dest, size_t *capacity, grpc_mdstr *value) {
@@ -497,9 +502,12 @@
             &rc->data.batch.details->method_capacity, calld->path);
       rc->data.batch.details->deadline = calld->deadline;
       rc->data.batch.details->flags =
-          0 | (calld->recv_idempotent_request
-                   ? GRPC_INITIAL_METADATA_IDEMPOTENT_REQUEST
-                   : 0);
+          (calld->recv_idempotent_request
+               ? GRPC_INITIAL_METADATA_IDEMPOTENT_REQUEST
+               : 0) |
+          (calld->recv_cacheable_request
+               ? GRPC_INITIAL_METADATA_CACHEABLE_REQUEST
+               : 0);
       break;
     case REGISTERED_CALL:
       *rc->data.registered.deadline = calld->deadline;
@@ -765,8 +773,7 @@
         GRPC_ERROR_CREATE_REFERENCING("Missing :authority or :path", &error, 1);
   }
 
-  grpc_exec_ctx_sched(exec_ctx, calld->on_done_recv_initial_metadata, error,
-                      NULL);
+  grpc_closure_run(exec_ctx, calld->on_done_recv_initial_metadata, error);
 }
 
 static void server_mutate_op(grpc_call_element *elem,
@@ -779,6 +786,7 @@
     calld->on_done_recv_initial_metadata = op->recv_initial_metadata_ready;
     op->recv_initial_metadata_ready = &calld->server_on_recv_initial_metadata;
     op->recv_idempotent_request = &calld->recv_idempotent_request;
+    op->recv_cacheable_request = &calld->recv_cacheable_request;
   }
 }
 
@@ -820,11 +828,20 @@
                           const void *transport_server_data) {
   channel_data *chand = cd;
   /* create a call */
-  grpc_call *call = grpc_call_create(chand->channel, NULL, 0, NULL, NULL,
-                                     transport_server_data, NULL, 0,
-                                     gpr_inf_future(GPR_CLOCK_MONOTONIC));
+  grpc_call_create_args args;
+  memset(&args, 0, sizeof(args));
+  args.channel = chand->channel;
+  args.server_transport_data = transport_server_data;
+  args.send_deadline = gpr_inf_future(GPR_CLOCK_MONOTONIC);
+  grpc_call *call;
+  grpc_error *error = grpc_call_create(&args, &call);
   grpc_call_element *elem =
       grpc_call_stack_element(grpc_call_get_call_stack(call), 0);
+  if (error != GRPC_ERROR_NONE) {
+    got_initial_metadata(exec_ctx, elem, error);
+    GRPC_ERROR_UNREF(error);
+    return;
+  }
   call_data *calld = elem->call_data;
   grpc_op op;
   memset(&op, 0, sizeof(op));
@@ -840,17 +857,16 @@
   channel_data *chand = cd;
   grpc_server *server = chand->server;
   if (chand->connectivity_state != GRPC_CHANNEL_SHUTDOWN) {
-    grpc_transport_op op;
-    memset(&op, 0, sizeof(op));
-    op.on_connectivity_state_change = &chand->channel_connectivity_changed,
-    op.connectivity_state = &chand->connectivity_state;
+    grpc_transport_op *op = grpc_make_transport_op(NULL);
+    op->on_connectivity_state_change = &chand->channel_connectivity_changed,
+    op->connectivity_state = &chand->connectivity_state;
     grpc_channel_next_op(exec_ctx,
                          grpc_channel_stack_element(
                              grpc_channel_get_channel_stack(chand->channel), 0),
-                         &op);
+                         op);
   } else {
     gpr_mu_lock(&server->mu_global);
-    destroy_channel(exec_ctx, chand);
+    destroy_channel(exec_ctx, chand, GRPC_ERROR_REF(error));
     gpr_mu_unlock(&server->mu_global);
     GRPC_CHANNEL_INTERNAL_UNREF(exec_ctx, chand->channel, "connectivity");
   }
@@ -1114,7 +1130,7 @@
   size_t slots;
   uint32_t probes;
   uint32_t max_probes = 0;
-  grpc_transport_op op;
+  grpc_transport_op *op = NULL;
 
   channel =
       grpc_channel_create(exec_ctx, NULL, args, GRPC_SERVER_CHANNEL, transport);
@@ -1174,16 +1190,16 @@
   gpr_mu_unlock(&s->mu_global);
 
   GRPC_CHANNEL_INTERNAL_REF(channel, "connectivity");
-  memset(&op, 0, sizeof(op));
-  op.set_accept_stream = true;
-  op.set_accept_stream_fn = accept_stream;
-  op.set_accept_stream_user_data = chand;
-  op.on_connectivity_state_change = &chand->channel_connectivity_changed;
-  op.connectivity_state = &chand->connectivity_state;
+  op = grpc_make_transport_op(NULL);
+  op->set_accept_stream = true;
+  op->set_accept_stream_fn = accept_stream;
+  op->set_accept_stream_user_data = chand;
+  op->on_connectivity_state_change = &chand->channel_connectivity_changed;
+  op->connectivity_state = &chand->connectivity_state;
   if (gpr_atm_acq_load(&s->shutdown_flag) != 0) {
-    op.disconnect_with_error = GRPC_ERROR_CREATE("Server shutdown");
+    op->disconnect_with_error = GRPC_ERROR_CREATE("Server shutdown");
   }
-  grpc_transport_perform_op(exec_ctx, transport, &op);
+  grpc_transport_perform_op(exec_ctx, transport, op);
 }
 
 void done_published_shutdown(grpc_exec_ctx *exec_ctx, void *done_arg,
diff --git a/src/core/lib/surface/version.c b/src/core/lib/surface/version.c
index 1942075..4124268 100644
--- a/src/core/lib/surface/version.c
+++ b/src/core/lib/surface/version.c
@@ -37,3 +37,5 @@
 #include <grpc/grpc.h>
 
 const char *grpc_version_string(void) { return "1.1.0-dev"; }
+
+const char *grpc_g_stands_for(void) { return "good"; }
diff --git a/src/core/lib/transport/connectivity_state.c b/src/core/lib/transport/connectivity_state.c
index 68d05e3..fdb5307 100644
--- a/src/core/lib/transport/connectivity_state.c
+++ b/src/core/lib/transport/connectivity_state.c
@@ -180,7 +180,8 @@
     *w->current = tracker->current_state;
     tracker->watchers = w->next;
     if (grpc_connectivity_state_trace) {
-      gpr_log(GPR_DEBUG, "NOTIFY: %p", w->notify);
+      gpr_log(GPR_DEBUG, "NOTIFY: %p %s: %p", tracker, tracker->name,
+              w->notify);
     }
     grpc_exec_ctx_sched(exec_ctx, w->notify,
                         GRPC_ERROR_REF(tracker->current_error), NULL);
diff --git a/src/core/lib/transport/static_metadata.c b/src/core/lib/transport/static_metadata.c
index 8f3e5b5..fce591f 100644
--- a/src/core/lib/transport/static_metadata.c
+++ b/src/core/lib/transport/static_metadata.c
@@ -51,15 +51,15 @@
     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
 
 const uint8_t grpc_static_metadata_elem_indices[GRPC_STATIC_MDELEM_COUNT * 2] =
-    {11, 33, 10, 33, 12, 33, 12, 49, 13, 33, 14, 33, 15, 33, 16, 33, 17, 33,
+    {11, 33, 10, 33, 12, 33, 12, 50, 13, 33, 14, 33, 15, 33, 16, 33, 17, 33,
      19, 33, 20, 33, 21, 33, 22, 33, 23, 33, 24, 33, 25, 33, 26, 33, 27, 33,
      28, 18, 28, 33, 29, 33, 30, 33, 34, 33, 35, 33, 36, 33, 37, 33, 40, 31,
-     40, 32, 40, 48, 40, 53, 40, 54, 40, 55, 40, 56, 42, 31, 42, 48, 42, 53,
-     45, 0,  45, 1,  45, 2,  50, 33, 57, 33, 58, 33, 59, 33, 60, 33, 61, 33,
-     62, 33, 63, 33, 64, 33, 65, 33, 66, 33, 67, 33, 68, 38, 68, 70, 68, 73,
-     69, 81, 69, 82, 71, 33, 72, 33, 74, 33, 75, 33, 76, 33, 77, 33, 78, 39,
-     78, 51, 78, 52, 79, 33, 80, 33, 83, 3,  83, 4,  83, 5,  83, 6,  83, 7,
-     83, 8,  83, 9,  84, 33, 85, 86, 87, 33, 88, 33, 89, 33, 90, 33, 91, 33};
+     40, 32, 40, 49, 40, 54, 40, 55, 40, 56, 40, 57, 42, 31, 42, 49, 42, 54,
+     46, 0,  46, 1,  46, 2,  51, 33, 58, 33, 59, 33, 60, 33, 61, 33, 62, 33,
+     63, 33, 64, 33, 65, 33, 66, 33, 67, 33, 68, 33, 69, 38, 69, 71, 69, 74,
+     70, 82, 70, 83, 72, 33, 73, 33, 75, 33, 76, 33, 77, 33, 78, 33, 79, 39,
+     79, 52, 79, 53, 80, 33, 81, 33, 84, 3,  84, 4,  84, 5,  84, 6,  84, 7,
+     84, 8,  84, 9,  85, 33, 86, 87, 88, 33, 89, 33, 90, 33, 91, 33, 92, 33};
 
 const char *const grpc_static_metadata_strings[GRPC_STATIC_MDSTR_COUNT] = {
     "0",
@@ -107,6 +107,7 @@
     "grpc-encoding",
     "grpc-internal-encoding-request",
     "grpc-message",
+    "grpc-payload-bin",
     "grpc-status",
     "grpc-timeout",
     "grpc-tracing-bin",
diff --git a/src/core/lib/transport/static_metadata.h b/src/core/lib/transport/static_metadata.h
index b51baca..54b6f38 100644
--- a/src/core/lib/transport/static_metadata.h
+++ b/src/core/lib/transport/static_metadata.h
@@ -44,7 +44,7 @@
 
 #include "src/core/lib/transport/metadata.h"
 
-#define GRPC_STATIC_MDSTR_COUNT 92
+#define GRPC_STATIC_MDSTR_COUNT 93
 extern grpc_mdstr grpc_static_mdstr_table[GRPC_STATIC_MDSTR_COUNT];
 /* "0" */
 #define GRPC_MDSTR_0 (&grpc_static_mdstr_table[0])
@@ -136,101 +136,103 @@
 #define GRPC_MDSTR_GRPC_INTERNAL_ENCODING_REQUEST (&grpc_static_mdstr_table[43])
 /* "grpc-message" */
 #define GRPC_MDSTR_GRPC_MESSAGE (&grpc_static_mdstr_table[44])
+/* "grpc-payload-bin" */
+#define GRPC_MDSTR_GRPC_PAYLOAD_BIN (&grpc_static_mdstr_table[45])
 /* "grpc-status" */
-#define GRPC_MDSTR_GRPC_STATUS (&grpc_static_mdstr_table[45])
+#define GRPC_MDSTR_GRPC_STATUS (&grpc_static_mdstr_table[46])
 /* "grpc-timeout" */
-#define GRPC_MDSTR_GRPC_TIMEOUT (&grpc_static_mdstr_table[46])
+#define GRPC_MDSTR_GRPC_TIMEOUT (&grpc_static_mdstr_table[47])
 /* "grpc-tracing-bin" */
-#define GRPC_MDSTR_GRPC_TRACING_BIN (&grpc_static_mdstr_table[47])
+#define GRPC_MDSTR_GRPC_TRACING_BIN (&grpc_static_mdstr_table[48])
 /* "gzip" */
-#define GRPC_MDSTR_GZIP (&grpc_static_mdstr_table[48])
+#define GRPC_MDSTR_GZIP (&grpc_static_mdstr_table[49])
 /* "gzip, deflate" */
-#define GRPC_MDSTR_GZIP_COMMA_DEFLATE (&grpc_static_mdstr_table[49])
+#define GRPC_MDSTR_GZIP_COMMA_DEFLATE (&grpc_static_mdstr_table[50])
 /* "host" */
-#define GRPC_MDSTR_HOST (&grpc_static_mdstr_table[50])
+#define GRPC_MDSTR_HOST (&grpc_static_mdstr_table[51])
 /* "http" */
-#define GRPC_MDSTR_HTTP (&grpc_static_mdstr_table[51])
+#define GRPC_MDSTR_HTTP (&grpc_static_mdstr_table[52])
 /* "https" */
-#define GRPC_MDSTR_HTTPS (&grpc_static_mdstr_table[52])
+#define GRPC_MDSTR_HTTPS (&grpc_static_mdstr_table[53])
 /* "identity" */
-#define GRPC_MDSTR_IDENTITY (&grpc_static_mdstr_table[53])
+#define GRPC_MDSTR_IDENTITY (&grpc_static_mdstr_table[54])
 /* "identity,deflate" */
-#define GRPC_MDSTR_IDENTITY_COMMA_DEFLATE (&grpc_static_mdstr_table[54])
+#define GRPC_MDSTR_IDENTITY_COMMA_DEFLATE (&grpc_static_mdstr_table[55])
 /* "identity,deflate,gzip" */
 #define GRPC_MDSTR_IDENTITY_COMMA_DEFLATE_COMMA_GZIP \
-  (&grpc_static_mdstr_table[55])
+  (&grpc_static_mdstr_table[56])
 /* "identity,gzip" */
-#define GRPC_MDSTR_IDENTITY_COMMA_GZIP (&grpc_static_mdstr_table[56])
+#define GRPC_MDSTR_IDENTITY_COMMA_GZIP (&grpc_static_mdstr_table[57])
 /* "if-match" */
-#define GRPC_MDSTR_IF_MATCH (&grpc_static_mdstr_table[57])
+#define GRPC_MDSTR_IF_MATCH (&grpc_static_mdstr_table[58])
 /* "if-modified-since" */
-#define GRPC_MDSTR_IF_MODIFIED_SINCE (&grpc_static_mdstr_table[58])
+#define GRPC_MDSTR_IF_MODIFIED_SINCE (&grpc_static_mdstr_table[59])
 /* "if-none-match" */
-#define GRPC_MDSTR_IF_NONE_MATCH (&grpc_static_mdstr_table[59])
+#define GRPC_MDSTR_IF_NONE_MATCH (&grpc_static_mdstr_table[60])
 /* "if-range" */
-#define GRPC_MDSTR_IF_RANGE (&grpc_static_mdstr_table[60])
+#define GRPC_MDSTR_IF_RANGE (&grpc_static_mdstr_table[61])
 /* "if-unmodified-since" */
-#define GRPC_MDSTR_IF_UNMODIFIED_SINCE (&grpc_static_mdstr_table[61])
+#define GRPC_MDSTR_IF_UNMODIFIED_SINCE (&grpc_static_mdstr_table[62])
 /* "last-modified" */
-#define GRPC_MDSTR_LAST_MODIFIED (&grpc_static_mdstr_table[62])
+#define GRPC_MDSTR_LAST_MODIFIED (&grpc_static_mdstr_table[63])
 /* "link" */
-#define GRPC_MDSTR_LINK (&grpc_static_mdstr_table[63])
+#define GRPC_MDSTR_LINK (&grpc_static_mdstr_table[64])
 /* "load-reporting-initial" */
-#define GRPC_MDSTR_LOAD_REPORTING_INITIAL (&grpc_static_mdstr_table[64])
+#define GRPC_MDSTR_LOAD_REPORTING_INITIAL (&grpc_static_mdstr_table[65])
 /* "load-reporting-trailing" */
-#define GRPC_MDSTR_LOAD_REPORTING_TRAILING (&grpc_static_mdstr_table[65])
+#define GRPC_MDSTR_LOAD_REPORTING_TRAILING (&grpc_static_mdstr_table[66])
 /* "location" */
-#define GRPC_MDSTR_LOCATION (&grpc_static_mdstr_table[66])
+#define GRPC_MDSTR_LOCATION (&grpc_static_mdstr_table[67])
 /* "max-forwards" */
-#define GRPC_MDSTR_MAX_FORWARDS (&grpc_static_mdstr_table[67])
+#define GRPC_MDSTR_MAX_FORWARDS (&grpc_static_mdstr_table[68])
 /* ":method" */
-#define GRPC_MDSTR_METHOD (&grpc_static_mdstr_table[68])
+#define GRPC_MDSTR_METHOD (&grpc_static_mdstr_table[69])
 /* ":path" */
-#define GRPC_MDSTR_PATH (&grpc_static_mdstr_table[69])
+#define GRPC_MDSTR_PATH (&grpc_static_mdstr_table[70])
 /* "POST" */
-#define GRPC_MDSTR_POST (&grpc_static_mdstr_table[70])
+#define GRPC_MDSTR_POST (&grpc_static_mdstr_table[71])
 /* "proxy-authenticate" */
-#define GRPC_MDSTR_PROXY_AUTHENTICATE (&grpc_static_mdstr_table[71])
+#define GRPC_MDSTR_PROXY_AUTHENTICATE (&grpc_static_mdstr_table[72])
 /* "proxy-authorization" */
-#define GRPC_MDSTR_PROXY_AUTHORIZATION (&grpc_static_mdstr_table[72])
+#define GRPC_MDSTR_PROXY_AUTHORIZATION (&grpc_static_mdstr_table[73])
 /* "PUT" */
-#define GRPC_MDSTR_PUT (&grpc_static_mdstr_table[73])
+#define GRPC_MDSTR_PUT (&grpc_static_mdstr_table[74])
 /* "range" */
-#define GRPC_MDSTR_RANGE (&grpc_static_mdstr_table[74])
+#define GRPC_MDSTR_RANGE (&grpc_static_mdstr_table[75])
 /* "referer" */
-#define GRPC_MDSTR_REFERER (&grpc_static_mdstr_table[75])
+#define GRPC_MDSTR_REFERER (&grpc_static_mdstr_table[76])
 /* "refresh" */
-#define GRPC_MDSTR_REFRESH (&grpc_static_mdstr_table[76])
+#define GRPC_MDSTR_REFRESH (&grpc_static_mdstr_table[77])
 /* "retry-after" */
-#define GRPC_MDSTR_RETRY_AFTER (&grpc_static_mdstr_table[77])
+#define GRPC_MDSTR_RETRY_AFTER (&grpc_static_mdstr_table[78])
 /* ":scheme" */
-#define GRPC_MDSTR_SCHEME (&grpc_static_mdstr_table[78])
+#define GRPC_MDSTR_SCHEME (&grpc_static_mdstr_table[79])
 /* "server" */
-#define GRPC_MDSTR_SERVER (&grpc_static_mdstr_table[79])
+#define GRPC_MDSTR_SERVER (&grpc_static_mdstr_table[80])
 /* "set-cookie" */
-#define GRPC_MDSTR_SET_COOKIE (&grpc_static_mdstr_table[80])
+#define GRPC_MDSTR_SET_COOKIE (&grpc_static_mdstr_table[81])
 /* "/" */
-#define GRPC_MDSTR_SLASH (&grpc_static_mdstr_table[81])
+#define GRPC_MDSTR_SLASH (&grpc_static_mdstr_table[82])
 /* "/index.html" */
-#define GRPC_MDSTR_SLASH_INDEX_DOT_HTML (&grpc_static_mdstr_table[82])
+#define GRPC_MDSTR_SLASH_INDEX_DOT_HTML (&grpc_static_mdstr_table[83])
 /* ":status" */
-#define GRPC_MDSTR_STATUS (&grpc_static_mdstr_table[83])
+#define GRPC_MDSTR_STATUS (&grpc_static_mdstr_table[84])
 /* "strict-transport-security" */
-#define GRPC_MDSTR_STRICT_TRANSPORT_SECURITY (&grpc_static_mdstr_table[84])
+#define GRPC_MDSTR_STRICT_TRANSPORT_SECURITY (&grpc_static_mdstr_table[85])
 /* "te" */
-#define GRPC_MDSTR_TE (&grpc_static_mdstr_table[85])
+#define GRPC_MDSTR_TE (&grpc_static_mdstr_table[86])
 /* "trailers" */
-#define GRPC_MDSTR_TRAILERS (&grpc_static_mdstr_table[86])
+#define GRPC_MDSTR_TRAILERS (&grpc_static_mdstr_table[87])
 /* "transfer-encoding" */
-#define GRPC_MDSTR_TRANSFER_ENCODING (&grpc_static_mdstr_table[87])
+#define GRPC_MDSTR_TRANSFER_ENCODING (&grpc_static_mdstr_table[88])
 /* "user-agent" */
-#define GRPC_MDSTR_USER_AGENT (&grpc_static_mdstr_table[88])
+#define GRPC_MDSTR_USER_AGENT (&grpc_static_mdstr_table[89])
 /* "vary" */
-#define GRPC_MDSTR_VARY (&grpc_static_mdstr_table[89])
+#define GRPC_MDSTR_VARY (&grpc_static_mdstr_table[90])
 /* "via" */
-#define GRPC_MDSTR_VIA (&grpc_static_mdstr_table[90])
+#define GRPC_MDSTR_VIA (&grpc_static_mdstr_table[91])
 /* "www-authenticate" */
-#define GRPC_MDSTR_WWW_AUTHENTICATE (&grpc_static_mdstr_table[91])
+#define GRPC_MDSTR_WWW_AUTHENTICATE (&grpc_static_mdstr_table[92])
 
 #define GRPC_STATIC_MDELEM_COUNT 81
 extern grpc_mdelem grpc_static_mdelem_table[GRPC_STATIC_MDELEM_COUNT];
diff --git a/src/core/lib/transport/transport.c b/src/core/lib/transport/transport.c
index 857c390..b951218 100644
--- a/src/core/lib/transport/transport.c
+++ b/src/core/lib/transport/transport.c
@@ -32,18 +32,23 @@
  */
 
 #include "src/core/lib/transport/transport.h"
+
+#include <string.h>
+
 #include <grpc/support/alloc.h>
 #include <grpc/support/atm.h>
 #include <grpc/support/log.h>
 #include <grpc/support/sync.h>
+
 #include "src/core/lib/support/string.h"
 #include "src/core/lib/transport/transport_impl.h"
 
 #ifdef GRPC_STREAM_REFCOUNT_DEBUG
 void grpc_stream_ref(grpc_stream_refcount *refcount, const char *reason) {
   gpr_atm val = gpr_atm_no_barrier_load(&refcount->refs.count);
-  gpr_log(GPR_DEBUG, "%s %p:%p   REF %d->%d %s", refcount->object_type,
-          refcount, refcount->destroy.cb_arg, val, val + 1, reason);
+  gpr_log(GPR_DEBUG, "%s %p:%p   REF %" PRIdPTR "->%" PRIdPTR " %s",
+          refcount->object_type, refcount, refcount->destroy.cb_arg, val,
+          val + 1, reason);
 #else
 void grpc_stream_ref(grpc_stream_refcount *refcount) {
 #endif
@@ -54,8 +59,9 @@
 void grpc_stream_unref(grpc_exec_ctx *exec_ctx, grpc_stream_refcount *refcount,
                        const char *reason) {
   gpr_atm val = gpr_atm_no_barrier_load(&refcount->refs.count);
-  gpr_log(GPR_DEBUG, "%s %p:%p UNREF %d->%d %s", refcount->object_type,
-          refcount, refcount->destroy.cb_arg, val, val - 1, reason);
+  gpr_log(GPR_DEBUG, "%s %p:%p UNREF %" PRIdPTR "->%" PRIdPTR " %s",
+          refcount->object_type, refcount, refcount->destroy.cb_arg, val,
+          val - 1, reason);
 #else
 void grpc_stream_unref(grpc_exec_ctx *exec_ctx,
                        grpc_stream_refcount *refcount) {
@@ -247,3 +253,51 @@
   error = grpc_error_set_int(error, GRPC_ERROR_INT_GRPC_STATUS, status);
   add_error(op, &op->close_error, error);
 }
+
+typedef struct {
+  grpc_closure outer_on_complete;
+  grpc_closure *inner_on_complete;
+  grpc_transport_op op;
+} made_transport_op;
+
+static void destroy_made_transport_op(grpc_exec_ctx *exec_ctx, void *arg,
+                                      grpc_error *error) {
+  made_transport_op *op = arg;
+  grpc_exec_ctx_sched(exec_ctx, op->inner_on_complete, GRPC_ERROR_REF(error),
+                      NULL);
+  gpr_free(op);
+}
+
+grpc_transport_op *grpc_make_transport_op(grpc_closure *on_complete) {
+  made_transport_op *op = gpr_malloc(sizeof(*op));
+  grpc_closure_init(&op->outer_on_complete, destroy_made_transport_op, op);
+  op->inner_on_complete = on_complete;
+  memset(&op->op, 0, sizeof(op->op));
+  op->op.on_consumed = &op->outer_on_complete;
+  return &op->op;
+}
+
+typedef struct {
+  grpc_closure outer_on_complete;
+  grpc_closure *inner_on_complete;
+  grpc_transport_stream_op op;
+} made_transport_stream_op;
+
+static void destroy_made_transport_stream_op(grpc_exec_ctx *exec_ctx, void *arg,
+                                             grpc_error *error) {
+  made_transport_stream_op *op = arg;
+  grpc_exec_ctx_sched(exec_ctx, op->inner_on_complete, GRPC_ERROR_REF(error),
+                      NULL);
+  gpr_free(op);
+}
+
+grpc_transport_stream_op *grpc_make_transport_stream_op(
+    grpc_closure *on_complete) {
+  made_transport_stream_op *op = gpr_malloc(sizeof(*op));
+  grpc_closure_init(&op->outer_on_complete, destroy_made_transport_stream_op,
+                    op);
+  op->inner_on_complete = on_complete;
+  memset(&op->op, 0, sizeof(op->op));
+  op->op.on_complete = &op->outer_on_complete;
+  return &op->op;
+}
diff --git a/src/core/lib/transport/transport.h b/src/core/lib/transport/transport.h
index 1705e6e..50253eb 100644
--- a/src/core/lib/transport/transport.h
+++ b/src/core/lib/transport/transport.h
@@ -100,6 +100,11 @@
 void grpc_transport_move_stats(grpc_transport_stream_stats *from,
                                grpc_transport_stream_stats *to);
 
+typedef struct {
+  grpc_closure closure;
+  void *args[2];
+} grpc_transport_private_op_data;
+
 /* Transport stream op: a set of operations to perform on a transport
    against a single stream */
 typedef struct grpc_transport_stream_op {
@@ -108,6 +113,10 @@
       have been completed. */
   grpc_closure *on_complete;
 
+  /** Is the completion of this op covered by a poller (if false: the op should
+      complete independently of some pollset being polled) */
+  bool covered_by_poller;
+
   /** Send initial metadata to the peer, from the provided metadata batch.
       idempotent_request MUST be set if this is non-null */
   grpc_metadata_batch *send_initial_metadata;
@@ -124,6 +133,7 @@
   /** Receive initial metadata from the stream, into provided metadata batch. */
   grpc_metadata_batch *recv_initial_metadata;
   bool *recv_idempotent_request;
+  bool *recv_cacheable_request;
   /** Should be enqueued when initial metadata is ready to be processed. */
   grpc_closure *recv_initial_metadata_ready;
 
@@ -148,6 +158,12 @@
 
   /* Indexes correspond to grpc_context_index enum values */
   grpc_call_context_element *context;
+
+  /***************************************************************************
+   * remaining fields are initialized and used at the discretion of the
+   * transport implementation */
+
+  grpc_transport_private_op_data transport_private;
 } grpc_transport_stream_op;
 
 /** Transport op: a set of operations to perform on a transport as a whole */
@@ -181,6 +197,12 @@
   grpc_pollset_set *bind_pollset_set;
   /** send a ping, call this back if not NULL */
   grpc_closure *send_ping;
+
+  /***************************************************************************
+   * remaining fields are initialized and used at the discretion of the
+   * transport implementation */
+
+  grpc_transport_private_op_data transport_private;
 } grpc_transport_op;
 
 /* Returns the amount of memory required to store a grpc_stream for this
@@ -234,6 +256,7 @@
                                         gpr_slice *optional_message);
 
 char *grpc_transport_stream_op_string(grpc_transport_stream_op *op);
+char *grpc_transport_op_string(grpc_transport_op *op);
 
 /* Send a batch of operations on a transport
 
@@ -272,6 +295,14 @@
 char *grpc_transport_get_peer(grpc_exec_ctx *exec_ctx,
                               grpc_transport *transport);
 
+/* Allocate a grpc_transport_op, and preconfigure the on_consumed closure to
+   \a on_consumed and then delete the returned transport op */
+grpc_transport_op *grpc_make_transport_op(grpc_closure *on_consumed);
+/* Allocate a grpc_transport_stream_op, and preconfigure the on_consumed closure
+   to \a on_consumed and then delete the returned transport op */
+grpc_transport_stream_op *grpc_make_transport_stream_op(
+    grpc_closure *on_consumed);
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/src/core/lib/transport/transport_op_string.c b/src/core/lib/transport/transport_op_string.c
index 138591d..8a687d8 100644
--- a/src/core/lib/transport/transport_op_string.c
+++ b/src/core/lib/transport/transport_op_string.c
@@ -41,6 +41,7 @@
 #include <grpc/support/string_util.h>
 #include <grpc/support/useful.h>
 #include "src/core/lib/support/string.h"
+#include "src/core/lib/transport/connectivity_state.h"
 
 /* These routines are here to facilitate debugging - they produce string
    representations of various transport data structures */
@@ -143,6 +144,82 @@
   return out;
 }
 
+char *grpc_transport_op_string(grpc_transport_op *op) {
+  char *tmp;
+  char *out;
+  int first = 1;
+
+  gpr_strvec b;
+  gpr_strvec_init(&b);
+
+  if (op->on_connectivity_state_change != NULL) {
+    if (!first) gpr_strvec_add(&b, gpr_strdup(" "));
+    first = 0;
+    if (op->connectivity_state != NULL) {
+      gpr_asprintf(&tmp, "ON_CONNECTIVITY_STATE_CHANGE:p=%p:from=%s",
+                   op->on_connectivity_state_change,
+                   grpc_connectivity_state_name(*op->connectivity_state));
+      gpr_strvec_add(&b, tmp);
+    } else {
+      gpr_asprintf(&tmp, "ON_CONNECTIVITY_STATE_CHANGE:p=%p:unsubscribe",
+                   op->on_connectivity_state_change);
+      gpr_strvec_add(&b, tmp);
+    }
+  }
+
+  if (op->disconnect_with_error != GRPC_ERROR_NONE) {
+    if (!first) gpr_strvec_add(&b, gpr_strdup(" "));
+    first = 0;
+    const char *err = grpc_error_string(op->disconnect_with_error);
+    gpr_asprintf(&tmp, "DISCONNECT:%s", err);
+    gpr_strvec_add(&b, tmp);
+    grpc_error_free_string(err);
+  }
+
+  if (op->send_goaway) {
+    if (!first) gpr_strvec_add(&b, gpr_strdup(" "));
+    first = 0;
+    char *msg = op->goaway_message == NULL
+                    ? "null"
+                    : gpr_dump_slice(*op->goaway_message,
+                                     GPR_DUMP_ASCII | GPR_DUMP_HEX);
+    gpr_asprintf(&tmp, "SEND_GOAWAY:status=%d:msg=%s", op->goaway_status, msg);
+    if (op->goaway_message != NULL) gpr_free(msg);
+    gpr_strvec_add(&b, tmp);
+  }
+
+  if (op->set_accept_stream) {
+    if (!first) gpr_strvec_add(&b, gpr_strdup(" "));
+    first = 0;
+    gpr_asprintf(&tmp, "SET_ACCEPT_STREAM:%p(%p,...)", op->set_accept_stream_fn,
+                 op->set_accept_stream_user_data);
+    gpr_strvec_add(&b, tmp);
+  }
+
+  if (op->bind_pollset != NULL) {
+    if (!first) gpr_strvec_add(&b, gpr_strdup(" "));
+    first = 0;
+    gpr_strvec_add(&b, gpr_strdup("BIND_POLLSET"));
+  }
+
+  if (op->bind_pollset_set != NULL) {
+    if (!first) gpr_strvec_add(&b, gpr_strdup(" "));
+    first = 0;
+    gpr_strvec_add(&b, gpr_strdup("BIND_POLLSET_SET"));
+  }
+
+  if (op->send_ping != NULL) {
+    if (!first) gpr_strvec_add(&b, gpr_strdup(" "));
+    first = 0;
+    gpr_strvec_add(&b, gpr_strdup("SEND_PING"));
+  }
+
+  out = gpr_strvec_flatten(&b, NULL);
+  gpr_strvec_destroy(&b);
+
+  return out;
+}
+
 void grpc_call_log_op(char *file, int line, gpr_log_severity severity,
                       grpc_call_element *elem, grpc_transport_stream_op *op) {
   char *str = grpc_transport_stream_op_string(op);
diff --git a/src/cpp/common/channel_filter.h b/src/cpp/common/channel_filter.h
index 3fbacd8..ec2af63 100644
--- a/src/cpp/common/channel_filter.h
+++ b/src/cpp/common/channel_filter.h
@@ -35,7 +35,6 @@
 #define GRPCXX_CHANNEL_FILTER_H
 
 #include <grpc++/impl/codegen/config.h>
-#include <grpc/census.h>
 #include <grpc/grpc.h>
 #include <grpc/impl/codegen/alloc.h>
 
@@ -43,7 +42,6 @@
 #include <vector>
 
 #include "src/core/lib/channel/channel_stack.h"
-#include "src/core/lib/security/context/security_context.h"
 #include "src/core/lib/surface/channel_init.h"
 #include "src/core/lib/transport/metadata_batch.h"
 
@@ -56,6 +54,11 @@
 ///       "name-of-filter", GRPC_SERVER_CHANNEL, INT_MAX, nullptr);
 /// \endcode
 
+/// Forward declaration to avoid including the file
+/// "src/core/lib/security/context/security_context.h"
+struct grpc_client_security_context;
+struct grpc_server_security_context;
+
 namespace grpc {
 
 /// A C++ wrapper for the \c grpc_metadata_batch struct.
diff --git a/src/cpp/server/server_builder.cc b/src/cpp/server/server_builder.cc
index 45bb858..1a014da 100644
--- a/src/cpp/server/server_builder.cc
+++ b/src/cpp/server/server_builder.cc
@@ -35,10 +35,9 @@
 
 #include <grpc++/impl/service_type.h>
 #include <grpc++/server.h>
-#include <grpc/support/cpu.h>
 #include <grpc/support/log.h>
+#include <grpc/support/useful.h>
 
-#include "include/grpc/support/useful.h"
 #include "src/cpp/server/thread_pool_interface.h"
 
 namespace grpc {
@@ -154,14 +153,12 @@
     (*option)->UpdateArguments(&args);
     (*option)->UpdatePlugins(&plugins_);
   }
-  if (!thread_pool) {
-    for (auto plugin = plugins_.begin(); plugin != plugins_.end(); plugin++) {
-      if ((*plugin)->has_sync_methods()) {
-        thread_pool.reset(CreateDefaultThreadPool());
-        has_sync_methods = true;
-        break;
-      }
+  for (auto plugin = plugins_.begin(); plugin != plugins_.end(); plugin++) {
+    if (!thread_pool && (*plugin)->has_sync_methods()) {
+      thread_pool.reset(CreateDefaultThreadPool());
+      has_sync_methods = true;
     }
+    (*plugin)->UpdateChannelArguments(&args);
   }
   if (max_message_size_ > 0) {
     args.SetInt(GRPC_ARG_MAX_MESSAGE_LENGTH, max_message_size_);
diff --git a/src/cpp/util/byte_buffer.cc b/src/cpp/util/byte_buffer.cc
index 4c4772a..91ed66b 100644
--- a/src/cpp/util/byte_buffer.cc
+++ b/src/cpp/util/byte_buffer.cc
@@ -104,8 +104,8 @@
 
 void ByteBuffer::Swap(ByteBuffer* other) {
   grpc_byte_buffer* tmp = other->buffer_;
-  other->buffer_ = this->buffer_;
-  this->buffer_ = tmp;
+  other->buffer_ = buffer_;
+  buffer_ = tmp;
 }
 
 }  // namespace grpc
diff --git "a/src/objective-c/\041ProtoCompiler-gRPCPlugin.podspec" "b/src/objective-c/\041ProtoCompiler-gRPCPlugin.podspec"
index 07d62d2..0c3c321 100644
--- "a/src/objective-c/\041ProtoCompiler-gRPCPlugin.podspec"
+++ "b/src/objective-c/\041ProtoCompiler-gRPCPlugin.podspec"
@@ -36,8 +36,8 @@
   # exclamation mark ensures that other "regular" pods will be able to find it as it'll be installed
   # before them.
   s.name     = '!ProtoCompiler-gRPCPlugin'
-  v = '1.0.0-pre1'
-  s.version  = "#{v}.2" # .2 to depend on protoc 3.0.0
+  v = '1.0.0'
+  s.version  = v
   s.summary  = 'The gRPC ProtoC plugin generates Objective-C files from .proto services.'
   s.description = <<-DESC
     This podspec only downloads the gRPC protoc plugin so that local pods generating protos can use
@@ -82,10 +82,9 @@
   s.authors  = { 'The gRPC contributors' => 'grpc-packages@google.com' }
 
   repo = 'grpc/grpc'
-  release = "objective-c-v#{v}"
   file = "grpc_objective_c_plugin-#{v}-macos-x86_64.zip"
   s.source = {
-    :http => "https://github.com/#{repo}/releases/download/#{release}/#{file}",
+    :http => "https://github.com/#{repo}/releases/download/v#{v}/#{file}",
     # TODO(jcanizales): Add sha1 or sha256
     # :sha1 => '??',
   }
diff --git a/src/objective-c/BoringSSL.podspec b/src/objective-c/BoringSSL.podspec
index b759997..e14f39b 100644
--- a/src/objective-c/BoringSSL.podspec
+++ b/src/objective-c/BoringSSL.podspec
@@ -31,7 +31,7 @@
 
 Pod::Spec.new do |s|
   s.name     = 'BoringSSL'
-  version = '5.0'
+  version = '6.0'
   s.version  = version
   s.summary  = 'BoringSSL is a fork of OpenSSL that is designed to meet Google’s needs.'
   # Adapted from the homepage:
@@ -70,7 +70,7 @@
   s.source = {
     :git => 'https://boringssl.googlesource.com/boringssl',
     :tag => "version_for_cocoapods_#{version}",
-    # :commit => '8d343b44bbab829d1a28fdef650ca95f7db4412e',
+    # :commit => '4ac2dc4c0d48ca45da4f66c40e60d6b425fa94a3',
   }
 
   name = 'openssl'
@@ -388,42 +388,42 @@
           0x28340c19,
           0x283480ac,
           0x283500ea,
-          0x2c3227cb,
-          0x2c32a7d9,
-          0x2c3327eb,
-          0x2c33a7fd,
-          0x2c342811,
-          0x2c34a823,
-          0x2c35283e,
-          0x2c35a850,
-          0x2c362863,
+          0x2c322843,
+          0x2c32a851,
+          0x2c332863,
+          0x2c33a875,
+          0x2c342889,
+          0x2c34a89b,
+          0x2c3528b6,
+          0x2c35a8c8,
+          0x2c3628db,
           0x2c36832d,
-          0x2c372870,
-          0x2c37a882,
-          0x2c382895,
-          0x2c38a8ac,
-          0x2c3928ba,
-          0x2c39a8ca,
-          0x2c3a28dc,
-          0x2c3aa8f0,
-          0x2c3b2901,
-          0x2c3ba920,
-          0x2c3c2934,
-          0x2c3ca94a,
-          0x2c3d2963,
-          0x2c3da980,
-          0x2c3e2991,
-          0x2c3ea99f,
-          0x2c3f29b7,
-          0x2c3fa9cf,
-          0x2c4029dc,
+          0x2c3728e8,
+          0x2c37a8fa,
+          0x2c38290d,
+          0x2c38a924,
+          0x2c392932,
+          0x2c39a942,
+          0x2c3a2954,
+          0x2c3aa968,
+          0x2c3b2979,
+          0x2c3ba998,
+          0x2c3c29ac,
+          0x2c3ca9c2,
+          0x2c3d29db,
+          0x2c3da9f8,
+          0x2c3e2a09,
+          0x2c3eaa17,
+          0x2c3f2a2f,
+          0x2c3faa47,
+          0x2c402a54,
           0x2c4090e7,
-          0x2c4129ed,
-          0x2c41aa00,
+          0x2c412a65,
+          0x2c41aa78,
           0x2c4210c0,
-          0x2c42aa11,
+          0x2c42aa89,
           0x2c430720,
-          0x2c43a912,
+          0x2c43a98a,
           0x30320000,
           0x30328015,
           0x3033001f,
@@ -576,169 +576,174 @@
           0x403b9861,
           0x403c0064,
           0x403c8083,
-          0x403d186d,
-          0x403d9883,
-          0x403e1892,
-          0x403e98a5,
-          0x403f18bf,
-          0x403f98cd,
-          0x404018e2,
-          0x404098f6,
-          0x40411913,
-          0x4041992e,
-          0x40421947,
-          0x4042995a,
-          0x4043196e,
-          0x40439986,
-          0x4044199d,
+          0x403d1890,
+          0x403d98a6,
+          0x403e18b5,
+          0x403e98c8,
+          0x403f18e2,
+          0x403f98f0,
+          0x40401905,
+          0x40409919,
+          0x40411936,
+          0x40419951,
+          0x4042196a,
+          0x4042997d,
+          0x40431991,
+          0x404399a9,
+          0x404419c0,
           0x404480ac,
-          0x404519b2,
-          0x404599c4,
-          0x404619e8,
-          0x40469a08,
-          0x40471a16,
-          0x40479a3d,
-          0x40481a52,
-          0x40489a6b,
-          0x40491a82,
-          0x40499a9c,
-          0x404a1ab3,
-          0x404a9ad1,
-          0x404b1ae9,
-          0x404b9b00,
-          0x404c1b16,
-          0x404c9b28,
-          0x404d1b49,
-          0x404d9b6b,
-          0x404e1b7f,
-          0x404e9b8c,
-          0x404f1ba3,
-          0x404f9bb3,
-          0x40501bdd,
-          0x40509bf1,
-          0x40511c0c,
-          0x40519c1c,
-          0x40521c33,
-          0x40529c45,
-          0x40531c5d,
-          0x40539c70,
-          0x40541c85,
-          0x40549ca8,
-          0x40551cb6,
-          0x40559cd3,
-          0x40561ce0,
-          0x40569cf9,
-          0x40571d11,
-          0x40579d24,
-          0x40581d39,
-          0x40589d4b,
-          0x40591d7a,
-          0x40599d93,
-          0x405a1da7,
-          0x405a9db7,
-          0x405b1dcf,
-          0x405b9de0,
-          0x405c1df3,
-          0x405c9e04,
-          0x405d1e11,
-          0x405d9e28,
-          0x405e1e48,
+          0x404519d5,
+          0x404599e7,
+          0x40461a0b,
+          0x40469a2b,
+          0x40471a39,
+          0x40479a60,
+          0x40481a89,
+          0x40489aa2,
+          0x40491ab9,
+          0x40499ad3,
+          0x404a1aea,
+          0x404a9b08,
+          0x404b1b20,
+          0x404b9b37,
+          0x404c1b4d,
+          0x404c9b5f,
+          0x404d1b80,
+          0x404d9ba2,
+          0x404e1bb6,
+          0x404e9bc3,
+          0x404f1bf0,
+          0x404f9c19,
+          0x40501c43,
+          0x40509c57,
+          0x40511c72,
+          0x40519c82,
+          0x40521c99,
+          0x40529cbd,
+          0x40531cd5,
+          0x40539ce8,
+          0x40541cfd,
+          0x40549d20,
+          0x40551d2e,
+          0x40559d4b,
+          0x40561d58,
+          0x40569d71,
+          0x40571d89,
+          0x40579d9c,
+          0x40581db1,
+          0x40589dc3,
+          0x40591df2,
+          0x40599e0b,
+          0x405a1e1f,
+          0x405a9e2f,
+          0x405b1e47,
+          0x405b9e58,
+          0x405c1e6b,
+          0x405c9e7c,
+          0x405d1e89,
+          0x405d9ea0,
+          0x405e1ec0,
           0x405e8a95,
-          0x405f1e69,
-          0x405f9e76,
-          0x40601e84,
-          0x40609ea6,
-          0x40611ece,
-          0x40619ee3,
-          0x40621efa,
-          0x40629f0b,
-          0x40631f1c,
-          0x40639f31,
-          0x40641f48,
-          0x40649f59,
-          0x40651f74,
-          0x40659f8b,
-          0x40661fa3,
-          0x40669fcd,
-          0x40671ff8,
-          0x4067a019,
-          0x4068202c,
-          0x4068a04d,
-          0x4069207f,
-          0x4069a0ad,
-          0x406a20ce,
-          0x406aa0ee,
-          0x406b2276,
-          0x406ba299,
-          0x406c22af,
-          0x406ca4db,
-          0x406d250a,
-          0x406da532,
-          0x406e254b,
-          0x406ea563,
-          0x406f2582,
-          0x406fa597,
-          0x407025aa,
-          0x4070a5c7,
+          0x405f1ee1,
+          0x405f9eee,
+          0x40601efc,
+          0x40609f1e,
+          0x40611f46,
+          0x40619f5b,
+          0x40621f72,
+          0x40629f83,
+          0x40631f94,
+          0x40639fa9,
+          0x40641fc0,
+          0x40649fd1,
+          0x40651fec,
+          0x4065a003,
+          0x4066201b,
+          0x4066a045,
+          0x40672070,
+          0x4067a091,
+          0x406820a4,
+          0x4068a0c5,
+          0x406920f7,
+          0x4069a125,
+          0x406a2146,
+          0x406aa166,
+          0x406b22ee,
+          0x406ba311,
+          0x406c2327,
+          0x406ca553,
+          0x406d2582,
+          0x406da5aa,
+          0x406e25c3,
+          0x406ea5db,
+          0x406f25fa,
+          0x406fa60f,
+          0x40702622,
+          0x4070a63f,
           0x40710800,
-          0x4071a5d9,
-          0x407225ec,
-          0x4072a605,
-          0x4073261d,
+          0x4071a651,
+          0x40722664,
+          0x4072a67d,
+          0x40732695,
           0x4073936d,
-          0x40742631,
-          0x4074a64b,
-          0x4075265c,
-          0x4075a670,
-          0x4076267e,
+          0x407426a9,
+          0x4074a6c3,
+          0x407526d4,
+          0x4075a6e8,
+          0x407626f6,
           0x407691aa,
-          0x407726a3,
-          0x4077a6c5,
-          0x407826e0,
-          0x4078a719,
-          0x40792730,
-          0x4079a746,
-          0x407a2752,
-          0x407aa765,
-          0x407b277a,
-          0x407ba78c,
-          0x407c27a1,
-          0x407ca7aa,
-          0x407d2068,
-          0x407d9bc3,
-          0x407e26f5,
-          0x407e9d5b,
-          0x407f1a2a,
-          0x41f421a1,
-          0x41f92233,
-          0x41fe2126,
-          0x41fea302,
-          0x41ff23f3,
-          0x420321ba,
-          0x420821dc,
-          0x4208a218,
-          0x4209210a,
-          0x4209a252,
-          0x420a2161,
-          0x420aa141,
-          0x420b2181,
-          0x420ba1fa,
-          0x420c240f,
-          0x420ca2cf,
-          0x420d22e9,
-          0x420da320,
-          0x4212233a,
-          0x421723d6,
-          0x4217a37c,
-          0x421c239e,
-          0x421f2359,
-          0x42212426,
-          0x422623b9,
-          0x422b24bf,
-          0x422ba488,
-          0x422c24a7,
-          0x422ca462,
-          0x422d2441,
+          0x4077271b,
+          0x4077a73d,
+          0x40782758,
+          0x4078a791,
+          0x407927a8,
+          0x4079a7be,
+          0x407a27ca,
+          0x407aa7dd,
+          0x407b27f2,
+          0x407ba804,
+          0x407c2819,
+          0x407ca822,
+          0x407d20e0,
+          0x407d9c29,
+          0x407e276d,
+          0x407e9dd3,
+          0x407f1a4d,
+          0x407f986d,
+          0x40801c00,
+          0x40809a75,
+          0x40811cab,
+          0x40819bda,
+          0x41f42219,
+          0x41f922ab,
+          0x41fe219e,
+          0x41fea37a,
+          0x41ff246b,
+          0x42032232,
+          0x42082254,
+          0x4208a290,
+          0x42092182,
+          0x4209a2ca,
+          0x420a21d9,
+          0x420aa1b9,
+          0x420b21f9,
+          0x420ba272,
+          0x420c2487,
+          0x420ca347,
+          0x420d2361,
+          0x420da398,
+          0x421223b2,
+          0x4217244e,
+          0x4217a3f4,
+          0x421c2416,
+          0x421f23d1,
+          0x4221249e,
+          0x42262431,
+          0x422b2537,
+          0x422ba500,
+          0x422c251f,
+          0x422ca4da,
+          0x422d24b9,
           0x4432072b,
           0x4432873a,
           0x44330746,
@@ -781,69 +786,69 @@
           0x4c3d136d,
           0x4c3d937c,
           0x4c3e1389,
-          0x50322a23,
-          0x5032aa32,
-          0x50332a3d,
-          0x5033aa4d,
-          0x50342a66,
-          0x5034aa80,
-          0x50352a8e,
-          0x5035aaa4,
-          0x50362ab6,
-          0x5036aacc,
-          0x50372ae5,
-          0x5037aaf8,
-          0x50382b10,
-          0x5038ab21,
-          0x50392b36,
-          0x5039ab4a,
-          0x503a2b6a,
-          0x503aab80,
-          0x503b2b98,
-          0x503babaa,
-          0x503c2bc6,
-          0x503cabdd,
-          0x503d2bf6,
-          0x503dac0c,
-          0x503e2c19,
-          0x503eac2f,
-          0x503f2c41,
+          0x50322a9b,
+          0x5032aaaa,
+          0x50332ab5,
+          0x5033aac5,
+          0x50342ade,
+          0x5034aaf8,
+          0x50352b06,
+          0x5035ab1c,
+          0x50362b2e,
+          0x5036ab44,
+          0x50372b5d,
+          0x5037ab70,
+          0x50382b88,
+          0x5038ab99,
+          0x50392bae,
+          0x5039abc2,
+          0x503a2be2,
+          0x503aabf8,
+          0x503b2c10,
+          0x503bac22,
+          0x503c2c3e,
+          0x503cac55,
+          0x503d2c6e,
+          0x503dac84,
+          0x503e2c91,
+          0x503eaca7,
+          0x503f2cb9,
           0x503f8382,
-          0x50402c54,
-          0x5040ac64,
-          0x50412c7e,
-          0x5041ac8d,
-          0x50422ca7,
-          0x5042acc4,
-          0x50432cd4,
-          0x5043ace4,
-          0x50442cf3,
+          0x50402ccc,
+          0x5040acdc,
+          0x50412cf6,
+          0x5041ad05,
+          0x50422d1f,
+          0x5042ad3c,
+          0x50432d4c,
+          0x5043ad5c,
+          0x50442d6b,
           0x5044843f,
-          0x50452d07,
-          0x5045ad25,
-          0x50462d38,
-          0x5046ad4e,
-          0x50472d60,
-          0x5047ad75,
-          0x50482d9b,
-          0x5048ada9,
-          0x50492dbc,
-          0x5049add1,
-          0x504a2de7,
-          0x504aadf7,
-          0x504b2e17,
-          0x504bae2a,
-          0x504c2e4d,
-          0x504cae7b,
-          0x504d2e8d,
-          0x504daeaa,
-          0x504e2ec5,
-          0x504eaee1,
-          0x504f2ef3,
-          0x504faf0a,
-          0x50502f19,
+          0x50452d7f,
+          0x5045ad9d,
+          0x50462db0,
+          0x5046adc6,
+          0x50472dd8,
+          0x5047aded,
+          0x50482e13,
+          0x5048ae21,
+          0x50492e34,
+          0x5049ae49,
+          0x504a2e5f,
+          0x504aae6f,
+          0x504b2e8f,
+          0x504baea2,
+          0x504c2ec5,
+          0x504caef3,
+          0x504d2f05,
+          0x504daf22,
+          0x504e2f3d,
+          0x504eaf59,
+          0x504f2f6b,
+          0x504faf82,
+          0x50502f91,
           0x505086ef,
-          0x50512f2c,
+          0x50512fa4,
           0x58320ec9,
           0x68320e8b,
           0x68328c25,
@@ -1204,6 +1209,7 @@
           "BAD_SSL_FILETYPE\\0"
           "BAD_WRITE_RETRY\\0"
           "BIO_NOT_SET\\0"
+          "BUFFERED_MESSAGES_ON_CIPHER_CHANGE\\0"
           "CA_DN_LENGTH_MISMATCH\\0"
           "CA_DN_TOO_LONG\\0"
           "CCS_RECEIVED_EARLY\\0"
@@ -1226,6 +1232,7 @@
           "DIGEST_CHECK_FAILED\\0"
           "DOWNGRADE_DETECTED\\0"
           "DTLS_MESSAGE_TOO_BIG\\0"
+          "DUPLICATE_EXTENSION\\0"
           "ECC_CERT_NOT_FOR_SIGNING\\0"
           "EMS_STATE_INCONSISTENT\\0"
           "ENCRYPTED_LENGTH_TOO_LONG\\0"
@@ -1240,7 +1247,9 @@
           "HTTPS_PROXY_REQUEST\\0"
           "HTTP_REQUEST\\0"
           "INAPPROPRIATE_FALLBACK\\0"
+          "INVALID_ALPN_PROTOCOL\\0"
           "INVALID_COMMAND\\0"
+          "INVALID_COMPRESSION_LIST\\0"
           "INVALID_MESSAGE\\0"
           "INVALID_OUTER_RECORD_TYPE\\0"
           "INVALID_SSL_SESSION\\0"
@@ -1248,6 +1257,7 @@
           "LENGTH_MISMATCH\\0"
           "LIBRARY_HAS_NO_CIPHERS\\0"
           "MISSING_EXTENSION\\0"
+          "MISSING_KEY_SHARE\\0"
           "MISSING_RSA_CERTIFICATE\\0"
           "MISSING_TMP_DH_KEY\\0"
           "MISSING_TMP_ECDH_KEY\\0"
diff --git a/src/objective-c/GRPCClient/private/GRPCHost.m b/src/objective-c/GRPCClient/private/GRPCHost.m
index 477ddf5..9cd9593 100644
--- a/src/objective-c/GRPCClient/private/GRPCHost.m
+++ b/src/objective-c/GRPCClient/private/GRPCHost.m
@@ -49,7 +49,7 @@
 
 // TODO(jcanizales): Generate the version in a standalone header, from templates. Like
 // templates/src/core/surface/version.c.template .
-#define GRPC_OBJC_VERSION_STRING @"1.0.0-pre1"
+#define GRPC_OBJC_VERSION_STRING @"1.0.0"
 
 static NSMutableDictionary *kHostCache;
 
diff --git a/src/objective-c/README.md b/src/objective-c/README.md
index 909b12b..3624475 100644
--- a/src/objective-c/README.md
+++ b/src/objective-c/README.md
@@ -48,7 +48,7 @@
   src = '.'
 
   # We'll use protoc with the gRPC plugin.
-  s.dependency '!ProtoCompiler-gRPCPlugin', '~> 1.0.0-pre1.2'
+  s.dependency '!ProtoCompiler-gRPCPlugin', '~> 1.0'
 
   # Pods directory corresponding to this app's Podfile, relative to the location of this podspec.
   pods_root = '<path to your Podfile>/Pods'
@@ -82,10 +82,6 @@
     ms.requires_arc = false
     # The generated files depend on the protobuf runtime.
     ms.dependency 'Protobuf'
-    # This is needed by all pods that depend on Protobuf:
-    ms.pod_target_xcconfig = {
-      'GCC_PREPROCESSOR_DEFINITIONS' => '$(inherited) GPB_USE_PROTOBUF_FRAMEWORK_IMPORTS=1',
-    }
   end
 
   # The --objcgrpc_out plugin generates a pair of .pbrpc.h/.pbrpc.m files for each .proto file with
@@ -98,6 +94,13 @@
     ss.dependency 'gRPC-ProtoRPC'
     ss.dependency "#{s.name}/Messages"
   end
+
+  s.pod_target_xcconfig = {
+    # This is needed by all pods that depend on Protobuf:
+    'GCC_PREPROCESSOR_DEFINITIONS' => '$(inherited) GPB_USE_PROTOBUF_FRAMEWORK_IMPORTS=1',
+    # This is needed by all pods that depend on gRPC-RxLibrary:
+    'CLANG_ALLOW_NON_MODULAR_INCLUDES_IN_FRAMEWORK_MODULES' => 'YES',
+  }
 end
 ```
 
diff --git a/src/objective-c/RxLibrary/transformations/GRXMappingWriter.m b/src/objective-c/RxLibrary/transformations/GRXMappingWriter.m
index f3242e4..6ee1545 100644
--- a/src/objective-c/RxLibrary/transformations/GRXMappingWriter.m
+++ b/src/objective-c/RxLibrary/transformations/GRXMappingWriter.m
@@ -33,10 +33,6 @@
 
 #import "GRXMappingWriter.h"
 
-static id (^kIdentity)(id value) = ^id(id value) {
-  return value;
-};
-
 @interface GRXForwardingWriter () <GRXWriteable>
 @end
 
@@ -51,7 +47,9 @@
 // Designated initializer
 - (instancetype)initWithWriter:(GRXWriter *)writer map:(id (^)(id value))map {
   if ((self = [super initWithWriter:writer])) {
-    _map = map ?: kIdentity;
+    _map = map ?: ^id(id value) {
+      return value;
+    };
   }
   return self;
 }
diff --git a/src/objective-c/examples/RemoteTestClient/RemoteTest.podspec b/src/objective-c/examples/RemoteTestClient/RemoteTest.podspec
index 974a676..ea61813 100644
--- a/src/objective-c/examples/RemoteTestClient/RemoteTest.podspec
+++ b/src/objective-c/examples/RemoteTestClient/RemoteTest.podspec
@@ -11,7 +11,7 @@
   s.osx.deployment_target = '10.9'
 
   # Run protoc with the Objective-C and gRPC plugins to generate protocol messages and gRPC clients.
-  s.dependency "!ProtoCompiler-gRPCPlugin", "~> 1.0.0-pre1.2"
+  s.dependency "!ProtoCompiler-gRPCPlugin"
 
   repo_root = '../../../..'
   bin_dir = "#{repo_root}/bins/$CONFIG"
@@ -35,10 +35,6 @@
     ms.header_mappings_dir = '.'
     ms.requires_arc = false
     ms.dependency 'Protobuf'
-    # This is needed by all pods that depend on Protobuf:
-    ms.pod_target_xcconfig = {
-      'GCC_PREPROCESSOR_DEFINITIONS' => '$(inherited) GPB_USE_PROTOBUF_FRAMEWORK_IMPORTS=1',
-    }
   end
 
   s.subspec 'Services' do |ss|
@@ -48,4 +44,11 @@
     ss.dependency 'gRPC-ProtoRPC'
     ss.dependency "#{s.name}/Messages"
   end
+
+  s.pod_target_xcconfig = {
+    # This is needed by all pods that depend on Protobuf:
+    'GCC_PREPROCESSOR_DEFINITIONS' => '$(inherited) GPB_USE_PROTOBUF_FRAMEWORK_IMPORTS=1',
+    # This is needed by all pods that depend on gRPC-RxLibrary:
+    'CLANG_ALLOW_NON_MODULAR_INCLUDES_IN_FRAMEWORK_MODULES' => 'YES',
+  }
 end
diff --git a/src/objective-c/tests/RemoteTestClient/RemoteTest.podspec b/src/objective-c/tests/RemoteTestClient/RemoteTest.podspec
index 3d28234..2e0a050 100644
--- a/src/objective-c/tests/RemoteTestClient/RemoteTest.podspec
+++ b/src/objective-c/tests/RemoteTestClient/RemoteTest.podspec
@@ -11,7 +11,7 @@
   s.osx.deployment_target = '10.9'
 
   # Run protoc with the Objective-C and gRPC plugins to generate protocol messages and gRPC clients.
-  s.dependency "!ProtoCompiler-gRPCPlugin", "~> 1.0.0-pre1.2"
+  s.dependency "!ProtoCompiler-gRPCPlugin"
 
   repo_root = '../../../..'
   bin_dir = "#{repo_root}/bins/$CONFIG"
@@ -35,10 +35,6 @@
     ms.header_mappings_dir = "."
     ms.requires_arc = false
     ms.dependency "Protobuf"
-    # This is needed by all pods that depend on Protobuf:
-    ms.pod_target_xcconfig = {
-      'GCC_PREPROCESSOR_DEFINITIONS' => '$(inherited) GPB_USE_PROTOBUF_FRAMEWORK_IMPORTS=1',
-    }
   end
 
   s.subspec "Services" do |ss|
@@ -48,4 +44,11 @@
     ss.dependency "gRPC-ProtoRPC"
     ss.dependency "#{s.name}/Messages"
   end
+
+  s.pod_target_xcconfig = {
+    # This is needed by all pods that depend on Protobuf:
+    'GCC_PREPROCESSOR_DEFINITIONS' => '$(inherited) GPB_USE_PROTOBUF_FRAMEWORK_IMPORTS=1',
+    # This is needed by all pods that depend on gRPC-RxLibrary:
+    'CLANG_ALLOW_NON_MODULAR_INCLUDES_IN_FRAMEWORK_MODULES' => 'YES',
+  }
 end
diff --git a/src/php/composer.json b/src/php/composer.json
index 1eacc64..571f300 100644
--- a/src/php/composer.json
+++ b/src/php/composer.json
@@ -5,7 +5,7 @@
   "keywords": ["rpc"],
   "homepage": "http://grpc.io",
   "license": "BSD-3-Clause",
-  "version": "1.0.0",
+  "version": "1.1.0",
   "require": {
     "php": ">=5.5.0",
     "stanley-cheung/protobuf-php": "v0.6"
diff --git a/src/php/ext/grpc/call.c b/src/php/ext/grpc/call.c
index 66ca151..31c59fe 100644
--- a/src/php/ext/grpc/call.c
+++ b/src/php/ext/grpc/call.c
@@ -164,6 +164,9 @@
     if (key_type1 != HASH_KEY_IS_STRING) {
       return false;
     }
+    if (!grpc_header_key_is_legal(key1, strlen(key1))) {
+      return false;
+    }
     inner_array_hash = Z_ARRVAL_P(inner_array);
     PHP_GRPC_HASH_FOREACH_VAL_START(inner_array_hash, value)
       if (Z_TYPE_P(value) != IS_STRING) {
diff --git a/src/php/ext/grpc/call_credentials.c b/src/php/ext/grpc/call_credentials.c
index 6921a5d..25c92c9 100644
--- a/src/php/ext/grpc/call_credentials.c
+++ b/src/php/ext/grpc/call_credentials.c
@@ -192,23 +192,15 @@
   /* call the user callback function */
   zend_call_function(state->fci, state->fci_cache TSRMLS_CC);
 
-  if (Z_TYPE_P(retval) != IS_ARRAY) {
-    zend_throw_exception(spl_ce_InvalidArgumentException,
-                         "plugin callback must return metadata array",
-                         1 TSRMLS_CC);
-    return;
-  }
-
-  grpc_metadata_array metadata;
-  if (!create_metadata_array(retval, &metadata)) {
-    zend_throw_exception(spl_ce_InvalidArgumentException,
-                         "invalid metadata", 1 TSRMLS_CC);
-    grpc_metadata_array_destroy(&metadata);
-    return;
-  }
-
-  /* TODO: handle error */
   grpc_status_code code = GRPC_STATUS_OK;
+  grpc_metadata_array metadata;
+
+  if (Z_TYPE_P(retval) != IS_ARRAY) {
+    code = GRPC_STATUS_INVALID_ARGUMENT;
+  } else if (!create_metadata_array(retval, &metadata)) {
+    grpc_metadata_array_destroy(&metadata);
+    code = GRPC_STATUS_INVALID_ARGUMENT;
+  }
 
   /* Pass control back to core */
   cb(user_data, metadata.metadata, metadata.count, code, NULL);
diff --git a/src/php/lib/Grpc/AbstractCall.php b/src/php/lib/Grpc/AbstractCall.php
index c86d298..c58ee56 100644
--- a/src/php/lib/Grpc/AbstractCall.php
+++ b/src/php/lib/Grpc/AbstractCall.php
@@ -34,8 +34,15 @@
 
 namespace Grpc;
 
+/**
+ * Class AbstractCall
+ * @package Grpc
+ */
 abstract class AbstractCall
 {
+    /**
+     * @var Call
+     */
     protected $call;
     protected $deserialize;
     protected $metadata;
@@ -51,13 +58,15 @@
      *                              the response
      * @param array    $options     Call options (optional)
      */
-    public function __construct(Channel $channel,
-                                $method,
-                                $deserialize,
-                                $options = [])
-    {
-        if (isset($options['timeout']) &&
-            is_numeric($timeout = $options['timeout'])) {
+    public function __construct(
+        Channel $channel,
+        $method,
+        $deserialize,
+        $options = []
+    ) {
+        if (array_key_exists('timeout', $options) &&
+            is_numeric($timeout = $options['timeout'])
+        ) {
             $now = Timeval::now();
             $delta = new Timeval($timeout);
             $deadline = $now->add($delta);
@@ -68,17 +77,19 @@
         $this->deserialize = $deserialize;
         $this->metadata = null;
         $this->trailing_metadata = null;
-        if (isset($options['call_credentials_callback']) &&
+        if (array_key_exists('call_credentials_callback', $options) &&
             is_callable($call_credentials_callback =
-                        $options['call_credentials_callback'])) {
+                $options['call_credentials_callback'])
+        ) {
             $call_credentials = CallCredentials::createFromPlugin(
-                $call_credentials_callback);
+                $call_credentials_callback
+            );
             $this->call->setCredentials($call_credentials);
         }
     }
 
     /**
-     * @return The metadata sent by the server.
+     * @return mixed The metadata sent by the server.
      */
     public function getMetadata()
     {
@@ -86,7 +97,7 @@
     }
 
     /**
-     * @return The trailing metadata sent by the server.
+     * @return mixed The trailing metadata sent by the server.
      */
     public function getTrailingMetadata()
     {
@@ -114,7 +125,7 @@
      *
      * @param string $value The binary value to deserialize
      *
-     * @return The deserialized value
+     * @return mixed The deserialized value
      */
     protected function deserializeResponse($value)
     {
diff --git a/src/php/lib/Grpc/BidiStreamingCall.php b/src/php/lib/Grpc/BidiStreamingCall.php
index c2fdb94..5d6ecfb 100644
--- a/src/php/lib/Grpc/BidiStreamingCall.php
+++ b/src/php/lib/Grpc/BidiStreamingCall.php
@@ -45,7 +45,7 @@
      *
      * @param array $metadata Metadata to send with the call, if applicable
      */
-    public function start($metadata = [])
+    public function start(array $metadata = [])
     {
         $this->call->startBatch([
             OP_SEND_INITIAL_METADATA => $metadata,
@@ -55,7 +55,7 @@
     /**
      * Reads the next value from the server.
      *
-     * @return The next value from the server, or null if there is none
+     * @return mixed The next value from the server, or null if there is none
      */
     public function read()
     {
@@ -82,7 +82,7 @@
     public function write($data, $options = [])
     {
         $message_array = ['message' => $data->serialize()];
-        if (isset($options['flags'])) {
+        if (array_key_exists('flags', $options)) {
             $message_array['flags'] = $options['flags'];
         }
         $this->call->startBatch([
@@ -103,8 +103,8 @@
     /**
      * Wait for the server to send the status, and return it.
      *
-     * @return object The status object, with integer $code, string $details,
-     *                and array $metadata members
+     * @return \stdClass The status object, with integer $code, string $details,
+     *                   and array $metadata members
      */
     public function getStatus()
     {
diff --git a/src/php/lib/Grpc/ClientStreamingCall.php b/src/php/lib/Grpc/ClientStreamingCall.php
index 4050f7e..c96e26d 100644
--- a/src/php/lib/Grpc/ClientStreamingCall.php
+++ b/src/php/lib/Grpc/ClientStreamingCall.php
@@ -60,10 +60,10 @@
      * @param array      $options an array of options, possible keys:
      *                            'flags' => a number
      */
-    public function write($data, $options = [])
+    public function write($data, array $options = [])
     {
         $message_array = ['message' => $data->serialize()];
-        if (isset($options['flags'])) {
+        if (array_key_exists('flags', $options)) {
             $message_array['flags'] = $options['flags'];
         }
         $this->call->startBatch([
@@ -74,7 +74,7 @@
     /**
      * Wait for the server to respond with data and a status.
      *
-     * @return [response data, status]
+     * @return array [response data, status]
      */
     public function wait()
     {
diff --git a/src/php/lib/Grpc/ServerStreamingCall.php b/src/php/lib/Grpc/ServerStreamingCall.php
index ba89d9f..5f0d42c 100644
--- a/src/php/lib/Grpc/ServerStreamingCall.php
+++ b/src/php/lib/Grpc/ServerStreamingCall.php
@@ -36,14 +36,14 @@
 
 /**
  * Represents an active call that sends a single message and then gets a stream
- * of reponses.
+ * of responses.
  */
 class ServerStreamingCall extends AbstractCall
 {
     /**
      * Start the call.
      *
-     * @param $data The data to send
+     * @param mixed $data     The data to send
      * @param array $metadata Metadata to send with the call, if applicable
      * @param array $options  an array of options, possible keys:
      *                        'flags' => a number
@@ -51,7 +51,7 @@
     public function start($data, $metadata = [], $options = [])
     {
         $message_array = ['message' => $data->serialize()];
-        if (isset($options['flags'])) {
+        if (array_key_exists('flags', $options)) {
             $message_array['flags'] = $options['flags'];
         }
         $event = $this->call->startBatch([
@@ -64,7 +64,7 @@
     }
 
     /**
-     * @return An iterator of response values
+     * @return mixed An iterator of response values
      */
     public function responses()
     {
@@ -82,8 +82,8 @@
     /**
      * Wait for the server to send the status, and return it.
      *
-     * @return object The status object, with integer $code, string $details,
-     *                and array $metadata members
+     * @return \stdClass The status object, with integer $code, string $details,
+     *                   and array $metadata members
      */
     public function getStatus()
     {
diff --git a/src/php/lib/Grpc/UnaryCall.php b/src/php/lib/Grpc/UnaryCall.php
index a71b05d..487b89e 100644
--- a/src/php/lib/Grpc/UnaryCall.php
+++ b/src/php/lib/Grpc/UnaryCall.php
@@ -43,7 +43,7 @@
     /**
      * Start the call.
      *
-     * @param $data The data to send
+     * @param mixed $data     The data to send
      * @param array $metadata Metadata to send with the call, if applicable
      * @param array $options  an array of options, possible keys:
      *                        'flags' => a number
@@ -66,7 +66,7 @@
     /**
      * Wait for the server to respond with data and a status.
      *
-     * @return [response data, status]
+     * @return array [response data, status]
      */
     public function wait()
     {
diff --git a/src/php/tests/interop/interop_client.php b/src/php/tests/interop/interop_client.php
index bf40549..c94ba61 100755
--- a/src/php/tests/interop/interop_client.php
+++ b/src/php/tests/interop/interop_client.php
@@ -54,6 +54,15 @@
     }
 }
 
+function hardAssertIfStatusOk($status)
+{
+    if ($status->code !== Grpc\STATUS_OK) {
+        echo "Call did not complete successfully. Status object:\n";
+        var_dump($status);
+        exit(1);
+    }
+}
+
 /**
  * Run the empty_unary test.
  *
@@ -62,7 +71,7 @@
 function emptyUnary($stub)
 {
     list($result, $status) = $stub->EmptyCall(new grpc\testing\EmptyMessage())->wait();
-    hardAssert($status->code === Grpc\STATUS_OK, 'Call did not complete successfully');
+    hardAssertIfStatusOk($status);
     hardAssert($result !== null, 'Call completed with a null response');
 }
 
@@ -105,7 +114,7 @@
     }
 
     list($result, $status) = $stub->UnaryCall($request, [], $options)->wait();
-    hardAssert($status->code === Grpc\STATUS_OK, 'Call did not complete successfully');
+    hardAssertIfStatusOk($status);
     hardAssert($result !== null, 'Call returned a null response');
     $payload = $result->getPayload();
     hardAssert($payload->getType() === grpc\testing\PayloadType::COMPRESSABLE,
@@ -197,7 +206,12 @@
     $methodName = $context->method_name;
     $auth_credentials = ApplicationDefaultCredentials::getCredentials();
 
-    return $auth_credentials->updateMetadata($metadata = [], $authUri);
+    $metadata = [];
+    $result = $auth_credentials->updateMetadata([], $authUri);
+    foreach ($result as $key => $value) {
+      $metadata[strtolower($key)] = $value;
+    }
+    return $metadata;
 }
 
 /**
@@ -242,7 +256,7 @@
         $call->write($request);
     }
     list($result, $status) = $call->wait();
-    hardAssert($status->code === Grpc\STATUS_OK, 'Call did not complete successfully');
+    hardAssertIfStatusOk($status);
     hardAssert($result->getAggregatedPayloadSize() === 74922,
               'aggregated_payload_size was incorrect');
 }
@@ -275,8 +289,7 @@
                 'Response '.$i.' had the wrong length');
         $i += 1;
     }
-    hardAssert($call->getStatus()->code === Grpc\STATUS_OK,
-             'Call did not complete successfully');
+    hardAssertIfStatusOk($call->getStatus());
 }
 
 /**
@@ -312,8 +325,7 @@
     }
     $call->writesDone();
     hardAssert($call->read() === null, 'Server returned too many responses');
-    hardAssert($call->getStatus()->code === Grpc\STATUS_OK,
-              'Call did not complete successfully');
+    hardAssertIfStatusOk($call->getStatus());
 }
 
 /**
@@ -326,8 +338,7 @@
     $call = $stub->FullDuplexCall();
     $call->writesDone();
     hardAssert($call->read() === null, 'Server returned too many responses');
-    hardAssert($call->getStatus()->code === Grpc\STATUS_OK,
-             'Call did not complete successfully');
+    hardAssertIfStatusOk($call->getStatus());
 }
 
 /**
@@ -419,8 +430,7 @@
                'Incorrect initial metadata value');
 
     list($result, $status) = $call->wait();
-    hardAssert($status->code === Grpc\STATUS_OK,
-               'Call did not complete successfully');
+    hardAssertIfStatusOk($status);
 
     $trailing_metadata = $call->getTrailingMetadata();
     hardAssert(array_key_exists($ECHO_TRAILING_KEY, $trailing_metadata),
@@ -435,8 +445,7 @@
     $streaming_call->write($streaming_request);
     $streaming_call->writesDone();
 
-    hardAssert($streaming_call->getStatus()->code === Grpc\STATUS_OK,
-               'Call did not complete successfully');
+    hardAssertIfStatusOk($streaming_call->getStatus());
 
     $streaming_trailing_metadata = $streaming_call->getTrailingMetadata();
     hardAssert(array_key_exists($ECHO_TRAILING_KEY,
diff --git a/src/php/tests/unit_tests/CallCredentials2Test.php b/src/php/tests/unit_tests/CallCredentials2Test.php
index a57e2b9..b3b98a2 100644
--- a/src/php/tests/unit_tests/CallCredentials2Test.php
+++ b/src/php/tests/unit_tests/CallCredentials2Test.php
@@ -132,4 +132,69 @@
         unset($call);
         unset($server_call);
     }
+
+    public function invalidKeyCallbackFunc($context)
+    {
+        $this->assertTrue(is_string($context->service_url));
+        $this->assertTrue(is_string($context->method_name));
+
+        return ['K1' => ['v1']];
+    }
+
+    public function testCallbackWithInvalidKey()
+    {
+        $deadline = Grpc\Timeval::infFuture();
+        $status_text = 'xyz';
+        $call = new Grpc\Call($this->channel,
+                              '/abc/dummy_method',
+                              $deadline,
+                              $this->host_override);
+
+        $call_credentials = Grpc\CallCredentials::createFromPlugin(
+            array($this, 'invalidKeyCallbackFunc'));
+        $call->setCredentials($call_credentials);
+
+        $event = $call->startBatch([
+            Grpc\OP_SEND_INITIAL_METADATA => [],
+            Grpc\OP_SEND_CLOSE_FROM_CLIENT => true,
+            Grpc\OP_RECV_STATUS_ON_CLIENT => true,
+        ]);
+
+        $this->assertTrue($event->send_metadata);
+        $this->assertTrue($event->send_close);
+        $this->assertTrue($event->status->code == Grpc\STATUS_UNAUTHENTICATED);
+    }
+
+    public function invalidReturnCallbackFunc($context)
+    {
+        $this->assertTrue(is_string($context->service_url));
+        $this->assertTrue(is_string($context->method_name));
+
+        return "a string";
+    }
+
+    public function testCallbackWithInvalidReturnValue()
+    {
+        $deadline = Grpc\Timeval::infFuture();
+        $status_text = 'xyz';
+        $call = new Grpc\Call($this->channel,
+                              '/abc/dummy_method',
+                              $deadline,
+                              $this->host_override);
+
+        $call_credentials = Grpc\CallCredentials::createFromPlugin(
+            array($this, 'invalidReturnCallbackFunc'));
+        $call->setCredentials($call_credentials);
+
+        $event = $call->startBatch([
+            Grpc\OP_SEND_INITIAL_METADATA => [],
+            Grpc\OP_SEND_CLOSE_FROM_CLIENT => true,
+            Grpc\OP_RECV_STATUS_ON_CLIENT => true,
+        ]);
+
+        $this->assertTrue($event->send_metadata);
+        $this->assertTrue($event->send_close);
+        $this->assertTrue($event->status->code == Grpc\STATUS_UNAUTHENTICATED);
+    }
+
 }
diff --git a/src/php/tests/unit_tests/CallCredentials3Test.php b/src/php/tests/unit_tests/CallCredentials3Test.php
deleted file mode 100644
index 8f5e109..0000000
--- a/src/php/tests/unit_tests/CallCredentials3Test.php
+++ /dev/null
@@ -1,135 +0,0 @@
-<?php
-/*
- *
- * Copyright 2015, Google Inc.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- *     * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *     * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-class CallCredentials3Test extends PHPUnit_Framework_TestCase
-{
-    public function setUp()
-    {
-        $this->credentials = Grpc\ChannelCredentials::createSsl(
-            file_get_contents(dirname(__FILE__).'/../data/ca.pem'));
-        $server_credentials = Grpc\ServerCredentials::createSsl(
-            null,
-            file_get_contents(dirname(__FILE__).'/../data/server1.key'),
-            file_get_contents(dirname(__FILE__).'/../data/server1.pem'));
-        $this->server = new Grpc\Server();
-        $this->port = $this->server->addSecureHttp2Port('0.0.0.0:0',
-                                              $server_credentials);
-        $this->server->start();
-        $this->host_override = 'foo.test.google.fr';
-        $this->channel = new Grpc\Channel(
-            'localhost:'.$this->port,
-            [
-            'grpc.ssl_target_name_override' => $this->host_override,
-            'grpc.default_authority' => $this->host_override,
-            'credentials' => $this->credentials,
-            ]
-        );
-    }
-
-    public function tearDown()
-    {
-        unset($this->channel);
-        unset($this->server);
-    }
-
-    public function callbackFunc($context)
-    {
-        $this->assertTrue(is_string($context->service_url));
-        $this->assertTrue(is_string($context->method_name));
-
-        return ['k1' => ['v1'], 'k2' => ['v2']];
-    }
-
-    public function testCreateFromPlugin()
-    {
-        $deadline = Grpc\Timeval::infFuture();
-        $status_text = 'xyz';
-        $call = new Grpc\Call($this->channel,
-                              '/abc/dummy_method',
-                              $deadline,
-                              $this->host_override);
-
-        $call_credentials = Grpc\CallCredentials::createFromPlugin(
-            [$this, 'callbackFunc']);
-        $call->setCredentials($call_credentials);
-
-        $event = $call->startBatch([
-            Grpc\OP_SEND_INITIAL_METADATA => [],
-            Grpc\OP_SEND_CLOSE_FROM_CLIENT => true,
-        ]);
-
-        $this->assertTrue($event->send_metadata);
-        $this->assertTrue($event->send_close);
-
-        $event = $this->server->requestCall();
-
-        $this->assertTrue(is_array($event->metadata));
-        $metadata = $event->metadata;
-        $this->assertTrue(array_key_exists('k1', $metadata));
-        $this->assertTrue(array_key_exists('k2', $metadata));
-        $this->assertSame($metadata['k1'], ['v1']);
-        $this->assertSame($metadata['k2'], ['v2']);
-
-        $this->assertSame('/abc/dummy_method', $event->method);
-        $server_call = $event->call;
-
-        $event = $server_call->startBatch([
-            Grpc\OP_SEND_INITIAL_METADATA => [],
-            Grpc\OP_SEND_STATUS_FROM_SERVER => [
-                'metadata' => [],
-                'code' => Grpc\STATUS_OK,
-                'details' => $status_text,
-            ],
-            Grpc\OP_RECV_CLOSE_ON_SERVER => true,
-        ]);
-
-        $this->assertTrue($event->send_metadata);
-        $this->assertTrue($event->send_status);
-        $this->assertFalse($event->cancelled);
-
-        $event = $call->startBatch([
-            Grpc\OP_RECV_INITIAL_METADATA => true,
-            Grpc\OP_RECV_STATUS_ON_CLIENT => true,
-        ]);
-
-        $this->assertSame([], $event->metadata);
-        $status = $event->status;
-        $this->assertSame([], $status->metadata);
-        $this->assertSame(Grpc\STATUS_OK, $status->code);
-        $this->assertSame($status_text, $status->details);
-
-        unset($call);
-        unset($server_call);
-    }
-}
diff --git a/src/php/tests/unit_tests/CallTest.php b/src/php/tests/unit_tests/CallTest.php
index d736f51..1205f0c 100644
--- a/src/php/tests/unit_tests/CallTest.php
+++ b/src/php/tests/unit_tests/CallTest.php
@@ -113,7 +113,7 @@
     /**
      * @expectedException InvalidArgumentException
      */
-    public function testInvalidMetadataKey()
+    public function testInvalidStartBatchKey()
     {
         $batch = [
             'invalid' => ['key1' => 'value1'],
@@ -124,6 +124,28 @@
     /**
      * @expectedException InvalidArgumentException
      */
+    public function testInvalidMetadataStrKey()
+    {
+        $batch = [
+            Grpc\OP_SEND_INITIAL_METADATA => ['Key' => ['value1', 'value2']],
+        ];
+        $result = $this->call->startBatch($batch);
+    }
+
+    /**
+     * @expectedException InvalidArgumentException
+     */
+    public function testInvalidMetadataIntKey()
+    {
+        $batch = [
+            Grpc\OP_SEND_INITIAL_METADATA => [1 => ['value1', 'value2']],
+        ];
+        $result = $this->call->startBatch($batch);
+    }
+
+    /**
+     * @expectedException InvalidArgumentException
+     */
     public function testInvalidMetadataInnerValue()
     {
         $batch = [
diff --git a/src/proto/census/trace_context.options b/src/proto/census/trace_context.options
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/proto/census/trace_context.options
diff --git a/src/proto/census/trace_context.proto b/src/proto/census/trace_context.proto
new file mode 100644
index 0000000..a5d5a95
--- /dev/null
+++ b/src/proto/census/trace_context.proto
@@ -0,0 +1,48 @@
+// Copyright 2016, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+syntax = "proto3";
+
+package google.trace;
+
+// A TraceId uniquely represents a single Trace. It is a 128-bit nonce.
+message TraceId {
+  fixed64 hi = 1;
+  fixed64 lo = 2;
+}
+
+// Tracing information that is propagated with RPC's.
+message TraceContext {
+  // Trace identifer. Must be present.
+  TraceId trace_id = 1;
+  // ID of parent (client) span. Must be present.
+  fixed64 span_id = 2;
+  // true if this trace is sampled.
+  bool is_sampled = 3;
+}
diff --git a/src/python/grpcio/_spawn_patch.py b/src/python/grpcio/_spawn_patch.py
new file mode 100644
index 0000000..24306f0
--- /dev/null
+++ b/src/python/grpcio/_spawn_patch.py
@@ -0,0 +1,73 @@
+# Copyright 2016, Google Inc.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+#     * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+#     * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+"""Patches the spawn() command for windows compilers.
+
+Windows has an 8191 character command line limit, but some compilers
+support an @command_file directive where command_file is a file
+containing the full command line.
+"""
+
+from distutils import ccompiler
+import os
+import os.path
+import shutil
+import sys
+import tempfile
+
+MAX_COMMAND_LENGTH = 8191
+
+_classic_spawn = ccompiler.CCompiler.spawn
+
+def _commandfile_spawn(self, command):
+  command_length = sum([len(arg) for arg in command])
+  if os.name == 'nt' and command_length > MAX_COMMAND_LENGTH:
+    # Even if this command doesn't support the @command_file, it will
+    # fail as is so we try blindly
+    print('Command line length exceeded, using command file')
+    print(' '.join(command))
+    temporary_directory = tempfile.mkdtemp()
+    command_filename = os.path.abspath(
+    os.path.join(temporary_directory, 'command'))
+    with open(command_filename, 'w') as command_file:
+      escaped_args = ['"' + arg.replace('\\', '\\\\') + '"' for arg in command[1:]]
+      command_file.write(' '.join(escaped_args))
+    modified_command = command[:1] + ['@{}'.format(command_filename)]
+    try:
+      _classic_spawn(self, modified_command)
+    finally:
+      shutil.rmtree(temporary_directory)
+  else:
+    _classic_spawn(self, command)
+
+
+def monkeypatch_spawn():
+  """Monkeypatching is dumb, but it's either that or we become maintainers of
+     something much, much bigger."""
+  ccompiler.CCompiler.spawn = _commandfile_spawn
diff --git a/src/python/grpcio/_unixccompiler_patch.py b/src/python/grpcio/_unixccompiler_patch.py
deleted file mode 100644
index 894c3ef..0000000
--- a/src/python/grpcio/_unixccompiler_patch.py
+++ /dev/null
@@ -1,77 +0,0 @@
-# Copyright 2016, Google Inc.
-# All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions are
-# met:
-#
-#     * Redistributions of source code must retain the above copyright
-# notice, this list of conditions and the following disclaimer.
-#     * Redistributions in binary form must reproduce the above
-# copyright notice, this list of conditions and the following disclaimer
-# in the documentation and/or other materials provided with the
-# distribution.
-#     * Neither the name of Google Inc. nor the names of its
-# contributors may be used to endorse or promote products derived from
-# this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-"""Covers inadequacies in distutils."""
-
-from distutils import ccompiler
-from distutils import errors
-from distutils import unixccompiler
-import os
-import os.path
-import shlex
-import shutil
-import sys
-import tempfile
-
-def _unix_commandfile_spawn(self, command):
-  """Wrapper around distutils.util.spawn that attempts to use command files.
-
-  Meant to replace the CCompiler method `spawn` on UnixCCompiler and its
-  derivatives (e.g. the MinGW32 compiler).
-
-  Some commands like `gcc` (and friends like `clang`) support command files to
-  work around shell command length limits.
-  """
-  # Sometimes distutils embeds the executables as full strings including some
-  # hard-coded flags rather than as lists.
-  command = list(shlex.split(command[0])) + list(command[1:])
-  command_base = os.path.basename(command[0].strip())
-  if command_base == 'ccache':
-    command_base = command[:2]
-    command_args = command[2:]
-  elif command_base.startswith('ccache') or command_base in ['gcc', 'clang', 'clang++', 'g++']:
-    command_base = command[:1]
-    command_args = command[1:]
-  else:
-    return ccompiler.CCompiler.spawn(self, command)
-  temporary_directory = tempfile.mkdtemp()
-  command_filename = os.path.abspath(os.path.join(temporary_directory, 'command'))
-  with open(command_filename, 'w') as command_file:
-    escaped_args = [arg.replace('\\', '\\\\') for arg in command_args]
-    command_file.write(' '.join(escaped_args))
-  modified_command = command_base + ['@{}'.format(command_filename)]
-  result = ccompiler.CCompiler.spawn(self, modified_command)
-  shutil.rmtree(temporary_directory)
-  return result
-
-
-def monkeypatch_unix_compiler():
-  """Monkeypatching is dumb, but it's either that or we become maintainers of
-     something much, much bigger."""
-  unixccompiler.UnixCCompiler.spawn = _unix_commandfile_spawn
diff --git a/src/python/grpcio/grpc_core_dependencies.py b/src/python/grpcio/grpc_core_dependencies.py
index 7ae76f5..1ae412e 100644
--- a/src/python/grpcio/grpc_core_dependencies.py
+++ b/src/python/grpcio/grpc_core_dependencies.py
@@ -50,6 +50,7 @@
   'src/core/lib/support/log_linux.c',
   'src/core/lib/support/log_posix.c',
   'src/core/lib/support/log_windows.c',
+  'src/core/lib/support/mpscq.c',
   'src/core/lib/support/murmur_hash.c',
   'src/core/lib/support/slice.c',
   'src/core/lib/support/slice_buffer.c',
@@ -91,6 +92,7 @@
   'src/core/lib/http/httpcli.c',
   'src/core/lib/http/parser.c',
   'src/core/lib/iomgr/closure.c',
+  'src/core/lib/iomgr/combiner.c',
   'src/core/lib/iomgr/endpoint.c',
   'src/core/lib/iomgr/endpoint_pair_posix.c',
   'src/core/lib/iomgr/endpoint_pair_windows.c',
@@ -220,7 +222,6 @@
   'src/core/ext/client_config/channel_connectivity.c',
   'src/core/ext/client_config/client_channel.c',
   'src/core/ext/client_config/client_channel_factory.c',
-  'src/core/ext/client_config/client_config.c',
   'src/core/ext/client_config/client_config_plugin.c',
   'src/core/ext/client_config/connector.c',
   'src/core/ext/client_config/default_initial_connect_string.c',
@@ -232,8 +233,8 @@
   'src/core/ext/client_config/resolver.c',
   'src/core/ext/client_config/resolver_factory.c',
   'src/core/ext/client_config/resolver_registry.c',
+  'src/core/ext/client_config/resolver_result.c',
   'src/core/ext/client_config/subchannel.c',
-  'src/core/ext/client_config/subchannel_call_holder.c',
   'src/core/ext/client_config/subchannel_index.c',
   'src/core/ext/client_config/uri_parser.c',
   'src/core/ext/transport/chttp2/server/insecure/server_chttp2.c',
@@ -255,6 +256,7 @@
   'src/core/ext/census/base_resources.c',
   'src/core/ext/census/context.c',
   'src/core/ext/census/gen/census.pb.c',
+  'src/core/ext/census/gen/trace_context.pb.c',
   'src/core/ext/census/grpc_context.c',
   'src/core/ext/census/grpc_filter.c',
   'src/core/ext/census/grpc_plugin.c',
diff --git a/src/python/grpcio_health_checking/setup.py b/src/python/grpcio_health_checking/setup.py
index 6074175..8c92ee1 100644
--- a/src/python/grpcio_health_checking/setup.py
+++ b/src/python/grpcio_health_checking/setup.py
@@ -46,12 +46,12 @@
 }
 
 SETUP_REQUIRES = (
-    'grpcio-tools>=0.15.0',
+    'grpcio-tools>={version}'.format(version=grpc_version.VERSION),
 )
 
 INSTALL_REQUIRES = (
     'protobuf>=3.0.0',
-    'grpcio>=0.15.0',
+    'grpcio>={version}'.format(version=grpc_version.VERSION),
 )
 
 COMMAND_CLASS = {
diff --git a/src/python/grpcio_tests/setup.py b/src/python/grpcio_tests/setup.py
index 5c60eac..3524355 100644
--- a/src/python/grpcio_tests/setup.py
+++ b/src/python/grpcio_tests/setup.py
@@ -60,17 +60,14 @@
     'coverage>=4.0',
     'enum34>=1.0.4',
     'futures>=2.2.0',
-    'grpcio>=0.14.0',
-    'grpcio-health-checking>=0.14.0',
+    'grpcio>={version}'.format(version=grpc_version.VERSION),
+    'grpcio-tools>={version}'.format(version=grpc_version.VERSION),
+    'grpcio-health-checking>={version}'.format(version=grpc_version.VERSION),
     'oauth2client>=1.4.7',
     'protobuf>=3.0.0',
     'six>=1.10',
 )
 
-SETUP_REQUIRES = (
-    'grpcio-tools>=0.14.0',
-)
-
 COMMAND_CLASS = {
     # Run `preprocess` *before* doing any packaging!
     'preprocess': commands.GatherProto,
@@ -115,7 +112,6 @@
   package_dir=PACKAGE_DIRECTORIES,
   package_data=PACKAGE_DATA,
   install_requires=INSTALL_REQUIRES,
-  setup_requires=SETUP_REQUIRES,
   cmdclass=COMMAND_CLASS,
   tests_require=TESTS_REQUIRE,
   test_suite=TEST_SUITE,
diff --git a/src/python/grpcio_tests/tests/unit/_cython/cygrpc_test.py b/src/python/grpcio_tests/tests/unit/_cython/cygrpc_test.py
index 2f50263..142387d 100644
--- a/src/python/grpcio_tests/tests/unit/_cython/cygrpc_test.py
+++ b/src/python/grpcio_tests/tests/unit/_cython/cygrpc_test.py
@@ -114,9 +114,6 @@
         lambda ignored_a, ignored_b: None, b'')
     del plugin
 
-  @unittest.skipIf(
-    platform.python_implementation() == "PyPy",
-    'TODO(issue 7672): figure out why this fails on PyPy')
   def testCallCredentialsFromPluginUpDown(self):
     plugin = cygrpc.CredentialsMetadataPlugin(_metadata_plugin_callback, b'')
     call_credentials = cygrpc.call_credentials_metadata_plugin(plugin)
diff --git a/src/ruby/ext/grpc/rb_grpc_imports.generated.c b/src/ruby/ext/grpc/rb_grpc_imports.generated.c
index aee57b1..9caaf7b 100644
--- a/src/ruby/ext/grpc/rb_grpc_imports.generated.c
+++ b/src/ruby/ext/grpc/rb_grpc_imports.generated.c
@@ -80,6 +80,7 @@
 grpc_init_type grpc_init_import;
 grpc_shutdown_type grpc_shutdown_import;
 grpc_version_string_type grpc_version_string_import;
+grpc_g_stands_for_type grpc_g_stands_for_import;
 grpc_completion_queue_create_type grpc_completion_queue_create_import;
 grpc_completion_queue_next_type grpc_completion_queue_next_import;
 grpc_completion_queue_pluck_type grpc_completion_queue_pluck_import;
@@ -348,6 +349,7 @@
   grpc_init_import = (grpc_init_type) GetProcAddress(library, "grpc_init");
   grpc_shutdown_import = (grpc_shutdown_type) GetProcAddress(library, "grpc_shutdown");
   grpc_version_string_import = (grpc_version_string_type) GetProcAddress(library, "grpc_version_string");
+  grpc_g_stands_for_import = (grpc_g_stands_for_type) GetProcAddress(library, "grpc_g_stands_for");
   grpc_completion_queue_create_import = (grpc_completion_queue_create_type) GetProcAddress(library, "grpc_completion_queue_create");
   grpc_completion_queue_next_import = (grpc_completion_queue_next_type) GetProcAddress(library, "grpc_completion_queue_next");
   grpc_completion_queue_pluck_import = (grpc_completion_queue_pluck_type) GetProcAddress(library, "grpc_completion_queue_pluck");
diff --git a/src/ruby/ext/grpc/rb_grpc_imports.generated.h b/src/ruby/ext/grpc/rb_grpc_imports.generated.h
index 3bb76fb..a2f5b86 100644
--- a/src/ruby/ext/grpc/rb_grpc_imports.generated.h
+++ b/src/ruby/ext/grpc/rb_grpc_imports.generated.h
@@ -191,6 +191,9 @@
 typedef const char *(*grpc_version_string_type)(void);
 extern grpc_version_string_type grpc_version_string_import;
 #define grpc_version_string grpc_version_string_import
+typedef const char *(*grpc_g_stands_for_type)(void);
+extern grpc_g_stands_for_type grpc_g_stands_for_import;
+#define grpc_g_stands_for grpc_g_stands_for_import
 typedef grpc_completion_queue *(*grpc_completion_queue_create_type)(void *reserved);
 extern grpc_completion_queue_create_type grpc_completion_queue_create_import;
 #define grpc_completion_queue_create grpc_completion_queue_create_import
diff --git a/summerofcode/2016/siddharth_shukla.md b/summerofcode/2016/siddharth_shukla.md
new file mode 100644
index 0000000..d753d8b
--- /dev/null
+++ b/summerofcode/2016/siddharth_shukla.md
@@ -0,0 +1,65 @@
+Project Overview
+================
+The project, titled 'GRPC Python compatibility support', involved 
+collaborating with the GRPC team to improve the library compatibility 
+for the GRPC Python library.
+
+Python is, originally, a specification for a programming language. This
+specification has been implemented differently in different
+implementations of the [language specification](https://docs.python.org/3/reference/). 
+
+A small, and by no means exhaustive, list of some major python implementations
+is:
+
+- [CPython](https://www.python.org/): The reference implementation
+- [Jython](http://www.jython.org/): Python implemented in Java
+- [Python for .NET](http://pythonnet.sourceforge.net/): CPython implementation that enables .NET library usage
+- [IronPython](http://ironpython.net/): Python implemented in .NET
+- [PyPy](http://pypy.org/): Python implemented completely in Python
+- [Stackless](https://bitbucket.org/stackless-dev/stackless/wiki/Home): Replaces the dependency for the C call stack with it's own stack
+
+The development in this project revolved around
+introducing changes to the codebase that enable support for latest 
+stable as well as development releases of the reference implementation 
+(CPython) of the Python programming language namely `Python 3.4`,
+`Python 3.5`,and `Python 3.6` as well as the stable releases of the 
+PyPy implementation. Special changes were required to enable PyPy 
+support because PyPy has a non-deterministic garbage collector that does
+not rely on reference counting unlike the CPython garbage collector.
+
+The changes to the codebase involved changes to the library code as well
+as changes to the tests and scripts in the test infrastructure which
+resulted in both the library as well as the testing infrastructure being
+Python 3.x and PyPy compatible.
+
+The list of merged commits, as of 22.08.2016 23:59 CEST,  is summarized 
+here for the perusal of those interested:
+
+- [Enable py35 and py36 testing](https://github.com/grpc/grpc/commit/c478214e475e103c5cdf477f0adc18bba2c03903)
+- [Make testing toolchain python 3.x compliant](https://github.com/grpc/grpc/commit/0589e533cd65a2ca9e0e610cc1b284d016986572)
+- [Add .idea folder to .gitignore](https://github.com/grpc/grpc/commit/365ef40947e22b5438a63f123679ae9a5474c47c)
+- [Fix the ThreadPoolExecutor: max_workers can't be 0](https://github.com/grpc/grpc/commit/de84d566b8fad6808e5263a25a17fa231cb5713c)
+- [Add PyPy to testing toolchain](https://github.com/grpc/grpc/commit/2135a1b557f8b992186d5317cb767ac4dbcdfe5c)
+- [Switch init/shutdown: lib-wide -> per-object](https://github.com/grpc/grpc/commit/9eedb4ffd74aed8d246a07f8007960b2bc167f55)
+- [Skip test run if running with pypy](https://github.com/grpc/grpc/commit/f0f58e68738abbc317f7f449c5104f7fbbff26bd)
+
+The list of unmerged pull requests is as follows:
+
+- [Add PyPy 5.3.1 to dockerfile and template](https://github.com/grpc/grpc/pull/7763)
+- [remove skipIf from TypeSmokeTest (issue 7672)](https://github.com/grpc/grpc/pull/7831)
+  
+The list of tasks that have pending unsubmitted pull requests is as follows:
+
+- Modify run_tests.py to enable testing of new languages without
+  affecting old branches.
+
+
+Project Details
+===============
+- Title: GRPC Python compatibility support
+- Student: [Siddharth Shukla](https://github.com/thunderboltsid)
+- Mentors: [Nathaniel Manista](https://github.com/nathanielmanistaatgoogle), [Masood Malekghassemi](https://github.com/soltanmm)
+- Duration: May 23 - August 23
+- Hat tip: [Ken Payson](https://github.com/kpayson64), [Jan Tattermusch](https://github.com/jtattermusch), [Nicolas Noble](https://github.com/nicolasnoble)
+
+
diff --git a/templates/BUILD.template b/templates/BUILD.template
index 23a656c..af23fb2 100644
--- a/templates/BUILD.template
+++ b/templates/BUILD.template
@@ -38,6 +38,8 @@
   
   licenses(["notice"])  # 3-clause BSD
   
+  exports_files(["LICENSE"])
+  
   package(default_visibility = ["//visibility:public"])
   
   <%!
diff --git a/templates/Makefile.template b/templates/Makefile.template
index 6a7805c..e6a28d1 100644
--- a/templates/Makefile.template
+++ b/templates/Makefile.template
@@ -380,7 +380,7 @@
   OPENSSL_ALPN_CHECK_CMD = $(PKG_CONFIG) --atleast-version=1.0.2 openssl
   OPENSSL_NPN_CHECK_CMD = $(PKG_CONFIG) --atleast-version=1.0.1 openssl
   ZLIB_CHECK_CMD = $(PKG_CONFIG) --exists zlib
-  PROTOBUF_CHECK_CMD = $(PKG_CONFIG) --atleast-version=3.0.0-alpha-3 protobuf
+  PROTOBUF_CHECK_CMD = $(PKG_CONFIG) --atleast-version=3.0.0 protobuf
   else # HAS_PKG_CONFIG
 
   ifeq ($(SYSTEM),MINGW32)
diff --git a/templates/gRPC-Core.podspec.template b/templates/gRPC-Core.podspec.template
index 644dc4a..1d5a473 100644
--- a/templates/gRPC-Core.podspec.template
+++ b/templates/gRPC-Core.podspec.template
@@ -62,7 +62,7 @@
   %>
   Pod::Spec.new do |s|
     s.name     = 'gRPC-Core'
-    version = '1.0.0-pre1'
+    version = '1.0.0'
     s.version  = version
     s.summary  = 'Core cross-platform gRPC library, written in C'
     s.homepage = 'http://www.grpc.io'
@@ -71,7 +71,7 @@
 
     s.source = {
       :git => 'https://github.com/grpc/grpc.git',
-      :tag => "objective-c-v#{version}",
+      :tag => "v#{version}",
       # TODO(jcanizales): Depend explicitly on the nanopb pod, and disable submodules.
       :submodules => true,
     }
@@ -149,7 +149,7 @@
       ss.header_mappings_dir = '.'
       ss.libraries = 'z'
       ss.dependency "#{s.name}/Interface", version
-      ss.dependency 'BoringSSL', '~> 5.0'
+      ss.dependency 'BoringSSL', '~> 6.0'
 
       # To save you from scrolling, this is the last part of the podspec.
       ss.source_files = ${ruby_multiline_list(grpc_private_files(libs), 22)}
diff --git a/templates/package.xml.template b/templates/package.xml.template
index 43d3aa2..32ed3b6 100644
--- a/templates/package.xml.template
+++ b/templates/package.xml.template
@@ -12,7 +12,7 @@
     <email>grpc-packages@google.com</email>
     <active>yes</active>
    </lead>
-   <date>2016-08-09</date>
+   <date>2016-08-22</date>
    <time>16:06:07</time>
    <version>
     <release>${settings.php_version.php()}</release>
@@ -24,7 +24,7 @@
    </stability>
    <license>BSD</license>
    <notes>
-  - Fixed Ubuntu compile error #7571, #7642
+  - Reject metadata keys which are not legal #7881
    </notes>
    <contents>
     <dir baseinstalldir="/" name="/">
@@ -264,5 +264,35 @@
   - Fixed Ubuntu compile error #7571, #7642
      </notes>
     </release>
+    <release>
+     <version>
+      <release>1.0.0</release>
+      <api>1.0.0</api>
+     </version>
+     <stability>
+      <release>stable</release>
+      <api>stable</api>
+     </stability>
+     <date>2016-08-18</date>
+     <license>BSD</license>
+     <notes>
+  - gRPC 1.0.0 release
+     </notes>
+    </release>
+    <release>
+     <version>
+      <release>${settings.php_version.php()}</release>
+      <api>${settings.php_version.php()}</api>
+     </version>
+     <stability>
+      <release>stable</release>
+      <api>stable</api>
+     </stability>
+     <date>2016-08-22</date>
+     <license>BSD</license>
+     <notes>
+  - Reject metadata keys which are not legal #7881
+     </notes>
+    </release>
    </changelog>
   </package>
diff --git a/templates/src/core/lib/surface/version.c.template b/templates/src/core/lib/surface/version.c.template
index 5f0273e..12c490e 100644
--- a/templates/src/core/lib/surface/version.c.template
+++ b/templates/src/core/lib/surface/version.c.template
@@ -32,10 +32,12 @@
    * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
    *
    */
-  
+
   /* This file is autogenerated from:
      templates/src/core/surface/version.c.template */
-  
+
   #include <grpc/grpc.h>
-  
+
   const char *grpc_version_string(void) { return "${settings.core_version}"; }
+
+  const char *grpc_g_stands_for(void) { return "${settings.g_stands_for}"; }
diff --git a/templates/src/php/composer.json.template b/templates/src/php/composer.json.template
new file mode 100644
index 0000000..bf876f3
--- /dev/null
+++ b/templates/src/php/composer.json.template
@@ -0,0 +1,23 @@
+%YAML 1.2
+--- |
+  {
+    "name": "grpc/grpc",
+    "type": "library",
+    "description": "gRPC library for PHP",
+    "keywords": ["rpc"],
+    "homepage": "http://grpc.io",
+    "license": "BSD-3-Clause",
+    "version": "${settings.php_version.php_composer()}",
+    "require": {
+      "php": ">=5.5.0",
+      "stanley-cheung/protobuf-php": "v0.6"
+    },
+    "require-dev": {
+      "google/auth": "v0.9"
+    },
+    "autoload": {
+      "psr-4": {
+        "Grpc\\": "lib/Grpc/"
+      }
+    }
+  }
diff --git a/templates/tools/dockerfile/apt_get_pyenv.include b/templates/tools/dockerfile/apt_get_pyenv.include
index 70e9028..816b279 100644
--- a/templates/tools/dockerfile/apt_get_pyenv.include
+++ b/templates/tools/dockerfile/apt_get_pyenv.include
@@ -15,4 +15,5 @@
 RUN pyenv update
 RUN pyenv install 3.5-dev
 RUN pyenv install 3.6-dev
-RUN pyenv local 3.5-dev 3.6-dev
+RUN pyenv install pypy-5.3.1
+RUN pyenv local 3.5-dev 3.6-dev pypy-5.3.1
diff --git a/test/core/bad_client/tests/head_of_line_blocking.c b/test/core/bad_client/tests/head_of_line_blocking.c
index e4051bb..64cb79d 100644
--- a/test/core/bad_client/tests/head_of_line_blocking.c
+++ b/test/core/bad_client/tests/head_of_line_blocking.c
@@ -97,7 +97,7 @@
                                               &deadline, &request_metadata_recv,
                                               &payload, cq, cq, tag(101));
   GPR_ASSERT(GRPC_CALL_OK == error);
-  cq_expect_completion(cqv, tag(101), 1);
+  CQ_EXPECT_COMPLETION(cqv, tag(101), 1);
   cq_verify(cqv);
 
   GPR_ASSERT(payload != NULL);
diff --git a/test/core/bad_client/tests/large_metadata.c b/test/core/bad_client/tests/large_metadata.c
index ded5f17..b9c8093 100644
--- a/test/core/bad_client/tests/large_metadata.c
+++ b/test/core/bad_client/tests/large_metadata.c
@@ -50,6 +50,7 @@
   "\x00\x00\x00\x04\x00\x00\x00\x00\x00" /* headers: generated from        \
                                             large_metadata.headers in this \
                                             directory */                   \
+  "\x00\x00\x00\x04\x01\x00\x00\x00\x00"                                   \
   "\x00"                                                                   \
   "5{\x01\x05\x00\x00\x00\x01"                                             \
   "\x10\x05:path\x08/foo/bar"                                              \
@@ -92,6 +93,7 @@
                                                                     in this                \
                                                                     directory              \
                                                                     */                     \
+  "\x00\x00\x00\x04\x01\x00\x00\x00\x00"                                                   \
   "\x00\x00\xc9\x01\x04\x00\x00\x00\x01"                                                   \
   "\x10\x05:path\x08/foo/bar"                                                              \
   "\x10\x07:scheme\x04http"                                                                \
@@ -121,7 +123,7 @@
   error = grpc_server_request_call(server, &s, &call_details,
                                    &request_metadata_recv, cq, cq, tag(101));
   GPR_ASSERT(GRPC_CALL_OK == error);
-  cq_expect_completion(cqv, tag(101), 1);
+  CQ_EXPECT_COMPLETION(cqv, tag(101), 1);
   cq_verify(cqv);
 
   GPR_ASSERT(0 == strcmp(call_details.host, "localhost"));
@@ -148,7 +150,7 @@
   error = grpc_server_request_call(server, &s, &call_details,
                                    &request_metadata_recv, cq, cq, tag(101));
   GPR_ASSERT(GRPC_CALL_OK == error);
-  cq_expect_completion(cqv, tag(101), 1);
+  CQ_EXPECT_COMPLETION(cqv, tag(101), 1);
   cq_verify(cqv);
 
   GPR_ASSERT(0 == strcmp(call_details.host, "localhost"));
@@ -171,7 +173,7 @@
   op.reserved = NULL;
   error = grpc_call_start_batch(s, &op, 1, tag(102), NULL);
   GPR_ASSERT(GRPC_CALL_OK == error);
-  cq_expect_completion(cqv, tag(102), 0);  // Operation fails.
+  CQ_EXPECT_COMPLETION(cqv, tag(102), 0);  // Operation fails.
   cq_verify(cqv);
 
   gpr_free((char *)meta.value);
diff --git a/test/core/bad_client/tests/server_registered_method.c b/test/core/bad_client/tests/server_registered_method.c
index 6216553..e174af5 100644
--- a/test/core/bad_client/tests/server_registered_method.c
+++ b/test/core/bad_client/tests/server_registered_method.c
@@ -70,7 +70,7 @@
                                               &deadline, &request_metadata_recv,
                                               &payload, cq, cq, tag(101));
   GPR_ASSERT(GRPC_CALL_OK == error);
-  cq_expect_completion(cqv, tag(101), 1);
+  CQ_EXPECT_COMPLETION(cqv, tag(101), 1);
   cq_verify(cqv);
 
   GPR_ASSERT(payload != NULL);
@@ -96,7 +96,7 @@
                                               &deadline, &request_metadata_recv,
                                               &payload, cq, cq, tag(101));
   GPR_ASSERT(GRPC_CALL_OK == error);
-  cq_expect_completion(cqv, tag(101), 1);
+  CQ_EXPECT_COMPLETION(cqv, tag(101), 1);
   cq_verify(cqv);
 
   GPR_ASSERT(payload == NULL);
diff --git a/test/core/bad_client/tests/simple_request.c b/test/core/bad_client/tests/simple_request.c
index 25bbe96..c08aa40 100644
--- a/test/core/bad_client/tests/simple_request.c
+++ b/test/core/bad_client/tests/simple_request.c
@@ -114,7 +114,7 @@
   error = grpc_server_request_call(server, &s, &call_details,
                                    &request_metadata_recv, cq, cq, tag(101));
   GPR_ASSERT(GRPC_CALL_OK == error);
-  cq_expect_completion(cqv, tag(101), 1);
+  CQ_EXPECT_COMPLETION(cqv, tag(101), 1);
   cq_verify(cqv);
 
   GPR_ASSERT(0 == strcmp(call_details.host, "localhost"));
diff --git a/test/core/bad_ssl/bad_ssl_test.c b/test/core/bad_ssl/bad_ssl_test.c
index bb06ab0..c9cdb16 100644
--- a/test/core/bad_ssl/bad_ssl_test.c
+++ b/test/core/bad_ssl/bad_ssl_test.c
@@ -111,7 +111,7 @@
   error = grpc_call_start_batch(c, ops, nops, tag(1), NULL);
   GPR_ASSERT(GRPC_CALL_OK == error);
 
-  cq_expect_completion(cqv, tag(1), 1);
+  CQ_EXPECT_COMPLETION(cqv, tag(1), 1);
   cq_verify(cqv);
 
   GPR_ASSERT(status != GRPC_STATUS_OK);
diff --git a/test/core/client_config/lb_policies_test.c b/test/core/client_config/lb_policies_test.c
index 3160312..0b9648b 100644
--- a/test/core/client_config/lb_policies_test.c
+++ b/test/core/client_config/lb_policies_test.c
@@ -351,9 +351,9 @@
                                                        ops, (size_t)(op - ops),
                                                        tag(102), NULL));
 
-      cq_expect_completion(cqv, tag(102), 1);
+      CQ_EXPECT_COMPLETION(cqv, tag(102), 1);
       if (!completed_client) {
-        cq_expect_completion(cqv, tag(1), 1);
+        CQ_EXPECT_COMPLETION(cqv, tag(1), 1);
       }
       cq_verify(cqv);
 
@@ -376,7 +376,7 @@
     } else { /* no response from server */
       grpc_call_cancel(c, NULL);
       if (!completed_client) {
-        cq_expect_completion(cqv, tag(1), 1);
+        CQ_EXPECT_COMPLETION(cqv, tag(1), 1);
         cq_verify(cqv);
       }
     }
@@ -576,7 +576,7 @@
   client = create_client(f);
 
   grpc_channel_ping(client, f->cq, tag(0), NULL);
-  cq_expect_completion(cqv, tag(0), 0);
+  CQ_EXPECT_COMPLETION(cqv, tag(0), 0);
 
   /* check that we're still in idle, and start connecting */
   GPR_ASSERT(grpc_channel_check_connectivity_state(client, 1) ==
@@ -586,7 +586,7 @@
   while (state != GRPC_CHANNEL_READY) {
     grpc_channel_watch_connectivity_state(
         client, state, GRPC_TIMEOUT_SECONDS_TO_DEADLINE(3), f->cq, tag(99));
-    cq_expect_completion(cqv, tag(99), 1);
+    CQ_EXPECT_COMPLETION(cqv, tag(99), 1);
     cq_verify(cqv);
     state = grpc_channel_check_connectivity_state(client, 0);
     GPR_ASSERT(state == GRPC_CHANNEL_READY ||
@@ -596,7 +596,7 @@
 
   for (i = 1; i <= 5; i++) {
     grpc_channel_ping(client, f->cq, tag(i), NULL);
-    cq_expect_completion(cqv, tag(i), 1);
+    CQ_EXPECT_COMPLETION(cqv, tag(i), 1);
     cq_verify(cqv);
   }
   gpr_free(rdata.call_details);
diff --git a/test/core/client_config/resolvers/dns_resolver_connectivity_test.c b/test/core/client_config/resolvers/dns_resolver_connectivity_test.c
index 69c07d8..6a33525 100644
--- a/test/core/client_config/resolvers/dns_resolver_connectivity_test.c
+++ b/test/core/client_config/resolvers/dns_resolver_connectivity_test.c
@@ -127,26 +127,26 @@
 
   grpc_resolver *resolver = create_resolver("dns:test");
 
-  grpc_client_config *config = (grpc_client_config *)1;
+  grpc_resolver_result *result = (grpc_resolver_result *)1;
 
   grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
   gpr_event ev1;
   gpr_event_init(&ev1);
-  grpc_resolver_next(&exec_ctx, resolver, &config,
+  grpc_resolver_next(&exec_ctx, resolver, &result,
                      grpc_closure_create(on_done, &ev1));
   grpc_exec_ctx_flush(&exec_ctx);
   GPR_ASSERT(wait_loop(5, &ev1));
-  GPR_ASSERT(config == NULL);
+  GPR_ASSERT(result == NULL);
 
   gpr_event ev2;
   gpr_event_init(&ev2);
-  grpc_resolver_next(&exec_ctx, resolver, &config,
+  grpc_resolver_next(&exec_ctx, resolver, &result,
                      grpc_closure_create(on_done, &ev2));
   grpc_exec_ctx_flush(&exec_ctx);
   GPR_ASSERT(wait_loop(30, &ev2));
-  GPR_ASSERT(config != NULL);
+  GPR_ASSERT(result != NULL);
 
-  grpc_client_config_unref(&exec_ctx, config);
+  grpc_resolver_result_unref(&exec_ctx, result);
   GRPC_RESOLVER_UNREF(&exec_ctx, resolver, "test");
   grpc_exec_ctx_finish(&exec_ctx);
 
diff --git a/test/core/end2end/bad_server_response_test.c b/test/core/end2end/bad_server_response_test.c
index ab80adf..5ed0eb6 100644
--- a/test/core/end2end/bad_server_response_test.c
+++ b/test/core/end2end/bad_server_response_test.c
@@ -206,7 +206,7 @@
 
   GPR_ASSERT(GRPC_CALL_OK == error);
 
-  cq_expect_completion(cqv, tag(1), 1);
+  CQ_EXPECT_COMPLETION(cqv, tag(1), 1);
   cq_verify(cqv);
 
   gpr_log(GPR_DEBUG, "Rpc status: %d, details: %s", status, details);
diff --git a/test/core/end2end/cq_verifier.c b/test/core/end2end/cq_verifier.c
index b775680..1f42d34 100644
--- a/test/core/end2end/cq_verifier.c
+++ b/test/core/end2end/cq_verifier.c
@@ -61,7 +61,8 @@
    list to detail other expectations */
 typedef struct expectation {
   struct expectation *next;
-  struct expectation *prev;
+  const char *file;
+  int line;
   grpc_completion_type type;
   void *tag;
   int success;
@@ -71,17 +72,14 @@
 struct cq_verifier {
   /* bound completion queue */
   grpc_completion_queue *cq;
-  /* the root/sentinal expectation */
-  expectation expect;
+  /* start of expectation list */
+  expectation *first_expectation;
 };
 
 cq_verifier *cq_verifier_create(grpc_completion_queue *cq) {
   cq_verifier *v = gpr_malloc(sizeof(cq_verifier));
-  v->expect.type = ROOT_EXPECTATION;
-  v->expect.tag = NULL;
-  v->expect.next = &v->expect;
-  v->expect.prev = &v->expect;
   v->cq = cq;
+  v->first_expectation = NULL;
   return v;
 }
 
@@ -184,7 +182,8 @@
 
   switch (e->type) {
     case GRPC_OP_COMPLETE:
-      gpr_asprintf(&tmp, "GRPC_OP_COMPLETE result=%d", e->success);
+      gpr_asprintf(&tmp, "GRPC_OP_COMPLETE result=%d %s:%d", e->success,
+                   e->file, e->line);
       gpr_strvec_add(buf, tmp);
       break;
     case GRPC_QUEUE_TIMEOUT:
@@ -198,7 +197,7 @@
 static void expectations_to_strvec(gpr_strvec *buf, cq_verifier *v) {
   expectation *e;
 
-  for (e = v->expect.next; e != &v->expect; e = e->next) {
+  for (e = v->first_expectation; e != NULL; e = e->next) {
     expectation_to_strvec(buf, e);
     gpr_strvec_add(buf, gpr_strdup("\n"));
   }
@@ -218,45 +217,39 @@
 }
 
 void cq_verify(cq_verifier *v) {
-  gpr_timespec deadline = GRPC_TIMEOUT_SECONDS_TO_DEADLINE(10);
-  grpc_event ev;
-  expectation *e;
-  char *s;
-  gpr_strvec have_tags;
-
-  gpr_strvec_init(&have_tags);
-
-  while (v->expect.next != &v->expect) {
-    ev = grpc_completion_queue_next(v->cq, deadline, NULL);
+  const gpr_timespec deadline = GRPC_TIMEOUT_SECONDS_TO_DEADLINE(10);
+  while (v->first_expectation != NULL) {
+    grpc_event ev = grpc_completion_queue_next(v->cq, deadline, NULL);
     if (ev.type == GRPC_QUEUE_TIMEOUT) {
       fail_no_event_received(v);
       break;
     }
-
-    for (e = v->expect.next; e != &v->expect; e = e->next) {
-      gpr_asprintf(&s, " %p", e->tag);
-      gpr_strvec_add(&have_tags, s);
+    expectation *e;
+    expectation *prev = NULL;
+    for (e = v->first_expectation; e != NULL; e = e->next) {
       if (e->tag == ev.tag) {
         verify_matches(e, &ev);
-        e->next->prev = e->prev;
-        e->prev->next = e->next;
+        if (e == v->first_expectation) v->first_expectation = e->next;
+        if (prev != NULL) prev->next = e->next;
         gpr_free(e);
         break;
       }
+      prev = e;
     }
-    if (e == &v->expect) {
-      s = grpc_event_string(&ev);
-      gpr_log(GPR_ERROR, "event not found: %s", s);
+    if (e == NULL) {
+      char *s = grpc_event_string(&ev);
+      gpr_log(GPR_ERROR, "cq returned unexpected event: %s", s);
       gpr_free(s);
-      s = gpr_strvec_flatten(&have_tags, NULL);
-      gpr_log(GPR_ERROR, "have tags:%s", s);
+      gpr_strvec expectations;
+      gpr_strvec_init(&expectations);
+      expectations_to_strvec(&expectations, v);
+      s = gpr_strvec_flatten(&expectations, NULL);
+      gpr_strvec_destroy(&expectations);
+      gpr_log(GPR_ERROR, "expected tags:\n%s", s);
       gpr_free(s);
-      gpr_strvec_destroy(&have_tags);
       abort();
     }
   }
-
-  gpr_strvec_destroy(&have_tags);
 }
 
 void cq_verify_empty_timeout(cq_verifier *v, int timeout_sec) {
@@ -265,7 +258,7 @@
                    gpr_time_from_seconds(timeout_sec, GPR_TIMESPAN));
   grpc_event ev;
 
-  GPR_ASSERT(v->expect.next == &v->expect && "expectation queue must be empty");
+  GPR_ASSERT(v->first_expectation == NULL && "expectation queue must be empty");
 
   ev = grpc_completion_queue_next(v->cq, deadline, NULL);
   if (ev.type != GRPC_QUEUE_TIMEOUT) {
@@ -278,16 +271,19 @@
 
 void cq_verify_empty(cq_verifier *v) { cq_verify_empty_timeout(v, 1); }
 
-static expectation *add(cq_verifier *v, grpc_completion_type type, void *tag) {
+static void add(cq_verifier *v, const char *file, int line,
+                grpc_completion_type type, void *tag, bool success) {
   expectation *e = gpr_malloc(sizeof(expectation));
   e->type = type;
+  e->file = file;
+  e->line = line;
   e->tag = tag;
-  e->next = &v->expect;
-  e->prev = e->next->prev;
-  e->next->prev = e->prev->next = e;
-  return e;
+  e->success = success;
+  e->next = v->first_expectation;
+  v->first_expectation = e;
 }
 
-void cq_expect_completion(cq_verifier *v, void *tag, bool success) {
-  add(v, GRPC_OP_COMPLETE, tag)->success = success;
+void cq_expect_completion(cq_verifier *v, const char *file, int line, void *tag,
+                          bool success) {
+  add(v, file, line, GRPC_OP_COMPLETE, tag, success);
 }
diff --git a/test/core/end2end/cq_verifier.h b/test/core/end2end/cq_verifier.h
index bf82468..0a7c03c 100644
--- a/test/core/end2end/cq_verifier.h
+++ b/test/core/end2end/cq_verifier.h
@@ -62,7 +62,10 @@
    Any functions taking ... expect a NULL terminated list of key/value pairs
    (each pair using two parameter slots) of metadata that MUST be present in
    the event. */
-void cq_expect_completion(cq_verifier *v, void *tag, bool success);
+void cq_expect_completion(cq_verifier *v, const char *file, int line, void *tag,
+                          bool success);
+#define CQ_EXPECT_COMPLETION(v, tag, success) \
+  cq_expect_completion(v, __FILE__, __LINE__, tag, success)
 
 int byte_buffer_eq_string(grpc_byte_buffer *byte_buffer, const char *string);
 int contains_metadata(grpc_metadata_array *array, const char *key,
diff --git a/test/core/end2end/dualstack_socket_test.c b/test/core/end2end/dualstack_socket_test.c
index 348b9ed..8abb81c 100644
--- a/test/core/end2end/dualstack_socket_test.c
+++ b/test/core/end2end/dualstack_socket_test.c
@@ -199,7 +199,7 @@
     error = grpc_server_request_call(server, &s, &call_details,
                                      &request_metadata_recv, cq, cq, tag(101));
     GPR_ASSERT(GRPC_CALL_OK == error);
-    cq_expect_completion(cqv, tag(101), 1);
+    CQ_EXPECT_COMPLETION(cqv, tag(101), 1);
     cq_verify(cqv);
 
     memset(ops, 0, sizeof(ops));
@@ -221,8 +221,8 @@
     error = grpc_call_start_batch(s, ops, (size_t)(op - ops), tag(102), NULL);
     GPR_ASSERT(GRPC_CALL_OK == error);
 
-    cq_expect_completion(cqv, tag(102), 1);
-    cq_expect_completion(cqv, tag(1), 1);
+    CQ_EXPECT_COMPLETION(cqv, tag(102), 1);
+    CQ_EXPECT_COMPLETION(cqv, tag(1), 1);
     cq_verify(cqv);
 
     peer = grpc_call_get_peer(c);
@@ -238,7 +238,7 @@
     grpc_call_destroy(s);
   } else {
     /* Check for a failed connection. */
-    cq_expect_completion(cqv, tag(1), 1);
+    CQ_EXPECT_COMPLETION(cqv, tag(1), 1);
     cq_verify(cqv);
 
     GPR_ASSERT(status == GRPC_STATUS_UNAVAILABLE);
diff --git a/test/core/end2end/end2end_nosec_tests.c b/test/core/end2end/end2end_nosec_tests.c
index 3efd18c..2e8da05 100644
--- a/test/core/end2end/end2end_nosec_tests.c
+++ b/test/core/end2end/end2end_nosec_tests.c
@@ -95,6 +95,8 @@
 extern void negative_deadline_pre_init(void);
 extern void network_status_change(grpc_end2end_test_config config);
 extern void network_status_change_pre_init(void);
+extern void no_logging(grpc_end2end_test_config config);
+extern void no_logging_pre_init(void);
 extern void no_op(grpc_end2end_test_config config);
 extern void no_op_pre_init(void);
 extern void payload(grpc_end2end_test_config config);
@@ -155,6 +157,7 @@
   max_message_length_pre_init();
   negative_deadline_pre_init();
   network_status_change_pre_init();
+  no_logging_pre_init();
   no_op_pre_init();
   payload_pre_init();
   ping_pre_init();
@@ -205,6 +208,7 @@
     max_message_length(config);
     negative_deadline(config);
     network_status_change(config);
+    no_logging(config);
     no_op(config);
     payload(config);
     ping(config);
@@ -328,6 +332,10 @@
       network_status_change(config);
       continue;
     }
+    if (0 == strcmp("no_logging", argv[i])) {
+      no_logging(config);
+      continue;
+    }
     if (0 == strcmp("no_op", argv[i])) {
       no_op(config);
       continue;
diff --git a/test/core/end2end/end2end_tests.c b/test/core/end2end/end2end_tests.c
index e3d791a..22a914e 100644
--- a/test/core/end2end/end2end_tests.c
+++ b/test/core/end2end/end2end_tests.c
@@ -97,6 +97,8 @@
 extern void negative_deadline_pre_init(void);
 extern void network_status_change(grpc_end2end_test_config config);
 extern void network_status_change_pre_init(void);
+extern void no_logging(grpc_end2end_test_config config);
+extern void no_logging_pre_init(void);
 extern void no_op(grpc_end2end_test_config config);
 extern void no_op_pre_init(void);
 extern void payload(grpc_end2end_test_config config);
@@ -158,6 +160,7 @@
   max_message_length_pre_init();
   negative_deadline_pre_init();
   network_status_change_pre_init();
+  no_logging_pre_init();
   no_op_pre_init();
   payload_pre_init();
   ping_pre_init();
@@ -209,6 +212,7 @@
     max_message_length(config);
     negative_deadline(config);
     network_status_change(config);
+    no_logging(config);
     no_op(config);
     payload(config);
     ping(config);
@@ -336,6 +340,10 @@
       network_status_change(config);
       continue;
     }
+    if (0 == strcmp("no_logging", argv[i])) {
+      no_logging(config);
+      continue;
+    }
     if (0 == strcmp("no_op", argv[i])) {
       no_op(config);
       continue;
diff --git a/test/core/end2end/fixtures/h2_ssl_cert.c b/test/core/end2end/fixtures/h2_ssl_cert.c
index b476bf5..ae2604d 100644
--- a/test/core/end2end/fixtures/h2_ssl_cert.c
+++ b/test/core/end2end/fixtures/h2_ssl_cert.c
@@ -331,7 +331,7 @@
   error = grpc_call_start_batch(c, ops, (size_t)(op - ops), tag(1), NULL);
   GPR_ASSERT(GRPC_CALL_OK == error);
 
-  cq_expect_completion(cqv, tag(1), expected_result == SUCCESS);
+  CQ_EXPECT_COMPLETION(cqv, tag(1), expected_result == SUCCESS);
   cq_verify(cqv);
 
   grpc_call_destroy(c);
diff --git a/test/core/end2end/fuzzers/client_fuzzer_corpus/0083d5addbeca55271ed7ef93c8016bf7ca76903 b/test/core/end2end/fuzzers/client_fuzzer_corpus/0083d5addbeca55271ed7ef93c8016bf7ca76903
new file mode 100644
index 0000000..821d85d
--- /dev/null
+++ b/test/core/end2end/fuzzers/client_fuzzer_corpus/0083d5addbeca55271ed7ef93c8016bf7ca76903
Binary files differ
diff --git a/test/core/end2end/fuzzers/client_fuzzer_corpus/07b0bed3226eefac4a84000ec584e4ce06ebf1bf b/test/core/end2end/fuzzers/client_fuzzer_corpus/07b0bed3226eefac4a84000ec584e4ce06ebf1bf
new file mode 100644
index 0000000..8ba8dfa
--- /dev/null
+++ b/test/core/end2end/fuzzers/client_fuzzer_corpus/07b0bed3226eefac4a84000ec584e4ce06ebf1bf
Binary files differ
diff --git a/test/core/end2end/fuzzers/client_fuzzer_corpus/07cec5c8d9c856a910c6fb57da2ae954f44beed0 b/test/core/end2end/fuzzers/client_fuzzer_corpus/07cec5c8d9c856a910c6fb57da2ae954f44beed0
new file mode 100644
index 0000000..28c9554
--- /dev/null
+++ b/test/core/end2end/fuzzers/client_fuzzer_corpus/07cec5c8d9c856a910c6fb57da2ae954f44beed0
Binary files differ
diff --git a/test/core/end2end/fuzzers/client_fuzzer_corpus/0c27c9999302b39bf2256a90b0cdb767fb2b6fe3 b/test/core/end2end/fuzzers/client_fuzzer_corpus/0c27c9999302b39bf2256a90b0cdb767fb2b6fe3
new file mode 100644
index 0000000..a3ecb27
--- /dev/null
+++ b/test/core/end2end/fuzzers/client_fuzzer_corpus/0c27c9999302b39bf2256a90b0cdb767fb2b6fe3
Binary files differ
diff --git a/test/core/end2end/fuzzers/client_fuzzer_corpus/0d407f099f8418de3dd94bd2146c858a8c6575ad b/test/core/end2end/fuzzers/client_fuzzer_corpus/0d407f099f8418de3dd94bd2146c858a8c6575ad
new file mode 100644
index 0000000..ad20f50
--- /dev/null
+++ b/test/core/end2end/fuzzers/client_fuzzer_corpus/0d407f099f8418de3dd94bd2146c858a8c6575ad
Binary files differ
diff --git a/test/core/end2end/fuzzers/client_fuzzer_corpus/0d4d486aa9fd6e9c10cc9ca8967e922cadddb2fe b/test/core/end2end/fuzzers/client_fuzzer_corpus/0d4d486aa9fd6e9c10cc9ca8967e922cadddb2fe
new file mode 100644
index 0000000..fa6d96d
--- /dev/null
+++ b/test/core/end2end/fuzzers/client_fuzzer_corpus/0d4d486aa9fd6e9c10cc9ca8967e922cadddb2fe
Binary files differ
diff --git a/test/core/end2end/fuzzers/client_fuzzer_corpus/0d9ba07b57eb0e076b187c4455f662db085e730b b/test/core/end2end/fuzzers/client_fuzzer_corpus/0d9ba07b57eb0e076b187c4455f662db085e730b
new file mode 100644
index 0000000..bf6ec61
--- /dev/null
+++ b/test/core/end2end/fuzzers/client_fuzzer_corpus/0d9ba07b57eb0e076b187c4455f662db085e730b
Binary files differ
diff --git a/test/core/end2end/fuzzers/client_fuzzer_corpus/0f6b989cec08ef9da603dc83704d85900bd22f1f b/test/core/end2end/fuzzers/client_fuzzer_corpus/0f6b989cec08ef9da603dc83704d85900bd22f1f
new file mode 100644
index 0000000..6469f3c
--- /dev/null
+++ b/test/core/end2end/fuzzers/client_fuzzer_corpus/0f6b989cec08ef9da603dc83704d85900bd22f1f
Binary files differ
diff --git a/test/core/end2end/fuzzers/client_fuzzer_corpus/10b25b0726cb6d820165699e5a453691c7a9c343 b/test/core/end2end/fuzzers/client_fuzzer_corpus/10b25b0726cb6d820165699e5a453691c7a9c343
new file mode 100644
index 0000000..bda05de
--- /dev/null
+++ b/test/core/end2end/fuzzers/client_fuzzer_corpus/10b25b0726cb6d820165699e5a453691c7a9c343
Binary files differ
diff --git a/test/core/end2end/fuzzers/client_fuzzer_corpus/1231c6d007d9e43d169122348363e20d9f25ee93 b/test/core/end2end/fuzzers/client_fuzzer_corpus/1231c6d007d9e43d169122348363e20d9f25ee93
new file mode 100644
index 0000000..ed848cb
--- /dev/null
+++ b/test/core/end2end/fuzzers/client_fuzzer_corpus/1231c6d007d9e43d169122348363e20d9f25ee93
Binary files differ
diff --git a/test/core/end2end/fuzzers/client_fuzzer_corpus/13a9b61e431c20734c19bb36d85883b6a501284e b/test/core/end2end/fuzzers/client_fuzzer_corpus/13a9b61e431c20734c19bb36d85883b6a501284e
new file mode 100644
index 0000000..462273d
--- /dev/null
+++ b/test/core/end2end/fuzzers/client_fuzzer_corpus/13a9b61e431c20734c19bb36d85883b6a501284e
Binary files differ
diff --git a/test/core/end2end/fuzzers/client_fuzzer_corpus/1698ec182fad9d973b84615da3a683ecdf2d0b3b b/test/core/end2end/fuzzers/client_fuzzer_corpus/1698ec182fad9d973b84615da3a683ecdf2d0b3b
new file mode 100644
index 0000000..0c2710f
--- /dev/null
+++ b/test/core/end2end/fuzzers/client_fuzzer_corpus/1698ec182fad9d973b84615da3a683ecdf2d0b3b
Binary files differ
diff --git a/test/core/end2end/fuzzers/client_fuzzer_corpus/1859e2ee759e20fe195f67615a1576ce2b7d5bbd b/test/core/end2end/fuzzers/client_fuzzer_corpus/1859e2ee759e20fe195f67615a1576ce2b7d5bbd
new file mode 100644
index 0000000..ed91baf
--- /dev/null
+++ b/test/core/end2end/fuzzers/client_fuzzer_corpus/1859e2ee759e20fe195f67615a1576ce2b7d5bbd
Binary files differ
diff --git a/test/core/end2end/fuzzers/client_fuzzer_corpus/1a9017db5ad8a9dc6cfe72305da1683a87a73452 b/test/core/end2end/fuzzers/client_fuzzer_corpus/1a9017db5ad8a9dc6cfe72305da1683a87a73452
new file mode 100644
index 0000000..85d4be1
--- /dev/null
+++ b/test/core/end2end/fuzzers/client_fuzzer_corpus/1a9017db5ad8a9dc6cfe72305da1683a87a73452
Binary files differ
diff --git a/test/core/end2end/fuzzers/client_fuzzer_corpus/1bd90335afc9e0a1e6a9296e3cc27c03c1201886 b/test/core/end2end/fuzzers/client_fuzzer_corpus/1bd90335afc9e0a1e6a9296e3cc27c03c1201886
new file mode 100644
index 0000000..f020c9b
--- /dev/null
+++ b/test/core/end2end/fuzzers/client_fuzzer_corpus/1bd90335afc9e0a1e6a9296e3cc27c03c1201886
Binary files differ
diff --git a/test/core/end2end/fuzzers/client_fuzzer_corpus/1be157b0fc79f0e7e1e05dfa3cbbe1ad71528bc2 b/test/core/end2end/fuzzers/client_fuzzer_corpus/1be157b0fc79f0e7e1e05dfa3cbbe1ad71528bc2
new file mode 100644
index 0000000..ce32d23
--- /dev/null
+++ b/test/core/end2end/fuzzers/client_fuzzer_corpus/1be157b0fc79f0e7e1e05dfa3cbbe1ad71528bc2
Binary files differ
diff --git a/test/core/end2end/fuzzers/client_fuzzer_corpus/2185f411bdb1edc610f16ffc86836ae366193e03 b/test/core/end2end/fuzzers/client_fuzzer_corpus/2185f411bdb1edc610f16ffc86836ae366193e03
new file mode 100644
index 0000000..0516cfa
--- /dev/null
+++ b/test/core/end2end/fuzzers/client_fuzzer_corpus/2185f411bdb1edc610f16ffc86836ae366193e03
Binary files differ
diff --git a/test/core/end2end/fuzzers/client_fuzzer_corpus/22661803bd1c7198df4be6e08924ef6a48af9cd4 b/test/core/end2end/fuzzers/client_fuzzer_corpus/22661803bd1c7198df4be6e08924ef6a48af9cd4
new file mode 100644
index 0000000..2443c3b
--- /dev/null
+++ b/test/core/end2end/fuzzers/client_fuzzer_corpus/22661803bd1c7198df4be6e08924ef6a48af9cd4
Binary files differ
diff --git a/test/core/end2end/fuzzers/client_fuzzer_corpus/2717067bbc0e9bfc1d90d15cddf6154800a25ec6 b/test/core/end2end/fuzzers/client_fuzzer_corpus/2717067bbc0e9bfc1d90d15cddf6154800a25ec6
new file mode 100644
index 0000000..d0fe18d
--- /dev/null
+++ b/test/core/end2end/fuzzers/client_fuzzer_corpus/2717067bbc0e9bfc1d90d15cddf6154800a25ec6
Binary files differ
diff --git a/test/core/end2end/fuzzers/client_fuzzer_corpus/2825cfc19c9371f4fe70851283c68d49470d4d55 b/test/core/end2end/fuzzers/client_fuzzer_corpus/2825cfc19c9371f4fe70851283c68d49470d4d55
new file mode 100644
index 0000000..e1e52b9
--- /dev/null
+++ b/test/core/end2end/fuzzers/client_fuzzer_corpus/2825cfc19c9371f4fe70851283c68d49470d4d55
Binary files differ
diff --git a/test/core/end2end/fuzzers/client_fuzzer_corpus/29303c16f3afa18c2c0b84e77e587535a705a74c b/test/core/end2end/fuzzers/client_fuzzer_corpus/29303c16f3afa18c2c0b84e77e587535a705a74c
new file mode 100644
index 0000000..b684106
--- /dev/null
+++ b/test/core/end2end/fuzzers/client_fuzzer_corpus/29303c16f3afa18c2c0b84e77e587535a705a74c
Binary files differ
diff --git a/test/core/end2end/fuzzers/client_fuzzer_corpus/2b5eb5aac77af905877bd98ec2c4d746b247abb6 b/test/core/end2end/fuzzers/client_fuzzer_corpus/2b5eb5aac77af905877bd98ec2c4d746b247abb6
new file mode 100644
index 0000000..76655ea
--- /dev/null
+++ b/test/core/end2end/fuzzers/client_fuzzer_corpus/2b5eb5aac77af905877bd98ec2c4d746b247abb6
Binary files differ
diff --git a/test/core/end2end/fuzzers/client_fuzzer_corpus/2cc43573f271ecd332551c1fb34ebc8645eaefe8 b/test/core/end2end/fuzzers/client_fuzzer_corpus/2cc43573f271ecd332551c1fb34ebc8645eaefe8
new file mode 100644
index 0000000..25ead66
--- /dev/null
+++ b/test/core/end2end/fuzzers/client_fuzzer_corpus/2cc43573f271ecd332551c1fb34ebc8645eaefe8
Binary files differ
diff --git a/test/core/end2end/fuzzers/client_fuzzer_corpus/2feb41037f5dd34e9f3465a2fbf1a6d355c8ce9d b/test/core/end2end/fuzzers/client_fuzzer_corpus/2feb41037f5dd34e9f3465a2fbf1a6d355c8ce9d
new file mode 100644
index 0000000..9614683
--- /dev/null
+++ b/test/core/end2end/fuzzers/client_fuzzer_corpus/2feb41037f5dd34e9f3465a2fbf1a6d355c8ce9d
Binary files differ
diff --git a/test/core/end2end/fuzzers/client_fuzzer_corpus/300998021c7f743ff49d9cc192343ffd43eb47f2 b/test/core/end2end/fuzzers/client_fuzzer_corpus/300998021c7f743ff49d9cc192343ffd43eb47f2
new file mode 100644
index 0000000..a327645
--- /dev/null
+++ b/test/core/end2end/fuzzers/client_fuzzer_corpus/300998021c7f743ff49d9cc192343ffd43eb47f2
Binary files differ
diff --git a/test/core/end2end/fuzzers/client_fuzzer_corpus/310b2aff5e2ec78b6004630bed39d49f8d13bb21 b/test/core/end2end/fuzzers/client_fuzzer_corpus/310b2aff5e2ec78b6004630bed39d49f8d13bb21
new file mode 100644
index 0000000..e48ee01
--- /dev/null
+++ b/test/core/end2end/fuzzers/client_fuzzer_corpus/310b2aff5e2ec78b6004630bed39d49f8d13bb21
Binary files differ
diff --git a/test/core/end2end/fuzzers/client_fuzzer_corpus/3bb052abecc1b916cc869b9aad29c9dd55a95068 b/test/core/end2end/fuzzers/client_fuzzer_corpus/3bb052abecc1b916cc869b9aad29c9dd55a95068
new file mode 100644
index 0000000..e256230
--- /dev/null
+++ b/test/core/end2end/fuzzers/client_fuzzer_corpus/3bb052abecc1b916cc869b9aad29c9dd55a95068
Binary files differ
diff --git a/test/core/end2end/fuzzers/client_fuzzer_corpus/3c5fa483ebfabe6e684831ce7c413176bc998c33 b/test/core/end2end/fuzzers/client_fuzzer_corpus/3c5fa483ebfabe6e684831ce7c413176bc998c33
new file mode 100644
index 0000000..82c60ba
--- /dev/null
+++ b/test/core/end2end/fuzzers/client_fuzzer_corpus/3c5fa483ebfabe6e684831ce7c413176bc998c33
Binary files differ
diff --git a/test/core/end2end/fuzzers/client_fuzzer_corpus/3c6444b64ace5cd6c145614ad4412382271a6120 b/test/core/end2end/fuzzers/client_fuzzer_corpus/3c6444b64ace5cd6c145614ad4412382271a6120
new file mode 100644
index 0000000..a829aad
--- /dev/null
+++ b/test/core/end2end/fuzzers/client_fuzzer_corpus/3c6444b64ace5cd6c145614ad4412382271a6120
Binary files differ
diff --git a/test/core/end2end/fuzzers/client_fuzzer_corpus/4045d25f065bb1d70a8b9c3751f7453d4b0625b9 b/test/core/end2end/fuzzers/client_fuzzer_corpus/4045d25f065bb1d70a8b9c3751f7453d4b0625b9
new file mode 100644
index 0000000..d3d6384
--- /dev/null
+++ b/test/core/end2end/fuzzers/client_fuzzer_corpus/4045d25f065bb1d70a8b9c3751f7453d4b0625b9
Binary files differ
diff --git a/test/core/end2end/fuzzers/client_fuzzer_corpus/407cedf992b14edac6e19f7d440ab73c88e72465 b/test/core/end2end/fuzzers/client_fuzzer_corpus/407cedf992b14edac6e19f7d440ab73c88e72465
new file mode 100644
index 0000000..151a983
--- /dev/null
+++ b/test/core/end2end/fuzzers/client_fuzzer_corpus/407cedf992b14edac6e19f7d440ab73c88e72465
Binary files differ
diff --git a/test/core/end2end/fuzzers/client_fuzzer_corpus/411966ea7d9164fc432eeab55a55248ad808bb01 b/test/core/end2end/fuzzers/client_fuzzer_corpus/411966ea7d9164fc432eeab55a55248ad808bb01
new file mode 100644
index 0000000..b60637b
--- /dev/null
+++ b/test/core/end2end/fuzzers/client_fuzzer_corpus/411966ea7d9164fc432eeab55a55248ad808bb01
Binary files differ
diff --git a/test/core/end2end/fuzzers/client_fuzzer_corpus/415dde26637ed3c0e803111c532a1a9ea9c49092 b/test/core/end2end/fuzzers/client_fuzzer_corpus/415dde26637ed3c0e803111c532a1a9ea9c49092
new file mode 100644
index 0000000..2d8b9cf
--- /dev/null
+++ b/test/core/end2end/fuzzers/client_fuzzer_corpus/415dde26637ed3c0e803111c532a1a9ea9c49092
Binary files differ
diff --git a/test/core/end2end/fuzzers/client_fuzzer_corpus/4fc34239f220392581520aa8cebc659daa65a7a6 b/test/core/end2end/fuzzers/client_fuzzer_corpus/4fc34239f220392581520aa8cebc659daa65a7a6
new file mode 100644
index 0000000..1ca1c28
--- /dev/null
+++ b/test/core/end2end/fuzzers/client_fuzzer_corpus/4fc34239f220392581520aa8cebc659daa65a7a6
Binary files differ
diff --git a/test/core/end2end/fuzzers/client_fuzzer_corpus/52939682304314f04897deddfbc9c7afa8ee50a9 b/test/core/end2end/fuzzers/client_fuzzer_corpus/52939682304314f04897deddfbc9c7afa8ee50a9
new file mode 100644
index 0000000..27c5ca4
--- /dev/null
+++ b/test/core/end2end/fuzzers/client_fuzzer_corpus/52939682304314f04897deddfbc9c7afa8ee50a9
Binary files differ
diff --git a/test/core/end2end/fuzzers/client_fuzzer_corpus/5369926a559827d08bccf264876d592c7cae660d b/test/core/end2end/fuzzers/client_fuzzer_corpus/5369926a559827d08bccf264876d592c7cae660d
new file mode 100644
index 0000000..9a2c59f
--- /dev/null
+++ b/test/core/end2end/fuzzers/client_fuzzer_corpus/5369926a559827d08bccf264876d592c7cae660d
Binary files differ
diff --git a/test/core/end2end/fuzzers/client_fuzzer_corpus/53ef530f65b0cff2e338a51b469c224f53b628d7 b/test/core/end2end/fuzzers/client_fuzzer_corpus/53ef530f65b0cff2e338a51b469c224f53b628d7
new file mode 100644
index 0000000..cd12901
--- /dev/null
+++ b/test/core/end2end/fuzzers/client_fuzzer_corpus/53ef530f65b0cff2e338a51b469c224f53b628d7
Binary files differ
diff --git a/test/core/end2end/fuzzers/client_fuzzer_corpus/560c1057487e6b0d2d457748c3ad8434423eb263 b/test/core/end2end/fuzzers/client_fuzzer_corpus/560c1057487e6b0d2d457748c3ad8434423eb263
new file mode 100644
index 0000000..889056f
--- /dev/null
+++ b/test/core/end2end/fuzzers/client_fuzzer_corpus/560c1057487e6b0d2d457748c3ad8434423eb263
Binary files differ
diff --git a/test/core/end2end/fuzzers/client_fuzzer_corpus/564f203f678fb333c7b1f8f4df79237589ce346d b/test/core/end2end/fuzzers/client_fuzzer_corpus/564f203f678fb333c7b1f8f4df79237589ce346d
new file mode 100644
index 0000000..d64ca59
--- /dev/null
+++ b/test/core/end2end/fuzzers/client_fuzzer_corpus/564f203f678fb333c7b1f8f4df79237589ce346d
Binary files differ
diff --git a/test/core/end2end/fuzzers/client_fuzzer_corpus/56b0ac0636c57838f63415082b3ae2ec7a93f017 b/test/core/end2end/fuzzers/client_fuzzer_corpus/56b0ac0636c57838f63415082b3ae2ec7a93f017
new file mode 100644
index 0000000..f997ced
--- /dev/null
+++ b/test/core/end2end/fuzzers/client_fuzzer_corpus/56b0ac0636c57838f63415082b3ae2ec7a93f017
Binary files differ
diff --git a/test/core/end2end/fuzzers/client_fuzzer_corpus/58bcbd601894835bb3312d2a0bc56f2e0f65984c b/test/core/end2end/fuzzers/client_fuzzer_corpus/58bcbd601894835bb3312d2a0bc56f2e0f65984c
new file mode 100644
index 0000000..016a98e
--- /dev/null
+++ b/test/core/end2end/fuzzers/client_fuzzer_corpus/58bcbd601894835bb3312d2a0bc56f2e0f65984c
Binary files differ
diff --git a/test/core/end2end/fuzzers/client_fuzzer_corpus/598d346f284bcff26d1de997c4ba5c4794c90b68 b/test/core/end2end/fuzzers/client_fuzzer_corpus/598d346f284bcff26d1de997c4ba5c4794c90b68
new file mode 100644
index 0000000..1230998
--- /dev/null
+++ b/test/core/end2end/fuzzers/client_fuzzer_corpus/598d346f284bcff26d1de997c4ba5c4794c90b68
Binary files differ
diff --git a/test/core/end2end/fuzzers/client_fuzzer_corpus/5c14b48da74ab06b3cc20c4fe355e24f7dd7852a b/test/core/end2end/fuzzers/client_fuzzer_corpus/5c14b48da74ab06b3cc20c4fe355e24f7dd7852a
new file mode 100644
index 0000000..c0223af
--- /dev/null
+++ b/test/core/end2end/fuzzers/client_fuzzer_corpus/5c14b48da74ab06b3cc20c4fe355e24f7dd7852a
Binary files differ
diff --git a/test/core/end2end/fuzzers/client_fuzzer_corpus/5de72e607205dc17a45df703ec4e9b63c36821ec b/test/core/end2end/fuzzers/client_fuzzer_corpus/5de72e607205dc17a45df703ec4e9b63c36821ec
new file mode 100644
index 0000000..6f50853
--- /dev/null
+++ b/test/core/end2end/fuzzers/client_fuzzer_corpus/5de72e607205dc17a45df703ec4e9b63c36821ec
Binary files differ
diff --git a/test/core/end2end/fuzzers/client_fuzzer_corpus/5e25cf639ba8ea37543d944f5efa94824c6272ff b/test/core/end2end/fuzzers/client_fuzzer_corpus/5e25cf639ba8ea37543d944f5efa94824c6272ff
new file mode 100644
index 0000000..33b465f
--- /dev/null
+++ b/test/core/end2end/fuzzers/client_fuzzer_corpus/5e25cf639ba8ea37543d944f5efa94824c6272ff
Binary files differ
diff --git a/test/core/end2end/fuzzers/client_fuzzer_corpus/5f247d7b6753f7a8798cf952f49f303c532e017c b/test/core/end2end/fuzzers/client_fuzzer_corpus/5f247d7b6753f7a8798cf952f49f303c532e017c
new file mode 100644
index 0000000..922c3cc
--- /dev/null
+++ b/test/core/end2end/fuzzers/client_fuzzer_corpus/5f247d7b6753f7a8798cf952f49f303c532e017c
Binary files differ
diff --git a/test/core/end2end/fuzzers/client_fuzzer_corpus/63a1cb41d219394c9bab947202921506f3574ad0 b/test/core/end2end/fuzzers/client_fuzzer_corpus/63a1cb41d219394c9bab947202921506f3574ad0
new file mode 100644
index 0000000..417548a
--- /dev/null
+++ b/test/core/end2end/fuzzers/client_fuzzer_corpus/63a1cb41d219394c9bab947202921506f3574ad0
Binary files differ
diff --git a/test/core/end2end/fuzzers/client_fuzzer_corpus/650f74738d3961af2d1fe85ad8fc8212ea13cbbf b/test/core/end2end/fuzzers/client_fuzzer_corpus/650f74738d3961af2d1fe85ad8fc8212ea13cbbf
new file mode 100644
index 0000000..382f3de
--- /dev/null
+++ b/test/core/end2end/fuzzers/client_fuzzer_corpus/650f74738d3961af2d1fe85ad8fc8212ea13cbbf
Binary files differ
diff --git a/test/core/end2end/fuzzers/client_fuzzer_corpus/65dff388749da6a44926b491cdc555f61d708171 b/test/core/end2end/fuzzers/client_fuzzer_corpus/65dff388749da6a44926b491cdc555f61d708171
new file mode 100644
index 0000000..8e35246
--- /dev/null
+++ b/test/core/end2end/fuzzers/client_fuzzer_corpus/65dff388749da6a44926b491cdc555f61d708171
Binary files differ
diff --git a/test/core/end2end/fuzzers/client_fuzzer_corpus/676adbb1e5b3f4f9e3cba51d3d4ef963ba4ea7e3 b/test/core/end2end/fuzzers/client_fuzzer_corpus/676adbb1e5b3f4f9e3cba51d3d4ef963ba4ea7e3
new file mode 100644
index 0000000..720dcdb
--- /dev/null
+++ b/test/core/end2end/fuzzers/client_fuzzer_corpus/676adbb1e5b3f4f9e3cba51d3d4ef963ba4ea7e3
Binary files differ
diff --git a/test/core/end2end/fuzzers/client_fuzzer_corpus/67f160446ded73c408f4e5a0665731b642b6edd4 b/test/core/end2end/fuzzers/client_fuzzer_corpus/67f160446ded73c408f4e5a0665731b642b6edd4
new file mode 100644
index 0000000..cdbee59
--- /dev/null
+++ b/test/core/end2end/fuzzers/client_fuzzer_corpus/67f160446ded73c408f4e5a0665731b642b6edd4
Binary files differ
diff --git a/test/core/end2end/fuzzers/client_fuzzer_corpus/6856c7cb02d2ba74a60fd47140f042701dda63b3 b/test/core/end2end/fuzzers/client_fuzzer_corpus/6856c7cb02d2ba74a60fd47140f042701dda63b3
new file mode 100644
index 0000000..f2dc196
--- /dev/null
+++ b/test/core/end2end/fuzzers/client_fuzzer_corpus/6856c7cb02d2ba74a60fd47140f042701dda63b3
Binary files differ
diff --git a/test/core/end2end/fuzzers/client_fuzzer_corpus/69e14b73af03e8f2d998cfcf16215f65bf589efb b/test/core/end2end/fuzzers/client_fuzzer_corpus/69e14b73af03e8f2d998cfcf16215f65bf589efb
new file mode 100644
index 0000000..ae23d16
--- /dev/null
+++ b/test/core/end2end/fuzzers/client_fuzzer_corpus/69e14b73af03e8f2d998cfcf16215f65bf589efb
Binary files differ
diff --git a/test/core/end2end/fuzzers/client_fuzzer_corpus/77cff7548cafe87410e4a0dde3ba6892b25594d3 b/test/core/end2end/fuzzers/client_fuzzer_corpus/77cff7548cafe87410e4a0dde3ba6892b25594d3
new file mode 100644
index 0000000..95defaa
--- /dev/null
+++ b/test/core/end2end/fuzzers/client_fuzzer_corpus/77cff7548cafe87410e4a0dde3ba6892b25594d3
Binary files differ
diff --git a/test/core/end2end/fuzzers/client_fuzzer_corpus/7beeb19272131701f3a0d1dd633f1b1969899366 b/test/core/end2end/fuzzers/client_fuzzer_corpus/7beeb19272131701f3a0d1dd633f1b1969899366
new file mode 100644
index 0000000..4293d0c
--- /dev/null
+++ b/test/core/end2end/fuzzers/client_fuzzer_corpus/7beeb19272131701f3a0d1dd633f1b1969899366
Binary files differ
diff --git a/test/core/end2end/fuzzers/client_fuzzer_corpus/8b0cf53ac17015fe066002cb3814933df9ee96be b/test/core/end2end/fuzzers/client_fuzzer_corpus/8b0cf53ac17015fe066002cb3814933df9ee96be
new file mode 100644
index 0000000..ba952ec
--- /dev/null
+++ b/test/core/end2end/fuzzers/client_fuzzer_corpus/8b0cf53ac17015fe066002cb3814933df9ee96be
Binary files differ
diff --git a/test/core/end2end/fuzzers/client_fuzzer_corpus/8b5c4543923da5e468aca1de1ab880aed2ac4451 b/test/core/end2end/fuzzers/client_fuzzer_corpus/8b5c4543923da5e468aca1de1ab880aed2ac4451
new file mode 100644
index 0000000..7c5cd2b
--- /dev/null
+++ b/test/core/end2end/fuzzers/client_fuzzer_corpus/8b5c4543923da5e468aca1de1ab880aed2ac4451
Binary files differ
diff --git a/test/core/end2end/fuzzers/client_fuzzer_corpus/8d9784f85e9662734e180ca8bec2164425ae8a87 b/test/core/end2end/fuzzers/client_fuzzer_corpus/8d9784f85e9662734e180ca8bec2164425ae8a87
new file mode 100644
index 0000000..b2ad2b0
--- /dev/null
+++ b/test/core/end2end/fuzzers/client_fuzzer_corpus/8d9784f85e9662734e180ca8bec2164425ae8a87
Binary files differ
diff --git a/test/core/end2end/fuzzers/client_fuzzer_corpus/8e3f138d163022d6e105ab595788f4cfdd9b9db3 b/test/core/end2end/fuzzers/client_fuzzer_corpus/8e3f138d163022d6e105ab595788f4cfdd9b9db3
new file mode 100644
index 0000000..e10a35c
--- /dev/null
+++ b/test/core/end2end/fuzzers/client_fuzzer_corpus/8e3f138d163022d6e105ab595788f4cfdd9b9db3
Binary files differ
diff --git a/test/core/end2end/fuzzers/client_fuzzer_corpus/914464d372dcccf31ed5331293d84121e17616bb b/test/core/end2end/fuzzers/client_fuzzer_corpus/914464d372dcccf31ed5331293d84121e17616bb
new file mode 100644
index 0000000..c67d9de
--- /dev/null
+++ b/test/core/end2end/fuzzers/client_fuzzer_corpus/914464d372dcccf31ed5331293d84121e17616bb
Binary files differ
diff --git a/test/core/end2end/fuzzers/client_fuzzer_corpus/934a41b5027d1c5cca27ebda57560c38cb9e09ea b/test/core/end2end/fuzzers/client_fuzzer_corpus/934a41b5027d1c5cca27ebda57560c38cb9e09ea
new file mode 100644
index 0000000..8ca1a43
--- /dev/null
+++ b/test/core/end2end/fuzzers/client_fuzzer_corpus/934a41b5027d1c5cca27ebda57560c38cb9e09ea
Binary files differ
diff --git a/test/core/end2end/fuzzers/client_fuzzer_corpus/9354652806d96b09c8e7082b1b7d22e7c3fb9f0b b/test/core/end2end/fuzzers/client_fuzzer_corpus/9354652806d96b09c8e7082b1b7d22e7c3fb9f0b
new file mode 100644
index 0000000..41461a1
--- /dev/null
+++ b/test/core/end2end/fuzzers/client_fuzzer_corpus/9354652806d96b09c8e7082b1b7d22e7c3fb9f0b
Binary files differ
diff --git a/test/core/end2end/fuzzers/client_fuzzer_corpus/9398ac1c2b4015792661266a9c84b6d7a68c3155 b/test/core/end2end/fuzzers/client_fuzzer_corpus/9398ac1c2b4015792661266a9c84b6d7a68c3155
new file mode 100644
index 0000000..f9b2aaf
--- /dev/null
+++ b/test/core/end2end/fuzzers/client_fuzzer_corpus/9398ac1c2b4015792661266a9c84b6d7a68c3155
Binary files differ
diff --git a/test/core/end2end/fuzzers/client_fuzzer_corpus/99099024a3f3e389f57cb7b697eb34485846f316 b/test/core/end2end/fuzzers/client_fuzzer_corpus/99099024a3f3e389f57cb7b697eb34485846f316
new file mode 100644
index 0000000..1721f92
--- /dev/null
+++ b/test/core/end2end/fuzzers/client_fuzzer_corpus/99099024a3f3e389f57cb7b697eb34485846f316
Binary files differ
diff --git a/test/core/end2end/fuzzers/client_fuzzer_corpus/998a54dc94ab6e7d6a6066415fb0dd9b52356171 b/test/core/end2end/fuzzers/client_fuzzer_corpus/998a54dc94ab6e7d6a6066415fb0dd9b52356171
new file mode 100644
index 0000000..06ec60a
--- /dev/null
+++ b/test/core/end2end/fuzzers/client_fuzzer_corpus/998a54dc94ab6e7d6a6066415fb0dd9b52356171
Binary files differ
diff --git a/test/core/end2end/fuzzers/client_fuzzer_corpus/a25b31398669b585ccab97bceadc31994de7ead7 b/test/core/end2end/fuzzers/client_fuzzer_corpus/a25b31398669b585ccab97bceadc31994de7ead7
new file mode 100644
index 0000000..9d41026
--- /dev/null
+++ b/test/core/end2end/fuzzers/client_fuzzer_corpus/a25b31398669b585ccab97bceadc31994de7ead7
Binary files differ
diff --git a/test/core/end2end/fuzzers/client_fuzzer_corpus/a39ac9e92b41d1889096ed415b4c2eb1aba6ed50 b/test/core/end2end/fuzzers/client_fuzzer_corpus/a39ac9e92b41d1889096ed415b4c2eb1aba6ed50
new file mode 100644
index 0000000..be4a64b
--- /dev/null
+++ b/test/core/end2end/fuzzers/client_fuzzer_corpus/a39ac9e92b41d1889096ed415b4c2eb1aba6ed50
Binary files differ
diff --git a/test/core/end2end/fuzzers/client_fuzzer_corpus/a5c2fdae1a1c0487d00db0eec6e3429b12244b1f b/test/core/end2end/fuzzers/client_fuzzer_corpus/a5c2fdae1a1c0487d00db0eec6e3429b12244b1f
new file mode 100644
index 0000000..1c323b7
--- /dev/null
+++ b/test/core/end2end/fuzzers/client_fuzzer_corpus/a5c2fdae1a1c0487d00db0eec6e3429b12244b1f
Binary files differ
diff --git a/test/core/end2end/fuzzers/client_fuzzer_corpus/a649093880c2a2f143f861893eaff5d30be95eb7 b/test/core/end2end/fuzzers/client_fuzzer_corpus/a649093880c2a2f143f861893eaff5d30be95eb7
new file mode 100644
index 0000000..7b879ac
--- /dev/null
+++ b/test/core/end2end/fuzzers/client_fuzzer_corpus/a649093880c2a2f143f861893eaff5d30be95eb7
Binary files differ
diff --git a/test/core/end2end/fuzzers/client_fuzzer_corpus/a8249ebfe91327806446f14a6b2e7d9c8440257f b/test/core/end2end/fuzzers/client_fuzzer_corpus/a8249ebfe91327806446f14a6b2e7d9c8440257f
new file mode 100644
index 0000000..2bdbe51
--- /dev/null
+++ b/test/core/end2end/fuzzers/client_fuzzer_corpus/a8249ebfe91327806446f14a6b2e7d9c8440257f
Binary files differ
diff --git a/test/core/end2end/fuzzers/client_fuzzer_corpus/a8e306820fb76566b522c23ec68bdce0ad0536f2 b/test/core/end2end/fuzzers/client_fuzzer_corpus/a8e306820fb76566b522c23ec68bdce0ad0536f2
new file mode 100644
index 0000000..3c62087
--- /dev/null
+++ b/test/core/end2end/fuzzers/client_fuzzer_corpus/a8e306820fb76566b522c23ec68bdce0ad0536f2
Binary files differ
diff --git a/test/core/end2end/fuzzers/client_fuzzer_corpus/a97dbb159ef9bc6e39c9c25e04315752e871e739 b/test/core/end2end/fuzzers/client_fuzzer_corpus/a97dbb159ef9bc6e39c9c25e04315752e871e739
new file mode 100644
index 0000000..b43e55b
--- /dev/null
+++ b/test/core/end2end/fuzzers/client_fuzzer_corpus/a97dbb159ef9bc6e39c9c25e04315752e871e739
Binary files differ
diff --git a/test/core/end2end/fuzzers/client_fuzzer_corpus/ae448bfe17f9a3a6eff074d4caa9f7261c94d2d5 b/test/core/end2end/fuzzers/client_fuzzer_corpus/ae448bfe17f9a3a6eff074d4caa9f7261c94d2d5
new file mode 100644
index 0000000..5d16743
--- /dev/null
+++ b/test/core/end2end/fuzzers/client_fuzzer_corpus/ae448bfe17f9a3a6eff074d4caa9f7261c94d2d5
Binary files differ
diff --git a/test/core/end2end/fuzzers/client_fuzzer_corpus/ae8cdc02275a1436bc131bee52a17ee797e2e6c9 b/test/core/end2end/fuzzers/client_fuzzer_corpus/ae8cdc02275a1436bc131bee52a17ee797e2e6c9
new file mode 100644
index 0000000..12c2446
--- /dev/null
+++ b/test/core/end2end/fuzzers/client_fuzzer_corpus/ae8cdc02275a1436bc131bee52a17ee797e2e6c9
Binary files differ
diff --git a/test/core/end2end/fuzzers/client_fuzzer_corpus/b10353c265bef989d8909055fd6cd52e49eef3e6 b/test/core/end2end/fuzzers/client_fuzzer_corpus/b10353c265bef989d8909055fd6cd52e49eef3e6
new file mode 100644
index 0000000..4f6e5cc
--- /dev/null
+++ b/test/core/end2end/fuzzers/client_fuzzer_corpus/b10353c265bef989d8909055fd6cd52e49eef3e6
Binary files differ
diff --git a/test/core/end2end/fuzzers/client_fuzzer_corpus/b387e46c23912785e6c353ab49b8ea4a92c2c2e5 b/test/core/end2end/fuzzers/client_fuzzer_corpus/b387e46c23912785e6c353ab49b8ea4a92c2c2e5
new file mode 100644
index 0000000..32397f0
--- /dev/null
+++ b/test/core/end2end/fuzzers/client_fuzzer_corpus/b387e46c23912785e6c353ab49b8ea4a92c2c2e5
Binary files differ
diff --git a/test/core/end2end/fuzzers/client_fuzzer_corpus/b3cfcd55b0331ab0c931b8c61d4df41464587f10 b/test/core/end2end/fuzzers/client_fuzzer_corpus/b3cfcd55b0331ab0c931b8c61d4df41464587f10
new file mode 100644
index 0000000..fd118bc
--- /dev/null
+++ b/test/core/end2end/fuzzers/client_fuzzer_corpus/b3cfcd55b0331ab0c931b8c61d4df41464587f10
Binary files differ
diff --git a/test/core/end2end/fuzzers/client_fuzzer_corpus/b758f5c019696f33c50895168219c0e6cb04e11d b/test/core/end2end/fuzzers/client_fuzzer_corpus/b758f5c019696f33c50895168219c0e6cb04e11d
new file mode 100644
index 0000000..6b74b8a
--- /dev/null
+++ b/test/core/end2end/fuzzers/client_fuzzer_corpus/b758f5c019696f33c50895168219c0e6cb04e11d
Binary files differ
diff --git a/test/core/end2end/fuzzers/client_fuzzer_corpus/b93fd0a15287dd035eac86e547e3ce42183bdb28 b/test/core/end2end/fuzzers/client_fuzzer_corpus/b93fd0a15287dd035eac86e547e3ce42183bdb28
new file mode 100644
index 0000000..0bb5774
--- /dev/null
+++ b/test/core/end2end/fuzzers/client_fuzzer_corpus/b93fd0a15287dd035eac86e547e3ce42183bdb28
Binary files differ
diff --git a/test/core/end2end/fuzzers/client_fuzzer_corpus/ba3566735888b53712c6b2e6d52ff5f2197afd6a b/test/core/end2end/fuzzers/client_fuzzer_corpus/ba3566735888b53712c6b2e6d52ff5f2197afd6a
new file mode 100644
index 0000000..3d91afe
--- /dev/null
+++ b/test/core/end2end/fuzzers/client_fuzzer_corpus/ba3566735888b53712c6b2e6d52ff5f2197afd6a
Binary files differ
diff --git a/test/core/end2end/fuzzers/client_fuzzer_corpus/bd275178fd473028a5cedf7d5780b27e809882ee b/test/core/end2end/fuzzers/client_fuzzer_corpus/bd275178fd473028a5cedf7d5780b27e809882ee
new file mode 100644
index 0000000..eb3276b
--- /dev/null
+++ b/test/core/end2end/fuzzers/client_fuzzer_corpus/bd275178fd473028a5cedf7d5780b27e809882ee
Binary files differ
diff --git a/test/core/end2end/fuzzers/client_fuzzer_corpus/c4c53b4727e9e1f040c5d7870639dd3daa184ddb b/test/core/end2end/fuzzers/client_fuzzer_corpus/c4c53b4727e9e1f040c5d7870639dd3daa184ddb
new file mode 100644
index 0000000..80e75c5
--- /dev/null
+++ b/test/core/end2end/fuzzers/client_fuzzer_corpus/c4c53b4727e9e1f040c5d7870639dd3daa184ddb
Binary files differ
diff --git a/test/core/end2end/fuzzers/client_fuzzer_corpus/c9e2cf8be8a4dc2294020026c62840ef1fb4853b b/test/core/end2end/fuzzers/client_fuzzer_corpus/c9e2cf8be8a4dc2294020026c62840ef1fb4853b
new file mode 100644
index 0000000..e97dce0
--- /dev/null
+++ b/test/core/end2end/fuzzers/client_fuzzer_corpus/c9e2cf8be8a4dc2294020026c62840ef1fb4853b
Binary files differ
diff --git a/test/core/end2end/fuzzers/client_fuzzer_corpus/caaf9a7751c0eccc34f0fc00a048012ab5ed2f37 b/test/core/end2end/fuzzers/client_fuzzer_corpus/caaf9a7751c0eccc34f0fc00a048012ab5ed2f37
new file mode 100644
index 0000000..f2374b7
--- /dev/null
+++ b/test/core/end2end/fuzzers/client_fuzzer_corpus/caaf9a7751c0eccc34f0fc00a048012ab5ed2f37
Binary files differ
diff --git a/test/core/end2end/fuzzers/client_fuzzer_corpus/cb49955601d171fd14c9ac21137b221392c7dab1 b/test/core/end2end/fuzzers/client_fuzzer_corpus/cb49955601d171fd14c9ac21137b221392c7dab1
new file mode 100644
index 0000000..adfce80
--- /dev/null
+++ b/test/core/end2end/fuzzers/client_fuzzer_corpus/cb49955601d171fd14c9ac21137b221392c7dab1
Binary files differ
diff --git a/test/core/end2end/fuzzers/client_fuzzer_corpus/cbaabef34763f2fd922e67ff5f2ea283347e9823 b/test/core/end2end/fuzzers/client_fuzzer_corpus/cbaabef34763f2fd922e67ff5f2ea283347e9823
new file mode 100644
index 0000000..3a937ae
--- /dev/null
+++ b/test/core/end2end/fuzzers/client_fuzzer_corpus/cbaabef34763f2fd922e67ff5f2ea283347e9823
Binary files differ
diff --git a/test/core/end2end/fuzzers/client_fuzzer_corpus/cdd1a4e358ee2396ece54b32c1f0a8d0a2e3f3dc b/test/core/end2end/fuzzers/client_fuzzer_corpus/cdd1a4e358ee2396ece54b32c1f0a8d0a2e3f3dc
new file mode 100644
index 0000000..82466bf
--- /dev/null
+++ b/test/core/end2end/fuzzers/client_fuzzer_corpus/cdd1a4e358ee2396ece54b32c1f0a8d0a2e3f3dc
Binary files differ
diff --git a/test/core/end2end/fuzzers/client_fuzzer_corpus/cf922d44bf08d223d3ebcd37a7e77d3e43555d08 b/test/core/end2end/fuzzers/client_fuzzer_corpus/cf922d44bf08d223d3ebcd37a7e77d3e43555d08
new file mode 100644
index 0000000..b9399a2
--- /dev/null
+++ b/test/core/end2end/fuzzers/client_fuzzer_corpus/cf922d44bf08d223d3ebcd37a7e77d3e43555d08
Binary files differ
diff --git a/test/core/end2end/fuzzers/client_fuzzer_corpus/crash-ff53a3d713e83ae945b8dd1782e21f5b51aa649a b/test/core/end2end/fuzzers/client_fuzzer_corpus/crash-ff53a3d713e83ae945b8dd1782e21f5b51aa649a
new file mode 100644
index 0000000..28ad75e
--- /dev/null
+++ b/test/core/end2end/fuzzers/client_fuzzer_corpus/crash-ff53a3d713e83ae945b8dd1782e21f5b51aa649a
Binary files differ
diff --git a/test/core/end2end/fuzzers/client_fuzzer_corpus/d17e9507af1855fcf9eca78e2d25c8fb2c40a34c b/test/core/end2end/fuzzers/client_fuzzer_corpus/d17e9507af1855fcf9eca78e2d25c8fb2c40a34c
new file mode 100644
index 0000000..b262a23
--- /dev/null
+++ b/test/core/end2end/fuzzers/client_fuzzer_corpus/d17e9507af1855fcf9eca78e2d25c8fb2c40a34c
Binary files differ
diff --git a/test/core/end2end/fuzzers/client_fuzzer_corpus/d46c3dcede830286dd9f4a1ba02a20a0b1430664 b/test/core/end2end/fuzzers/client_fuzzer_corpus/d46c3dcede830286dd9f4a1ba02a20a0b1430664
new file mode 100644
index 0000000..a11ecbe
--- /dev/null
+++ b/test/core/end2end/fuzzers/client_fuzzer_corpus/d46c3dcede830286dd9f4a1ba02a20a0b1430664
Binary files differ
diff --git a/test/core/end2end/fuzzers/client_fuzzer_corpus/d4a744ef6dcef5cf08d5289e167b26270d39e9f2 b/test/core/end2end/fuzzers/client_fuzzer_corpus/d4a744ef6dcef5cf08d5289e167b26270d39e9f2
new file mode 100644
index 0000000..462391f
--- /dev/null
+++ b/test/core/end2end/fuzzers/client_fuzzer_corpus/d4a744ef6dcef5cf08d5289e167b26270d39e9f2
Binary files differ
diff --git a/test/core/end2end/fuzzers/client_fuzzer_corpus/d5a85ad91cfde27a96960b2e783d2ee43c50dcb9 b/test/core/end2end/fuzzers/client_fuzzer_corpus/d5a85ad91cfde27a96960b2e783d2ee43c50dcb9
new file mode 100644
index 0000000..c187ee3
--- /dev/null
+++ b/test/core/end2end/fuzzers/client_fuzzer_corpus/d5a85ad91cfde27a96960b2e783d2ee43c50dcb9
Binary files differ
diff --git a/test/core/end2end/fuzzers/client_fuzzer_corpus/d88bb0b7ff687af84f33e6af22d3516fcdac5534 b/test/core/end2end/fuzzers/client_fuzzer_corpus/d88bb0b7ff687af84f33e6af22d3516fcdac5534
new file mode 100644
index 0000000..a64fe17
--- /dev/null
+++ b/test/core/end2end/fuzzers/client_fuzzer_corpus/d88bb0b7ff687af84f33e6af22d3516fcdac5534
Binary files differ
diff --git a/test/core/end2end/fuzzers/client_fuzzer_corpus/d895ece988ad4712b87de8aa9bc273eee315e8b8 b/test/core/end2end/fuzzers/client_fuzzer_corpus/d895ece988ad4712b87de8aa9bc273eee315e8b8
new file mode 100644
index 0000000..615ac35
--- /dev/null
+++ b/test/core/end2end/fuzzers/client_fuzzer_corpus/d895ece988ad4712b87de8aa9bc273eee315e8b8
Binary files differ
diff --git a/test/core/end2end/fuzzers/client_fuzzer_corpus/da424090e1b94c5d0e91e26f3f3dd6c4af18fcd5 b/test/core/end2end/fuzzers/client_fuzzer_corpus/da424090e1b94c5d0e91e26f3f3dd6c4af18fcd5
new file mode 100644
index 0000000..99ae121
--- /dev/null
+++ b/test/core/end2end/fuzzers/client_fuzzer_corpus/da424090e1b94c5d0e91e26f3f3dd6c4af18fcd5
Binary files differ
diff --git a/test/core/end2end/fuzzers/client_fuzzer_corpus/db3a30a6d8e605dd587e51b214c42f68bc43cf19 b/test/core/end2end/fuzzers/client_fuzzer_corpus/db3a30a6d8e605dd587e51b214c42f68bc43cf19
new file mode 100644
index 0000000..cc05683
--- /dev/null
+++ b/test/core/end2end/fuzzers/client_fuzzer_corpus/db3a30a6d8e605dd587e51b214c42f68bc43cf19
Binary files differ
diff --git a/test/core/end2end/fuzzers/client_fuzzer_corpus/e3d12a2385b75443fe38d989e77c252e1f3cdb6d b/test/core/end2end/fuzzers/client_fuzzer_corpus/e3d12a2385b75443fe38d989e77c252e1f3cdb6d
new file mode 100644
index 0000000..1878ff2
--- /dev/null
+++ b/test/core/end2end/fuzzers/client_fuzzer_corpus/e3d12a2385b75443fe38d989e77c252e1f3cdb6d
Binary files differ
diff --git a/test/core/end2end/fuzzers/client_fuzzer_corpus/e4f55281c481484bd9edc28fd10df0c2e0f7d546 b/test/core/end2end/fuzzers/client_fuzzer_corpus/e4f55281c481484bd9edc28fd10df0c2e0f7d546
new file mode 100644
index 0000000..042b169
--- /dev/null
+++ b/test/core/end2end/fuzzers/client_fuzzer_corpus/e4f55281c481484bd9edc28fd10df0c2e0f7d546
Binary files differ
diff --git a/test/core/end2end/fuzzers/client_fuzzer_corpus/e6c52f2f31db7595d1ecde2939a7390777f15182 b/test/core/end2end/fuzzers/client_fuzzer_corpus/e6c52f2f31db7595d1ecde2939a7390777f15182
new file mode 100644
index 0000000..17fbabe
--- /dev/null
+++ b/test/core/end2end/fuzzers/client_fuzzer_corpus/e6c52f2f31db7595d1ecde2939a7390777f15182
Binary files differ
diff --git a/test/core/end2end/fuzzers/client_fuzzer_corpus/f09cd3e3a16658174717668e51e7382e491df1da b/test/core/end2end/fuzzers/client_fuzzer_corpus/f09cd3e3a16658174717668e51e7382e491df1da
new file mode 100644
index 0000000..82c3e4f
--- /dev/null
+++ b/test/core/end2end/fuzzers/client_fuzzer_corpus/f09cd3e3a16658174717668e51e7382e491df1da
Binary files differ
diff --git a/test/core/end2end/fuzzers/client_fuzzer_corpus/f11abb090bae8cdac1f7d9a2e344f2def0e50066 b/test/core/end2end/fuzzers/client_fuzzer_corpus/f11abb090bae8cdac1f7d9a2e344f2def0e50066
new file mode 100644
index 0000000..2a12fb9
--- /dev/null
+++ b/test/core/end2end/fuzzers/client_fuzzer_corpus/f11abb090bae8cdac1f7d9a2e344f2def0e50066
Binary files differ
diff --git a/test/core/end2end/fuzzers/client_fuzzer_corpus/f4ae2a2b692bfa83cdde75d007813426e14daef7 b/test/core/end2end/fuzzers/client_fuzzer_corpus/f4ae2a2b692bfa83cdde75d007813426e14daef7
new file mode 100644
index 0000000..ea1c77e
--- /dev/null
+++ b/test/core/end2end/fuzzers/client_fuzzer_corpus/f4ae2a2b692bfa83cdde75d007813426e14daef7
Binary files differ
diff --git a/test/core/end2end/fuzzers/client_fuzzer_corpus/f5a629c8fd5720236b66a875e96ea22e29c45965 b/test/core/end2end/fuzzers/client_fuzzer_corpus/f5a629c8fd5720236b66a875e96ea22e29c45965
new file mode 100644
index 0000000..8b2a877
--- /dev/null
+++ b/test/core/end2end/fuzzers/client_fuzzer_corpus/f5a629c8fd5720236b66a875e96ea22e29c45965
Binary files differ
diff --git a/test/core/end2end/fuzzers/client_fuzzer_corpus/f6627c55881fe4f0c8e6999980fb226836e6f5ce b/test/core/end2end/fuzzers/client_fuzzer_corpus/f6627c55881fe4f0c8e6999980fb226836e6f5ce
new file mode 100644
index 0000000..60c8c75
--- /dev/null
+++ b/test/core/end2end/fuzzers/client_fuzzer_corpus/f6627c55881fe4f0c8e6999980fb226836e6f5ce
Binary files differ
diff --git a/test/core/end2end/fuzzers/client_fuzzer_corpus/f7aeceaf0b6d971038a677994b5d080fa0e18011 b/test/core/end2end/fuzzers/client_fuzzer_corpus/f7aeceaf0b6d971038a677994b5d080fa0e18011
new file mode 100644
index 0000000..a80c582
--- /dev/null
+++ b/test/core/end2end/fuzzers/client_fuzzer_corpus/f7aeceaf0b6d971038a677994b5d080fa0e18011
Binary files differ
diff --git a/test/core/end2end/fuzzers/client_fuzzer_corpus/f803c87a92662898e2c8c847787b56d2c31f63b3 b/test/core/end2end/fuzzers/client_fuzzer_corpus/f803c87a92662898e2c8c847787b56d2c31f63b3
new file mode 100644
index 0000000..146a748
--- /dev/null
+++ b/test/core/end2end/fuzzers/client_fuzzer_corpus/f803c87a92662898e2c8c847787b56d2c31f63b3
Binary files differ
diff --git a/test/core/end2end/fuzzers/client_fuzzer_corpus/f89ad475ff51a5a9fe18603df833453bed320f36 b/test/core/end2end/fuzzers/client_fuzzer_corpus/f89ad475ff51a5a9fe18603df833453bed320f36
new file mode 100644
index 0000000..ae4812d
--- /dev/null
+++ b/test/core/end2end/fuzzers/client_fuzzer_corpus/f89ad475ff51a5a9fe18603df833453bed320f36
Binary files differ
diff --git a/test/core/end2end/fuzzers/client_fuzzer_corpus/f9583b3a39c1aecbba6e81d71e7fe9b9519c8b08 b/test/core/end2end/fuzzers/client_fuzzer_corpus/f9583b3a39c1aecbba6e81d71e7fe9b9519c8b08
new file mode 100644
index 0000000..9018d4d
--- /dev/null
+++ b/test/core/end2end/fuzzers/client_fuzzer_corpus/f9583b3a39c1aecbba6e81d71e7fe9b9519c8b08
Binary files differ
diff --git a/test/core/end2end/fuzzers/client_fuzzer_corpus/ffd52d31f9c59a346aa195a683f077dda5ecef6b b/test/core/end2end/fuzzers/client_fuzzer_corpus/ffd52d31f9c59a346aa195a683f077dda5ecef6b
new file mode 100644
index 0000000..d7e73ad
--- /dev/null
+++ b/test/core/end2end/fuzzers/client_fuzzer_corpus/ffd52d31f9c59a346aa195a683f077dda5ecef6b
Binary files differ
diff --git a/test/core/end2end/fuzzers/hpack.dictionary b/test/core/end2end/fuzzers/hpack.dictionary
index 3157dfc..e5a73d5 100644
--- a/test/core/end2end/fuzzers/hpack.dictionary
+++ b/test/core/end2end/fuzzers/hpack.dictionary
@@ -44,6 +44,7 @@
 "\x0Dgrpc-encoding"
 "\x1Egrpc-internal-encoding-request"
 "\x0Cgrpc-message"
+"\x10grpc-payload-bin"
 "\x0Bgrpc-status"
 "\x0Cgrpc-timeout"
 "\x10grpc-tracing-bin"
diff --git a/test/core/end2end/gen_build_yaml.py b/test/core/end2end/gen_build_yaml.py
index e59b7dc..b8ff573 100755
--- a/test/core/end2end/gen_build_yaml.py
+++ b/test/core/end2end/gen_build_yaml.py
@@ -114,6 +114,7 @@
     'max_message_length': default_test_options,
     'negative_deadline': default_test_options,
     'network_status_change': default_test_options,
+    'no_logging': default_test_options._replace(traceable=False),
     'no_op': default_test_options,
     'payload': default_test_options,
     'load_reporting_hook': default_test_options,
diff --git a/test/core/end2end/goaway_server_test.c b/test/core/end2end/goaway_server_test.c
index 67cc24c..a8c7b2b 100644
--- a/test/core/end2end/goaway_server_test.c
+++ b/test/core/end2end/goaway_server_test.c
@@ -175,8 +175,8 @@
   set_resolve_port(port1);
 
   /* first call should now start */
-  cq_expect_completion(cqv, tag(0x101), 1);
-  cq_expect_completion(cqv, tag(0x301), 1);
+  CQ_EXPECT_COMPLETION(cqv, tag(0x101), 1);
+  CQ_EXPECT_COMPLETION(cqv, tag(0x301), 1);
   cq_verify(cqv);
 
   GPR_ASSERT(GRPC_CHANNEL_READY ==
@@ -200,7 +200,7 @@
    * we should see a connectivity change and then nothing */
   set_resolve_port(-1);
   grpc_server_shutdown_and_notify(server1, cq, tag(0xdead1));
-  cq_expect_completion(cqv, tag(0x9999), 1);
+  CQ_EXPECT_COMPLETION(cqv, tag(0x9999), 1);
   cq_verify(cqv);
   cq_verify_empty(cqv);
 
@@ -250,8 +250,8 @@
                                       &request_metadata2, cq, cq, tag(0x401)));
 
   /* second call should now start */
-  cq_expect_completion(cqv, tag(0x201), 1);
-  cq_expect_completion(cqv, tag(0x401), 1);
+  CQ_EXPECT_COMPLETION(cqv, tag(0x201), 1);
+  CQ_EXPECT_COMPLETION(cqv, tag(0x401), 1);
   cq_verify(cqv);
 
   /* listen for close on the server call to probe for finishing */
@@ -273,12 +273,12 @@
   grpc_call_cancel(call2, NULL);
 
   /* now everything else should finish */
-  cq_expect_completion(cqv, tag(0x102), 1);
-  cq_expect_completion(cqv, tag(0x202), 1);
-  cq_expect_completion(cqv, tag(0x302), 1);
-  cq_expect_completion(cqv, tag(0x402), 1);
-  cq_expect_completion(cqv, tag(0xdead1), 1);
-  cq_expect_completion(cqv, tag(0xdead2), 1);
+  CQ_EXPECT_COMPLETION(cqv, tag(0x102), 1);
+  CQ_EXPECT_COMPLETION(cqv, tag(0x202), 1);
+  CQ_EXPECT_COMPLETION(cqv, tag(0x302), 1);
+  CQ_EXPECT_COMPLETION(cqv, tag(0x402), 1);
+  CQ_EXPECT_COMPLETION(cqv, tag(0xdead1), 1);
+  CQ_EXPECT_COMPLETION(cqv, tag(0xdead2), 1);
   cq_verify(cqv);
 
   grpc_call_destroy(call1);
diff --git a/test/core/end2end/invalid_call_argument_test.c b/test/core/end2end/invalid_call_argument_test.c
index 3545660..2b9904a 100644
--- a/test/core/end2end/invalid_call_argument_test.c
+++ b/test/core/end2end/invalid_call_argument_test.c
@@ -116,8 +116,8 @@
                                         &g_state.call_details,
                                         &g_state.server_initial_metadata_recv,
                                         g_state.cq, g_state.cq, tag(101)));
-    cq_expect_completion(g_state.cqv, tag(101), 1);
-    cq_expect_completion(g_state.cqv, tag(1), 1);
+    CQ_EXPECT_COMPLETION(g_state.cqv, tag(101), 1);
+    CQ_EXPECT_COMPLETION(g_state.cqv, tag(1), 1);
     cq_verify(g_state.cqv);
   }
 }
@@ -191,7 +191,7 @@
   GPR_ASSERT(GRPC_CALL_OK == grpc_call_start_batch(g_state.call, g_state.ops,
                                                    (size_t)(op - g_state.ops),
                                                    tag(1), NULL));
-  cq_expect_completion(g_state.cqv, tag(1), 0);
+  CQ_EXPECT_COMPLETION(g_state.cqv, tag(1), 0);
   cq_verify(g_state.cqv);
 
   op = g_state.ops;
@@ -312,7 +312,7 @@
   GPR_ASSERT(GRPC_CALL_OK == grpc_call_start_batch(g_state.call, g_state.ops,
                                                    (size_t)(op - g_state.ops),
                                                    tag(1), NULL));
-  cq_expect_completion(g_state.cqv, tag(1), 0);
+  CQ_EXPECT_COMPLETION(g_state.cqv, tag(1), 0);
   cq_verify(g_state.cqv);
   op = g_state.ops;
   op->op = GRPC_OP_RECV_INITIAL_METADATA;
@@ -405,7 +405,7 @@
   GPR_ASSERT(GRPC_CALL_OK == grpc_call_start_batch(g_state.call, g_state.ops,
                                                    (size_t)(op - g_state.ops),
                                                    tag(1), NULL));
-  cq_expect_completion(g_state.cqv, tag(1), 1);
+  CQ_EXPECT_COMPLETION(g_state.cqv, tag(1), 1);
   cq_verify(g_state.cqv);
 
   op = g_state.ops;
diff --git a/test/core/end2end/no_server_test.c b/test/core/end2end/no_server_test.c
index 08af382..03ff70a 100644
--- a/test/core/end2end/no_server_test.c
+++ b/test/core/end2end/no_server_test.c
@@ -86,7 +86,7 @@
   GPR_ASSERT(GRPC_CALL_OK == grpc_call_start_batch(
                                  call, ops, (size_t)(op - ops), tag(1), NULL));
   /* verify that all tags get completed */
-  cq_expect_completion(cqv, tag(1), 1);
+  CQ_EXPECT_COMPLETION(cqv, tag(1), 1);
   cq_verify(cqv);
 
   GPR_ASSERT(status == GRPC_STATUS_DEADLINE_EXCEEDED);
diff --git a/test/core/end2end/tests/bad_hostname.c b/test/core/end2end/tests/bad_hostname.c
index c9663c2..e0c7ac7 100644
--- a/test/core/end2end/tests/bad_hostname.c
+++ b/test/core/end2end/tests/bad_hostname.c
@@ -45,8 +45,6 @@
 #include "src/core/lib/support/string.h"
 #include "test/core/end2end/cq_verifier.h"
 
-enum { TIMEOUT = 200000 };
-
 static void *tag(intptr_t t) { return (void *)t; }
 
 static grpc_end2end_test_fixture begin_test(grpc_end2end_test_config config,
@@ -150,7 +148,7 @@
   error = grpc_call_start_batch(c, ops, (size_t)(op - ops), tag(1), NULL);
   GPR_ASSERT(GRPC_CALL_OK == error);
 
-  cq_expect_completion(cqv, tag(1), 1);
+  CQ_EXPECT_COMPLETION(cqv, tag(1), 1);
   cq_verify(cqv);
 
   GPR_ASSERT(status == GRPC_STATUS_INTERNAL);
diff --git a/test/core/end2end/tests/binary_metadata.c b/test/core/end2end/tests/binary_metadata.c
index 3dd2612..6b105de 100644
--- a/test/core/end2end/tests/binary_metadata.c
+++ b/test/core/end2end/tests/binary_metadata.c
@@ -43,8 +43,6 @@
 #include <grpc/support/useful.h>
 #include "test/core/end2end/cq_verifier.h"
 
-enum { TIMEOUT = 200000 };
-
 static void *tag(intptr_t t) { return (void *)t; }
 
 static grpc_end2end_test_fixture begin_test(grpc_end2end_test_config config,
@@ -199,7 +197,7 @@
       grpc_server_request_call(f.server, &s, &call_details,
                                &request_metadata_recv, f.cq, f.cq, tag(101));
   GPR_ASSERT(GRPC_CALL_OK == error);
-  cq_expect_completion(cqv, tag(101), 1);
+  CQ_EXPECT_COMPLETION(cqv, tag(101), 1);
   cq_verify(cqv);
 
   memset(ops, 0, sizeof(ops));
@@ -218,7 +216,7 @@
   error = grpc_call_start_batch(s, ops, (size_t)(op - ops), tag(102), NULL);
   GPR_ASSERT(GRPC_CALL_OK == error);
 
-  cq_expect_completion(cqv, tag(102), 1);
+  CQ_EXPECT_COMPLETION(cqv, tag(102), 1);
   cq_verify(cqv);
 
   memset(ops, 0, sizeof(ops));
@@ -243,8 +241,8 @@
   error = grpc_call_start_batch(s, ops, (size_t)(op - ops), tag(103), NULL);
   GPR_ASSERT(GRPC_CALL_OK == error);
 
-  cq_expect_completion(cqv, tag(103), 1);
-  cq_expect_completion(cqv, tag(1), 1);
+  CQ_EXPECT_COMPLETION(cqv, tag(103), 1);
+  CQ_EXPECT_COMPLETION(cqv, tag(1), 1);
   cq_verify(cqv);
 
   GPR_ASSERT(status == GRPC_STATUS_OK);
diff --git a/test/core/end2end/tests/call_creds.c b/test/core/end2end/tests/call_creds.c
index 694a0aa..981c0fc 100644
--- a/test/core/end2end/tests/call_creds.c
+++ b/test/core/end2end/tests/call_creds.c
@@ -53,8 +53,6 @@
 
 typedef enum { NONE, OVERRIDE, DESTROY } override_mode;
 
-enum { TIMEOUT = 200000 };
-
 static void *tag(intptr_t t) { return (void *)t; }
 
 static grpc_end2end_test_fixture begin_test(grpc_end2end_test_config config,
@@ -234,7 +232,7 @@
       grpc_server_request_call(f.server, &s, &call_details,
                                &request_metadata_recv, f.cq, f.cq, tag(101));
   GPR_ASSERT(GRPC_CALL_OK == error);
-  cq_expect_completion(cqv, tag(101), 1);
+  CQ_EXPECT_COMPLETION(cqv, tag(101), 1);
   cq_verify(cqv);
   s_auth_context = grpc_call_auth_context(s);
   GPR_ASSERT(s_auth_context != NULL);
@@ -264,7 +262,7 @@
   error = grpc_call_start_batch(s, ops, (size_t)(op - ops), tag(102), NULL);
   GPR_ASSERT(GRPC_CALL_OK == error);
 
-  cq_expect_completion(cqv, tag(102), 1);
+  CQ_EXPECT_COMPLETION(cqv, tag(102), 1);
   cq_verify(cqv);
 
   memset(ops, 0, sizeof(ops));
@@ -289,8 +287,8 @@
   error = grpc_call_start_batch(s, ops, (size_t)(op - ops), tag(103), NULL);
   GPR_ASSERT(GRPC_CALL_OK == error);
 
-  cq_expect_completion(cqv, tag(103), 1);
-  cq_expect_completion(cqv, tag(1), 1);
+  CQ_EXPECT_COMPLETION(cqv, tag(103), 1);
+  CQ_EXPECT_COMPLETION(cqv, tag(1), 1);
   cq_verify(cqv);
 
   GPR_ASSERT(status == GRPC_STATUS_OK);
@@ -450,7 +448,7 @@
   error = grpc_call_start_batch(c, ops, (size_t)(op - ops), tag(1), NULL);
   GPR_ASSERT(error == GRPC_CALL_OK);
 
-  cq_expect_completion(cqv, tag(1), 1);
+  CQ_EXPECT_COMPLETION(cqv, tag(1), 1);
   cq_verify(cqv);
 
   GPR_ASSERT(status == GRPC_STATUS_UNAUTHENTICATED);
diff --git a/test/core/end2end/tests/cancel_after_accept.c b/test/core/end2end/tests/cancel_after_accept.c
index 51c13da..b4ac3b3 100644
--- a/test/core/end2end/tests/cancel_after_accept.c
+++ b/test/core/end2end/tests/cancel_after_accept.c
@@ -44,8 +44,6 @@
 #include "test/core/end2end/cq_verifier.h"
 #include "test/core/end2end/tests/cancel_test_helpers.h"
 
-enum { TIMEOUT = 200000 };
-
 static void *tag(intptr_t t) { return (void *)t; }
 
 static grpc_end2end_test_fixture begin_test(grpc_end2end_test_config config,
@@ -172,7 +170,7 @@
   error = grpc_server_request_call(f.server, &s, &call_details,
                                    &request_metadata_recv, f.cq, f.cq, tag(2));
   GPR_ASSERT(GRPC_CALL_OK == error);
-  cq_expect_completion(cqv, tag(2), 1);
+  CQ_EXPECT_COMPLETION(cqv, tag(2), 1);
   cq_verify(cqv);
 
   memset(ops, 0, sizeof(ops));
@@ -202,8 +200,8 @@
 
   GPR_ASSERT(GRPC_CALL_OK == mode.initiate_cancel(c, NULL));
 
-  cq_expect_completion(cqv, tag(3), 1);
-  cq_expect_completion(cqv, tag(1), 1);
+  CQ_EXPECT_COMPLETION(cqv, tag(3), 1);
+  CQ_EXPECT_COMPLETION(cqv, tag(1), 1);
   cq_verify(cqv);
 
   GPR_ASSERT(status == mode.expect_status || status == GRPC_STATUS_INTERNAL);
diff --git a/test/core/end2end/tests/cancel_after_client_done.c b/test/core/end2end/tests/cancel_after_client_done.c
index 2b5a409..5adc71e 100644
--- a/test/core/end2end/tests/cancel_after_client_done.c
+++ b/test/core/end2end/tests/cancel_after_client_done.c
@@ -44,8 +44,6 @@
 #include "test/core/end2end/cq_verifier.h"
 #include "test/core/end2end/tests/cancel_test_helpers.h"
 
-enum { TIMEOUT = 200000 };
-
 static void *tag(intptr_t t) { return (void *)t; }
 
 static grpc_end2end_test_fixture begin_test(grpc_end2end_test_config config,
@@ -176,7 +174,7 @@
   error = grpc_server_request_call(f.server, &s, &call_details,
                                    &request_metadata_recv, f.cq, f.cq, tag(2));
   GPR_ASSERT(GRPC_CALL_OK == error);
-  cq_expect_completion(cqv, tag(2), 1);
+  CQ_EXPECT_COMPLETION(cqv, tag(2), 1);
   cq_verify(cqv);
 
   memset(ops, 0, sizeof(ops));
@@ -206,8 +204,8 @@
 
   GPR_ASSERT(GRPC_CALL_OK == mode.initiate_cancel(c, NULL));
 
-  cq_expect_completion(cqv, tag(3), 1);
-  cq_expect_completion(cqv, tag(1), 1);
+  CQ_EXPECT_COMPLETION(cqv, tag(3), 1);
+  CQ_EXPECT_COMPLETION(cqv, tag(1), 1);
   cq_verify(cqv);
 
   GPR_ASSERT(status == mode.expect_status || status == GRPC_STATUS_INTERNAL);
diff --git a/test/core/end2end/tests/cancel_after_invoke.c b/test/core/end2end/tests/cancel_after_invoke.c
index 85fbe9d..85d8799 100644
--- a/test/core/end2end/tests/cancel_after_invoke.c
+++ b/test/core/end2end/tests/cancel_after_invoke.c
@@ -44,8 +44,6 @@
 #include "test/core/end2end/cq_verifier.h"
 #include "test/core/end2end/tests/cancel_test_helpers.h"
 
-enum { TIMEOUT = 200000 };
-
 static void *tag(intptr_t t) { return (void *)t; }
 
 static grpc_end2end_test_fixture begin_test(grpc_end2end_test_config config,
@@ -170,7 +168,7 @@
 
   GPR_ASSERT(GRPC_CALL_OK == mode.initiate_cancel(c, NULL));
 
-  cq_expect_completion(cqv, tag(1), 1);
+  CQ_EXPECT_COMPLETION(cqv, tag(1), 1);
   cq_verify(cqv);
 
   GPR_ASSERT(status == mode.expect_status || status == GRPC_STATUS_INTERNAL);
diff --git a/test/core/end2end/tests/cancel_before_invoke.c b/test/core/end2end/tests/cancel_before_invoke.c
index d99062c..c570914 100644
--- a/test/core/end2end/tests/cancel_before_invoke.c
+++ b/test/core/end2end/tests/cancel_before_invoke.c
@@ -43,8 +43,6 @@
 #include <grpc/support/useful.h>
 #include "test/core/end2end/cq_verifier.h"
 
-enum { TIMEOUT = 200000 };
-
 static void *tag(intptr_t t) { return (void *)t; }
 
 static grpc_end2end_test_fixture begin_test(grpc_end2end_test_config config,
@@ -168,7 +166,7 @@
   error = grpc_call_start_batch(c, ops, test_ops, tag(1), NULL);
   GPR_ASSERT(GRPC_CALL_OK == error);
 
-  cq_expect_completion(cqv, tag(1), 1);
+  CQ_EXPECT_COMPLETION(cqv, tag(1), 1);
   cq_verify(cqv);
 
   GPR_ASSERT(status == GRPC_STATUS_CANCELLED);
diff --git a/test/core/end2end/tests/cancel_in_a_vacuum.c b/test/core/end2end/tests/cancel_in_a_vacuum.c
index 0c893b5..3b03616 100644
--- a/test/core/end2end/tests/cancel_in_a_vacuum.c
+++ b/test/core/end2end/tests/cancel_in_a_vacuum.c
@@ -44,8 +44,6 @@
 #include "test/core/end2end/cq_verifier.h"
 #include "test/core/end2end/tests/cancel_test_helpers.h"
 
-enum { TIMEOUT = 200000 };
-
 static void *tag(intptr_t t) { return (void *)t; }
 
 static grpc_end2end_test_fixture begin_test(grpc_end2end_test_config config,
diff --git a/test/core/end2end/tests/cancel_with_status.c b/test/core/end2end/tests/cancel_with_status.c
index 673c705..e65390a 100644
--- a/test/core/end2end/tests/cancel_with_status.c
+++ b/test/core/end2end/tests/cancel_with_status.c
@@ -45,8 +45,6 @@
 #include "src/core/lib/support/string.h"
 #include "test/core/end2end/cq_verifier.h"
 
-enum { TIMEOUT = 200000 };
-
 static void *tag(intptr_t t) { return (void *)t; }
 
 static grpc_end2end_test_fixture begin_test(grpc_end2end_test_config config,
@@ -152,7 +150,7 @@
 
   grpc_call_cancel_with_status(c, GRPC_STATUS_UNIMPLEMENTED, "xyz", NULL);
 
-  cq_expect_completion(cqv, tag(1), 1);
+  CQ_EXPECT_COMPLETION(cqv, tag(1), 1);
   cq_verify(cqv);
 
   GPR_ASSERT(status == GRPC_STATUS_UNIMPLEMENTED);
diff --git a/test/core/end2end/tests/compressed_payload.c b/test/core/end2end/tests/compressed_payload.c
index ec5c012..1724da4 100644
--- a/test/core/end2end/tests/compressed_payload.c
+++ b/test/core/end2end/tests/compressed_payload.c
@@ -50,8 +50,6 @@
 #include "src/core/lib/surface/call_test_only.h"
 #include "test/core/end2end/cq_verifier.h"
 
-enum { TIMEOUT = 200000 };
-
 static void *tag(intptr_t t) { return (void *)t; }
 
 static grpc_end2end_test_fixture begin_test(grpc_end2end_test_config config,
@@ -198,7 +196,7 @@
       grpc_server_request_call(f.server, &s, &call_details,
                                &request_metadata_recv, f.cq, f.cq, tag(101));
   GPR_ASSERT(GRPC_CALL_OK == error);
-  cq_expect_completion(cqv, tag(101), true);
+  CQ_EXPECT_COMPLETION(cqv, tag(101), true);
   cq_verify(cqv);
 
   op = ops;
@@ -215,7 +213,7 @@
   error = grpc_call_start_batch(s, ops, (size_t)(op - ops), tag(102), NULL);
   GPR_ASSERT(GRPC_CALL_OK == error);
 
-  cq_expect_completion(cqv, tag(102), false);
+  CQ_EXPECT_COMPLETION(cqv, tag(102), false);
 
   op = ops;
   op->op = GRPC_OP_RECV_CLOSE_ON_SERVER;
@@ -226,8 +224,8 @@
   error = grpc_call_start_batch(s, ops, (size_t)(op - ops), tag(103), NULL);
   GPR_ASSERT(GRPC_CALL_OK == error);
 
-  cq_expect_completion(cqv, tag(103), true);
-  cq_expect_completion(cqv, tag(1), true);
+  CQ_EXPECT_COMPLETION(cqv, tag(103), true);
+  CQ_EXPECT_COMPLETION(cqv, tag(1), true);
   cq_verify(cqv);
 
   /* call was cancelled (closed) ... */
@@ -361,7 +359,7 @@
       grpc_server_request_call(f.server, &s, &call_details,
                                &request_metadata_recv, f.cq, f.cq, tag(100));
   GPR_ASSERT(GRPC_CALL_OK == error);
-  cq_expect_completion(cqv, tag(100), true);
+  CQ_EXPECT_COMPLETION(cqv, tag(100), true);
   cq_verify(cqv);
 
   GPR_ASSERT(GPR_BITCOUNT(grpc_call_test_only_get_encodings_accepted_by_peer(
@@ -421,7 +419,7 @@
     op++;
     error = grpc_call_start_batch(s, ops, (size_t)(op - ops), tag(102), NULL);
     GPR_ASSERT(GRPC_CALL_OK == error);
-    cq_expect_completion(cqv, tag(102), 1);
+    CQ_EXPECT_COMPLETION(cqv, tag(102), 1);
     cq_verify(cqv);
 
     GPR_ASSERT(request_payload_recv->type == GRPC_BB_RAW);
@@ -438,8 +436,8 @@
     op++;
     error = grpc_call_start_batch(s, ops, (size_t)(op - ops), tag(103), NULL);
     GPR_ASSERT(GRPC_CALL_OK == error);
-    cq_expect_completion(cqv, tag(103), 1);
-    cq_expect_completion(cqv, tag(2), 1);
+    CQ_EXPECT_COMPLETION(cqv, tag(103), 1);
+    CQ_EXPECT_COMPLETION(cqv, tag(2), 1);
     cq_verify(cqv);
 
     GPR_ASSERT(response_payload_recv->type == GRPC_BB_RAW);
@@ -484,10 +482,10 @@
   error = grpc_call_start_batch(s, ops, (size_t)(op - ops), tag(104), NULL);
   GPR_ASSERT(GRPC_CALL_OK == error);
 
-  cq_expect_completion(cqv, tag(1), 1);
-  cq_expect_completion(cqv, tag(3), 1);
-  cq_expect_completion(cqv, tag(101), 1);
-  cq_expect_completion(cqv, tag(104), 1);
+  CQ_EXPECT_COMPLETION(cqv, tag(1), 1);
+  CQ_EXPECT_COMPLETION(cqv, tag(3), 1);
+  CQ_EXPECT_COMPLETION(cqv, tag(101), 1);
+  CQ_EXPECT_COMPLETION(cqv, tag(104), 1);
   cq_verify(cqv);
 
   GPR_ASSERT(status == GRPC_STATUS_OK);
diff --git a/test/core/end2end/tests/connectivity.c b/test/core/end2end/tests/connectivity.c
index 5775976..260297e 100644
--- a/test/core/end2end/tests/connectivity.c
+++ b/test/core/end2end/tests/connectivity.c
@@ -102,7 +102,7 @@
                                         f.cq, tag(2));
 
   /* and now the watch should trigger */
-  cq_expect_completion(cqv, tag(2), 1);
+  CQ_EXPECT_COMPLETION(cqv, tag(2), 1);
   cq_verify(cqv);
   state = grpc_channel_check_connectivity_state(f.client, 0);
   GPR_ASSERT(state == GRPC_CHANNEL_TRANSIENT_FAILURE ||
@@ -112,7 +112,7 @@
   grpc_channel_watch_connectivity_state(f.client, GRPC_CHANNEL_CONNECTING,
                                         GRPC_TIMEOUT_SECONDS_TO_DEADLINE(3),
                                         f.cq, tag(3));
-  cq_expect_completion(cqv, tag(3), 1);
+  CQ_EXPECT_COMPLETION(cqv, tag(3), 1);
   cq_verify(cqv);
   state = grpc_channel_check_connectivity_state(f.client, 0);
   GPR_ASSERT(state == GRPC_CHANNEL_TRANSIENT_FAILURE ||
@@ -130,7 +130,7 @@
   while (state != GRPC_CHANNEL_READY) {
     grpc_channel_watch_connectivity_state(
         f.client, state, GRPC_TIMEOUT_SECONDS_TO_DEADLINE(3), f.cq, tag(4));
-    cq_expect_completion(cqv, tag(4), 1);
+    CQ_EXPECT_COMPLETION(cqv, tag(4), 1);
     cq_verify(cqv);
     state = grpc_channel_check_connectivity_state(f.client, 0);
     GPR_ASSERT(state == GRPC_CHANNEL_READY ||
@@ -148,8 +148,8 @@
 
   grpc_server_shutdown_and_notify(f.server, f.cq, tag(0xdead));
 
-  cq_expect_completion(cqv, tag(5), 1);
-  cq_expect_completion(cqv, tag(0xdead), 1);
+  CQ_EXPECT_COMPLETION(cqv, tag(5), 1);
+  CQ_EXPECT_COMPLETION(cqv, tag(0xdead), 1);
   cq_verify(cqv);
   state = grpc_channel_check_connectivity_state(f.client, 0);
   GPR_ASSERT(state == GRPC_CHANNEL_TRANSIENT_FAILURE ||
diff --git a/test/core/end2end/tests/default_host.c b/test/core/end2end/tests/default_host.c
index 728ee59..208e316 100644
--- a/test/core/end2end/tests/default_host.c
+++ b/test/core/end2end/tests/default_host.c
@@ -45,8 +45,6 @@
 #include "src/core/lib/support/string.h"
 #include "test/core/end2end/cq_verifier.h"
 
-enum { TIMEOUT = 200000 };
-
 static void *tag(intptr_t t) { return (void *)t; }
 
 static grpc_end2end_test_fixture begin_test(grpc_end2end_test_config config,
@@ -162,7 +160,7 @@
       grpc_server_request_call(f.server, &s, &call_details,
                                &request_metadata_recv, f.cq, f.cq, tag(101));
   GPR_ASSERT(error == GRPC_CALL_OK);
-  cq_expect_completion(cqv, tag(101), 1);
+  CQ_EXPECT_COMPLETION(cqv, tag(101), 1);
   cq_verify(cqv);
 
   peer = grpc_call_get_peer(s);
@@ -196,8 +194,8 @@
   error = grpc_call_start_batch(s, ops, (size_t)(op - ops), tag(102), NULL);
   GPR_ASSERT(error == GRPC_CALL_OK);
 
-  cq_expect_completion(cqv, tag(102), 1);
-  cq_expect_completion(cqv, tag(1), 1);
+  CQ_EXPECT_COMPLETION(cqv, tag(102), 1);
+  CQ_EXPECT_COMPLETION(cqv, tag(1), 1);
   cq_verify(cqv);
 
   GPR_ASSERT(status == GRPC_STATUS_UNIMPLEMENTED);
diff --git a/test/core/end2end/tests/disappearing_server.c b/test/core/end2end/tests/disappearing_server.c
index 536fbd0..a0059b9 100644
--- a/test/core/end2end/tests/disappearing_server.c
+++ b/test/core/end2end/tests/disappearing_server.c
@@ -43,8 +43,6 @@
 #include <grpc/support/useful.h>
 #include "test/core/end2end/cq_verifier.h"
 
-enum { TIMEOUT = 200000 };
-
 static void *tag(intptr_t t) { return (void *)t; }
 
 static gpr_timespec n_seconds_time(int n) {
@@ -139,7 +137,7 @@
       grpc_server_request_call(f->server, &s, &call_details,
                                &request_metadata_recv, f->cq, f->cq, tag(101));
   GPR_ASSERT(GRPC_CALL_OK == error);
-  cq_expect_completion(cqv, tag(101), 1);
+  CQ_EXPECT_COMPLETION(cqv, tag(101), 1);
   cq_verify(cqv);
 
   /* should be able to shut down the server early
@@ -168,9 +166,9 @@
   error = grpc_call_start_batch(s, ops, (size_t)(op - ops), tag(102), NULL);
   GPR_ASSERT(GRPC_CALL_OK == error);
 
-  cq_expect_completion(cqv, tag(102), 1);
-  cq_expect_completion(cqv, tag(1), 1);
-  cq_expect_completion(cqv, tag(1000), 1);
+  CQ_EXPECT_COMPLETION(cqv, tag(102), 1);
+  CQ_EXPECT_COMPLETION(cqv, tag(1), 1);
+  CQ_EXPECT_COMPLETION(cqv, tag(1000), 1);
   cq_verify(cqv);
 
   GPR_ASSERT(status == GRPC_STATUS_UNIMPLEMENTED);
diff --git a/test/core/end2end/tests/empty_batch.c b/test/core/end2end/tests/empty_batch.c
index c05b919..ac53e18 100644
--- a/test/core/end2end/tests/empty_batch.c
+++ b/test/core/end2end/tests/empty_batch.c
@@ -45,8 +45,6 @@
 #include "src/core/lib/support/string.h"
 #include "test/core/end2end/cq_verifier.h"
 
-enum { TIMEOUT = 200000 };
-
 static void *tag(intptr_t t) { return (void *)t; }
 
 static grpc_end2end_test_fixture begin_test(grpc_end2end_test_config config,
@@ -112,7 +110,7 @@
 
   error = grpc_call_start_batch(c, op, 0, tag(1), NULL);
   GPR_ASSERT(GRPC_CALL_OK == error);
-  cq_expect_completion(cqv, tag(1), 1);
+  CQ_EXPECT_COMPLETION(cqv, tag(1), 1);
   cq_verify(cqv);
 
   grpc_call_destroy(c);
diff --git a/test/core/end2end/tests/filter_call_init_fails.c b/test/core/end2end/tests/filter_call_init_fails.c
index a09183b..a70f50a 100644
--- a/test/core/end2end/tests/filter_call_init_fails.c
+++ b/test/core/end2end/tests/filter_call_init_fails.c
@@ -174,7 +174,7 @@
                                &request_metadata_recv, f.cq, f.cq, tag(101));
   GPR_ASSERT(GRPC_CALL_OK == error);
 
-  cq_expect_completion(cqv, tag(1), 1);
+  CQ_EXPECT_COMPLETION(cqv, tag(1), 1);
   cq_verify(cqv);
 
   GPR_ASSERT(status == GRPC_STATUS_PERMISSION_DENIED);
diff --git a/test/core/end2end/tests/filter_causes_close.c b/test/core/end2end/tests/filter_causes_close.c
index c6c36d6..f14bb32 100644
--- a/test/core/end2end/tests/filter_causes_close.c
+++ b/test/core/end2end/tests/filter_causes_close.c
@@ -46,8 +46,6 @@
 #include "src/core/lib/surface/channel_init.h"
 #include "test/core/end2end/cq_verifier.h"
 
-enum { TIMEOUT = 200000 };
-
 static bool g_enable_filter = false;
 
 static void *tag(intptr_t t) { return (void *)t; }
@@ -172,7 +170,7 @@
                                &request_metadata_recv, f.cq, f.cq, tag(101));
   GPR_ASSERT(GRPC_CALL_OK == error);
 
-  cq_expect_completion(cqv, tag(1), 1);
+  CQ_EXPECT_COMPLETION(cqv, tag(1), 1);
   cq_verify(cqv);
 
   GPR_ASSERT(status == GRPC_STATUS_PERMISSION_DENIED);
@@ -211,11 +209,10 @@
     // close the stream with an error.
     gpr_slice message =
         gpr_slice_from_copied_string("Failure that's not preventable.");
-    grpc_transport_stream_op op;
-    memset(&op, 0, sizeof(op));
-    grpc_transport_stream_op_add_close(&op, GRPC_STATUS_PERMISSION_DENIED,
+    grpc_transport_stream_op *op = grpc_make_transport_stream_op(NULL);
+    grpc_transport_stream_op_add_close(op, GRPC_STATUS_PERMISSION_DENIED,
                                        &message);
-    grpc_call_next_op(exec_ctx, elem, &op);
+    grpc_call_next_op(exec_ctx, elem, op);
   }
   grpc_exec_ctx_sched(
       exec_ctx, calld->recv_im_ready,
diff --git a/test/core/end2end/tests/graceful_server_shutdown.c b/test/core/end2end/tests/graceful_server_shutdown.c
index f527b86..29347a0 100644
--- a/test/core/end2end/tests/graceful_server_shutdown.c
+++ b/test/core/end2end/tests/graceful_server_shutdown.c
@@ -43,8 +43,6 @@
 #include <grpc/support/useful.h>
 #include "test/core/end2end/cq_verifier.h"
 
-enum { TIMEOUT = 200000 };
-
 static void *tag(intptr_t t) { return (void *)t; }
 
 static grpc_end2end_test_fixture begin_test(grpc_end2end_test_config config,
@@ -154,7 +152,7 @@
       grpc_server_request_call(f.server, &s, &call_details,
                                &request_metadata_recv, f.cq, f.cq, tag(101));
   GPR_ASSERT(GRPC_CALL_OK == error);
-  cq_expect_completion(cqv, tag(101), 1);
+  CQ_EXPECT_COMPLETION(cqv, tag(101), 1);
   cq_verify(cqv);
 
   /* shutdown and destroy the server */
@@ -183,9 +181,9 @@
   error = grpc_call_start_batch(s, ops, (size_t)(op - ops), tag(102), NULL);
   GPR_ASSERT(GRPC_CALL_OK == error);
 
-  cq_expect_completion(cqv, tag(102), 1);
-  cq_expect_completion(cqv, tag(0xdead), 1);
-  cq_expect_completion(cqv, tag(1), 1);
+  CQ_EXPECT_COMPLETION(cqv, tag(102), 1);
+  CQ_EXPECT_COMPLETION(cqv, tag(0xdead), 1);
+  CQ_EXPECT_COMPLETION(cqv, tag(1), 1);
   cq_verify(cqv);
 
   grpc_call_destroy(s);
diff --git a/test/core/end2end/tests/high_initial_seqno.c b/test/core/end2end/tests/high_initial_seqno.c
index db45f5e..dab5270 100644
--- a/test/core/end2end/tests/high_initial_seqno.c
+++ b/test/core/end2end/tests/high_initial_seqno.c
@@ -47,8 +47,6 @@
 #include "src/core/lib/support/string.h"
 #include "test/core/end2end/cq_verifier.h"
 
-enum { TIMEOUT = 200000 };
-
 static void *tag(intptr_t t) { return (void *)t; }
 
 static grpc_end2end_test_fixture begin_test(grpc_end2end_test_config config,
@@ -159,7 +157,7 @@
       grpc_server_request_call(f.server, &s, &call_details,
                                &request_metadata_recv, f.cq, f.cq, tag(101));
   GPR_ASSERT(GRPC_CALL_OK == error);
-  cq_expect_completion(cqv, tag(101), 1);
+  CQ_EXPECT_COMPLETION(cqv, tag(101), 1);
   cq_verify(cqv);
 
   memset(ops, 0, sizeof(ops));
@@ -184,8 +182,8 @@
   error = grpc_call_start_batch(s, ops, (size_t)(op - ops), tag(102), NULL);
   GPR_ASSERT(GRPC_CALL_OK == error);
 
-  cq_expect_completion(cqv, tag(102), 1);
-  cq_expect_completion(cqv, tag(1), 1);
+  CQ_EXPECT_COMPLETION(cqv, tag(102), 1);
+  CQ_EXPECT_COMPLETION(cqv, tag(1), 1);
   cq_verify(cqv);
 
   GPR_ASSERT(status == GRPC_STATUS_UNIMPLEMENTED);
diff --git a/test/core/end2end/tests/hpack_size.c b/test/core/end2end/tests/hpack_size.c
index 7ff0461..fb00ae4 100644
--- a/test/core/end2end/tests/hpack_size.c
+++ b/test/core/end2end/tests/hpack_size.c
@@ -310,7 +310,7 @@
       grpc_server_request_call(f.server, &s, &call_details,
                                &request_metadata_recv, f.cq, f.cq, tag(101));
   GPR_ASSERT(GRPC_CALL_OK == error);
-  cq_expect_completion(cqv, tag(101), 1);
+  CQ_EXPECT_COMPLETION(cqv, tag(101), 1);
   cq_verify(cqv);
 
   memset(ops, 0, sizeof(ops));
@@ -335,8 +335,8 @@
   error = grpc_call_start_batch(s, ops, (size_t)(op - ops), tag(102), NULL);
   GPR_ASSERT(GRPC_CALL_OK == error);
 
-  cq_expect_completion(cqv, tag(102), 1);
-  cq_expect_completion(cqv, tag(1), 1);
+  CQ_EXPECT_COMPLETION(cqv, tag(102), 1);
+  CQ_EXPECT_COMPLETION(cqv, tag(1), 1);
   cq_verify(cqv);
 
   GPR_ASSERT(status == GRPC_STATUS_UNIMPLEMENTED);
diff --git a/test/core/end2end/tests/idempotent_request.c b/test/core/end2end/tests/idempotent_request.c
index dfedcfe..65f6dd0 100644
--- a/test/core/end2end/tests/idempotent_request.c
+++ b/test/core/end2end/tests/idempotent_request.c
@@ -45,8 +45,6 @@
 #include "src/core/lib/support/string.h"
 #include "test/core/end2end/cq_verifier.h"
 
-enum { TIMEOUT = 200000 };
-
 static void *tag(intptr_t t) { return (void *)t; }
 
 static grpc_end2end_test_fixture begin_test(grpc_end2end_test_config config,
@@ -163,7 +161,7 @@
       grpc_server_request_call(f.server, &s, &call_details,
                                &request_metadata_recv, f.cq, f.cq, tag(101));
   GPR_ASSERT(GRPC_CALL_OK == error);
-  cq_expect_completion(cqv, tag(101), 1);
+  CQ_EXPECT_COMPLETION(cqv, tag(101), 1);
   cq_verify(cqv);
 
   peer = grpc_call_get_peer(s);
@@ -197,8 +195,8 @@
   error = grpc_call_start_batch(s, ops, (size_t)(op - ops), tag(102), NULL);
   GPR_ASSERT(GRPC_CALL_OK == error);
 
-  cq_expect_completion(cqv, tag(102), 1);
-  cq_expect_completion(cqv, tag(1), 1);
+  CQ_EXPECT_COMPLETION(cqv, tag(102), 1);
+  CQ_EXPECT_COMPLETION(cqv, tag(1), 1);
   cq_verify(cqv);
 
   GPR_ASSERT(status == GRPC_STATUS_UNIMPLEMENTED);
diff --git a/test/core/end2end/tests/invoke_large_request.c b/test/core/end2end/tests/invoke_large_request.c
index 9c9ca95..a62fb01 100644
--- a/test/core/end2end/tests/invoke_large_request.c
+++ b/test/core/end2end/tests/invoke_large_request.c
@@ -43,8 +43,6 @@
 #include <grpc/support/useful.h>
 #include "test/core/end2end/cq_verifier.h"
 
-enum { TIMEOUT = 200000 };
-
 static void *tag(intptr_t t) { return (void *)t; }
 
 static grpc_end2end_test_fixture begin_test(grpc_end2end_test_config config,
@@ -179,7 +177,7 @@
       grpc_server_request_call(f.server, &s, &call_details,
                                &request_metadata_recv, f.cq, f.cq, tag(101));
   GPR_ASSERT(GRPC_CALL_OK == error);
-  cq_expect_completion(cqv, tag(101), 1);
+  CQ_EXPECT_COMPLETION(cqv, tag(101), 1);
   cq_verify(cqv);
 
   memset(ops, 0, sizeof(ops));
@@ -197,7 +195,7 @@
   error = grpc_call_start_batch(s, ops, (size_t)(op - ops), tag(102), NULL);
   GPR_ASSERT(GRPC_CALL_OK == error);
 
-  cq_expect_completion(cqv, tag(102), 1);
+  CQ_EXPECT_COMPLETION(cqv, tag(102), 1);
   cq_verify(cqv);
 
   memset(ops, 0, sizeof(ops));
@@ -222,8 +220,8 @@
   error = grpc_call_start_batch(s, ops, (size_t)(op - ops), tag(103), NULL);
   GPR_ASSERT(GRPC_CALL_OK == error);
 
-  cq_expect_completion(cqv, tag(103), 1);
-  cq_expect_completion(cqv, tag(1), 1);
+  CQ_EXPECT_COMPLETION(cqv, tag(103), 1);
+  CQ_EXPECT_COMPLETION(cqv, tag(1), 1);
   cq_verify(cqv);
 
   GPR_ASSERT(status == GRPC_STATUS_UNIMPLEMENTED);
diff --git a/test/core/end2end/tests/large_metadata.c b/test/core/end2end/tests/large_metadata.c
index 1f27896..eb174a2 100644
--- a/test/core/end2end/tests/large_metadata.c
+++ b/test/core/end2end/tests/large_metadata.c
@@ -43,8 +43,6 @@
 #include <grpc/support/useful.h>
 #include "test/core/end2end/cq_verifier.h"
 
-enum { TIMEOUT = 200000 };
-
 static void *tag(intptr_t t) { return (void *)t; }
 
 static grpc_end2end_test_fixture begin_test(grpc_end2end_test_config config,
@@ -181,7 +179,7 @@
                                &request_metadata_recv, f.cq, f.cq, tag(101));
   GPR_ASSERT(GRPC_CALL_OK == error);
 
-  cq_expect_completion(cqv, tag(101), 1);
+  CQ_EXPECT_COMPLETION(cqv, tag(101), 1);
   cq_verify(cqv);
 
   memset(ops, 0, sizeof(ops));
@@ -200,7 +198,7 @@
   error = grpc_call_start_batch(s, ops, (size_t)(op - ops), tag(102), NULL);
   GPR_ASSERT(GRPC_CALL_OK == error);
 
-  cq_expect_completion(cqv, tag(102), 1);
+  CQ_EXPECT_COMPLETION(cqv, tag(102), 1);
   cq_verify(cqv);
 
   memset(ops, 0, sizeof(ops));
@@ -222,8 +220,8 @@
   error = grpc_call_start_batch(s, ops, (size_t)(op - ops), tag(103), NULL);
   GPR_ASSERT(GRPC_CALL_OK == error);
 
-  cq_expect_completion(cqv, tag(103), 1);
-  cq_expect_completion(cqv, tag(1), 1);
+  CQ_EXPECT_COMPLETION(cqv, tag(103), 1);
+  CQ_EXPECT_COMPLETION(cqv, tag(1), 1);
   cq_verify(cqv);
 
   GPR_ASSERT(status == GRPC_STATUS_OK);
diff --git a/test/core/end2end/tests/load_reporting_hook.c b/test/core/end2end/tests/load_reporting_hook.c
index 2c65198..59d054c 100644
--- a/test/core/end2end/tests/load_reporting_hook.c
+++ b/test/core/end2end/tests/load_reporting_hook.c
@@ -204,7 +204,7 @@
       grpc_server_request_call(f.server, &s, &call_details,
                                &request_metadata_recv, f.cq, f.cq, tag(101));
   GPR_ASSERT(GRPC_CALL_OK == error);
-  cq_expect_completion(cqv, tag(101), 1);
+  CQ_EXPECT_COMPLETION(cqv, tag(101), 1);
   cq_verify(cqv);
 
   memset(ops, 0, sizeof(ops));
@@ -222,7 +222,7 @@
   error = grpc_call_start_batch(s, ops, (size_t)(op - ops), tag(102), NULL);
   GPR_ASSERT(GRPC_CALL_OK == error);
 
-  cq_expect_completion(cqv, tag(102), 1);
+  CQ_EXPECT_COMPLETION(cqv, tag(102), 1);
   cq_verify(cqv);
 
   memset(ops, 0, sizeof(ops));
@@ -249,8 +249,8 @@
   error = grpc_call_start_batch(s, ops, (size_t)(op - ops), tag(103), NULL);
   GPR_ASSERT(GRPC_CALL_OK == error);
 
-  cq_expect_completion(cqv, tag(103), 1);
-  cq_expect_completion(cqv, tag(1), 1);
+  CQ_EXPECT_COMPLETION(cqv, tag(103), 1);
+  CQ_EXPECT_COMPLETION(cqv, tag(1), 1);
   cq_verify(cqv);
 
   GPR_ASSERT(status == GRPC_STATUS_OK);
diff --git a/test/core/end2end/tests/max_concurrent_streams.c b/test/core/end2end/tests/max_concurrent_streams.c
index 41de74f..65fa946 100644
--- a/test/core/end2end/tests/max_concurrent_streams.c
+++ b/test/core/end2end/tests/max_concurrent_streams.c
@@ -43,8 +43,6 @@
 #include <grpc/support/useful.h>
 #include "test/core/end2end/cq_verifier.h"
 
-enum { TIMEOUT = 200000 };
-
 static void *tag(intptr_t t) { return (void *)t; }
 
 static grpc_end2end_test_fixture begin_test(grpc_end2end_test_config config,
@@ -155,7 +153,7 @@
       grpc_server_request_call(f.server, &s, &call_details,
                                &request_metadata_recv, f.cq, f.cq, tag(101));
   GPR_ASSERT(GRPC_CALL_OK == error);
-  cq_expect_completion(cqv, tag(101), 1);
+  CQ_EXPECT_COMPLETION(cqv, tag(101), 1);
   cq_verify(cqv);
 
   memset(ops, 0, sizeof(ops));
@@ -180,8 +178,8 @@
   error = grpc_call_start_batch(s, ops, (size_t)(op - ops), tag(102), NULL);
   GPR_ASSERT(GRPC_CALL_OK == error);
 
-  cq_expect_completion(cqv, tag(102), 1);
-  cq_expect_completion(cqv, tag(1), 1);
+  CQ_EXPECT_COMPLETION(cqv, tag(102), 1);
+  CQ_EXPECT_COMPLETION(cqv, tag(1), 1);
   cq_verify(cqv);
 
   GPR_ASSERT(status == GRPC_STATUS_UNIMPLEMENTED);
@@ -382,17 +380,17 @@
   error = grpc_call_start_batch(s1, ops, (size_t)(op - ops), tag(102), NULL);
   GPR_ASSERT(GRPC_CALL_OK == error);
 
-  cq_expect_completion(cqv, tag(102), 1);
-  cq_expect_completion(cqv, tag(live_call + 2), 1);
+  CQ_EXPECT_COMPLETION(cqv, tag(102), 1);
+  CQ_EXPECT_COMPLETION(cqv, tag(live_call + 2), 1);
   /* first request is finished, we should be able to start the second */
   live_call = (live_call == 300) ? 400 : 300;
-  cq_expect_completion(cqv, tag(live_call + 1), 1);
+  CQ_EXPECT_COMPLETION(cqv, tag(live_call + 1), 1);
   cq_verify(cqv);
 
   GPR_ASSERT(GRPC_CALL_OK == grpc_server_request_call(
                                  f.server, &s2, &call_details,
                                  &request_metadata_recv, f.cq, f.cq, tag(201)));
-  cq_expect_completion(cqv, tag(201), 1);
+  CQ_EXPECT_COMPLETION(cqv, tag(201), 1);
   cq_verify(cqv);
 
   memset(ops, 0, sizeof(ops));
@@ -417,8 +415,8 @@
   error = grpc_call_start_batch(s2, ops, (size_t)(op - ops), tag(202), NULL);
   GPR_ASSERT(GRPC_CALL_OK == error);
 
-  cq_expect_completion(cqv, tag(live_call + 2), 1);
-  cq_expect_completion(cqv, tag(202), 1);
+  CQ_EXPECT_COMPLETION(cqv, tag(live_call + 2), 1);
+  CQ_EXPECT_COMPLETION(cqv, tag(202), 1);
   cq_verify(cqv);
 
   cq_verifier_destroy(cqv);
diff --git a/test/core/end2end/tests/max_message_length.c b/test/core/end2end/tests/max_message_length.c
index 08d326a..43f71f5 100644
--- a/test/core/end2end/tests/max_message_length.c
+++ b/test/core/end2end/tests/max_message_length.c
@@ -43,8 +43,6 @@
 #include <grpc/support/useful.h>
 #include "test/core/end2end/cq_verifier.h"
 
-enum { TIMEOUT = 200000 };
-
 static void *tag(intptr_t t) { return (void *)t; }
 
 static grpc_end2end_test_fixture begin_test(grpc_end2end_test_config config,
@@ -179,7 +177,7 @@
       grpc_server_request_call(f.server, &s, &call_details,
                                &request_metadata_recv, f.cq, f.cq, tag(101));
   GPR_ASSERT(GRPC_CALL_OK == error);
-  cq_expect_completion(cqv, tag(101), 1);
+  CQ_EXPECT_COMPLETION(cqv, tag(101), 1);
   cq_verify(cqv);
 
   memset(ops, 0, sizeof(ops));
@@ -197,8 +195,8 @@
   error = grpc_call_start_batch(s, ops, (size_t)(op - ops), tag(102), NULL);
   GPR_ASSERT(GRPC_CALL_OK == error);
 
-  cq_expect_completion(cqv, tag(102), 1);
-  cq_expect_completion(cqv, tag(1), 1);
+  CQ_EXPECT_COMPLETION(cqv, tag(102), 1);
+  CQ_EXPECT_COMPLETION(cqv, tag(1), 1);
   cq_verify(cqv);
 
   GPR_ASSERT(status != GRPC_STATUS_OK);
diff --git a/test/core/end2end/tests/negative_deadline.c b/test/core/end2end/tests/negative_deadline.c
index dff7992..c999ac1 100644
--- a/test/core/end2end/tests/negative_deadline.c
+++ b/test/core/end2end/tests/negative_deadline.c
@@ -45,8 +45,6 @@
 #include "src/core/lib/support/string.h"
 #include "test/core/end2end/cq_verifier.h"
 
-enum { TIMEOUT = 200000 };
-
 static void *tag(intptr_t t) { return (void *)t; }
 
 static grpc_end2end_test_fixture begin_test(grpc_end2end_test_config config,
@@ -150,7 +148,7 @@
   error = grpc_call_start_batch(c, ops, num_ops, tag(1), NULL);
   GPR_ASSERT(GRPC_CALL_OK == error);
 
-  cq_expect_completion(cqv, tag(1), 1);
+  CQ_EXPECT_COMPLETION(cqv, tag(1), 1);
   cq_verify(cqv);
 
   GPR_ASSERT(status == GRPC_STATUS_DEADLINE_EXCEEDED);
diff --git a/test/core/end2end/tests/network_status_change.c b/test/core/end2end/tests/network_status_change.c
index 39ddc13..1d4b6db 100644
--- a/test/core/end2end/tests/network_status_change.c
+++ b/test/core/end2end/tests/network_status_change.c
@@ -46,8 +46,6 @@
 /* this is a private API but exposed here for testing*/
 extern void grpc_network_status_shutdown_all_endpoints();
 
-enum { TIMEOUT = 200000 };
-
 static void *tag(intptr_t t) { return (void *)t; }
 
 static grpc_end2end_test_fixture begin_test(grpc_end2end_test_config config,
@@ -168,7 +166,7 @@
   GPR_ASSERT(GRPC_CALL_OK == grpc_server_request_call(
                                  f.server, &s, &call_details,
                                  &request_metadata_recv, f.cq, f.cq, tag(101)));
-  cq_expect_completion(cqv, tag(101), 1);
+  CQ_EXPECT_COMPLETION(cqv, tag(101), 1);
   cq_verify(cqv);
 
   op = ops;
@@ -185,7 +183,7 @@
   error = grpc_call_start_batch(s, ops, (size_t)(op - ops), tag(102), NULL);
   GPR_ASSERT(GRPC_CALL_OK == error);
 
-  cq_expect_completion(cqv, tag(102), 1);
+  CQ_EXPECT_COMPLETION(cqv, tag(102), 1);
   cq_verify(cqv);
 
   // Simulate the network loss event
@@ -207,8 +205,8 @@
   error = grpc_call_start_batch(s, ops, (size_t)(op - ops), tag(103), NULL);
   GPR_ASSERT(GRPC_CALL_OK == error);
 
-  cq_expect_completion(cqv, tag(103), 1);
-  cq_expect_completion(cqv, tag(1), 1);
+  CQ_EXPECT_COMPLETION(cqv, tag(103), 1);
+  CQ_EXPECT_COMPLETION(cqv, tag(1), 1);
   cq_verify(cqv);
 
   // Expected behavior of a RPC when network is lost.
diff --git a/test/core/end2end/tests/no_logging.c b/test/core/end2end/tests/no_logging.c
new file mode 100644
index 0000000..d03d336
--- /dev/null
+++ b/test/core/end2end/tests/no_logging.c
@@ -0,0 +1,295 @@
+/*
+ *
+ * Copyright 2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "test/core/end2end/end2end_tests.h"
+
+#include <stdio.h>
+#include <string.h>
+
+#include <grpc/byte_buffer.h>
+#include <grpc/grpc.h>
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+#include <grpc/support/string_util.h>
+#include <grpc/support/time.h>
+#include <grpc/support/useful.h>
+#include "src/core/lib/iomgr/error.h"
+#include "src/core/lib/support/string.h"
+#include "test/core/end2end/cq_verifier.h"
+
+enum { TIMEOUT = 200000 };
+
+static void *tag(intptr_t t) { return (void *)t; }
+
+extern void gpr_default_log(gpr_log_func_args *args);
+
+static void test_no_log(gpr_log_func_args *args) {
+  char *message = NULL;
+  gpr_asprintf(&message, "Unwanted log: %s", args->message);
+  args->message = message;
+  gpr_default_log(args);
+  gpr_free(message);
+  abort();
+}
+
+static void test_no_error_log(gpr_log_func_args *args) {
+  if (args->severity == GPR_LOG_SEVERITY_ERROR) {
+    test_no_log(args);
+  }
+}
+
+static grpc_end2end_test_fixture begin_test(grpc_end2end_test_config config,
+                                            const char *test_name,
+                                            grpc_channel_args *client_args,
+                                            grpc_channel_args *server_args) {
+  grpc_end2end_test_fixture f;
+  gpr_log(GPR_INFO, "%s/%s", test_name, config.name);
+  f = config.create_fixture(client_args, server_args);
+  config.init_server(&f, server_args);
+  config.init_client(&f, client_args);
+  return f;
+}
+
+static gpr_timespec n_seconds_time(int n) {
+  return GRPC_TIMEOUT_SECONDS_TO_DEADLINE(n);
+}
+
+static gpr_timespec five_seconds_time(void) { return n_seconds_time(5); }
+
+static void drain_cq(grpc_completion_queue *cq) {
+  grpc_event ev;
+  do {
+    ev = grpc_completion_queue_next(cq, five_seconds_time(), NULL);
+  } while (ev.type != GRPC_QUEUE_SHUTDOWN);
+}
+
+static void shutdown_server(grpc_end2end_test_fixture *f) {
+  if (!f->server) return;
+  grpc_server_shutdown_and_notify(f->server, f->cq, tag(1000));
+  GPR_ASSERT(grpc_completion_queue_pluck(
+                 f->cq, tag(1000), GRPC_TIMEOUT_SECONDS_TO_DEADLINE(5), NULL)
+                 .type == GRPC_OP_COMPLETE);
+  grpc_server_destroy(f->server);
+  f->server = NULL;
+}
+
+static void shutdown_client(grpc_end2end_test_fixture *f) {
+  if (!f->client) return;
+  grpc_channel_destroy(f->client);
+  f->client = NULL;
+}
+
+static void end_test(grpc_end2end_test_fixture *f) {
+  shutdown_server(f);
+  shutdown_client(f);
+
+  grpc_completion_queue_shutdown(f->cq);
+  drain_cq(f->cq);
+  grpc_completion_queue_destroy(f->cq);
+}
+
+static void simple_request_body(grpc_end2end_test_fixture f) {
+  grpc_call *c;
+  grpc_call *s;
+  gpr_timespec deadline = five_seconds_time();
+  cq_verifier *cqv = cq_verifier_create(f.cq);
+  grpc_op ops[6];
+  grpc_op *op;
+  grpc_metadata_array initial_metadata_recv;
+  grpc_metadata_array trailing_metadata_recv;
+  grpc_metadata_array request_metadata_recv;
+  grpc_call_details call_details;
+  grpc_status_code status;
+  grpc_call_error error;
+  char *details = NULL;
+  size_t details_capacity = 0;
+  int was_cancelled = 2;
+  char *peer;
+
+  c = grpc_channel_create_call(f.client, NULL, GRPC_PROPAGATE_DEFAULTS, f.cq,
+                               "/foo", "foo.test.google.fr:1234", deadline,
+                               NULL);
+  GPR_ASSERT(c);
+
+  peer = grpc_call_get_peer(c);
+  GPR_ASSERT(peer != NULL);
+  gpr_free(peer);
+
+  grpc_metadata_array_init(&initial_metadata_recv);
+  grpc_metadata_array_init(&trailing_metadata_recv);
+  grpc_metadata_array_init(&request_metadata_recv);
+  grpc_call_details_init(&call_details);
+
+  memset(ops, 0, sizeof(ops));
+  op = ops;
+  op->op = GRPC_OP_SEND_INITIAL_METADATA;
+  op->data.send_initial_metadata.count = 0;
+  op->flags = 0;
+  op->reserved = NULL;
+  op++;
+  op->op = GRPC_OP_SEND_CLOSE_FROM_CLIENT;
+  op->flags = 0;
+  op->reserved = NULL;
+  op++;
+  op->op = GRPC_OP_RECV_INITIAL_METADATA;
+  op->data.recv_initial_metadata = &initial_metadata_recv;
+  op->flags = 0;
+  op->reserved = NULL;
+  op++;
+  op->op = GRPC_OP_RECV_STATUS_ON_CLIENT;
+  op->data.recv_status_on_client.trailing_metadata = &trailing_metadata_recv;
+  op->data.recv_status_on_client.status = &status;
+  op->data.recv_status_on_client.status_details = &details;
+  op->data.recv_status_on_client.status_details_capacity = &details_capacity;
+  op->flags = 0;
+  op->reserved = NULL;
+  op++;
+  error = grpc_call_start_batch(c, ops, (size_t)(op - ops), tag(1), NULL);
+  GPR_ASSERT(GRPC_CALL_OK == error);
+
+  error =
+      grpc_server_request_call(f.server, &s, &call_details,
+                               &request_metadata_recv, f.cq, f.cq, tag(101));
+  GPR_ASSERT(GRPC_CALL_OK == error);
+  CQ_EXPECT_COMPLETION(cqv, tag(101), 1);
+  cq_verify(cqv);
+
+  peer = grpc_call_get_peer(s);
+  GPR_ASSERT(peer != NULL);
+  gpr_free(peer);
+  peer = grpc_call_get_peer(c);
+  GPR_ASSERT(peer != NULL);
+  gpr_free(peer);
+
+  memset(ops, 0, sizeof(ops));
+  op = ops;
+  op->op = GRPC_OP_SEND_INITIAL_METADATA;
+  op->data.send_initial_metadata.count = 0;
+  op->flags = 0;
+  op->reserved = NULL;
+  op++;
+  op->op = GRPC_OP_SEND_STATUS_FROM_SERVER;
+  op->data.send_status_from_server.trailing_metadata_count = 0;
+  op->data.send_status_from_server.status = GRPC_STATUS_UNIMPLEMENTED;
+  op->data.send_status_from_server.status_details = "xyz";
+  op->flags = 0;
+  op->reserved = NULL;
+  op++;
+  op->op = GRPC_OP_RECV_CLOSE_ON_SERVER;
+  op->data.recv_close_on_server.cancelled = &was_cancelled;
+  op->flags = 0;
+  op->reserved = NULL;
+  op++;
+  error = grpc_call_start_batch(s, ops, (size_t)(op - ops), tag(102), NULL);
+  GPR_ASSERT(GRPC_CALL_OK == error);
+
+  CQ_EXPECT_COMPLETION(cqv, tag(102), 1);
+  CQ_EXPECT_COMPLETION(cqv, tag(1), 1);
+  cq_verify(cqv);
+
+  GPR_ASSERT(status == GRPC_STATUS_UNIMPLEMENTED);
+  GPR_ASSERT(0 == strcmp(details, "xyz"));
+  GPR_ASSERT(0 == strcmp(call_details.method, "/foo"));
+  GPR_ASSERT(0 == strcmp(call_details.host, "foo.test.google.fr:1234"));
+  GPR_ASSERT(0 == call_details.flags);
+  GPR_ASSERT(was_cancelled == 1);
+
+  gpr_free(details);
+  grpc_metadata_array_destroy(&initial_metadata_recv);
+  grpc_metadata_array_destroy(&trailing_metadata_recv);
+  grpc_metadata_array_destroy(&request_metadata_recv);
+  grpc_call_details_destroy(&call_details);
+
+  grpc_call_destroy(c);
+  grpc_call_destroy(s);
+
+  cq_verifier_destroy(cqv);
+}
+
+static void test_invoke_simple_request(grpc_end2end_test_config config) {
+  grpc_end2end_test_fixture f;
+
+  f = begin_test(config, "test_invoke_simple_request_with_no_error_logging",
+                 NULL, NULL);
+  simple_request_body(f);
+  end_test(&f);
+  config.tear_down_data(&f);
+}
+
+static void test_invoke_10_simple_requests(grpc_end2end_test_config config) {
+  int i;
+  grpc_end2end_test_fixture f =
+      begin_test(config, "test_invoke_10_simple_requests_with_no_error_logging",
+                 NULL, NULL);
+  for (i = 0; i < 10; i++) {
+    simple_request_body(f);
+    gpr_log(GPR_INFO, "Passed simple request %d", i);
+  }
+  simple_request_body(f);
+  end_test(&f);
+  config.tear_down_data(&f);
+}
+
+static void test_no_error_logging_in_entire_process(
+    grpc_end2end_test_config config) {
+  int i;
+  gpr_set_log_function(test_no_error_log);
+  for (i = 0; i < 10; i++) {
+    test_invoke_simple_request(config);
+  }
+  test_invoke_10_simple_requests(config);
+  gpr_set_log_function(gpr_default_log);
+}
+
+static void test_no_logging_in_one_request(grpc_end2end_test_config config) {
+  int i;
+  grpc_end2end_test_fixture f =
+      begin_test(config, "test_no_logging_in_last_request", NULL, NULL);
+  for (i = 0; i < 10; i++) {
+    simple_request_body(f);
+  }
+  gpr_set_log_function(test_no_log);
+  simple_request_body(f);
+  gpr_set_log_function(gpr_default_log);
+  end_test(&f);
+  config.tear_down_data(&f);
+}
+
+void no_logging(grpc_end2end_test_config config) {
+  gpr_set_log_verbosity(GPR_LOG_SEVERITY_DEBUG);
+  grpc_tracer_set_enabled("all", 0);
+  test_no_logging_in_one_request(config);
+  test_no_error_logging_in_entire_process(config);
+}
+
+void no_logging_pre_init(void) {}
diff --git a/test/core/end2end/tests/no_op.c b/test/core/end2end/tests/no_op.c
index 284be7a..8b29c21 100644
--- a/test/core/end2end/tests/no_op.c
+++ b/test/core/end2end/tests/no_op.c
@@ -43,8 +43,6 @@
 #include <grpc/support/useful.h>
 #include "test/core/end2end/cq_verifier.h"
 
-enum { TIMEOUT = 200000 };
-
 static void *tag(intptr_t t) { return (void *)t; }
 
 static grpc_end2end_test_fixture begin_test(grpc_end2end_test_config config,
diff --git a/test/core/end2end/tests/payload.c b/test/core/end2end/tests/payload.c
index 443d85e..c71704f 100644
--- a/test/core/end2end/tests/payload.c
+++ b/test/core/end2end/tests/payload.c
@@ -43,8 +43,6 @@
 #include <grpc/support/useful.h>
 #include "test/core/end2end/cq_verifier.h"
 
-enum { TIMEOUT = 200000 };
-
 static void *tag(intptr_t t) { return (void *)t; }
 
 static grpc_end2end_test_fixture begin_test(grpc_end2end_test_config config,
@@ -172,7 +170,7 @@
       grpc_server_request_call(f.server, &s, &call_details,
                                &request_metadata_recv, f.cq, f.cq, tag(101));
   GPR_ASSERT(GRPC_CALL_OK == error);
-  cq_expect_completion(cqv, tag(101), 1);
+  CQ_EXPECT_COMPLETION(cqv, tag(101), 1);
   cq_verify(cqv);
 
   memset(ops, 0, sizeof(ops));
@@ -190,7 +188,7 @@
   error = grpc_call_start_batch(s, ops, (size_t)(op - ops), tag(102), NULL);
   GPR_ASSERT(GRPC_CALL_OK == error);
 
-  cq_expect_completion(cqv, tag(102), 1);
+  CQ_EXPECT_COMPLETION(cqv, tag(102), 1);
   cq_verify(cqv);
 
   memset(ops, 0, sizeof(ops));
@@ -215,8 +213,8 @@
   error = grpc_call_start_batch(s, ops, (size_t)(op - ops), tag(103), NULL);
   GPR_ASSERT(GRPC_CALL_OK == error);
 
-  cq_expect_completion(cqv, tag(103), 1);
-  cq_expect_completion(cqv, tag(1), 1);
+  CQ_EXPECT_COMPLETION(cqv, tag(103), 1);
+  CQ_EXPECT_COMPLETION(cqv, tag(1), 1);
   cq_verify(cqv);
 
   GPR_ASSERT(status == GRPC_STATUS_OK);
diff --git a/test/core/end2end/tests/ping.c b/test/core/end2end/tests/ping.c
index d49bec9..5e5169d 100644
--- a/test/core/end2end/tests/ping.c
+++ b/test/core/end2end/tests/ping.c
@@ -52,7 +52,7 @@
   config.init_server(&f, NULL);
 
   grpc_channel_ping(f.client, f.cq, tag(0), NULL);
-  cq_expect_completion(cqv, tag(0), 0);
+  CQ_EXPECT_COMPLETION(cqv, tag(0), 0);
 
   /* check that we're still in idle, and start connecting */
   GPR_ASSERT(grpc_channel_check_connectivity_state(f.client, 1) ==
@@ -62,7 +62,7 @@
   while (state != GRPC_CHANNEL_READY) {
     grpc_channel_watch_connectivity_state(
         f.client, state, GRPC_TIMEOUT_SECONDS_TO_DEADLINE(3), f.cq, tag(99));
-    cq_expect_completion(cqv, tag(99), 1);
+    CQ_EXPECT_COMPLETION(cqv, tag(99), 1);
     cq_verify(cqv);
     state = grpc_channel_check_connectivity_state(f.client, 0);
     GPR_ASSERT(state == GRPC_CHANNEL_READY ||
@@ -72,12 +72,12 @@
 
   for (i = 1; i <= 5; i++) {
     grpc_channel_ping(f.client, f.cq, tag(i), NULL);
-    cq_expect_completion(cqv, tag(i), 1);
+    CQ_EXPECT_COMPLETION(cqv, tag(i), 1);
     cq_verify(cqv);
   }
 
   grpc_server_shutdown_and_notify(f.server, f.cq, tag(0xdead));
-  cq_expect_completion(cqv, tag(0xdead), 1);
+  CQ_EXPECT_COMPLETION(cqv, tag(0xdead), 1);
   cq_verify(cqv);
 
   /* cleanup server */
diff --git a/test/core/end2end/tests/ping_pong_streaming.c b/test/core/end2end/tests/ping_pong_streaming.c
index 1d2f794..7e360c4 100644
--- a/test/core/end2end/tests/ping_pong_streaming.c
+++ b/test/core/end2end/tests/ping_pong_streaming.c
@@ -43,8 +43,6 @@
 #include <grpc/support/useful.h>
 #include "test/core/end2end/cq_verifier.h"
 
-enum { TIMEOUT = 200000 };
-
 static void *tag(intptr_t t) { return (void *)t; }
 
 static grpc_end2end_test_fixture begin_test(grpc_end2end_test_config config,
@@ -162,7 +160,7 @@
       grpc_server_request_call(f.server, &s, &call_details,
                                &request_metadata_recv, f.cq, f.cq, tag(100));
   GPR_ASSERT(GRPC_CALL_OK == error);
-  cq_expect_completion(cqv, tag(100), 1);
+  CQ_EXPECT_COMPLETION(cqv, tag(100), 1);
   cq_verify(cqv);
 
   memset(ops, 0, sizeof(ops));
@@ -208,7 +206,7 @@
     op++;
     error = grpc_call_start_batch(s, ops, (size_t)(op - ops), tag(102), NULL);
     GPR_ASSERT(GRPC_CALL_OK == error);
-    cq_expect_completion(cqv, tag(102), 1);
+    CQ_EXPECT_COMPLETION(cqv, tag(102), 1);
     cq_verify(cqv);
 
     memset(ops, 0, sizeof(ops));
@@ -220,8 +218,8 @@
     op++;
     error = grpc_call_start_batch(s, ops, (size_t)(op - ops), tag(103), NULL);
     GPR_ASSERT(GRPC_CALL_OK == error);
-    cq_expect_completion(cqv, tag(103), 1);
-    cq_expect_completion(cqv, tag(2), 1);
+    CQ_EXPECT_COMPLETION(cqv, tag(103), 1);
+    CQ_EXPECT_COMPLETION(cqv, tag(2), 1);
     cq_verify(cqv);
 
     grpc_byte_buffer_destroy(request_payload);
@@ -254,10 +252,10 @@
   error = grpc_call_start_batch(s, ops, (size_t)(op - ops), tag(104), NULL);
   GPR_ASSERT(GRPC_CALL_OK == error);
 
-  cq_expect_completion(cqv, tag(1), 1);
-  cq_expect_completion(cqv, tag(3), 1);
-  cq_expect_completion(cqv, tag(101), 1);
-  cq_expect_completion(cqv, tag(104), 1);
+  CQ_EXPECT_COMPLETION(cqv, tag(1), 1);
+  CQ_EXPECT_COMPLETION(cqv, tag(3), 1);
+  CQ_EXPECT_COMPLETION(cqv, tag(101), 1);
+  CQ_EXPECT_COMPLETION(cqv, tag(104), 1);
   cq_verify(cqv);
 
   grpc_call_destroy(c);
diff --git a/test/core/end2end/tests/registered_call.c b/test/core/end2end/tests/registered_call.c
index ece6250..9b2b42b 100644
--- a/test/core/end2end/tests/registered_call.c
+++ b/test/core/end2end/tests/registered_call.c
@@ -45,8 +45,6 @@
 #include "src/core/lib/support/string.h"
 #include "test/core/end2end/cq_verifier.h"
 
-enum { TIMEOUT = 200000 };
-
 static void *tag(intptr_t t) { return (void *)t; }
 
 static grpc_end2end_test_fixture begin_test(grpc_end2end_test_config config,
@@ -156,7 +154,7 @@
       grpc_server_request_call(f.server, &s, &call_details,
                                &request_metadata_recv, f.cq, f.cq, tag(101));
   GPR_ASSERT(GRPC_CALL_OK == error);
-  cq_expect_completion(cqv, tag(101), 1);
+  CQ_EXPECT_COMPLETION(cqv, tag(101), 1);
   cq_verify(cqv);
 
   memset(ops, 0, sizeof(ops));
@@ -181,8 +179,8 @@
   error = grpc_call_start_batch(s, ops, (size_t)(op - ops), tag(102), NULL);
   GPR_ASSERT(GRPC_CALL_OK == error);
 
-  cq_expect_completion(cqv, tag(102), 1);
-  cq_expect_completion(cqv, tag(1), 1);
+  CQ_EXPECT_COMPLETION(cqv, tag(102), 1);
+  CQ_EXPECT_COMPLETION(cqv, tag(1), 1);
   cq_verify(cqv);
 
   GPR_ASSERT(status == GRPC_STATUS_UNIMPLEMENTED);
diff --git a/test/core/end2end/tests/request_with_flags.c b/test/core/end2end/tests/request_with_flags.c
index b5d398b..25150e6 100644
--- a/test/core/end2end/tests/request_with_flags.c
+++ b/test/core/end2end/tests/request_with_flags.c
@@ -44,8 +44,6 @@
 #include "src/core/lib/transport/byte_stream.h"
 #include "test/core/end2end/cq_verifier.h"
 
-enum { TIMEOUT = 200000 };
-
 static void *tag(intptr_t t) { return (void *)t; }
 
 static grpc_end2end_test_fixture begin_test(grpc_end2end_test_config config,
@@ -165,7 +163,7 @@
   GPR_ASSERT(expectation == error);
 
   if (expectation == GRPC_CALL_OK) {
-    cq_expect_completion(cqv, tag(1), 1);
+    CQ_EXPECT_COMPLETION(cqv, tag(1), 1);
     cq_verify(cqv);
   }
 
diff --git a/test/core/end2end/tests/request_with_payload.c b/test/core/end2end/tests/request_with_payload.c
index d94267e..67208c0 100644
--- a/test/core/end2end/tests/request_with_payload.c
+++ b/test/core/end2end/tests/request_with_payload.c
@@ -43,8 +43,6 @@
 #include <grpc/support/useful.h>
 #include "test/core/end2end/cq_verifier.h"
 
-enum { TIMEOUT = 200000 };
-
 static void *tag(intptr_t t) { return (void *)t; }
 
 static grpc_end2end_test_fixture begin_test(grpc_end2end_test_config config,
@@ -165,7 +163,7 @@
   GPR_ASSERT(GRPC_CALL_OK == grpc_server_request_call(
                                  f.server, &s, &call_details,
                                  &request_metadata_recv, f.cq, f.cq, tag(101)));
-  cq_expect_completion(cqv, tag(101), 1);
+  CQ_EXPECT_COMPLETION(cqv, tag(101), 1);
   cq_verify(cqv);
 
   memset(ops, 0, sizeof(ops));
@@ -183,7 +181,7 @@
   error = grpc_call_start_batch(s, ops, (size_t)(op - ops), tag(102), NULL);
   GPR_ASSERT(GRPC_CALL_OK == error);
 
-  cq_expect_completion(cqv, tag(102), 1);
+  CQ_EXPECT_COMPLETION(cqv, tag(102), 1);
   cq_verify(cqv);
 
   memset(ops, 0, sizeof(ops));
@@ -203,8 +201,8 @@
   error = grpc_call_start_batch(s, ops, (size_t)(op - ops), tag(103), NULL);
   GPR_ASSERT(GRPC_CALL_OK == error);
 
-  cq_expect_completion(cqv, tag(103), 1);
-  cq_expect_completion(cqv, tag(1), 1);
+  CQ_EXPECT_COMPLETION(cqv, tag(103), 1);
+  CQ_EXPECT_COMPLETION(cqv, tag(1), 1);
   cq_verify(cqv);
 
   GPR_ASSERT(status == GRPC_STATUS_OK);
diff --git a/test/core/end2end/tests/server_finishes_request.c b/test/core/end2end/tests/server_finishes_request.c
index a723c6f..7fb9025 100644
--- a/test/core/end2end/tests/server_finishes_request.c
+++ b/test/core/end2end/tests/server_finishes_request.c
@@ -45,8 +45,6 @@
 #include "src/core/lib/support/string.h"
 #include "test/core/end2end/cq_verifier.h"
 
-enum { TIMEOUT = 200000 };
-
 static void *tag(intptr_t t) { return (void *)t; }
 
 static grpc_end2end_test_fixture begin_test(grpc_end2end_test_config config,
@@ -153,7 +151,7 @@
       grpc_server_request_call(f.server, &s, &call_details,
                                &request_metadata_recv, f.cq, f.cq, tag(101));
   GPR_ASSERT(GRPC_CALL_OK == error);
-  cq_expect_completion(cqv, tag(101), 1);
+  CQ_EXPECT_COMPLETION(cqv, tag(101), 1);
   cq_verify(cqv);
 
   memset(ops, 0, sizeof(ops));
@@ -178,8 +176,8 @@
   error = grpc_call_start_batch(s, ops, (size_t)(op - ops), tag(102), NULL);
   GPR_ASSERT(GRPC_CALL_OK == error);
 
-  cq_expect_completion(cqv, tag(102), 1);
-  cq_expect_completion(cqv, tag(1), 1);
+  CQ_EXPECT_COMPLETION(cqv, tag(102), 1);
+  CQ_EXPECT_COMPLETION(cqv, tag(1), 1);
   cq_verify(cqv);
 
   GPR_ASSERT(status == GRPC_STATUS_UNIMPLEMENTED);
diff --git a/test/core/end2end/tests/shutdown_finishes_calls.c b/test/core/end2end/tests/shutdown_finishes_calls.c
index abb6b26..dff2e6f 100644
--- a/test/core/end2end/tests/shutdown_finishes_calls.c
+++ b/test/core/end2end/tests/shutdown_finishes_calls.c
@@ -43,8 +43,6 @@
 #include <grpc/support/useful.h>
 #include "test/core/end2end/cq_verifier.h"
 
-enum { TIMEOUT = 200000 };
-
 static void *tag(intptr_t t) { return (void *)t; }
 
 static grpc_end2end_test_fixture begin_test(grpc_end2end_test_config config,
@@ -147,7 +145,7 @@
       grpc_server_request_call(f.server, &s, &call_details,
                                &request_metadata_recv, f.cq, f.cq, tag(101));
   GPR_ASSERT(GRPC_CALL_OK == error);
-  cq_expect_completion(cqv, tag(101), 1);
+  CQ_EXPECT_COMPLETION(cqv, tag(101), 1);
   cq_verify(cqv);
 
   memset(ops, 0, sizeof(ops));
@@ -164,9 +162,9 @@
   grpc_server_shutdown_and_notify(f.server, f.cq, tag(1000));
   grpc_server_cancel_all_calls(f.server);
 
-  cq_expect_completion(cqv, tag(1000), 1);
-  cq_expect_completion(cqv, tag(102), 1);
-  cq_expect_completion(cqv, tag(1), 1);
+  CQ_EXPECT_COMPLETION(cqv, tag(1000), 1);
+  CQ_EXPECT_COMPLETION(cqv, tag(102), 1);
+  CQ_EXPECT_COMPLETION(cqv, tag(1), 1);
   cq_verify(cqv);
 
   grpc_server_destroy(f.server);
diff --git a/test/core/end2end/tests/shutdown_finishes_tags.c b/test/core/end2end/tests/shutdown_finishes_tags.c
index b1f3c94..1d110a7 100644
--- a/test/core/end2end/tests/shutdown_finishes_tags.c
+++ b/test/core/end2end/tests/shutdown_finishes_tags.c
@@ -43,8 +43,6 @@
 #include <grpc/support/useful.h>
 #include "test/core/end2end/cq_verifier.h"
 
-enum { TIMEOUT = 200000 };
-
 static void *tag(intptr_t t) { return (void *)t; }
 
 static grpc_end2end_test_fixture begin_test(grpc_end2end_test_config config,
@@ -104,8 +102,8 @@
                                  f.server, &s, &call_details,
                                  &request_metadata_recv, f.cq, f.cq, tag(101)));
   grpc_server_shutdown_and_notify(f.server, f.cq, tag(1000));
-  cq_expect_completion(cqv, tag(101), 0);
-  cq_expect_completion(cqv, tag(1000), 1);
+  CQ_EXPECT_COMPLETION(cqv, tag(101), 0);
+  CQ_EXPECT_COMPLETION(cqv, tag(1000), 1);
   cq_verify(cqv);
   GPR_ASSERT(s == NULL);
 
diff --git a/test/core/end2end/tests/simple_delayed_request.c b/test/core/end2end/tests/simple_delayed_request.c
index e1fcc03..74f1232 100644
--- a/test/core/end2end/tests/simple_delayed_request.c
+++ b/test/core/end2end/tests/simple_delayed_request.c
@@ -43,8 +43,6 @@
 #include <grpc/support/useful.h>
 #include "test/core/end2end/cq_verifier.h"
 
-enum { TIMEOUT = 200000 };
-
 static void *tag(intptr_t t) { return (void *)t; }
 
 static gpr_timespec n_seconds_time(int n) {
@@ -150,7 +148,7 @@
       grpc_server_request_call(f->server, &s, &call_details,
                                &request_metadata_recv, f->cq, f->cq, tag(101));
   GPR_ASSERT(GRPC_CALL_OK == error);
-  cq_expect_completion(cqv, tag(101), 1);
+  CQ_EXPECT_COMPLETION(cqv, tag(101), 1);
   cq_verify(cqv);
 
   memset(ops, 0, sizeof(ops));
@@ -175,8 +173,8 @@
   error = grpc_call_start_batch(s, ops, (size_t)(op - ops), tag(102), NULL);
   GPR_ASSERT(GRPC_CALL_OK == error);
 
-  cq_expect_completion(cqv, tag(102), 1);
-  cq_expect_completion(cqv, tag(1), 1);
+  CQ_EXPECT_COMPLETION(cqv, tag(102), 1);
+  CQ_EXPECT_COMPLETION(cqv, tag(1), 1);
   cq_verify(cqv);
 
   GPR_ASSERT(status == GRPC_STATUS_UNIMPLEMENTED);
diff --git a/test/core/end2end/tests/simple_metadata.c b/test/core/end2end/tests/simple_metadata.c
index c9b1a03..13c77c0 100644
--- a/test/core/end2end/tests/simple_metadata.c
+++ b/test/core/end2end/tests/simple_metadata.c
@@ -43,8 +43,6 @@
 #include <grpc/support/useful.h>
 #include "test/core/end2end/cq_verifier.h"
 
-enum { TIMEOUT = 200000 };
-
 static void *tag(intptr_t t) { return (void *)t; }
 
 static grpc_end2end_test_fixture begin_test(grpc_end2end_test_config config,
@@ -183,7 +181,7 @@
       grpc_server_request_call(f.server, &s, &call_details,
                                &request_metadata_recv, f.cq, f.cq, tag(101));
   GPR_ASSERT(GRPC_CALL_OK == error);
-  cq_expect_completion(cqv, tag(101), 1);
+  CQ_EXPECT_COMPLETION(cqv, tag(101), 1);
   cq_verify(cqv);
 
   memset(ops, 0, sizeof(ops));
@@ -202,7 +200,7 @@
   error = grpc_call_start_batch(s, ops, (size_t)(op - ops), tag(102), NULL);
   GPR_ASSERT(GRPC_CALL_OK == error);
 
-  cq_expect_completion(cqv, tag(102), 1);
+  CQ_EXPECT_COMPLETION(cqv, tag(102), 1);
   cq_verify(cqv);
 
   memset(ops, 0, sizeof(ops));
@@ -227,8 +225,8 @@
   error = grpc_call_start_batch(s, ops, (size_t)(op - ops), tag(103), NULL);
   GPR_ASSERT(GRPC_CALL_OK == error);
 
-  cq_expect_completion(cqv, tag(103), 1);
-  cq_expect_completion(cqv, tag(1), 1);
+  CQ_EXPECT_COMPLETION(cqv, tag(103), 1);
+  CQ_EXPECT_COMPLETION(cqv, tag(1), 1);
   cq_verify(cqv);
 
   GPR_ASSERT(status == GRPC_STATUS_OK);
diff --git a/test/core/end2end/tests/simple_request.c b/test/core/end2end/tests/simple_request.c
index a8014e6..ed7b850 100644
--- a/test/core/end2end/tests/simple_request.c
+++ b/test/core/end2end/tests/simple_request.c
@@ -45,8 +45,6 @@
 #include "src/core/lib/support/string.h"
 #include "test/core/end2end/cq_verifier.h"
 
-enum { TIMEOUT = 200000 };
-
 static void *tag(intptr_t t) { return (void *)t; }
 
 static grpc_end2end_test_fixture begin_test(grpc_end2end_test_config config,
@@ -163,7 +161,7 @@
       grpc_server_request_call(f.server, &s, &call_details,
                                &request_metadata_recv, f.cq, f.cq, tag(101));
   GPR_ASSERT(GRPC_CALL_OK == error);
-  cq_expect_completion(cqv, tag(101), 1);
+  CQ_EXPECT_COMPLETION(cqv, tag(101), 1);
   cq_verify(cqv);
 
   peer = grpc_call_get_peer(s);
@@ -197,8 +195,8 @@
   error = grpc_call_start_batch(s, ops, (size_t)(op - ops), tag(102), NULL);
   GPR_ASSERT(GRPC_CALL_OK == error);
 
-  cq_expect_completion(cqv, tag(102), 1);
-  cq_expect_completion(cqv, tag(1), 1);
+  CQ_EXPECT_COMPLETION(cqv, tag(102), 1);
+  CQ_EXPECT_COMPLETION(cqv, tag(1), 1);
   cq_verify(cqv);
 
   GPR_ASSERT(status == GRPC_STATUS_UNIMPLEMENTED);
diff --git a/test/core/end2end/tests/streaming_error_response.c b/test/core/end2end/tests/streaming_error_response.c
index e15c132..8285468 100644
--- a/test/core/end2end/tests/streaming_error_response.c
+++ b/test/core/end2end/tests/streaming_error_response.c
@@ -43,8 +43,6 @@
 #include <grpc/support/useful.h>
 #include "test/core/end2end/cq_verifier.h"
 
-enum { TIMEOUT = 200000 };
-
 static void *tag(intptr_t t) { return (void *)t; }
 
 static grpc_end2end_test_fixture begin_test(grpc_end2end_test_config config,
@@ -163,7 +161,7 @@
   GPR_ASSERT(GRPC_CALL_OK == grpc_server_request_call(
                                  f.server, &s, &call_details,
                                  &request_metadata_recv, f.cq, f.cq, tag(101)));
-  cq_expect_completion(cqv, tag(101), 1);
+  CQ_EXPECT_COMPLETION(cqv, tag(101), 1);
   cq_verify(cqv);
 
   memset(ops, 0, sizeof(ops));
@@ -177,7 +175,7 @@
   error = grpc_call_start_batch(s, ops, (size_t)(op - ops), tag(102), NULL);
   GPR_ASSERT(GRPC_CALL_OK == error);
 
-  cq_expect_completion(cqv, tag(102), 1);
+  CQ_EXPECT_COMPLETION(cqv, tag(102), 1);
   cq_verify(cqv);
 
   memset(ops, 0, sizeof(ops));
@@ -188,9 +186,9 @@
   error = grpc_call_start_batch(s, ops, (size_t)(op - ops), tag(103), NULL);
   GPR_ASSERT(GRPC_CALL_OK == error);
 
-  cq_expect_completion(cqv, tag(103), 1);
+  CQ_EXPECT_COMPLETION(cqv, tag(103), 1);
   if (!request_status_early) {
-    cq_expect_completion(cqv, tag(1), 1);
+    CQ_EXPECT_COMPLETION(cqv, tag(1), 1);
   }
   cq_verify(cqv);
 
@@ -217,11 +215,11 @@
     GPR_ASSERT(GRPC_CALL_OK == error);
   }
 
-  cq_expect_completion(cqv, tag(104), 1);
+  CQ_EXPECT_COMPLETION(cqv, tag(104), 1);
   if (request_status_early) {
-    cq_expect_completion(cqv, tag(1), 1);
+    CQ_EXPECT_COMPLETION(cqv, tag(1), 1);
   } else {
-    cq_expect_completion(cqv, tag(2), 1);
+    CQ_EXPECT_COMPLETION(cqv, tag(2), 1);
   }
   cq_verify(cqv);
 
@@ -237,7 +235,7 @@
     error = grpc_call_start_batch(c, ops, (size_t)(op - ops), tag(3), NULL);
     GPR_ASSERT(GRPC_CALL_OK == error);
 
-    cq_expect_completion(cqv, tag(3), 1);
+    CQ_EXPECT_COMPLETION(cqv, tag(3), 1);
     cq_verify(cqv);
 
     GPR_ASSERT(response_payload1_recv != NULL);
diff --git a/test/core/end2end/tests/trailing_metadata.c b/test/core/end2end/tests/trailing_metadata.c
index 41e0f00..d7093ae 100644
--- a/test/core/end2end/tests/trailing_metadata.c
+++ b/test/core/end2end/tests/trailing_metadata.c
@@ -43,8 +43,6 @@
 #include <grpc/support/useful.h>
 #include "test/core/end2end/cq_verifier.h"
 
-enum { TIMEOUT = 200000 };
-
 static void *tag(intptr_t t) { return (void *)t; }
 
 static grpc_end2end_test_fixture begin_test(grpc_end2end_test_config config,
@@ -186,7 +184,7 @@
       grpc_server_request_call(f.server, &s, &call_details,
                                &request_metadata_recv, f.cq, f.cq, tag(101));
   GPR_ASSERT(GRPC_CALL_OK == error);
-  cq_expect_completion(cqv, tag(101), 1);
+  CQ_EXPECT_COMPLETION(cqv, tag(101), 1);
   cq_verify(cqv);
 
   memset(ops, 0, sizeof(ops));
@@ -205,7 +203,7 @@
   error = grpc_call_start_batch(s, ops, (size_t)(op - ops), tag(102), NULL);
   GPR_ASSERT(GRPC_CALL_OK == error);
 
-  cq_expect_completion(cqv, tag(102), 1);
+  CQ_EXPECT_COMPLETION(cqv, tag(102), 1);
   cq_verify(cqv);
 
   memset(ops, 0, sizeof(ops));
@@ -231,8 +229,8 @@
   error = grpc_call_start_batch(s, ops, (size_t)(op - ops), tag(103), NULL);
   GPR_ASSERT(GRPC_CALL_OK == error);
 
-  cq_expect_completion(cqv, tag(103), 1);
-  cq_expect_completion(cqv, tag(1), 1);
+  CQ_EXPECT_COMPLETION(cqv, tag(103), 1);
+  CQ_EXPECT_COMPLETION(cqv, tag(1), 1);
   cq_verify(cqv);
 
   GPR_ASSERT(status == GRPC_STATUS_OK);
diff --git a/test/core/iomgr/combiner_test.c b/test/core/iomgr/combiner_test.c
new file mode 100644
index 0000000..f7d5809
--- /dev/null
+++ b/test/core/iomgr/combiner_test.c
@@ -0,0 +1,165 @@
+/*
+ *
+ * Copyright 2015, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "src/core/lib/iomgr/combiner.h"
+
+#include <grpc/grpc.h>
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+#include <grpc/support/thd.h>
+#include <grpc/support/useful.h>
+
+#include "test/core/util/test_config.h"
+
+static void test_no_op(void) {
+  gpr_log(GPR_DEBUG, "test_no_op");
+  grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+  grpc_combiner_destroy(&exec_ctx, grpc_combiner_create(NULL));
+  grpc_exec_ctx_finish(&exec_ctx);
+}
+
+static void set_bool_to_true(grpc_exec_ctx *exec_ctx, void *value,
+                             grpc_error *error) {
+  *(bool *)value = true;
+}
+
+static void test_execute_one(void) {
+  gpr_log(GPR_DEBUG, "test_execute_one");
+
+  grpc_combiner *lock = grpc_combiner_create(NULL);
+  bool done = false;
+  grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+  grpc_combiner_execute(&exec_ctx, lock,
+                        grpc_closure_create(set_bool_to_true, &done),
+                        GRPC_ERROR_NONE, false);
+  grpc_exec_ctx_flush(&exec_ctx);
+  GPR_ASSERT(done);
+  grpc_combiner_destroy(&exec_ctx, lock);
+  grpc_exec_ctx_finish(&exec_ctx);
+}
+
+typedef struct {
+  size_t ctr;
+  grpc_combiner *lock;
+} thd_args;
+
+typedef struct {
+  size_t *ctr;
+  size_t value;
+} ex_args;
+
+static void check_one(grpc_exec_ctx *exec_ctx, void *a, grpc_error *error) {
+  ex_args *args = a;
+  GPR_ASSERT(*args->ctr == args->value - 1);
+  *args->ctr = args->value;
+  gpr_free(a);
+}
+
+static void execute_many_loop(void *a) {
+  thd_args *args = a;
+  grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+  size_t n = 1;
+  for (size_t i = 0; i < 10; i++) {
+    for (size_t j = 0; j < 10000; j++) {
+      ex_args *c = gpr_malloc(sizeof(*c));
+      c->ctr = &args->ctr;
+      c->value = n++;
+      grpc_combiner_execute(&exec_ctx, args->lock,
+                            grpc_closure_create(check_one, c), GRPC_ERROR_NONE,
+                            false);
+      grpc_exec_ctx_flush(&exec_ctx);
+    }
+    // sleep for a little bit, to test a combiner draining and another thread
+    // picking it up
+    gpr_sleep_until(GRPC_TIMEOUT_MILLIS_TO_DEADLINE(100));
+  }
+  grpc_exec_ctx_finish(&exec_ctx);
+}
+
+static void test_execute_many(void) {
+  gpr_log(GPR_DEBUG, "test_execute_many");
+
+  grpc_combiner *lock = grpc_combiner_create(NULL);
+  gpr_thd_id thds[100];
+  thd_args ta[GPR_ARRAY_SIZE(thds)];
+  for (size_t i = 0; i < GPR_ARRAY_SIZE(thds); i++) {
+    gpr_thd_options options = gpr_thd_options_default();
+    gpr_thd_options_set_joinable(&options);
+    ta[i].ctr = 0;
+    ta[i].lock = lock;
+    GPR_ASSERT(gpr_thd_new(&thds[i], execute_many_loop, &ta[i], &options));
+  }
+  for (size_t i = 0; i < GPR_ARRAY_SIZE(thds); i++) {
+    gpr_thd_join(thds[i]);
+  }
+  grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+  grpc_combiner_destroy(&exec_ctx, lock);
+  grpc_exec_ctx_finish(&exec_ctx);
+}
+
+static bool got_in_finally = false;
+
+static void in_finally(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *error) {
+  got_in_finally = true;
+}
+
+static void add_finally(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *error) {
+  grpc_combiner_execute_finally(exec_ctx, arg,
+                                grpc_closure_create(in_finally, NULL),
+                                GRPC_ERROR_NONE, false);
+}
+
+static void test_execute_finally(void) {
+  gpr_log(GPR_DEBUG, "test_execute_finally");
+
+  grpc_combiner *lock = grpc_combiner_create(NULL);
+  grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+  grpc_combiner_execute(&exec_ctx, lock, grpc_closure_create(add_finally, lock),
+                        GRPC_ERROR_NONE, false);
+  grpc_exec_ctx_flush(&exec_ctx);
+  GPR_ASSERT(got_in_finally);
+  grpc_combiner_destroy(&exec_ctx, lock);
+  grpc_exec_ctx_finish(&exec_ctx);
+}
+
+int main(int argc, char **argv) {
+  grpc_test_init(argc, argv);
+  grpc_init();
+  test_no_op();
+  test_execute_one();
+  test_execute_finally();
+  test_execute_many();
+  grpc_shutdown();
+
+  return 0;
+}
diff --git a/test/core/support/mpscq_test.c b/test/core/support/mpscq_test.c
new file mode 100644
index 0000000..491eb91
--- /dev/null
+++ b/test/core/support/mpscq_test.c
@@ -0,0 +1,206 @@
+/*
+ *
+ * Copyright 2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "src/core/lib/support/mpscq.h"
+
+#include <stdlib.h>
+
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+#include <grpc/support/sync.h>
+#include <grpc/support/thd.h>
+#include <grpc/support/useful.h>
+#include "test/core/util/test_config.h"
+
+typedef struct test_node {
+  gpr_mpscq_node node;
+  size_t i;
+  size_t *ctr;
+} test_node;
+
+static test_node *new_node(size_t i, size_t *ctr) {
+  test_node *n = gpr_malloc(sizeof(test_node));
+  n->i = i;
+  n->ctr = ctr;
+  return n;
+}
+
+static void test_serial(void) {
+  gpr_log(GPR_DEBUG, "test_serial");
+  gpr_mpscq q;
+  gpr_mpscq_init(&q);
+  for (size_t i = 0; i < 10000000; i++) {
+    gpr_mpscq_push(&q, &new_node(i, NULL)->node);
+  }
+  for (size_t i = 0; i < 10000000; i++) {
+    test_node *n = (test_node *)gpr_mpscq_pop(&q);
+    GPR_ASSERT(n);
+    GPR_ASSERT(n->i == i);
+    gpr_free(n);
+  }
+}
+
+typedef struct {
+  size_t ctr;
+  gpr_mpscq *q;
+  gpr_event *start;
+} thd_args;
+
+#define THREAD_ITERATIONS 100000
+
+static void test_thread(void *args) {
+  thd_args *a = args;
+  gpr_event_wait(a->start, gpr_inf_future(GPR_CLOCK_REALTIME));
+  for (size_t i = 1; i <= THREAD_ITERATIONS; i++) {
+    gpr_mpscq_push(a->q, &new_node(i, &a->ctr)->node);
+  }
+}
+
+static void test_mt(void) {
+  gpr_log(GPR_DEBUG, "test_mt");
+  gpr_event start;
+  gpr_event_init(&start);
+  gpr_thd_id thds[100];
+  thd_args ta[GPR_ARRAY_SIZE(thds)];
+  gpr_mpscq q;
+  gpr_mpscq_init(&q);
+  for (size_t i = 0; i < GPR_ARRAY_SIZE(thds); i++) {
+    gpr_thd_options options = gpr_thd_options_default();
+    gpr_thd_options_set_joinable(&options);
+    ta[i].ctr = 0;
+    ta[i].q = &q;
+    ta[i].start = &start;
+    GPR_ASSERT(gpr_thd_new(&thds[i], test_thread, &ta[i], &options));
+  }
+  size_t num_done = 0;
+  size_t spins = 0;
+  gpr_event_set(&start, (void *)1);
+  while (num_done != GPR_ARRAY_SIZE(thds)) {
+    gpr_mpscq_node *n;
+    while ((n = gpr_mpscq_pop(&q)) == NULL) {
+      spins++;
+    }
+    test_node *tn = (test_node *)n;
+    GPR_ASSERT(*tn->ctr == tn->i - 1);
+    *tn->ctr = tn->i;
+    if (tn->i == THREAD_ITERATIONS) num_done++;
+    gpr_free(tn);
+  }
+  gpr_log(GPR_DEBUG, "spins: %" PRIdPTR, spins);
+  for (size_t i = 0; i < GPR_ARRAY_SIZE(thds); i++) {
+    gpr_thd_join(thds[i]);
+  }
+  gpr_mpscq_destroy(&q);
+}
+
+typedef struct {
+  thd_args *ta;
+  size_t num_thds;
+  gpr_mu mu;
+  size_t num_done;
+  size_t spins;
+  gpr_mpscq *q;
+  gpr_event *start;
+} pull_args;
+
+static void pull_thread(void *arg) {
+  pull_args *pa = arg;
+  gpr_event_wait(pa->start, gpr_inf_future(GPR_CLOCK_REALTIME));
+
+  for (;;) {
+    gpr_mu_lock(&pa->mu);
+    if (pa->num_done == pa->num_thds) {
+      gpr_mu_unlock(&pa->mu);
+      return;
+    }
+    gpr_mpscq_node *n;
+    while ((n = gpr_mpscq_pop(pa->q)) == NULL) {
+      pa->spins++;
+    }
+    test_node *tn = (test_node *)n;
+    GPR_ASSERT(*tn->ctr == tn->i - 1);
+    *tn->ctr = tn->i;
+    if (tn->i == THREAD_ITERATIONS) pa->num_done++;
+    gpr_free(tn);
+    gpr_mu_unlock(&pa->mu);
+  }
+}
+
+static void test_mt_multipop(void) {
+  gpr_log(GPR_DEBUG, "test_mt_multipop");
+  gpr_event start;
+  gpr_event_init(&start);
+  gpr_thd_id thds[100];
+  gpr_thd_id pull_thds[100];
+  thd_args ta[GPR_ARRAY_SIZE(thds)];
+  gpr_mpscq q;
+  gpr_mpscq_init(&q);
+  for (size_t i = 0; i < GPR_ARRAY_SIZE(thds); i++) {
+    gpr_thd_options options = gpr_thd_options_default();
+    gpr_thd_options_set_joinable(&options);
+    ta[i].ctr = 0;
+    ta[i].q = &q;
+    ta[i].start = &start;
+    GPR_ASSERT(gpr_thd_new(&thds[i], test_thread, &ta[i], &options));
+  }
+  pull_args pa;
+  pa.ta = ta;
+  pa.num_thds = GPR_ARRAY_SIZE(thds);
+  pa.spins = 0;
+  pa.num_done = 0;
+  pa.q = &q;
+  pa.start = &start;
+  gpr_mu_init(&pa.mu);
+  for (size_t i = 0; i < GPR_ARRAY_SIZE(pull_thds); i++) {
+    gpr_thd_options options = gpr_thd_options_default();
+    gpr_thd_options_set_joinable(&options);
+    GPR_ASSERT(gpr_thd_new(&pull_thds[i], pull_thread, &pa, &options));
+  }
+  gpr_event_set(&start, (void *)1);
+  for (size_t i = 0; i < GPR_ARRAY_SIZE(pull_thds); i++) {
+    gpr_thd_join(pull_thds[i]);
+  }
+  gpr_log(GPR_DEBUG, "spins: %" PRIdPTR, pa.spins);
+  for (size_t i = 0; i < GPR_ARRAY_SIZE(thds); i++) {
+    gpr_thd_join(thds[i]);
+  }
+  gpr_mpscq_destroy(&q);
+}
+
+int main(int argc, char **argv) {
+  grpc_test_init(argc, argv);
+  test_serial();
+  test_mt();
+  test_mt_multipop();
+  return 0;
+}
diff --git a/test/core/support/string_test.c b/test/core/support/string_test.c
index 553a824..378e45a 100644
--- a/test/core/support/string_test.c
+++ b/test/core/support/string_test.c
@@ -366,6 +366,13 @@
   gpr_free(padded);
 }
 
+static void test_stricmp(void) {
+  GPR_ASSERT(0 == gpr_stricmp("hello", "hello"));
+  GPR_ASSERT(0 == gpr_stricmp("HELLO", "hello"));
+  GPR_ASSERT(gpr_stricmp("a", "b") < 0);
+  GPR_ASSERT(gpr_stricmp("b", "a") > 0);
+}
+
 int main(int argc, char **argv) {
   grpc_test_init(argc, argv);
   test_strdup();
@@ -379,5 +386,6 @@
   test_ltoa();
   test_int64toa();
   test_leftpad();
+  test_stricmp();
   return 0;
 }
diff --git a/test/core/surface/lame_client_test.c b/test/core/surface/lame_client_test.c
index f36f980..6afcefc 100644
--- a/test/core/surface/lame_client_test.c
+++ b/test/core/surface/lame_client_test.c
@@ -49,32 +49,31 @@
 
 void verify_connectivity(grpc_exec_ctx *exec_ctx, void *arg,
                          grpc_error *error) {
-  grpc_transport_op *op = arg;
-  GPR_ASSERT(GRPC_CHANNEL_SHUTDOWN == *op->connectivity_state);
+  grpc_connectivity_state *state = arg;
+  GPR_ASSERT(GRPC_CHANNEL_SHUTDOWN == *state);
   GPR_ASSERT(error == GRPC_ERROR_NONE);
 }
 
 void do_nothing(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *error) {}
 
 void test_transport_op(grpc_channel *channel) {
-  grpc_transport_op op;
+  grpc_transport_op *op;
   grpc_channel_element *elem;
   grpc_connectivity_state state = GRPC_CHANNEL_IDLE;
   grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
 
-  memset(&op, 0, sizeof(op));
-  grpc_closure_init(&transport_op_cb, verify_connectivity, &op);
+  grpc_closure_init(&transport_op_cb, verify_connectivity, &state);
 
-  op.on_connectivity_state_change = &transport_op_cb;
-  op.connectivity_state = &state;
+  op = grpc_make_transport_op(NULL);
+  op->on_connectivity_state_change = &transport_op_cb;
+  op->connectivity_state = &state;
   elem = grpc_channel_stack_element(grpc_channel_get_channel_stack(channel), 0);
-  elem->filter->start_transport_op(&exec_ctx, elem, &op);
+  elem->filter->start_transport_op(&exec_ctx, elem, op);
   grpc_exec_ctx_finish(&exec_ctx);
 
-  memset(&op, 0, sizeof(op));
   grpc_closure_init(&transport_op_cb, do_nothing, NULL);
-  op.on_consumed = &transport_op_cb;
-  elem->filter->start_transport_op(&exec_ctx, elem, &op);
+  op = grpc_make_transport_op(&transport_op_cb);
+  elem->filter->start_transport_op(&exec_ctx, elem, op);
   grpc_exec_ctx_finish(&exec_ctx);
 }
 
@@ -132,7 +131,7 @@
   GPR_ASSERT(GRPC_CALL_OK == error);
 
   /* the call should immediately fail */
-  cq_expect_completion(cqv, tag(1), 0);
+  CQ_EXPECT_COMPLETION(cqv, tag(1), 0);
   cq_verify(cqv);
 
   memset(ops, 0, sizeof(ops));
@@ -149,7 +148,7 @@
   GPR_ASSERT(GRPC_CALL_OK == error);
 
   /* the call should immediately fail */
-  cq_expect_completion(cqv, tag(2), 1);
+  CQ_EXPECT_COMPLETION(cqv, tag(2), 1);
   cq_verify(cqv);
 
   peer = grpc_call_get_peer(call);
diff --git a/test/core/transport/chttp2/hpack_parser_fuzzer_test.c b/test/core/transport/chttp2/hpack_parser_fuzzer_test.c
index b7f68e0..95acbf1 100644
--- a/test/core/transport/chttp2/hpack_parser_fuzzer_test.c
+++ b/test/core/transport/chttp2/hpack_parser_fuzzer_test.c
@@ -43,7 +43,9 @@
 bool squelch = true;
 bool leak_check = true;
 
-static void onhdr(void *ud, grpc_mdelem *md) { GRPC_MDELEM_UNREF(md); }
+static void onhdr(grpc_exec_ctx *exec_ctx, void *ud, grpc_mdelem *md) {
+  GRPC_MDELEM_UNREF(md);
+}
 static void dont_log(gpr_log_func_args *args) {}
 
 int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
@@ -53,7 +55,10 @@
   grpc_chttp2_hpack_parser parser;
   grpc_chttp2_hpack_parser_init(&parser);
   parser.on_header = onhdr;
-  GRPC_ERROR_UNREF(grpc_chttp2_hpack_parser_parse(&parser, data, data + size));
+  grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+  GRPC_ERROR_UNREF(
+      grpc_chttp2_hpack_parser_parse(&exec_ctx, &parser, data, data + size));
+  grpc_exec_ctx_finish(&exec_ctx);
   grpc_chttp2_hpack_parser_destroy(&parser);
   grpc_shutdown();
   return 0;
diff --git a/test/core/transport/chttp2/hpack_parser_test.c b/test/core/transport/chttp2/hpack_parser_test.c
index 9ddceb8..55b64f5 100644
--- a/test/core/transport/chttp2/hpack_parser_test.c
+++ b/test/core/transport/chttp2/hpack_parser_test.c
@@ -45,7 +45,7 @@
 
 typedef struct { va_list args; } test_checker;
 
-static void onhdr(void *ud, grpc_mdelem *md) {
+static void onhdr(grpc_exec_ctx *exec_ctx, void *ud, grpc_mdelem *md) {
   const char *ekey, *evalue;
   test_checker *chk = ud;
   ekey = va_arg(chk->args, char *);
@@ -75,9 +75,11 @@
   gpr_slice_unref(input);
 
   for (i = 0; i < nslices; i++) {
+    grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
     GPR_ASSERT(grpc_chttp2_hpack_parser_parse(
-                   parser, GPR_SLICE_START_PTR(slices[i]),
+                   &exec_ctx, parser, GPR_SLICE_START_PTR(slices[i]),
                    GPR_SLICE_END_PTR(slices[i])) == GRPC_ERROR_NONE);
+    grpc_exec_ctx_finish(&exec_ctx);
   }
 
   for (i = 0; i < nslices; i++) {
diff --git a/test/cpp/end2end/thread_stress_test.cc b/test/cpp/end2end/thread_stress_test.cc
index b021b34..ebede19 100644
--- a/test/cpp/end2end/thread_stress_test.cc
+++ b/test/cpp/end2end/thread_stress_test.cc
@@ -339,7 +339,10 @@
     ClientContext context;
     Status s = stub->Echo(&context, request, &response);
     EXPECT_EQ(response.message(), request.message());
-    EXPECT_TRUE(s.ok());
+    if (!s.ok()) {
+      gpr_log(GPR_ERROR, "RPC error: %d: %s", s.error_code(), s.error_message().c_str());
+    }
+    ASSERT_TRUE(s.ok());
   }
 }
 
diff --git a/test/cpp/grpclb/grpclb_test.cc b/test/cpp/grpclb/grpclb_test.cc
index b2fdce2..a4aa973 100644
--- a/test/cpp/grpclb/grpclb_test.cc
+++ b/test/cpp/grpclb/grpclb_test.cc
@@ -177,7 +177,7 @@
                                    tag(200));
   GPR_ASSERT(GRPC_CALL_OK == error);
   gpr_log(GPR_INFO, "LB Server[%s] up", sf->servers_hostport);
-  cq_expect_completion(cqv, tag(200), 1);
+  CQ_EXPECT_COMPLETION(cqv, tag(200), 1);
   cq_verify(cqv);
   gpr_log(GPR_INFO, "LB Server[%s] after tag 200", sf->servers_hostport);
 
@@ -205,7 +205,7 @@
   op++;
   error = grpc_call_start_batch(s, ops, (size_t)(op - ops), tag(202), NULL);
   GPR_ASSERT(GRPC_CALL_OK == error);
-  cq_expect_completion(cqv, tag(202), 1);
+  CQ_EXPECT_COMPLETION(cqv, tag(202), 1);
   cq_verify(cqv);
   gpr_log(GPR_INFO, "LB Server[%s] after RECV_MSG", sf->servers_hostport);
   // TODO(dgq): validate request.
@@ -233,7 +233,7 @@
     op++;
     error = grpc_call_start_batch(s, ops, (size_t)(op - ops), tag(203), NULL);
     GPR_ASSERT(GRPC_CALL_OK == error);
-    cq_expect_completion(cqv, tag(203), 1);
+    CQ_EXPECT_COMPLETION(cqv, tag(203), 1);
     cq_verify(cqv);
     gpr_log(GPR_INFO, "LB Server[%s] after SEND_MESSAGE, iter %d",
             sf->servers_hostport, i);
@@ -254,8 +254,8 @@
   error = grpc_call_start_batch(s, ops, (size_t)(op - ops), tag(204), NULL);
   GPR_ASSERT(GRPC_CALL_OK == error);
 
-  cq_expect_completion(cqv, tag(201), 1);
-  cq_expect_completion(cqv, tag(204), 1);
+  CQ_EXPECT_COMPLETION(cqv, tag(201), 1);
+  CQ_EXPECT_COMPLETION(cqv, tag(204), 1);
   cq_verify(cqv);
   gpr_log(GPR_INFO, "LB Server[%s] after tag 204. All done. LB server out",
           sf->servers_hostport);
@@ -394,8 +394,8 @@
     error = grpc_call_start_batch(s, ops, (size_t)(op - ops), tag(104), NULL);
     GPR_ASSERT(GRPC_CALL_OK == error);
 
-    cq_expect_completion(cqv, tag(101), 1);
-    cq_expect_completion(cqv, tag(104), 1);
+    CQ_EXPECT_COMPLETION(cqv, tag(101), 1);
+    CQ_EXPECT_COMPLETION(cqv, tag(104), 1);
     cq_verify(cqv);
     gpr_log(GPR_INFO, "Server[%s] DONE. After servicing %d calls",
             sf->servers_hostport, sf->num_calls_serviced);
@@ -475,7 +475,7 @@
     GPR_ASSERT(GRPC_CALL_OK == error);
 
     peer = grpc_call_get_peer(c);
-    cq_expect_completion(cqv, tag(2), 1);
+    CQ_EXPECT_COMPLETION(cqv, tag(2), 1);
     cq_verify(cqv);
     gpr_free(peer);
 
@@ -493,8 +493,8 @@
   error = grpc_call_start_batch(c, ops, (size_t)(op - ops), tag(3), NULL);
   GPR_ASSERT(GRPC_CALL_OK == error);
 
-  cq_expect_completion(cqv, tag(1), 1);
-  cq_expect_completion(cqv, tag(3), 1);
+  CQ_EXPECT_COMPLETION(cqv, tag(1), 1);
+  CQ_EXPECT_COMPLETION(cqv, tag(3), 1);
   cq_verify(cqv);
   peer = grpc_call_get_peer(c);
   gpr_log(GPR_INFO, "Client DONE WITH SERVER %s ", peer);
diff --git a/test/cpp/qps/client_sync.cc b/test/cpp/qps/client_sync.cc
index 8062424..ef54b4b 100644
--- a/test/cpp/qps/client_sync.cc
+++ b/test/cpp/qps/client_sync.cc
@@ -130,6 +130,9 @@
     grpc::Status s =
         stub->UnaryCall(&context, request_, &responses_[thread_idx]);
     entry->set_value((UsageTimer::Now() - start) * 1e9);
+    if (!s.ok()) {
+      gpr_log(GPR_ERROR, "RPC error: %d: %s", s.error_code(), s.error_message().c_str());
+    }
     return s.ok();
   }
 };
diff --git a/test/cpp/qps/driver.cc b/test/cpp/qps/driver.cc
index b205f74..96f8150 100644
--- a/test/cpp/qps/driver.cc
+++ b/test/cpp/qps/driver.cc
@@ -45,6 +45,7 @@
 #include <grpc/support/host_port.h>
 #include <grpc/support/log.h>
 
+#include "src/core/lib/profiling/timers.h"
 #include "src/core/lib/support/env.h"
 #include "src/proto/grpc/testing/services.grpc.pb.h"
 #include "test/core/util/port.h"
@@ -313,6 +314,7 @@
   // clients is array rather than std::vector to avoid gcc-4.4 issues
   // where class contained in std::vector must have a copy constructor
   auto* clients = new ClientData[num_clients];
+  size_t channels_allocated = 0;
   for (size_t i = 0; i < num_clients; i++) {
     const auto& worker = workers[i + num_servers];
     gpr_log(GPR_INFO, "Starting client on %s (worker #%" PRIuPTR ")",
@@ -348,6 +350,16 @@
       }
     }
 
+    // Reduce channel count so that total channels specified is held regardless
+    // of the number of clients available
+    size_t num_channels =
+        (client_config.client_channels() - channels_allocated) /
+        (num_clients - i);
+    channels_allocated += num_channels;
+    gpr_log(GPR_DEBUG, "Client %" PRIdPTR " gets %" PRIdPTR " channels", i,
+            num_channels);
+    per_client_config.set_client_channels(num_channels);
+
     ClientArgs args;
     *args.mutable_setup() = per_client_config;
     clients[i].stream =
@@ -408,6 +420,8 @@
       start,
       gpr_time_from_seconds(warmup_seconds + benchmark_seconds, GPR_TIMESPAN)));
 
+  gpr_timer_set_enabled(0);
+
   // Finish a run
   std::unique_ptr<ScenarioResult> result(new ScenarioResult);
   Histogram merged_latencies;
diff --git a/test/cpp/util/grpc_tool.cc b/test/cpp/util/grpc_tool.cc
index f06053c..4af00cd 100644
--- a/test/cpp/util/grpc_tool.cc
+++ b/test/cpp/util/grpc_tool.cc
@@ -57,7 +57,7 @@
 DEFINE_string(metadata, "",
               "Metadata to send to server, in the form of key1:val1:key2:val2");
 DEFINE_string(proto_path, ".", "Path to look for the proto file.");
-DEFINE_string(proto_file, "", "Name of the proto file.");
+DEFINE_string(protofiles, "", "Name of the proto file.");
 DEFINE_bool(binary_input, false, "Input in binary format");
 DEFINE_bool(binary_output, false, "Output in binary format");
 DEFINE_string(infile, "", "Input file (default is stdin)");
@@ -71,9 +71,9 @@
   explicit GrpcTool();
   virtual ~GrpcTool() {}
 
-  bool Help(int argc, const char** argv, CliCredentials cred,
+  bool Help(int argc, const char** argv, const CliCredentials& cred,
             GrpcToolOutputCallback callback);
-  bool CallMethod(int argc, const char** argv, CliCredentials cred,
+  bool CallMethod(int argc, const char** argv, const CliCredentials& cred,
                   GrpcToolOutputCallback callback);
   // TODO(zyc): implement the following methods
   // bool ListServices(int argc, const char** argv, GrpcToolOutputCallback
@@ -101,7 +101,7 @@
 };
 
 template <typename T>
-std::function<bool(GrpcTool*, int, const char**, const CliCredentials,
+std::function<bool(GrpcTool*, int, const char**, const CliCredentials&,
                    GrpcToolOutputCallback)>
 BindWith5Args(T&& func) {
   return std::bind(std::forward<T>(func), std::placeholders::_1,
@@ -156,7 +156,7 @@
 
 struct Command {
   const char* command;
-  std::function<bool(GrpcTool*, int, const char**, const CliCredentials,
+  std::function<bool(GrpcTool*, int, const char**, const CliCredentials&,
                      GrpcToolOutputCallback)>
       function;
   int min_args;
@@ -201,7 +201,7 @@
 }
 }  // namespace
 
-int GrpcToolMainLib(int argc, const char** argv, const CliCredentials cred,
+int GrpcToolMainLib(int argc, const char** argv, const CliCredentials& cred,
                     GrpcToolOutputCallback callback) {
   if (argc < 2) {
     Usage("No command specified");
@@ -238,7 +238,7 @@
   }
 }
 
-bool GrpcTool::Help(int argc, const char** argv, const CliCredentials cred,
+bool GrpcTool::Help(int argc, const char** argv, const CliCredentials& cred,
                     GrpcToolOutputCallback callback) {
   CommandUsage(
       "Print help\n"
@@ -258,7 +258,7 @@
 }
 
 bool GrpcTool::CallMethod(int argc, const char** argv,
-                          const CliCredentials cred,
+                          const CliCredentials& cred,
                           GrpcToolOutputCallback callback) {
   CommandUsage(
       "Call method\n"
@@ -267,10 +267,10 @@
       "    <service>                ; Exported service name\n"
       "    <method>                 ; Method name\n"
       "    <request>                ; Text protobuffer (overrides infile)\n"
-      "    --proto_file             ; Comma separated proto files used as a"
+      "    --protofiles             ; Comma separated proto files used as a"
       " fallback when parsing request/response\n"
       "    --proto_path             ; The search path of proto files, valid"
-      " only when --proto_file is given\n"
+      " only when --protofiles is given\n"
       "    --metadata               ; The metadata to be sent to the server\n"
       "    --infile                 ; Input filename (defaults to stdin)\n"
       "    --outfile                ; Output filename (defaults to stdout)\n"
@@ -310,7 +310,7 @@
   if (!FLAGS_binary_input || !FLAGS_binary_output) {
     parser.reset(
         new grpc::testing::ProtoFileParser(FLAGS_remotedb ? channel : nullptr,
-                                           FLAGS_proto_path, FLAGS_proto_file));
+                                           FLAGS_proto_path, FLAGS_protofiles));
     if (parser->HasError()) {
       return false;
     }
diff --git a/test/cpp/util/grpc_tool.h b/test/cpp/util/grpc_tool.h
index 3da8693..df36802 100644
--- a/test/cpp/util/grpc_tool.h
+++ b/test/cpp/util/grpc_tool.h
@@ -45,7 +45,7 @@
 
 typedef std::function<bool(const grpc::string &)> GrpcToolOutputCallback;
 
-int GrpcToolMainLib(int argc, const char **argv, CliCredentials cred,
+int GrpcToolMainLib(int argc, const char **argv, const CliCredentials &cred,
                     GrpcToolOutputCallback callback);
 
 }  // namespace testing
diff --git a/third_party/protobuf b/third_party/protobuf
index e8ae137..bba446b 160000
--- a/third_party/protobuf
+++ b/third_party/protobuf
@@ -1 +1 @@
-Subproject commit e8ae137c96444ea313485ed1118c5e43b2099cf1
+Subproject commit bba446bbf2ac7b0b9923d4eb07d5acd0665a8cf0
diff --git a/tools/buildgen/plugins/expand_version.py b/tools/buildgen/plugins/expand_version.py
index c6cc562..6098cca 100755
--- a/tools/buildgen/plugins/expand_version.py
+++ b/tools/buildgen/plugins/expand_version.py
@@ -85,10 +85,21 @@
       return '%d.%d.%d' % (self.major, self.minor, self.patch)
 
   def php(self):
-    """Version string in PHP style"""
-    """PECL does not allow tag in version string"""
-    return '%d.%d.%d' % (self.major, self.minor, self.patch)
+    """Version string for PHP PECL package"""
+    s = '%d.%d.%d' % (self.major, self.minor, self.patch)
+    if self.tag:
+      if self.tag == 'dev':
+        s += 'dev'
+      elif len(self.tag) >= 3 and self.tag[0:3] == 'pre':
+        s += 'RC%d' % int(self.tag[3:])
+      else:
+        raise Exception('Don\'t know how to translate version tag "%s" to PECL version' % self.tag)
+    return s
 
+  def php_composer(self):
+    """Version string for PHP Composer package"""
+    return '%d.%d.%d' % (self.major, self.minor, self.patch)
+    
 def mako_plugin(dictionary):
   """Expand version numbers:
      - for each language, ensure there's a language_version tag in
diff --git a/tools/codegen/core/gen_static_metadata.py b/tools/codegen/core/gen_static_metadata.py
index 859adcb..2a16baa 100755
--- a/tools/codegen/core/gen_static_metadata.py
+++ b/tools/codegen/core/gen_static_metadata.py
@@ -42,6 +42,7 @@
 CONFIG = [
     'grpc-timeout',
     'grpc-internal-encoding-request',
+    'grpc-payload-bin',
     ':path',
     'grpc-encoding',
     'grpc-accept-encoding',
diff --git a/tools/distrib/python/grpcio_tools/setup.py b/tools/distrib/python/grpcio_tools/setup.py
index e810599..a07a586 100644
--- a/tools/distrib/python/grpcio_tools/setup.py
+++ b/tools/distrib/python/grpcio_tools/setup.py
@@ -27,6 +27,7 @@
 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
+from distutils import cygwinccompiler
 from distutils import extension
 from distutils import util
 import errno
@@ -68,26 +69,35 @@
 EXTRA_ENV_COMPILE_ARGS = os.environ.get('GRPC_PYTHON_CFLAGS', None)
 EXTRA_ENV_LINK_ARGS = os.environ.get('GRPC_PYTHON_LDFLAGS', None)
 if EXTRA_ENV_COMPILE_ARGS is None:
-  EXTRA_ENV_COMPILE_ARGS = '-fno-wrapv -frtti -std=c++11'
+  EXTRA_ENV_COMPILE_ARGS = '-std=c++11'
   if 'win32' in sys.platform:
-    # We use define flags here and don't directly add to DEFINE_MACROS below to
-    # ensure that the expert user/builder has a way of turning it off (via the
-    # envvars) without adding yet more GRPC-specific envvars.
-    # See https://sourceforge.net/p/mingw-w64/bugs/363/
-    if '32' in platform.architecture()[0]:
-      EXTRA_ENV_COMPILE_ARGS += ' -D_ftime=_ftime32 -D_timeb=__timeb32 -D_ftime_s=_ftime32_s'
+    if sys.version_info < (3, 5):
+      # We use define flags here and don't directly add to DEFINE_MACROS below to
+      # ensure that the expert user/builder has a way of turning it off (via the
+      # envvars) without adding yet more GRPC-specific envvars.
+      # See https://sourceforge.net/p/mingw-w64/bugs/363/
+      if '32' in platform.architecture()[0]:
+        EXTRA_ENV_COMPILE_ARGS += ' -D_ftime=_ftime32 -D_timeb=__timeb32 -D_ftime_s=_ftime32_s'
+      else:
+        EXTRA_ENV_COMPILE_ARGS += ' -D_ftime=_ftime64 -D_timeb=__timeb64'
     else:
-      EXTRA_ENV_COMPILE_ARGS += ' -D_ftime=_ftime64 -D_timeb=__timeb64'
+      # We need to statically link the C++ Runtime, only the C runtime is
+      # available dynamically
+      EXTRA_ENV_COMPILE_ARGS += ' /MT'
+  elif "linux" in sys.platform or "darwin" in sys.platform:
+    EXTRA_ENV_COMPILE_ARGS += ' -fno-wrapv -frtti'
 if EXTRA_ENV_LINK_ARGS is None:
-  EXTRA_ENV_LINK_ARGS = '-lpthread'
-  if 'win32' in sys.platform:
-    # TODO(atash) check if this is actually safe to just import and call on
-    # non-Windows (to avoid breaking import style)
-    from distutils.cygwinccompiler import get_msvcr
-    msvcr = get_msvcr()[0]
+  EXTRA_ENV_LINK_ARGS = ''
+  if "linux" in sys.platform or "darwin" in sys.platform:
+    EXTRA_ENV_LINK_ARGS += ' -lpthread'
+  elif "win32" in sys.platform and sys.version_info < (3, 5):
+    msvcr = cygwinccompiler.get_msvcr()[0]
+    # TODO(atash) sift through the GCC specs to see if libstdc++ can have any
+    # influence on the linkage outcome on MinGW for non-C++ programs.
     EXTRA_ENV_LINK_ARGS += (
         ' -static-libgcc -static-libstdc++ -mcrtdll={msvcr} '
         '-static'.format(msvcr=msvcr))
+
 EXTRA_COMPILE_ARGS = shlex.split(EXTRA_ENV_COMPILE_ARGS)
 EXTRA_LINK_ARGS = shlex.split(EXTRA_ENV_LINK_ARGS)
 
@@ -101,9 +111,13 @@
 GRPC_PYTHON_TOOLS_PACKAGE = 'grpc.tools'
 GRPC_PYTHON_PROTO_RESOURCES_NAME = '_proto'
 
-DEFINE_MACROS = (('HAVE_PTHREAD', 1),)
-if "win32" in sys.platform and '64bit' in platform.architecture()[0]:
-  DEFINE_MACROS += (('MS_WIN64', 1),)
+DEFINE_MACROS = ()
+if "win32" in sys.platform:
+  DEFINE_MACROS += (('WIN32_LEAN_AND_MEAN', 1),)
+  if '64bit' in platform.architecture()[0]:
+    DEFINE_MACROS += (('MS_WIN64', 1),)
+elif "linux" in sys.platform or "darwin" in sys.platform:
+  DEFINE_MACROS += (('HAVE_PTHREAD', 1),)
 
 # By default, Python3 distutils enforces compatibility of
 # c plugins (.so files) with the OSX version Python3 was built with.
@@ -178,7 +192,7 @@
   namespace_packages=['grpc'],
   install_requires=[
     'protobuf>=3.0.0',
-    'grpcio>=0.15.0',
+    'grpcio>={version}'.format(version=grpc_version.VERSION),
   ],
   package_data=package_data(),
 )
diff --git a/tools/distrib/python/make_grpcio_tools.py b/tools/distrib/python/make_grpcio_tools.py
index adf5844..7413928 100755
--- a/tools/distrib/python/make_grpcio_tools.py
+++ b/tools/distrib/python/make_grpcio_tools.py
@@ -88,22 +88,23 @@
     os.path.join(os.path.dirname(os.path.abspath(__file__)),
                  '..', '..', '..'))
 
-GRPC_PYTHON_ROOT = os.path.join(GRPC_ROOT, 'tools/distrib/python/grpcio_tools')
+GRPC_PYTHON_ROOT = os.path.join(GRPC_ROOT, 'tools', 'distrib',
+                                'python', 'grpcio_tools')
 
-GRPC_PYTHON_PROTOBUF_RELATIVE_ROOT = 'third_party/protobuf/src'
+GRPC_PYTHON_PROTOBUF_RELATIVE_ROOT = os.path.join('third_party', 'protobuf', 'src')
 GRPC_PROTOBUF = os.path.join(GRPC_ROOT, GRPC_PYTHON_PROTOBUF_RELATIVE_ROOT)
-GRPC_PROTOC_PLUGINS = os.path.join(GRPC_ROOT, 'src/compiler')
-GRPC_PYTHON_PROTOBUF = os.path.join(GRPC_PYTHON_ROOT,
-                                    'third_party/protobuf/src')
-GRPC_PYTHON_PROTOC_PLUGINS = os.path.join(GRPC_PYTHON_ROOT,
-                                          'grpc_root/src/compiler')
+GRPC_PROTOC_PLUGINS = os.path.join(GRPC_ROOT, 'src', 'compiler')
+GRPC_PYTHON_PROTOBUF = os.path.join(GRPC_PYTHON_ROOT, 'third_party', 'protobuf',
+                                    'src')
+GRPC_PYTHON_PROTOC_PLUGINS = os.path.join(GRPC_PYTHON_ROOT, 'grpc_root', 'src',
+                                          'compiler')
 GRPC_PYTHON_PROTOC_LIB_DEPS = os.path.join(GRPC_PYTHON_ROOT,
                                            'protoc_lib_deps.py')
 
 GRPC_INCLUDE = os.path.join(GRPC_ROOT, 'include')
-GRPC_PYTHON_INCLUDE = os.path.join(GRPC_PYTHON_ROOT, 'grpc_root/include')
+GRPC_PYTHON_INCLUDE = os.path.join(GRPC_PYTHON_ROOT, 'grpc_root', 'include')
 
-BAZEL_DEPS = os.path.join(GRPC_ROOT, 'tools/distrib/python/bazel_deps.sh')
+BAZEL_DEPS = os.path.join(GRPC_ROOT, 'tools', 'distrib', 'python', 'bazel_deps.sh')
 BAZEL_DEPS_PROTOC_LIB_QUERY = '//:protoc_lib'
 BAZEL_DEPS_COMMON_PROTOS_QUERY = '//:well_known_protos'
 
@@ -136,64 +137,6 @@
   else:
     return path
 
-def atomic_file_copy(src, dst):
-  """Based on the lock-free-whack-a-mole algorithm, depending on filesystem
-     renaming being atomic. Described at http://stackoverflow.com/a/28090883.
-  """
-  try:
-    if filecmp.cmp(src, dst):
-      return
-  except:
-    pass
-  dst_dir = os.path.abspath(os.path.dirname(dst))
-  dst_base = os.path.basename(dst)
-  this_id = str(uuid.uuid4()).replace('.', '-')
-  temporary_file = os.path.join(dst_dir, '{}.{}.tmp'.format(dst_base, this_id))
-  mole_file = os.path.join(dst_dir, '{}.{}.mole.tmp'.format(dst_base, this_id))
-  mole_pattern = os.path.join(dst_dir, '{}.*.mole.tmp'.format(dst_base))
-  src = long_path(src)
-  dst = long_path(dst)
-  temporary_file = long_path(temporary_file)
-  mole_file = long_path(mole_file)
-  mole_pattern = long_path(mole_pattern)
-  shutil.copy2(src, temporary_file)
-  try:
-    os.rename(temporary_file, mole_file)
-  except:
-    print('Error moving temporary file {} to {}'.format(temporary_file, mole_file), file=sys.stderr)
-    print('while trying to copy file {} to {}'.format(src, dst), file=sys.stderr)
-    raise
-  for other_file in glob.glob(mole_pattern):
-    other_id = other_file.split('.')[-3]
-    if this_id == other_id:
-      pass
-    elif this_id < other_id:
-      try:
-        os.remove(other_file)
-      except:
-        pass
-    else:
-      try:
-        os.remove(mole_file)
-      except:
-        pass
-      this_id = other_id
-      mole_file = other_file
-  try:
-    if filecmp.cmp(src, dst):
-      try:
-        os.remove(mole_file)
-      except:
-        pass
-      return
-  except:
-    pass
-  try:
-    os.rename(mole_file, dst)
-  except:
-    pass
-
-
 def main():
   os.chdir(GRPC_ROOT)
 
@@ -211,7 +154,7 @@
       for relative_file in files:
         source_file = os.path.abspath(os.path.join(source_dir, relative_file))
         target_file = os.path.abspath(os.path.join(target_dir, relative_file))
-        atomic_file_copy(source_file, target_file)
+        shutil.copyfile(source_file, target_file)
 
   try:
     protoc_lib_deps_content = get_deps()
diff --git a/tools/dockerfile/test/python_pyenv_x64/Dockerfile b/tools/dockerfile/test/python_pyenv_x64/Dockerfile
index abb5f3c..ecd785a 100644
--- a/tools/dockerfile/test/python_pyenv_x64/Dockerfile
+++ b/tools/dockerfile/test/python_pyenv_x64/Dockerfile
@@ -95,7 +95,8 @@
 RUN pyenv update
 RUN pyenv install 3.5-dev
 RUN pyenv install 3.6-dev
-RUN pyenv local 3.5-dev 3.6-dev
+RUN pyenv install pypy-5.3.1
+RUN pyenv local 3.5-dev 3.6-dev pypy-5.3.1
 
 # Prepare ccache
 RUN ln -s /usr/bin/ccache /usr/local/bin/gcc
diff --git a/tools/doxygen/Doxyfile.c++ b/tools/doxygen/Doxyfile.c++
index a2415e1..314a42d 100644
--- a/tools/doxygen/Doxyfile.c++
+++ b/tools/doxygen/Doxyfile.c++
@@ -807,6 +807,34 @@
 include/grpc++/support/stub_options.h \
 include/grpc++/support/sync_stream.h \
 include/grpc++/support/time.h \
+include/grpc/byte_buffer.h \
+include/grpc/byte_buffer_reader.h \
+include/grpc/compression.h \
+include/grpc/grpc.h \
+include/grpc/grpc_posix.h \
+include/grpc/grpc_security_constants.h \
+include/grpc/status.h \
+include/grpc/impl/codegen/byte_buffer.h \
+include/grpc/impl/codegen/byte_buffer_reader.h \
+include/grpc/impl/codegen/compression_types.h \
+include/grpc/impl/codegen/connectivity_state.h \
+include/grpc/impl/codegen/grpc_types.h \
+include/grpc/impl/codegen/propagation_bits.h \
+include/grpc/impl/codegen/status.h \
+include/grpc/impl/codegen/alloc.h \
+include/grpc/impl/codegen/atm.h \
+include/grpc/impl/codegen/atm_gcc_atomic.h \
+include/grpc/impl/codegen/atm_gcc_sync.h \
+include/grpc/impl/codegen/atm_windows.h \
+include/grpc/impl/codegen/log.h \
+include/grpc/impl/codegen/port_platform.h \
+include/grpc/impl/codegen/slice.h \
+include/grpc/impl/codegen/slice_buffer.h \
+include/grpc/impl/codegen/sync.h \
+include/grpc/impl/codegen/sync_generic.h \
+include/grpc/impl/codegen/sync_posix.h \
+include/grpc/impl/codegen/sync_windows.h \
+include/grpc/impl/codegen/time.h \
 include/grpc++/impl/codegen/async_stream.h \
 include/grpc++/impl/codegen/async_unary_call.h \
 include/grpc++/impl/codegen/call.h \
@@ -836,28 +864,7 @@
 include/grpc++/impl/codegen/sync_cxx11.h \
 include/grpc++/impl/codegen/sync_no_cxx11.h \
 include/grpc++/impl/codegen/sync_stream.h \
-include/grpc++/impl/codegen/time.h \
-include/grpc/impl/codegen/byte_buffer.h \
-include/grpc/impl/codegen/byte_buffer_reader.h \
-include/grpc/impl/codegen/compression_types.h \
-include/grpc/impl/codegen/connectivity_state.h \
-include/grpc/impl/codegen/grpc_types.h \
-include/grpc/impl/codegen/propagation_bits.h \
-include/grpc/impl/codegen/status.h \
-include/grpc/impl/codegen/alloc.h \
-include/grpc/impl/codegen/atm.h \
-include/grpc/impl/codegen/atm_gcc_atomic.h \
-include/grpc/impl/codegen/atm_gcc_sync.h \
-include/grpc/impl/codegen/atm_windows.h \
-include/grpc/impl/codegen/log.h \
-include/grpc/impl/codegen/port_platform.h \
-include/grpc/impl/codegen/slice.h \
-include/grpc/impl/codegen/slice_buffer.h \
-include/grpc/impl/codegen/sync.h \
-include/grpc/impl/codegen/sync_generic.h \
-include/grpc/impl/codegen/sync_posix.h \
-include/grpc/impl/codegen/sync_windows.h \
-include/grpc/impl/codegen/time.h
+include/grpc++/impl/codegen/time.h
 
 # This tag can be used to specify the character encoding of the source files
 # that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses
diff --git a/tools/doxygen/Doxyfile.c++.internal b/tools/doxygen/Doxyfile.c++.internal
index 95c0e85..12eb651 100644
--- a/tools/doxygen/Doxyfile.c++.internal
+++ b/tools/doxygen/Doxyfile.c++.internal
@@ -807,6 +807,34 @@
 include/grpc++/support/stub_options.h \
 include/grpc++/support/sync_stream.h \
 include/grpc++/support/time.h \
+include/grpc/byte_buffer.h \
+include/grpc/byte_buffer_reader.h \
+include/grpc/compression.h \
+include/grpc/grpc.h \
+include/grpc/grpc_posix.h \
+include/grpc/grpc_security_constants.h \
+include/grpc/status.h \
+include/grpc/impl/codegen/byte_buffer.h \
+include/grpc/impl/codegen/byte_buffer_reader.h \
+include/grpc/impl/codegen/compression_types.h \
+include/grpc/impl/codegen/connectivity_state.h \
+include/grpc/impl/codegen/grpc_types.h \
+include/grpc/impl/codegen/propagation_bits.h \
+include/grpc/impl/codegen/status.h \
+include/grpc/impl/codegen/alloc.h \
+include/grpc/impl/codegen/atm.h \
+include/grpc/impl/codegen/atm_gcc_atomic.h \
+include/grpc/impl/codegen/atm_gcc_sync.h \
+include/grpc/impl/codegen/atm_windows.h \
+include/grpc/impl/codegen/log.h \
+include/grpc/impl/codegen/port_platform.h \
+include/grpc/impl/codegen/slice.h \
+include/grpc/impl/codegen/slice_buffer.h \
+include/grpc/impl/codegen/sync.h \
+include/grpc/impl/codegen/sync_generic.h \
+include/grpc/impl/codegen/sync_posix.h \
+include/grpc/impl/codegen/sync_windows.h \
+include/grpc/impl/codegen/time.h \
 include/grpc++/impl/codegen/async_stream.h \
 include/grpc++/impl/codegen/async_unary_call.h \
 include/grpc++/impl/codegen/call.h \
@@ -837,27 +865,6 @@
 include/grpc++/impl/codegen/sync_no_cxx11.h \
 include/grpc++/impl/codegen/sync_stream.h \
 include/grpc++/impl/codegen/time.h \
-include/grpc/impl/codegen/byte_buffer.h \
-include/grpc/impl/codegen/byte_buffer_reader.h \
-include/grpc/impl/codegen/compression_types.h \
-include/grpc/impl/codegen/connectivity_state.h \
-include/grpc/impl/codegen/grpc_types.h \
-include/grpc/impl/codegen/propagation_bits.h \
-include/grpc/impl/codegen/status.h \
-include/grpc/impl/codegen/alloc.h \
-include/grpc/impl/codegen/atm.h \
-include/grpc/impl/codegen/atm_gcc_atomic.h \
-include/grpc/impl/codegen/atm_gcc_sync.h \
-include/grpc/impl/codegen/atm_windows.h \
-include/grpc/impl/codegen/log.h \
-include/grpc/impl/codegen/port_platform.h \
-include/grpc/impl/codegen/slice.h \
-include/grpc/impl/codegen/slice_buffer.h \
-include/grpc/impl/codegen/sync.h \
-include/grpc/impl/codegen/sync_generic.h \
-include/grpc/impl/codegen/sync_posix.h \
-include/grpc/impl/codegen/sync_windows.h \
-include/grpc/impl/codegen/time.h \
 include/grpc++/impl/codegen/core_codegen.h \
 src/cpp/client/secure_credentials.h \
 src/cpp/common/secure_auth_context.h \
@@ -866,6 +873,86 @@
 src/cpp/common/channel_filter.h \
 src/cpp/server/dynamic_thread_pool.h \
 src/cpp/server/thread_pool_interface.h \
+src/core/lib/channel/channel_args.h \
+src/core/lib/channel/channel_stack.h \
+src/core/lib/channel/channel_stack_builder.h \
+src/core/lib/channel/compress_filter.h \
+src/core/lib/channel/connected_channel.h \
+src/core/lib/channel/context.h \
+src/core/lib/channel/handshaker.h \
+src/core/lib/channel/http_client_filter.h \
+src/core/lib/channel/http_server_filter.h \
+src/core/lib/compression/algorithm_metadata.h \
+src/core/lib/compression/message_compress.h \
+src/core/lib/debug/trace.h \
+src/core/lib/http/format_request.h \
+src/core/lib/http/httpcli.h \
+src/core/lib/http/parser.h \
+src/core/lib/iomgr/closure.h \
+src/core/lib/iomgr/endpoint.h \
+src/core/lib/iomgr/endpoint_pair.h \
+src/core/lib/iomgr/error.h \
+src/core/lib/iomgr/ev_epoll_linux.h \
+src/core/lib/iomgr/ev_poll_and_epoll_posix.h \
+src/core/lib/iomgr/ev_poll_posix.h \
+src/core/lib/iomgr/ev_posix.h \
+src/core/lib/iomgr/exec_ctx.h \
+src/core/lib/iomgr/executor.h \
+src/core/lib/iomgr/iocp_windows.h \
+src/core/lib/iomgr/iomgr.h \
+src/core/lib/iomgr/iomgr_internal.h \
+src/core/lib/iomgr/iomgr_posix.h \
+src/core/lib/iomgr/load_file.h \
+src/core/lib/iomgr/network_status_tracker.h \
+src/core/lib/iomgr/polling_entity.h \
+src/core/lib/iomgr/pollset.h \
+src/core/lib/iomgr/pollset_set.h \
+src/core/lib/iomgr/pollset_set_windows.h \
+src/core/lib/iomgr/pollset_windows.h \
+src/core/lib/iomgr/resolve_address.h \
+src/core/lib/iomgr/sockaddr.h \
+src/core/lib/iomgr/sockaddr_posix.h \
+src/core/lib/iomgr/sockaddr_utils.h \
+src/core/lib/iomgr/sockaddr_windows.h \
+src/core/lib/iomgr/socket_utils_posix.h \
+src/core/lib/iomgr/socket_windows.h \
+src/core/lib/iomgr/tcp_client.h \
+src/core/lib/iomgr/tcp_posix.h \
+src/core/lib/iomgr/tcp_server.h \
+src/core/lib/iomgr/tcp_windows.h \
+src/core/lib/iomgr/time_averaged_stats.h \
+src/core/lib/iomgr/timer.h \
+src/core/lib/iomgr/timer_heap.h \
+src/core/lib/iomgr/udp_server.h \
+src/core/lib/iomgr/unix_sockets_posix.h \
+src/core/lib/iomgr/wakeup_fd_pipe.h \
+src/core/lib/iomgr/wakeup_fd_posix.h \
+src/core/lib/iomgr/workqueue.h \
+src/core/lib/iomgr/workqueue_posix.h \
+src/core/lib/iomgr/workqueue_windows.h \
+src/core/lib/json/json.h \
+src/core/lib/json/json_common.h \
+src/core/lib/json/json_reader.h \
+src/core/lib/json/json_writer.h \
+src/core/lib/surface/api_trace.h \
+src/core/lib/surface/call.h \
+src/core/lib/surface/call_test_only.h \
+src/core/lib/surface/channel.h \
+src/core/lib/surface/channel_init.h \
+src/core/lib/surface/channel_stack_type.h \
+src/core/lib/surface/completion_queue.h \
+src/core/lib/surface/event_string.h \
+src/core/lib/surface/init.h \
+src/core/lib/surface/lame_client.h \
+src/core/lib/surface/server.h \
+src/core/lib/transport/byte_stream.h \
+src/core/lib/transport/connectivity_state.h \
+src/core/lib/transport/metadata.h \
+src/core/lib/transport/metadata_batch.h \
+src/core/lib/transport/static_metadata.h \
+src/core/lib/transport/timeout_encoding.h \
+src/core/lib/transport/transport.h \
+src/core/lib/transport/transport_impl.h \
 src/cpp/client/secure_credentials.cc \
 src/cpp/common/auth_property_iterator.cc \
 src/cpp/common/secure_auth_context.cc \
@@ -899,6 +986,95 @@
 src/cpp/util/status.cc \
 src/cpp/util/string_ref.cc \
 src/cpp/util/time.cc \
+src/core/lib/channel/channel_args.c \
+src/core/lib/channel/channel_stack.c \
+src/core/lib/channel/channel_stack_builder.c \
+src/core/lib/channel/compress_filter.c \
+src/core/lib/channel/connected_channel.c \
+src/core/lib/channel/handshaker.c \
+src/core/lib/channel/http_client_filter.c \
+src/core/lib/channel/http_server_filter.c \
+src/core/lib/compression/compression.c \
+src/core/lib/compression/message_compress.c \
+src/core/lib/debug/trace.c \
+src/core/lib/http/format_request.c \
+src/core/lib/http/httpcli.c \
+src/core/lib/http/parser.c \
+src/core/lib/iomgr/closure.c \
+src/core/lib/iomgr/endpoint.c \
+src/core/lib/iomgr/endpoint_pair_posix.c \
+src/core/lib/iomgr/endpoint_pair_windows.c \
+src/core/lib/iomgr/error.c \
+src/core/lib/iomgr/ev_epoll_linux.c \
+src/core/lib/iomgr/ev_poll_and_epoll_posix.c \
+src/core/lib/iomgr/ev_poll_posix.c \
+src/core/lib/iomgr/ev_posix.c \
+src/core/lib/iomgr/exec_ctx.c \
+src/core/lib/iomgr/executor.c \
+src/core/lib/iomgr/iocp_windows.c \
+src/core/lib/iomgr/iomgr.c \
+src/core/lib/iomgr/iomgr_posix.c \
+src/core/lib/iomgr/iomgr_windows.c \
+src/core/lib/iomgr/load_file.c \
+src/core/lib/iomgr/network_status_tracker.c \
+src/core/lib/iomgr/polling_entity.c \
+src/core/lib/iomgr/pollset_set_windows.c \
+src/core/lib/iomgr/pollset_windows.c \
+src/core/lib/iomgr/resolve_address_posix.c \
+src/core/lib/iomgr/resolve_address_windows.c \
+src/core/lib/iomgr/sockaddr_utils.c \
+src/core/lib/iomgr/socket_utils_common_posix.c \
+src/core/lib/iomgr/socket_utils_linux.c \
+src/core/lib/iomgr/socket_utils_posix.c \
+src/core/lib/iomgr/socket_windows.c \
+src/core/lib/iomgr/tcp_client_posix.c \
+src/core/lib/iomgr/tcp_client_windows.c \
+src/core/lib/iomgr/tcp_posix.c \
+src/core/lib/iomgr/tcp_server_posix.c \
+src/core/lib/iomgr/tcp_server_windows.c \
+src/core/lib/iomgr/tcp_windows.c \
+src/core/lib/iomgr/time_averaged_stats.c \
+src/core/lib/iomgr/timer.c \
+src/core/lib/iomgr/timer_heap.c \
+src/core/lib/iomgr/udp_server.c \
+src/core/lib/iomgr/unix_sockets_posix.c \
+src/core/lib/iomgr/unix_sockets_posix_noop.c \
+src/core/lib/iomgr/wakeup_fd_eventfd.c \
+src/core/lib/iomgr/wakeup_fd_nospecial.c \
+src/core/lib/iomgr/wakeup_fd_pipe.c \
+src/core/lib/iomgr/wakeup_fd_posix.c \
+src/core/lib/iomgr/workqueue_posix.c \
+src/core/lib/iomgr/workqueue_windows.c \
+src/core/lib/json/json.c \
+src/core/lib/json/json_reader.c \
+src/core/lib/json/json_string.c \
+src/core/lib/json/json_writer.c \
+src/core/lib/surface/alarm.c \
+src/core/lib/surface/api_trace.c \
+src/core/lib/surface/byte_buffer.c \
+src/core/lib/surface/byte_buffer_reader.c \
+src/core/lib/surface/call.c \
+src/core/lib/surface/call_details.c \
+src/core/lib/surface/call_log_batch.c \
+src/core/lib/surface/channel.c \
+src/core/lib/surface/channel_init.c \
+src/core/lib/surface/channel_ping.c \
+src/core/lib/surface/channel_stack_type.c \
+src/core/lib/surface/completion_queue.c \
+src/core/lib/surface/event_string.c \
+src/core/lib/surface/lame_client.c \
+src/core/lib/surface/metadata_array.c \
+src/core/lib/surface/server.c \
+src/core/lib/surface/validate_metadata.c \
+src/core/lib/surface/version.c \
+src/core/lib/transport/byte_stream.c \
+src/core/lib/transport/connectivity_state.c \
+src/core/lib/transport/metadata.c \
+src/core/lib/transport/metadata_batch.c \
+src/core/lib/transport/static_metadata.c \
+src/core/lib/transport/timeout_encoding.c \
+src/core/lib/transport/transport.c \
+src/core/lib/transport/transport_op_string.c \
 src/cpp/codegen/codegen_init.cc
 
 # This tag can be used to specify the character encoding of the source files
diff --git a/tools/doxygen/Doxyfile.core b/tools/doxygen/Doxyfile.core
index e631c96..27f878e 100644
--- a/tools/doxygen/Doxyfile.core
+++ b/tools/doxygen/Doxyfile.core
@@ -765,6 +765,7 @@
 include/grpc/compression.h \
 include/grpc/grpc.h \
 include/grpc/grpc_posix.h \
+include/grpc/grpc_security_constants.h \
 include/grpc/status.h \
 include/grpc/impl/codegen/byte_buffer.h \
 include/grpc/impl/codegen/byte_buffer_reader.h \
@@ -788,7 +789,6 @@
 include/grpc/impl/codegen/sync_windows.h \
 include/grpc/impl/codegen/time.h \
 include/grpc/grpc_security.h \
-include/grpc/grpc_security_constants.h \
 include/grpc/census.h \
 include/grpc/support/alloc.h \
 include/grpc/support/atm.h \
diff --git a/tools/doxygen/Doxyfile.core.internal b/tools/doxygen/Doxyfile.core.internal
index dcb11bd..3ffd5e1 100644
--- a/tools/doxygen/Doxyfile.core.internal
+++ b/tools/doxygen/Doxyfile.core.internal
@@ -765,6 +765,7 @@
 include/grpc/compression.h \
 include/grpc/grpc.h \
 include/grpc/grpc_posix.h \
+include/grpc/grpc_security_constants.h \
 include/grpc/status.h \
 include/grpc/impl/codegen/byte_buffer.h \
 include/grpc/impl/codegen/byte_buffer_reader.h \
@@ -788,7 +789,6 @@
 include/grpc/impl/codegen/sync_windows.h \
 include/grpc/impl/codegen/time.h \
 include/grpc/grpc_security.h \
-include/grpc/grpc_security_constants.h \
 include/grpc/census.h \
 src/core/lib/channel/channel_args.h \
 src/core/lib/channel/channel_stack.h \
@@ -806,6 +806,7 @@
 src/core/lib/http/httpcli.h \
 src/core/lib/http/parser.h \
 src/core/lib/iomgr/closure.h \
+src/core/lib/iomgr/combiner.h \
 src/core/lib/iomgr/endpoint.h \
 src/core/lib/iomgr/endpoint_pair.h \
 src/core/lib/iomgr/error.h \
@@ -917,7 +918,6 @@
 src/core/lib/tsi/transport_security_interface.h \
 src/core/ext/client_config/client_channel.h \
 src/core/ext/client_config/client_channel_factory.h \
-src/core/ext/client_config/client_config.h \
 src/core/ext/client_config/connector.h \
 src/core/ext/client_config/initial_connect_string.h \
 src/core/ext/client_config/lb_policy.h \
@@ -927,8 +927,8 @@
 src/core/ext/client_config/resolver.h \
 src/core/ext/client_config/resolver_factory.h \
 src/core/ext/client_config/resolver_registry.h \
+src/core/ext/client_config/resolver_result.h \
 src/core/ext/client_config/subchannel.h \
-src/core/ext/client_config/subchannel_call_holder.h \
 src/core/ext/client_config/subchannel_index.h \
 src/core/ext/client_config/uri_parser.h \
 src/core/ext/lb_policy/grpclb/grpclb.h \
@@ -945,6 +945,7 @@
 src/core/ext/census/census_interface.h \
 src/core/ext/census/census_rpc_stats.h \
 src/core/ext/census/gen/census.pb.h \
+src/core/ext/census/gen/trace_context.pb.h \
 src/core/ext/census/grpc_filter.h \
 src/core/ext/census/mlog.h \
 src/core/ext/census/resource.h \
@@ -965,6 +966,7 @@
 src/core/lib/http/httpcli.c \
 src/core/lib/http/parser.c \
 src/core/lib/iomgr/closure.c \
+src/core/lib/iomgr/combiner.c \
 src/core/lib/iomgr/endpoint.c \
 src/core/lib/iomgr/endpoint_pair_posix.c \
 src/core/lib/iomgr/endpoint_pair_windows.c \
@@ -1094,7 +1096,6 @@
 src/core/ext/client_config/channel_connectivity.c \
 src/core/ext/client_config/client_channel.c \
 src/core/ext/client_config/client_channel_factory.c \
-src/core/ext/client_config/client_config.c \
 src/core/ext/client_config/client_config_plugin.c \
 src/core/ext/client_config/connector.c \
 src/core/ext/client_config/default_initial_connect_string.c \
@@ -1106,8 +1107,8 @@
 src/core/ext/client_config/resolver.c \
 src/core/ext/client_config/resolver_factory.c \
 src/core/ext/client_config/resolver_registry.c \
+src/core/ext/client_config/resolver_result.c \
 src/core/ext/client_config/subchannel.c \
-src/core/ext/client_config/subchannel_call_holder.c \
 src/core/ext/client_config/subchannel_index.c \
 src/core/ext/client_config/uri_parser.c \
 src/core/ext/transport/chttp2/server/insecure/server_chttp2.c \
@@ -1129,6 +1130,7 @@
 src/core/ext/census/base_resources.c \
 src/core/ext/census/context.c \
 src/core/ext/census/gen/census.pb.c \
+src/core/ext/census/gen/trace_context.pb.c \
 src/core/ext/census/grpc_context.c \
 src/core/ext/census/grpc_filter.c \
 src/core/ext/census/grpc_plugin.c \
@@ -1185,6 +1187,7 @@
 src/core/lib/support/backoff.h \
 src/core/lib/support/block_annotate.h \
 src/core/lib/support/env.h \
+src/core/lib/support/mpscq.h \
 src/core/lib/support/murmur_hash.h \
 src/core/lib/support/stack_lockfree.h \
 src/core/lib/support/string.h \
@@ -1212,6 +1215,7 @@
 src/core/lib/support/log_linux.c \
 src/core/lib/support/log_posix.c \
 src/core/lib/support/log_windows.c \
+src/core/lib/support/mpscq.c \
 src/core/lib/support/murmur_hash.c \
 src/core/lib/support/slice.c \
 src/core/lib/support/slice_buffer.c \
diff --git a/tools/jenkins/run_full_interop.sh b/tools/jenkins/run_full_cloud_prod.sh
old mode 100755
new mode 100644
similarity index 87%
rename from tools/jenkins/run_full_interop.sh
rename to tools/jenkins/run_full_cloud_prod.sh
index a82da1c..ea51b50
--- a/tools/jenkins/run_full_interop.sh
+++ b/tools/jenkins/run_full_cloud_prod.sh
@@ -31,7 +31,14 @@
 # This script is invoked by Jenkins and runs interop test suite.
 set -ex
 
+export LANG=en_US.UTF-8
+
 # Enter the gRPC repo root
 cd $(dirname $0)/../..
 
-tools/run_tests/run_interop_tests.py -l all -s all --cloud_to_prod --cloud_to_prod_auth --prod_servers default cloud_gateway gateway_v2 cloud_gateway_v2 gateway_v4 cloud_gateway_v4 --use_docker --http2_interop -t -j 12 $@ || true
+tools/run_tests/run_interop_tests.py \
+    -l all \
+    --cloud_to_prod \
+    --cloud_to_prod_auth \
+    --prod_servers default cloud_gateway gateway_v4 cloud_gateway_v4 \
+    --use_docker -t -j 12 $@ || true
diff --git a/tools/jenkins/run_interop.sh b/tools/jenkins/run_interop.sh
index a424aea..4a7bff3 100755
--- a/tools/jenkins/run_interop.sh
+++ b/tools/jenkins/run_interop.sh
@@ -31,6 +31,8 @@
 # This script is invoked by Jenkins and runs interop test suite.
 set -ex
 
+export LANG=en_US.UTF-8
+
 # Enter the gRPC repo root
 cd $(dirname $0)/../..
 
diff --git a/tools/run_tests/artifact_targets.py b/tools/run_tests/artifact_targets.py
index 8550ee7..d36f963 100644
--- a/tools/run_tests/artifact_targets.py
+++ b/tools/run_tests/artifact_targets.py
@@ -31,6 +31,8 @@
 """Definition of targets to build artifacts."""
 
 import os.path
+import random
+import string
 import sys
 
 import jobset
@@ -79,27 +81,16 @@
   'x64': '-m64'
 }
 
-python_windows_version_arch_map = {
-  ('x86', '2.7'): 'Python27_32bits',
-  ('x64', '2.7'): 'Python27',
-  ('x86', '3.4'): 'Python34_32bits',
-  ('x64', '3.4'): 'Python34',
-}
 
 class PythonArtifact:
   """Builds Python artifacts."""
 
-  def __init__(self, platform, arch, python_version, manylinux_build=None):
-    if manylinux_build:
-      self.name = 'python%s_%s_%s_%s' % (python_version, platform, arch, manylinux_build)
-    else:
-      self.name = 'python%s_%s_%s' % (python_version, platform, arch)
+  def __init__(self, platform, arch, py_version):
+    self.name = 'python_%s_%s_%s' % (platform, arch, py_version)
     self.platform = platform
     self.arch = arch
-    self.labels = ['artifact', 'python', python_version, platform, arch]
-    self.python_version = python_version
-    self.python_windows_prefix = python_windows_version_arch_map[arch, python_version]
-    self.manylinux_build = manylinux_build
+    self.labels = ['artifact', 'python', platform, arch, py_version]
+    self.py_version = py_version
 
   def pre_build_jobspecs(self):
     return []
@@ -111,8 +102,8 @@
         environ['SETARCH_CMD'] = 'linux32'
       # Inside the manylinux container, the python installations are located in
       # special places...
-      environ['PYTHON'] = '/opt/python/{}/bin/python'.format(self.manylinux_build)
-      environ['PIP'] = '/opt/python/{}/bin/pip'.format(self.manylinux_build)
+      environ['PYTHON'] = '/opt/python/{}/bin/python'.format(self.py_version)
+      environ['PIP'] = '/opt/python/{}/bin/pip'.format(self.py_version)
       # Platform autodetection for the manylinux1 image breaks so we set the
       # defines ourselves.
       # TODO(atash) get better platform-detection support in core so we don't
@@ -126,14 +117,24 @@
           environ=environ,
           timeout_seconds=60*60)
     elif self.platform == 'windows':
+      if 'Python27' in self.py_version or 'Python34' in self.py_version:
+        environ['EXT_COMPILER'] = 'mingw32'
+      else:
+        environ['EXT_COMPILER'] = 'msvc'
+      # For some reason, the batch script %random% always runs with the same
+      # seed.  We create a random temp-dir here
+      dir = ''.join(random.choice(string.ascii_uppercase) for _ in range(10))
       return create_jobspec(self.name,
                             ['tools\\run_tests\\build_artifact_python.bat',
-                             self.python_windows_prefix,
-                             '32' if self.arch == 'x86' else '64'
+                             self.py_version,
+                             '32' if self.arch == 'x86' else '64',
+                             dir
                             ],
+                            environ=environ,
                             shell=True)
     else:
-      environ['PYTHON'] = 'python{}'.format(self.python_version)
+      environ['PYTHON'] = self.py_version
+      environ['SKIP_PIP_INSTALL'] = 'TRUE'
       return create_jobspec(self.name,
                             ['tools/run_tests/build_artifact_python.sh'],
                             environ=environ)
@@ -330,18 +331,23 @@
            for Cls in (CSharpExtArtifact, NodeExtArtifact, ProtocArtifact)
            for platform in ('linux', 'macos', 'windows')
            for arch in ('x86', 'x64')] +
-          [PythonArtifact('linux', 'x86', '2.7', 'cp27-cp27m'),
-           PythonArtifact('linux', 'x86', '2.7', 'cp27-cp27mu'),
-           PythonArtifact('linux', 'x64', '2.7', 'cp27-cp27m'),
-           PythonArtifact('linux', 'x64', '2.7', 'cp27-cp27mu'),
-           PythonArtifact('macos', 'x64', '2.7'),
-           PythonArtifact('windows', 'x86', '2.7'),
-           PythonArtifact('windows', 'x64', '2.7'),
-           PythonArtifact('linux', 'x86', '3.4', 'cp34-cp34m'),
-           PythonArtifact('linux', 'x64', '3.4', 'cp34-cp34m'),
-           PythonArtifact('macos', 'x64', '3.4'),
-           PythonArtifact('windows', 'x86', '3.4'),
-           PythonArtifact('windows', 'x64', '3.4'),
+          [PythonArtifact('linux', 'x86', 'cp27-cp27m'),
+           PythonArtifact('linux', 'x86', 'cp27-cp27mu'),
+           PythonArtifact('linux', 'x86', 'cp34-cp34m'),
+           PythonArtifact('linux', 'x86', 'cp35-cp35m'),
+           PythonArtifact('linux', 'x64', 'cp27-cp27m'),
+           PythonArtifact('linux', 'x64', 'cp27-cp27mu'),
+           PythonArtifact('linux', 'x64', 'cp34-cp34m'),
+           PythonArtifact('linux', 'x64', 'cp35-cp35m'),
+           PythonArtifact('macos', 'x64', 'python2.7'),
+           PythonArtifact('macos', 'x64', 'python3.4'),
+           PythonArtifact('macos', 'x64', 'python3.5'),
+           PythonArtifact('windows', 'x86', 'Python27_32bits'),
+           PythonArtifact('windows', 'x86', 'Python34_32bits'),
+           PythonArtifact('windows', 'x86', 'Python35_32bits'),
+           PythonArtifact('windows', 'x64', 'Python27'),
+           PythonArtifact('windows', 'x64', 'Python34'),
+           PythonArtifact('windows', 'x64', 'Python35'),
            RubyArtifact('linux', 'x86'),
            RubyArtifact('linux', 'x64'),
            RubyArtifact('macos', 'x64'),
diff --git a/tools/run_tests/build_artifact_python.bat b/tools/run_tests/build_artifact_python.bat
index 074a3c6..246713a 100644
--- a/tools/run_tests/build_artifact_python.bat
+++ b/tools/run_tests/build_artifact_python.bat
@@ -36,31 +36,43 @@
 
 set GRPC_PYTHON_BUILD_WITH_CYTHON=1
 
+@rem Multiple builds are running simultaneously, so to avoid distutils
+@rem file collisions, we build everything in a tmp directory
+if not exist "artifacts" mkdir "artifacts"
+set ARTIFACT_DIR=%cd%\artifacts
+set BUILD_DIR=C:\Windows\Temp\pygrpc-%3\
+mkdir %BUILD_DIR%
+xcopy /s/e/q %cd%\* %BUILD_DIR%
+pushd %BUILD_DIR%
+
 
 @rem Set up gRPC Python tools
 python tools\distrib\python\make_grpcio_tools.py
 
 @rem Build gRPC Python extensions
-python setup.py build_ext -c mingw32
+python setup.py build_ext -c %EXT_COMPILER% || goto :error
 
 pushd tools\distrib\python\grpcio_tools
-python setup.py build_ext -c mingw32
+python setup.py build_ext -c %EXT_COMPILER% || goto :error
 popd
 
-
 @rem Build gRPC Python distributions
-python setup.py bdist_wheel
+python setup.py bdist_wheel || goto :error
 
 pushd tools\distrib\python\grpcio_tools
-python setup.py bdist_wheel
+python setup.py bdist_wheel || goto :error
 popd
 
 
-mkdir artifacts
-xcopy /Y /I /S dist\* artifacts\ || goto :error
-xcopy /Y /I /S tools\distrib\python\grpcio_tools\dist\* artifacts\ || goto :error
+xcopy /Y /I /S dist\* %ARTIFACT_DIR% || goto :error
+xcopy /Y /I /S tools\distrib\python\grpcio_tools\dist\* %ARTIFACT_DIR% || goto :error
+
+popd
+rmdir /s /q %BUILD_DIR%
 
 goto :EOF
 
 :error
+popd
+rmdir /s /q %BUILD_DIR%
 exit /b 1
diff --git a/tools/run_tests/build_artifact_python.sh b/tools/run_tests/build_artifact_python.sh
index 8f8330e..9fed7c5 100755
--- a/tools/run_tests/build_artifact_python.sh
+++ b/tools/run_tests/build_artifact_python.sh
@@ -38,38 +38,42 @@
 export PIP=${PIP:-pip}
 export AUDITWHEEL=${AUDITWHEEL:-auditwheel}
 
+# Because multiple builds run in parallel, some distutils file
+# operations may collide.  To avoid this, each build is run in
+# a temp directory
+mkdir -p artifacts
+ARTIFACT_DIR="$PWD/artifacts"
+BUILD_DIR=`mktemp -d "${TMPDIR:-/tmp}/pygrpc.XXXXXX"`
+trap "rm -rf $BUILD_DIR" EXIT
+cp -r * "$BUILD_DIR"
+cd "$BUILD_DIR"
 
 # Build the source distribution first because MANIFEST.in cannot override
 # exclusion of built shared objects among package resources (for some
 # inexplicable reason).
-${SETARCH_CMD} ${PYTHON} setup.py  \
-    sdist
+${SETARCH_CMD} ${PYTHON} setup.py sdist
 
 # Wheel has a bug where directories don't get excluded.
 # https://bitbucket.org/pypa/wheel/issues/99/cannot-exclude-directory
-${SETARCH_CMD} ${PYTHON} setup.py  \
-    bdist_wheel
+${SETARCH_CMD} ${PYTHON} setup.py bdist_wheel
 
 # Build gRPC tools package distribution
 ${PYTHON} tools/distrib/python/make_grpcio_tools.py
 
 # Build gRPC tools package source distribution
-${SETARCH_CMD} ${PYTHON} tools/distrib/python/grpcio_tools/setup.py  \
-    sdist
+${SETARCH_CMD} ${PYTHON} tools/distrib/python/grpcio_tools/setup.py sdist
 
 # Build gRPC tools package binary distribution
-CFLAGS="$CFLAGS -fno-wrapv" ${SETARCH_CMD} \
-  ${PYTHON} tools/distrib/python/grpcio_tools/setup.py bdist_wheel
+${SETARCH_CMD} ${PYTHON} tools/distrib/python/grpcio_tools/setup.py bdist_wheel
 
-mkdir -p artifacts
 if [ "$BUILD_MANYLINUX_WHEEL" != "" ]
 then
   for wheel in dist/*.whl; do
-    ${AUDITWHEEL} repair $wheel -w artifacts/
+    ${AUDITWHEEL} repair $wheel -w "$ARTIFACT_DIR"
     rm $wheel
   done
   for wheel in tools/distrib/python/grpcio_tools/dist/*.whl; do
-    ${AUDITWHEEL} repair $wheel -w artifacts/
+    ${AUDITWHEEL} repair $wheel -w "$ARTIFACT_DIR"
     rm $wheel
   done
 fi
@@ -81,14 +85,14 @@
 if [ "$BUILD_HEALTH_CHECKING" != "" ]
 then
   ${PIP} install -rrequirements.txt
-  ${PIP} install grpcio --no-index --find-links "file://${PWD}/artifacts/"
-  ${PIP} install grpcio-tools --no-index --find-links "file://${PWD}/artifacts/"
+  ${PIP} install grpcio --no-index --find-links "file://$ARTIFACT_DIR/"
+  ${PIP} install grpcio-tools --no-index --find-links "file://$ARTIFACT_DIR/"
 
   # Build gRPC health check source distribution
   ${SETARCH_CMD} ${PYTHON} src/python/grpcio_health_checking/setup.py \
       preprocess build_package_protos sdist
-  cp -r src/python/grpcio_health_checking/dist/* artifacts
+  cp -r src/python/grpcio_health_checking/dist/* "$ARTIFACT_DIR"
 fi
 
-cp -r dist/* artifacts
-cp -r tools/distrib/python/grpcio_tools/dist/* artifacts
+cp -r dist/* "$ARTIFACT_DIR"
+cp -r tools/distrib/python/grpcio_tools/dist/* "$ARTIFACT_DIR"
diff --git a/tools/run_tests/run_interop_tests.py b/tools/run_tests/run_interop_tests.py
index 0d402d6..5feda65 100755
--- a/tools/run_tests/run_interop_tests.py
+++ b/tools/run_tests/run_interop_tests.py
@@ -623,15 +623,15 @@
 # TODO(adelez): implement logic for errors_allowed where if the indicated tests
 # fail, they don't impact the overall test result.
 prod_servers = {
-    'default': ('grpc-test.sandbox.googleapis.com',
+    'default': ('216.239.32.254',
                 'grpc-test.sandbox.googleapis.com', False),
-    'gateway_v2': ('grpc-test2.sandbox.googleapis.com',
+    'gateway_v2': ('216.239.32.254',
                    'grpc-test2.sandbox.googleapis.com', True),
     'cloud_gateway': ('216.239.32.255', 'grpc-test.sandbox.googleapis.com',
                       False),
     'cloud_gateway_v2': ('216.239.32.255', 'grpc-test2.sandbox.googleapis.com',
                          True),
-    'gateway_v4': ('grpc-test4.sandbox.googleapis.com',
+    'gateway_v4': ('216.239.32.254',
                    'grpc-test4.sandbox.googleapis.com', True),
     'cloud_gateway_v4': ('216.239.32.255', 'grpc-test4.sandbox.googleapis.com',
                          True),
diff --git a/tools/run_tests/sanity/check_submodules.sh b/tools/run_tests/sanity/check_submodules.sh
index d2ab5b0..5562d33 100755
--- a/tools/run_tests/sanity/check_submodules.sh
+++ b/tools/run_tests/sanity/check_submodules.sh
@@ -45,7 +45,7 @@
  05b155ff59114735ec8cd089f669c4c3d8f59029 third_party/gflags (v2.1.0-45-g05b155f)
  c99458533a9b4c743ed51537e25989ea55944908 third_party/googletest (release-1.7.0)
  f8ac463766281625ad710900479130c7fcb4d63b third_party/nanopb (nanopb-0.3.4-29-gf8ac463)
- e8ae137c96444ea313485ed1118c5e43b2099cf1 third_party/protobuf (v3.0.0-beta-4-74-ge8ae137)
+ bba446bbf2ac7b0b9923d4eb07d5acd0665a8cf0 third_party/protobuf (v3.0.0-beta-4-160-gbba446b)
  50893291621658f355bc5b4d450a8d06a563053d third_party/zlib (v1.2.8)
  bcad91771b7f0bff28a1cac1981d7ef2b9bcef3c third_party/thrift
 EOF
diff --git a/tools/run_tests/sources_and_headers.json b/tools/run_tests/sources_and_headers.json
index e5946cc..1945d1c 100644
--- a/tools/run_tests/sources_and_headers.json
+++ b/tools/run_tests/sources_and_headers.json
@@ -261,6 +261,22 @@
     ], 
     "headers": [], 
     "language": "c", 
+    "name": "combiner_test", 
+    "src": [
+      "test/core/iomgr/combiner_test.c"
+    ], 
+    "third_party": false, 
+    "type": "target"
+  }, 
+  {
+    "deps": [
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
     "name": "compression_test", 
     "src": [
       "test/core/compression/compression_test.c"
@@ -620,6 +636,20 @@
     ], 
     "headers": [], 
     "language": "c", 
+    "name": "gpr_mpscq_test", 
+    "src": [
+      "test/core/support/mpscq_test.c"
+    ], 
+    "third_party": false, 
+    "type": "target"
+  }, 
+  {
+    "deps": [
+      "gpr", 
+      "gpr_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
     "name": "gpr_slice_buffer_test", 
     "src": [
       "test/core/support/slice_buffer_test.c"
@@ -4413,6 +4443,7 @@
   }, 
   {
     "deps": [
+      "gpr", 
       "grpc", 
       "grpc++_base", 
       "grpc++_codegen_base", 
@@ -4533,7 +4564,6 @@
   {
     "deps": [
       "gpr", 
-      "grpc", 
       "grpc++_base", 
       "grpc++_codegen_base", 
       "grpc++_codegen_base_src", 
@@ -5501,6 +5531,7 @@
       "test/core/end2end/tests/max_message_length.c", 
       "test/core/end2end/tests/negative_deadline.c", 
       "test/core/end2end/tests/network_status_change.c", 
+      "test/core/end2end/tests/no_logging.c", 
       "test/core/end2end/tests/no_op.c", 
       "test/core/end2end/tests/payload.c", 
       "test/core/end2end/tests/ping.c", 
@@ -5563,6 +5594,7 @@
       "test/core/end2end/tests/max_message_length.c", 
       "test/core/end2end/tests/negative_deadline.c", 
       "test/core/end2end/tests/network_status_change.c", 
+      "test/core/end2end/tests/no_logging.c", 
       "test/core/end2end/tests/no_op.c", 
       "test/core/end2end/tests/payload.c", 
       "test/core/end2end/tests/ping.c", 
@@ -5595,6 +5627,7 @@
       "src/core/ext/census/census_interface.h", 
       "src/core/ext/census/census_rpc_stats.h", 
       "src/core/ext/census/gen/census.pb.h", 
+      "src/core/ext/census/gen/trace_context.pb.h", 
       "src/core/ext/census/grpc_filter.h", 
       "src/core/ext/census/mlog.h", 
       "src/core/ext/census/resource.h", 
@@ -5612,6 +5645,8 @@
       "src/core/ext/census/context.c", 
       "src/core/ext/census/gen/census.pb.c", 
       "src/core/ext/census/gen/census.pb.h", 
+      "src/core/ext/census/gen/trace_context.pb.c", 
+      "src/core/ext/census/gen/trace_context.pb.h", 
       "src/core/ext/census/grpc_context.c", 
       "src/core/ext/census/grpc_filter.c", 
       "src/core/ext/census/grpc_filter.h", 
@@ -5666,6 +5701,7 @@
       "src/core/lib/support/backoff.h", 
       "src/core/lib/support/block_annotate.h", 
       "src/core/lib/support/env.h", 
+      "src/core/lib/support/mpscq.h", 
       "src/core/lib/support/murmur_hash.h", 
       "src/core/lib/support/stack_lockfree.h", 
       "src/core/lib/support/string.h", 
@@ -5729,6 +5765,8 @@
       "src/core/lib/support/log_linux.c", 
       "src/core/lib/support/log_posix.c", 
       "src/core/lib/support/log_windows.c", 
+      "src/core/lib/support/mpscq.c", 
+      "src/core/lib/support/mpscq.h", 
       "src/core/lib/support/murmur_hash.c", 
       "src/core/lib/support/murmur_hash.h", 
       "src/core/lib/support/slice.c", 
@@ -5815,6 +5853,7 @@
       "include/grpc/compression.h", 
       "include/grpc/grpc.h", 
       "include/grpc/grpc_posix.h", 
+      "include/grpc/grpc_security_constants.h", 
       "include/grpc/status.h", 
       "src/core/lib/channel/channel_args.h", 
       "src/core/lib/channel/channel_stack.h", 
@@ -5832,6 +5871,7 @@
       "src/core/lib/http/httpcli.h", 
       "src/core/lib/http/parser.h", 
       "src/core/lib/iomgr/closure.h", 
+      "src/core/lib/iomgr/combiner.h", 
       "src/core/lib/iomgr/endpoint.h", 
       "src/core/lib/iomgr/endpoint_pair.h", 
       "src/core/lib/iomgr/error.h", 
@@ -5905,6 +5945,7 @@
       "include/grpc/compression.h", 
       "include/grpc/grpc.h", 
       "include/grpc/grpc_posix.h", 
+      "include/grpc/grpc_security_constants.h", 
       "include/grpc/status.h", 
       "src/core/lib/channel/channel_args.c", 
       "src/core/lib/channel/channel_args.h", 
@@ -5937,6 +5978,8 @@
       "src/core/lib/http/parser.h", 
       "src/core/lib/iomgr/closure.c", 
       "src/core/lib/iomgr/closure.h", 
+      "src/core/lib/iomgr/combiner.c", 
+      "src/core/lib/iomgr/combiner.h", 
       "src/core/lib/iomgr/endpoint.c", 
       "src/core/lib/iomgr/endpoint.h", 
       "src/core/lib/iomgr/endpoint_pair.h", 
@@ -6087,7 +6130,6 @@
     "headers": [
       "src/core/ext/client_config/client_channel.h", 
       "src/core/ext/client_config/client_channel_factory.h", 
-      "src/core/ext/client_config/client_config.h", 
       "src/core/ext/client_config/connector.h", 
       "src/core/ext/client_config/initial_connect_string.h", 
       "src/core/ext/client_config/lb_policy.h", 
@@ -6097,8 +6139,8 @@
       "src/core/ext/client_config/resolver.h", 
       "src/core/ext/client_config/resolver_factory.h", 
       "src/core/ext/client_config/resolver_registry.h", 
+      "src/core/ext/client_config/resolver_result.h", 
       "src/core/ext/client_config/subchannel.h", 
-      "src/core/ext/client_config/subchannel_call_holder.h", 
       "src/core/ext/client_config/subchannel_index.h", 
       "src/core/ext/client_config/uri_parser.h"
     ], 
@@ -6110,8 +6152,6 @@
       "src/core/ext/client_config/client_channel.h", 
       "src/core/ext/client_config/client_channel_factory.c", 
       "src/core/ext/client_config/client_channel_factory.h", 
-      "src/core/ext/client_config/client_config.c", 
-      "src/core/ext/client_config/client_config.h", 
       "src/core/ext/client_config/client_config_plugin.c", 
       "src/core/ext/client_config/connector.c", 
       "src/core/ext/client_config/connector.h", 
@@ -6132,10 +6172,10 @@
       "src/core/ext/client_config/resolver_factory.h", 
       "src/core/ext/client_config/resolver_registry.c", 
       "src/core/ext/client_config/resolver_registry.h", 
+      "src/core/ext/client_config/resolver_result.c", 
+      "src/core/ext/client_config/resolver_result.h", 
       "src/core/ext/client_config/subchannel.c", 
       "src/core/ext/client_config/subchannel.h", 
-      "src/core/ext/client_config/subchannel_call_holder.c", 
-      "src/core/ext/client_config/subchannel_call_holder.h", 
       "src/core/ext/client_config/subchannel_index.c", 
       "src/core/ext/client_config/subchannel_index.h", 
       "src/core/ext/client_config/uri_parser.c", 
@@ -6285,7 +6325,6 @@
     ], 
     "headers": [
       "include/grpc/grpc_security.h", 
-      "include/grpc/grpc_security_constants.h", 
       "src/core/lib/security/context/security_context.h", 
       "src/core/lib/security/credentials/composite/composite_credentials.h", 
       "src/core/lib/security/credentials/credentials.h", 
@@ -6310,7 +6349,6 @@
     "name": "grpc_secure", 
     "src": [
       "include/grpc/grpc_security.h", 
-      "include/grpc/grpc_security_constants.h", 
       "src/core/lib/http/httpcli_security_connector.c", 
       "src/core/lib/security/context/security_context.c", 
       "src/core/lib/security/context/security_context.h", 
@@ -6631,8 +6669,9 @@
   }, 
   {
     "deps": [
-      "grpc", 
-      "grpc++_codegen_base"
+      "gpr", 
+      "grpc++_codegen_base", 
+      "grpc_base"
     ], 
     "headers": [
       "include/grpc++/alarm.h", 
diff --git a/tools/run_tests/tests.json b/tools/run_tests/tests.json
index b0c09ac..e056514 100644
--- a/tools/run_tests/tests.json
+++ b/tools/run_tests/tests.json
@@ -303,6 +303,27 @@
       "posix", 
       "windows"
     ], 
+    "cpu_cost": 30, 
+    "exclude_configs": [], 
+    "flaky": false, 
+    "gtest": false, 
+    "language": "c", 
+    "name": "combiner_test", 
+    "platforms": [
+      "linux", 
+      "mac", 
+      "posix", 
+      "windows"
+    ]
+  }, 
+  {
+    "args": [], 
+    "ci_platforms": [
+      "linux", 
+      "mac", 
+      "posix", 
+      "windows"
+    ], 
     "cpu_cost": 1.0, 
     "exclude_configs": [], 
     "flaky": false, 
@@ -705,6 +726,27 @@
       "posix", 
       "windows"
     ], 
+    "cpu_cost": 30, 
+    "exclude_configs": [], 
+    "flaky": false, 
+    "gtest": false, 
+    "language": "c", 
+    "name": "gpr_mpscq_test", 
+    "platforms": [
+      "linux", 
+      "mac", 
+      "posix", 
+      "windows"
+    ]
+  }, 
+  {
+    "args": [], 
+    "ci_platforms": [
+      "linux", 
+      "mac", 
+      "posix", 
+      "windows"
+    ], 
     "cpu_cost": 1.0, 
     "exclude_configs": [], 
     "flaky": false, 
@@ -5048,6 +5090,28 @@
   }, 
   {
     "args": [
+      "no_logging"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_census_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
       "no_op"
     ], 
     "ci_platforms": [
@@ -5972,6 +6036,28 @@
   }, 
   {
     "args": [
+      "no_logging"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_compress_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
       "no_op"
     ], 
     "ci_platforms": [
@@ -6869,6 +6955,27 @@
   }, 
   {
     "args": [
+      "no_logging"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "posix"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_fakesec_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
       "no_op"
     ], 
     "ci_platforms": [
@@ -7664,6 +7771,26 @@
   }, 
   {
     "args": [
+      "no_logging"
+    ], 
+    "ci_platforms": [
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_fd_test", 
+    "platforms": [
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
       "no_op"
     ], 
     "ci_platforms": [
@@ -8518,6 +8645,28 @@
   }, 
   {
     "args": [
+      "no_logging"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
       "no_op"
     ], 
     "ci_platforms": [
@@ -9280,6 +9429,22 @@
   }, 
   {
     "args": [
+      "no_logging"
+    ], 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full+pipe_test", 
+    "platforms": [
+      "linux"
+    ]
+  }, 
+  {
+    "args": [
       "no_op"
     ], 
     "ci_platforms": [
@@ -11016,6 +11181,28 @@
   }, 
   {
     "args": [
+      "no_logging"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_load_reporting_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
       "no_op"
     ], 
     "ci_platforms": [
@@ -11913,6 +12100,27 @@
   }, 
   {
     "args": [
+      "no_logging"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "posix"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_oauth2_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
       "no_op"
     ], 
     "ci_platforms": [
@@ -12711,6 +12919,27 @@
   }, 
   {
     "args": [
+      "no_logging"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "posix"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_proxy_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
       "no_op"
     ], 
     "ci_platforms": [
@@ -13488,6 +13717,27 @@
   }, 
   {
     "args": [
+      "no_logging"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "posix"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_sockpair_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
       "no_op"
     ], 
     "ci_platforms": [
@@ -15021,6 +15271,27 @@
   }, 
   {
     "args": [
+      "no_logging"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "posix"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_sockpair_1byte_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
       "no_op"
     ], 
     "ci_platforms": [
@@ -15888,6 +16159,28 @@
   }, 
   {
     "args": [
+      "no_logging"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_ssl_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
       "no_op"
     ], 
     "ci_platforms": [
@@ -16812,6 +17105,28 @@
   }, 
   {
     "args": [
+      "no_logging"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_ssl_cert_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
       "no_op"
     ], 
     "ci_platforms": [
@@ -17625,6 +17940,27 @@
   }, 
   {
     "args": [
+      "no_logging"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "posix"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_ssl_proxy_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
       "no_op"
     ], 
     "ci_platforms": [
@@ -18418,6 +18754,26 @@
   }, 
   {
     "args": [
+      "no_logging"
+    ], 
+    "ci_platforms": [
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_uds_test", 
+    "platforms": [
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
       "no_op"
     ], 
     "ci_platforms": [
@@ -19290,6 +19646,28 @@
   }, 
   {
     "args": [
+      "no_logging"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_census_nosec_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
       "no_op"
     ], 
     "ci_platforms": [
@@ -20192,6 +20570,28 @@
   }, 
   {
     "args": [
+      "no_logging"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_compress_nosec_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
       "no_op"
     ], 
     "ci_platforms": [
@@ -20982,6 +21382,26 @@
   }, 
   {
     "args": [
+      "no_logging"
+    ], 
+    "ci_platforms": [
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_fd_nosec_test", 
+    "platforms": [
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
       "no_op"
     ], 
     "ci_platforms": [
@@ -21814,6 +22234,28 @@
   }, 
   {
     "args": [
+      "no_logging"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full_nosec_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
       "no_op"
     ], 
     "ci_platforms": [
@@ -22560,6 +23002,22 @@
   }, 
   {
     "args": [
+      "no_logging"
+    ], 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_full+pipe_nosec_test", 
+    "platforms": [
+      "linux"
+    ]
+  }, 
+  {
+    "args": [
       "no_op"
     ], 
     "ci_platforms": [
@@ -24252,6 +24710,28 @@
   }, 
   {
     "args": [
+      "no_logging"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_load_reporting_nosec_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
       "no_op"
     ], 
     "ci_platforms": [
@@ -25044,6 +25524,27 @@
   }, 
   {
     "args": [
+      "no_logging"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "posix"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_proxy_nosec_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
       "no_op"
     ], 
     "ci_platforms": [
@@ -25800,6 +26301,27 @@
   }, 
   {
     "args": [
+      "no_logging"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "posix"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_sockpair_nosec_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
       "no_op"
     ], 
     "ci_platforms": [
@@ -27337,6 +27859,29 @@
   }, 
   {
     "args": [
+      "no_logging"
+    ], 
+    "ci_platforms": [
+      "windows", 
+      "linux", 
+      "posix"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [
+      "msan"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_sockpair_1byte_nosec_test", 
+    "platforms": [
+      "windows", 
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
       "no_op"
     ], 
     "ci_platforms": [
@@ -28136,6 +28681,26 @@
   }, 
   {
     "args": [
+      "no_logging"
+    ], 
+    "ci_platforms": [
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "h2_uds_nosec_test", 
+    "platforms": [
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
+  {
+    "args": [
       "no_op"
     ], 
     "ci_platforms": [
@@ -54860,6 +55425,25 @@
   }, 
   {
     "args": [
+      "test/core/end2end/fuzzers/client_fuzzer_corpus/0083d5addbeca55271ed7ef93c8016bf7ca76903"
+    ], 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [
+      "tsan"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "client_fuzzer_one_entry", 
+    "platforms": [
+      "linux"
+    ], 
+    "uses_polling": false
+  }, 
+  {
+    "args": [
       "test/core/end2end/fuzzers/client_fuzzer_corpus/00c8446b230bebbae2b473552b174a06b446337a"
     ], 
     "ci_platforms": [
@@ -55088,6 +55672,44 @@
   }, 
   {
     "args": [
+      "test/core/end2end/fuzzers/client_fuzzer_corpus/07b0bed3226eefac4a84000ec584e4ce06ebf1bf"
+    ], 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [
+      "tsan"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "client_fuzzer_one_entry", 
+    "platforms": [
+      "linux"
+    ], 
+    "uses_polling": false
+  }, 
+  {
+    "args": [
+      "test/core/end2end/fuzzers/client_fuzzer_corpus/07cec5c8d9c856a910c6fb57da2ae954f44beed0"
+    ], 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [
+      "tsan"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "client_fuzzer_one_entry", 
+    "platforms": [
+      "linux"
+    ], 
+    "uses_polling": false
+  }, 
+  {
+    "args": [
       "test/core/end2end/fuzzers/client_fuzzer_corpus/08a8a647b6a8f47ae10852322d14832fc15021f1"
     ], 
     "ci_platforms": [
@@ -55145,6 +55767,25 @@
   }, 
   {
     "args": [
+      "test/core/end2end/fuzzers/client_fuzzer_corpus/0c27c9999302b39bf2256a90b0cdb767fb2b6fe3"
+    ], 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [
+      "tsan"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "client_fuzzer_one_entry", 
+    "platforms": [
+      "linux"
+    ], 
+    "uses_polling": false
+  }, 
+  {
+    "args": [
       "test/core/end2end/fuzzers/client_fuzzer_corpus/0c30868720d5e1a19ff23c53740749c37a43540d"
     ], 
     "ci_platforms": [
@@ -55221,6 +55862,44 @@
   }, 
   {
     "args": [
+      "test/core/end2end/fuzzers/client_fuzzer_corpus/0d407f099f8418de3dd94bd2146c858a8c6575ad"
+    ], 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [
+      "tsan"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "client_fuzzer_one_entry", 
+    "platforms": [
+      "linux"
+    ], 
+    "uses_polling": false
+  }, 
+  {
+    "args": [
+      "test/core/end2end/fuzzers/client_fuzzer_corpus/0d4d486aa9fd6e9c10cc9ca8967e922cadddb2fe"
+    ], 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [
+      "tsan"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "client_fuzzer_one_entry", 
+    "platforms": [
+      "linux"
+    ], 
+    "uses_polling": false
+  }, 
+  {
+    "args": [
       "test/core/end2end/fuzzers/client_fuzzer_corpus/0d8c547f1d261ba07c2648bae009636c17709600"
     ], 
     "ci_platforms": [
@@ -55240,6 +55919,25 @@
   }, 
   {
     "args": [
+      "test/core/end2end/fuzzers/client_fuzzer_corpus/0d9ba07b57eb0e076b187c4455f662db085e730b"
+    ], 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [
+      "tsan"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "client_fuzzer_one_entry", 
+    "platforms": [
+      "linux"
+    ], 
+    "uses_polling": false
+  }, 
+  {
+    "args": [
       "test/core/end2end/fuzzers/client_fuzzer_corpus/0dd33527db106a3e84172e8f2189734b00ced4ed"
     ], 
     "ci_platforms": [
@@ -55297,6 +55995,25 @@
   }, 
   {
     "args": [
+      "test/core/end2end/fuzzers/client_fuzzer_corpus/0f6b989cec08ef9da603dc83704d85900bd22f1f"
+    ], 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [
+      "tsan"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "client_fuzzer_one_entry", 
+    "platforms": [
+      "linux"
+    ], 
+    "uses_polling": false
+  }, 
+  {
+    "args": [
       "test/core/end2end/fuzzers/client_fuzzer_corpus/0f83cbec19c834f534f353f4fce20c0cd88231f5"
     ], 
     "ci_platforms": [
@@ -55392,6 +56109,25 @@
   }, 
   {
     "args": [
+      "test/core/end2end/fuzzers/client_fuzzer_corpus/10b25b0726cb6d820165699e5a453691c7a9c343"
+    ], 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [
+      "tsan"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "client_fuzzer_one_entry", 
+    "platforms": [
+      "linux"
+    ], 
+    "uses_polling": false
+  }, 
+  {
+    "args": [
       "test/core/end2end/fuzzers/client_fuzzer_corpus/10f5d1937cb068fee7f85e2654be2bfe77498bb9"
     ], 
     "ci_platforms": [
@@ -55468,6 +56204,25 @@
   }, 
   {
     "args": [
+      "test/core/end2end/fuzzers/client_fuzzer_corpus/1231c6d007d9e43d169122348363e20d9f25ee93"
+    ], 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [
+      "tsan"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "client_fuzzer_one_entry", 
+    "platforms": [
+      "linux"
+    ], 
+    "uses_polling": false
+  }, 
+  {
+    "args": [
       "test/core/end2end/fuzzers/client_fuzzer_corpus/1306c4c6ea714d4db0e4d814c944d8d40335e0fa"
     ], 
     "ci_platforms": [
@@ -55487,6 +56242,25 @@
   }, 
   {
     "args": [
+      "test/core/end2end/fuzzers/client_fuzzer_corpus/13a9b61e431c20734c19bb36d85883b6a501284e"
+    ], 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [
+      "tsan"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "client_fuzzer_one_entry", 
+    "platforms": [
+      "linux"
+    ], 
+    "uses_polling": false
+  }, 
+  {
+    "args": [
       "test/core/end2end/fuzzers/client_fuzzer_corpus/1402bbcac6fa24eeb0475250e33f704096e2fb45"
     ], 
     "ci_platforms": [
@@ -55601,6 +56375,25 @@
   }, 
   {
     "args": [
+      "test/core/end2end/fuzzers/client_fuzzer_corpus/1698ec182fad9d973b84615da3a683ecdf2d0b3b"
+    ], 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [
+      "tsan"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "client_fuzzer_one_entry", 
+    "platforms": [
+      "linux"
+    ], 
+    "uses_polling": false
+  }, 
+  {
+    "args": [
       "test/core/end2end/fuzzers/client_fuzzer_corpus/169f579e66b4b8ff423891a40380e648e8d45247"
     ], 
     "ci_platforms": [
@@ -55658,6 +56451,25 @@
   }, 
   {
     "args": [
+      "test/core/end2end/fuzzers/client_fuzzer_corpus/1859e2ee759e20fe195f67615a1576ce2b7d5bbd"
+    ], 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [
+      "tsan"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "client_fuzzer_one_entry", 
+    "platforms": [
+      "linux"
+    ], 
+    "uses_polling": false
+  }, 
+  {
+    "args": [
       "test/core/end2end/fuzzers/client_fuzzer_corpus/1875a4acdcffe505ca92ea8af8d9d6b174736e80"
     ], 
     "ci_platforms": [
@@ -55753,6 +56565,25 @@
   }, 
   {
     "args": [
+      "test/core/end2end/fuzzers/client_fuzzer_corpus/1a9017db5ad8a9dc6cfe72305da1683a87a73452"
+    ], 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [
+      "tsan"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "client_fuzzer_one_entry", 
+    "platforms": [
+      "linux"
+    ], 
+    "uses_polling": false
+  }, 
+  {
+    "args": [
       "test/core/end2end/fuzzers/client_fuzzer_corpus/1aee32faadffa3c2ec508e8fd30006423665488f"
     ], 
     "ci_platforms": [
@@ -55791,6 +56622,44 @@
   }, 
   {
     "args": [
+      "test/core/end2end/fuzzers/client_fuzzer_corpus/1bd90335afc9e0a1e6a9296e3cc27c03c1201886"
+    ], 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [
+      "tsan"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "client_fuzzer_one_entry", 
+    "platforms": [
+      "linux"
+    ], 
+    "uses_polling": false
+  }, 
+  {
+    "args": [
+      "test/core/end2end/fuzzers/client_fuzzer_corpus/1be157b0fc79f0e7e1e05dfa3cbbe1ad71528bc2"
+    ], 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [
+      "tsan"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "client_fuzzer_one_entry", 
+    "platforms": [
+      "linux"
+    ], 
+    "uses_polling": false
+  }, 
+  {
+    "args": [
       "test/core/end2end/fuzzers/client_fuzzer_corpus/1c222dae4e2cde1fca9f9bf6226200f70d625342"
     ], 
     "ci_platforms": [
@@ -56152,6 +57021,25 @@
   }, 
   {
     "args": [
+      "test/core/end2end/fuzzers/client_fuzzer_corpus/2185f411bdb1edc610f16ffc86836ae366193e03"
+    ], 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [
+      "tsan"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "client_fuzzer_one_entry", 
+    "platforms": [
+      "linux"
+    ], 
+    "uses_polling": false
+  }, 
+  {
+    "args": [
       "test/core/end2end/fuzzers/client_fuzzer_corpus/21a6a133f3d1e06c077032ba56a7df4161f62efe"
     ], 
     "ci_platforms": [
@@ -56190,6 +57078,25 @@
   }, 
   {
     "args": [
+      "test/core/end2end/fuzzers/client_fuzzer_corpus/22661803bd1c7198df4be6e08924ef6a48af9cd4"
+    ], 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [
+      "tsan"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "client_fuzzer_one_entry", 
+    "platforms": [
+      "linux"
+    ], 
+    "uses_polling": false
+  }, 
+  {
+    "args": [
       "test/core/end2end/fuzzers/client_fuzzer_corpus/230527b90b0179139c961aca426187893191fdf2"
     ], 
     "ci_platforms": [
@@ -56437,6 +57344,25 @@
   }, 
   {
     "args": [
+      "test/core/end2end/fuzzers/client_fuzzer_corpus/2717067bbc0e9bfc1d90d15cddf6154800a25ec6"
+    ], 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [
+      "tsan"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "client_fuzzer_one_entry", 
+    "platforms": [
+      "linux"
+    ], 
+    "uses_polling": false
+  }, 
+  {
+    "args": [
       "test/core/end2end/fuzzers/client_fuzzer_corpus/27f37037525aac7a41ffbadd6ce52e5a1851a2b7"
     ], 
     "ci_platforms": [
@@ -56456,6 +57382,25 @@
   }, 
   {
     "args": [
+      "test/core/end2end/fuzzers/client_fuzzer_corpus/2825cfc19c9371f4fe70851283c68d49470d4d55"
+    ], 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [
+      "tsan"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "client_fuzzer_one_entry", 
+    "platforms": [
+      "linux"
+    ], 
+    "uses_polling": false
+  }, 
+  {
+    "args": [
       "test/core/end2end/fuzzers/client_fuzzer_corpus/2862adc802092f1a422416a1666a5142f71d5d7f"
     ], 
     "ci_platforms": [
@@ -56551,6 +57496,25 @@
   }, 
   {
     "args": [
+      "test/core/end2end/fuzzers/client_fuzzer_corpus/29303c16f3afa18c2c0b84e77e587535a705a74c"
+    ], 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [
+      "tsan"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "client_fuzzer_one_entry", 
+    "platforms": [
+      "linux"
+    ], 
+    "uses_polling": false
+  }, 
+  {
+    "args": [
       "test/core/end2end/fuzzers/client_fuzzer_corpus/299034b9e0cc8d91c049c489dca6d1a2b8b08959"
     ], 
     "ci_platforms": [
@@ -56665,6 +57629,25 @@
   }, 
   {
     "args": [
+      "test/core/end2end/fuzzers/client_fuzzer_corpus/2b5eb5aac77af905877bd98ec2c4d746b247abb6"
+    ], 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [
+      "tsan"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "client_fuzzer_one_entry", 
+    "platforms": [
+      "linux"
+    ], 
+    "uses_polling": false
+  }, 
+  {
+    "args": [
       "test/core/end2end/fuzzers/client_fuzzer_corpus/2b71439e9ebf611a92386b9f21ad44bde7926184"
     ], 
     "ci_platforms": [
@@ -56779,6 +57762,25 @@
   }, 
   {
     "args": [
+      "test/core/end2end/fuzzers/client_fuzzer_corpus/2cc43573f271ecd332551c1fb34ebc8645eaefe8"
+    ], 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [
+      "tsan"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "client_fuzzer_one_entry", 
+    "platforms": [
+      "linux"
+    ], 
+    "uses_polling": false
+  }, 
+  {
+    "args": [
       "test/core/end2end/fuzzers/client_fuzzer_corpus/2d83097b3cbd2245b085e749fe923fb590790e0c"
     ], 
     "ci_platforms": [
@@ -56893,6 +57895,44 @@
   }, 
   {
     "args": [
+      "test/core/end2end/fuzzers/client_fuzzer_corpus/2feb41037f5dd34e9f3465a2fbf1a6d355c8ce9d"
+    ], 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [
+      "tsan"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "client_fuzzer_one_entry", 
+    "platforms": [
+      "linux"
+    ], 
+    "uses_polling": false
+  }, 
+  {
+    "args": [
+      "test/core/end2end/fuzzers/client_fuzzer_corpus/300998021c7f743ff49d9cc192343ffd43eb47f2"
+    ], 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [
+      "tsan"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "client_fuzzer_one_entry", 
+    "platforms": [
+      "linux"
+    ], 
+    "uses_polling": false
+  }, 
+  {
+    "args": [
       "test/core/end2end/fuzzers/client_fuzzer_corpus/301e10bb6d9f60d91efde4e0c48893203a5b8b88"
     ], 
     "ci_platforms": [
@@ -56931,6 +57971,25 @@
   }, 
   {
     "args": [
+      "test/core/end2end/fuzzers/client_fuzzer_corpus/310b2aff5e2ec78b6004630bed39d49f8d13bb21"
+    ], 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [
+      "tsan"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "client_fuzzer_one_entry", 
+    "platforms": [
+      "linux"
+    ], 
+    "uses_polling": false
+  }, 
+  {
+    "args": [
       "test/core/end2end/fuzzers/client_fuzzer_corpus/3128887b8e02f1873ed6b36766a870543269ea00"
     ], 
     "ci_platforms": [
@@ -57311,6 +58370,25 @@
   }, 
   {
     "args": [
+      "test/core/end2end/fuzzers/client_fuzzer_corpus/3bb052abecc1b916cc869b9aad29c9dd55a95068"
+    ], 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [
+      "tsan"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "client_fuzzer_one_entry", 
+    "platforms": [
+      "linux"
+    ], 
+    "uses_polling": false
+  }, 
+  {
+    "args": [
       "test/core/end2end/fuzzers/client_fuzzer_corpus/3c01b1f89d50fa37fcb3457cd3dd6502fe84e25b"
     ], 
     "ci_platforms": [
@@ -57330,6 +58408,44 @@
   }, 
   {
     "args": [
+      "test/core/end2end/fuzzers/client_fuzzer_corpus/3c5fa483ebfabe6e684831ce7c413176bc998c33"
+    ], 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [
+      "tsan"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "client_fuzzer_one_entry", 
+    "platforms": [
+      "linux"
+    ], 
+    "uses_polling": false
+  }, 
+  {
+    "args": [
+      "test/core/end2end/fuzzers/client_fuzzer_corpus/3c6444b64ace5cd6c145614ad4412382271a6120"
+    ], 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [
+      "tsan"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "client_fuzzer_one_entry", 
+    "platforms": [
+      "linux"
+    ], 
+    "uses_polling": false
+  }, 
+  {
+    "args": [
       "test/core/end2end/fuzzers/client_fuzzer_corpus/3c7b516e302ad3503a933b5dcfb8c58acaea07a0"
     ], 
     "ci_platforms": [
@@ -57444,6 +58560,44 @@
   }, 
   {
     "args": [
+      "test/core/end2end/fuzzers/client_fuzzer_corpus/4045d25f065bb1d70a8b9c3751f7453d4b0625b9"
+    ], 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [
+      "tsan"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "client_fuzzer_one_entry", 
+    "platforms": [
+      "linux"
+    ], 
+    "uses_polling": false
+  }, 
+  {
+    "args": [
+      "test/core/end2end/fuzzers/client_fuzzer_corpus/407cedf992b14edac6e19f7d440ab73c88e72465"
+    ], 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [
+      "tsan"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "client_fuzzer_one_entry", 
+    "platforms": [
+      "linux"
+    ], 
+    "uses_polling": false
+  }, 
+  {
+    "args": [
       "test/core/end2end/fuzzers/client_fuzzer_corpus/4097094277bc09981f428280fc0cc0f590f20ded"
     ], 
     "ci_platforms": [
@@ -57463,6 +58617,44 @@
   }, 
   {
     "args": [
+      "test/core/end2end/fuzzers/client_fuzzer_corpus/411966ea7d9164fc432eeab55a55248ad808bb01"
+    ], 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [
+      "tsan"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "client_fuzzer_one_entry", 
+    "platforms": [
+      "linux"
+    ], 
+    "uses_polling": false
+  }, 
+  {
+    "args": [
+      "test/core/end2end/fuzzers/client_fuzzer_corpus/415dde26637ed3c0e803111c532a1a9ea9c49092"
+    ], 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [
+      "tsan"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "client_fuzzer_one_entry", 
+    "platforms": [
+      "linux"
+    ], 
+    "uses_polling": false
+  }, 
+  {
+    "args": [
       "test/core/end2end/fuzzers/client_fuzzer_corpus/41aad2f11a7ab418213352e84de872d9997db8d2"
     ], 
     "ci_platforms": [
@@ -58014,6 +59206,25 @@
   }, 
   {
     "args": [
+      "test/core/end2end/fuzzers/client_fuzzer_corpus/4fc34239f220392581520aa8cebc659daa65a7a6"
+    ], 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [
+      "tsan"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "client_fuzzer_one_entry", 
+    "platforms": [
+      "linux"
+    ], 
+    "uses_polling": false
+  }, 
+  {
+    "args": [
       "test/core/end2end/fuzzers/client_fuzzer_corpus/50ece7ea16659b4e1a2284cea963fab662c19e6b"
     ], 
     "ci_platforms": [
@@ -58071,6 +59282,25 @@
   }, 
   {
     "args": [
+      "test/core/end2end/fuzzers/client_fuzzer_corpus/52939682304314f04897deddfbc9c7afa8ee50a9"
+    ], 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [
+      "tsan"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "client_fuzzer_one_entry", 
+    "platforms": [
+      "linux"
+    ], 
+    "uses_polling": false
+  }, 
+  {
+    "args": [
       "test/core/end2end/fuzzers/client_fuzzer_corpus/52c00bde7f4af95a86deb0a6717d1faf2828a939"
     ], 
     "ci_platforms": [
@@ -58128,6 +59358,44 @@
   }, 
   {
     "args": [
+      "test/core/end2end/fuzzers/client_fuzzer_corpus/5369926a559827d08bccf264876d592c7cae660d"
+    ], 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [
+      "tsan"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "client_fuzzer_one_entry", 
+    "platforms": [
+      "linux"
+    ], 
+    "uses_polling": false
+  }, 
+  {
+    "args": [
+      "test/core/end2end/fuzzers/client_fuzzer_corpus/53ef530f65b0cff2e338a51b469c224f53b628d7"
+    ], 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [
+      "tsan"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "client_fuzzer_one_entry", 
+    "platforms": [
+      "linux"
+    ], 
+    "uses_polling": false
+  }, 
+  {
+    "args": [
       "test/core/end2end/fuzzers/client_fuzzer_corpus/542c958c84d1e319b9ba23c52de2c4bca08a8dc7"
     ], 
     "ci_platforms": [
@@ -58223,6 +59491,63 @@
   }, 
   {
     "args": [
+      "test/core/end2end/fuzzers/client_fuzzer_corpus/560c1057487e6b0d2d457748c3ad8434423eb263"
+    ], 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [
+      "tsan"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "client_fuzzer_one_entry", 
+    "platforms": [
+      "linux"
+    ], 
+    "uses_polling": false
+  }, 
+  {
+    "args": [
+      "test/core/end2end/fuzzers/client_fuzzer_corpus/564f203f678fb333c7b1f8f4df79237589ce346d"
+    ], 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [
+      "tsan"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "client_fuzzer_one_entry", 
+    "platforms": [
+      "linux"
+    ], 
+    "uses_polling": false
+  }, 
+  {
+    "args": [
+      "test/core/end2end/fuzzers/client_fuzzer_corpus/56b0ac0636c57838f63415082b3ae2ec7a93f017"
+    ], 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [
+      "tsan"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "client_fuzzer_one_entry", 
+    "platforms": [
+      "linux"
+    ], 
+    "uses_polling": false
+  }, 
+  {
+    "args": [
       "test/core/end2end/fuzzers/client_fuzzer_corpus/570ca8d2555dde94aa3b3121e8f5256e83eabe5e"
     ], 
     "ci_platforms": [
@@ -58299,6 +59624,25 @@
   }, 
   {
     "args": [
+      "test/core/end2end/fuzzers/client_fuzzer_corpus/58bcbd601894835bb3312d2a0bc56f2e0f65984c"
+    ], 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [
+      "tsan"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "client_fuzzer_one_entry", 
+    "platforms": [
+      "linux"
+    ], 
+    "uses_polling": false
+  }, 
+  {
+    "args": [
       "test/core/end2end/fuzzers/client_fuzzer_corpus/58d6dffb65a1fe1bc4e3fa970a15459587a32f77"
     ], 
     "ci_platforms": [
@@ -58337,6 +59681,25 @@
   }, 
   {
     "args": [
+      "test/core/end2end/fuzzers/client_fuzzer_corpus/598d346f284bcff26d1de997c4ba5c4794c90b68"
+    ], 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [
+      "tsan"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "client_fuzzer_one_entry", 
+    "platforms": [
+      "linux"
+    ], 
+    "uses_polling": false
+  }, 
+  {
+    "args": [
       "test/core/end2end/fuzzers/client_fuzzer_corpus/59d28886db21f371ac9d999b68b116bcf425d971"
     ], 
     "ci_platforms": [
@@ -58394,6 +59757,25 @@
   }, 
   {
     "args": [
+      "test/core/end2end/fuzzers/client_fuzzer_corpus/5c14b48da74ab06b3cc20c4fe355e24f7dd7852a"
+    ], 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [
+      "tsan"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "client_fuzzer_one_entry", 
+    "platforms": [
+      "linux"
+    ], 
+    "uses_polling": false
+  }, 
+  {
+    "args": [
       "test/core/end2end/fuzzers/client_fuzzer_corpus/5ca233a53e3e425cc12e04b466a49789291eaa00"
     ], 
     "ci_platforms": [
@@ -58432,6 +59814,25 @@
   }, 
   {
     "args": [
+      "test/core/end2end/fuzzers/client_fuzzer_corpus/5de72e607205dc17a45df703ec4e9b63c36821ec"
+    ], 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [
+      "tsan"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "client_fuzzer_one_entry", 
+    "platforms": [
+      "linux"
+    ], 
+    "uses_polling": false
+  }, 
+  {
+    "args": [
       "test/core/end2end/fuzzers/client_fuzzer_corpus/5e1659e7cd840ab3f958273ebffdd215f2c81da6"
     ], 
     "ci_platforms": [
@@ -58451,6 +59852,44 @@
   }, 
   {
     "args": [
+      "test/core/end2end/fuzzers/client_fuzzer_corpus/5e25cf639ba8ea37543d944f5efa94824c6272ff"
+    ], 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [
+      "tsan"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "client_fuzzer_one_entry", 
+    "platforms": [
+      "linux"
+    ], 
+    "uses_polling": false
+  }, 
+  {
+    "args": [
+      "test/core/end2end/fuzzers/client_fuzzer_corpus/5f247d7b6753f7a8798cf952f49f303c532e017c"
+    ], 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [
+      "tsan"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "client_fuzzer_one_entry", 
+    "platforms": [
+      "linux"
+    ], 
+    "uses_polling": false
+  }, 
+  {
+    "args": [
       "test/core/end2end/fuzzers/client_fuzzer_corpus/605e474e9d9436488dfe084d348908e4dfab81a3"
     ], 
     "ci_platforms": [
@@ -58565,6 +60004,25 @@
   }, 
   {
     "args": [
+      "test/core/end2end/fuzzers/client_fuzzer_corpus/63a1cb41d219394c9bab947202921506f3574ad0"
+    ], 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [
+      "tsan"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "client_fuzzer_one_entry", 
+    "platforms": [
+      "linux"
+    ], 
+    "uses_polling": false
+  }, 
+  {
+    "args": [
       "test/core/end2end/fuzzers/client_fuzzer_corpus/64696e93ead18265cdac3fb37dae29ad3be6d764"
     ], 
     "ci_platforms": [
@@ -58641,6 +60099,25 @@
   }, 
   {
     "args": [
+      "test/core/end2end/fuzzers/client_fuzzer_corpus/650f74738d3961af2d1fe85ad8fc8212ea13cbbf"
+    ], 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [
+      "tsan"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "client_fuzzer_one_entry", 
+    "platforms": [
+      "linux"
+    ], 
+    "uses_polling": false
+  }, 
+  {
+    "args": [
       "test/core/end2end/fuzzers/client_fuzzer_corpus/653ec14661c40ea25bdbab4a7cb9371c669d10d9"
     ], 
     "ci_platforms": [
@@ -58660,6 +60137,25 @@
   }, 
   {
     "args": [
+      "test/core/end2end/fuzzers/client_fuzzer_corpus/65dff388749da6a44926b491cdc555f61d708171"
+    ], 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [
+      "tsan"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "client_fuzzer_one_entry", 
+    "platforms": [
+      "linux"
+    ], 
+    "uses_polling": false
+  }, 
+  {
+    "args": [
       "test/core/end2end/fuzzers/client_fuzzer_corpus/66145518601b1405361df12570f6e0b2b9a2e5b3"
     ], 
     "ci_platforms": [
@@ -58736,6 +60232,25 @@
   }, 
   {
     "args": [
+      "test/core/end2end/fuzzers/client_fuzzer_corpus/676adbb1e5b3f4f9e3cba51d3d4ef963ba4ea7e3"
+    ], 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [
+      "tsan"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "client_fuzzer_one_entry", 
+    "platforms": [
+      "linux"
+    ], 
+    "uses_polling": false
+  }, 
+  {
+    "args": [
       "test/core/end2end/fuzzers/client_fuzzer_corpus/67e72cea2b7042f08e8dfba5191d27bb390e4d00"
     ], 
     "ci_platforms": [
@@ -58755,6 +60270,44 @@
   }, 
   {
     "args": [
+      "test/core/end2end/fuzzers/client_fuzzer_corpus/67f160446ded73c408f4e5a0665731b642b6edd4"
+    ], 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [
+      "tsan"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "client_fuzzer_one_entry", 
+    "platforms": [
+      "linux"
+    ], 
+    "uses_polling": false
+  }, 
+  {
+    "args": [
+      "test/core/end2end/fuzzers/client_fuzzer_corpus/6856c7cb02d2ba74a60fd47140f042701dda63b3"
+    ], 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [
+      "tsan"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "client_fuzzer_one_entry", 
+    "platforms": [
+      "linux"
+    ], 
+    "uses_polling": false
+  }, 
+  {
+    "args": [
       "test/core/end2end/fuzzers/client_fuzzer_corpus/685fbddd9ea612b25e325a50bd659997b4d77da1"
     ], 
     "ci_platforms": [
@@ -58831,6 +60384,25 @@
   }, 
   {
     "args": [
+      "test/core/end2end/fuzzers/client_fuzzer_corpus/69e14b73af03e8f2d998cfcf16215f65bf589efb"
+    ], 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [
+      "tsan"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "client_fuzzer_one_entry", 
+    "platforms": [
+      "linux"
+    ], 
+    "uses_polling": false
+  }, 
+  {
+    "args": [
       "test/core/end2end/fuzzers/client_fuzzer_corpus/69e52eef5dd0c51012b5c974cf70f4074ba814a9"
     ], 
     "ci_platforms": [
@@ -59116,6 +60688,25 @@
   }, 
   {
     "args": [
+      "test/core/end2end/fuzzers/client_fuzzer_corpus/77cff7548cafe87410e4a0dde3ba6892b25594d3"
+    ], 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [
+      "tsan"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "client_fuzzer_one_entry", 
+    "platforms": [
+      "linux"
+    ], 
+    "uses_polling": false
+  }, 
+  {
+    "args": [
       "test/core/end2end/fuzzers/client_fuzzer_corpus/77ea9180617391d8503427a1c060538182f7729f"
     ], 
     "ci_platforms": [
@@ -59192,6 +60783,25 @@
   }, 
   {
     "args": [
+      "test/core/end2end/fuzzers/client_fuzzer_corpus/7beeb19272131701f3a0d1dd633f1b1969899366"
+    ], 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [
+      "tsan"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "client_fuzzer_one_entry", 
+    "platforms": [
+      "linux"
+    ], 
+    "uses_polling": false
+  }, 
+  {
+    "args": [
       "test/core/end2end/fuzzers/client_fuzzer_corpus/7c2e48b0d08aaeb95b5ca26036384aa2cec9de77"
     ], 
     "ci_platforms": [
@@ -59648,6 +61258,44 @@
   }, 
   {
     "args": [
+      "test/core/end2end/fuzzers/client_fuzzer_corpus/8b0cf53ac17015fe066002cb3814933df9ee96be"
+    ], 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [
+      "tsan"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "client_fuzzer_one_entry", 
+    "platforms": [
+      "linux"
+    ], 
+    "uses_polling": false
+  }, 
+  {
+    "args": [
+      "test/core/end2end/fuzzers/client_fuzzer_corpus/8b5c4543923da5e468aca1de1ab880aed2ac4451"
+    ], 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [
+      "tsan"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "client_fuzzer_one_entry", 
+    "platforms": [
+      "linux"
+    ], 
+    "uses_polling": false
+  }, 
+  {
+    "args": [
       "test/core/end2end/fuzzers/client_fuzzer_corpus/8b7b914723bfc23ec650cb91d209141641fba09f"
     ], 
     "ci_platforms": [
@@ -59781,6 +61429,25 @@
   }, 
   {
     "args": [
+      "test/core/end2end/fuzzers/client_fuzzer_corpus/8d9784f85e9662734e180ca8bec2164425ae8a87"
+    ], 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [
+      "tsan"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "client_fuzzer_one_entry", 
+    "platforms": [
+      "linux"
+    ], 
+    "uses_polling": false
+  }, 
+  {
+    "args": [
       "test/core/end2end/fuzzers/client_fuzzer_corpus/8dfc4e78007040009f37109f9ca928c31b3ebb49"
     ], 
     "ci_platforms": [
@@ -59800,6 +61467,25 @@
   }, 
   {
     "args": [
+      "test/core/end2end/fuzzers/client_fuzzer_corpus/8e3f138d163022d6e105ab595788f4cfdd9b9db3"
+    ], 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [
+      "tsan"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "client_fuzzer_one_entry", 
+    "platforms": [
+      "linux"
+    ], 
+    "uses_polling": false
+  }, 
+  {
+    "args": [
       "test/core/end2end/fuzzers/client_fuzzer_corpus/8ea624983d766ed45780378a3eec24eb2faeb229"
     ], 
     "ci_platforms": [
@@ -59914,6 +61600,25 @@
   }, 
   {
     "args": [
+      "test/core/end2end/fuzzers/client_fuzzer_corpus/914464d372dcccf31ed5331293d84121e17616bb"
+    ], 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [
+      "tsan"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "client_fuzzer_one_entry", 
+    "platforms": [
+      "linux"
+    ], 
+    "uses_polling": false
+  }, 
+  {
+    "args": [
       "test/core/end2end/fuzzers/client_fuzzer_corpus/91916df7c8f04d8c2b6b8f4aeaeee6972ce0de74"
     ], 
     "ci_platforms": [
@@ -59990,6 +61695,63 @@
   }, 
   {
     "args": [
+      "test/core/end2end/fuzzers/client_fuzzer_corpus/934a41b5027d1c5cca27ebda57560c38cb9e09ea"
+    ], 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [
+      "tsan"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "client_fuzzer_one_entry", 
+    "platforms": [
+      "linux"
+    ], 
+    "uses_polling": false
+  }, 
+  {
+    "args": [
+      "test/core/end2end/fuzzers/client_fuzzer_corpus/9354652806d96b09c8e7082b1b7d22e7c3fb9f0b"
+    ], 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [
+      "tsan"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "client_fuzzer_one_entry", 
+    "platforms": [
+      "linux"
+    ], 
+    "uses_polling": false
+  }, 
+  {
+    "args": [
+      "test/core/end2end/fuzzers/client_fuzzer_corpus/9398ac1c2b4015792661266a9c84b6d7a68c3155"
+    ], 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [
+      "tsan"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "client_fuzzer_one_entry", 
+    "platforms": [
+      "linux"
+    ], 
+    "uses_polling": false
+  }, 
+  {
+    "args": [
       "test/core/end2end/fuzzers/client_fuzzer_corpus/93ac93b7deabdfb4f86eb37a1e9f6669957d14a6"
     ], 
     "ci_platforms": [
@@ -60180,6 +61942,44 @@
   }, 
   {
     "args": [
+      "test/core/end2end/fuzzers/client_fuzzer_corpus/99099024a3f3e389f57cb7b697eb34485846f316"
+    ], 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [
+      "tsan"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "client_fuzzer_one_entry", 
+    "platforms": [
+      "linux"
+    ], 
+    "uses_polling": false
+  }, 
+  {
+    "args": [
+      "test/core/end2end/fuzzers/client_fuzzer_corpus/998a54dc94ab6e7d6a6066415fb0dd9b52356171"
+    ], 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [
+      "tsan"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "client_fuzzer_one_entry", 
+    "platforms": [
+      "linux"
+    ], 
+    "uses_polling": false
+  }, 
+  {
+    "args": [
       "test/core/end2end/fuzzers/client_fuzzer_corpus/999d0995c2f09beda8783eac95d7643a11d5c89a"
     ], 
     "ci_platforms": [
@@ -60560,6 +62360,25 @@
   }, 
   {
     "args": [
+      "test/core/end2end/fuzzers/client_fuzzer_corpus/a25b31398669b585ccab97bceadc31994de7ead7"
+    ], 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [
+      "tsan"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "client_fuzzer_one_entry", 
+    "platforms": [
+      "linux"
+    ], 
+    "uses_polling": false
+  }, 
+  {
+    "args": [
       "test/core/end2end/fuzzers/client_fuzzer_corpus/a29a547671badd3154789e1a02bdb87332fcd6a4"
     ], 
     "ci_platforms": [
@@ -60617,6 +62436,25 @@
   }, 
   {
     "args": [
+      "test/core/end2end/fuzzers/client_fuzzer_corpus/a39ac9e92b41d1889096ed415b4c2eb1aba6ed50"
+    ], 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [
+      "tsan"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "client_fuzzer_one_entry", 
+    "platforms": [
+      "linux"
+    ], 
+    "uses_polling": false
+  }, 
+  {
+    "args": [
       "test/core/end2end/fuzzers/client_fuzzer_corpus/a3cd54d43d3b3bdfcf224d636dc11ce1b5ee4d30"
     ], 
     "ci_platforms": [
@@ -60712,6 +62550,25 @@
   }, 
   {
     "args": [
+      "test/core/end2end/fuzzers/client_fuzzer_corpus/a5c2fdae1a1c0487d00db0eec6e3429b12244b1f"
+    ], 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [
+      "tsan"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "client_fuzzer_one_entry", 
+    "platforms": [
+      "linux"
+    ], 
+    "uses_polling": false
+  }, 
+  {
+    "args": [
       "test/core/end2end/fuzzers/client_fuzzer_corpus/a5cf80b996b2ba8c9580f8ecd22720c48de41044"
     ], 
     "ci_platforms": [
@@ -60750,6 +62607,25 @@
   }, 
   {
     "args": [
+      "test/core/end2end/fuzzers/client_fuzzer_corpus/a649093880c2a2f143f861893eaff5d30be95eb7"
+    ], 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [
+      "tsan"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "client_fuzzer_one_entry", 
+    "platforms": [
+      "linux"
+    ], 
+    "uses_polling": false
+  }, 
+  {
+    "args": [
       "test/core/end2end/fuzzers/client_fuzzer_corpus/a6603e797695274d10bce000f66ca0a715f7d8c0"
     ], 
     "ci_platforms": [
@@ -60845,6 +62721,44 @@
   }, 
   {
     "args": [
+      "test/core/end2end/fuzzers/client_fuzzer_corpus/a8249ebfe91327806446f14a6b2e7d9c8440257f"
+    ], 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [
+      "tsan"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "client_fuzzer_one_entry", 
+    "platforms": [
+      "linux"
+    ], 
+    "uses_polling": false
+  }, 
+  {
+    "args": [
+      "test/core/end2end/fuzzers/client_fuzzer_corpus/a8e306820fb76566b522c23ec68bdce0ad0536f2"
+    ], 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [
+      "tsan"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "client_fuzzer_one_entry", 
+    "platforms": [
+      "linux"
+    ], 
+    "uses_polling": false
+  }, 
+  {
+    "args": [
       "test/core/end2end/fuzzers/client_fuzzer_corpus/a8e67676784506d2e6eab3a0dfa25e53a80b40a0"
     ], 
     "ci_platforms": [
@@ -60864,6 +62778,25 @@
   }, 
   {
     "args": [
+      "test/core/end2end/fuzzers/client_fuzzer_corpus/a97dbb159ef9bc6e39c9c25e04315752e871e739"
+    ], 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [
+      "tsan"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "client_fuzzer_one_entry", 
+    "platforms": [
+      "linux"
+    ], 
+    "uses_polling": false
+  }, 
+  {
+    "args": [
       "test/core/end2end/fuzzers/client_fuzzer_corpus/a9d71e1ff2912d8874e38fc61cbd9a8ef28af4a9"
     ], 
     "ci_platforms": [
@@ -61054,6 +62987,25 @@
   }, 
   {
     "args": [
+      "test/core/end2end/fuzzers/client_fuzzer_corpus/ae448bfe17f9a3a6eff074d4caa9f7261c94d2d5"
+    ], 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [
+      "tsan"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "client_fuzzer_one_entry", 
+    "platforms": [
+      "linux"
+    ], 
+    "uses_polling": false
+  }, 
+  {
+    "args": [
       "test/core/end2end/fuzzers/client_fuzzer_corpus/ae8c538d4ad7f2996ac724bad7a075e1aea32556"
     ], 
     "ci_platforms": [
@@ -61073,6 +63025,25 @@
   }, 
   {
     "args": [
+      "test/core/end2end/fuzzers/client_fuzzer_corpus/ae8cdc02275a1436bc131bee52a17ee797e2e6c9"
+    ], 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [
+      "tsan"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "client_fuzzer_one_entry", 
+    "platforms": [
+      "linux"
+    ], 
+    "uses_polling": false
+  }, 
+  {
+    "args": [
       "test/core/end2end/fuzzers/client_fuzzer_corpus/aef36c49d7dec0dcf8cdc224d9e9221fa2cb1db0"
     ], 
     "ci_platforms": [
@@ -61168,6 +63139,25 @@
   }, 
   {
     "args": [
+      "test/core/end2end/fuzzers/client_fuzzer_corpus/b10353c265bef989d8909055fd6cd52e49eef3e6"
+    ], 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [
+      "tsan"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "client_fuzzer_one_entry", 
+    "platforms": [
+      "linux"
+    ], 
+    "uses_polling": false
+  }, 
+  {
+    "args": [
       "test/core/end2end/fuzzers/client_fuzzer_corpus/b24a0dd1bc0bfabb832f0d1c8410c018c4ddaf4e"
     ], 
     "ci_platforms": [
@@ -61282,6 +63272,25 @@
   }, 
   {
     "args": [
+      "test/core/end2end/fuzzers/client_fuzzer_corpus/b387e46c23912785e6c353ab49b8ea4a92c2c2e5"
+    ], 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [
+      "tsan"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "client_fuzzer_one_entry", 
+    "platforms": [
+      "linux"
+    ], 
+    "uses_polling": false
+  }, 
+  {
+    "args": [
       "test/core/end2end/fuzzers/client_fuzzer_corpus/b39bfaf6a3072d8a50984dcc54967e9246f8d3e5"
     ], 
     "ci_platforms": [
@@ -61301,6 +63310,25 @@
   }, 
   {
     "args": [
+      "test/core/end2end/fuzzers/client_fuzzer_corpus/b3cfcd55b0331ab0c931b8c61d4df41464587f10"
+    ], 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [
+      "tsan"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "client_fuzzer_one_entry", 
+    "platforms": [
+      "linux"
+    ], 
+    "uses_polling": false
+  }, 
+  {
+    "args": [
       "test/core/end2end/fuzzers/client_fuzzer_corpus/b3f33b78433af7f607bc99b569b0cef95a1a6ca0"
     ], 
     "ci_platforms": [
@@ -61377,6 +63405,25 @@
   }, 
   {
     "args": [
+      "test/core/end2end/fuzzers/client_fuzzer_corpus/b758f5c019696f33c50895168219c0e6cb04e11d"
+    ], 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [
+      "tsan"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "client_fuzzer_one_entry", 
+    "platforms": [
+      "linux"
+    ], 
+    "uses_polling": false
+  }, 
+  {
+    "args": [
       "test/core/end2end/fuzzers/client_fuzzer_corpus/b7b664a39372dd6142b8ef7906857e4ab3f1fc84"
     ], 
     "ci_platforms": [
@@ -61415,6 +63462,44 @@
   }, 
   {
     "args": [
+      "test/core/end2end/fuzzers/client_fuzzer_corpus/b93fd0a15287dd035eac86e547e3ce42183bdb28"
+    ], 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [
+      "tsan"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "client_fuzzer_one_entry", 
+    "platforms": [
+      "linux"
+    ], 
+    "uses_polling": false
+  }, 
+  {
+    "args": [
+      "test/core/end2end/fuzzers/client_fuzzer_corpus/ba3566735888b53712c6b2e6d52ff5f2197afd6a"
+    ], 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [
+      "tsan"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "client_fuzzer_one_entry", 
+    "platforms": [
+      "linux"
+    ], 
+    "uses_polling": false
+  }, 
+  {
+    "args": [
       "test/core/end2end/fuzzers/client_fuzzer_corpus/ba942f8fb244b60561a067129c242c4bc4fdd5e1"
     ], 
     "ci_platforms": [
@@ -61548,6 +63633,25 @@
   }, 
   {
     "args": [
+      "test/core/end2end/fuzzers/client_fuzzer_corpus/bd275178fd473028a5cedf7d5780b27e809882ee"
+    ], 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [
+      "tsan"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "client_fuzzer_one_entry", 
+    "platforms": [
+      "linux"
+    ], 
+    "uses_polling": false
+  }, 
+  {
+    "args": [
       "test/core/end2end/fuzzers/client_fuzzer_corpus/be3237e72b3d8d56eec0520145dd7d1a5064eede"
     ], 
     "ci_platforms": [
@@ -61700,6 +63804,25 @@
   }, 
   {
     "args": [
+      "test/core/end2end/fuzzers/client_fuzzer_corpus/c4c53b4727e9e1f040c5d7870639dd3daa184ddb"
+    ], 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [
+      "tsan"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "client_fuzzer_one_entry", 
+    "platforms": [
+      "linux"
+    ], 
+    "uses_polling": false
+  }, 
+  {
+    "args": [
       "test/core/end2end/fuzzers/client_fuzzer_corpus/c4e60ae7c05b12a90dd7c43fbc85ae4be7540f18"
     ], 
     "ci_platforms": [
@@ -61890,6 +64013,25 @@
   }, 
   {
     "args": [
+      "test/core/end2end/fuzzers/client_fuzzer_corpus/c9e2cf8be8a4dc2294020026c62840ef1fb4853b"
+    ], 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [
+      "tsan"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "client_fuzzer_one_entry", 
+    "platforms": [
+      "linux"
+    ], 
+    "uses_polling": false
+  }, 
+  {
+    "args": [
       "test/core/end2end/fuzzers/client_fuzzer_corpus/ca0db313bf949ba3f87a5254646a7a7dc8a7f89d"
     ], 
     "ci_platforms": [
@@ -61909,6 +64051,63 @@
   }, 
   {
     "args": [
+      "test/core/end2end/fuzzers/client_fuzzer_corpus/caaf9a7751c0eccc34f0fc00a048012ab5ed2f37"
+    ], 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [
+      "tsan"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "client_fuzzer_one_entry", 
+    "platforms": [
+      "linux"
+    ], 
+    "uses_polling": false
+  }, 
+  {
+    "args": [
+      "test/core/end2end/fuzzers/client_fuzzer_corpus/cb49955601d171fd14c9ac21137b221392c7dab1"
+    ], 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [
+      "tsan"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "client_fuzzer_one_entry", 
+    "platforms": [
+      "linux"
+    ], 
+    "uses_polling": false
+  }, 
+  {
+    "args": [
+      "test/core/end2end/fuzzers/client_fuzzer_corpus/cbaabef34763f2fd922e67ff5f2ea283347e9823"
+    ], 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [
+      "tsan"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "client_fuzzer_one_entry", 
+    "platforms": [
+      "linux"
+    ], 
+    "uses_polling": false
+  }, 
+  {
+    "args": [
       "test/core/end2end/fuzzers/client_fuzzer_corpus/cbe59c62c6d36c7307c438159327e320cd2fcf57"
     ], 
     "ci_platforms": [
@@ -62004,6 +64203,25 @@
   }, 
   {
     "args": [
+      "test/core/end2end/fuzzers/client_fuzzer_corpus/cdd1a4e358ee2396ece54b32c1f0a8d0a2e3f3dc"
+    ], 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [
+      "tsan"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "client_fuzzer_one_entry", 
+    "platforms": [
+      "linux"
+    ], 
+    "uses_polling": false
+  }, 
+  {
+    "args": [
       "test/core/end2end/fuzzers/client_fuzzer_corpus/ce1c326f3b0147841550ce3b5126390764bae8e8"
     ], 
     "ci_platforms": [
@@ -62099,6 +64317,25 @@
   }, 
   {
     "args": [
+      "test/core/end2end/fuzzers/client_fuzzer_corpus/cf922d44bf08d223d3ebcd37a7e77d3e43555d08"
+    ], 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [
+      "tsan"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "client_fuzzer_one_entry", 
+    "platforms": [
+      "linux"
+    ], 
+    "uses_polling": false
+  }, 
+  {
+    "args": [
       "test/core/end2end/fuzzers/client_fuzzer_corpus/cfa40fccc5ea4304e83ca26f4e567765c2c08627"
     ], 
     "ci_platforms": [
@@ -62289,6 +64526,44 @@
   }, 
   {
     "args": [
+      "test/core/end2end/fuzzers/client_fuzzer_corpus/crash-ff53a3d713e83ae945b8dd1782e21f5b51aa649a"
+    ], 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [
+      "tsan"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "client_fuzzer_one_entry", 
+    "platforms": [
+      "linux"
+    ], 
+    "uses_polling": false
+  }, 
+  {
+    "args": [
+      "test/core/end2end/fuzzers/client_fuzzer_corpus/d17e9507af1855fcf9eca78e2d25c8fb2c40a34c"
+    ], 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [
+      "tsan"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "client_fuzzer_one_entry", 
+    "platforms": [
+      "linux"
+    ], 
+    "uses_polling": false
+  }, 
+  {
+    "args": [
       "test/core/end2end/fuzzers/client_fuzzer_corpus/d194592e6f471dd487ca2625e6c3da7802ea372f"
     ], 
     "ci_platforms": [
@@ -62498,6 +64773,25 @@
   }, 
   {
     "args": [
+      "test/core/end2end/fuzzers/client_fuzzer_corpus/d46c3dcede830286dd9f4a1ba02a20a0b1430664"
+    ], 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [
+      "tsan"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "client_fuzzer_one_entry", 
+    "platforms": [
+      "linux"
+    ], 
+    "uses_polling": false
+  }, 
+  {
+    "args": [
       "test/core/end2end/fuzzers/client_fuzzer_corpus/d49450b97f489f0dea74a9f83c71abeba1066d3c"
     ], 
     "ci_platforms": [
@@ -62536,6 +64830,44 @@
   }, 
   {
     "args": [
+      "test/core/end2end/fuzzers/client_fuzzer_corpus/d4a744ef6dcef5cf08d5289e167b26270d39e9f2"
+    ], 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [
+      "tsan"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "client_fuzzer_one_entry", 
+    "platforms": [
+      "linux"
+    ], 
+    "uses_polling": false
+  }, 
+  {
+    "args": [
+      "test/core/end2end/fuzzers/client_fuzzer_corpus/d5a85ad91cfde27a96960b2e783d2ee43c50dcb9"
+    ], 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [
+      "tsan"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "client_fuzzer_one_entry", 
+    "platforms": [
+      "linux"
+    ], 
+    "uses_polling": false
+  }, 
+  {
+    "args": [
       "test/core/end2end/fuzzers/client_fuzzer_corpus/d60469c0b5b385f20d55aa5cca55bc2c801f3b95"
     ], 
     "ci_platforms": [
@@ -62612,6 +64944,25 @@
   }, 
   {
     "args": [
+      "test/core/end2end/fuzzers/client_fuzzer_corpus/d88bb0b7ff687af84f33e6af22d3516fcdac5534"
+    ], 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [
+      "tsan"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "client_fuzzer_one_entry", 
+    "platforms": [
+      "linux"
+    ], 
+    "uses_polling": false
+  }, 
+  {
+    "args": [
       "test/core/end2end/fuzzers/client_fuzzer_corpus/d89026894e6c5f8b5c88dec12950f56c4b6924ba"
     ], 
     "ci_platforms": [
@@ -62631,6 +64982,25 @@
   }, 
   {
     "args": [
+      "test/core/end2end/fuzzers/client_fuzzer_corpus/d895ece988ad4712b87de8aa9bc273eee315e8b8"
+    ], 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [
+      "tsan"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "client_fuzzer_one_entry", 
+    "platforms": [
+      "linux"
+    ], 
+    "uses_polling": false
+  }, 
+  {
+    "args": [
       "test/core/end2end/fuzzers/client_fuzzer_corpus/d90c312791129dee8c5f85cb3308323d0c39b70d"
     ], 
     "ci_platforms": [
@@ -62688,6 +65058,25 @@
   }, 
   {
     "args": [
+      "test/core/end2end/fuzzers/client_fuzzer_corpus/da424090e1b94c5d0e91e26f3f3dd6c4af18fcd5"
+    ], 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [
+      "tsan"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "client_fuzzer_one_entry", 
+    "platforms": [
+      "linux"
+    ], 
+    "uses_polling": false
+  }, 
+  {
+    "args": [
       "test/core/end2end/fuzzers/client_fuzzer_corpus/da4d300d0a8e6f803ec053e3e7689c4b91eaef90"
     ], 
     "ci_platforms": [
@@ -62764,6 +65153,25 @@
   }, 
   {
     "args": [
+      "test/core/end2end/fuzzers/client_fuzzer_corpus/db3a30a6d8e605dd587e51b214c42f68bc43cf19"
+    ], 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [
+      "tsan"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "client_fuzzer_one_entry", 
+    "platforms": [
+      "linux"
+    ], 
+    "uses_polling": false
+  }, 
+  {
+    "args": [
       "test/core/end2end/fuzzers/client_fuzzer_corpus/dc4a248fa4c903ce3a571dd18aea575019445740"
     ], 
     "ci_platforms": [
@@ -63068,6 +65476,25 @@
   }, 
   {
     "args": [
+      "test/core/end2end/fuzzers/client_fuzzer_corpus/e3d12a2385b75443fe38d989e77c252e1f3cdb6d"
+    ], 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [
+      "tsan"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "client_fuzzer_one_entry", 
+    "platforms": [
+      "linux"
+    ], 
+    "uses_polling": false
+  }, 
+  {
+    "args": [
       "test/core/end2end/fuzzers/client_fuzzer_corpus/e40b0fa5d814be8f2081ca2c8e0a4090d4893831"
     ], 
     "ci_platforms": [
@@ -63144,6 +65571,25 @@
   }, 
   {
     "args": [
+      "test/core/end2end/fuzzers/client_fuzzer_corpus/e4f55281c481484bd9edc28fd10df0c2e0f7d546"
+    ], 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [
+      "tsan"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "client_fuzzer_one_entry", 
+    "platforms": [
+      "linux"
+    ], 
+    "uses_polling": false
+  }, 
+  {
+    "args": [
       "test/core/end2end/fuzzers/client_fuzzer_corpus/e5a7c086208248a15ee6fa5195fc4ce22469de15"
     ], 
     "ci_platforms": [
@@ -63239,6 +65685,25 @@
   }, 
   {
     "args": [
+      "test/core/end2end/fuzzers/client_fuzzer_corpus/e6c52f2f31db7595d1ecde2939a7390777f15182"
+    ], 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [
+      "tsan"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "client_fuzzer_one_entry", 
+    "platforms": [
+      "linux"
+    ], 
+    "uses_polling": false
+  }, 
+  {
+    "args": [
       "test/core/end2end/fuzzers/client_fuzzer_corpus/e6f5cc0702a5f38b9e7339849e1dd2e4001e547d"
     ], 
     "ci_platforms": [
@@ -63543,6 +66008,44 @@
   }, 
   {
     "args": [
+      "test/core/end2end/fuzzers/client_fuzzer_corpus/f09cd3e3a16658174717668e51e7382e491df1da"
+    ], 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [
+      "tsan"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "client_fuzzer_one_entry", 
+    "platforms": [
+      "linux"
+    ], 
+    "uses_polling": false
+  }, 
+  {
+    "args": [
+      "test/core/end2end/fuzzers/client_fuzzer_corpus/f11abb090bae8cdac1f7d9a2e344f2def0e50066"
+    ], 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [
+      "tsan"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "client_fuzzer_one_entry", 
+    "platforms": [
+      "linux"
+    ], 
+    "uses_polling": false
+  }, 
+  {
+    "args": [
       "test/core/end2end/fuzzers/client_fuzzer_corpus/f1b9b6803e41beabb1a762d511fc148116e09e78"
     ], 
     "ci_platforms": [
@@ -63638,6 +66141,44 @@
   }, 
   {
     "args": [
+      "test/core/end2end/fuzzers/client_fuzzer_corpus/f4ae2a2b692bfa83cdde75d007813426e14daef7"
+    ], 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [
+      "tsan"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "client_fuzzer_one_entry", 
+    "platforms": [
+      "linux"
+    ], 
+    "uses_polling": false
+  }, 
+  {
+    "args": [
+      "test/core/end2end/fuzzers/client_fuzzer_corpus/f5a629c8fd5720236b66a875e96ea22e29c45965"
+    ], 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [
+      "tsan"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "client_fuzzer_one_entry", 
+    "platforms": [
+      "linux"
+    ], 
+    "uses_polling": false
+  }, 
+  {
+    "args": [
       "test/core/end2end/fuzzers/client_fuzzer_corpus/f5b1eab444efb2664a295d4e6d087eb209c0c480"
     ], 
     "ci_platforms": [
@@ -63657,6 +66198,25 @@
   }, 
   {
     "args": [
+      "test/core/end2end/fuzzers/client_fuzzer_corpus/f6627c55881fe4f0c8e6999980fb226836e6f5ce"
+    ], 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [
+      "tsan"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "client_fuzzer_one_entry", 
+    "platforms": [
+      "linux"
+    ], 
+    "uses_polling": false
+  }, 
+  {
+    "args": [
       "test/core/end2end/fuzzers/client_fuzzer_corpus/f66305230042fa83fcd1b98c469d90ffef3ff6da"
     ], 
     "ci_platforms": [
@@ -63733,6 +66293,44 @@
   }, 
   {
     "args": [
+      "test/core/end2end/fuzzers/client_fuzzer_corpus/f7aeceaf0b6d971038a677994b5d080fa0e18011"
+    ], 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [
+      "tsan"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "client_fuzzer_one_entry", 
+    "platforms": [
+      "linux"
+    ], 
+    "uses_polling": false
+  }, 
+  {
+    "args": [
+      "test/core/end2end/fuzzers/client_fuzzer_corpus/f803c87a92662898e2c8c847787b56d2c31f63b3"
+    ], 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [
+      "tsan"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "client_fuzzer_one_entry", 
+    "platforms": [
+      "linux"
+    ], 
+    "uses_polling": false
+  }, 
+  {
+    "args": [
       "test/core/end2end/fuzzers/client_fuzzer_corpus/f8467d9574de94b9bb904f75a6a7e2405c36f105"
     ], 
     "ci_platforms": [
@@ -63771,6 +66369,25 @@
   }, 
   {
     "args": [
+      "test/core/end2end/fuzzers/client_fuzzer_corpus/f89ad475ff51a5a9fe18603df833453bed320f36"
+    ], 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [
+      "tsan"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "client_fuzzer_one_entry", 
+    "platforms": [
+      "linux"
+    ], 
+    "uses_polling": false
+  }, 
+  {
+    "args": [
       "test/core/end2end/fuzzers/client_fuzzer_corpus/f8fb1348ec3ceeb75c2a03df6a2ead0de6f4127a"
     ], 
     "ci_platforms": [
@@ -63809,6 +66426,25 @@
   }, 
   {
     "args": [
+      "test/core/end2end/fuzzers/client_fuzzer_corpus/f9583b3a39c1aecbba6e81d71e7fe9b9519c8b08"
+    ], 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [
+      "tsan"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "client_fuzzer_one_entry", 
+    "platforms": [
+      "linux"
+    ], 
+    "uses_polling": false
+  }, 
+  {
+    "args": [
       "test/core/end2end/fuzzers/client_fuzzer_corpus/f96843fdf2d6fdd661c26201d96ae7bec72c6c3d"
     ], 
     "ci_platforms": [
@@ -64018,6 +66654,25 @@
   }, 
   {
     "args": [
+      "test/core/end2end/fuzzers/client_fuzzer_corpus/ffd52d31f9c59a346aa195a683f077dda5ecef6b"
+    ], 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [
+      "tsan"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "client_fuzzer_one_entry", 
+    "platforms": [
+      "linux"
+    ], 
+    "uses_polling": false
+  }, 
+  {
+    "args": [
       "test/core/end2end/fuzzers/client_fuzzer_corpus/hdr_frame.bin"
     ], 
     "ci_platforms": [
diff --git a/vsprojects/buildtests_c.sln b/vsprojects/buildtests_c.sln
index c28f3ba..56800c4 100644
--- a/vsprojects/buildtests_c.sln
+++ b/vsprojects/buildtests_c.sln
@@ -175,6 +175,17 @@
 		{B23D3D1A-9438-4EDA-BEB6-9A0A03D17792} = {B23D3D1A-9438-4EDA-BEB6-9A0A03D17792}
 	EndProjectSection
 EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "combiner_test", "vcxproj\test\combiner_test\combiner_test.vcxproj", "{C237D1E4-8825-80BA-1FC3-5E147E53E96E}"
+	ProjectSection(myProperties) = preProject
+        	lib = "False"
+	EndProjectSection
+	ProjectSection(ProjectDependencies) = postProject
+		{17BCAFC0-5FDC-4C94-AEB9-95F3E220614B} = {17BCAFC0-5FDC-4C94-AEB9-95F3E220614B}
+		{29D16885-7228-4C31-81ED-5F9187C7F2A9} = {29D16885-7228-4C31-81ED-5F9187C7F2A9}
+		{EAB0A629-17A9-44DB-B5FF-E91A721FE037} = {EAB0A629-17A9-44DB-B5FF-E91A721FE037}
+		{B23D3D1A-9438-4EDA-BEB6-9A0A03D17792} = {B23D3D1A-9438-4EDA-BEB6-9A0A03D17792}
+	EndProjectSection
+EndProject
 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "compression_test", "vcxproj\test\compression_test\compression_test.vcxproj", "{5AFE7D17-A4A7-D68E-4491-CBC852F9D2A0}"
 	ProjectSection(myProperties) = preProject
         	lib = "False"
@@ -377,6 +388,15 @@
 		{B23D3D1A-9438-4EDA-BEB6-9A0A03D17792} = {B23D3D1A-9438-4EDA-BEB6-9A0A03D17792}
 	EndProjectSection
 EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "gpr_mpscq_test", "vcxproj\test\gpr_mpscq_test\gpr_mpscq_test.vcxproj", "{B3D7760B-8BEA-2EF6-F1D4-9F9020E166D6}"
+	ProjectSection(myProperties) = preProject
+        	lib = "False"
+	EndProjectSection
+	ProjectSection(ProjectDependencies) = postProject
+		{EAB0A629-17A9-44DB-B5FF-E91A721FE037} = {EAB0A629-17A9-44DB-B5FF-E91A721FE037}
+		{B23D3D1A-9438-4EDA-BEB6-9A0A03D17792} = {B23D3D1A-9438-4EDA-BEB6-9A0A03D17792}
+	EndProjectSection
+EndProject
 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "gpr_slice_buffer_test", "vcxproj\test\gpr_slice_buffer_test\gpr_slice_buffer_test.vcxproj", "{E679773D-DE89-AEBB-9787-59019989B825}"
 	ProjectSection(myProperties) = preProject
         	lib = "False"
@@ -1706,6 +1726,22 @@
 		{6B29F634-1277-74B8-47F6-78756190BA7B}.Release-DLL|Win32.Build.0 = Release|Win32
 		{6B29F634-1277-74B8-47F6-78756190BA7B}.Release-DLL|x64.ActiveCfg = Release|x64
 		{6B29F634-1277-74B8-47F6-78756190BA7B}.Release-DLL|x64.Build.0 = Release|x64
+		{C237D1E4-8825-80BA-1FC3-5E147E53E96E}.Debug|Win32.ActiveCfg = Debug|Win32
+		{C237D1E4-8825-80BA-1FC3-5E147E53E96E}.Debug|x64.ActiveCfg = Debug|x64
+		{C237D1E4-8825-80BA-1FC3-5E147E53E96E}.Release|Win32.ActiveCfg = Release|Win32
+		{C237D1E4-8825-80BA-1FC3-5E147E53E96E}.Release|x64.ActiveCfg = Release|x64
+		{C237D1E4-8825-80BA-1FC3-5E147E53E96E}.Debug|Win32.Build.0 = Debug|Win32
+		{C237D1E4-8825-80BA-1FC3-5E147E53E96E}.Debug|x64.Build.0 = Debug|x64
+		{C237D1E4-8825-80BA-1FC3-5E147E53E96E}.Release|Win32.Build.0 = Release|Win32
+		{C237D1E4-8825-80BA-1FC3-5E147E53E96E}.Release|x64.Build.0 = Release|x64
+		{C237D1E4-8825-80BA-1FC3-5E147E53E96E}.Debug-DLL|Win32.ActiveCfg = Debug|Win32
+		{C237D1E4-8825-80BA-1FC3-5E147E53E96E}.Debug-DLL|Win32.Build.0 = Debug|Win32
+		{C237D1E4-8825-80BA-1FC3-5E147E53E96E}.Debug-DLL|x64.ActiveCfg = Debug|x64
+		{C237D1E4-8825-80BA-1FC3-5E147E53E96E}.Debug-DLL|x64.Build.0 = Debug|x64
+		{C237D1E4-8825-80BA-1FC3-5E147E53E96E}.Release-DLL|Win32.ActiveCfg = Release|Win32
+		{C237D1E4-8825-80BA-1FC3-5E147E53E96E}.Release-DLL|Win32.Build.0 = Release|Win32
+		{C237D1E4-8825-80BA-1FC3-5E147E53E96E}.Release-DLL|x64.ActiveCfg = Release|x64
+		{C237D1E4-8825-80BA-1FC3-5E147E53E96E}.Release-DLL|x64.Build.0 = Release|x64
 		{5AFE7D17-A4A7-D68E-4491-CBC852F9D2A0}.Debug|Win32.ActiveCfg = Debug|Win32
 		{5AFE7D17-A4A7-D68E-4491-CBC852F9D2A0}.Debug|x64.ActiveCfg = Debug|x64
 		{5AFE7D17-A4A7-D68E-4491-CBC852F9D2A0}.Release|Win32.ActiveCfg = Release|Win32
@@ -2042,6 +2078,22 @@
 		{38797EE3-62CC-3CBF-18D5-009ED6DD0BEC}.Release-DLL|Win32.Build.0 = Release|Win32
 		{38797EE3-62CC-3CBF-18D5-009ED6DD0BEC}.Release-DLL|x64.ActiveCfg = Release|x64
 		{38797EE3-62CC-3CBF-18D5-009ED6DD0BEC}.Release-DLL|x64.Build.0 = Release|x64
+		{B3D7760B-8BEA-2EF6-F1D4-9F9020E166D6}.Debug|Win32.ActiveCfg = Debug|Win32
+		{B3D7760B-8BEA-2EF6-F1D4-9F9020E166D6}.Debug|x64.ActiveCfg = Debug|x64
+		{B3D7760B-8BEA-2EF6-F1D4-9F9020E166D6}.Release|Win32.ActiveCfg = Release|Win32
+		{B3D7760B-8BEA-2EF6-F1D4-9F9020E166D6}.Release|x64.ActiveCfg = Release|x64
+		{B3D7760B-8BEA-2EF6-F1D4-9F9020E166D6}.Debug|Win32.Build.0 = Debug|Win32
+		{B3D7760B-8BEA-2EF6-F1D4-9F9020E166D6}.Debug|x64.Build.0 = Debug|x64
+		{B3D7760B-8BEA-2EF6-F1D4-9F9020E166D6}.Release|Win32.Build.0 = Release|Win32
+		{B3D7760B-8BEA-2EF6-F1D4-9F9020E166D6}.Release|x64.Build.0 = Release|x64
+		{B3D7760B-8BEA-2EF6-F1D4-9F9020E166D6}.Debug-DLL|Win32.ActiveCfg = Debug|Win32
+		{B3D7760B-8BEA-2EF6-F1D4-9F9020E166D6}.Debug-DLL|Win32.Build.0 = Debug|Win32
+		{B3D7760B-8BEA-2EF6-F1D4-9F9020E166D6}.Debug-DLL|x64.ActiveCfg = Debug|x64
+		{B3D7760B-8BEA-2EF6-F1D4-9F9020E166D6}.Debug-DLL|x64.Build.0 = Debug|x64
+		{B3D7760B-8BEA-2EF6-F1D4-9F9020E166D6}.Release-DLL|Win32.ActiveCfg = Release|Win32
+		{B3D7760B-8BEA-2EF6-F1D4-9F9020E166D6}.Release-DLL|Win32.Build.0 = Release|Win32
+		{B3D7760B-8BEA-2EF6-F1D4-9F9020E166D6}.Release-DLL|x64.ActiveCfg = Release|x64
+		{B3D7760B-8BEA-2EF6-F1D4-9F9020E166D6}.Release-DLL|x64.Build.0 = Release|x64
 		{E679773D-DE89-AEBB-9787-59019989B825}.Debug|Win32.ActiveCfg = Debug|Win32
 		{E679773D-DE89-AEBB-9787-59019989B825}.Debug|x64.ActiveCfg = Debug|x64
 		{E679773D-DE89-AEBB-9787-59019989B825}.Release|Win32.ActiveCfg = Release|Win32
diff --git a/vsprojects/grpc.sln b/vsprojects/grpc.sln
index 8472091..8fccc64 100644
--- a/vsprojects/grpc.sln
+++ b/vsprojects/grpc.sln
@@ -49,6 +49,7 @@
 	EndProjectSection
 	ProjectSection(ProjectDependencies) = postProject
 		{29D16885-7228-4C31-81ED-5F9187C7F2A9} = {29D16885-7228-4C31-81ED-5F9187C7F2A9}
+		{B23D3D1A-9438-4EDA-BEB6-9A0A03D17792} = {B23D3D1A-9438-4EDA-BEB6-9A0A03D17792}
 	EndProjectSection
 EndProject
 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "grpc++_reflection", "vcxproj\.\grpc++_reflection\grpc++_reflection.vcxproj", "{5F575402-3F89-5D1A-6910-9DB8BF5D2BAB}"
@@ -66,7 +67,6 @@
 	ProjectSection(ProjectDependencies) = postProject
 		{B23D3D1A-9438-4EDA-BEB6-9A0A03D17792} = {B23D3D1A-9438-4EDA-BEB6-9A0A03D17792}
 		{46CEDFFF-9692-456A-AA24-38B5D6BCF4C5} = {46CEDFFF-9692-456A-AA24-38B5D6BCF4C5}
-		{29D16885-7228-4C31-81ED-5F9187C7F2A9} = {29D16885-7228-4C31-81ED-5F9187C7F2A9}
 	EndProjectSection
 EndProject
 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "grpc_create_jwt", "vcxproj\.\grpc_create_jwt\grpc_create_jwt.vcxproj", "{77971F8D-F583-3E77-0E3C-6C1FB6B1749C}"
diff --git a/vsprojects/vcxproj/gpr/gpr.vcxproj b/vsprojects/vcxproj/gpr/gpr.vcxproj
index db8594e..f565d80 100644
--- a/vsprojects/vcxproj/gpr/gpr.vcxproj
+++ b/vsprojects/vcxproj/gpr/gpr.vcxproj
@@ -195,6 +195,7 @@
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\support\backoff.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\support\block_annotate.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\support\env.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\support\mpscq.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\support\murmur_hash.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\support\stack_lockfree.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\support\string.h" />
@@ -244,6 +245,8 @@
     </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\lib\support\log_windows.c">
     </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\support\mpscq.c">
+    </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\lib\support\murmur_hash.c">
     </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\lib\support\slice.c">
diff --git a/vsprojects/vcxproj/gpr/gpr.vcxproj.filters b/vsprojects/vcxproj/gpr/gpr.vcxproj.filters
index 9bab373..0dc13e3 100644
--- a/vsprojects/vcxproj/gpr/gpr.vcxproj.filters
+++ b/vsprojects/vcxproj/gpr/gpr.vcxproj.filters
@@ -61,6 +61,9 @@
     <ClCompile Include="$(SolutionDir)\..\src\core\lib\support\log_windows.c">
       <Filter>src\core\lib\support</Filter>
     </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\support\mpscq.c">
+      <Filter>src\core\lib\support</Filter>
+    </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\lib\support\murmur_hash.c">
       <Filter>src\core\lib\support</Filter>
     </ClCompile>
@@ -278,6 +281,9 @@
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\support\env.h">
       <Filter>src\core\lib\support</Filter>
     </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\support\mpscq.h">
+      <Filter>src\core\lib\support</Filter>
+    </ClInclude>
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\support\murmur_hash.h">
       <Filter>src\core\lib\support</Filter>
     </ClInclude>
diff --git a/vsprojects/vcxproj/grpc++/grpc++.vcxproj b/vsprojects/vcxproj/grpc++/grpc++.vcxproj
index 835e252..321a403 100644
--- a/vsprojects/vcxproj/grpc++/grpc++.vcxproj
+++ b/vsprojects/vcxproj/grpc++/grpc++.vcxproj
@@ -305,6 +305,34 @@
     <ClInclude Include="$(SolutionDir)\..\include\grpc++\support\stub_options.h" />
     <ClInclude Include="$(SolutionDir)\..\include\grpc++\support\sync_stream.h" />
     <ClInclude Include="$(SolutionDir)\..\include\grpc++\support\time.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\byte_buffer.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\byte_buffer_reader.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\compression.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\grpc.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\grpc_posix.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\grpc_security_constants.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\status.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\byte_buffer.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\byte_buffer_reader.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\compression_types.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\connectivity_state.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\grpc_types.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\propagation_bits.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\status.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\alloc.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\atm.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\atm_gcc_atomic.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\atm_gcc_sync.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\atm_windows.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\log.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\port_platform.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\slice.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\slice_buffer.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\sync.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\sync_generic.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\sync_posix.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\sync_windows.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\time.h" />
     <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\async_stream.h" />
     <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\async_unary_call.h" />
     <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\call.h" />
@@ -335,27 +363,6 @@
     <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\sync_no_cxx11.h" />
     <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\sync_stream.h" />
     <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\time.h" />
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\byte_buffer.h" />
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\byte_buffer_reader.h" />
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\compression_types.h" />
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\connectivity_state.h" />
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\grpc_types.h" />
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\propagation_bits.h" />
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\status.h" />
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\alloc.h" />
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\atm.h" />
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\atm_gcc_atomic.h" />
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\atm_gcc_sync.h" />
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\atm_windows.h" />
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\log.h" />
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\port_platform.h" />
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\slice.h" />
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\slice_buffer.h" />
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\sync.h" />
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\sync_generic.h" />
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\sync_posix.h" />
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\sync_windows.h" />
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\time.h" />
   </ItemGroup>
   <ItemGroup>
     <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\core_codegen.h" />
@@ -366,6 +373,86 @@
     <ClInclude Include="$(SolutionDir)\..\src\cpp\common\channel_filter.h" />
     <ClInclude Include="$(SolutionDir)\..\src\cpp\server\dynamic_thread_pool.h" />
     <ClInclude Include="$(SolutionDir)\..\src\cpp\server\thread_pool_interface.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\channel_args.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\channel_stack.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\channel_stack_builder.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\compress_filter.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\connected_channel.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\context.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\handshaker.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\http_client_filter.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\http_server_filter.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\compression\algorithm_metadata.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\compression\message_compress.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\debug\trace.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\http\format_request.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\http\httpcli.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\http\parser.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\closure.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\endpoint.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\endpoint_pair.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\error.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\ev_epoll_linux.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\ev_poll_and_epoll_posix.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\ev_poll_posix.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\ev_posix.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\exec_ctx.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\executor.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\iocp_windows.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\iomgr.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\iomgr_internal.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\iomgr_posix.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\load_file.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\network_status_tracker.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\polling_entity.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\pollset.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\pollset_set.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\pollset_set_windows.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\pollset_windows.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\resolve_address.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\sockaddr.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\sockaddr_posix.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\sockaddr_utils.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\sockaddr_windows.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\socket_utils_posix.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\socket_windows.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\tcp_client.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\tcp_posix.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\tcp_server.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\tcp_windows.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\time_averaged_stats.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\timer.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\timer_heap.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\udp_server.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\unix_sockets_posix.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\wakeup_fd_pipe.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\wakeup_fd_posix.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\workqueue.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\workqueue_posix.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\workqueue_windows.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\json\json.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\json\json_common.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\json\json_reader.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\json\json_writer.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\surface\api_trace.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\surface\call.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\surface\call_test_only.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\surface\channel.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\surface\channel_init.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\surface\channel_stack_type.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\surface\completion_queue.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\surface\event_string.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\surface\init.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\surface\lame_client.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\surface\server.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\byte_stream.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\connectivity_state.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\metadata.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\metadata_batch.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\static_metadata.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\timeout_encoding.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\transport.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\transport_impl.h" />
   </ItemGroup>
   <ItemGroup>
     <ClCompile Include="$(SolutionDir)\..\src\cpp\client\secure_credentials.cc">
@@ -434,6 +521,184 @@
     </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\cpp\util\time.cc">
     </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\channel_args.c">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\channel_stack.c">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\channel_stack_builder.c">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\compress_filter.c">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\connected_channel.c">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\handshaker.c">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\http_client_filter.c">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\http_server_filter.c">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\compression\compression.c">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\compression\message_compress.c">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\debug\trace.c">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\http\format_request.c">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\http\httpcli.c">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\http\parser.c">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\closure.c">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\endpoint.c">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\endpoint_pair_posix.c">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\endpoint_pair_windows.c">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\error.c">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\ev_epoll_linux.c">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\ev_poll_and_epoll_posix.c">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\ev_poll_posix.c">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\ev_posix.c">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\exec_ctx.c">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\executor.c">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\iocp_windows.c">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\iomgr.c">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\iomgr_posix.c">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\iomgr_windows.c">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\load_file.c">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\network_status_tracker.c">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\polling_entity.c">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\pollset_set_windows.c">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\pollset_windows.c">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\resolve_address_posix.c">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\resolve_address_windows.c">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\sockaddr_utils.c">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\socket_utils_common_posix.c">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\socket_utils_linux.c">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\socket_utils_posix.c">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\socket_windows.c">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\tcp_client_posix.c">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\tcp_client_windows.c">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\tcp_posix.c">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\tcp_server_posix.c">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\tcp_server_windows.c">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\tcp_windows.c">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\time_averaged_stats.c">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\timer.c">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\timer_heap.c">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\udp_server.c">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\unix_sockets_posix.c">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\unix_sockets_posix_noop.c">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\wakeup_fd_eventfd.c">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\wakeup_fd_nospecial.c">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\wakeup_fd_pipe.c">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\wakeup_fd_posix.c">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\workqueue_posix.c">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\workqueue_windows.c">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\json\json.c">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\json\json_reader.c">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\json\json_string.c">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\json\json_writer.c">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\alarm.c">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\api_trace.c">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\byte_buffer.c">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\byte_buffer_reader.c">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\call.c">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\call_details.c">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\call_log_batch.c">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\channel.c">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\channel_init.c">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\channel_ping.c">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\channel_stack_type.c">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\completion_queue.c">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\event_string.c">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\lame_client.c">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\metadata_array.c">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\server.c">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\validate_metadata.c">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\version.c">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\transport\byte_stream.c">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\transport\connectivity_state.c">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\transport\metadata.c">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\transport\metadata_batch.c">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\transport\static_metadata.c">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\transport\timeout_encoding.c">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\transport\transport.c">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\transport\transport_op_string.c">
+    </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\cpp\codegen\codegen_init.cc">
     </ClCompile>
   </ItemGroup>
@@ -441,6 +706,9 @@
     <ProjectReference Include="$(SolutionDir)\..\vsprojects\vcxproj\.\grpc\grpc.vcxproj">
       <Project>{29D16885-7228-4C31-81ED-5F9187C7F2A9}</Project>
     </ProjectReference>
+    <ProjectReference Include="$(SolutionDir)\..\vsprojects\vcxproj\.\gpr\gpr.vcxproj">
+      <Project>{B23D3D1A-9438-4EDA-BEB6-9A0A03D17792}</Project>
+    </ProjectReference>
   </ItemGroup>
   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
   <ImportGroup Label="ExtensionTargets">
diff --git a/vsprojects/vcxproj/grpc++/grpc++.vcxproj.filters b/vsprojects/vcxproj/grpc++/grpc++.vcxproj.filters
index 883e66e..b34ca03 100644
--- a/vsprojects/vcxproj/grpc++/grpc++.vcxproj.filters
+++ b/vsprojects/vcxproj/grpc++/grpc++.vcxproj.filters
@@ -100,6 +100,273 @@
     <ClCompile Include="$(SolutionDir)\..\src\cpp\util\time.cc">
       <Filter>src\cpp\util</Filter>
     </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\channel_args.c">
+      <Filter>src\core\lib\channel</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\channel_stack.c">
+      <Filter>src\core\lib\channel</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\channel_stack_builder.c">
+      <Filter>src\core\lib\channel</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\compress_filter.c">
+      <Filter>src\core\lib\channel</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\connected_channel.c">
+      <Filter>src\core\lib\channel</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\handshaker.c">
+      <Filter>src\core\lib\channel</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\http_client_filter.c">
+      <Filter>src\core\lib\channel</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\http_server_filter.c">
+      <Filter>src\core\lib\channel</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\compression\compression.c">
+      <Filter>src\core\lib\compression</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\compression\message_compress.c">
+      <Filter>src\core\lib\compression</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\debug\trace.c">
+      <Filter>src\core\lib\debug</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\http\format_request.c">
+      <Filter>src\core\lib\http</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\http\httpcli.c">
+      <Filter>src\core\lib\http</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\http\parser.c">
+      <Filter>src\core\lib\http</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\closure.c">
+      <Filter>src\core\lib\iomgr</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\endpoint.c">
+      <Filter>src\core\lib\iomgr</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\endpoint_pair_posix.c">
+      <Filter>src\core\lib\iomgr</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\endpoint_pair_windows.c">
+      <Filter>src\core\lib\iomgr</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\error.c">
+      <Filter>src\core\lib\iomgr</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\ev_epoll_linux.c">
+      <Filter>src\core\lib\iomgr</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\ev_poll_and_epoll_posix.c">
+      <Filter>src\core\lib\iomgr</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\ev_poll_posix.c">
+      <Filter>src\core\lib\iomgr</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\ev_posix.c">
+      <Filter>src\core\lib\iomgr</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\exec_ctx.c">
+      <Filter>src\core\lib\iomgr</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\executor.c">
+      <Filter>src\core\lib\iomgr</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\iocp_windows.c">
+      <Filter>src\core\lib\iomgr</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\iomgr.c">
+      <Filter>src\core\lib\iomgr</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\iomgr_posix.c">
+      <Filter>src\core\lib\iomgr</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\iomgr_windows.c">
+      <Filter>src\core\lib\iomgr</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\load_file.c">
+      <Filter>src\core\lib\iomgr</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\network_status_tracker.c">
+      <Filter>src\core\lib\iomgr</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\polling_entity.c">
+      <Filter>src\core\lib\iomgr</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\pollset_set_windows.c">
+      <Filter>src\core\lib\iomgr</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\pollset_windows.c">
+      <Filter>src\core\lib\iomgr</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\resolve_address_posix.c">
+      <Filter>src\core\lib\iomgr</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\resolve_address_windows.c">
+      <Filter>src\core\lib\iomgr</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\sockaddr_utils.c">
+      <Filter>src\core\lib\iomgr</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\socket_utils_common_posix.c">
+      <Filter>src\core\lib\iomgr</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\socket_utils_linux.c">
+      <Filter>src\core\lib\iomgr</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\socket_utils_posix.c">
+      <Filter>src\core\lib\iomgr</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\socket_windows.c">
+      <Filter>src\core\lib\iomgr</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\tcp_client_posix.c">
+      <Filter>src\core\lib\iomgr</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\tcp_client_windows.c">
+      <Filter>src\core\lib\iomgr</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\tcp_posix.c">
+      <Filter>src\core\lib\iomgr</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\tcp_server_posix.c">
+      <Filter>src\core\lib\iomgr</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\tcp_server_windows.c">
+      <Filter>src\core\lib\iomgr</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\tcp_windows.c">
+      <Filter>src\core\lib\iomgr</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\time_averaged_stats.c">
+      <Filter>src\core\lib\iomgr</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\timer.c">
+      <Filter>src\core\lib\iomgr</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\timer_heap.c">
+      <Filter>src\core\lib\iomgr</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\udp_server.c">
+      <Filter>src\core\lib\iomgr</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\unix_sockets_posix.c">
+      <Filter>src\core\lib\iomgr</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\unix_sockets_posix_noop.c">
+      <Filter>src\core\lib\iomgr</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\wakeup_fd_eventfd.c">
+      <Filter>src\core\lib\iomgr</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\wakeup_fd_nospecial.c">
+      <Filter>src\core\lib\iomgr</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\wakeup_fd_pipe.c">
+      <Filter>src\core\lib\iomgr</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\wakeup_fd_posix.c">
+      <Filter>src\core\lib\iomgr</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\workqueue_posix.c">
+      <Filter>src\core\lib\iomgr</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\workqueue_windows.c">
+      <Filter>src\core\lib\iomgr</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\json\json.c">
+      <Filter>src\core\lib\json</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\json\json_reader.c">
+      <Filter>src\core\lib\json</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\json\json_string.c">
+      <Filter>src\core\lib\json</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\json\json_writer.c">
+      <Filter>src\core\lib\json</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\alarm.c">
+      <Filter>src\core\lib\surface</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\api_trace.c">
+      <Filter>src\core\lib\surface</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\byte_buffer.c">
+      <Filter>src\core\lib\surface</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\byte_buffer_reader.c">
+      <Filter>src\core\lib\surface</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\call.c">
+      <Filter>src\core\lib\surface</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\call_details.c">
+      <Filter>src\core\lib\surface</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\call_log_batch.c">
+      <Filter>src\core\lib\surface</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\channel.c">
+      <Filter>src\core\lib\surface</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\channel_init.c">
+      <Filter>src\core\lib\surface</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\channel_ping.c">
+      <Filter>src\core\lib\surface</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\channel_stack_type.c">
+      <Filter>src\core\lib\surface</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\completion_queue.c">
+      <Filter>src\core\lib\surface</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\event_string.c">
+      <Filter>src\core\lib\surface</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\lame_client.c">
+      <Filter>src\core\lib\surface</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\metadata_array.c">
+      <Filter>src\core\lib\surface</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\server.c">
+      <Filter>src\core\lib\surface</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\validate_metadata.c">
+      <Filter>src\core\lib\surface</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\version.c">
+      <Filter>src\core\lib\surface</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\transport\byte_stream.c">
+      <Filter>src\core\lib\transport</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\transport\connectivity_state.c">
+      <Filter>src\core\lib\transport</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\transport\metadata.c">
+      <Filter>src\core\lib\transport</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\transport\metadata_batch.c">
+      <Filter>src\core\lib\transport</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\transport\static_metadata.c">
+      <Filter>src\core\lib\transport</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\transport\timeout_encoding.c">
+      <Filter>src\core\lib\transport</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\transport\transport.c">
+      <Filter>src\core\lib\transport</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\transport\transport_op_string.c">
+      <Filter>src\core\lib\transport</Filter>
+    </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\cpp\codegen\codegen_init.cc">
       <Filter>src\cpp\codegen</Filter>
     </ClCompile>
@@ -246,6 +513,90 @@
     <ClInclude Include="$(SolutionDir)\..\include\grpc++\support\time.h">
       <Filter>include\grpc++\support</Filter>
     </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\byte_buffer.h">
+      <Filter>include\grpc</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\byte_buffer_reader.h">
+      <Filter>include\grpc</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\compression.h">
+      <Filter>include\grpc</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\grpc.h">
+      <Filter>include\grpc</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\grpc_posix.h">
+      <Filter>include\grpc</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\grpc_security_constants.h">
+      <Filter>include\grpc</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\status.h">
+      <Filter>include\grpc</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\byte_buffer.h">
+      <Filter>include\grpc\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\byte_buffer_reader.h">
+      <Filter>include\grpc\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\compression_types.h">
+      <Filter>include\grpc\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\connectivity_state.h">
+      <Filter>include\grpc\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\grpc_types.h">
+      <Filter>include\grpc\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\propagation_bits.h">
+      <Filter>include\grpc\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\status.h">
+      <Filter>include\grpc\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\alloc.h">
+      <Filter>include\grpc\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\atm.h">
+      <Filter>include\grpc\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\atm_gcc_atomic.h">
+      <Filter>include\grpc\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\atm_gcc_sync.h">
+      <Filter>include\grpc\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\atm_windows.h">
+      <Filter>include\grpc\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\log.h">
+      <Filter>include\grpc\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\port_platform.h">
+      <Filter>include\grpc\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\slice.h">
+      <Filter>include\grpc\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\slice_buffer.h">
+      <Filter>include\grpc\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\sync.h">
+      <Filter>include\grpc\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\sync_generic.h">
+      <Filter>include\grpc\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\sync_posix.h">
+      <Filter>include\grpc\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\sync_windows.h">
+      <Filter>include\grpc\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\time.h">
+      <Filter>include\grpc\impl\codegen</Filter>
+    </ClInclude>
     <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\async_stream.h">
       <Filter>include\grpc++\impl\codegen</Filter>
     </ClInclude>
@@ -336,69 +687,6 @@
     <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\time.h">
       <Filter>include\grpc++\impl\codegen</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\byte_buffer.h">
-      <Filter>include\grpc\impl\codegen</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\byte_buffer_reader.h">
-      <Filter>include\grpc\impl\codegen</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\compression_types.h">
-      <Filter>include\grpc\impl\codegen</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\connectivity_state.h">
-      <Filter>include\grpc\impl\codegen</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\grpc_types.h">
-      <Filter>include\grpc\impl\codegen</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\propagation_bits.h">
-      <Filter>include\grpc\impl\codegen</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\status.h">
-      <Filter>include\grpc\impl\codegen</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\alloc.h">
-      <Filter>include\grpc\impl\codegen</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\atm.h">
-      <Filter>include\grpc\impl\codegen</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\atm_gcc_atomic.h">
-      <Filter>include\grpc\impl\codegen</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\atm_gcc_sync.h">
-      <Filter>include\grpc\impl\codegen</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\atm_windows.h">
-      <Filter>include\grpc\impl\codegen</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\log.h">
-      <Filter>include\grpc\impl\codegen</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\port_platform.h">
-      <Filter>include\grpc\impl\codegen</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\slice.h">
-      <Filter>include\grpc\impl\codegen</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\slice_buffer.h">
-      <Filter>include\grpc\impl\codegen</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\sync.h">
-      <Filter>include\grpc\impl\codegen</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\sync_generic.h">
-      <Filter>include\grpc\impl\codegen</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\sync_posix.h">
-      <Filter>include\grpc\impl\codegen</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\sync_windows.h">
-      <Filter>include\grpc\impl\codegen</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\time.h">
-      <Filter>include\grpc\impl\codegen</Filter>
-    </ClInclude>
   </ItemGroup>
   <ItemGroup>
     <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\core_codegen.h">
@@ -425,6 +713,246 @@
     <ClInclude Include="$(SolutionDir)\..\src\cpp\server\thread_pool_interface.h">
       <Filter>src\cpp\server</Filter>
     </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\channel_args.h">
+      <Filter>src\core\lib\channel</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\channel_stack.h">
+      <Filter>src\core\lib\channel</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\channel_stack_builder.h">
+      <Filter>src\core\lib\channel</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\compress_filter.h">
+      <Filter>src\core\lib\channel</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\connected_channel.h">
+      <Filter>src\core\lib\channel</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\context.h">
+      <Filter>src\core\lib\channel</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\handshaker.h">
+      <Filter>src\core\lib\channel</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\http_client_filter.h">
+      <Filter>src\core\lib\channel</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\http_server_filter.h">
+      <Filter>src\core\lib\channel</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\compression\algorithm_metadata.h">
+      <Filter>src\core\lib\compression</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\compression\message_compress.h">
+      <Filter>src\core\lib\compression</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\debug\trace.h">
+      <Filter>src\core\lib\debug</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\http\format_request.h">
+      <Filter>src\core\lib\http</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\http\httpcli.h">
+      <Filter>src\core\lib\http</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\http\parser.h">
+      <Filter>src\core\lib\http</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\closure.h">
+      <Filter>src\core\lib\iomgr</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\endpoint.h">
+      <Filter>src\core\lib\iomgr</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\endpoint_pair.h">
+      <Filter>src\core\lib\iomgr</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\error.h">
+      <Filter>src\core\lib\iomgr</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\ev_epoll_linux.h">
+      <Filter>src\core\lib\iomgr</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\ev_poll_and_epoll_posix.h">
+      <Filter>src\core\lib\iomgr</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\ev_poll_posix.h">
+      <Filter>src\core\lib\iomgr</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\ev_posix.h">
+      <Filter>src\core\lib\iomgr</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\exec_ctx.h">
+      <Filter>src\core\lib\iomgr</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\executor.h">
+      <Filter>src\core\lib\iomgr</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\iocp_windows.h">
+      <Filter>src\core\lib\iomgr</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\iomgr.h">
+      <Filter>src\core\lib\iomgr</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\iomgr_internal.h">
+      <Filter>src\core\lib\iomgr</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\iomgr_posix.h">
+      <Filter>src\core\lib\iomgr</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\load_file.h">
+      <Filter>src\core\lib\iomgr</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\network_status_tracker.h">
+      <Filter>src\core\lib\iomgr</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\polling_entity.h">
+      <Filter>src\core\lib\iomgr</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\pollset.h">
+      <Filter>src\core\lib\iomgr</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\pollset_set.h">
+      <Filter>src\core\lib\iomgr</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\pollset_set_windows.h">
+      <Filter>src\core\lib\iomgr</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\pollset_windows.h">
+      <Filter>src\core\lib\iomgr</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\resolve_address.h">
+      <Filter>src\core\lib\iomgr</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\sockaddr.h">
+      <Filter>src\core\lib\iomgr</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\sockaddr_posix.h">
+      <Filter>src\core\lib\iomgr</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\sockaddr_utils.h">
+      <Filter>src\core\lib\iomgr</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\sockaddr_windows.h">
+      <Filter>src\core\lib\iomgr</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\socket_utils_posix.h">
+      <Filter>src\core\lib\iomgr</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\socket_windows.h">
+      <Filter>src\core\lib\iomgr</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\tcp_client.h">
+      <Filter>src\core\lib\iomgr</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\tcp_posix.h">
+      <Filter>src\core\lib\iomgr</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\tcp_server.h">
+      <Filter>src\core\lib\iomgr</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\tcp_windows.h">
+      <Filter>src\core\lib\iomgr</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\time_averaged_stats.h">
+      <Filter>src\core\lib\iomgr</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\timer.h">
+      <Filter>src\core\lib\iomgr</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\timer_heap.h">
+      <Filter>src\core\lib\iomgr</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\udp_server.h">
+      <Filter>src\core\lib\iomgr</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\unix_sockets_posix.h">
+      <Filter>src\core\lib\iomgr</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\wakeup_fd_pipe.h">
+      <Filter>src\core\lib\iomgr</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\wakeup_fd_posix.h">
+      <Filter>src\core\lib\iomgr</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\workqueue.h">
+      <Filter>src\core\lib\iomgr</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\workqueue_posix.h">
+      <Filter>src\core\lib\iomgr</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\workqueue_windows.h">
+      <Filter>src\core\lib\iomgr</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\json\json.h">
+      <Filter>src\core\lib\json</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\json\json_common.h">
+      <Filter>src\core\lib\json</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\json\json_reader.h">
+      <Filter>src\core\lib\json</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\json\json_writer.h">
+      <Filter>src\core\lib\json</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\surface\api_trace.h">
+      <Filter>src\core\lib\surface</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\surface\call.h">
+      <Filter>src\core\lib\surface</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\surface\call_test_only.h">
+      <Filter>src\core\lib\surface</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\surface\channel.h">
+      <Filter>src\core\lib\surface</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\surface\channel_init.h">
+      <Filter>src\core\lib\surface</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\surface\channel_stack_type.h">
+      <Filter>src\core\lib\surface</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\surface\completion_queue.h">
+      <Filter>src\core\lib\surface</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\surface\event_string.h">
+      <Filter>src\core\lib\surface</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\surface\init.h">
+      <Filter>src\core\lib\surface</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\surface\lame_client.h">
+      <Filter>src\core\lib\surface</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\surface\server.h">
+      <Filter>src\core\lib\surface</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\byte_stream.h">
+      <Filter>src\core\lib\transport</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\connectivity_state.h">
+      <Filter>src\core\lib\transport</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\metadata.h">
+      <Filter>src\core\lib\transport</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\metadata_batch.h">
+      <Filter>src\core\lib\transport</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\static_metadata.h">
+      <Filter>src\core\lib\transport</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\timeout_encoding.h">
+      <Filter>src\core\lib\transport</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\transport.h">
+      <Filter>src\core\lib\transport</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\transport_impl.h">
+      <Filter>src\core\lib\transport</Filter>
+    </ClInclude>
   </ItemGroup>
 
   <ItemGroup>
@@ -464,6 +992,36 @@
     <Filter Include="src">
       <UniqueIdentifier>{328ff211-2886-406e-56f9-18ba1686f363}</UniqueIdentifier>
     </Filter>
+    <Filter Include="src\core">
+      <UniqueIdentifier>{d02f1155-7e7e-3736-3c69-dc9146dc523d}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="src\core\lib">
+      <UniqueIdentifier>{80567a8f-622f-a3ce-c12d-aebb63984b07}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="src\core\lib\channel">
+      <UniqueIdentifier>{e769265c-8abd-cd64-2cc2-a52da484fe7b}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="src\core\lib\compression">
+      <UniqueIdentifier>{701b2d46-11c6-3640-b189-45287f00bee3}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="src\core\lib\debug">
+      <UniqueIdentifier>{ada68fd5-8e51-98cb-71a7-baf7989d8ffa}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="src\core\lib\http">
+      <UniqueIdentifier>{e770844e-61d4-555e-59be-81288e21a35f}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="src\core\lib\iomgr">
+      <UniqueIdentifier>{04dfa1c8-7ffe-4f06-4a7c-37441dc75764}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="src\core\lib\json">
+      <UniqueIdentifier>{a5d5bddf-6f19-b655-a03a-f30ff5c253a5}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="src\core\lib\surface">
+      <UniqueIdentifier>{fb2276d7-5a11-f1d9-82c3-e7c7f1155523}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="src\core\lib\transport">
+      <UniqueIdentifier>{4bd7971a-68f7-0d5a-f502-6dea3099caaa}</UniqueIdentifier>
+    </Filter>
     <Filter Include="src\cpp">
       <UniqueIdentifier>{2420a905-e4f1-a5aa-a364-6a112878a39e}</UniqueIdentifier>
     </Filter>
diff --git a/vsprojects/vcxproj/grpc++_unsecure/grpc++_unsecure.vcxproj b/vsprojects/vcxproj/grpc++_unsecure/grpc++_unsecure.vcxproj
index e71180f..a7bb3ef 100644
--- a/vsprojects/vcxproj/grpc++_unsecure/grpc++_unsecure.vcxproj
+++ b/vsprojects/vcxproj/grpc++_unsecure/grpc++_unsecure.vcxproj
@@ -305,6 +305,34 @@
     <ClInclude Include="$(SolutionDir)\..\include\grpc++\support\stub_options.h" />
     <ClInclude Include="$(SolutionDir)\..\include\grpc++\support\sync_stream.h" />
     <ClInclude Include="$(SolutionDir)\..\include\grpc++\support\time.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\byte_buffer.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\byte_buffer_reader.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\compression.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\grpc.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\grpc_posix.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\grpc_security_constants.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\status.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\byte_buffer.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\byte_buffer_reader.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\compression_types.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\connectivity_state.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\grpc_types.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\propagation_bits.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\status.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\alloc.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\atm.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\atm_gcc_atomic.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\atm_gcc_sync.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\atm_windows.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\log.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\port_platform.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\slice.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\slice_buffer.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\sync.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\sync_generic.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\sync_posix.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\sync_windows.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\time.h" />
     <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\async_stream.h" />
     <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\async_unary_call.h" />
     <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\call.h" />
@@ -335,33 +363,92 @@
     <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\sync_no_cxx11.h" />
     <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\sync_stream.h" />
     <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\time.h" />
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\byte_buffer.h" />
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\byte_buffer_reader.h" />
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\compression_types.h" />
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\connectivity_state.h" />
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\grpc_types.h" />
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\propagation_bits.h" />
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\status.h" />
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\alloc.h" />
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\atm.h" />
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\atm_gcc_atomic.h" />
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\atm_gcc_sync.h" />
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\atm_windows.h" />
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\log.h" />
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\port_platform.h" />
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\slice.h" />
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\slice_buffer.h" />
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\sync.h" />
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\sync_generic.h" />
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\sync_posix.h" />
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\sync_windows.h" />
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\time.h" />
   </ItemGroup>
   <ItemGroup>
     <ClInclude Include="$(SolutionDir)\..\src\cpp\client\create_channel_internal.h" />
     <ClInclude Include="$(SolutionDir)\..\src\cpp\common\channel_filter.h" />
     <ClInclude Include="$(SolutionDir)\..\src\cpp\server\dynamic_thread_pool.h" />
     <ClInclude Include="$(SolutionDir)\..\src\cpp\server\thread_pool_interface.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\channel_args.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\channel_stack.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\channel_stack_builder.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\compress_filter.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\connected_channel.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\context.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\handshaker.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\http_client_filter.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\http_server_filter.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\compression\algorithm_metadata.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\compression\message_compress.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\debug\trace.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\http\format_request.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\http\httpcli.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\http\parser.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\closure.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\endpoint.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\endpoint_pair.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\error.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\ev_epoll_linux.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\ev_poll_and_epoll_posix.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\ev_poll_posix.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\ev_posix.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\exec_ctx.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\executor.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\iocp_windows.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\iomgr.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\iomgr_internal.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\iomgr_posix.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\load_file.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\network_status_tracker.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\polling_entity.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\pollset.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\pollset_set.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\pollset_set_windows.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\pollset_windows.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\resolve_address.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\sockaddr.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\sockaddr_posix.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\sockaddr_utils.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\sockaddr_windows.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\socket_utils_posix.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\socket_windows.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\tcp_client.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\tcp_posix.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\tcp_server.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\tcp_windows.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\time_averaged_stats.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\timer.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\timer_heap.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\udp_server.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\unix_sockets_posix.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\wakeup_fd_pipe.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\wakeup_fd_posix.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\workqueue.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\workqueue_posix.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\workqueue_windows.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\json\json.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\json\json_common.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\json\json_reader.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\json\json_writer.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\surface\api_trace.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\surface\call.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\surface\call_test_only.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\surface\channel.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\surface\channel_init.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\surface\channel_stack_type.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\surface\completion_queue.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\surface\event_string.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\surface\init.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\surface\lame_client.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\surface\server.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\byte_stream.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\connectivity_state.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\metadata.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\metadata_batch.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\static_metadata.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\timeout_encoding.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\transport.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\transport_impl.h" />
   </ItemGroup>
   <ItemGroup>
     <ClCompile Include="$(SolutionDir)\..\src\cpp\common\insecure_create_auth_context.cc">
@@ -420,6 +507,184 @@
     </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\cpp\util\time.cc">
     </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\channel_args.c">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\channel_stack.c">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\channel_stack_builder.c">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\compress_filter.c">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\connected_channel.c">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\handshaker.c">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\http_client_filter.c">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\http_server_filter.c">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\compression\compression.c">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\compression\message_compress.c">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\debug\trace.c">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\http\format_request.c">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\http\httpcli.c">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\http\parser.c">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\closure.c">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\endpoint.c">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\endpoint_pair_posix.c">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\endpoint_pair_windows.c">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\error.c">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\ev_epoll_linux.c">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\ev_poll_and_epoll_posix.c">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\ev_poll_posix.c">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\ev_posix.c">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\exec_ctx.c">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\executor.c">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\iocp_windows.c">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\iomgr.c">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\iomgr_posix.c">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\iomgr_windows.c">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\load_file.c">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\network_status_tracker.c">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\polling_entity.c">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\pollset_set_windows.c">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\pollset_windows.c">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\resolve_address_posix.c">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\resolve_address_windows.c">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\sockaddr_utils.c">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\socket_utils_common_posix.c">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\socket_utils_linux.c">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\socket_utils_posix.c">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\socket_windows.c">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\tcp_client_posix.c">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\tcp_client_windows.c">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\tcp_posix.c">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\tcp_server_posix.c">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\tcp_server_windows.c">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\tcp_windows.c">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\time_averaged_stats.c">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\timer.c">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\timer_heap.c">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\udp_server.c">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\unix_sockets_posix.c">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\unix_sockets_posix_noop.c">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\wakeup_fd_eventfd.c">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\wakeup_fd_nospecial.c">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\wakeup_fd_pipe.c">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\wakeup_fd_posix.c">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\workqueue_posix.c">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\workqueue_windows.c">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\json\json.c">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\json\json_reader.c">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\json\json_string.c">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\json\json_writer.c">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\alarm.c">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\api_trace.c">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\byte_buffer.c">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\byte_buffer_reader.c">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\call.c">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\call_details.c">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\call_log_batch.c">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\channel.c">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\channel_init.c">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\channel_ping.c">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\channel_stack_type.c">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\completion_queue.c">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\event_string.c">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\lame_client.c">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\metadata_array.c">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\server.c">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\validate_metadata.c">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\version.c">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\transport\byte_stream.c">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\transport\connectivity_state.c">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\transport\metadata.c">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\transport\metadata_batch.c">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\transport\static_metadata.c">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\transport\timeout_encoding.c">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\transport\transport.c">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\transport\transport_op_string.c">
+    </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\cpp\codegen\codegen_init.cc">
     </ClCompile>
   </ItemGroup>
@@ -430,9 +695,6 @@
     <ProjectReference Include="$(SolutionDir)\..\vsprojects\vcxproj\.\grpc_unsecure\grpc_unsecure.vcxproj">
       <Project>{46CEDFFF-9692-456A-AA24-38B5D6BCF4C5}</Project>
     </ProjectReference>
-    <ProjectReference Include="$(SolutionDir)\..\vsprojects\vcxproj\.\grpc\grpc.vcxproj">
-      <Project>{29D16885-7228-4C31-81ED-5F9187C7F2A9}</Project>
-    </ProjectReference>
   </ItemGroup>
   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
   <ImportGroup Label="ExtensionTargets">
diff --git a/vsprojects/vcxproj/grpc++_unsecure/grpc++_unsecure.vcxproj.filters b/vsprojects/vcxproj/grpc++_unsecure/grpc++_unsecure.vcxproj.filters
index a9aa147..4ad0ae3 100644
--- a/vsprojects/vcxproj/grpc++_unsecure/grpc++_unsecure.vcxproj.filters
+++ b/vsprojects/vcxproj/grpc++_unsecure/grpc++_unsecure.vcxproj.filters
@@ -85,6 +85,273 @@
     <ClCompile Include="$(SolutionDir)\..\src\cpp\util\time.cc">
       <Filter>src\cpp\util</Filter>
     </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\channel_args.c">
+      <Filter>src\core\lib\channel</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\channel_stack.c">
+      <Filter>src\core\lib\channel</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\channel_stack_builder.c">
+      <Filter>src\core\lib\channel</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\compress_filter.c">
+      <Filter>src\core\lib\channel</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\connected_channel.c">
+      <Filter>src\core\lib\channel</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\handshaker.c">
+      <Filter>src\core\lib\channel</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\http_client_filter.c">
+      <Filter>src\core\lib\channel</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\channel\http_server_filter.c">
+      <Filter>src\core\lib\channel</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\compression\compression.c">
+      <Filter>src\core\lib\compression</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\compression\message_compress.c">
+      <Filter>src\core\lib\compression</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\debug\trace.c">
+      <Filter>src\core\lib\debug</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\http\format_request.c">
+      <Filter>src\core\lib\http</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\http\httpcli.c">
+      <Filter>src\core\lib\http</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\http\parser.c">
+      <Filter>src\core\lib\http</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\closure.c">
+      <Filter>src\core\lib\iomgr</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\endpoint.c">
+      <Filter>src\core\lib\iomgr</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\endpoint_pair_posix.c">
+      <Filter>src\core\lib\iomgr</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\endpoint_pair_windows.c">
+      <Filter>src\core\lib\iomgr</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\error.c">
+      <Filter>src\core\lib\iomgr</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\ev_epoll_linux.c">
+      <Filter>src\core\lib\iomgr</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\ev_poll_and_epoll_posix.c">
+      <Filter>src\core\lib\iomgr</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\ev_poll_posix.c">
+      <Filter>src\core\lib\iomgr</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\ev_posix.c">
+      <Filter>src\core\lib\iomgr</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\exec_ctx.c">
+      <Filter>src\core\lib\iomgr</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\executor.c">
+      <Filter>src\core\lib\iomgr</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\iocp_windows.c">
+      <Filter>src\core\lib\iomgr</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\iomgr.c">
+      <Filter>src\core\lib\iomgr</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\iomgr_posix.c">
+      <Filter>src\core\lib\iomgr</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\iomgr_windows.c">
+      <Filter>src\core\lib\iomgr</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\load_file.c">
+      <Filter>src\core\lib\iomgr</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\network_status_tracker.c">
+      <Filter>src\core\lib\iomgr</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\polling_entity.c">
+      <Filter>src\core\lib\iomgr</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\pollset_set_windows.c">
+      <Filter>src\core\lib\iomgr</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\pollset_windows.c">
+      <Filter>src\core\lib\iomgr</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\resolve_address_posix.c">
+      <Filter>src\core\lib\iomgr</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\resolve_address_windows.c">
+      <Filter>src\core\lib\iomgr</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\sockaddr_utils.c">
+      <Filter>src\core\lib\iomgr</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\socket_utils_common_posix.c">
+      <Filter>src\core\lib\iomgr</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\socket_utils_linux.c">
+      <Filter>src\core\lib\iomgr</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\socket_utils_posix.c">
+      <Filter>src\core\lib\iomgr</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\socket_windows.c">
+      <Filter>src\core\lib\iomgr</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\tcp_client_posix.c">
+      <Filter>src\core\lib\iomgr</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\tcp_client_windows.c">
+      <Filter>src\core\lib\iomgr</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\tcp_posix.c">
+      <Filter>src\core\lib\iomgr</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\tcp_server_posix.c">
+      <Filter>src\core\lib\iomgr</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\tcp_server_windows.c">
+      <Filter>src\core\lib\iomgr</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\tcp_windows.c">
+      <Filter>src\core\lib\iomgr</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\time_averaged_stats.c">
+      <Filter>src\core\lib\iomgr</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\timer.c">
+      <Filter>src\core\lib\iomgr</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\timer_heap.c">
+      <Filter>src\core\lib\iomgr</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\udp_server.c">
+      <Filter>src\core\lib\iomgr</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\unix_sockets_posix.c">
+      <Filter>src\core\lib\iomgr</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\unix_sockets_posix_noop.c">
+      <Filter>src\core\lib\iomgr</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\wakeup_fd_eventfd.c">
+      <Filter>src\core\lib\iomgr</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\wakeup_fd_nospecial.c">
+      <Filter>src\core\lib\iomgr</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\wakeup_fd_pipe.c">
+      <Filter>src\core\lib\iomgr</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\wakeup_fd_posix.c">
+      <Filter>src\core\lib\iomgr</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\workqueue_posix.c">
+      <Filter>src\core\lib\iomgr</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\workqueue_windows.c">
+      <Filter>src\core\lib\iomgr</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\json\json.c">
+      <Filter>src\core\lib\json</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\json\json_reader.c">
+      <Filter>src\core\lib\json</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\json\json_string.c">
+      <Filter>src\core\lib\json</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\json\json_writer.c">
+      <Filter>src\core\lib\json</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\alarm.c">
+      <Filter>src\core\lib\surface</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\api_trace.c">
+      <Filter>src\core\lib\surface</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\byte_buffer.c">
+      <Filter>src\core\lib\surface</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\byte_buffer_reader.c">
+      <Filter>src\core\lib\surface</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\call.c">
+      <Filter>src\core\lib\surface</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\call_details.c">
+      <Filter>src\core\lib\surface</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\call_log_batch.c">
+      <Filter>src\core\lib\surface</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\channel.c">
+      <Filter>src\core\lib\surface</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\channel_init.c">
+      <Filter>src\core\lib\surface</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\channel_ping.c">
+      <Filter>src\core\lib\surface</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\channel_stack_type.c">
+      <Filter>src\core\lib\surface</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\completion_queue.c">
+      <Filter>src\core\lib\surface</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\event_string.c">
+      <Filter>src\core\lib\surface</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\lame_client.c">
+      <Filter>src\core\lib\surface</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\metadata_array.c">
+      <Filter>src\core\lib\surface</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\server.c">
+      <Filter>src\core\lib\surface</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\validate_metadata.c">
+      <Filter>src\core\lib\surface</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\surface\version.c">
+      <Filter>src\core\lib\surface</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\transport\byte_stream.c">
+      <Filter>src\core\lib\transport</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\transport\connectivity_state.c">
+      <Filter>src\core\lib\transport</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\transport\metadata.c">
+      <Filter>src\core\lib\transport</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\transport\metadata_batch.c">
+      <Filter>src\core\lib\transport</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\transport\static_metadata.c">
+      <Filter>src\core\lib\transport</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\transport\timeout_encoding.c">
+      <Filter>src\core\lib\transport</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\transport\transport.c">
+      <Filter>src\core\lib\transport</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\transport\transport_op_string.c">
+      <Filter>src\core\lib\transport</Filter>
+    </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\cpp\codegen\codegen_init.cc">
       <Filter>src\cpp\codegen</Filter>
     </ClCompile>
@@ -231,6 +498,90 @@
     <ClInclude Include="$(SolutionDir)\..\include\grpc++\support\time.h">
       <Filter>include\grpc++\support</Filter>
     </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\byte_buffer.h">
+      <Filter>include\grpc</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\byte_buffer_reader.h">
+      <Filter>include\grpc</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\compression.h">
+      <Filter>include\grpc</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\grpc.h">
+      <Filter>include\grpc</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\grpc_posix.h">
+      <Filter>include\grpc</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\grpc_security_constants.h">
+      <Filter>include\grpc</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\status.h">
+      <Filter>include\grpc</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\byte_buffer.h">
+      <Filter>include\grpc\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\byte_buffer_reader.h">
+      <Filter>include\grpc\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\compression_types.h">
+      <Filter>include\grpc\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\connectivity_state.h">
+      <Filter>include\grpc\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\grpc_types.h">
+      <Filter>include\grpc\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\propagation_bits.h">
+      <Filter>include\grpc\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\status.h">
+      <Filter>include\grpc\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\alloc.h">
+      <Filter>include\grpc\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\atm.h">
+      <Filter>include\grpc\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\atm_gcc_atomic.h">
+      <Filter>include\grpc\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\atm_gcc_sync.h">
+      <Filter>include\grpc\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\atm_windows.h">
+      <Filter>include\grpc\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\log.h">
+      <Filter>include\grpc\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\port_platform.h">
+      <Filter>include\grpc\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\slice.h">
+      <Filter>include\grpc\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\slice_buffer.h">
+      <Filter>include\grpc\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\sync.h">
+      <Filter>include\grpc\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\sync_generic.h">
+      <Filter>include\grpc\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\sync_posix.h">
+      <Filter>include\grpc\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\sync_windows.h">
+      <Filter>include\grpc\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\time.h">
+      <Filter>include\grpc\impl\codegen</Filter>
+    </ClInclude>
     <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\async_stream.h">
       <Filter>include\grpc++\impl\codegen</Filter>
     </ClInclude>
@@ -321,69 +672,6 @@
     <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\time.h">
       <Filter>include\grpc++\impl\codegen</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\byte_buffer.h">
-      <Filter>include\grpc\impl\codegen</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\byte_buffer_reader.h">
-      <Filter>include\grpc\impl\codegen</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\compression_types.h">
-      <Filter>include\grpc\impl\codegen</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\connectivity_state.h">
-      <Filter>include\grpc\impl\codegen</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\grpc_types.h">
-      <Filter>include\grpc\impl\codegen</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\propagation_bits.h">
-      <Filter>include\grpc\impl\codegen</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\status.h">
-      <Filter>include\grpc\impl\codegen</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\alloc.h">
-      <Filter>include\grpc\impl\codegen</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\atm.h">
-      <Filter>include\grpc\impl\codegen</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\atm_gcc_atomic.h">
-      <Filter>include\grpc\impl\codegen</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\atm_gcc_sync.h">
-      <Filter>include\grpc\impl\codegen</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\atm_windows.h">
-      <Filter>include\grpc\impl\codegen</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\log.h">
-      <Filter>include\grpc\impl\codegen</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\port_platform.h">
-      <Filter>include\grpc\impl\codegen</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\slice.h">
-      <Filter>include\grpc\impl\codegen</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\slice_buffer.h">
-      <Filter>include\grpc\impl\codegen</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\sync.h">
-      <Filter>include\grpc\impl\codegen</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\sync_generic.h">
-      <Filter>include\grpc\impl\codegen</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\sync_posix.h">
-      <Filter>include\grpc\impl\codegen</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\sync_windows.h">
-      <Filter>include\grpc\impl\codegen</Filter>
-    </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\time.h">
-      <Filter>include\grpc\impl\codegen</Filter>
-    </ClInclude>
   </ItemGroup>
   <ItemGroup>
     <ClInclude Include="$(SolutionDir)\..\src\cpp\client\create_channel_internal.h">
@@ -398,6 +686,246 @@
     <ClInclude Include="$(SolutionDir)\..\src\cpp\server\thread_pool_interface.h">
       <Filter>src\cpp\server</Filter>
     </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\channel_args.h">
+      <Filter>src\core\lib\channel</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\channel_stack.h">
+      <Filter>src\core\lib\channel</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\channel_stack_builder.h">
+      <Filter>src\core\lib\channel</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\compress_filter.h">
+      <Filter>src\core\lib\channel</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\connected_channel.h">
+      <Filter>src\core\lib\channel</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\context.h">
+      <Filter>src\core\lib\channel</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\handshaker.h">
+      <Filter>src\core\lib\channel</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\http_client_filter.h">
+      <Filter>src\core\lib\channel</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\channel\http_server_filter.h">
+      <Filter>src\core\lib\channel</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\compression\algorithm_metadata.h">
+      <Filter>src\core\lib\compression</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\compression\message_compress.h">
+      <Filter>src\core\lib\compression</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\debug\trace.h">
+      <Filter>src\core\lib\debug</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\http\format_request.h">
+      <Filter>src\core\lib\http</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\http\httpcli.h">
+      <Filter>src\core\lib\http</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\http\parser.h">
+      <Filter>src\core\lib\http</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\closure.h">
+      <Filter>src\core\lib\iomgr</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\endpoint.h">
+      <Filter>src\core\lib\iomgr</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\endpoint_pair.h">
+      <Filter>src\core\lib\iomgr</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\error.h">
+      <Filter>src\core\lib\iomgr</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\ev_epoll_linux.h">
+      <Filter>src\core\lib\iomgr</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\ev_poll_and_epoll_posix.h">
+      <Filter>src\core\lib\iomgr</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\ev_poll_posix.h">
+      <Filter>src\core\lib\iomgr</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\ev_posix.h">
+      <Filter>src\core\lib\iomgr</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\exec_ctx.h">
+      <Filter>src\core\lib\iomgr</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\executor.h">
+      <Filter>src\core\lib\iomgr</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\iocp_windows.h">
+      <Filter>src\core\lib\iomgr</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\iomgr.h">
+      <Filter>src\core\lib\iomgr</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\iomgr_internal.h">
+      <Filter>src\core\lib\iomgr</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\iomgr_posix.h">
+      <Filter>src\core\lib\iomgr</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\load_file.h">
+      <Filter>src\core\lib\iomgr</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\network_status_tracker.h">
+      <Filter>src\core\lib\iomgr</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\polling_entity.h">
+      <Filter>src\core\lib\iomgr</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\pollset.h">
+      <Filter>src\core\lib\iomgr</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\pollset_set.h">
+      <Filter>src\core\lib\iomgr</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\pollset_set_windows.h">
+      <Filter>src\core\lib\iomgr</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\pollset_windows.h">
+      <Filter>src\core\lib\iomgr</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\resolve_address.h">
+      <Filter>src\core\lib\iomgr</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\sockaddr.h">
+      <Filter>src\core\lib\iomgr</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\sockaddr_posix.h">
+      <Filter>src\core\lib\iomgr</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\sockaddr_utils.h">
+      <Filter>src\core\lib\iomgr</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\sockaddr_windows.h">
+      <Filter>src\core\lib\iomgr</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\socket_utils_posix.h">
+      <Filter>src\core\lib\iomgr</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\socket_windows.h">
+      <Filter>src\core\lib\iomgr</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\tcp_client.h">
+      <Filter>src\core\lib\iomgr</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\tcp_posix.h">
+      <Filter>src\core\lib\iomgr</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\tcp_server.h">
+      <Filter>src\core\lib\iomgr</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\tcp_windows.h">
+      <Filter>src\core\lib\iomgr</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\time_averaged_stats.h">
+      <Filter>src\core\lib\iomgr</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\timer.h">
+      <Filter>src\core\lib\iomgr</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\timer_heap.h">
+      <Filter>src\core\lib\iomgr</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\udp_server.h">
+      <Filter>src\core\lib\iomgr</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\unix_sockets_posix.h">
+      <Filter>src\core\lib\iomgr</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\wakeup_fd_pipe.h">
+      <Filter>src\core\lib\iomgr</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\wakeup_fd_posix.h">
+      <Filter>src\core\lib\iomgr</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\workqueue.h">
+      <Filter>src\core\lib\iomgr</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\workqueue_posix.h">
+      <Filter>src\core\lib\iomgr</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\workqueue_windows.h">
+      <Filter>src\core\lib\iomgr</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\json\json.h">
+      <Filter>src\core\lib\json</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\json\json_common.h">
+      <Filter>src\core\lib\json</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\json\json_reader.h">
+      <Filter>src\core\lib\json</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\json\json_writer.h">
+      <Filter>src\core\lib\json</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\surface\api_trace.h">
+      <Filter>src\core\lib\surface</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\surface\call.h">
+      <Filter>src\core\lib\surface</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\surface\call_test_only.h">
+      <Filter>src\core\lib\surface</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\surface\channel.h">
+      <Filter>src\core\lib\surface</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\surface\channel_init.h">
+      <Filter>src\core\lib\surface</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\surface\channel_stack_type.h">
+      <Filter>src\core\lib\surface</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\surface\completion_queue.h">
+      <Filter>src\core\lib\surface</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\surface\event_string.h">
+      <Filter>src\core\lib\surface</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\surface\init.h">
+      <Filter>src\core\lib\surface</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\surface\lame_client.h">
+      <Filter>src\core\lib\surface</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\surface\server.h">
+      <Filter>src\core\lib\surface</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\byte_stream.h">
+      <Filter>src\core\lib\transport</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\connectivity_state.h">
+      <Filter>src\core\lib\transport</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\metadata.h">
+      <Filter>src\core\lib\transport</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\metadata_batch.h">
+      <Filter>src\core\lib\transport</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\static_metadata.h">
+      <Filter>src\core\lib\transport</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\timeout_encoding.h">
+      <Filter>src\core\lib\transport</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\transport.h">
+      <Filter>src\core\lib\transport</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\transport\transport_impl.h">
+      <Filter>src\core\lib\transport</Filter>
+    </ClInclude>
   </ItemGroup>
 
   <ItemGroup>
@@ -437,6 +965,36 @@
     <Filter Include="src">
       <UniqueIdentifier>{cce6a85d-1111-3834-6825-31e170d93cff}</UniqueIdentifier>
     </Filter>
+    <Filter Include="src\core">
+      <UniqueIdentifier>{595f2ea0-aafb-87e5-c938-db3ff0b0c69a}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="src\core\lib">
+      <UniqueIdentifier>{cf8fd5d8-ff54-331d-2d20-36d6cae0e14b}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="src\core\lib\channel">
+      <UniqueIdentifier>{7e0225af-000b-4873-1c16-caffffbfd084}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="src\core\lib\compression">
+      <UniqueIdentifier>{0bbdbf56-83ad-bb4b-c4e2-a6d38c342179}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="src\core\lib\debug">
+      <UniqueIdentifier>{3875f7d7-ff11-c91d-0f98-810260cb554b}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="src\core\lib\http">
+      <UniqueIdentifier>{4bd405b9-af65-f0a6-d67a-433f75900668}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="src\core\lib\iomgr">
+      <UniqueIdentifier>{f4b146e4-8fba-83a6-1cc1-1262ebb785e8}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="src\core\lib\json">
+      <UniqueIdentifier>{b83c8e70-e491-f6f9-a08c-85f632bb61d2}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="src\core\lib\surface">
+      <UniqueIdentifier>{1d59dcef-3358-d0ab-fa42-64da74065785}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="src\core\lib\transport">
+      <UniqueIdentifier>{ba865739-5dd9-6731-6772-48c25d45134f}</UniqueIdentifier>
+    </Filter>
     <Filter Include="src\cpp">
       <UniqueIdentifier>{1e5fd68c-bd87-e803-42b0-75a7fa19b91d}</UniqueIdentifier>
     </Filter>
diff --git a/vsprojects/vcxproj/grpc/grpc.vcxproj b/vsprojects/vcxproj/grpc/grpc.vcxproj
index ed010c5..98873ca 100644
--- a/vsprojects/vcxproj/grpc/grpc.vcxproj
+++ b/vsprojects/vcxproj/grpc/grpc.vcxproj
@@ -272,6 +272,7 @@
     <ClInclude Include="$(SolutionDir)\..\include\grpc\compression.h" />
     <ClInclude Include="$(SolutionDir)\..\include\grpc\grpc.h" />
     <ClInclude Include="$(SolutionDir)\..\include\grpc\grpc_posix.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\grpc_security_constants.h" />
     <ClInclude Include="$(SolutionDir)\..\include\grpc\status.h" />
     <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\byte_buffer.h" />
     <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\byte_buffer_reader.h" />
@@ -295,7 +296,6 @@
     <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\sync_windows.h" />
     <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\time.h" />
     <ClInclude Include="$(SolutionDir)\..\include\grpc\grpc_security.h" />
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\grpc_security_constants.h" />
     <ClInclude Include="$(SolutionDir)\..\include\grpc\census.h" />
   </ItemGroup>
   <ItemGroup>
@@ -315,6 +315,7 @@
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\http\httpcli.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\http\parser.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\closure.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\combiner.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\endpoint.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\endpoint_pair.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\error.h" />
@@ -426,7 +427,6 @@
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\tsi\transport_security_interface.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\ext\client_config\client_channel.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\ext\client_config\client_channel_factory.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\client_config\client_config.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\ext\client_config\connector.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\ext\client_config\initial_connect_string.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\ext\client_config\lb_policy.h" />
@@ -436,8 +436,8 @@
     <ClInclude Include="$(SolutionDir)\..\src\core\ext\client_config\resolver.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\ext\client_config\resolver_factory.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\ext\client_config\resolver_registry.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\ext\client_config\resolver_result.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\ext\client_config\subchannel.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\client_config\subchannel_call_holder.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\ext\client_config\subchannel_index.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\ext\client_config\uri_parser.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\ext\lb_policy\grpclb\grpclb.h" />
@@ -454,6 +454,7 @@
     <ClInclude Include="$(SolutionDir)\..\src\core\ext\census\census_interface.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\ext\census\census_rpc_stats.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\ext\census\gen\census.pb.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\ext\census\gen\trace_context.pb.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\ext\census\grpc_filter.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\ext\census\mlog.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\ext\census\resource.h" />
@@ -492,6 +493,8 @@
     </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\closure.c">
     </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\combiner.c">
+    </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\endpoint.c">
     </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\endpoint_pair_posix.c">
@@ -750,8 +753,6 @@
     </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\ext\client_config\client_channel_factory.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\client_config\client_config.c">
-    </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\ext\client_config\client_config_plugin.c">
     </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\ext\client_config\connector.c">
@@ -774,9 +775,9 @@
     </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\ext\client_config\resolver_registry.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\client_config\subchannel.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\client_config\resolver_result.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\client_config\subchannel_call_holder.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\client_config\subchannel.c">
     </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\ext\client_config\subchannel_index.c">
     </ClCompile>
@@ -820,6 +821,8 @@
     </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\ext\census\gen\census.pb.c">
     </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\census\gen\trace_context.pb.c">
+    </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\ext\census\grpc_context.c">
     </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\ext\census\grpc_filter.c">
diff --git a/vsprojects/vcxproj/grpc/grpc.vcxproj.filters b/vsprojects/vcxproj/grpc/grpc.vcxproj.filters
index b310172..f3d7958 100644
--- a/vsprojects/vcxproj/grpc/grpc.vcxproj.filters
+++ b/vsprojects/vcxproj/grpc/grpc.vcxproj.filters
@@ -49,6 +49,9 @@
     <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\closure.c">
       <Filter>src\core\lib\iomgr</Filter>
     </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\combiner.c">
+      <Filter>src\core\lib\iomgr</Filter>
+    </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\endpoint.c">
       <Filter>src\core\lib\iomgr</Filter>
     </ClCompile>
@@ -436,9 +439,6 @@
     <ClCompile Include="$(SolutionDir)\..\src\core\ext\client_config\client_channel_factory.c">
       <Filter>src\core\ext\client_config</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\client_config\client_config.c">
-      <Filter>src\core\ext\client_config</Filter>
-    </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\ext\client_config\client_config_plugin.c">
       <Filter>src\core\ext\client_config</Filter>
     </ClCompile>
@@ -472,10 +472,10 @@
     <ClCompile Include="$(SolutionDir)\..\src\core\ext\client_config\resolver_registry.c">
       <Filter>src\core\ext\client_config</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\client_config\subchannel.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\client_config\resolver_result.c">
       <Filter>src\core\ext\client_config</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\client_config\subchannel_call_holder.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\client_config\subchannel.c">
       <Filter>src\core\ext\client_config</Filter>
     </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\ext\client_config\subchannel_index.c">
@@ -541,6 +541,9 @@
     <ClCompile Include="$(SolutionDir)\..\src\core\ext\census\gen\census.pb.c">
       <Filter>src\core\ext\census\gen</Filter>
     </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\census\gen\trace_context.pb.c">
+      <Filter>src\core\ext\census\gen</Filter>
+    </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\ext\census\grpc_context.c">
       <Filter>src\core\ext\census</Filter>
     </ClCompile>
@@ -588,6 +591,9 @@
     <ClInclude Include="$(SolutionDir)\..\include\grpc\grpc_posix.h">
       <Filter>include\grpc</Filter>
     </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\grpc_security_constants.h">
+      <Filter>include\grpc</Filter>
+    </ClInclude>
     <ClInclude Include="$(SolutionDir)\..\include\grpc\status.h">
       <Filter>include\grpc</Filter>
     </ClInclude>
@@ -657,9 +663,6 @@
     <ClInclude Include="$(SolutionDir)\..\include\grpc\grpc_security.h">
       <Filter>include\grpc</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\include\grpc\grpc_security_constants.h">
-      <Filter>include\grpc</Filter>
-    </ClInclude>
     <ClInclude Include="$(SolutionDir)\..\include\grpc\census.h">
       <Filter>include\grpc</Filter>
     </ClInclude>
@@ -713,6 +716,9 @@
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\closure.h">
       <Filter>src\core\lib\iomgr</Filter>
     </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\combiner.h">
+      <Filter>src\core\lib\iomgr</Filter>
+    </ClInclude>
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\endpoint.h">
       <Filter>src\core\lib\iomgr</Filter>
     </ClInclude>
@@ -1046,9 +1052,6 @@
     <ClInclude Include="$(SolutionDir)\..\src\core\ext\client_config\client_channel_factory.h">
       <Filter>src\core\ext\client_config</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\client_config\client_config.h">
-      <Filter>src\core\ext\client_config</Filter>
-    </ClInclude>
     <ClInclude Include="$(SolutionDir)\..\src\core\ext\client_config\connector.h">
       <Filter>src\core\ext\client_config</Filter>
     </ClInclude>
@@ -1076,10 +1079,10 @@
     <ClInclude Include="$(SolutionDir)\..\src\core\ext\client_config\resolver_registry.h">
       <Filter>src\core\ext\client_config</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\client_config\subchannel.h">
+    <ClInclude Include="$(SolutionDir)\..\src\core\ext\client_config\resolver_result.h">
       <Filter>src\core\ext\client_config</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\client_config\subchannel_call_holder.h">
+    <ClInclude Include="$(SolutionDir)\..\src\core\ext\client_config\subchannel.h">
       <Filter>src\core\ext\client_config</Filter>
     </ClInclude>
     <ClInclude Include="$(SolutionDir)\..\src\core\ext\client_config\subchannel_index.h">
@@ -1130,6 +1133,9 @@
     <ClInclude Include="$(SolutionDir)\..\src\core\ext\census\gen\census.pb.h">
       <Filter>src\core\ext\census\gen</Filter>
     </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\ext\census\gen\trace_context.pb.h">
+      <Filter>src\core\ext\census\gen</Filter>
+    </ClInclude>
     <ClInclude Include="$(SolutionDir)\..\src\core\ext\census\grpc_filter.h">
       <Filter>src\core\ext\census</Filter>
     </ClInclude>
diff --git a/vsprojects/vcxproj/grpc_test_util/grpc_test_util.vcxproj b/vsprojects/vcxproj/grpc_test_util/grpc_test_util.vcxproj
index 84a71d2..b1bdde5 100644
--- a/vsprojects/vcxproj/grpc_test_util/grpc_test_util.vcxproj
+++ b/vsprojects/vcxproj/grpc_test_util/grpc_test_util.vcxproj
@@ -152,6 +152,7 @@
     <ClInclude Include="$(SolutionDir)\..\include\grpc\compression.h" />
     <ClInclude Include="$(SolutionDir)\..\include\grpc\grpc.h" />
     <ClInclude Include="$(SolutionDir)\..\include\grpc\grpc_posix.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\grpc_security_constants.h" />
     <ClInclude Include="$(SolutionDir)\..\include\grpc\status.h" />
     <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\byte_buffer.h" />
     <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\byte_buffer_reader.h" />
@@ -205,6 +206,7 @@
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\http\httpcli.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\http\parser.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\closure.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\combiner.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\endpoint.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\endpoint_pair.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\error.h" />
@@ -335,6 +337,8 @@
     </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\closure.c">
     </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\combiner.c">
+    </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\endpoint.c">
     </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\endpoint_pair_posix.c">
diff --git a/vsprojects/vcxproj/grpc_test_util/grpc_test_util.vcxproj.filters b/vsprojects/vcxproj/grpc_test_util/grpc_test_util.vcxproj.filters
index 18fe926..b78c7bf 100644
--- a/vsprojects/vcxproj/grpc_test_util/grpc_test_util.vcxproj.filters
+++ b/vsprojects/vcxproj/grpc_test_util/grpc_test_util.vcxproj.filters
@@ -97,6 +97,9 @@
     <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\closure.c">
       <Filter>src\core\lib\iomgr</Filter>
     </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\combiner.c">
+      <Filter>src\core\lib\iomgr</Filter>
+    </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\endpoint.c">
       <Filter>src\core\lib\iomgr</Filter>
     </ClCompile>
@@ -336,6 +339,9 @@
     <ClInclude Include="$(SolutionDir)\..\include\grpc\grpc_posix.h">
       <Filter>include\grpc</Filter>
     </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\grpc_security_constants.h">
+      <Filter>include\grpc</Filter>
+    </ClInclude>
     <ClInclude Include="$(SolutionDir)\..\include\grpc\status.h">
       <Filter>include\grpc</Filter>
     </ClInclude>
@@ -491,6 +497,9 @@
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\closure.h">
       <Filter>src\core\lib\iomgr</Filter>
     </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\combiner.h">
+      <Filter>src\core\lib\iomgr</Filter>
+    </ClInclude>
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\endpoint.h">
       <Filter>src\core\lib\iomgr</Filter>
     </ClInclude>
diff --git a/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj b/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj
index 7a5f858..0ea8808 100644
--- a/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj
+++ b/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj
@@ -263,6 +263,7 @@
     <ClInclude Include="$(SolutionDir)\..\include\grpc\compression.h" />
     <ClInclude Include="$(SolutionDir)\..\include\grpc\grpc.h" />
     <ClInclude Include="$(SolutionDir)\..\include\grpc\grpc_posix.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\grpc_security_constants.h" />
     <ClInclude Include="$(SolutionDir)\..\include\grpc\status.h" />
     <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\byte_buffer.h" />
     <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\byte_buffer_reader.h" />
@@ -304,6 +305,7 @@
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\http\httpcli.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\http\parser.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\closure.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\combiner.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\endpoint.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\endpoint_pair.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\error.h" />
@@ -391,7 +393,6 @@
     <ClInclude Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\alpn\alpn.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\ext\client_config\client_channel.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\ext\client_config\client_channel_factory.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\client_config\client_config.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\ext\client_config\connector.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\ext\client_config\initial_connect_string.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\ext\client_config\lb_policy.h" />
@@ -401,8 +402,8 @@
     <ClInclude Include="$(SolutionDir)\..\src\core\ext\client_config\resolver.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\ext\client_config\resolver_factory.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\ext\client_config\resolver_registry.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\ext\client_config\resolver_result.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\ext\client_config\subchannel.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\client_config\subchannel_call_holder.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\ext\client_config\subchannel_index.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\ext\client_config\uri_parser.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\ext\load_reporting\load_reporting.h" />
@@ -419,6 +420,7 @@
     <ClInclude Include="$(SolutionDir)\..\src\core\ext\census\census_interface.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\ext\census\census_rpc_stats.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\ext\census\gen\census.pb.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\ext\census\gen\trace_context.pb.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\ext\census\grpc_filter.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\ext\census\mlog.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\ext\census\resource.h" />
@@ -459,6 +461,8 @@
     </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\closure.c">
     </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\combiner.c">
+    </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\endpoint.c">
     </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\endpoint_pair_posix.c">
@@ -665,8 +669,6 @@
     </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\ext\client_config\client_channel_factory.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\client_config\client_config.c">
-    </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\ext\client_config\client_config_plugin.c">
     </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\ext\client_config\connector.c">
@@ -689,9 +691,9 @@
     </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\ext\client_config\resolver_registry.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\client_config\subchannel.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\client_config\resolver_result.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\client_config\subchannel_call_holder.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\client_config\subchannel.c">
     </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\ext\client_config\subchannel_index.c">
     </ClCompile>
@@ -727,6 +729,8 @@
     </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\ext\census\gen\census.pb.c">
     </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\census\gen\trace_context.pb.c">
+    </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\ext\census\grpc_context.c">
     </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\ext\census\grpc_filter.c">
diff --git a/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj.filters b/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj.filters
index 99db98e..7549a96 100644
--- a/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj.filters
+++ b/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj.filters
@@ -52,6 +52,9 @@
     <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\closure.c">
       <Filter>src\core\lib\iomgr</Filter>
     </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\combiner.c">
+      <Filter>src\core\lib\iomgr</Filter>
+    </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\endpoint.c">
       <Filter>src\core\lib\iomgr</Filter>
     </ClCompile>
@@ -361,9 +364,6 @@
     <ClCompile Include="$(SolutionDir)\..\src\core\ext\client_config\client_channel_factory.c">
       <Filter>src\core\ext\client_config</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\client_config\client_config.c">
-      <Filter>src\core\ext\client_config</Filter>
-    </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\ext\client_config\client_config_plugin.c">
       <Filter>src\core\ext\client_config</Filter>
     </ClCompile>
@@ -397,10 +397,10 @@
     <ClCompile Include="$(SolutionDir)\..\src\core\ext\client_config\resolver_registry.c">
       <Filter>src\core\ext\client_config</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\client_config\subchannel.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\client_config\resolver_result.c">
       <Filter>src\core\ext\client_config</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\ext\client_config\subchannel_call_holder.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\client_config\subchannel.c">
       <Filter>src\core\ext\client_config</Filter>
     </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\ext\client_config\subchannel_index.c">
@@ -454,6 +454,9 @@
     <ClCompile Include="$(SolutionDir)\..\src\core\ext\census\gen\census.pb.c">
       <Filter>src\core\ext\census\gen</Filter>
     </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\ext\census\gen\trace_context.pb.c">
+      <Filter>src\core\ext\census\gen</Filter>
+    </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\ext\census\grpc_context.c">
       <Filter>src\core\ext\census</Filter>
     </ClCompile>
@@ -501,6 +504,9 @@
     <ClInclude Include="$(SolutionDir)\..\include\grpc\grpc_posix.h">
       <Filter>include\grpc</Filter>
     </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\grpc_security_constants.h">
+      <Filter>include\grpc</Filter>
+    </ClInclude>
     <ClInclude Include="$(SolutionDir)\..\include\grpc\status.h">
       <Filter>include\grpc</Filter>
     </ClInclude>
@@ -620,6 +626,9 @@
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\closure.h">
       <Filter>src\core\lib\iomgr</Filter>
     </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\combiner.h">
+      <Filter>src\core\lib\iomgr</Filter>
+    </ClInclude>
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\endpoint.h">
       <Filter>src\core\lib\iomgr</Filter>
     </ClInclude>
@@ -881,9 +890,6 @@
     <ClInclude Include="$(SolutionDir)\..\src\core\ext\client_config\client_channel_factory.h">
       <Filter>src\core\ext\client_config</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\client_config\client_config.h">
-      <Filter>src\core\ext\client_config</Filter>
-    </ClInclude>
     <ClInclude Include="$(SolutionDir)\..\src\core\ext\client_config\connector.h">
       <Filter>src\core\ext\client_config</Filter>
     </ClInclude>
@@ -911,10 +917,10 @@
     <ClInclude Include="$(SolutionDir)\..\src\core\ext\client_config\resolver_registry.h">
       <Filter>src\core\ext\client_config</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\client_config\subchannel.h">
+    <ClInclude Include="$(SolutionDir)\..\src\core\ext\client_config\resolver_result.h">
       <Filter>src\core\ext\client_config</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\ext\client_config\subchannel_call_holder.h">
+    <ClInclude Include="$(SolutionDir)\..\src\core\ext\client_config\subchannel.h">
       <Filter>src\core\ext\client_config</Filter>
     </ClInclude>
     <ClInclude Include="$(SolutionDir)\..\src\core\ext\client_config\subchannel_index.h">
@@ -965,6 +971,9 @@
     <ClInclude Include="$(SolutionDir)\..\src\core\ext\census\gen\census.pb.h">
       <Filter>src\core\ext\census\gen</Filter>
     </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\ext\census\gen\trace_context.pb.h">
+      <Filter>src\core\ext\census\gen</Filter>
+    </ClInclude>
     <ClInclude Include="$(SolutionDir)\..\src\core\ext\census\grpc_filter.h">
       <Filter>src\core\ext\census</Filter>
     </ClInclude>
diff --git a/vsprojects/vcxproj/test/combiner_test/combiner_test.vcxproj b/vsprojects/vcxproj/test/combiner_test/combiner_test.vcxproj
new file mode 100644
index 0000000..f889d21
--- /dev/null
+++ b/vsprojects/vcxproj/test/combiner_test/combiner_test.vcxproj
@@ -0,0 +1,199 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <Import Project="$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.1.0.204.1\build\native\grpc.dependencies.openssl.props" Condition="Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.1.0.204.1\build\native\1.0.204.1.props')" />
+  <ItemGroup Label="ProjectConfigurations">
+    <ProjectConfiguration Include="Debug|Win32">
+      <Configuration>Debug</Configuration>
+      <Platform>Win32</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Debug|x64">
+      <Configuration>Debug</Configuration>
+      <Platform>x64</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Release|Win32">
+      <Configuration>Release</Configuration>
+      <Platform>Win32</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Release|x64">
+      <Configuration>Release</Configuration>
+      <Platform>x64</Platform>
+    </ProjectConfiguration>
+  </ItemGroup>
+  <PropertyGroup Label="Globals">
+    <ProjectGuid>{C237D1E4-8825-80BA-1FC3-5E147E53E96E}</ProjectGuid>
+    <IgnoreWarnIntDirInTempDetected>true</IgnoreWarnIntDirInTempDetected>
+    <IntDir>$(SolutionDir)IntDir\$(MSBuildProjectName)\</IntDir>
+  </PropertyGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+  <PropertyGroup Condition="'$(VisualStudioVersion)' == '10.0'" Label="Configuration">
+    <PlatformToolset>v100</PlatformToolset>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(VisualStudioVersion)' == '11.0'" Label="Configuration">
+    <PlatformToolset>v110</PlatformToolset>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(VisualStudioVersion)' == '12.0'" Label="Configuration">
+    <PlatformToolset>v120</PlatformToolset>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(VisualStudioVersion)' == '14.0'" Label="Configuration">
+    <PlatformToolset>v140</PlatformToolset>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)'=='Debug'" Label="Configuration">
+    <ConfigurationType>Application</ConfigurationType>
+    <UseDebugLibraries>true</UseDebugLibraries>
+    <CharacterSet>Unicode</CharacterSet>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)'=='Release'" Label="Configuration">
+    <ConfigurationType>Application</ConfigurationType>
+    <UseDebugLibraries>false</UseDebugLibraries>
+    <WholeProgramOptimization>true</WholeProgramOptimization>
+    <CharacterSet>Unicode</CharacterSet>
+  </PropertyGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+  <ImportGroup Label="ExtensionSettings">
+  </ImportGroup>
+  <ImportGroup Label="PropertySheets">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+    <Import Project="$(SolutionDir)\..\vsprojects\global.props" />
+    <Import Project="$(SolutionDir)\..\vsprojects\openssl.props" />
+    <Import Project="$(SolutionDir)\..\vsprojects\winsock.props" />
+    <Import Project="$(SolutionDir)\..\vsprojects\zlib.props" />
+  </ImportGroup>
+  <PropertyGroup Label="UserMacros" />
+  <PropertyGroup Condition="'$(Configuration)'=='Debug'">
+    <TargetName>combiner_test</TargetName>
+    <Linkage-grpc_dependencies_zlib>static</Linkage-grpc_dependencies_zlib>
+    <Configuration-grpc_dependencies_zlib>Debug</Configuration-grpc_dependencies_zlib>
+    <Linkage-grpc_dependencies_openssl>static</Linkage-grpc_dependencies_openssl>
+    <Configuration-grpc_dependencies_openssl>Debug</Configuration-grpc_dependencies_openssl>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)'=='Release'">
+    <TargetName>combiner_test</TargetName>
+    <Linkage-grpc_dependencies_zlib>static</Linkage-grpc_dependencies_zlib>
+    <Configuration-grpc_dependencies_zlib>Release</Configuration-grpc_dependencies_zlib>
+    <Linkage-grpc_dependencies_openssl>static</Linkage-grpc_dependencies_openssl>
+    <Configuration-grpc_dependencies_openssl>Release</Configuration-grpc_dependencies_openssl>
+  </PropertyGroup>
+    <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+    <ClCompile>
+      <PrecompiledHeader>NotUsing</PrecompiledHeader>
+      <WarningLevel>Level3</WarningLevel>
+      <Optimization>Disabled</Optimization>
+      <PreprocessorDefinitions>WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <SDLCheck>true</SDLCheck>
+      <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
+      <TreatWarningAsError>true</TreatWarningAsError>
+      <DebugInformationFormat Condition="$(Jenkins)">None</DebugInformationFormat>
+      <MinimalRebuild Condition="$(Jenkins)">false</MinimalRebuild>
+    </ClCompile>
+    <Link>
+      <SubSystem>Console</SubSystem>
+      <GenerateDebugInformation Condition="!$(Jenkins)">true</GenerateDebugInformation>
+      <GenerateDebugInformation Condition="$(Jenkins)">false</GenerateDebugInformation>
+    </Link>
+  </ItemDefinitionGroup>
+
+    <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+    <ClCompile>
+      <PrecompiledHeader>NotUsing</PrecompiledHeader>
+      <WarningLevel>Level3</WarningLevel>
+      <Optimization>Disabled</Optimization>
+      <PreprocessorDefinitions>WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <SDLCheck>true</SDLCheck>
+      <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
+      <TreatWarningAsError>true</TreatWarningAsError>
+      <DebugInformationFormat Condition="$(Jenkins)">None</DebugInformationFormat>
+      <MinimalRebuild Condition="$(Jenkins)">false</MinimalRebuild>
+    </ClCompile>
+    <Link>
+      <SubSystem>Console</SubSystem>
+      <GenerateDebugInformation Condition="!$(Jenkins)">true</GenerateDebugInformation>
+      <GenerateDebugInformation Condition="$(Jenkins)">false</GenerateDebugInformation>
+    </Link>
+  </ItemDefinitionGroup>
+
+    <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+    <ClCompile>
+      <PrecompiledHeader>NotUsing</PrecompiledHeader>
+      <WarningLevel>Level3</WarningLevel>
+      <Optimization>MaxSpeed</Optimization>
+      <PreprocessorDefinitions>WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <FunctionLevelLinking>true</FunctionLevelLinking>
+      <IntrinsicFunctions>true</IntrinsicFunctions>
+      <SDLCheck>true</SDLCheck>
+      <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
+      <TreatWarningAsError>true</TreatWarningAsError>
+      <DebugInformationFormat Condition="$(Jenkins)">None</DebugInformationFormat>
+      <MinimalRebuild Condition="$(Jenkins)">false</MinimalRebuild>
+    </ClCompile>
+    <Link>
+      <SubSystem>Console</SubSystem>
+      <GenerateDebugInformation Condition="!$(Jenkins)">true</GenerateDebugInformation>
+      <GenerateDebugInformation Condition="$(Jenkins)">false</GenerateDebugInformation>
+      <EnableCOMDATFolding>true</EnableCOMDATFolding>
+      <OptimizeReferences>true</OptimizeReferences>
+    </Link>
+  </ItemDefinitionGroup>
+
+    <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+    <ClCompile>
+      <PrecompiledHeader>NotUsing</PrecompiledHeader>
+      <WarningLevel>Level3</WarningLevel>
+      <Optimization>MaxSpeed</Optimization>
+      <PreprocessorDefinitions>WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <FunctionLevelLinking>true</FunctionLevelLinking>
+      <IntrinsicFunctions>true</IntrinsicFunctions>
+      <SDLCheck>true</SDLCheck>
+      <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
+      <TreatWarningAsError>true</TreatWarningAsError>
+      <DebugInformationFormat Condition="$(Jenkins)">None</DebugInformationFormat>
+      <MinimalRebuild Condition="$(Jenkins)">false</MinimalRebuild>
+    </ClCompile>
+    <Link>
+      <SubSystem>Console</SubSystem>
+      <GenerateDebugInformation Condition="!$(Jenkins)">true</GenerateDebugInformation>
+      <GenerateDebugInformation Condition="$(Jenkins)">false</GenerateDebugInformation>
+      <EnableCOMDATFolding>true</EnableCOMDATFolding>
+      <OptimizeReferences>true</OptimizeReferences>
+    </Link>
+  </ItemDefinitionGroup>
+
+  <ItemGroup>
+    <ClCompile Include="$(SolutionDir)\..\test\core\iomgr\combiner_test.c">
+    </ClCompile>
+  </ItemGroup>
+  <ItemGroup>
+    <ProjectReference Include="$(SolutionDir)\..\vsprojects\vcxproj\.\grpc_test_util\grpc_test_util.vcxproj">
+      <Project>{17BCAFC0-5FDC-4C94-AEB9-95F3E220614B}</Project>
+    </ProjectReference>
+    <ProjectReference Include="$(SolutionDir)\..\vsprojects\vcxproj\.\grpc\grpc.vcxproj">
+      <Project>{29D16885-7228-4C31-81ED-5F9187C7F2A9}</Project>
+    </ProjectReference>
+    <ProjectReference Include="$(SolutionDir)\..\vsprojects\vcxproj\.\gpr_test_util\gpr_test_util.vcxproj">
+      <Project>{EAB0A629-17A9-44DB-B5FF-E91A721FE037}</Project>
+    </ProjectReference>
+    <ProjectReference Include="$(SolutionDir)\..\vsprojects\vcxproj\.\gpr\gpr.vcxproj">
+      <Project>{B23D3D1A-9438-4EDA-BEB6-9A0A03D17792}</Project>
+    </ProjectReference>
+  </ItemGroup>
+  <ItemGroup>
+    <None Include="packages.config" />
+  </ItemGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+  <ImportGroup Label="ExtensionTargets">
+  <Import Project="$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.zlib.redist.1.2.8.10\build\native\grpc.dependencies.zlib.redist.targets" Condition="Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.zlib.redist.1.2.8.10\build\native\grpc.dependencies\grpc.dependencies.zlib.targets')" />
+  <Import Project="$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.zlib.1.2.8.10\build\native\grpc.dependencies.zlib.targets" Condition="Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.zlib.1.2.8.10\build\native\grpc.dependencies\grpc.dependencies.zlib.targets')" />
+  <Import Project="$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.redist.1.0.204.1\build\native\grpc.dependencies.openssl.redist.targets" Condition="Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.redist.1.0.204.1\build\native\grpc.dependencies\grpc.dependencies.openssl.targets')" />
+  <Import Project="$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.1.0.204.1\build\native\grpc.dependencies.openssl.targets" Condition="Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.1.0.204.1\build\native\grpc.dependencies\grpc.dependencies.openssl.targets')" />
+  </ImportGroup>
+  <Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
+    <PropertyGroup>
+      <ErrorText>This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them.  For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
+    </PropertyGroup>
+    <Error Condition="!Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.zlib.redist.1.2.8.10\build\native\grpc.dependencies.zlib.redist.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.zlib.redist.1.2.8.10\build\native\grpc.dependencies.zlib.redist.targets')" />
+    <Error Condition="!Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.zlib.1.2.8.10\build\native\grpc.dependencies.zlib.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.zlib.1.2.8.10\build\native\grpc.dependencies.zlib.targets')" />
+    <Error Condition="!Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.redist.1.0.204.1\build\native\grpc.dependencies.openssl.redist.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.redist.1.0.204.1\build\native\grpc.dependencies.openssl.redist.targets')" />
+    <Error Condition="!Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.1.0.204.1\build\native\grpc.dependencies.openssl.props')" Text="$([System.String]::Format('$(ErrorText)', '$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.1.0.204.1\build\native\grpc.dependencies.openssl.props')" />
+    <Error Condition="!Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.1.0.204.1\build\native\grpc.dependencies.openssl.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.1.0.204.1\build\native\grpc.dependencies.openssl.targets')" />
+  </Target>
+</Project>
+
diff --git a/vsprojects/vcxproj/test/combiner_test/combiner_test.vcxproj.filters b/vsprojects/vcxproj/test/combiner_test/combiner_test.vcxproj.filters
new file mode 100644
index 0000000..e8ebb09
--- /dev/null
+++ b/vsprojects/vcxproj/test/combiner_test/combiner_test.vcxproj.filters
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <ItemGroup>
+    <ClCompile Include="$(SolutionDir)\..\test\core\iomgr\combiner_test.c">
+      <Filter>test\core\iomgr</Filter>
+    </ClCompile>
+  </ItemGroup>
+
+  <ItemGroup>
+    <Filter Include="test">
+      <UniqueIdentifier>{82bca2af-d499-b405-fd05-4d345372496c}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="test\core">
+      <UniqueIdentifier>{c32d8e20-b719-532d-ba23-bd9d523fac15}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="test\core\iomgr">
+      <UniqueIdentifier>{b4fa8ca1-e6c7-dec5-6d62-8a62396825c6}</UniqueIdentifier>
+    </Filter>
+  </ItemGroup>
+</Project>
+
diff --git a/vsprojects/vcxproj/test/end2end/tests/end2end_nosec_tests/end2end_nosec_tests.vcxproj b/vsprojects/vcxproj/test/end2end/tests/end2end_nosec_tests/end2end_nosec_tests.vcxproj
index a500fe3..96c9574 100644
--- a/vsprojects/vcxproj/test/end2end/tests/end2end_nosec_tests/end2end_nosec_tests.vcxproj
+++ b/vsprojects/vcxproj/test/end2end/tests/end2end_nosec_tests/end2end_nosec_tests.vcxproj
@@ -205,6 +205,8 @@
     </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\test\core\end2end\tests\network_status_change.c">
     </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\test\core\end2end\tests\no_logging.c">
+    </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\test\core\end2end\tests\no_op.c">
     </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\test\core\end2end\tests\payload.c">
diff --git a/vsprojects/vcxproj/test/end2end/tests/end2end_nosec_tests/end2end_nosec_tests.vcxproj.filters b/vsprojects/vcxproj/test/end2end/tests/end2end_nosec_tests/end2end_nosec_tests.vcxproj.filters
index 6f2294c..42f1b8e 100644
--- a/vsprojects/vcxproj/test/end2end/tests/end2end_nosec_tests/end2end_nosec_tests.vcxproj.filters
+++ b/vsprojects/vcxproj/test/end2end/tests/end2end_nosec_tests/end2end_nosec_tests.vcxproj.filters
@@ -82,6 +82,9 @@
     <ClCompile Include="$(SolutionDir)\..\test\core\end2end\tests\network_status_change.c">
       <Filter>test\core\end2end\tests</Filter>
     </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\test\core\end2end\tests\no_logging.c">
+      <Filter>test\core\end2end\tests</Filter>
+    </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\test\core\end2end\tests\no_op.c">
       <Filter>test\core\end2end\tests</Filter>
     </ClCompile>
diff --git a/vsprojects/vcxproj/test/end2end/tests/end2end_tests/end2end_tests.vcxproj b/vsprojects/vcxproj/test/end2end/tests/end2end_tests/end2end_tests.vcxproj
index 7614089..4336f36 100644
--- a/vsprojects/vcxproj/test/end2end/tests/end2end_tests/end2end_tests.vcxproj
+++ b/vsprojects/vcxproj/test/end2end/tests/end2end_tests/end2end_tests.vcxproj
@@ -207,6 +207,8 @@
     </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\test\core\end2end\tests\network_status_change.c">
     </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\test\core\end2end\tests\no_logging.c">
+    </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\test\core\end2end\tests\no_op.c">
     </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\test\core\end2end\tests\payload.c">
diff --git a/vsprojects/vcxproj/test/end2end/tests/end2end_tests/end2end_tests.vcxproj.filters b/vsprojects/vcxproj/test/end2end/tests/end2end_tests/end2end_tests.vcxproj.filters
index db336f0..a94dbe8 100644
--- a/vsprojects/vcxproj/test/end2end/tests/end2end_tests/end2end_tests.vcxproj.filters
+++ b/vsprojects/vcxproj/test/end2end/tests/end2end_tests/end2end_tests.vcxproj.filters
@@ -85,6 +85,9 @@
     <ClCompile Include="$(SolutionDir)\..\test\core\end2end\tests\network_status_change.c">
       <Filter>test\core\end2end\tests</Filter>
     </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\test\core\end2end\tests\no_logging.c">
+      <Filter>test\core\end2end\tests</Filter>
+    </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\test\core\end2end\tests\no_op.c">
       <Filter>test\core\end2end\tests</Filter>
     </ClCompile>
diff --git a/vsprojects/vcxproj/test/gpr_mpscq_test/gpr_mpscq_test.vcxproj b/vsprojects/vcxproj/test/gpr_mpscq_test/gpr_mpscq_test.vcxproj
new file mode 100644
index 0000000..0134286
--- /dev/null
+++ b/vsprojects/vcxproj/test/gpr_mpscq_test/gpr_mpscq_test.vcxproj
@@ -0,0 +1,193 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <Import Project="$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.1.0.204.1\build\native\grpc.dependencies.openssl.props" Condition="Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.1.0.204.1\build\native\1.0.204.1.props')" />
+  <ItemGroup Label="ProjectConfigurations">
+    <ProjectConfiguration Include="Debug|Win32">
+      <Configuration>Debug</Configuration>
+      <Platform>Win32</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Debug|x64">
+      <Configuration>Debug</Configuration>
+      <Platform>x64</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Release|Win32">
+      <Configuration>Release</Configuration>
+      <Platform>Win32</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Release|x64">
+      <Configuration>Release</Configuration>
+      <Platform>x64</Platform>
+    </ProjectConfiguration>
+  </ItemGroup>
+  <PropertyGroup Label="Globals">
+    <ProjectGuid>{B3D7760B-8BEA-2EF6-F1D4-9F9020E166D6}</ProjectGuid>
+    <IgnoreWarnIntDirInTempDetected>true</IgnoreWarnIntDirInTempDetected>
+    <IntDir>$(SolutionDir)IntDir\$(MSBuildProjectName)\</IntDir>
+  </PropertyGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+  <PropertyGroup Condition="'$(VisualStudioVersion)' == '10.0'" Label="Configuration">
+    <PlatformToolset>v100</PlatformToolset>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(VisualStudioVersion)' == '11.0'" Label="Configuration">
+    <PlatformToolset>v110</PlatformToolset>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(VisualStudioVersion)' == '12.0'" Label="Configuration">
+    <PlatformToolset>v120</PlatformToolset>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(VisualStudioVersion)' == '14.0'" Label="Configuration">
+    <PlatformToolset>v140</PlatformToolset>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)'=='Debug'" Label="Configuration">
+    <ConfigurationType>Application</ConfigurationType>
+    <UseDebugLibraries>true</UseDebugLibraries>
+    <CharacterSet>Unicode</CharacterSet>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)'=='Release'" Label="Configuration">
+    <ConfigurationType>Application</ConfigurationType>
+    <UseDebugLibraries>false</UseDebugLibraries>
+    <WholeProgramOptimization>true</WholeProgramOptimization>
+    <CharacterSet>Unicode</CharacterSet>
+  </PropertyGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+  <ImportGroup Label="ExtensionSettings">
+  </ImportGroup>
+  <ImportGroup Label="PropertySheets">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+    <Import Project="$(SolutionDir)\..\vsprojects\global.props" />
+    <Import Project="$(SolutionDir)\..\vsprojects\openssl.props" />
+    <Import Project="$(SolutionDir)\..\vsprojects\winsock.props" />
+    <Import Project="$(SolutionDir)\..\vsprojects\zlib.props" />
+  </ImportGroup>
+  <PropertyGroup Label="UserMacros" />
+  <PropertyGroup Condition="'$(Configuration)'=='Debug'">
+    <TargetName>gpr_mpscq_test</TargetName>
+    <Linkage-grpc_dependencies_zlib>static</Linkage-grpc_dependencies_zlib>
+    <Configuration-grpc_dependencies_zlib>Debug</Configuration-grpc_dependencies_zlib>
+    <Linkage-grpc_dependencies_openssl>static</Linkage-grpc_dependencies_openssl>
+    <Configuration-grpc_dependencies_openssl>Debug</Configuration-grpc_dependencies_openssl>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)'=='Release'">
+    <TargetName>gpr_mpscq_test</TargetName>
+    <Linkage-grpc_dependencies_zlib>static</Linkage-grpc_dependencies_zlib>
+    <Configuration-grpc_dependencies_zlib>Release</Configuration-grpc_dependencies_zlib>
+    <Linkage-grpc_dependencies_openssl>static</Linkage-grpc_dependencies_openssl>
+    <Configuration-grpc_dependencies_openssl>Release</Configuration-grpc_dependencies_openssl>
+  </PropertyGroup>
+    <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+    <ClCompile>
+      <PrecompiledHeader>NotUsing</PrecompiledHeader>
+      <WarningLevel>Level3</WarningLevel>
+      <Optimization>Disabled</Optimization>
+      <PreprocessorDefinitions>WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <SDLCheck>true</SDLCheck>
+      <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
+      <TreatWarningAsError>true</TreatWarningAsError>
+      <DebugInformationFormat Condition="$(Jenkins)">None</DebugInformationFormat>
+      <MinimalRebuild Condition="$(Jenkins)">false</MinimalRebuild>
+    </ClCompile>
+    <Link>
+      <SubSystem>Console</SubSystem>
+      <GenerateDebugInformation Condition="!$(Jenkins)">true</GenerateDebugInformation>
+      <GenerateDebugInformation Condition="$(Jenkins)">false</GenerateDebugInformation>
+    </Link>
+  </ItemDefinitionGroup>
+
+    <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+    <ClCompile>
+      <PrecompiledHeader>NotUsing</PrecompiledHeader>
+      <WarningLevel>Level3</WarningLevel>
+      <Optimization>Disabled</Optimization>
+      <PreprocessorDefinitions>WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <SDLCheck>true</SDLCheck>
+      <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
+      <TreatWarningAsError>true</TreatWarningAsError>
+      <DebugInformationFormat Condition="$(Jenkins)">None</DebugInformationFormat>
+      <MinimalRebuild Condition="$(Jenkins)">false</MinimalRebuild>
+    </ClCompile>
+    <Link>
+      <SubSystem>Console</SubSystem>
+      <GenerateDebugInformation Condition="!$(Jenkins)">true</GenerateDebugInformation>
+      <GenerateDebugInformation Condition="$(Jenkins)">false</GenerateDebugInformation>
+    </Link>
+  </ItemDefinitionGroup>
+
+    <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+    <ClCompile>
+      <PrecompiledHeader>NotUsing</PrecompiledHeader>
+      <WarningLevel>Level3</WarningLevel>
+      <Optimization>MaxSpeed</Optimization>
+      <PreprocessorDefinitions>WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <FunctionLevelLinking>true</FunctionLevelLinking>
+      <IntrinsicFunctions>true</IntrinsicFunctions>
+      <SDLCheck>true</SDLCheck>
+      <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
+      <TreatWarningAsError>true</TreatWarningAsError>
+      <DebugInformationFormat Condition="$(Jenkins)">None</DebugInformationFormat>
+      <MinimalRebuild Condition="$(Jenkins)">false</MinimalRebuild>
+    </ClCompile>
+    <Link>
+      <SubSystem>Console</SubSystem>
+      <GenerateDebugInformation Condition="!$(Jenkins)">true</GenerateDebugInformation>
+      <GenerateDebugInformation Condition="$(Jenkins)">false</GenerateDebugInformation>
+      <EnableCOMDATFolding>true</EnableCOMDATFolding>
+      <OptimizeReferences>true</OptimizeReferences>
+    </Link>
+  </ItemDefinitionGroup>
+
+    <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+    <ClCompile>
+      <PrecompiledHeader>NotUsing</PrecompiledHeader>
+      <WarningLevel>Level3</WarningLevel>
+      <Optimization>MaxSpeed</Optimization>
+      <PreprocessorDefinitions>WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <FunctionLevelLinking>true</FunctionLevelLinking>
+      <IntrinsicFunctions>true</IntrinsicFunctions>
+      <SDLCheck>true</SDLCheck>
+      <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
+      <TreatWarningAsError>true</TreatWarningAsError>
+      <DebugInformationFormat Condition="$(Jenkins)">None</DebugInformationFormat>
+      <MinimalRebuild Condition="$(Jenkins)">false</MinimalRebuild>
+    </ClCompile>
+    <Link>
+      <SubSystem>Console</SubSystem>
+      <GenerateDebugInformation Condition="!$(Jenkins)">true</GenerateDebugInformation>
+      <GenerateDebugInformation Condition="$(Jenkins)">false</GenerateDebugInformation>
+      <EnableCOMDATFolding>true</EnableCOMDATFolding>
+      <OptimizeReferences>true</OptimizeReferences>
+    </Link>
+  </ItemDefinitionGroup>
+
+  <ItemGroup>
+    <ClCompile Include="$(SolutionDir)\..\test\core\support\mpscq_test.c">
+    </ClCompile>
+  </ItemGroup>
+  <ItemGroup>
+    <ProjectReference Include="$(SolutionDir)\..\vsprojects\vcxproj\.\gpr_test_util\gpr_test_util.vcxproj">
+      <Project>{EAB0A629-17A9-44DB-B5FF-E91A721FE037}</Project>
+    </ProjectReference>
+    <ProjectReference Include="$(SolutionDir)\..\vsprojects\vcxproj\.\gpr\gpr.vcxproj">
+      <Project>{B23D3D1A-9438-4EDA-BEB6-9A0A03D17792}</Project>
+    </ProjectReference>
+  </ItemGroup>
+  <ItemGroup>
+    <None Include="packages.config" />
+  </ItemGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+  <ImportGroup Label="ExtensionTargets">
+  <Import Project="$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.zlib.redist.1.2.8.10\build\native\grpc.dependencies.zlib.redist.targets" Condition="Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.zlib.redist.1.2.8.10\build\native\grpc.dependencies\grpc.dependencies.zlib.targets')" />
+  <Import Project="$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.zlib.1.2.8.10\build\native\grpc.dependencies.zlib.targets" Condition="Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.zlib.1.2.8.10\build\native\grpc.dependencies\grpc.dependencies.zlib.targets')" />
+  <Import Project="$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.redist.1.0.204.1\build\native\grpc.dependencies.openssl.redist.targets" Condition="Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.redist.1.0.204.1\build\native\grpc.dependencies\grpc.dependencies.openssl.targets')" />
+  <Import Project="$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.1.0.204.1\build\native\grpc.dependencies.openssl.targets" Condition="Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.1.0.204.1\build\native\grpc.dependencies\grpc.dependencies.openssl.targets')" />
+  </ImportGroup>
+  <Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
+    <PropertyGroup>
+      <ErrorText>This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them.  For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
+    </PropertyGroup>
+    <Error Condition="!Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.zlib.redist.1.2.8.10\build\native\grpc.dependencies.zlib.redist.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.zlib.redist.1.2.8.10\build\native\grpc.dependencies.zlib.redist.targets')" />
+    <Error Condition="!Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.zlib.1.2.8.10\build\native\grpc.dependencies.zlib.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.zlib.1.2.8.10\build\native\grpc.dependencies.zlib.targets')" />
+    <Error Condition="!Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.redist.1.0.204.1\build\native\grpc.dependencies.openssl.redist.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.redist.1.0.204.1\build\native\grpc.dependencies.openssl.redist.targets')" />
+    <Error Condition="!Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.1.0.204.1\build\native\grpc.dependencies.openssl.props')" Text="$([System.String]::Format('$(ErrorText)', '$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.1.0.204.1\build\native\grpc.dependencies.openssl.props')" />
+    <Error Condition="!Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.1.0.204.1\build\native\grpc.dependencies.openssl.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.1.0.204.1\build\native\grpc.dependencies.openssl.targets')" />
+  </Target>
+</Project>
+
diff --git a/vsprojects/vcxproj/test/gpr_mpscq_test/gpr_mpscq_test.vcxproj.filters b/vsprojects/vcxproj/test/gpr_mpscq_test/gpr_mpscq_test.vcxproj.filters
new file mode 100644
index 0000000..9cceb9f
--- /dev/null
+++ b/vsprojects/vcxproj/test/gpr_mpscq_test/gpr_mpscq_test.vcxproj.filters
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <ItemGroup>
+    <ClCompile Include="$(SolutionDir)\..\test\core\support\mpscq_test.c">
+      <Filter>test\core\support</Filter>
+    </ClCompile>
+  </ItemGroup>
+
+  <ItemGroup>
+    <Filter Include="test">
+      <UniqueIdentifier>{e82fb80c-10ba-2959-55d6-8653715f1e4f}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="test\core">
+      <UniqueIdentifier>{32120233-25e6-f3e4-f828-c6408d47ec04}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="test\core\support">
+      <UniqueIdentifier>{aa3a22bc-229a-c00a-dd4a-924c818c6a49}</UniqueIdentifier>
+    </Filter>
+  </ItemGroup>
+</Project>
+