Merge branch 'devel-monotonic' of https://github.com/iancoolidge/grpc into cv-wait-monotonic
diff --git a/.gitignore b/.gitignore
index 5ccad2e..151bbbd 100644
--- a/.gitignore
+++ b/.gitignore
@@ -56,6 +56,7 @@
 
 # Temporary test reports
 report.xml
+*/sponge_log.xml
 latency_trace.txt
 latency_trace.*.txt
 
diff --git a/BUILD b/BUILD
index 4e04b8c..1384319 100644
--- a/BUILD
+++ b/BUILD
@@ -38,6 +38,11 @@
     values = {"define": "grpc_no_ares=true"},
 )
 
+config_setting(
+    name = "remote_execution",
+    values = {"define": "GRPC_PORT_ISOLATED_RUNTIME=1"},
+)
+
 # This should be updated along with build.yaml
 g_stands_for = "generous"
 
@@ -54,7 +59,6 @@
     "include/grpc/support/avl.h",
     "include/grpc/support/cmdline.h",
     "include/grpc/support/cpu.h",
-    "include/grpc/support/histogram.h",
     "include/grpc/support/host_port.h",
     "include/grpc/support/log.h",
     "include/grpc/support/log_windows.h",
@@ -79,10 +83,11 @@
     "include/grpc/byte_buffer.h",
     "include/grpc/byte_buffer_reader.h",
     "include/grpc/compression.h",
-    "include/grpc/load_reporting.h",
+    "include/grpc/fork.h",
     "include/grpc/grpc.h",
     "include/grpc/grpc_posix.h",
     "include/grpc/grpc_security_constants.h",
+    "include/grpc/load_reporting.h",
     "include/grpc/slice.h",
     "include/grpc/slice_buffer.h",
     "include/grpc/status.h",
@@ -418,7 +423,6 @@
     ],
     external_deps = [
         "nanopb",
-        "libssl",
     ],
     language = "c++",
     public_hdrs = [
@@ -446,7 +450,7 @@
         "src/core/lib/support/env_linux.cc",
         "src/core/lib/support/env_posix.cc",
         "src/core/lib/support/env_windows.cc",
-        "src/core/lib/support/histogram.cc",
+        "src/core/lib/support/fork.cc",
         "src/core/lib/support/host_port.cc",
         "src/core/lib/support/log.cc",
         "src/core/lib/support/log_android.cc",
@@ -455,7 +459,6 @@
         "src/core/lib/support/log_windows.cc",
         "src/core/lib/support/mpscq.cc",
         "src/core/lib/support/murmur_hash.cc",
-        "src/core/lib/support/stack_lockfree.cc",
         "src/core/lib/support/string.cc",
         "src/core/lib/support/string_posix.cc",
         "src/core/lib/support/string_util_windows.cc",
@@ -480,28 +483,30 @@
     ],
     hdrs = [
         "src/core/lib/profiling/timers.h",
+        "src/core/lib/support/abstract.h",
         "src/core/lib/support/arena.h",
         "src/core/lib/support/atomic.h",
         "src/core/lib/support/atomic_with_atm.h",
         "src/core/lib/support/atomic_with_std.h",
         "src/core/lib/support/env.h",
-        "src/core/lib/support/memory.h",
-        "src/core/lib/support/vector.h",
+        "src/core/lib/support/fork.h",
         "src/core/lib/support/manual_constructor.h",
+        "src/core/lib/support/memory.h",
         "src/core/lib/support/mpscq.h",
         "src/core/lib/support/murmur_hash.h",
         "src/core/lib/support/spinlock.h",
-        "src/core/lib/support/stack_lockfree.h",
         "src/core/lib/support/string.h",
         "src/core/lib/support/string_windows.h",
+        "src/core/lib/support/thd_internal.h",
         "src/core/lib/support/time_precise.h",
         "src/core/lib/support/tmpfile.h",
+        "src/core/lib/support/vector.h",
     ],
     language = "c++",
     public_hdrs = GPR_PUBLIC_HDRS,
     deps = [
         "gpr_codegen",
-        "@com_google_absl//absl/container:inlined_vector"
+        "@com_google_absl//absl/container:inlined_vector",
     ],
 )
 
@@ -513,6 +518,7 @@
         "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/fork.h",
         "include/grpc/impl/codegen/gpr_slice.h",
         "include/grpc/impl/codegen/gpr_types.h",
         "include/grpc/impl/codegen/port_platform.h",
@@ -537,6 +543,28 @@
 )
 
 grpc_cc_library(
+    name = "debug_location",
+    public_hdrs = ["src/core/lib/support/debug_location.h"],
+    language = "c++",
+)
+
+grpc_cc_library(
+    name = "ref_counted",
+    public_hdrs = ["src/core/lib/support/ref_counted.h"],
+    language = "c++",
+    deps = [
+        "grpc_trace",
+        "debug_location",
+    ],
+)
+
+grpc_cc_library(
+    name = "ref_counted_ptr",
+    public_hdrs = ["src/core/lib/support/ref_counted_ptr.h"],
+    language = "c++",
+)
+
+grpc_cc_library(
     name = "grpc_base_c",
     srcs = [
         "src/core/lib/backoff/backoff.cc",
@@ -572,6 +600,8 @@
         "src/core/lib/iomgr/ev_windows.cc",
         "src/core/lib/iomgr/exec_ctx.cc",
         "src/core/lib/iomgr/executor.cc",
+        "src/core/lib/iomgr/fork_posix.cc",
+        "src/core/lib/iomgr/fork_windows.cc",
         "src/core/lib/iomgr/gethostname_fallback.cc",
         "src/core/lib/iomgr/gethostname_host_name_max.cc",
         "src/core/lib/iomgr/gethostname_sysconf.cc",
@@ -671,6 +701,7 @@
         "src/core/lib/transport/transport_op_string.cc",
     ],
     hdrs = [
+        "src/core/lib/backoff/backoff.h",
         "src/core/lib/channel/channel_args.h",
         "src/core/lib/channel/channel_stack.h",
         "src/core/lib/channel/channel_stack_builder.h",
@@ -689,6 +720,7 @@
         "src/core/lib/http/format_request.h",
         "src/core/lib/http/httpcli.h",
         "src/core/lib/http/parser.h",
+        "src/core/lib/iomgr/block_annotate.h",
         "src/core/lib/iomgr/call_combiner.h",
         "src/core/lib/iomgr/closure.h",
         "src/core/lib/iomgr/combiner.h",
@@ -733,7 +765,6 @@
         "src/core/lib/iomgr/socket_utils_posix.h",
         "src/core/lib/iomgr/socket_windows.h",
         "src/core/lib/iomgr/sys_epoll_wrapper.h",
-        "src/core/lib/iomgr/block_annotate.h",
         "src/core/lib/iomgr/tcp_client.h",
         "src/core/lib/iomgr/tcp_client_posix.h",
         "src/core/lib/iomgr/tcp_posix.h",
@@ -789,7 +820,6 @@
         "src/core/lib/transport/timeout_encoding.h",
         "src/core/lib/transport/transport.h",
         "src/core/lib/transport/transport_impl.h",
-        "src/core/lib/backoff/backoff.h",
     ],
     external_deps = [
         "zlib",
@@ -1249,8 +1279,8 @@
         "src/core/ext/transport/chttp2/transport/bin_decoder.h",
         "src/core/ext/transport/chttp2/transport/bin_encoder.h",
         "src/core/ext/transport/chttp2/transport/chttp2_transport.h",
-        "src/core/ext/transport/chttp2/transport/frame.h",
         "src/core/ext/transport/chttp2/transport/flow_control.h",
+        "src/core/ext/transport/chttp2/transport/frame.h",
         "src/core/ext/transport/chttp2/transport/frame_data.h",
         "src/core/ext/transport/chttp2/transport/frame_goaway.h",
         "src/core/ext/transport/chttp2/transport/frame_ping.h",
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 12e143c..297301b 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -24,7 +24,7 @@
 cmake_minimum_required(VERSION 2.8)
 
 set(PACKAGE_NAME      "grpc")
-set(PACKAGE_VERSION   "1.8.0-dev")
+set(PACKAGE_VERSION   "1.9.0-dev")
 set(PACKAGE_STRING    "${PACKAGE_NAME} ${PACKAGE_VERSION}")
 set(PACKAGE_TARNAME   "${PACKAGE_NAME}-${PACKAGE_VERSION}")
 set(PACKAGE_BUGREPORT "https://github.com/grpc/grpc/issues/")
@@ -235,6 +235,7 @@
 elseif("${gRPC_SSL_PROVIDER}" STREQUAL "package")
   find_package(OpenSSL REQUIRED)
   set(_gRPC_SSL_LIBRARIES ${OPENSSL_LIBRARIES})
+  include_directories(${OPENSSL_INCLUDE_DIR})
   set(_gRPC_FIND_SSL "if(NOT OPENSSL_FOUND)\n  find_package(OpenSSL)\nendif()")
 endif()
 
@@ -427,12 +428,11 @@
 add_dependencies(buildtests_c gpr_cmdline_test)
 add_dependencies(buildtests_c gpr_cpu_test)
 add_dependencies(buildtests_c gpr_env_test)
-add_dependencies(buildtests_c gpr_histogram_test)
 add_dependencies(buildtests_c gpr_host_port_test)
 add_dependencies(buildtests_c gpr_log_test)
+add_dependencies(buildtests_c gpr_manual_constructor_test)
 add_dependencies(buildtests_c gpr_mpscq_test)
 add_dependencies(buildtests_c gpr_spinlock_test)
-add_dependencies(buildtests_c gpr_stack_lockfree_test)
 add_dependencies(buildtests_c gpr_string_test)
 add_dependencies(buildtests_c gpr_sync_test)
 add_dependencies(buildtests_c gpr_thd_test)
@@ -465,6 +465,7 @@
 if(_gRPC_PLATFORM_LINUX)
 add_dependencies(buildtests_c handshake_server_with_readahead_handshaker)
 endif()
+add_dependencies(buildtests_c histogram_test)
 add_dependencies(buildtests_c hpack_parser_test)
 add_dependencies(buildtests_c hpack_table_test)
 add_dependencies(buildtests_c http_parser_test)
@@ -738,6 +739,8 @@
 add_dependencies(buildtests_cxx qps_worker)
 add_dependencies(buildtests_cxx reconnect_interop_client)
 add_dependencies(buildtests_cxx reconnect_interop_server)
+add_dependencies(buildtests_cxx ref_counted_ptr_test)
+add_dependencies(buildtests_cxx ref_counted_test)
 add_dependencies(buildtests_cxx secure_auth_context_test)
 if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_POSIX)
 add_dependencies(buildtests_cxx secure_sync_unary_ping_pong_test)
@@ -760,7 +763,6 @@
 add_dependencies(buildtests_cxx thread_manager_test)
 add_dependencies(buildtests_cxx thread_stress_test)
 add_dependencies(buildtests_cxx transport_pid_controller_test)
-add_dependencies(buildtests_cxx vector_test)
 if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_POSIX)
 add_dependencies(buildtests_cxx writes_per_rpc_test)
 endif()
@@ -797,7 +799,7 @@
   src/core/lib/support/env_linux.cc
   src/core/lib/support/env_posix.cc
   src/core/lib/support/env_windows.cc
-  src/core/lib/support/histogram.cc
+  src/core/lib/support/fork.cc
   src/core/lib/support/host_port.cc
   src/core/lib/support/log.cc
   src/core/lib/support/log_android.cc
@@ -806,7 +808,6 @@
   src/core/lib/support/log_windows.cc
   src/core/lib/support/mpscq.cc
   src/core/lib/support/murmur_hash.cc
-  src/core/lib/support/stack_lockfree.cc
   src/core/lib/support/string.cc
   src/core/lib/support/string_posix.cc
   src/core/lib/support/string_util_windows.cc
@@ -853,7 +854,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
 )
 
 target_link_libraries(gpr
@@ -869,7 +869,6 @@
   include/grpc/support/avl.h
   include/grpc/support/cmdline.h
   include/grpc/support/cpu.h
-  include/grpc/support/histogram.h
   include/grpc/support/host_port.h
   include/grpc/support/log.h
   include/grpc/support/log_windows.h
@@ -892,6 +891,7 @@
   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/fork.h
   include/grpc/impl/codegen/gpr_slice.h
   include/grpc/impl/codegen/gpr_types.h
   include/grpc/impl/codegen/port_platform.h
@@ -946,7 +946,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
 )
 
 target_link_libraries(gpr_test_util
@@ -992,6 +991,8 @@
   src/core/lib/iomgr/ev_windows.cc
   src/core/lib/iomgr/exec_ctx.cc
   src/core/lib/iomgr/executor.cc
+  src/core/lib/iomgr/fork_posix.cc
+  src/core/lib/iomgr/fork_windows.cc
   src/core/lib/iomgr/gethostname_fallback.cc
   src/core/lib/iomgr/gethostname_host_name_max.cc
   src/core/lib/iomgr/gethostname_sysconf.cc
@@ -1232,7 +1233,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
 )
 
 target_link_libraries(grpc
@@ -1258,6 +1258,7 @@
   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/fork.h
   include/grpc/impl/codegen/gpr_slice.h
   include/grpc/impl/codegen/gpr_types.h
   include/grpc/impl/codegen/port_platform.h
@@ -1270,6 +1271,7 @@
   include/grpc/byte_buffer.h
   include/grpc/byte_buffer_reader.h
   include/grpc/compression.h
+  include/grpc/fork.h
   include/grpc/grpc.h
   include/grpc/grpc_posix.h
   include/grpc/grpc_security_constants.h
@@ -1332,6 +1334,8 @@
   src/core/lib/iomgr/ev_windows.cc
   src/core/lib/iomgr/exec_ctx.cc
   src/core/lib/iomgr/executor.cc
+  src/core/lib/iomgr/fork_posix.cc
+  src/core/lib/iomgr/fork_windows.cc
   src/core/lib/iomgr/gethostname_fallback.cc
   src/core/lib/iomgr/gethostname_host_name_max.cc
   src/core/lib/iomgr/gethostname_sysconf.cc
@@ -1543,7 +1547,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
 )
 
 target_link_libraries(grpc_cronet
@@ -1569,6 +1572,7 @@
   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/fork.h
   include/grpc/impl/codegen/gpr_slice.h
   include/grpc/impl/codegen/gpr_types.h
   include/grpc/impl/codegen/port_platform.h
@@ -1612,13 +1616,16 @@
   test/core/iomgr/endpoint_tests.cc
   test/core/util/debugger_macros.cc
   test/core/util/grpc_profiler.cc
+  test/core/util/histogram.cc
   test/core/util/memory_counters.cc
   test/core/util/mock_endpoint.cc
   test/core/util/parse_hexstring.cc
   test/core/util/passthru_endpoint.cc
   test/core/util/port.cc
+  test/core/util/port_isolated_runtime_environment.cc
   test/core/util/port_server_client.cc
   test/core/util/slice_splitter.cc
+  test/core/util/tracer_util.cc
   test/core/util/trickle_endpoint.cc
   src/core/lib/backoff/backoff.cc
   src/core/lib/channel/channel_args.cc
@@ -1653,6 +1660,8 @@
   src/core/lib/iomgr/ev_windows.cc
   src/core/lib/iomgr/exec_ctx.cc
   src/core/lib/iomgr/executor.cc
+  src/core/lib/iomgr/fork_posix.cc
+  src/core/lib/iomgr/fork_windows.cc
   src/core/lib/iomgr/gethostname_fallback.cc
   src/core/lib/iomgr/gethostname_host_name_max.cc
   src/core/lib/iomgr/gethostname_sysconf.cc
@@ -1826,7 +1835,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
 )
 
 target_link_libraries(grpc_test_util
@@ -1850,6 +1858,7 @@
   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/fork.h
   include/grpc/impl/codegen/gpr_slice.h
   include/grpc/impl/codegen/gpr_types.h
   include/grpc/impl/codegen/port_platform.h
@@ -1877,13 +1886,16 @@
   test/core/iomgr/endpoint_tests.cc
   test/core/util/debugger_macros.cc
   test/core/util/grpc_profiler.cc
+  test/core/util/histogram.cc
   test/core/util/memory_counters.cc
   test/core/util/mock_endpoint.cc
   test/core/util/parse_hexstring.cc
   test/core/util/passthru_endpoint.cc
   test/core/util/port.cc
+  test/core/util/port_isolated_runtime_environment.cc
   test/core/util/port_server_client.cc
   test/core/util/slice_splitter.cc
+  test/core/util/tracer_util.cc
   test/core/util/trickle_endpoint.cc
   src/core/lib/backoff/backoff.cc
   src/core/lib/channel/channel_args.cc
@@ -1918,6 +1930,8 @@
   src/core/lib/iomgr/ev_windows.cc
   src/core/lib/iomgr/exec_ctx.cc
   src/core/lib/iomgr/executor.cc
+  src/core/lib/iomgr/fork_posix.cc
+  src/core/lib/iomgr/fork_windows.cc
   src/core/lib/iomgr/gethostname_fallback.cc
   src/core/lib/iomgr/gethostname_host_name_max.cc
   src/core/lib/iomgr/gethostname_sysconf.cc
@@ -2091,7 +2105,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
 )
 
 target_link_libraries(grpc_test_util_unsecure
@@ -2115,6 +2128,7 @@
   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/fork.h
   include/grpc/impl/codegen/gpr_slice.h
   include/grpc/impl/codegen/gpr_types.h
   include/grpc/impl/codegen/port_platform.h
@@ -2169,6 +2183,8 @@
   src/core/lib/iomgr/ev_windows.cc
   src/core/lib/iomgr/exec_ctx.cc
   src/core/lib/iomgr/executor.cc
+  src/core/lib/iomgr/fork_posix.cc
+  src/core/lib/iomgr/fork_windows.cc
   src/core/lib/iomgr/gethostname_fallback.cc
   src/core/lib/iomgr/gethostname_host_name_max.cc
   src/core/lib/iomgr/gethostname_sysconf.cc
@@ -2377,7 +2393,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
 )
 
 target_link_libraries(grpc_unsecure
@@ -2402,6 +2417,7 @@
   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/fork.h
   include/grpc/impl/codegen/gpr_slice.h
   include/grpc/impl/codegen/gpr_types.h
   include/grpc/impl/codegen/port_platform.h
@@ -2413,6 +2429,7 @@
   include/grpc/byte_buffer.h
   include/grpc/byte_buffer_reader.h
   include/grpc/compression.h
+  include/grpc/fork.h
   include/grpc/grpc.h
   include/grpc/grpc_posix.h
   include/grpc/grpc_security_constants.h
@@ -2468,7 +2485,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
 )
 
 target_link_libraries(reconnect_server
@@ -2511,7 +2527,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
 )
 
 target_link_libraries(test_tcp_server
@@ -2593,7 +2608,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
   PRIVATE ${_gRPC_PROTO_GENS_DIR}
 )
 
@@ -2660,7 +2674,6 @@
   include/grpc/support/avl.h
   include/grpc/support/cmdline.h
   include/grpc/support/cpu.h
-  include/grpc/support/histogram.h
   include/grpc/support/host_port.h
   include/grpc/support/log.h
   include/grpc/support/log_windows.h
@@ -2683,6 +2696,7 @@
   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/fork.h
   include/grpc/impl/codegen/gpr_slice.h
   include/grpc/impl/codegen/gpr_types.h
   include/grpc/impl/codegen/port_platform.h
@@ -2694,6 +2708,7 @@
   include/grpc/byte_buffer.h
   include/grpc/byte_buffer_reader.h
   include/grpc/compression.h
+  include/grpc/fork.h
   include/grpc/grpc.h
   include/grpc/grpc_posix.h
   include/grpc/grpc_security_constants.h
@@ -2796,7 +2811,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
   PRIVATE third_party/googletest/googletest/include
   PRIVATE third_party/googletest/googletest
   PRIVATE third_party/googletest/googlemock/include
@@ -2919,6 +2933,8 @@
   src/core/lib/iomgr/ev_windows.cc
   src/core/lib/iomgr/exec_ctx.cc
   src/core/lib/iomgr/executor.cc
+  src/core/lib/iomgr/fork_posix.cc
+  src/core/lib/iomgr/fork_windows.cc
   src/core/lib/iomgr/gethostname_fallback.cc
   src/core/lib/iomgr/gethostname_host_name_max.cc
   src/core/lib/iomgr/gethostname_sysconf.cc
@@ -3077,7 +3093,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
   PRIVATE ${_gRPC_PROTO_GENS_DIR}
 )
 
@@ -3145,7 +3160,6 @@
   include/grpc/support/avl.h
   include/grpc/support/cmdline.h
   include/grpc/support/cpu.h
-  include/grpc/support/histogram.h
   include/grpc/support/host_port.h
   include/grpc/support/log.h
   include/grpc/support/log_windows.h
@@ -3168,6 +3182,7 @@
   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/fork.h
   include/grpc/impl/codegen/gpr_slice.h
   include/grpc/impl/codegen/gpr_types.h
   include/grpc/impl/codegen/port_platform.h
@@ -3179,6 +3194,7 @@
   include/grpc/byte_buffer.h
   include/grpc/byte_buffer_reader.h
   include/grpc/compression.h
+  include/grpc/fork.h
   include/grpc/grpc.h
   include/grpc/grpc_posix.h
   include/grpc/grpc_security_constants.h
@@ -3279,7 +3295,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
   PRIVATE ${_gRPC_PROTO_GENS_DIR}
 )
 
@@ -3345,7 +3360,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
   PRIVATE third_party/googletest/googletest/include
   PRIVATE third_party/googletest/googletest
   PRIVATE third_party/googletest/googlemock/include
@@ -3407,7 +3421,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
   PRIVATE ${_gRPC_PROTO_GENS_DIR}
 )
 
@@ -3466,7 +3479,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
   PRIVATE third_party/googletest/googletest/include
   PRIVATE third_party/googletest/googletest
   PRIVATE third_party/googletest/googlemock/include
@@ -3545,7 +3557,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
   PRIVATE third_party/googletest/googletest/include
   PRIVATE third_party/googletest/googletest
   PRIVATE third_party/googletest/googlemock/include
@@ -3605,6 +3616,7 @@
   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/fork.h
   include/grpc/impl/codegen/gpr_slice.h
   include/grpc/impl/codegen/gpr_types.h
   include/grpc/impl/codegen/port_platform.h
@@ -3686,7 +3698,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
   PRIVATE third_party/googletest/googletest/include
   PRIVATE third_party/googletest/googletest
   PRIVATE third_party/googletest/googlemock/include
@@ -3746,6 +3757,7 @@
   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/fork.h
   include/grpc/impl/codegen/gpr_slice.h
   include/grpc/impl/codegen/gpr_types.h
   include/grpc/impl/codegen/port_platform.h
@@ -3829,7 +3841,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
   PRIVATE ${_gRPC_PROTO_GENS_DIR}
 )
 
@@ -3895,7 +3906,6 @@
   include/grpc/support/avl.h
   include/grpc/support/cmdline.h
   include/grpc/support/cpu.h
-  include/grpc/support/histogram.h
   include/grpc/support/host_port.h
   include/grpc/support/log.h
   include/grpc/support/log_windows.h
@@ -3918,6 +3928,7 @@
   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/fork.h
   include/grpc/impl/codegen/gpr_slice.h
   include/grpc/impl/codegen/gpr_types.h
   include/grpc/impl/codegen/port_platform.h
@@ -3929,6 +3940,7 @@
   include/grpc/byte_buffer.h
   include/grpc/byte_buffer_reader.h
   include/grpc/compression.h
+  include/grpc/fork.h
   include/grpc/grpc.h
   include/grpc/grpc_posix.h
   include/grpc/grpc_security_constants.h
@@ -4022,7 +4034,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
   PRIVATE third_party/googletest/googletest/include
   PRIVATE third_party/googletest/googletest
   PRIVATE third_party/googletest/googlemock/include
@@ -4082,7 +4093,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
   PRIVATE third_party/googletest/googletest/include
   PRIVATE third_party/googletest/googletest
   PRIVATE third_party/googletest/googlemock/include
@@ -4143,7 +4153,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
   PRIVATE ${_gRPC_PROTO_GENS_DIR}
 )
 
@@ -4222,7 +4231,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
   PRIVATE third_party/googletest/googletest/include
   PRIVATE third_party/googletest/googletest
   PRIVATE third_party/googletest/googlemock/include
@@ -4278,7 +4286,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
   PRIVATE third_party/googletest/googletest/include
   PRIVATE third_party/googletest/googletest
   PRIVATE third_party/googletest/googlemock/include
@@ -4349,7 +4356,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
   PRIVATE third_party/googletest/googletest/include
   PRIVATE third_party/googletest/googletest
   PRIVATE third_party/googletest/googlemock/include
@@ -4401,7 +4407,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
   PRIVATE third_party/googletest/googletest/include
   PRIVATE third_party/googletest/googletest
   PRIVATE third_party/googletest/googlemock/include
@@ -4471,7 +4476,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
   PRIVATE third_party/googletest/googletest/include
   PRIVATE third_party/googletest/googletest
   PRIVATE third_party/googletest/googlemock/include
@@ -4523,7 +4527,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
   PRIVATE third_party/googletest/googletest/include
   PRIVATE third_party/googletest/googletest
   PRIVATE third_party/googletest/googlemock/include
@@ -4612,7 +4615,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
   PRIVATE third_party/googletest/googletest/include
   PRIVATE third_party/googletest/googletest
   PRIVATE third_party/googletest/googlemock/include
@@ -4660,7 +4662,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
 )
 
 target_link_libraries(grpc_csharp_ext
@@ -4756,7 +4757,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
 )
 
 target_link_libraries(ares
@@ -4795,7 +4795,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
 )
 
 target_link_libraries(bad_client_test
@@ -4837,7 +4836,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
 )
 
 target_link_libraries(bad_ssl_test_server
@@ -4939,7 +4937,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
 )
 
 target_link_libraries(end2end_tests
@@ -5041,7 +5038,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
 )
 
 target_link_libraries(end2end_nosec_tests
@@ -5073,7 +5069,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
 )
 
 target_link_libraries(alarm_test
@@ -5103,7 +5098,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
 )
 
 target_link_libraries(algorithm_test
@@ -5133,7 +5127,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
 )
 
 target_link_libraries(alloc_test
@@ -5161,7 +5154,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
 )
 
 target_link_libraries(alpn_test
@@ -5191,7 +5183,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
 )
 
 target_link_libraries(arena_test
@@ -5219,7 +5210,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
 )
 
 target_link_libraries(backoff_test
@@ -5249,7 +5239,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
 )
 
 target_link_libraries(bad_server_response_test
@@ -5280,7 +5269,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
 )
 
 target_link_libraries(bin_decoder_test
@@ -5308,7 +5296,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
 )
 
 target_link_libraries(bin_encoder_test
@@ -5336,7 +5323,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
 )
 
 target_link_libraries(byte_stream_test
@@ -5366,7 +5352,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
 )
 
 target_link_libraries(channel_create_test
@@ -5395,7 +5380,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
 )
 
 target_link_libraries(check_epollexclusive
@@ -5431,7 +5415,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
 )
 
 target_link_libraries(chttp2_hpack_encoder_test
@@ -5461,7 +5444,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
 )
 
 target_link_libraries(chttp2_stream_map_test
@@ -5491,7 +5473,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
 )
 
 target_link_libraries(chttp2_varint_test
@@ -5521,7 +5502,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
 )
 
 target_link_libraries(combiner_test
@@ -5551,7 +5531,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
 )
 
 target_link_libraries(compression_test
@@ -5581,7 +5560,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
 )
 
 target_link_libraries(concurrent_connectivity_test
@@ -5611,7 +5589,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
 )
 
 target_link_libraries(connection_refused_test
@@ -5641,7 +5618,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
 )
 
 target_link_libraries(dns_resolver_connectivity_test
@@ -5671,7 +5647,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
 )
 
 target_link_libraries(dns_resolver_test
@@ -5702,7 +5677,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
 )
 
 target_link_libraries(dualstack_socket_test
@@ -5733,7 +5707,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
 )
 
 target_link_libraries(endpoint_pair_test
@@ -5763,7 +5736,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
 )
 
 target_link_libraries(error_test
@@ -5794,7 +5766,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
 )
 
 target_link_libraries(ev_epollsig_linux_test
@@ -5825,7 +5796,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
 )
 
 target_link_libraries(fake_resolver_test
@@ -5857,7 +5827,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
 )
 
 target_link_libraries(fake_transport_security_test
@@ -5888,7 +5857,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
 )
 
 target_link_libraries(fd_conservation_posix_test
@@ -5920,7 +5888,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
 )
 
 target_link_libraries(fd_posix_test
@@ -5951,7 +5918,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
 )
 
 target_link_libraries(fling_client
@@ -5981,7 +5947,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
 )
 
 target_link_libraries(fling_server
@@ -6012,7 +5977,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
 )
 
 target_link_libraries(fling_stream_test
@@ -6044,7 +6008,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
 )
 
 target_link_libraries(fling_test
@@ -6074,7 +6037,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
 )
 
 target_link_libraries(gen_hpack_tables
@@ -6109,7 +6071,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
 )
 
 target_link_libraries(gen_legal_metadata_characters
@@ -6142,7 +6103,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
 )
 
 target_link_libraries(gen_percent_encoding_tables
@@ -6177,7 +6137,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
 )
 
 target_link_libraries(goaway_server_test
@@ -6208,7 +6167,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
 )
 
 target_link_libraries(gpr_avl_test
@@ -6236,7 +6194,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
 )
 
 target_link_libraries(gpr_cmdline_test
@@ -6264,7 +6221,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
 )
 
 target_link_libraries(gpr_cpu_test
@@ -6292,7 +6248,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
 )
 
 target_link_libraries(gpr_env_test
@@ -6304,34 +6259,6 @@
 endif (gRPC_BUILD_TESTS)
 if (gRPC_BUILD_TESTS)
 
-add_executable(gpr_histogram_test
-  test/core/support/histogram_test.cc
-)
-
-
-target_include_directories(gpr_histogram_test
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/include
-  PRIVATE ${BORINGSSL_ROOT_DIR}/include
-  PRIVATE ${PROTOBUF_ROOT_DIR}/src
-  PRIVATE ${BENCHMARK_ROOT_DIR}/include
-  PRIVATE ${ZLIB_ROOT_DIR}
-  PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/zlib
-  PRIVATE ${CARES_INCLUDE_DIR}
-  PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
-  PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
-)
-
-target_link_libraries(gpr_histogram_test
-  ${_gRPC_ALLTARGETS_LIBRARIES}
-  gpr_test_util
-  gpr
-)
-
-endif (gRPC_BUILD_TESTS)
-if (gRPC_BUILD_TESTS)
-
 add_executable(gpr_host_port_test
   test/core/support/host_port_test.cc
 )
@@ -6348,7 +6275,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
 )
 
 target_link_libraries(gpr_host_port_test
@@ -6376,7 +6302,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
 )
 
 target_link_libraries(gpr_log_test
@@ -6388,6 +6313,33 @@
 endif (gRPC_BUILD_TESTS)
 if (gRPC_BUILD_TESTS)
 
+add_executable(gpr_manual_constructor_test
+  test/core/support/manual_constructor_test.cc
+)
+
+
+target_include_directories(gpr_manual_constructor_test
+  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}
+  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/include
+  PRIVATE ${BORINGSSL_ROOT_DIR}/include
+  PRIVATE ${PROTOBUF_ROOT_DIR}/src
+  PRIVATE ${BENCHMARK_ROOT_DIR}/include
+  PRIVATE ${ZLIB_ROOT_DIR}
+  PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/zlib
+  PRIVATE ${CARES_INCLUDE_DIR}
+  PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
+  PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
+)
+
+target_link_libraries(gpr_manual_constructor_test
+  ${_gRPC_ALLTARGETS_LIBRARIES}
+  gpr_test_util
+  gpr
+)
+
+endif (gRPC_BUILD_TESTS)
+if (gRPC_BUILD_TESTS)
+
 add_executable(gpr_mpscq_test
   test/core/support/mpscq_test.cc
 )
@@ -6404,7 +6356,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
 )
 
 target_link_libraries(gpr_mpscq_test
@@ -6432,7 +6383,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
 )
 
 target_link_libraries(gpr_spinlock_test
@@ -6444,34 +6394,6 @@
 endif (gRPC_BUILD_TESTS)
 if (gRPC_BUILD_TESTS)
 
-add_executable(gpr_stack_lockfree_test
-  test/core/support/stack_lockfree_test.cc
-)
-
-
-target_include_directories(gpr_stack_lockfree_test
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/include
-  PRIVATE ${BORINGSSL_ROOT_DIR}/include
-  PRIVATE ${PROTOBUF_ROOT_DIR}/src
-  PRIVATE ${BENCHMARK_ROOT_DIR}/include
-  PRIVATE ${ZLIB_ROOT_DIR}
-  PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/zlib
-  PRIVATE ${CARES_INCLUDE_DIR}
-  PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
-  PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
-)
-
-target_link_libraries(gpr_stack_lockfree_test
-  ${_gRPC_ALLTARGETS_LIBRARIES}
-  gpr_test_util
-  gpr
-)
-
-endif (gRPC_BUILD_TESTS)
-if (gRPC_BUILD_TESTS)
-
 add_executable(gpr_string_test
   test/core/support/string_test.cc
 )
@@ -6488,7 +6410,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
 )
 
 target_link_libraries(gpr_string_test
@@ -6516,7 +6437,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
 )
 
 target_link_libraries(gpr_sync_test
@@ -6544,7 +6464,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
 )
 
 target_link_libraries(gpr_thd_test
@@ -6572,7 +6491,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
 )
 
 target_link_libraries(gpr_time_test
@@ -6600,7 +6518,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
 )
 
 target_link_libraries(gpr_tls_test
@@ -6628,7 +6545,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
 )
 
 target_link_libraries(gpr_useful_test
@@ -6656,7 +6572,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
 )
 
 target_link_libraries(grpc_auth_context_test
@@ -6686,7 +6601,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
 )
 
 target_link_libraries(grpc_b64_test
@@ -6716,7 +6630,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
 )
 
 target_link_libraries(grpc_byte_buffer_reader_test
@@ -6746,7 +6659,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
 )
 
 target_link_libraries(grpc_channel_args_test
@@ -6776,7 +6688,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
 )
 
 target_link_libraries(grpc_channel_stack_builder_test
@@ -6806,7 +6717,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
 )
 
 target_link_libraries(grpc_channel_stack_test
@@ -6836,7 +6746,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
 )
 
 target_link_libraries(grpc_completion_queue_test
@@ -6866,7 +6775,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
 )
 
 target_link_libraries(grpc_completion_queue_threading_test
@@ -6895,7 +6803,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
 )
 
 target_link_libraries(grpc_create_jwt
@@ -6932,7 +6839,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
 )
 
 target_link_libraries(grpc_credentials_test
@@ -6962,7 +6868,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
 )
 
 target_link_libraries(grpc_fetch_oauth2
@@ -6992,7 +6897,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
 )
 
 target_link_libraries(grpc_invalid_channel_args_test
@@ -7023,7 +6927,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
 )
 
 target_link_libraries(grpc_json_token_test
@@ -7054,7 +6957,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
 )
 
 target_link_libraries(grpc_jwt_verifier_test
@@ -7083,7 +6985,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
 )
 
 target_link_libraries(grpc_print_google_default_creds_token
@@ -7119,7 +7020,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
 )
 
 target_link_libraries(grpc_security_connector_test
@@ -7149,7 +7049,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
 )
 
 target_link_libraries(grpc_ssl_credentials_test
@@ -7178,7 +7077,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
 )
 
 target_link_libraries(grpc_verify_jwt
@@ -7215,7 +7113,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
 )
 
 target_link_libraries(handshake_client
@@ -7249,7 +7146,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
 )
 
 target_link_libraries(handshake_server
@@ -7283,7 +7179,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
 )
 
 target_link_libraries(handshake_server_with_readahead_handshaker
@@ -7299,6 +7194,33 @@
 endif (gRPC_BUILD_TESTS)
 if (gRPC_BUILD_TESTS)
 
+add_executable(histogram_test
+  test/core/util/histogram_test.cc
+)
+
+
+target_include_directories(histogram_test
+  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}
+  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/include
+  PRIVATE ${BORINGSSL_ROOT_DIR}/include
+  PRIVATE ${PROTOBUF_ROOT_DIR}/src
+  PRIVATE ${BENCHMARK_ROOT_DIR}/include
+  PRIVATE ${ZLIB_ROOT_DIR}
+  PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/zlib
+  PRIVATE ${CARES_INCLUDE_DIR}
+  PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
+  PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
+)
+
+target_link_libraries(histogram_test
+  ${_gRPC_ALLTARGETS_LIBRARIES}
+  grpc_test_util
+  gpr
+)
+
+endif (gRPC_BUILD_TESTS)
+if (gRPC_BUILD_TESTS)
+
 add_executable(hpack_parser_test
   test/core/transport/chttp2/hpack_parser_test.cc
 )
@@ -7315,7 +7237,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
 )
 
 target_link_libraries(hpack_parser_test
@@ -7345,7 +7266,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
 )
 
 target_link_libraries(hpack_table_test
@@ -7375,7 +7295,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
 )
 
 target_link_libraries(http_parser_test
@@ -7405,7 +7324,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
 )
 
 target_link_libraries(httpcli_format_request_test
@@ -7436,7 +7354,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
 )
 
 target_link_libraries(httpcli_test
@@ -7468,7 +7385,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
 )
 
 target_link_libraries(httpscli_test
@@ -7499,7 +7415,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
 )
 
 target_link_libraries(init_test
@@ -7529,7 +7444,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
 )
 
 target_link_libraries(invalid_call_argument_test
@@ -7559,7 +7473,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
 )
 
 target_link_libraries(json_rewrite
@@ -7587,7 +7500,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
 )
 
 target_link_libraries(json_rewrite_test
@@ -7617,7 +7529,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
 )
 
 target_link_libraries(json_stream_error_test
@@ -7647,7 +7558,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
 )
 
 target_link_libraries(json_test
@@ -7677,7 +7587,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
 )
 
 target_link_libraries(lame_client_test
@@ -7707,7 +7616,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
 )
 
 target_link_libraries(lb_policies_test
@@ -7737,7 +7645,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
 )
 
 target_link_libraries(load_file_test
@@ -7767,7 +7674,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
 )
 
 target_link_libraries(memory_profile_client
@@ -7797,7 +7703,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
 )
 
 target_link_libraries(memory_profile_server
@@ -7828,7 +7733,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
 )
 
 target_link_libraries(memory_profile_test
@@ -7859,7 +7763,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
 )
 
 target_link_libraries(message_compress_test
@@ -7889,7 +7792,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
 )
 
 target_link_libraries(minimal_stack_is_minimal_test
@@ -7919,7 +7821,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
 )
 
 target_link_libraries(multiple_server_queues_test
@@ -7949,7 +7850,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
 )
 
 target_link_libraries(murmur_hash_test
@@ -7977,7 +7877,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
 )
 
 target_link_libraries(no_server_test
@@ -8007,7 +7906,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
 )
 
 target_link_libraries(num_external_connectivity_watchers_test
@@ -8037,7 +7935,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
 )
 
 target_link_libraries(parse_address_test
@@ -8067,7 +7964,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
 )
 
 target_link_libraries(percent_encoding_test
@@ -8098,7 +7994,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
 )
 
 target_link_libraries(pollset_set_test
@@ -8130,7 +8025,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
 )
 
 target_link_libraries(resolve_address_posix_test
@@ -8161,7 +8055,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
 )
 
 target_link_libraries(resolve_address_test
@@ -8191,7 +8084,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
 )
 
 target_link_libraries(resource_quota_test
@@ -8221,7 +8113,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
 )
 
 target_link_libraries(secure_channel_create_test
@@ -8251,7 +8142,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
 )
 
 target_link_libraries(secure_endpoint_test
@@ -8281,7 +8171,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
 )
 
 target_link_libraries(sequential_connectivity_test
@@ -8311,7 +8200,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
 )
 
 target_link_libraries(server_chttp2_test
@@ -8341,7 +8229,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
 )
 
 target_link_libraries(server_test
@@ -8371,7 +8258,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
 )
 
 target_link_libraries(slice_buffer_test
@@ -8401,7 +8287,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
 )
 
 target_link_libraries(slice_hash_table_test
@@ -8431,7 +8316,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
 )
 
 target_link_libraries(slice_string_helpers_test
@@ -8461,7 +8345,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
 )
 
 target_link_libraries(slice_test
@@ -8491,7 +8374,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
 )
 
 target_link_libraries(sockaddr_resolver_test
@@ -8521,7 +8403,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
 )
 
 target_link_libraries(sockaddr_utils_test
@@ -8552,7 +8433,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
 )
 
 target_link_libraries(socket_utils_test
@@ -8585,7 +8465,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
 )
 
 target_link_libraries(ssl_transport_security_test
@@ -8615,7 +8494,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
 )
 
 target_link_libraries(status_conversion_test
@@ -8645,7 +8523,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
 )
 
 target_link_libraries(stream_compression_test
@@ -8675,7 +8552,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
 )
 
 target_link_libraries(stream_owned_slice_test
@@ -8706,7 +8582,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
 )
 
 target_link_libraries(tcp_client_posix_test
@@ -8737,7 +8612,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
 )
 
 target_link_libraries(tcp_client_uv_test
@@ -8768,7 +8642,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
 )
 
 target_link_libraries(tcp_posix_test
@@ -8800,7 +8673,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
 )
 
 target_link_libraries(tcp_server_posix_test
@@ -8831,7 +8703,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
 )
 
 target_link_libraries(tcp_server_uv_test
@@ -8861,7 +8732,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
 )
 
 target_link_libraries(time_averaged_stats_test
@@ -8891,7 +8761,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
 )
 
 target_link_libraries(timeout_encoding_test
@@ -8921,7 +8790,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
 )
 
 target_link_libraries(timer_heap_test
@@ -8951,7 +8819,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
 )
 
 target_link_libraries(timer_list_test
@@ -8981,7 +8848,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
 )
 
 target_link_libraries(transport_connectivity_state_test
@@ -9011,7 +8877,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
 )
 
 target_link_libraries(transport_metadata_test
@@ -9042,7 +8907,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
 )
 
 target_link_libraries(transport_security_test
@@ -9074,7 +8938,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
 )
 
 target_link_libraries(udp_server_test
@@ -9105,7 +8968,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
 )
 
 target_link_libraries(uri_parser_test
@@ -9136,7 +8998,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
 )
 
 target_link_libraries(wakeup_fd_cv_test
@@ -9169,7 +9030,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
   PRIVATE third_party/googletest/googletest/include
   PRIVATE third_party/googletest/googletest
   PRIVATE third_party/googletest/googlemock/include
@@ -9210,7 +9070,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
   PRIVATE third_party/googletest/googletest/include
   PRIVATE third_party/googletest/googletest
   PRIVATE third_party/googletest/googlemock/include
@@ -9251,7 +9110,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
   PRIVATE third_party/googletest/googletest/include
   PRIVATE third_party/googletest/googletest
   PRIVATE third_party/googletest/googlemock/include
@@ -9292,7 +9150,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
   PRIVATE third_party/googletest/googletest/include
   PRIVATE third_party/googletest/googletest
   PRIVATE third_party/googletest/googlemock/include
@@ -9334,7 +9191,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
   PRIVATE third_party/googletest/googletest/include
   PRIVATE third_party/googletest/googletest
   PRIVATE third_party/googletest/googlemock/include
@@ -9379,7 +9235,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
   PRIVATE third_party/googletest/googletest/include
   PRIVATE third_party/googletest/googletest
   PRIVATE third_party/googletest/googlemock/include
@@ -9424,7 +9279,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
   PRIVATE third_party/googletest/googletest/include
   PRIVATE third_party/googletest/googletest
   PRIVATE third_party/googletest/googlemock/include
@@ -9469,7 +9323,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
   PRIVATE third_party/googletest/googletest/include
   PRIVATE third_party/googletest/googletest
   PRIVATE third_party/googletest/googlemock/include
@@ -9514,7 +9367,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
   PRIVATE third_party/googletest/googletest/include
   PRIVATE third_party/googletest/googletest
   PRIVATE third_party/googletest/googlemock/include
@@ -9559,7 +9411,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
   PRIVATE third_party/googletest/googletest/include
   PRIVATE third_party/googletest/googletest
   PRIVATE third_party/googletest/googlemock/include
@@ -9604,7 +9455,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
   PRIVATE third_party/googletest/googletest/include
   PRIVATE third_party/googletest/googletest
   PRIVATE third_party/googletest/googlemock/include
@@ -9649,7 +9499,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
   PRIVATE third_party/googletest/googletest/include
   PRIVATE third_party/googletest/googletest
   PRIVATE third_party/googletest/googlemock/include
@@ -9694,7 +9543,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
   PRIVATE third_party/googletest/googletest/include
   PRIVATE third_party/googletest/googletest
   PRIVATE third_party/googletest/googlemock/include
@@ -9739,7 +9587,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
   PRIVATE third_party/googletest/googletest/include
   PRIVATE third_party/googletest/googletest
   PRIVATE third_party/googletest/googlemock/include
@@ -9784,7 +9631,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
   PRIVATE third_party/googletest/googletest/include
   PRIVATE third_party/googletest/googletest
   PRIVATE third_party/googletest/googlemock/include
@@ -9830,7 +9676,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
   PRIVATE third_party/googletest/googletest/include
   PRIVATE third_party/googletest/googletest
   PRIVATE third_party/googletest/googlemock/include
@@ -9875,7 +9720,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
   PRIVATE third_party/googletest/googletest/include
   PRIVATE third_party/googletest/googletest
   PRIVATE third_party/googletest/googlemock/include
@@ -9920,7 +9764,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
   PRIVATE third_party/googletest/googletest/include
   PRIVATE third_party/googletest/googletest
   PRIVATE third_party/googletest/googlemock/include
@@ -9964,7 +9807,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
   PRIVATE third_party/googletest/googletest/include
   PRIVATE third_party/googletest/googletest
   PRIVATE third_party/googletest/googlemock/include
@@ -10002,7 +9844,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
   PRIVATE third_party/googletest/googletest/include
   PRIVATE third_party/googletest/googletest
   PRIVATE third_party/googletest/googlemock/include
@@ -10040,7 +9881,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
   PRIVATE third_party/googletest/googletest/include
   PRIVATE third_party/googletest/googletest
   PRIVATE third_party/googletest/googlemock/include
@@ -10089,7 +9929,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
   PRIVATE third_party/googletest/googletest/include
   PRIVATE third_party/googletest/googletest
   PRIVATE third_party/googletest/googlemock/include
@@ -10131,7 +9970,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
   PRIVATE third_party/googletest/googletest/include
   PRIVATE third_party/googletest/googletest
   PRIVATE third_party/googletest/googlemock/include
@@ -10173,7 +10011,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
   PRIVATE third_party/googletest/googletest/include
   PRIVATE third_party/googletest/googletest
   PRIVATE third_party/googletest/googlemock/include
@@ -10214,7 +10051,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
   PRIVATE third_party/googletest/googletest/include
   PRIVATE third_party/googletest/googletest
   PRIVATE third_party/googletest/googlemock/include
@@ -10290,7 +10126,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
   PRIVATE third_party/googletest/googletest/include
   PRIVATE third_party/googletest/googletest
   PRIVATE third_party/googletest/googlemock/include
@@ -10365,7 +10200,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
   PRIVATE third_party/googletest/googletest/include
   PRIVATE third_party/googletest/googletest
   PRIVATE third_party/googletest/googlemock/include
@@ -10403,7 +10237,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
   PRIVATE third_party/googletest/googletest/include
   PRIVATE third_party/googletest/googletest
   PRIVATE third_party/googletest/googlemock/include
@@ -10441,7 +10274,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
   PRIVATE third_party/googletest/googletest/include
   PRIVATE third_party/googletest/googletest
   PRIVATE third_party/googletest/googlemock/include
@@ -10481,7 +10313,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
   PRIVATE third_party/googletest/googletest/include
   PRIVATE third_party/googletest/googletest
   PRIVATE third_party/googletest/googlemock/include
@@ -10521,7 +10352,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
   PRIVATE third_party/googletest/googletest/include
   PRIVATE third_party/googletest/googletest
   PRIVATE third_party/googletest/googlemock/include
@@ -10558,7 +10388,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
   PRIVATE third_party/googletest/googletest/include
   PRIVATE third_party/googletest/googletest
   PRIVATE third_party/googletest/googlemock/include
@@ -10598,7 +10427,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
   PRIVATE third_party/googletest/googletest/include
   PRIVATE third_party/googletest/googletest
   PRIVATE third_party/googletest/googlemock/include
@@ -10646,7 +10474,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
   PRIVATE third_party/googletest/googletest/include
   PRIVATE third_party/googletest/googletest
   PRIVATE third_party/googletest/googlemock/include
@@ -10683,7 +10510,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
   PRIVATE third_party/googletest/googletest/include
   PRIVATE third_party/googletest/googletest
   PRIVATE third_party/googletest/googlemock/include
@@ -10724,7 +10550,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
   PRIVATE third_party/googletest/googletest/include
   PRIVATE third_party/googletest/googletest
   PRIVATE third_party/googletest/googlemock/include
@@ -10772,7 +10597,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
   PRIVATE third_party/googletest/googletest/include
   PRIVATE third_party/googletest/googletest
   PRIVATE third_party/googletest/googlemock/include
@@ -10810,7 +10634,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
   PRIVATE third_party/googletest/googletest/include
   PRIVATE third_party/googletest/googletest
   PRIVATE third_party/googletest/googlemock/include
@@ -10848,7 +10671,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
   PRIVATE ${_gRPC_PROTO_GENS_DIR}
 )
 
@@ -10885,7 +10707,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
   PRIVATE ${_gRPC_PROTO_GENS_DIR}
 )
 
@@ -10922,7 +10743,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
   PRIVATE ${_gRPC_PROTO_GENS_DIR}
 )
 
@@ -10959,7 +10779,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
   PRIVATE ${_gRPC_PROTO_GENS_DIR}
 )
 
@@ -10996,7 +10815,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
   PRIVATE ${_gRPC_PROTO_GENS_DIR}
 )
 
@@ -11033,7 +10851,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
   PRIVATE ${_gRPC_PROTO_GENS_DIR}
 )
 
@@ -11070,7 +10887,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
   PRIVATE ${_gRPC_PROTO_GENS_DIR}
 )
 
@@ -11124,7 +10940,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
   PRIVATE third_party/googletest/googletest/include
   PRIVATE third_party/googletest/googletest
   PRIVATE third_party/googletest/googlemock/include
@@ -11175,7 +10990,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
   PRIVATE third_party/googletest/googletest/include
   PRIVATE third_party/googletest/googletest
   PRIVATE third_party/googletest/googlemock/include
@@ -11221,7 +11035,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
   PRIVATE third_party/googletest/googletest/include
   PRIVATE third_party/googletest/googletest
   PRIVATE third_party/googletest/googlemock/include
@@ -11269,7 +11082,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
   PRIVATE third_party/googletest/googletest/include
   PRIVATE third_party/googletest/googletest
   PRIVATE third_party/googletest/googlemock/include
@@ -11310,7 +11122,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
   PRIVATE third_party/googletest/googletest/include
   PRIVATE third_party/googletest/googletest
   PRIVATE third_party/googletest/googlemock/include
@@ -11350,7 +11161,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
   PRIVATE third_party/googletest/googletest/include
   PRIVATE third_party/googletest/googletest
   PRIVATE third_party/googletest/googlemock/include
@@ -11391,7 +11201,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
   PRIVATE third_party/googletest/googletest/include
   PRIVATE third_party/googletest/googletest
   PRIVATE third_party/googletest/googlemock/include
@@ -11433,7 +11242,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
   PRIVATE third_party/googletest/googletest/include
   PRIVATE third_party/googletest/googletest
   PRIVATE third_party/googletest/googlemock/include
@@ -11475,7 +11283,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
   PRIVATE third_party/googletest/googletest/include
   PRIVATE third_party/googletest/googletest
   PRIVATE third_party/googletest/googlemock/include
@@ -11520,7 +11327,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
   PRIVATE third_party/googletest/googletest/include
   PRIVATE third_party/googletest/googletest
   PRIVATE third_party/googletest/googlemock/include
@@ -11565,7 +11371,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
   PRIVATE third_party/googletest/googletest/include
   PRIVATE third_party/googletest/googletest
   PRIVATE third_party/googletest/googlemock/include
@@ -11612,7 +11417,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
   PRIVATE third_party/googletest/googletest/include
   PRIVATE third_party/googletest/googletest
   PRIVATE third_party/googletest/googlemock/include
@@ -11654,7 +11458,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
   PRIVATE third_party/googletest/googletest/include
   PRIVATE third_party/googletest/googletest
   PRIVATE third_party/googletest/googlemock/include
@@ -11697,7 +11500,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
   PRIVATE third_party/googletest/googletest/include
   PRIVATE third_party/googletest/googletest
   PRIVATE third_party/googletest/googlemock/include
@@ -11744,7 +11546,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
   PRIVATE third_party/googletest/googletest/include
   PRIVATE third_party/googletest/googletest
   PRIVATE third_party/googletest/googlemock/include
@@ -11783,7 +11584,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
   PRIVATE third_party/googletest/googletest/include
   PRIVATE third_party/googletest/googletest
   PRIVATE third_party/googletest/googlemock/include
@@ -11824,7 +11624,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
   PRIVATE third_party/googletest/googletest/include
   PRIVATE third_party/googletest/googletest
   PRIVATE third_party/googletest/googlemock/include
@@ -11860,7 +11659,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
   PRIVATE third_party/googletest/googletest/include
   PRIVATE third_party/googletest/googletest
   PRIVATE third_party/googletest/googlemock/include
@@ -11903,7 +11701,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
   PRIVATE third_party/googletest/googletest/include
   PRIVATE third_party/googletest/googletest
   PRIVATE third_party/googletest/googlemock/include
@@ -11941,7 +11738,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
   PRIVATE third_party/googletest/googletest/include
   PRIVATE third_party/googletest/googletest
   PRIVATE third_party/googletest/googlemock/include
@@ -11985,7 +11781,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
   PRIVATE third_party/googletest/googletest/include
   PRIVATE third_party/googletest/googletest
   PRIVATE third_party/googletest/googlemock/include
@@ -12030,7 +11825,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
   PRIVATE third_party/googletest/googletest/include
   PRIVATE third_party/googletest/googletest
   PRIVATE third_party/googletest/googlemock/include
@@ -12075,7 +11869,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
   PRIVATE third_party/googletest/googletest/include
   PRIVATE third_party/googletest/googletest
   PRIVATE third_party/googletest/googlemock/include
@@ -12140,7 +11933,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
   PRIVATE third_party/googletest/googletest/include
   PRIVATE third_party/googletest/googletest
   PRIVATE third_party/googletest/googlemock/include
@@ -12203,7 +11995,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
   PRIVATE third_party/googletest/googletest/include
   PRIVATE third_party/googletest/googletest
   PRIVATE third_party/googletest/googlemock/include
@@ -12229,6 +12020,84 @@
 endif (gRPC_BUILD_TESTS)
 if (gRPC_BUILD_TESTS)
 
+add_executable(ref_counted_ptr_test
+  test/core/support/ref_counted_ptr_test.cc
+  third_party/googletest/googletest/src/gtest-all.cc
+  third_party/googletest/googlemock/src/gmock-all.cc
+)
+
+
+target_include_directories(ref_counted_ptr_test
+  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}
+  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/include
+  PRIVATE ${BORINGSSL_ROOT_DIR}/include
+  PRIVATE ${PROTOBUF_ROOT_DIR}/src
+  PRIVATE ${BENCHMARK_ROOT_DIR}/include
+  PRIVATE ${ZLIB_ROOT_DIR}
+  PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/zlib
+  PRIVATE ${CARES_INCLUDE_DIR}
+  PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
+  PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
+  PRIVATE third_party/googletest/googletest/include
+  PRIVATE third_party/googletest/googletest
+  PRIVATE third_party/googletest/googlemock/include
+  PRIVATE third_party/googletest/googlemock
+  PRIVATE ${_gRPC_PROTO_GENS_DIR}
+)
+
+target_link_libraries(ref_counted_ptr_test
+  ${_gRPC_PROTOBUF_LIBRARIES}
+  ${_gRPC_ALLTARGETS_LIBRARIES}
+  grpc_test_util
+  grpc++
+  grpc
+  gpr_test_util
+  gpr
+  ${_gRPC_GFLAGS_LIBRARIES}
+)
+
+endif (gRPC_BUILD_TESTS)
+if (gRPC_BUILD_TESTS)
+
+add_executable(ref_counted_test
+  test/core/support/ref_counted_test.cc
+  third_party/googletest/googletest/src/gtest-all.cc
+  third_party/googletest/googlemock/src/gmock-all.cc
+)
+
+
+target_include_directories(ref_counted_test
+  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}
+  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/include
+  PRIVATE ${BORINGSSL_ROOT_DIR}/include
+  PRIVATE ${PROTOBUF_ROOT_DIR}/src
+  PRIVATE ${BENCHMARK_ROOT_DIR}/include
+  PRIVATE ${ZLIB_ROOT_DIR}
+  PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/zlib
+  PRIVATE ${CARES_INCLUDE_DIR}
+  PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
+  PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
+  PRIVATE third_party/googletest/googletest/include
+  PRIVATE third_party/googletest/googletest
+  PRIVATE third_party/googletest/googlemock/include
+  PRIVATE third_party/googletest/googlemock
+  PRIVATE ${_gRPC_PROTO_GENS_DIR}
+)
+
+target_link_libraries(ref_counted_test
+  ${_gRPC_PROTOBUF_LIBRARIES}
+  ${_gRPC_ALLTARGETS_LIBRARIES}
+  grpc_test_util
+  grpc++
+  grpc
+  gpr_test_util
+  gpr
+  ${_gRPC_GFLAGS_LIBRARIES}
+)
+
+endif (gRPC_BUILD_TESTS)
+if (gRPC_BUILD_TESTS)
+
 add_executable(secure_auth_context_test
   test/cpp/common/secure_auth_context_test.cc
   third_party/googletest/googletest/src/gtest-all.cc
@@ -12247,7 +12116,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
   PRIVATE third_party/googletest/googletest/include
   PRIVATE third_party/googletest/googletest
   PRIVATE third_party/googletest/googlemock/include
@@ -12289,7 +12157,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
   PRIVATE third_party/googletest/googletest/include
   PRIVATE third_party/googletest/googletest
   PRIVATE third_party/googletest/googlemock/include
@@ -12334,7 +12201,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
   PRIVATE third_party/googletest/googletest/include
   PRIVATE third_party/googletest/googletest
   PRIVATE third_party/googletest/googlemock/include
@@ -12389,7 +12255,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
   PRIVATE third_party/googletest/googletest/include
   PRIVATE third_party/googletest/googletest
   PRIVATE third_party/googletest/googlemock/include
@@ -12430,7 +12295,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
   PRIVATE third_party/googletest/googletest/include
   PRIVATE third_party/googletest/googletest
   PRIVATE third_party/googletest/googlemock/include
@@ -12471,7 +12335,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
   PRIVATE third_party/googletest/googletest/include
   PRIVATE third_party/googletest/googletest
   PRIVATE third_party/googletest/googlemock/include
@@ -12513,7 +12376,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
   PRIVATE third_party/googletest/googletest/include
   PRIVATE third_party/googletest/googletest
   PRIVATE third_party/googletest/googlemock/include
@@ -12568,7 +12430,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
   PRIVATE third_party/googletest/googletest/include
   PRIVATE third_party/googletest/googletest
   PRIVATE third_party/googletest/googlemock/include
@@ -12609,7 +12470,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
   PRIVATE third_party/googletest/googletest/include
   PRIVATE third_party/googletest/googletest
   PRIVATE third_party/googletest/googlemock/include
@@ -12650,7 +12510,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
   PRIVATE third_party/googletest/googletest/include
   PRIVATE third_party/googletest/googletest
   PRIVATE third_party/googletest/googlemock/include
@@ -12690,7 +12549,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
   PRIVATE third_party/googletest/googletest/include
   PRIVATE third_party/googletest/googletest
   PRIVATE third_party/googletest/googlemock/include
@@ -12731,7 +12589,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
   PRIVATE third_party/googletest/googletest/include
   PRIVATE third_party/googletest/googletest
   PRIVATE third_party/googletest/googlemock/include
@@ -12804,7 +12661,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
   PRIVATE third_party/googletest/googletest/include
   PRIVATE third_party/googletest/googletest
   PRIVATE third_party/googletest/googlemock/include
@@ -12846,7 +12702,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
   PRIVATE third_party/googletest/googletest/include
   PRIVATE third_party/googletest/googletest
   PRIVATE third_party/googletest/googlemock/include
@@ -12885,7 +12740,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
   PRIVATE third_party/googletest/googletest/include
   PRIVATE third_party/googletest/googletest
   PRIVATE third_party/googletest/googlemock/include
@@ -12926,7 +12780,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
   PRIVATE third_party/googletest/googletest/include
   PRIVATE third_party/googletest/googletest
   PRIVATE third_party/googletest/googlemock/include
@@ -12948,46 +12801,6 @@
 
 endif (gRPC_BUILD_TESTS)
 if (gRPC_BUILD_TESTS)
-
-add_executable(vector_test
-  test/core/support/vector_test.cc
-  third_party/googletest/googletest/src/gtest-all.cc
-  third_party/googletest/googlemock/src/gmock-all.cc
-)
-
-
-target_include_directories(vector_test
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/include
-  PRIVATE ${BORINGSSL_ROOT_DIR}/include
-  PRIVATE ${PROTOBUF_ROOT_DIR}/src
-  PRIVATE ${BENCHMARK_ROOT_DIR}/include
-  PRIVATE ${ZLIB_ROOT_DIR}
-  PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/zlib
-  PRIVATE ${CARES_INCLUDE_DIR}
-  PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
-  PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
-  PRIVATE third_party/googletest/googletest/include
-  PRIVATE third_party/googletest/googletest
-  PRIVATE third_party/googletest/googlemock/include
-  PRIVATE third_party/googletest/googlemock
-  PRIVATE ${_gRPC_PROTO_GENS_DIR}
-)
-
-target_link_libraries(vector_test
-  ${_gRPC_PROTOBUF_LIBRARIES}
-  ${_gRPC_ALLTARGETS_LIBRARIES}
-  grpc_test_util
-  grpc++
-  grpc
-  gpr_test_util
-  gpr
-  ${_gRPC_GFLAGS_LIBRARIES}
-)
-
-endif (gRPC_BUILD_TESTS)
-if (gRPC_BUILD_TESTS)
 if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_POSIX)
 
 add_executable(writes_per_rpc_test
@@ -13008,7 +12821,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
   PRIVATE third_party/googletest/googletest/include
   PRIVATE third_party/googletest/googletest
   PRIVATE third_party/googletest/googlemock/include
@@ -13048,7 +12860,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
 )
 
 target_link_libraries(public_headers_must_be_c89
@@ -13076,7 +12887,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
 )
 
 target_link_libraries(badreq_bad_client_test
@@ -13108,7 +12918,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
 )
 
 target_link_libraries(connection_prefix_bad_client_test
@@ -13140,7 +12949,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
 )
 
 target_link_libraries(head_of_line_blocking_bad_client_test
@@ -13172,7 +12980,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
 )
 
 target_link_libraries(headers_bad_client_test
@@ -13204,7 +13011,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
 )
 
 target_link_libraries(initial_settings_frame_bad_client_test
@@ -13236,7 +13042,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
 )
 
 target_link_libraries(server_registered_method_bad_client_test
@@ -13268,7 +13073,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
 )
 
 target_link_libraries(simple_request_bad_client_test
@@ -13300,7 +13104,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
 )
 
 target_link_libraries(unknown_frame_bad_client_test
@@ -13332,7 +13135,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
 )
 
 target_link_libraries(window_overflow_bad_client_test
@@ -13365,7 +13167,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
 )
 
 target_link_libraries(bad_ssl_cert_server
@@ -13398,7 +13199,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
 )
 
 target_link_libraries(bad_ssl_cert_test
@@ -13429,7 +13229,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
 )
 
 target_link_libraries(h2_census_test
@@ -13460,7 +13259,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
 )
 
 target_link_libraries(h2_compress_test
@@ -13491,7 +13289,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
 )
 
 target_link_libraries(h2_fakesec_test
@@ -13523,7 +13320,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
 )
 
 target_link_libraries(h2_fd_test
@@ -13555,7 +13351,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
 )
 
 target_link_libraries(h2_full_test
@@ -13587,7 +13382,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
 )
 
 target_link_libraries(h2_full+pipe_test
@@ -13619,7 +13413,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
 )
 
 target_link_libraries(h2_full+trace_test
@@ -13650,7 +13443,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
 )
 
 target_link_libraries(h2_full+workarounds_test
@@ -13681,7 +13473,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
 )
 
 target_link_libraries(h2_http_proxy_test
@@ -13712,7 +13503,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
 )
 
 target_link_libraries(h2_load_reporting_test
@@ -13743,7 +13533,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
 )
 
 target_link_libraries(h2_oauth2_test
@@ -13774,7 +13563,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
 )
 
 target_link_libraries(h2_proxy_test
@@ -13805,7 +13593,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
 )
 
 target_link_libraries(h2_sockpair_test
@@ -13836,7 +13623,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
 )
 
 target_link_libraries(h2_sockpair+trace_test
@@ -13867,7 +13653,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
 )
 
 target_link_libraries(h2_sockpair_1byte_test
@@ -13898,7 +13683,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
 )
 
 target_link_libraries(h2_ssl_test
@@ -13929,7 +13713,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
 )
 
 target_link_libraries(h2_ssl_proxy_test
@@ -13961,7 +13744,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
 )
 
 target_link_libraries(h2_uds_test
@@ -13993,7 +13775,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
 )
 
 target_link_libraries(inproc_test
@@ -14024,7 +13805,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
 )
 
 target_link_libraries(h2_census_nosec_test
@@ -14055,7 +13835,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
 )
 
 target_link_libraries(h2_compress_nosec_test
@@ -14087,7 +13866,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
 )
 
 target_link_libraries(h2_fd_nosec_test
@@ -14119,7 +13897,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
 )
 
 target_link_libraries(h2_full_nosec_test
@@ -14151,7 +13928,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
 )
 
 target_link_libraries(h2_full+pipe_nosec_test
@@ -14183,7 +13959,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
 )
 
 target_link_libraries(h2_full+trace_nosec_test
@@ -14214,7 +13989,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
 )
 
 target_link_libraries(h2_full+workarounds_nosec_test
@@ -14245,7 +14019,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
 )
 
 target_link_libraries(h2_http_proxy_nosec_test
@@ -14276,7 +14049,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
 )
 
 target_link_libraries(h2_load_reporting_nosec_test
@@ -14307,7 +14079,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
 )
 
 target_link_libraries(h2_proxy_nosec_test
@@ -14338,7 +14109,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
 )
 
 target_link_libraries(h2_sockpair_nosec_test
@@ -14369,7 +14139,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
 )
 
 target_link_libraries(h2_sockpair+trace_nosec_test
@@ -14400,7 +14169,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
 )
 
 target_link_libraries(h2_sockpair_1byte_nosec_test
@@ -14432,7 +14200,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
 )
 
 target_link_libraries(h2_uds_nosec_test
@@ -14464,7 +14231,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
 )
 
 target_link_libraries(inproc_nosec_test
@@ -14498,7 +14264,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
   PRIVATE third_party/googletest/googletest/include
   PRIVATE third_party/googletest/googletest
   PRIVATE third_party/googletest/googlemock/include
@@ -14542,7 +14307,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
   PRIVATE third_party/googletest/googletest/include
   PRIVATE third_party/googletest/googletest
   PRIVATE third_party/googletest/googlemock/include
@@ -14586,7 +14350,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
   PRIVATE third_party/googletest/googletest/include
   PRIVATE third_party/googletest/googletest
   PRIVATE third_party/googletest/googlemock/include
@@ -14630,7 +14393,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
   PRIVATE third_party/googletest/googletest/include
   PRIVATE third_party/googletest/googletest
   PRIVATE third_party/googletest/googlemock/include
@@ -14672,7 +14434,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
 )
 
 target_link_libraries(api_fuzzer_one_entry
@@ -14703,7 +14464,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
 )
 
 target_link_libraries(client_fuzzer_one_entry
@@ -14734,7 +14494,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
 )
 
 target_link_libraries(hpack_parser_fuzzer_test_one_entry
@@ -14765,7 +14524,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
 )
 
 target_link_libraries(http_request_fuzzer_test_one_entry
@@ -14796,7 +14554,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
 )
 
 target_link_libraries(http_response_fuzzer_test_one_entry
@@ -14827,7 +14584,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
 )
 
 target_link_libraries(json_fuzzer_test_one_entry
@@ -14858,7 +14614,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
 )
 
 target_link_libraries(nanopb_fuzzer_response_test_one_entry
@@ -14889,7 +14644,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
 )
 
 target_link_libraries(nanopb_fuzzer_serverlist_test_one_entry
@@ -14920,7 +14674,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
 )
 
 target_link_libraries(percent_decode_fuzzer_one_entry
@@ -14951,7 +14704,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
 )
 
 target_link_libraries(percent_encode_fuzzer_one_entry
@@ -14982,7 +14734,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
 )
 
 target_link_libraries(server_fuzzer_one_entry
@@ -15013,7 +14764,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
 )
 
 target_link_libraries(ssl_server_fuzzer_one_entry
@@ -15044,7 +14794,6 @@
   PRIVATE ${CARES_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/abseil-cpp
 )
 
 target_link_libraries(uri_fuzzer_test_one_entry
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index e9c5fe2..af46246 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -7,7 +7,7 @@
 ## Legal requirements
 
 In order to protect both you and ourselves, you will need to sign the
-[Contributor License Agreement](https://cla.developers.google.com/clas).
+[Contributor License Agreement](https://identity.linuxfoundation.org/projects/cncf).
 
 ## Running tests
 
diff --git a/INSTALL.md b/INSTALL.md
index 15725bd..430fd71 100644
--- a/INSTALL.md
+++ b/INSTALL.md
@@ -95,37 +95,50 @@
 
 Builds gRPC C and C++ with boringssl.
 - Install Visual Studio 2015 or 2017 (Visual C++ compiler will be used).
+- Install [Git](https://git-scm.com/).
 - Install [CMake](https://cmake.org/download/).
-- Install [Active State Perl](https://www.activestate.com/activeperl/) (`choco install activeperl`)
-- Install [Ninja](https://ninja-build.org/) (`choco install ninja`)
-- Install [Go](https://golang.org/dl/) (`choco install golang`)
-- Install [yasm](http://yasm.tortall.net/) and add it to `PATH` (`choco install yasm`)
-- Run these commands in the repo root directory
+- Install [Active State Perl](https://www.activestate.com/activeperl/) (`choco install activeperl`) - *required by boringssl*
+- Install [Go](https://golang.org/dl/) (`choco install golang`) - *required by boringssl*
+- Install [yasm](http://yasm.tortall.net/) and add it to `PATH` (`choco install yasm`) - *required by boringssl*
+- (Optional) Install [Ninja](https://ninja-build.org/) (`choco install ninja`)
 
-#### cmake: Using Ninja (faster build, supports boringssl's assembly optimizations).
-Please note that when using Ninja, you'll still need Visual C++ (part of Visual Studio)
-installed to be able to compile the C/C++ sources.
+#### Clone grpc sources including submodules
+Before building, you need to clone the gRPC github repository and download submodules containing source code 
+for gRPC's dependencies (that's done by the `submodule` command).
 ```
-> md .build
-> cd .build
-> call "%VS140COMNTOOLS%..\..\VC\vcvarsall.bat" x64
-> cmake .. -GNinja -DCMAKE_BUILD_TYPE=Release
-> cmake --build .
+> @rem You can also do just "git clone --recursive -b THE_BRANCH_YOU_WANT https://github.com/grpc/grpc"
+> powershell git clone --recursive -b ((New-Object System.Net.WebClient).DownloadString(\"https://grpc.io/release\").Trim()) https://github.com/grpc/grpc
+> cd grpc
+> @rem To update submodules at later time, run "git submodule update --init"
 ```
 
-#### cmake: Using Visual Studio 2015 (can only build with OPENSSL_NO_ASM).
+#### cmake: Using Visual Studio 2015 or 2017 (can only build with OPENSSL_NO_ASM).
 When using the "Visual Studio" generator,
 cmake will generate a solution (`grpc.sln`) that contains a VS project for 
 every target defined in `CMakeLists.txt` (+ few extra convenience projects
 added automatically by cmake). After opening the solution with Visual Studio 
 you will be able to browse and build the code as usual.
 ```
+> @rem Run from grpc directory after cloning the repo with --recursive or updating submodules.
 > md .build
 > cd .build
 > cmake .. -G "Visual Studio 14 2015" -DCMAKE_BUILD_TYPE=Release
 > cmake --build .
 ```
 
+#### cmake: Using Ninja (faster build, supports boringssl's assembly optimizations).
+Please note that when using Ninja, you'll still need Visual C++ (part of Visual Studio)
+installed to be able to compile the C/C++ sources.
+```
+> @rem Run from grpc directory after cloning the repo with --recursive or updating submodules.
+> md .build
+> cd .build
+> call "%VS140COMNTOOLS%..\..\VC\vcvarsall.bat" x64
+> cmake .. -GNinja -DCMAKE_BUILD_TYPE=Release
+> cmake --build .
+> ninja
+```
+
 ### msys2 (with mingw)
 
 The Makefile (and source code) should support msys2's mingw32 and mingw64
diff --git a/Makefile b/Makefile
index 5db1163..0e52d5a 100644
--- a/Makefile
+++ b/Makefile
@@ -114,7 +114,7 @@
 CXX_msan = clang++
 LD_msan = clang++
 LDXX_msan = clang++
-CPPFLAGS_msan = -O0 -fsanitize-coverage=edge -fsanitize=memory -fsanitize-memory-track-origins -fno-omit-frame-pointer -DGTEST_HAS_TR1_TUPLE=0 -DGTEST_USE_OWN_TR1_TUPLE=1 -Wno-unused-command-line-argument -fPIE -pie -DGPR_NO_DIRECT_SYSCALLS
+CPPFLAGS_msan = -O0 -fsanitize-coverage=edge -fsanitize=memory -fsanitize-memory-track-origins -fsanitize-memory-use-after-dtor -fno-omit-frame-pointer -DGTEST_HAS_TR1_TUPLE=0 -DGTEST_USE_OWN_TR1_TUPLE=1 -Wno-unused-command-line-argument -fPIE -pie -DGPR_NO_DIRECT_SYSCALLS
 LDFLAGS_msan = -fsanitize=memory -DGTEST_HAS_TR1_TUPLE=0 -DGTEST_USE_OWN_TR1_TUPLE=1 -fPIE -pie $(if $(JENKINS_BUILD),-Wl$(comma)-Ttext-segment=0x7e0000000000,)
 DEFINES_msan = NDEBUG
 
@@ -327,7 +327,8 @@
 ifeq ($(SYSTEM),Darwin)
 CXXFLAGS += -stdlib=libc++
 endif
-CPPFLAGS += -g -Wall -Wextra -Werror -Wno-long-long -Wno-unused-parameter -DOSATOMIC_USE_INLINED=1 -Ithird_party/abseil-cpp
+CPPFLAGS += -g -Wall -Wextra -Werror -Wno-long-long -Wno-unused-parameter -DOSATOMIC_USE_INLINED=1
+COREFLAGS += -fno-rtti -fno-exceptions
 LDFLAGS += -g
 
 CPPFLAGS += $(CPPFLAGS_$(CONFIG))
@@ -411,8 +412,8 @@
 endif
 
 CORE_VERSION = 5.0.0-dev
-CPP_VERSION = 1.8.0-dev
-CSHARP_VERSION = 1.8.0-dev
+CPP_VERSION = 1.9.0-dev
+CSHARP_VERSION = 1.9.0-dev
 
 CPPFLAGS_NO_ARCH += $(addprefix -I, $(INCLUDES)) $(addprefix -D, $(DEFINES))
 CPPFLAGS += $(CPPFLAGS_NO_ARCH) $(ARCH_FLAGS)
@@ -987,12 +988,11 @@
 gpr_cmdline_test: $(BINDIR)/$(CONFIG)/gpr_cmdline_test
 gpr_cpu_test: $(BINDIR)/$(CONFIG)/gpr_cpu_test
 gpr_env_test: $(BINDIR)/$(CONFIG)/gpr_env_test
-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_manual_constructor_test: $(BINDIR)/$(CONFIG)/gpr_manual_constructor_test
 gpr_mpscq_test: $(BINDIR)/$(CONFIG)/gpr_mpscq_test
 gpr_spinlock_test: $(BINDIR)/$(CONFIG)/gpr_spinlock_test
-gpr_stack_lockfree_test: $(BINDIR)/$(CONFIG)/gpr_stack_lockfree_test
 gpr_string_test: $(BINDIR)/$(CONFIG)/gpr_string_test
 gpr_sync_test: $(BINDIR)/$(CONFIG)/gpr_sync_test
 gpr_thd_test: $(BINDIR)/$(CONFIG)/gpr_thd_test
@@ -1020,6 +1020,7 @@
 handshake_client: $(BINDIR)/$(CONFIG)/handshake_client
 handshake_server: $(BINDIR)/$(CONFIG)/handshake_server
 handshake_server_with_readahead_handshaker: $(BINDIR)/$(CONFIG)/handshake_server_with_readahead_handshaker
+histogram_test: $(BINDIR)/$(CONFIG)/histogram_test
 hpack_parser_fuzzer_test: $(BINDIR)/$(CONFIG)/hpack_parser_fuzzer_test
 hpack_parser_test: $(BINDIR)/$(CONFIG)/hpack_parser_test
 hpack_table_test: $(BINDIR)/$(CONFIG)/hpack_table_test
@@ -1163,6 +1164,8 @@
 qps_worker: $(BINDIR)/$(CONFIG)/qps_worker
 reconnect_interop_client: $(BINDIR)/$(CONFIG)/reconnect_interop_client
 reconnect_interop_server: $(BINDIR)/$(CONFIG)/reconnect_interop_server
+ref_counted_ptr_test: $(BINDIR)/$(CONFIG)/ref_counted_ptr_test
+ref_counted_test: $(BINDIR)/$(CONFIG)/ref_counted_test
 secure_auth_context_test: $(BINDIR)/$(CONFIG)/secure_auth_context_test
 secure_sync_unary_ping_pong_test: $(BINDIR)/$(CONFIG)/secure_sync_unary_ping_pong_test
 server_builder_plugin_test: $(BINDIR)/$(CONFIG)/server_builder_plugin_test
@@ -1179,7 +1182,6 @@
 thread_manager_test: $(BINDIR)/$(CONFIG)/thread_manager_test
 thread_stress_test: $(BINDIR)/$(CONFIG)/thread_stress_test
 transport_pid_controller_test: $(BINDIR)/$(CONFIG)/transport_pid_controller_test
-vector_test: $(BINDIR)/$(CONFIG)/vector_test
 writes_per_rpc_test: $(BINDIR)/$(CONFIG)/writes_per_rpc_test
 public_headers_must_be_c89: $(BINDIR)/$(CONFIG)/public_headers_must_be_c89
 boringssl_aes_test: $(BINDIR)/$(CONFIG)/boringssl_aes_test
@@ -1381,12 +1383,11 @@
   $(BINDIR)/$(CONFIG)/gpr_cmdline_test \
   $(BINDIR)/$(CONFIG)/gpr_cpu_test \
   $(BINDIR)/$(CONFIG)/gpr_env_test \
-  $(BINDIR)/$(CONFIG)/gpr_histogram_test \
   $(BINDIR)/$(CONFIG)/gpr_host_port_test \
   $(BINDIR)/$(CONFIG)/gpr_log_test \
+  $(BINDIR)/$(CONFIG)/gpr_manual_constructor_test \
   $(BINDIR)/$(CONFIG)/gpr_mpscq_test \
   $(BINDIR)/$(CONFIG)/gpr_spinlock_test \
-  $(BINDIR)/$(CONFIG)/gpr_stack_lockfree_test \
   $(BINDIR)/$(CONFIG)/gpr_string_test \
   $(BINDIR)/$(CONFIG)/gpr_sync_test \
   $(BINDIR)/$(CONFIG)/gpr_thd_test \
@@ -1411,6 +1412,7 @@
   $(BINDIR)/$(CONFIG)/handshake_client \
   $(BINDIR)/$(CONFIG)/handshake_server \
   $(BINDIR)/$(CONFIG)/handshake_server_with_readahead_handshaker \
+  $(BINDIR)/$(CONFIG)/histogram_test \
   $(BINDIR)/$(CONFIG)/hpack_parser_test \
   $(BINDIR)/$(CONFIG)/hpack_table_test \
   $(BINDIR)/$(CONFIG)/http_parser_test \
@@ -1598,6 +1600,8 @@
   $(BINDIR)/$(CONFIG)/qps_worker \
   $(BINDIR)/$(CONFIG)/reconnect_interop_client \
   $(BINDIR)/$(CONFIG)/reconnect_interop_server \
+  $(BINDIR)/$(CONFIG)/ref_counted_ptr_test \
+  $(BINDIR)/$(CONFIG)/ref_counted_test \
   $(BINDIR)/$(CONFIG)/secure_auth_context_test \
   $(BINDIR)/$(CONFIG)/secure_sync_unary_ping_pong_test \
   $(BINDIR)/$(CONFIG)/server_builder_plugin_test \
@@ -1614,7 +1618,6 @@
   $(BINDIR)/$(CONFIG)/thread_manager_test \
   $(BINDIR)/$(CONFIG)/thread_stress_test \
   $(BINDIR)/$(CONFIG)/transport_pid_controller_test \
-  $(BINDIR)/$(CONFIG)/vector_test \
   $(BINDIR)/$(CONFIG)/writes_per_rpc_test \
   $(BINDIR)/$(CONFIG)/boringssl_aes_test \
   $(BINDIR)/$(CONFIG)/boringssl_asn1_test \
@@ -1724,6 +1727,8 @@
   $(BINDIR)/$(CONFIG)/qps_worker \
   $(BINDIR)/$(CONFIG)/reconnect_interop_client \
   $(BINDIR)/$(CONFIG)/reconnect_interop_server \
+  $(BINDIR)/$(CONFIG)/ref_counted_ptr_test \
+  $(BINDIR)/$(CONFIG)/ref_counted_test \
   $(BINDIR)/$(CONFIG)/secure_auth_context_test \
   $(BINDIR)/$(CONFIG)/secure_sync_unary_ping_pong_test \
   $(BINDIR)/$(CONFIG)/server_builder_plugin_test \
@@ -1740,7 +1745,6 @@
   $(BINDIR)/$(CONFIG)/thread_manager_test \
   $(BINDIR)/$(CONFIG)/thread_stress_test \
   $(BINDIR)/$(CONFIG)/transport_pid_controller_test \
-  $(BINDIR)/$(CONFIG)/vector_test \
   $(BINDIR)/$(CONFIG)/writes_per_rpc_test \
   $(BINDIR)/$(CONFIG)/resolver_component_test_unsecure \
   $(BINDIR)/$(CONFIG)/resolver_component_test \
@@ -1825,18 +1829,16 @@
 	$(Q) $(BINDIR)/$(CONFIG)/gpr_cpu_test || ( echo test gpr_cpu_test failed ; exit 1 )
 	$(E) "[RUN]     Testing gpr_env_test"
 	$(Q) $(BINDIR)/$(CONFIG)/gpr_env_test || ( echo test gpr_env_test failed ; exit 1 )
-	$(E) "[RUN]     Testing gpr_histogram_test"
-	$(Q) $(BINDIR)/$(CONFIG)/gpr_histogram_test || ( echo test gpr_histogram_test failed ; exit 1 )
 	$(E) "[RUN]     Testing gpr_host_port_test"
 	$(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_manual_constructor_test"
+	$(Q) $(BINDIR)/$(CONFIG)/gpr_manual_constructor_test || ( echo test gpr_manual_constructor_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_spinlock_test"
 	$(Q) $(BINDIR)/$(CONFIG)/gpr_spinlock_test || ( echo test gpr_spinlock_test failed ; exit 1 )
-	$(E) "[RUN]     Testing gpr_stack_lockfree_test"
-	$(Q) $(BINDIR)/$(CONFIG)/gpr_stack_lockfree_test || ( echo test gpr_stack_lockfree_test failed ; exit 1 )
 	$(E) "[RUN]     Testing gpr_string_test"
 	$(Q) $(BINDIR)/$(CONFIG)/gpr_string_test || ( echo test gpr_string_test failed ; exit 1 )
 	$(E) "[RUN]     Testing gpr_sync_test"
@@ -1883,6 +1885,8 @@
 	$(Q) $(BINDIR)/$(CONFIG)/handshake_server || ( echo test handshake_server failed ; exit 1 )
 	$(E) "[RUN]     Testing handshake_server_with_readahead_handshaker"
 	$(Q) $(BINDIR)/$(CONFIG)/handshake_server_with_readahead_handshaker || ( echo test handshake_server_with_readahead_handshaker failed ; exit 1 )
+	$(E) "[RUN]     Testing histogram_test"
+	$(Q) $(BINDIR)/$(CONFIG)/histogram_test || ( echo test histogram_test failed ; exit 1 )
 	$(E) "[RUN]     Testing hpack_parser_test"
 	$(Q) $(BINDIR)/$(CONFIG)/hpack_parser_test || ( echo test hpack_parser_test failed ; exit 1 )
 	$(E) "[RUN]     Testing hpack_table_test"
@@ -2125,6 +2129,10 @@
 	$(Q) $(BINDIR)/$(CONFIG)/proto_utils_test || ( echo test proto_utils_test failed ; exit 1 )
 	$(E) "[RUN]     Testing qps_openloop_test"
 	$(Q) $(BINDIR)/$(CONFIG)/qps_openloop_test || ( echo test qps_openloop_test failed ; exit 1 )
+	$(E) "[RUN]     Testing ref_counted_ptr_test"
+	$(Q) $(BINDIR)/$(CONFIG)/ref_counted_ptr_test || ( echo test ref_counted_ptr_test failed ; exit 1 )
+	$(E) "[RUN]     Testing ref_counted_test"
+	$(Q) $(BINDIR)/$(CONFIG)/ref_counted_test || ( echo test ref_counted_test failed ; exit 1 )
 	$(E) "[RUN]     Testing secure_auth_context_test"
 	$(Q) $(BINDIR)/$(CONFIG)/secure_auth_context_test || ( echo test secure_auth_context_test failed ; exit 1 )
 	$(E) "[RUN]     Testing secure_sync_unary_ping_pong_test"
@@ -2153,8 +2161,6 @@
 	$(Q) $(BINDIR)/$(CONFIG)/thread_stress_test || ( echo test thread_stress_test failed ; exit 1 )
 	$(E) "[RUN]     Testing transport_pid_controller_test"
 	$(Q) $(BINDIR)/$(CONFIG)/transport_pid_controller_test || ( echo test transport_pid_controller_test failed ; exit 1 )
-	$(E) "[RUN]     Testing vector_test"
-	$(Q) $(BINDIR)/$(CONFIG)/vector_test || ( echo test vector_test failed ; exit 1 )
 	$(E) "[RUN]     Testing writes_per_rpc_test"
 	$(Q) $(BINDIR)/$(CONFIG)/writes_per_rpc_test || ( echo test writes_per_rpc_test failed ; exit 1 )
 	$(E) "[RUN]     Testing resolver_component_tests_runner_invoker_unsecure"
@@ -2579,6 +2585,16 @@
 	$(Q) mkdir -p `dirname $@`
 	$(Q) $(HOST_CXX) $(HOST_CXXFLAGS) $(HOST_CPPFLAGS) -MMD -MF $(addsuffix .dep, $(basename $@)) -c -o $@ $<
 
+$(OBJDIR)/$(CONFIG)/src/core/%.o : src/core/%.cc
+	$(E) "[CXX]     Compiling $<"
+	$(Q) mkdir -p `dirname $@`
+	$(Q) $(CXX) $(CPPFLAGS) $(CXXFLAGS) $(COREFLAGS) -MMD -MF $(addsuffix .dep, $(basename $@)) -c -o $@ $<
+
+$(OBJDIR)/$(CONFIG)/test/core/%.o : test/core/%.cc
+	$(E) "[CXX]     Compiling $<"
+	$(Q) mkdir -p `dirname $@`
+	$(Q) $(CXX) $(CPPFLAGS) $(CXXFLAGS) $(COREFLAGS) -MMD -MF $(addsuffix .dep, $(basename $@)) -c -o $@ $<
+
 $(OBJDIR)/$(CONFIG)/%.o : %.cc
 	$(E) "[CXX]     Compiling $<"
 	$(Q) mkdir -p `dirname $@`
@@ -2812,7 +2828,7 @@
     src/core/lib/support/env_linux.cc \
     src/core/lib/support/env_posix.cc \
     src/core/lib/support/env_windows.cc \
-    src/core/lib/support/histogram.cc \
+    src/core/lib/support/fork.cc \
     src/core/lib/support/host_port.cc \
     src/core/lib/support/log.cc \
     src/core/lib/support/log_android.cc \
@@ -2821,7 +2837,6 @@
     src/core/lib/support/log_windows.cc \
     src/core/lib/support/mpscq.cc \
     src/core/lib/support/murmur_hash.cc \
-    src/core/lib/support/stack_lockfree.cc \
     src/core/lib/support/string.cc \
     src/core/lib/support/string_posix.cc \
     src/core/lib/support/string_util_windows.cc \
@@ -2853,7 +2868,6 @@
     include/grpc/support/avl.h \
     include/grpc/support/cmdline.h \
     include/grpc/support/cpu.h \
-    include/grpc/support/histogram.h \
     include/grpc/support/host_port.h \
     include/grpc/support/log.h \
     include/grpc/support/log_windows.h \
@@ -2876,6 +2890,7 @@
     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/fork.h \
     include/grpc/impl/codegen/gpr_slice.h \
     include/grpc/impl/codegen/gpr_types.h \
     include/grpc/impl/codegen/port_platform.h \
@@ -2982,6 +2997,8 @@
     src/core/lib/iomgr/ev_windows.cc \
     src/core/lib/iomgr/exec_ctx.cc \
     src/core/lib/iomgr/executor.cc \
+    src/core/lib/iomgr/fork_posix.cc \
+    src/core/lib/iomgr/fork_windows.cc \
     src/core/lib/iomgr/gethostname_fallback.cc \
     src/core/lib/iomgr/gethostname_host_name_max.cc \
     src/core/lib/iomgr/gethostname_sysconf.cc \
@@ -3212,6 +3229,7 @@
     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/fork.h \
     include/grpc/impl/codegen/gpr_slice.h \
     include/grpc/impl/codegen/gpr_types.h \
     include/grpc/impl/codegen/port_platform.h \
@@ -3224,6 +3242,7 @@
     include/grpc/byte_buffer.h \
     include/grpc/byte_buffer_reader.h \
     include/grpc/compression.h \
+    include/grpc/fork.h \
     include/grpc/grpc.h \
     include/grpc/grpc_posix.h \
     include/grpc/grpc_security_constants.h \
@@ -3321,6 +3340,8 @@
     src/core/lib/iomgr/ev_windows.cc \
     src/core/lib/iomgr/exec_ctx.cc \
     src/core/lib/iomgr/executor.cc \
+    src/core/lib/iomgr/fork_posix.cc \
+    src/core/lib/iomgr/fork_windows.cc \
     src/core/lib/iomgr/gethostname_fallback.cc \
     src/core/lib/iomgr/gethostname_host_name_max.cc \
     src/core/lib/iomgr/gethostname_sysconf.cc \
@@ -3522,6 +3543,7 @@
     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/fork.h \
     include/grpc/impl/codegen/gpr_slice.h \
     include/grpc/impl/codegen/gpr_types.h \
     include/grpc/impl/codegen/port_platform.h \
@@ -3599,13 +3621,16 @@
     test/core/iomgr/endpoint_tests.cc \
     test/core/util/debugger_macros.cc \
     test/core/util/grpc_profiler.cc \
+    test/core/util/histogram.cc \
     test/core/util/memory_counters.cc \
     test/core/util/mock_endpoint.cc \
     test/core/util/parse_hexstring.cc \
     test/core/util/passthru_endpoint.cc \
     test/core/util/port.cc \
+    test/core/util/port_isolated_runtime_environment.cc \
     test/core/util/port_server_client.cc \
     test/core/util/slice_splitter.cc \
+    test/core/util/tracer_util.cc \
     test/core/util/trickle_endpoint.cc \
     src/core/lib/backoff/backoff.cc \
     src/core/lib/channel/channel_args.cc \
@@ -3640,6 +3665,8 @@
     src/core/lib/iomgr/ev_windows.cc \
     src/core/lib/iomgr/exec_ctx.cc \
     src/core/lib/iomgr/executor.cc \
+    src/core/lib/iomgr/fork_posix.cc \
+    src/core/lib/iomgr/fork_windows.cc \
     src/core/lib/iomgr/gethostname_fallback.cc \
     src/core/lib/iomgr/gethostname_host_name_max.cc \
     src/core/lib/iomgr/gethostname_sysconf.cc \
@@ -3803,6 +3830,7 @@
     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/fork.h \
     include/grpc/impl/codegen/gpr_slice.h \
     include/grpc/impl/codegen/gpr_types.h \
     include/grpc/impl/codegen/port_platform.h \
@@ -3854,13 +3882,16 @@
     test/core/iomgr/endpoint_tests.cc \
     test/core/util/debugger_macros.cc \
     test/core/util/grpc_profiler.cc \
+    test/core/util/histogram.cc \
     test/core/util/memory_counters.cc \
     test/core/util/mock_endpoint.cc \
     test/core/util/parse_hexstring.cc \
     test/core/util/passthru_endpoint.cc \
     test/core/util/port.cc \
+    test/core/util/port_isolated_runtime_environment.cc \
     test/core/util/port_server_client.cc \
     test/core/util/slice_splitter.cc \
+    test/core/util/tracer_util.cc \
     test/core/util/trickle_endpoint.cc \
     src/core/lib/backoff/backoff.cc \
     src/core/lib/channel/channel_args.cc \
@@ -3895,6 +3926,8 @@
     src/core/lib/iomgr/ev_windows.cc \
     src/core/lib/iomgr/exec_ctx.cc \
     src/core/lib/iomgr/executor.cc \
+    src/core/lib/iomgr/fork_posix.cc \
+    src/core/lib/iomgr/fork_windows.cc \
     src/core/lib/iomgr/gethostname_fallback.cc \
     src/core/lib/iomgr/gethostname_host_name_max.cc \
     src/core/lib/iomgr/gethostname_sysconf.cc \
@@ -4058,6 +4091,7 @@
     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/fork.h \
     include/grpc/impl/codegen/gpr_slice.h \
     include/grpc/impl/codegen/gpr_types.h \
     include/grpc/impl/codegen/port_platform.h \
@@ -4123,6 +4157,8 @@
     src/core/lib/iomgr/ev_windows.cc \
     src/core/lib/iomgr/exec_ctx.cc \
     src/core/lib/iomgr/executor.cc \
+    src/core/lib/iomgr/fork_posix.cc \
+    src/core/lib/iomgr/fork_windows.cc \
     src/core/lib/iomgr/gethostname_fallback.cc \
     src/core/lib/iomgr/gethostname_host_name_max.cc \
     src/core/lib/iomgr/gethostname_sysconf.cc \
@@ -4321,6 +4357,7 @@
     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/fork.h \
     include/grpc/impl/codegen/gpr_slice.h \
     include/grpc/impl/codegen/gpr_types.h \
     include/grpc/impl/codegen/port_platform.h \
@@ -4332,6 +4369,7 @@
     include/grpc/byte_buffer.h \
     include/grpc/byte_buffer_reader.h \
     include/grpc/compression.h \
+    include/grpc/fork.h \
     include/grpc/grpc.h \
     include/grpc/grpc_posix.h \
     include/grpc/grpc_security_constants.h \
@@ -4555,7 +4593,6 @@
     include/grpc/support/avl.h \
     include/grpc/support/cmdline.h \
     include/grpc/support/cpu.h \
-    include/grpc/support/histogram.h \
     include/grpc/support/host_port.h \
     include/grpc/support/log.h \
     include/grpc/support/log_windows.h \
@@ -4578,6 +4615,7 @@
     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/fork.h \
     include/grpc/impl/codegen/gpr_slice.h \
     include/grpc/impl/codegen/gpr_types.h \
     include/grpc/impl/codegen/port_platform.h \
@@ -4589,6 +4627,7 @@
     include/grpc/byte_buffer.h \
     include/grpc/byte_buffer_reader.h \
     include/grpc/compression.h \
+    include/grpc/fork.h \
     include/grpc/grpc.h \
     include/grpc/grpc_posix.h \
     include/grpc/grpc_security_constants.h \
@@ -4851,6 +4890,8 @@
     src/core/lib/iomgr/ev_windows.cc \
     src/core/lib/iomgr/exec_ctx.cc \
     src/core/lib/iomgr/executor.cc \
+    src/core/lib/iomgr/fork_posix.cc \
+    src/core/lib/iomgr/fork_windows.cc \
     src/core/lib/iomgr/gethostname_fallback.cc \
     src/core/lib/iomgr/gethostname_host_name_max.cc \
     src/core/lib/iomgr/gethostname_sysconf.cc \
@@ -5039,7 +5080,6 @@
     include/grpc/support/avl.h \
     include/grpc/support/cmdline.h \
     include/grpc/support/cpu.h \
-    include/grpc/support/histogram.h \
     include/grpc/support/host_port.h \
     include/grpc/support/log.h \
     include/grpc/support/log_windows.h \
@@ -5062,6 +5102,7 @@
     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/fork.h \
     include/grpc/impl/codegen/gpr_slice.h \
     include/grpc/impl/codegen/gpr_types.h \
     include/grpc/impl/codegen/port_platform.h \
@@ -5073,6 +5114,7 @@
     include/grpc/byte_buffer.h \
     include/grpc/byte_buffer_reader.h \
     include/grpc/compression.h \
+    include/grpc/fork.h \
     include/grpc/grpc.h \
     include/grpc/grpc_posix.h \
     include/grpc/grpc_security_constants.h \
@@ -5487,6 +5529,7 @@
     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/fork.h \
     include/grpc/impl/codegen/gpr_slice.h \
     include/grpc/impl/codegen/gpr_types.h \
     include/grpc/impl/codegen/port_platform.h \
@@ -5604,6 +5647,7 @@
     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/fork.h \
     include/grpc/impl/codegen/gpr_slice.h \
     include/grpc/impl/codegen/gpr_types.h \
     include/grpc/impl/codegen/port_platform.h \
@@ -5757,7 +5801,6 @@
     include/grpc/support/avl.h \
     include/grpc/support/cmdline.h \
     include/grpc/support/cpu.h \
-    include/grpc/support/histogram.h \
     include/grpc/support/host_port.h \
     include/grpc/support/log.h \
     include/grpc/support/log_windows.h \
@@ -5780,6 +5823,7 @@
     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/fork.h \
     include/grpc/impl/codegen/gpr_slice.h \
     include/grpc/impl/codegen/gpr_types.h \
     include/grpc/impl/codegen/port_platform.h \
@@ -5791,6 +5835,7 @@
     include/grpc/byte_buffer.h \
     include/grpc/byte_buffer_reader.h \
     include/grpc/compression.h \
+    include/grpc/fork.h \
     include/grpc/grpc.h \
     include/grpc/grpc_posix.h \
     include/grpc/grpc_security_constants.h \
@@ -10049,38 +10094,6 @@
 endif
 
 
-GPR_HISTOGRAM_TEST_SRC = \
-    test/core/support/histogram_test.cc \
-
-GPR_HISTOGRAM_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(GPR_HISTOGRAM_TEST_SRC))))
-ifeq ($(NO_SECURE),true)
-
-# You can't build secure targets if you don't have OpenSSL.
-
-$(BINDIR)/$(CONFIG)/gpr_histogram_test: openssl_dep_error
-
-else
-
-
-
-$(BINDIR)/$(CONFIG)/gpr_histogram_test: $(GPR_HISTOGRAM_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
-	$(E) "[LD]      Linking $@"
-	$(Q) mkdir -p `dirname $@`
-	$(Q) $(LD) $(LDFLAGS) $(GPR_HISTOGRAM_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBS) $(LDLIBS_SECURE) -o $(BINDIR)/$(CONFIG)/gpr_histogram_test
-
-endif
-
-$(OBJDIR)/$(CONFIG)/test/core/support/histogram_test.o:  $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
-
-deps_gpr_histogram_test: $(GPR_HISTOGRAM_TEST_OBJS:.o=.dep)
-
-ifneq ($(NO_SECURE),true)
-ifneq ($(NO_DEPS),true)
--include $(GPR_HISTOGRAM_TEST_OBJS:.o=.dep)
-endif
-endif
-
-
 GPR_HOST_PORT_TEST_SRC = \
     test/core/support/host_port_test.cc \
 
@@ -10145,6 +10158,38 @@
 endif
 
 
+GPR_MANUAL_CONSTRUCTOR_TEST_SRC = \
+    test/core/support/manual_constructor_test.cc \
+
+GPR_MANUAL_CONSTRUCTOR_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(GPR_MANUAL_CONSTRUCTOR_TEST_SRC))))
+ifeq ($(NO_SECURE),true)
+
+# You can't build secure targets if you don't have OpenSSL.
+
+$(BINDIR)/$(CONFIG)/gpr_manual_constructor_test: openssl_dep_error
+
+else
+
+
+
+$(BINDIR)/$(CONFIG)/gpr_manual_constructor_test: $(GPR_MANUAL_CONSTRUCTOR_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
+	$(E) "[LD]      Linking $@"
+	$(Q) mkdir -p `dirname $@`
+	$(Q) $(LD) $(LDFLAGS) $(GPR_MANUAL_CONSTRUCTOR_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBS) $(LDLIBS_SECURE) -o $(BINDIR)/$(CONFIG)/gpr_manual_constructor_test
+
+endif
+
+$(OBJDIR)/$(CONFIG)/test/core/support/manual_constructor_test.o:  $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
+
+deps_gpr_manual_constructor_test: $(GPR_MANUAL_CONSTRUCTOR_TEST_OBJS:.o=.dep)
+
+ifneq ($(NO_SECURE),true)
+ifneq ($(NO_DEPS),true)
+-include $(GPR_MANUAL_CONSTRUCTOR_TEST_OBJS:.o=.dep)
+endif
+endif
+
+
 GPR_MPSCQ_TEST_SRC = \
     test/core/support/mpscq_test.cc \
 
@@ -10209,38 +10254,6 @@
 endif
 
 
-GPR_STACK_LOCKFREE_TEST_SRC = \
-    test/core/support/stack_lockfree_test.cc \
-
-GPR_STACK_LOCKFREE_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(GPR_STACK_LOCKFREE_TEST_SRC))))
-ifeq ($(NO_SECURE),true)
-
-# You can't build secure targets if you don't have OpenSSL.
-
-$(BINDIR)/$(CONFIG)/gpr_stack_lockfree_test: openssl_dep_error
-
-else
-
-
-
-$(BINDIR)/$(CONFIG)/gpr_stack_lockfree_test: $(GPR_STACK_LOCKFREE_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
-	$(E) "[LD]      Linking $@"
-	$(Q) mkdir -p `dirname $@`
-	$(Q) $(LD) $(LDFLAGS) $(GPR_STACK_LOCKFREE_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBS) $(LDLIBS_SECURE) -o $(BINDIR)/$(CONFIG)/gpr_stack_lockfree_test
-
-endif
-
-$(OBJDIR)/$(CONFIG)/test/core/support/stack_lockfree_test.o:  $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
-
-deps_gpr_stack_lockfree_test: $(GPR_STACK_LOCKFREE_TEST_OBJS:.o=.dep)
-
-ifneq ($(NO_SECURE),true)
-ifneq ($(NO_DEPS),true)
--include $(GPR_STACK_LOCKFREE_TEST_OBJS:.o=.dep)
-endif
-endif
-
-
 GPR_STRING_TEST_SRC = \
     test/core/support/string_test.cc \
 
@@ -11111,6 +11124,38 @@
 endif
 
 
+HISTOGRAM_TEST_SRC = \
+    test/core/util/histogram_test.cc \
+
+HISTOGRAM_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(HISTOGRAM_TEST_SRC))))
+ifeq ($(NO_SECURE),true)
+
+# You can't build secure targets if you don't have OpenSSL.
+
+$(BINDIR)/$(CONFIG)/histogram_test: openssl_dep_error
+
+else
+
+
+
+$(BINDIR)/$(CONFIG)/histogram_test: $(HISTOGRAM_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
+	$(E) "[LD]      Linking $@"
+	$(Q) mkdir -p `dirname $@`
+	$(Q) $(LD) $(LDFLAGS) $(HISTOGRAM_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBS) $(LDLIBS_SECURE) -o $(BINDIR)/$(CONFIG)/histogram_test
+
+endif
+
+$(OBJDIR)/$(CONFIG)/test/core/util/histogram_test.o:  $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
+
+deps_histogram_test: $(HISTOGRAM_TEST_OBJS:.o=.dep)
+
+ifneq ($(NO_SECURE),true)
+ifneq ($(NO_DEPS),true)
+-include $(HISTOGRAM_TEST_OBJS:.o=.dep)
+endif
+endif
+
+
 HPACK_PARSER_FUZZER_TEST_SRC = \
     test/core/transport/chttp2/hpack_parser_fuzzer_test.cc \
 
@@ -16446,6 +16491,92 @@
 $(OBJDIR)/$(CONFIG)/test/cpp/interop/reconnect_interop_server.o: $(GENDIR)/src/proto/grpc/testing/empty.pb.cc $(GENDIR)/src/proto/grpc/testing/empty.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/messages.pb.cc $(GENDIR)/src/proto/grpc/testing/messages.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/test.pb.cc $(GENDIR)/src/proto/grpc/testing/test.grpc.pb.cc
 
 
+REF_COUNTED_PTR_TEST_SRC = \
+    test/core/support/ref_counted_ptr_test.cc \
+
+REF_COUNTED_PTR_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(REF_COUNTED_PTR_TEST_SRC))))
+ifeq ($(NO_SECURE),true)
+
+# You can't build secure targets if you don't have OpenSSL.
+
+$(BINDIR)/$(CONFIG)/ref_counted_ptr_test: openssl_dep_error
+
+else
+
+
+
+
+ifeq ($(NO_PROTOBUF),true)
+
+# You can't build the protoc plugins or protobuf-enabled targets if you don't have protobuf 3.0.0+.
+
+$(BINDIR)/$(CONFIG)/ref_counted_ptr_test: protobuf_dep_error
+
+else
+
+$(BINDIR)/$(CONFIG)/ref_counted_ptr_test: $(PROTOBUF_DEP) $(REF_COUNTED_PTR_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
+	$(E) "[LD]      Linking $@"
+	$(Q) mkdir -p `dirname $@`
+	$(Q) $(LDXX) $(LDFLAGS) $(REF_COUNTED_PTR_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBSXX) $(LDLIBS_PROTOBUF) $(LDLIBS) $(LDLIBS_SECURE) $(GTEST_LIB) -o $(BINDIR)/$(CONFIG)/ref_counted_ptr_test
+
+endif
+
+endif
+
+$(OBJDIR)/$(CONFIG)/test/core/support/ref_counted_ptr_test.o:  $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
+
+deps_ref_counted_ptr_test: $(REF_COUNTED_PTR_TEST_OBJS:.o=.dep)
+
+ifneq ($(NO_SECURE),true)
+ifneq ($(NO_DEPS),true)
+-include $(REF_COUNTED_PTR_TEST_OBJS:.o=.dep)
+endif
+endif
+
+
+REF_COUNTED_TEST_SRC = \
+    test/core/support/ref_counted_test.cc \
+
+REF_COUNTED_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(REF_COUNTED_TEST_SRC))))
+ifeq ($(NO_SECURE),true)
+
+# You can't build secure targets if you don't have OpenSSL.
+
+$(BINDIR)/$(CONFIG)/ref_counted_test: openssl_dep_error
+
+else
+
+
+
+
+ifeq ($(NO_PROTOBUF),true)
+
+# You can't build the protoc plugins or protobuf-enabled targets if you don't have protobuf 3.0.0+.
+
+$(BINDIR)/$(CONFIG)/ref_counted_test: protobuf_dep_error
+
+else
+
+$(BINDIR)/$(CONFIG)/ref_counted_test: $(PROTOBUF_DEP) $(REF_COUNTED_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
+	$(E) "[LD]      Linking $@"
+	$(Q) mkdir -p `dirname $@`
+	$(Q) $(LDXX) $(LDFLAGS) $(REF_COUNTED_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBSXX) $(LDLIBS_PROTOBUF) $(LDLIBS) $(LDLIBS_SECURE) $(GTEST_LIB) -o $(BINDIR)/$(CONFIG)/ref_counted_test
+
+endif
+
+endif
+
+$(OBJDIR)/$(CONFIG)/test/core/support/ref_counted_test.o:  $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
+
+deps_ref_counted_test: $(REF_COUNTED_TEST_OBJS:.o=.dep)
+
+ifneq ($(NO_SECURE),true)
+ifneq ($(NO_DEPS),true)
+-include $(REF_COUNTED_TEST_OBJS:.o=.dep)
+endif
+endif
+
+
 SECURE_AUTH_CONTEXT_TEST_SRC = \
     test/cpp/common/secure_auth_context_test.cc \
 
@@ -17173,49 +17304,6 @@
 endif
 
 
-VECTOR_TEST_SRC = \
-    test/core/support/vector_test.cc \
-
-VECTOR_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(VECTOR_TEST_SRC))))
-ifeq ($(NO_SECURE),true)
-
-# You can't build secure targets if you don't have OpenSSL.
-
-$(BINDIR)/$(CONFIG)/vector_test: openssl_dep_error
-
-else
-
-
-
-
-ifeq ($(NO_PROTOBUF),true)
-
-# You can't build the protoc plugins or protobuf-enabled targets if you don't have protobuf 3.0.0+.
-
-$(BINDIR)/$(CONFIG)/vector_test: protobuf_dep_error
-
-else
-
-$(BINDIR)/$(CONFIG)/vector_test: $(PROTOBUF_DEP) $(VECTOR_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
-	$(E) "[LD]      Linking $@"
-	$(Q) mkdir -p `dirname $@`
-	$(Q) $(LDXX) $(LDFLAGS) $(VECTOR_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBSXX) $(LDLIBS_PROTOBUF) $(LDLIBS) $(LDLIBS_SECURE) $(GTEST_LIB) -o $(BINDIR)/$(CONFIG)/vector_test
-
-endif
-
-endif
-
-$(OBJDIR)/$(CONFIG)/test/core/support/vector_test.o:  $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
-
-deps_vector_test: $(VECTOR_TEST_OBJS:.o=.dep)
-
-ifneq ($(NO_SECURE),true)
-ifneq ($(NO_DEPS),true)
--include $(VECTOR_TEST_OBJS:.o=.dep)
-endif
-endif
-
-
 WRITES_PER_RPC_TEST_SRC = \
     test/cpp/performance/writes_per_rpc_test.cc \
 
diff --git a/README.md b/README.md
index 61479f3..048614a 100644
--- a/README.md
+++ b/README.md
@@ -30,7 +30,6 @@
 | Shared C [core library] | [src/core](src/core)                | 1.6     |
 | C++                     | [src/cpp](src/cpp)                  | 1.6     |
 | Ruby                    | [src/ruby](src/ruby)                | 1.6     |
-| NodeJS                  | [src/node](src/node)                | 1.6     |
 | Python                  | [src/python](src/python)            | 1.6     |
 | PHP                     | [src/php](src/php)                  | 1.6     |
 | C#                      | [src/csharp](src/csharp)            | 1.6     |
@@ -38,7 +37,8 @@
 
 Java source code is in the [grpc-java](http://github.com/grpc/grpc-java)
 repository. Go source code is in the
-[grpc-go](http://github.com/grpc/grpc-go) repository.
+[grpc-go](http://github.com/grpc/grpc-go) repository. NodeJS source code is in the
+[grpc-node](https://github.com/grpc/grpc-node) repository.
 
 See [MANIFEST.md](MANIFEST.md) for a listing of top-level items in the
 repository.
diff --git a/WORKSPACE b/WORKSPACE
index 5f87d68..bf09aa7 100644
--- a/WORKSPACE
+++ b/WORKSPACE
@@ -10,7 +10,7 @@
 
 bind(
     name = "zlib",
-    actual = "@submodule_zlib//:z",
+    actual = "@com_github_madler_zlib//:z",
 )
 
 bind(
@@ -35,22 +35,22 @@
 
 bind(
     name = "cares",
-    actual = "@submodule_cares//:ares",
+    actual = "@com_github_cares_cares//:ares",
 )
 
 bind(
     name = "gtest",
-    actual = "@submodule_gtest//:gtest",
+    actual = "@com_github_google_googletest//:gtest",
 )
 
 bind(
     name = "gmock",
-    actual = "@submodule_gtest//:gmock",
+    actual = "@com_github_google_googletest//:gmock",
 )
 
 bind(
     name = "benchmark",
-    actual = "@submodule_benchmark//:benchmark",
+    actual = "@com_github_google_benchmark//:benchmark",
 )
 
 bind(
@@ -58,47 +58,70 @@
     actual = "@com_github_gflags_gflags//:gflags",
 )
 
-local_repository(
+http_archive(
     name = "boringssl",
-    path = "third_party/boringssl-with-bazel",
+    # on the master-with-bazel branch
+    url = "https://boringssl.googlesource.com/boringssl/+archive/886e7d75368e3f4fab3f4d0d3584e4abfc557755.tar.gz",
 )
 
-new_local_repository(
-    name = "submodule_zlib",
+new_http_archive(
+    name = "com_github_madler_zlib",
     build_file = "third_party/zlib.BUILD",
-    path = "third_party/zlib",
+    strip_prefix = "zlib-cacf7f1d4e3d44d871b605da3b647f07d718623f",
+    url = "https://github.com/madler/zlib/archive/cacf7f1d4e3d44d871b605da3b647f07d718623f.tar.gz",
 )
 
-new_local_repository(
+http_archive(
     name = "com_google_protobuf",
-    build_file = "third_party/protobuf/BUILD",
-    path = "third_party/protobuf",
+    strip_prefix = "protobuf-2761122b810fe8861004ae785cc3ab39f384d342",
+    url = "https://github.com/google/protobuf/archive/2761122b810fe8861004ae785cc3ab39f384d342.tar.gz",
 )
 
-new_local_repository(
-    name = "submodule_gtest",
+new_http_archive(
+    name = "com_github_google_googletest",
     build_file = "third_party/gtest.BUILD",
-    path = "third_party/googletest",
+    strip_prefix = "googletest-ec44c6c1675c25b9827aacd08c02433cccde7780",
+    url = "https://github.com/google/googletest/archive/ec44c6c1675c25b9827aacd08c02433cccde7780.tar.gz",
 )
 
-local_repository(
+http_archive(
     name = "com_github_gflags_gflags",
-    path = "third_party/gflags",
+    strip_prefix = "gflags-30dbc81fb5ffdc98ea9b14b1918bfe4e8779b26e",
+    url = "https://github.com/gflags/gflags/archive/30dbc81fb5ffdc98ea9b14b1918bfe4e8779b26e.tar.gz",
 )
 
-new_local_repository(
-    name = "submodule_benchmark",
-    path = "third_party/benchmark",
+new_http_archive(
+    name = "com_github_google_benchmark",
     build_file = "third_party/benchmark.BUILD",
+    strip_prefix = "benchmark-5b7683f49e1e9223cf9927b24f6fd3d6bd82e3f8",
+    url = "https://github.com/google/benchmark/archive/5b7683f49e1e9223cf9927b24f6fd3d6bd82e3f8.tar.gz",
 )
 
 new_local_repository(
-    name = "submodule_cares",
+    name = "cares_local_files",
+    build_file = "third_party/cares/cares_local_files.BUILD",
     path = "third_party/cares",
-    build_file = "third_party/cares/cares.BUILD",
 )
 
-local_repository(
+new_http_archive(
+    name = "com_github_cares_cares",
+    build_file = "third_party/cares/cares.BUILD",
+    strip_prefix = "c-ares-3be1924221e1326df520f8498d704a5c4c8d0cce",
+    url = "https://github.com/c-ares/c-ares/archive/3be1924221e1326df520f8498d704a5c4c8d0cce.tar.gz",
+)
+
+http_archive(
     name = "com_google_absl",
-    path = "third_party/abseil-cpp",
+    strip_prefix = "abseil-cpp-cc4bed2d74f7c8717e31f9579214ab52a9c9c610",
+    url = "https://github.com/abseil/abseil-cpp/archive/cc4bed2d74f7c8717e31f9579214ab52a9c9c610.tar.gz",
+)
+
+http_archive(
+    name = "bazel_toolchains",
+    urls = [
+        "https://mirror.bazel.build/github.com/bazelbuild/bazel-toolchains/archive/af4681c3d19f063f090222ec3d04108c4e0ca255.tar.gz",
+        "https://github.com/bazelbuild/bazel-toolchains/archive/af4681c3d19f063f090222ec3d04108c4e0ca255.tar.gz",
+    ],
+    strip_prefix = "bazel-toolchains-af4681c3d19f063f090222ec3d04108c4e0ca255",
+    sha256 = "d58bb2d6c8603f600d522b6104d6192a65339aa26cbba9f11ff5c4b36dedb928",
 )
diff --git a/bazel/cc_grpc_library.bzl b/bazel/cc_grpc_library.bzl
index afc5543..94781ed 100644
--- a/bazel/cc_grpc_library.bzl
+++ b/bazel/cc_grpc_library.bzl
@@ -60,10 +60,10 @@
 
     if use_external:
       # when this file is used by non-grpc projects
-      grpc_deps = ["//external:grpc++", "//external:grpc++_codegen_proto",
+      grpc_deps = ["//external:grpc++_codegen_proto",
                    "//external:protobuf"]
     else:
-      grpc_deps = ["//:grpc++", "//:grpc++_codegen_proto", "//external:protobuf"]
+      grpc_deps = ["//:grpc++_codegen_proto", "//external:protobuf"]
 
     native.cc_library(
         name = name,
diff --git a/bazel/grpc_build_system.bzl b/bazel/grpc_build_system.bzl
index b35ca73..2ef8544 100644
--- a/bazel/grpc_build_system.bzl
+++ b/bazel/grpc_build_system.bzl
@@ -23,6 +23,9 @@
 # each change must be ported from one to the other.
 #
 
+# The set of pollers to test against if a test exercises polling
+POLLERS = ['epollex', 'epollsig', 'epoll1', 'poll', 'poll-cv']
+
 def grpc_cc_library(name, srcs = [], public_hdrs = [], hdrs = [],
                     external_deps = [], deps = [], standalone = False,
                     language = "C++", testonly = False, visibility = None,
@@ -33,10 +36,10 @@
   native.cc_library(
     name = name,
     srcs = srcs,
-    defines = select({
-        "//:grpc_no_ares": ["GRPC_ARES=0"],
-	"//conditions:default": [],
-    }),
+    defines = select({"//:grpc_no_ares": ["GRPC_ARES=0"],
+                      "//conditions:default": [],}) +
+              select({"//:remote_execution":  ["GRPC_PORT_ISOLATED_RUNTIME=1"],
+                      "//conditions:default": [],}),
     hdrs = hdrs + public_hdrs,
     deps = deps + ["//external:" + dep for dep in external_deps],
     copts = copts,
@@ -70,19 +73,35 @@
     generate_mock = generate_mock,
   )
 
-def grpc_cc_test(name, srcs = [], deps = [], external_deps = [], args = [], data = [], language = "C++"):
+def grpc_cc_test(name, srcs = [], deps = [], external_deps = [], args = [], data = [], uses_polling = True, language = "C++"):
   copts = []
   if language.upper() == "C":
     copts = ["-std=c99"]
-  native.cc_test(
-    name = name,
-    srcs = srcs,
-    args = args,
-    data = data,
-    deps = deps + ["//external:" + dep for dep in external_deps],
-    copts = copts,
-    linkopts = ["-pthread"],
-  )
+  args = {
+    'name': name,
+    'srcs': srcs,
+    'args': args,
+    'data': data,
+    'deps': deps + ["//external:" + dep for dep in external_deps],
+    'copts': copts,
+    'linkopts': ["-pthread"],
+  }
+  if uses_polling:
+    native.cc_binary(testonly=True, **args)
+    for poller in POLLERS:
+      native.sh_test(
+        name = name + '@poller=' + poller,
+        data = [name],
+        srcs = [
+          '//test/core/util:run_with_poller_sh',
+        ],
+        args = [
+          poller,
+          '$(location %s)' % name
+        ],
+      )
+  else:
+    native.cc_test(**args)
 
 def grpc_cc_binary(name, srcs = [], deps = [], external_deps = [], args = [], data = [], language = "C++", testonly = False, linkshared = False, linkopts = []):
   copts = []
diff --git a/binding.gyp b/binding.gyp
new file mode 100644
index 0000000..cb0a2fb
--- /dev/null
+++ b/binding.gyp
@@ -0,0 +1,994 @@
+# GRPC Node gyp file
+# This currently builds the Node extension and dependencies
+# This file has been automatically generated from a template file.
+# Please look at the templates directory instead.
+# This file can be regenerated from the template by running
+# tools/buildgen/generate_projects.sh
+
+# Copyright 2015 gRPC authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Some of this file is built with the help of
+# https://n8.io/converting-a-c-library-to-gyp/
+{
+  'variables': {
+    'runtime%': 'node',
+    # Some Node installations use the system installation of OpenSSL, and on
+    # some systems, the system OpenSSL still does not have ALPN support. This
+    # will let users recompile gRPC to work without ALPN.
+    'grpc_alpn%': 'true',
+    # Indicates that the library should be built with gcov.
+    'grpc_gcov%': 'false',
+    # Indicates that the library should be built with compatibility for musl
+    # libc, so that it can run on Alpine Linux. This is only necessary if not
+    # building on Alpine Linux
+    'grpc_alpine%': 'false'
+  },
+  'target_defaults': {
+    'configurations': {
+      'Release': {
+        'cflags': [
+            '-O2',
+        ],
+        'defines': [
+            'NDEBUG',
+        ],
+      },
+      'Debug': {
+        'cflags': [
+            '-O0',
+        ],
+        'defines': [
+            '_DEBUG',
+            'DEBUG',
+        ],
+      },
+    },
+    'cflags': [
+        '-g',
+        '-Wall',
+        '-Wextra',
+        '-Werror',
+        '-Wno-long-long',
+        '-Wno-unused-parameter',
+        '-DOSATOMIC_USE_INLINED=1',
+    ],
+    'ldflags': [
+        '-g',
+    ],
+    'cflags_c': [
+      '-Werror',
+      '-std=c99'
+    ],
+    'cflags_cc': [
+      '-Werror',
+      '-std=c++11'
+    ],
+    'include_dirs': [
+      '.',
+      'include'
+    ],
+    'defines': [
+      'GPR_BACKWARDS_COMPATIBILITY_MODE',
+      'GRPC_ARES=0',
+      'GRPC_UV'
+    ],
+    'conditions': [
+      ['grpc_gcov=="true"', {
+        'cflags': [
+            '-O0',
+            '-fprofile-arcs',
+            '-ftest-coverage',
+            '-Wno-return-type',
+        ],
+        'defines': [
+            '_DEBUG',
+            'DEBUG',
+            'GPR_GCOV',
+        ],
+        'ldflags': [
+            '-fprofile-arcs',
+            '-ftest-coverage',
+            '-rdynamic',
+        ],
+      }],
+      ['grpc_alpine=="true"', {
+        'defines': [
+          'GPR_MUSL_LIBC_COMPAT'
+        ]
+      }],
+      ['OS!="win" and runtime=="electron"', {
+        "defines": [
+          'OPENSSL_NO_THREADS'
+        ]
+      }],
+      # This is the condition for using boringssl
+      ['OS=="win" or runtime=="electron"', {
+        "include_dirs": [
+          "third_party/boringssl/include"
+        ],
+        "defines": [
+          'OPENSSL_NO_ASM'
+        ]
+      }, {
+        'conditions': [
+          ["target_arch=='ia32'", {
+             "include_dirs": [ "<(node_root_dir)/deps/openssl/config/piii" ]
+          }],
+          ["target_arch=='x64'", {
+             "include_dirs": [ "<(node_root_dir)/deps/openssl/config/k8" ]
+          }],
+          ["target_arch=='arm'", {
+             "include_dirs": [ "<(node_root_dir)/deps/openssl/config/arm" ]
+          }],
+          ['grpc_alpn=="true"', {
+            'defines': [
+              'TSI_OPENSSL_ALPN_SUPPORT=1'
+            ],
+          }, {
+            'defines': [
+              'TSI_OPENSSL_ALPN_SUPPORT=0'
+            ],
+          }]
+        ],
+        'include_dirs': [
+          '<(node_root_dir)/deps/openssl/openssl/include',
+        ]
+      }],
+      ['OS == "win"', {
+        "include_dirs": [
+          "third_party/zlib",
+          "third_party/cares/cares"
+        ],
+        "defines": [
+          '_WIN32_WINNT=0x0600',
+          'WIN32_LEAN_AND_MEAN',
+          '_HAS_EXCEPTIONS=0',
+          'UNICODE',
+          '_UNICODE',
+          'NOMINMAX',
+        ],
+        "msvs_settings": {
+          'VCCLCompilerTool': {
+            'RuntimeLibrary': 1, # static debug
+          }
+        },
+        "libraries": [
+          "ws2_32"
+        ]
+      }, { # OS != "win"
+        'include_dirs': [
+          '<(node_root_dir)/deps/zlib',
+          '<(node_root_dir)/deps/cares/include'
+        ]
+      }],
+      ['OS == "mac"', {
+        'xcode_settings': {
+          'OTHER_CFLAGS': [
+              '-g',
+              '-Wall',
+              '-Wextra',
+              '-Werror',
+              '-Wno-long-long',
+              '-Wno-unused-parameter',
+              '-DOSATOMIC_USE_INLINED=1',
+          ],
+          'OTHER_CPLUSPLUSFLAGS': [
+              '-g',
+              '-Wall',
+              '-Wextra',
+              '-Werror',
+              '-Wno-long-long',
+              '-Wno-unused-parameter',
+              '-DOSATOMIC_USE_INLINED=1',
+            '-stdlib=libc++',
+            '-std=c++11',
+            '-Wno-error=deprecated-declarations'
+          ],
+        },
+      }]
+    ]
+  },
+  'conditions': [
+    ['OS=="win" or runtime=="electron"', {
+      'targets': [
+        {
+          'target_name': 'boringssl',
+          'product_prefix': 'lib',
+          'type': 'static_library',
+          'dependencies': [
+          ],
+          'sources': [
+            'src/boringssl/err_data.c',
+            'third_party/boringssl/crypto/aes/aes.c',
+            'third_party/boringssl/crypto/aes/key_wrap.c',
+            'third_party/boringssl/crypto/aes/mode_wrappers.c',
+            'third_party/boringssl/crypto/asn1/a_bitstr.c',
+            'third_party/boringssl/crypto/asn1/a_bool.c',
+            'third_party/boringssl/crypto/asn1/a_d2i_fp.c',
+            'third_party/boringssl/crypto/asn1/a_dup.c',
+            'third_party/boringssl/crypto/asn1/a_enum.c',
+            'third_party/boringssl/crypto/asn1/a_gentm.c',
+            'third_party/boringssl/crypto/asn1/a_i2d_fp.c',
+            'third_party/boringssl/crypto/asn1/a_int.c',
+            'third_party/boringssl/crypto/asn1/a_mbstr.c',
+            'third_party/boringssl/crypto/asn1/a_object.c',
+            'third_party/boringssl/crypto/asn1/a_octet.c',
+            'third_party/boringssl/crypto/asn1/a_print.c',
+            'third_party/boringssl/crypto/asn1/a_strnid.c',
+            'third_party/boringssl/crypto/asn1/a_time.c',
+            'third_party/boringssl/crypto/asn1/a_type.c',
+            'third_party/boringssl/crypto/asn1/a_utctm.c',
+            'third_party/boringssl/crypto/asn1/a_utf8.c',
+            'third_party/boringssl/crypto/asn1/asn1_lib.c',
+            'third_party/boringssl/crypto/asn1/asn1_par.c',
+            'third_party/boringssl/crypto/asn1/asn_pack.c',
+            'third_party/boringssl/crypto/asn1/f_enum.c',
+            'third_party/boringssl/crypto/asn1/f_int.c',
+            'third_party/boringssl/crypto/asn1/f_string.c',
+            'third_party/boringssl/crypto/asn1/t_bitst.c',
+            'third_party/boringssl/crypto/asn1/tasn_dec.c',
+            'third_party/boringssl/crypto/asn1/tasn_enc.c',
+            'third_party/boringssl/crypto/asn1/tasn_fre.c',
+            'third_party/boringssl/crypto/asn1/tasn_new.c',
+            'third_party/boringssl/crypto/asn1/tasn_typ.c',
+            'third_party/boringssl/crypto/asn1/tasn_utl.c',
+            'third_party/boringssl/crypto/asn1/time_support.c',
+            'third_party/boringssl/crypto/asn1/x_bignum.c',
+            'third_party/boringssl/crypto/asn1/x_long.c',
+            'third_party/boringssl/crypto/base64/base64.c',
+            'third_party/boringssl/crypto/bio/bio.c',
+            'third_party/boringssl/crypto/bio/bio_mem.c',
+            'third_party/boringssl/crypto/bio/connect.c',
+            'third_party/boringssl/crypto/bio/fd.c',
+            'third_party/boringssl/crypto/bio/file.c',
+            'third_party/boringssl/crypto/bio/hexdump.c',
+            'third_party/boringssl/crypto/bio/pair.c',
+            'third_party/boringssl/crypto/bio/printf.c',
+            'third_party/boringssl/crypto/bio/socket.c',
+            'third_party/boringssl/crypto/bio/socket_helper.c',
+            'third_party/boringssl/crypto/bn/add.c',
+            'third_party/boringssl/crypto/bn/asm/x86_64-gcc.c',
+            'third_party/boringssl/crypto/bn/bn.c',
+            'third_party/boringssl/crypto/bn/bn_asn1.c',
+            'third_party/boringssl/crypto/bn/cmp.c',
+            'third_party/boringssl/crypto/bn/convert.c',
+            'third_party/boringssl/crypto/bn/ctx.c',
+            'third_party/boringssl/crypto/bn/div.c',
+            'third_party/boringssl/crypto/bn/exponentiation.c',
+            'third_party/boringssl/crypto/bn/gcd.c',
+            'third_party/boringssl/crypto/bn/generic.c',
+            'third_party/boringssl/crypto/bn/kronecker.c',
+            'third_party/boringssl/crypto/bn/montgomery.c',
+            'third_party/boringssl/crypto/bn/montgomery_inv.c',
+            'third_party/boringssl/crypto/bn/mul.c',
+            'third_party/boringssl/crypto/bn/prime.c',
+            'third_party/boringssl/crypto/bn/random.c',
+            'third_party/boringssl/crypto/bn/rsaz_exp.c',
+            'third_party/boringssl/crypto/bn/shift.c',
+            'third_party/boringssl/crypto/bn/sqrt.c',
+            'third_party/boringssl/crypto/buf/buf.c',
+            'third_party/boringssl/crypto/bytestring/asn1_compat.c',
+            'third_party/boringssl/crypto/bytestring/ber.c',
+            'third_party/boringssl/crypto/bytestring/cbb.c',
+            'third_party/boringssl/crypto/bytestring/cbs.c',
+            'third_party/boringssl/crypto/chacha/chacha.c',
+            'third_party/boringssl/crypto/cipher/aead.c',
+            'third_party/boringssl/crypto/cipher/cipher.c',
+            'third_party/boringssl/crypto/cipher/derive_key.c',
+            'third_party/boringssl/crypto/cipher/e_aes.c',
+            'third_party/boringssl/crypto/cipher/e_chacha20poly1305.c',
+            'third_party/boringssl/crypto/cipher/e_des.c',
+            'third_party/boringssl/crypto/cipher/e_null.c',
+            'third_party/boringssl/crypto/cipher/e_rc2.c',
+            'third_party/boringssl/crypto/cipher/e_rc4.c',
+            'third_party/boringssl/crypto/cipher/e_ssl3.c',
+            'third_party/boringssl/crypto/cipher/e_tls.c',
+            'third_party/boringssl/crypto/cipher/tls_cbc.c',
+            'third_party/boringssl/crypto/cmac/cmac.c',
+            'third_party/boringssl/crypto/conf/conf.c',
+            'third_party/boringssl/crypto/cpu-aarch64-linux.c',
+            'third_party/boringssl/crypto/cpu-arm-linux.c',
+            'third_party/boringssl/crypto/cpu-arm.c',
+            'third_party/boringssl/crypto/cpu-intel.c',
+            'third_party/boringssl/crypto/cpu-ppc64le.c',
+            'third_party/boringssl/crypto/crypto.c',
+            'third_party/boringssl/crypto/curve25519/curve25519.c',
+            'third_party/boringssl/crypto/curve25519/spake25519.c',
+            'third_party/boringssl/crypto/curve25519/x25519-x86_64.c',
+            'third_party/boringssl/crypto/des/des.c',
+            'third_party/boringssl/crypto/dh/check.c',
+            'third_party/boringssl/crypto/dh/dh.c',
+            'third_party/boringssl/crypto/dh/dh_asn1.c',
+            'third_party/boringssl/crypto/dh/params.c',
+            'third_party/boringssl/crypto/digest/digest.c',
+            'third_party/boringssl/crypto/digest/digests.c',
+            'third_party/boringssl/crypto/dsa/dsa.c',
+            'third_party/boringssl/crypto/dsa/dsa_asn1.c',
+            'third_party/boringssl/crypto/ec/ec.c',
+            'third_party/boringssl/crypto/ec/ec_asn1.c',
+            'third_party/boringssl/crypto/ec/ec_key.c',
+            'third_party/boringssl/crypto/ec/ec_montgomery.c',
+            'third_party/boringssl/crypto/ec/oct.c',
+            'third_party/boringssl/crypto/ec/p224-64.c',
+            'third_party/boringssl/crypto/ec/p256-64.c',
+            'third_party/boringssl/crypto/ec/p256-x86_64.c',
+            'third_party/boringssl/crypto/ec/simple.c',
+            'third_party/boringssl/crypto/ec/util-64.c',
+            'third_party/boringssl/crypto/ec/wnaf.c',
+            'third_party/boringssl/crypto/ecdh/ecdh.c',
+            'third_party/boringssl/crypto/ecdsa/ecdsa.c',
+            'third_party/boringssl/crypto/ecdsa/ecdsa_asn1.c',
+            'third_party/boringssl/crypto/engine/engine.c',
+            'third_party/boringssl/crypto/err/err.c',
+            'third_party/boringssl/crypto/evp/digestsign.c',
+            'third_party/boringssl/crypto/evp/evp.c',
+            'third_party/boringssl/crypto/evp/evp_asn1.c',
+            'third_party/boringssl/crypto/evp/evp_ctx.c',
+            'third_party/boringssl/crypto/evp/p_dsa_asn1.c',
+            'third_party/boringssl/crypto/evp/p_ec.c',
+            'third_party/boringssl/crypto/evp/p_ec_asn1.c',
+            'third_party/boringssl/crypto/evp/p_rsa.c',
+            'third_party/boringssl/crypto/evp/p_rsa_asn1.c',
+            'third_party/boringssl/crypto/evp/pbkdf.c',
+            'third_party/boringssl/crypto/evp/print.c',
+            'third_party/boringssl/crypto/evp/sign.c',
+            'third_party/boringssl/crypto/ex_data.c',
+            'third_party/boringssl/crypto/hkdf/hkdf.c',
+            'third_party/boringssl/crypto/hmac/hmac.c',
+            'third_party/boringssl/crypto/lhash/lhash.c',
+            'third_party/boringssl/crypto/md4/md4.c',
+            'third_party/boringssl/crypto/md5/md5.c',
+            'third_party/boringssl/crypto/mem.c',
+            'third_party/boringssl/crypto/modes/cbc.c',
+            'third_party/boringssl/crypto/modes/cfb.c',
+            'third_party/boringssl/crypto/modes/ctr.c',
+            'third_party/boringssl/crypto/modes/gcm.c',
+            'third_party/boringssl/crypto/modes/ofb.c',
+            'third_party/boringssl/crypto/modes/polyval.c',
+            'third_party/boringssl/crypto/obj/obj.c',
+            'third_party/boringssl/crypto/obj/obj_xref.c',
+            'third_party/boringssl/crypto/pem/pem_all.c',
+            'third_party/boringssl/crypto/pem/pem_info.c',
+            'third_party/boringssl/crypto/pem/pem_lib.c',
+            'third_party/boringssl/crypto/pem/pem_oth.c',
+            'third_party/boringssl/crypto/pem/pem_pk8.c',
+            'third_party/boringssl/crypto/pem/pem_pkey.c',
+            'third_party/boringssl/crypto/pem/pem_x509.c',
+            'third_party/boringssl/crypto/pem/pem_xaux.c',
+            'third_party/boringssl/crypto/pkcs8/p5_pbev2.c',
+            'third_party/boringssl/crypto/pkcs8/p8_pkey.c',
+            'third_party/boringssl/crypto/pkcs8/pkcs8.c',
+            'third_party/boringssl/crypto/poly1305/poly1305.c',
+            'third_party/boringssl/crypto/poly1305/poly1305_arm.c',
+            'third_party/boringssl/crypto/poly1305/poly1305_vec.c',
+            'third_party/boringssl/crypto/pool/pool.c',
+            'third_party/boringssl/crypto/rand/deterministic.c',
+            'third_party/boringssl/crypto/rand/fuchsia.c',
+            'third_party/boringssl/crypto/rand/rand.c',
+            'third_party/boringssl/crypto/rand/urandom.c',
+            'third_party/boringssl/crypto/rand/windows.c',
+            'third_party/boringssl/crypto/rc4/rc4.c',
+            'third_party/boringssl/crypto/refcount_c11.c',
+            'third_party/boringssl/crypto/refcount_lock.c',
+            'third_party/boringssl/crypto/rsa/blinding.c',
+            'third_party/boringssl/crypto/rsa/padding.c',
+            'third_party/boringssl/crypto/rsa/rsa.c',
+            'third_party/boringssl/crypto/rsa/rsa_asn1.c',
+            'third_party/boringssl/crypto/rsa/rsa_impl.c',
+            'third_party/boringssl/crypto/sha/sha1-altivec.c',
+            'third_party/boringssl/crypto/sha/sha1.c',
+            'third_party/boringssl/crypto/sha/sha256.c',
+            'third_party/boringssl/crypto/sha/sha512.c',
+            'third_party/boringssl/crypto/stack/stack.c',
+            'third_party/boringssl/crypto/thread.c',
+            'third_party/boringssl/crypto/thread_none.c',
+            'third_party/boringssl/crypto/thread_pthread.c',
+            'third_party/boringssl/crypto/thread_win.c',
+            'third_party/boringssl/crypto/x509/a_digest.c',
+            'third_party/boringssl/crypto/x509/a_sign.c',
+            'third_party/boringssl/crypto/x509/a_strex.c',
+            'third_party/boringssl/crypto/x509/a_verify.c',
+            'third_party/boringssl/crypto/x509/algorithm.c',
+            'third_party/boringssl/crypto/x509/asn1_gen.c',
+            'third_party/boringssl/crypto/x509/by_dir.c',
+            'third_party/boringssl/crypto/x509/by_file.c',
+            'third_party/boringssl/crypto/x509/i2d_pr.c',
+            'third_party/boringssl/crypto/x509/pkcs7.c',
+            'third_party/boringssl/crypto/x509/rsa_pss.c',
+            'third_party/boringssl/crypto/x509/t_crl.c',
+            'third_party/boringssl/crypto/x509/t_req.c',
+            'third_party/boringssl/crypto/x509/t_x509.c',
+            'third_party/boringssl/crypto/x509/t_x509a.c',
+            'third_party/boringssl/crypto/x509/x509.c',
+            'third_party/boringssl/crypto/x509/x509_att.c',
+            'third_party/boringssl/crypto/x509/x509_cmp.c',
+            'third_party/boringssl/crypto/x509/x509_d2.c',
+            'third_party/boringssl/crypto/x509/x509_def.c',
+            'third_party/boringssl/crypto/x509/x509_ext.c',
+            'third_party/boringssl/crypto/x509/x509_lu.c',
+            'third_party/boringssl/crypto/x509/x509_obj.c',
+            'third_party/boringssl/crypto/x509/x509_r2x.c',
+            'third_party/boringssl/crypto/x509/x509_req.c',
+            'third_party/boringssl/crypto/x509/x509_set.c',
+            'third_party/boringssl/crypto/x509/x509_trs.c',
+            'third_party/boringssl/crypto/x509/x509_txt.c',
+            'third_party/boringssl/crypto/x509/x509_v3.c',
+            'third_party/boringssl/crypto/x509/x509_vfy.c',
+            'third_party/boringssl/crypto/x509/x509_vpm.c',
+            'third_party/boringssl/crypto/x509/x509cset.c',
+            'third_party/boringssl/crypto/x509/x509name.c',
+            'third_party/boringssl/crypto/x509/x509rset.c',
+            'third_party/boringssl/crypto/x509/x509spki.c',
+            'third_party/boringssl/crypto/x509/x509type.c',
+            'third_party/boringssl/crypto/x509/x_algor.c',
+            'third_party/boringssl/crypto/x509/x_all.c',
+            'third_party/boringssl/crypto/x509/x_attrib.c',
+            'third_party/boringssl/crypto/x509/x_crl.c',
+            'third_party/boringssl/crypto/x509/x_exten.c',
+            'third_party/boringssl/crypto/x509/x_info.c',
+            'third_party/boringssl/crypto/x509/x_name.c',
+            'third_party/boringssl/crypto/x509/x_pkey.c',
+            'third_party/boringssl/crypto/x509/x_pubkey.c',
+            'third_party/boringssl/crypto/x509/x_req.c',
+            'third_party/boringssl/crypto/x509/x_sig.c',
+            'third_party/boringssl/crypto/x509/x_spki.c',
+            'third_party/boringssl/crypto/x509/x_val.c',
+            'third_party/boringssl/crypto/x509/x_x509.c',
+            'third_party/boringssl/crypto/x509/x_x509a.c',
+            'third_party/boringssl/crypto/x509v3/pcy_cache.c',
+            'third_party/boringssl/crypto/x509v3/pcy_data.c',
+            'third_party/boringssl/crypto/x509v3/pcy_lib.c',
+            'third_party/boringssl/crypto/x509v3/pcy_map.c',
+            'third_party/boringssl/crypto/x509v3/pcy_node.c',
+            'third_party/boringssl/crypto/x509v3/pcy_tree.c',
+            'third_party/boringssl/crypto/x509v3/v3_akey.c',
+            'third_party/boringssl/crypto/x509v3/v3_akeya.c',
+            'third_party/boringssl/crypto/x509v3/v3_alt.c',
+            'third_party/boringssl/crypto/x509v3/v3_bcons.c',
+            'third_party/boringssl/crypto/x509v3/v3_bitst.c',
+            'third_party/boringssl/crypto/x509v3/v3_conf.c',
+            'third_party/boringssl/crypto/x509v3/v3_cpols.c',
+            'third_party/boringssl/crypto/x509v3/v3_crld.c',
+            'third_party/boringssl/crypto/x509v3/v3_enum.c',
+            'third_party/boringssl/crypto/x509v3/v3_extku.c',
+            'third_party/boringssl/crypto/x509v3/v3_genn.c',
+            'third_party/boringssl/crypto/x509v3/v3_ia5.c',
+            'third_party/boringssl/crypto/x509v3/v3_info.c',
+            'third_party/boringssl/crypto/x509v3/v3_int.c',
+            'third_party/boringssl/crypto/x509v3/v3_lib.c',
+            'third_party/boringssl/crypto/x509v3/v3_ncons.c',
+            'third_party/boringssl/crypto/x509v3/v3_pci.c',
+            'third_party/boringssl/crypto/x509v3/v3_pcia.c',
+            'third_party/boringssl/crypto/x509v3/v3_pcons.c',
+            'third_party/boringssl/crypto/x509v3/v3_pku.c',
+            'third_party/boringssl/crypto/x509v3/v3_pmaps.c',
+            'third_party/boringssl/crypto/x509v3/v3_prn.c',
+            'third_party/boringssl/crypto/x509v3/v3_purp.c',
+            'third_party/boringssl/crypto/x509v3/v3_skey.c',
+            'third_party/boringssl/crypto/x509v3/v3_sxnet.c',
+            'third_party/boringssl/crypto/x509v3/v3_utl.c',
+            'third_party/boringssl/ssl/bio_ssl.c',
+            'third_party/boringssl/ssl/custom_extensions.c',
+            'third_party/boringssl/ssl/d1_both.c',
+            'third_party/boringssl/ssl/d1_lib.c',
+            'third_party/boringssl/ssl/d1_pkt.c',
+            'third_party/boringssl/ssl/d1_srtp.c',
+            'third_party/boringssl/ssl/dtls_method.c',
+            'third_party/boringssl/ssl/dtls_record.c',
+            'third_party/boringssl/ssl/handshake_client.c',
+            'third_party/boringssl/ssl/handshake_server.c',
+            'third_party/boringssl/ssl/s3_both.c',
+            'third_party/boringssl/ssl/s3_lib.c',
+            'third_party/boringssl/ssl/s3_pkt.c',
+            'third_party/boringssl/ssl/ssl_aead_ctx.c',
+            'third_party/boringssl/ssl/ssl_asn1.c',
+            'third_party/boringssl/ssl/ssl_buffer.c',
+            'third_party/boringssl/ssl/ssl_cert.c',
+            'third_party/boringssl/ssl/ssl_cipher.c',
+            'third_party/boringssl/ssl/ssl_ecdh.c',
+            'third_party/boringssl/ssl/ssl_file.c',
+            'third_party/boringssl/ssl/ssl_lib.c',
+            'third_party/boringssl/ssl/ssl_privkey.c',
+            'third_party/boringssl/ssl/ssl_privkey_cc.cc',
+            'third_party/boringssl/ssl/ssl_session.c',
+            'third_party/boringssl/ssl/ssl_stat.c',
+            'third_party/boringssl/ssl/ssl_transcript.c',
+            'third_party/boringssl/ssl/ssl_x509.c',
+            'third_party/boringssl/ssl/t1_enc.c',
+            'third_party/boringssl/ssl/t1_lib.c',
+            'third_party/boringssl/ssl/tls13_both.c',
+            'third_party/boringssl/ssl/tls13_client.c',
+            'third_party/boringssl/ssl/tls13_enc.c',
+            'third_party/boringssl/ssl/tls13_server.c',
+            'third_party/boringssl/ssl/tls_method.c',
+            'third_party/boringssl/ssl/tls_record.c',
+          ],
+          'conditions': [
+            ['OS == "mac"', {
+              'xcode_settings': {
+                'MACOSX_DEPLOYMENT_TARGET': '10.9'
+              }
+            }]
+          ]
+        },
+      ],
+    }],
+    ['OS == "win" and runtime!="electron"', {
+      'targets': [
+        {
+          # IMPORTANT WINDOWS BUILD INFORMATION
+          # This library does not build on Windows without modifying the Node
+          # development packages that node-gyp downloads in order to build.
+          # Due to https://github.com/nodejs/node/issues/4932, the headers for
+          # BoringSSL conflict with the OpenSSL headers included by default
+          # when including the Node headers. The remedy for this is to remove
+          # the OpenSSL headers, from the downloaded Node development package,
+          # which is typically located in `.node-gyp` in your home directory.
+          #
+          # This is not true of Electron, which does not have OpenSSL headers.
+          'target_name': 'WINDOWS_BUILD_WARNING',
+          'rules': [
+            {
+              'rule_name': 'WINDOWS_BUILD_WARNING',
+              'extension': 'S',
+              'inputs': [
+                'package.json'
+              ],
+              'outputs': [
+                'ignore_this_part'
+              ],
+              'action': ['echo', 'IMPORTANT: Due to https://github.com/nodejs/node/issues/4932, to build this library on Windows, you must first remove <(node_root_dir)/include/node/openssl/']
+            }
+          ]
+        },
+      ]
+    }],
+    ['OS == "win"', {
+      'targets': [
+        # Only want to compile zlib under Windows
+        {
+          'target_name': 'z',
+          'product_prefix': 'lib',
+          'type': 'static_library',
+          'dependencies': [
+          ],
+          'sources': [
+            'third_party/zlib/adler32.c',
+            'third_party/zlib/compress.c',
+            'third_party/zlib/crc32.c',
+            'third_party/zlib/deflate.c',
+            'third_party/zlib/gzclose.c',
+            'third_party/zlib/gzlib.c',
+            'third_party/zlib/gzread.c',
+            'third_party/zlib/gzwrite.c',
+            'third_party/zlib/infback.c',
+            'third_party/zlib/inffast.c',
+            'third_party/zlib/inflate.c',
+            'third_party/zlib/inftrees.c',
+            'third_party/zlib/trees.c',
+            'third_party/zlib/uncompr.c',
+            'third_party/zlib/zutil.c',
+          ]
+        },
+      ]
+    }]
+  ],
+  'targets': [
+    {
+      'target_name': 'gpr',
+      'product_prefix': 'lib',
+      'type': 'static_library',
+      'dependencies': [
+      ],
+      'sources': [
+        'src/core/lib/profiling/basic_timers.c',
+        'src/core/lib/profiling/stap_timers.c',
+        'src/core/lib/support/alloc.c',
+        'src/core/lib/support/arena.c',
+        'src/core/lib/support/atm.c',
+        'src/core/lib/support/avl.c',
+        'src/core/lib/support/backoff.c',
+        'src/core/lib/support/cmdline.c',
+        'src/core/lib/support/cpu_iphone.c',
+        'src/core/lib/support/cpu_linux.c',
+        'src/core/lib/support/cpu_posix.c',
+        'src/core/lib/support/cpu_windows.c',
+        'src/core/lib/support/env_linux.c',
+        'src/core/lib/support/env_posix.c',
+        'src/core/lib/support/env_windows.c',
+        'src/core/lib/support/fork.c',
+        'src/core/lib/support/histogram.c',
+        'src/core/lib/support/host_port.c',
+        'src/core/lib/support/log.c',
+        'src/core/lib/support/log_android.c',
+        '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/stack_lockfree.c',
+        'src/core/lib/support/string.c',
+        'src/core/lib/support/string_posix.c',
+        'src/core/lib/support/string_util_windows.c',
+        'src/core/lib/support/string_windows.c',
+        'src/core/lib/support/subprocess_posix.c',
+        'src/core/lib/support/subprocess_windows.c',
+        'src/core/lib/support/sync.c',
+        'src/core/lib/support/sync_posix.c',
+        'src/core/lib/support/sync_windows.c',
+        'src/core/lib/support/thd.c',
+        'src/core/lib/support/thd_posix.c',
+        'src/core/lib/support/thd_windows.c',
+        'src/core/lib/support/time.c',
+        'src/core/lib/support/time_posix.c',
+        'src/core/lib/support/time_precise.c',
+        'src/core/lib/support/time_windows.c',
+        'src/core/lib/support/tls_pthread.c',
+        'src/core/lib/support/tmpfile_msys.c',
+        'src/core/lib/support/tmpfile_posix.c',
+        'src/core/lib/support/tmpfile_windows.c',
+        'src/core/lib/support/wrap_memcpy.c',
+      ],
+      'conditions': [
+        ['OS == "mac"', {
+          'xcode_settings': {
+            'MACOSX_DEPLOYMENT_TARGET': '10.9'
+          }
+        }]
+      ]
+    },
+    {
+      'target_name': 'grpc',
+      'product_prefix': 'lib',
+      'type': 'static_library',
+      'dependencies': [
+        'gpr',
+      ],
+      'sources': [
+        'src/core/lib/surface/init.c',
+        '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/connected_channel.c',
+        'src/core/lib/channel/handshaker.c',
+        'src/core/lib/channel/handshaker_factory.c',
+        'src/core/lib/channel/handshaker_registry.c',
+        'src/core/lib/compression/compression.c',
+        'src/core/lib/compression/message_compress.c',
+        'src/core/lib/compression/stream_compression.c',
+        'src/core/lib/compression/stream_compression_gzip.c',
+        'src/core/lib/compression/stream_compression_identity.c',
+        'src/core/lib/debug/stats.c',
+        'src/core/lib/debug/stats_data.c',
+        'src/core/lib/http/format_request.c',
+        'src/core/lib/http/httpcli.c',
+        'src/core/lib/http/parser.c',
+        'src/core/lib/iomgr/call_combiner.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_uv.c',
+        'src/core/lib/iomgr/endpoint_pair_windows.c',
+        'src/core/lib/iomgr/error.c',
+        'src/core/lib/iomgr/ev_epoll1_linux.c',
+        'src/core/lib/iomgr/ev_epollex_linux.c',
+        'src/core/lib/iomgr/ev_epollsig_linux.c',
+        'src/core/lib/iomgr/ev_poll_posix.c',
+        'src/core/lib/iomgr/ev_posix.c',
+        'src/core/lib/iomgr/ev_windows.c',
+        'src/core/lib/iomgr/exec_ctx.c',
+        'src/core/lib/iomgr/executor.c',
+        'src/core/lib/iomgr/fork_posix.c',
+        'src/core/lib/iomgr/fork_windows.c',
+        'src/core/lib/iomgr/gethostname_fallback.c',
+        'src/core/lib/iomgr/gethostname_host_name_max.c',
+        'src/core/lib/iomgr/gethostname_sysconf.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_uv.c',
+        'src/core/lib/iomgr/iomgr_windows.c',
+        'src/core/lib/iomgr/is_epollexclusive_available.c',
+        'src/core/lib/iomgr/load_file.c',
+        'src/core/lib/iomgr/lockfree_event.c',
+        'src/core/lib/iomgr/network_status_tracker.c',
+        'src/core/lib/iomgr/polling_entity.c',
+        'src/core/lib/iomgr/pollset_set_uv.c',
+        'src/core/lib/iomgr/pollset_set_windows.c',
+        'src/core/lib/iomgr/pollset_uv.c',
+        'src/core/lib/iomgr/pollset_windows.c',
+        'src/core/lib/iomgr/resolve_address_posix.c',
+        'src/core/lib/iomgr/resolve_address_uv.c',
+        'src/core/lib/iomgr/resolve_address_windows.c',
+        'src/core/lib/iomgr/resource_quota.c',
+        'src/core/lib/iomgr/sockaddr_utils.c',
+        'src/core/lib/iomgr/socket_factory_posix.c',
+        'src/core/lib/iomgr/socket_mutator.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_utils_uv.c',
+        'src/core/lib/iomgr/socket_utils_windows.c',
+        'src/core/lib/iomgr/socket_windows.c',
+        'src/core/lib/iomgr/tcp_client_posix.c',
+        'src/core/lib/iomgr/tcp_client_uv.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_utils_posix_common.c',
+        'src/core/lib/iomgr/tcp_server_utils_posix_ifaddrs.c',
+        'src/core/lib/iomgr/tcp_server_utils_posix_noifaddrs.c',
+        'src/core/lib/iomgr/tcp_server_uv.c',
+        'src/core/lib/iomgr/tcp_server_windows.c',
+        'src/core/lib/iomgr/tcp_uv.c',
+        'src/core/lib/iomgr/tcp_windows.c',
+        'src/core/lib/iomgr/time_averaged_stats.c',
+        'src/core/lib/iomgr/timer_generic.c',
+        'src/core/lib/iomgr/timer_heap.c',
+        'src/core/lib/iomgr/timer_manager.c',
+        'src/core/lib/iomgr/timer_uv.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_cv.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/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/slice/b64.c',
+        'src/core/lib/slice/percent_encoding.c',
+        'src/core/lib/slice/slice.c',
+        'src/core/lib/slice/slice_buffer.c',
+        'src/core/lib/slice/slice_hash_table.c',
+        'src/core/lib/slice/slice_intern.c',
+        'src/core/lib/slice/slice_string_helpers.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/completion_queue_factory.c',
+        'src/core/lib/surface/event_string.c',
+        'src/core/lib/surface/lame_client.cc',
+        '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/bdp_estimator.c',
+        'src/core/lib/transport/byte_stream.c',
+        'src/core/lib/transport/connectivity_state.c',
+        'src/core/lib/transport/error_utils.c',
+        'src/core/lib/transport/metadata.c',
+        'src/core/lib/transport/metadata_batch.c',
+        'src/core/lib/transport/pid_controller.c',
+        'src/core/lib/transport/service_config.c',
+        'src/core/lib/transport/static_metadata.c',
+        'src/core/lib/transport/status_conversion.c',
+        'src/core/lib/transport/timeout_encoding.c',
+        'src/core/lib/transport/transport.c',
+        'src/core/lib/transport/transport_op_string.c',
+        'src/core/lib/debug/trace.c',
+        'src/core/ext/transport/chttp2/server/secure/server_secure_chttp2.c',
+        'src/core/ext/transport/chttp2/transport/bin_decoder.c',
+        'src/core/ext/transport/chttp2/transport/bin_encoder.c',
+        'src/core/ext/transport/chttp2/transport/chttp2_plugin.c',
+        'src/core/ext/transport/chttp2/transport/chttp2_transport.c',
+        'src/core/ext/transport/chttp2/transport/flow_control.c',
+        'src/core/ext/transport/chttp2/transport/frame_data.c',
+        'src/core/ext/transport/chttp2/transport/frame_goaway.c',
+        'src/core/ext/transport/chttp2/transport/frame_ping.c',
+        'src/core/ext/transport/chttp2/transport/frame_rst_stream.c',
+        'src/core/ext/transport/chttp2/transport/frame_settings.c',
+        'src/core/ext/transport/chttp2/transport/frame_window_update.c',
+        'src/core/ext/transport/chttp2/transport/hpack_encoder.c',
+        'src/core/ext/transport/chttp2/transport/hpack_parser.c',
+        'src/core/ext/transport/chttp2/transport/hpack_table.c',
+        'src/core/ext/transport/chttp2/transport/http2_settings.c',
+        'src/core/ext/transport/chttp2/transport/huffsyms.c',
+        'src/core/ext/transport/chttp2/transport/incoming_metadata.c',
+        'src/core/ext/transport/chttp2/transport/parsing.c',
+        'src/core/ext/transport/chttp2/transport/stream_lists.c',
+        'src/core/ext/transport/chttp2/transport/stream_map.c',
+        'src/core/ext/transport/chttp2/transport/varint.c',
+        'src/core/ext/transport/chttp2/transport/writing.c',
+        'src/core/ext/transport/chttp2/alpn/alpn.c',
+        'src/core/ext/filters/http/client/http_client_filter.c',
+        'src/core/ext/filters/http/http_filters_plugin.c',
+        'src/core/ext/filters/http/message_compress/message_compress_filter.c',
+        'src/core/ext/filters/http/server/http_server_filter.c',
+        'src/core/lib/http/httpcli_security_connector.c',
+        'src/core/lib/security/context/security_context.c',
+        'src/core/lib/security/credentials/composite/composite_credentials.c',
+        'src/core/lib/security/credentials/credentials.c',
+        'src/core/lib/security/credentials/credentials_metadata.c',
+        'src/core/lib/security/credentials/fake/fake_credentials.c',
+        'src/core/lib/security/credentials/google_default/credentials_generic.c',
+        'src/core/lib/security/credentials/google_default/google_default_credentials.c',
+        'src/core/lib/security/credentials/iam/iam_credentials.c',
+        'src/core/lib/security/credentials/jwt/json_token.c',
+        'src/core/lib/security/credentials/jwt/jwt_credentials.c',
+        'src/core/lib/security/credentials/jwt/jwt_verifier.c',
+        'src/core/lib/security/credentials/oauth2/oauth2_credentials.c',
+        'src/core/lib/security/credentials/plugin/plugin_credentials.c',
+        'src/core/lib/security/credentials/ssl/ssl_credentials.c',
+        'src/core/lib/security/transport/client_auth_filter.c',
+        'src/core/lib/security/transport/lb_targets_info.c',
+        'src/core/lib/security/transport/secure_endpoint.c',
+        'src/core/lib/security/transport/security_connector.c',
+        'src/core/lib/security/transport/security_handshaker.c',
+        'src/core/lib/security/transport/server_auth_filter.c',
+        'src/core/lib/security/transport/tsi_error.c',
+        'src/core/lib/security/util/json_util.c',
+        'src/core/lib/surface/init_secure.c',
+        'src/core/tsi/fake_transport_security.c',
+        'src/core/tsi/gts_transport_security.c',
+        'src/core/tsi/ssl_transport_security.c',
+        'src/core/tsi/transport_security_grpc.c',
+        'src/core/tsi/transport_security.c',
+        'src/core/tsi/transport_security_adapter.c',
+        'src/core/ext/transport/chttp2/server/chttp2_server.c',
+        'src/core/ext/transport/chttp2/client/secure/secure_channel_create.c',
+        'src/core/ext/filters/client_channel/channel_connectivity.c',
+        'src/core/ext/filters/client_channel/client_channel.c',
+        'src/core/ext/filters/client_channel/client_channel_factory.c',
+        'src/core/ext/filters/client_channel/client_channel_plugin.c',
+        'src/core/ext/filters/client_channel/connector.c',
+        'src/core/ext/filters/client_channel/http_connect_handshaker.c',
+        'src/core/ext/filters/client_channel/http_proxy.c',
+        'src/core/ext/filters/client_channel/lb_policy.c',
+        'src/core/ext/filters/client_channel/lb_policy_factory.c',
+        'src/core/ext/filters/client_channel/lb_policy_registry.c',
+        'src/core/ext/filters/client_channel/parse_address.c',
+        'src/core/ext/filters/client_channel/proxy_mapper.c',
+        'src/core/ext/filters/client_channel/proxy_mapper_registry.c',
+        'src/core/ext/filters/client_channel/resolver.c',
+        'src/core/ext/filters/client_channel/resolver_factory.c',
+        'src/core/ext/filters/client_channel/resolver_registry.c',
+        'src/core/ext/filters/client_channel/retry_throttle.c',
+        'src/core/ext/filters/client_channel/subchannel.c',
+        'src/core/ext/filters/client_channel/subchannel_index.c',
+        'src/core/ext/filters/client_channel/uri_parser.c',
+        'src/core/ext/filters/deadline/deadline_filter.c',
+        'src/core/ext/transport/chttp2/client/chttp2_connector.c',
+        'src/core/ext/transport/chttp2/server/insecure/server_chttp2.c',
+        'src/core/ext/transport/chttp2/server/insecure/server_chttp2_posix.c',
+        'src/core/ext/transport/chttp2/client/insecure/channel_create.c',
+        'src/core/ext/transport/chttp2/client/insecure/channel_create_posix.c',
+        'src/core/ext/transport/inproc/inproc_plugin.c',
+        'src/core/ext/transport/inproc/inproc_transport.c',
+        'src/core/ext/filters/client_channel/lb_policy/grpclb/client_load_reporting_filter.c',
+        'src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb.c',
+        'src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_channel_secure.c',
+        'src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_client_stats.c',
+        'src/core/ext/filters/client_channel/lb_policy/grpclb/load_balancer_api.c',
+        'src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.c',
+        'third_party/nanopb/pb_common.c',
+        'third_party/nanopb/pb_decode.c',
+        'third_party/nanopb/pb_encode.c',
+        'src/core/ext/filters/client_channel/resolver/fake/fake_resolver.c',
+        'src/core/ext/filters/client_channel/lb_policy/pick_first/pick_first.c',
+        'src/core/ext/filters/client_channel/lb_policy/round_robin/round_robin.c',
+        'src/core/ext/filters/client_channel/resolver/dns/c_ares/dns_resolver_ares.c',
+        'src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver_posix.c',
+        'src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.c',
+        'src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_fallback.c',
+        'src/core/ext/filters/client_channel/resolver/dns/native/dns_resolver.c',
+        'src/core/ext/filters/client_channel/resolver/sockaddr/sockaddr_resolver.c',
+        'src/core/ext/filters/load_reporting/server_load_reporting_filter.c',
+        'src/core/ext/filters/load_reporting/server_load_reporting_plugin.c',
+        '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',
+        'src/core/ext/census/initialize.c',
+        'src/core/ext/census/intrusive_hash_map.c',
+        'src/core/ext/census/mlog.c',
+        'src/core/ext/census/operation.c',
+        'src/core/ext/census/placeholders.c',
+        'src/core/ext/census/resource.c',
+        'src/core/ext/census/trace_context.c',
+        'src/core/ext/census/tracing.c',
+        'src/core/ext/filters/max_age/max_age_filter.c',
+        'src/core/ext/filters/message_size/message_size_filter.c',
+        'src/core/ext/filters/workarounds/workaround_cronet_compression_filter.c',
+        'src/core/ext/filters/workarounds/workaround_utils.c',
+        'src/core/plugin_registry/grpc_plugin_registry.c',
+      ],
+      'conditions': [
+        ['OS == "mac"', {
+          'xcode_settings': {
+            'MACOSX_DEPLOYMENT_TARGET': '10.9'
+          }
+        }]
+      ]
+    },
+    {
+      'include_dirs': [
+        "<!(node -e \"require('nan')\")"
+      ],
+      'cflags': [
+        '-pthread',
+        '-zdefs',
+        '-Wno-error=deprecated-declarations'
+      ],
+      "conditions": [
+        ['OS=="win" or runtime=="electron"', {
+          'dependencies': [
+            "boringssl",
+          ]
+        }],
+        ['OS=="win"', {
+          'dependencies': [
+            "z",
+          ]
+        }],
+        ['OS=="linux"', {
+          'ldflags': [
+            '-Wl,-wrap,memcpy'
+          ]
+        }],
+        ['OS == "mac"', {
+          'xcode_settings': {
+            'MACOSX_DEPLOYMENT_TARGET': '10.9'
+          }
+        }]
+      ],
+      "target_name": "grpc_node",
+      "sources": [
+        "src/node/ext/byte_buffer.cc",
+        "src/node/ext/call.cc",
+        "src/node/ext/call_credentials.cc",
+        "src/node/ext/channel.cc",
+        "src/node/ext/channel_credentials.cc",
+        "src/node/ext/completion_queue.cc",
+        "src/node/ext/node_grpc.cc",
+        "src/node/ext/server.cc",
+        "src/node/ext/server_credentials.cc",
+        "src/node/ext/slice.cc",
+        "src/node/ext/timeval.cc",
+      ],
+      "dependencies": [
+        "grpc",
+        "gpr",
+      ]
+    },
+    {
+      "target_name": "action_after_build",
+      "type": "none",
+      "dependencies": [ "<(module_name)" ],
+      "copies": [
+        {
+          "files": [ "<(PRODUCT_DIR)/<(module_name).node"],
+          "destination": "<(module_path)"
+        }
+      ]
+    }
+  ]
+}
diff --git a/build.yaml b/build.yaml
index a82a783..854a695 100644
--- a/build.yaml
+++ b/build.yaml
@@ -13,8 +13,8 @@
   '#09': Per-language overrides are possible with (eg) ruby_version tag here
   '#10': See the expand_version.py for all the quirks here
   core_version: 5.0.0-dev
-  g_stands_for: generous
-  version: 1.8.0-dev
+  g_stands_for: glossy
+  version: 1.9.0-dev
 filegroups:
 - name: census
   public_headers:
@@ -40,7 +40,7 @@
   - src/core/lib/support/env_linux.cc
   - src/core/lib/support/env_posix.cc
   - src/core/lib/support/env_windows.cc
-  - src/core/lib/support/histogram.cc
+  - src/core/lib/support/fork.cc
   - src/core/lib/support/host_port.cc
   - src/core/lib/support/log.cc
   - src/core/lib/support/log_android.cc
@@ -49,7 +49,6 @@
   - src/core/lib/support/log_windows.cc
   - src/core/lib/support/mpscq.cc
   - src/core/lib/support/murmur_hash.cc
-  - src/core/lib/support/stack_lockfree.cc
   - src/core/lib/support/string.cc
   - src/core/lib/support/string_posix.cc
   - src/core/lib/support/string_util_windows.cc
@@ -83,7 +82,6 @@
   - include/grpc/support/avl.h
   - include/grpc/support/cmdline.h
   - include/grpc/support/cpu.h
-  - include/grpc/support/histogram.h
   - include/grpc/support/host_port.h
   - include/grpc/support/log.h
   - include/grpc/support/log_windows.h
@@ -104,19 +102,21 @@
   - include/grpc/support/useful.h
   headers:
   - src/core/lib/profiling/timers.h
+  - src/core/lib/support/abstract.h
   - src/core/lib/support/arena.h
   - src/core/lib/support/atomic.h
   - src/core/lib/support/atomic_with_atm.h
   - src/core/lib/support/atomic_with_std.h
   - src/core/lib/support/env.h
+  - src/core/lib/support/fork.h
   - src/core/lib/support/manual_constructor.h
   - src/core/lib/support/memory.h
   - src/core/lib/support/mpscq.h
   - src/core/lib/support/murmur_hash.h
   - src/core/lib/support/spinlock.h
-  - src/core/lib/support/stack_lockfree.h
   - src/core/lib/support/string.h
   - src/core/lib/support/string_windows.h
+  - src/core/lib/support/thd_internal.h
   - src/core/lib/support/time_precise.h
   - src/core/lib/support/tmpfile.h
   uses:
@@ -127,6 +127,7 @@
   - 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/fork.h
   - include/grpc/impl/codegen/gpr_slice.h
   - include/grpc/impl/codegen/gpr_types.h
   - include/grpc/impl/codegen/port_platform.h
@@ -182,6 +183,8 @@
   - src/core/lib/iomgr/ev_windows.cc
   - src/core/lib/iomgr/exec_ctx.cc
   - src/core/lib/iomgr/executor.cc
+  - src/core/lib/iomgr/fork_posix.cc
+  - src/core/lib/iomgr/fork_windows.cc
   - src/core/lib/iomgr/gethostname_fallback.cc
   - src/core/lib/iomgr/gethostname_host_name_max.cc
   - src/core/lib/iomgr/gethostname_sysconf.cc
@@ -292,6 +295,7 @@
   - include/grpc/byte_buffer.h
   - include/grpc/byte_buffer_reader.h
   - include/grpc/compression.h
+  - include/grpc/fork.h
   - include/grpc/grpc.h
   - include/grpc/grpc_posix.h
   - include/grpc/grpc_security_constants.h
@@ -392,7 +396,9 @@
   - src/core/lib/slice/slice_hash_table.h
   - src/core/lib/slice/slice_internal.h
   - src/core/lib/slice/slice_string_helpers.h
-  - src/core/lib/support/vector.h
+  - src/core/lib/support/debug_location.h
+  - src/core/lib/support/ref_counted.h
+  - src/core/lib/support/ref_counted_ptr.h
   - src/core/lib/surface/alarm_internal.h
   - src/core/lib/surface/api_trace.h
   - src/core/lib/surface/call.h
@@ -706,6 +712,7 @@
   - test/core/iomgr/endpoint_tests.h
   - test/core/util/debugger_macros.h
   - test/core/util/grpc_profiler.h
+  - test/core/util/histogram.h
   - test/core/util/memory_counters.h
   - test/core/util/mock_endpoint.h
   - test/core/util/parse_hexstring.h
@@ -713,6 +720,7 @@
   - test/core/util/port.h
   - test/core/util/port_server_client.h
   - test/core/util/slice_splitter.h
+  - test/core/util/tracer_util.h
   - test/core/util/trickle_endpoint.h
   src:
   - src/core/ext/filters/client_channel/resolver/fake/fake_resolver.cc
@@ -722,13 +730,16 @@
   - test/core/iomgr/endpoint_tests.cc
   - test/core/util/debugger_macros.cc
   - test/core/util/grpc_profiler.cc
+  - test/core/util/histogram.cc
   - test/core/util/memory_counters.cc
   - test/core/util/mock_endpoint.cc
   - test/core/util/parse_hexstring.cc
   - test/core/util/passthru_endpoint.cc
   - test/core/util/port.cc
+  - test/core/util/port_isolated_runtime_environment.cc
   - test/core/util/port_server_client.cc
   - test/core/util/slice_splitter.cc
+  - test/core/util/tracer_util.cc
   - test/core/util/trickle_endpoint.cc
   deps:
   - gpr_test_util
@@ -2186,15 +2197,6 @@
   - gpr_test_util
   - gpr
   uses_polling: false
-- name: gpr_histogram_test
-  build: test
-  language: c
-  src:
-  - test/core/support/histogram_test.cc
-  deps:
-  - gpr_test_util
-  - gpr
-  uses_polling: false
 - name: gpr_host_port_test
   build: test
   language: c
@@ -2213,6 +2215,16 @@
   - gpr_test_util
   - gpr
   uses_polling: false
+- name: gpr_manual_constructor_test
+  cpu_cost: 3
+  build: test
+  language: c
+  src:
+  - test/core/support/manual_constructor_test.cc
+  deps:
+  - gpr_test_util
+  - gpr
+  uses_polling: false
 - name: gpr_mpscq_test
   cpu_cost: 30
   build: test
@@ -2233,16 +2245,6 @@
   - gpr_test_util
   - gpr
   uses_polling: false
-- name: gpr_stack_lockfree_test
-  cpu_cost: 7
-  build: test
-  language: c
-  src:
-  - test/core/support/stack_lockfree_test.cc
-  deps:
-  - gpr_test_util
-  - gpr
-  uses_polling: false
 - name: gpr_string_test
   build: test
   language: c
@@ -2543,6 +2545,15 @@
   platforms:
   - linux
   secure: true
+- name: histogram_test
+  build: test
+  language: c
+  src:
+  - test/core/util/histogram_test.cc
+  deps:
+  - grpc_test_util
+  - gpr
+  uses_polling: false
 - name: hpack_parser_fuzzer_test
   build: fuzzer
   language: c
@@ -4528,6 +4539,34 @@
   - gpr_test_util
   - gpr
   - grpc++_test_config
+- name: ref_counted_ptr_test
+  gtest: true
+  build: test
+  language: c++
+  src:
+  - test/core/support/ref_counted_ptr_test.cc
+  deps:
+  - grpc_test_util
+  - grpc++
+  - grpc
+  - gpr_test_util
+  - gpr
+  uses:
+  - grpc++_test
+- name: ref_counted_test
+  gtest: true
+  build: test
+  language: c++
+  src:
+  - test/core/support/ref_counted_test.cc
+  deps:
+  - grpc_test_util
+  - grpc++
+  - grpc
+  - gpr_test_util
+  - gpr
+  uses:
+  - grpc++_test
 - name: secure_auth_context_test
   gtest: true
   build: test
@@ -4769,20 +4808,6 @@
   - grpc
   - gpr_test_util
   - gpr
-- name: vector_test
-  gtest: true
-  build: test
-  language: c++
-  src:
-  - test/core/support/vector_test.cc
-  deps:
-  - grpc_test_util
-  - grpc++
-  - grpc
-  - gpr_test_util
-  - gpr
-  uses:
-  - grpc++_test
 - name: writes_per_rpc_test
   gtest: true
   cpu_cost: 0.5
@@ -4902,8 +4927,8 @@
   msan:
     CC: clang
     CPPFLAGS: -O0 -fsanitize-coverage=edge -fsanitize=memory -fsanitize-memory-track-origins
-      -fno-omit-frame-pointer -DGTEST_HAS_TR1_TUPLE=0 -DGTEST_USE_OWN_TR1_TUPLE=1
-      -Wno-unused-command-line-argument -fPIE -pie -DGPR_NO_DIRECT_SYSCALLS
+      -fsanitize-memory-use-after-dtor -fno-omit-frame-pointer -DGTEST_HAS_TR1_TUPLE=0
+      -DGTEST_USE_OWN_TR1_TUPLE=1 -Wno-unused-command-line-argument -fPIE -pie -DGPR_NO_DIRECT_SYSCALLS
     CXX: clang++
     DEFINES: NDEBUG
     LD: clang++
@@ -4911,6 +4936,8 @@
       -fPIE -pie $(if $(JENKINS_BUILD),-Wl$(comma)-Ttext-segment=0x7e0000000000,)
     LDXX: clang++
     compile_the_world: true
+    test_environ:
+      MSAN_OPTIONS: poison_in_dtor=1
   mutrace:
     CPPFLAGS: -O3 -fno-omit-frame-pointer
     DEFINES: NDEBUG
@@ -4963,8 +4990,8 @@
     CPPFLAGS: -Ithird_party/boringssl/include -fvisibility=hidden -DOPENSSL_NO_ASM
       -D_GNU_SOURCE -DWIN32_LEAN_AND_MEAN -D_HAS_EXCEPTIONS=0 -DNOMINMAX
   global:
+    COREFLAGS: -fno-rtti -fno-exceptions
     CPPFLAGS: -g -Wall -Wextra -Werror -Wno-long-long -Wno-unused-parameter -DOSATOMIC_USE_INLINED=1
-      -Ithird_party/abseil-cpp
     LDFLAGS: -g
   zlib:
     CFLAGS: -Wno-sign-conversion -Wno-conversion -Wno-unused-value -Wno-implicit-function-declaration
diff --git a/config.m4 b/config.m4
index d2f2520..c026b83 100644
--- a/config.m4
+++ b/config.m4
@@ -53,7 +53,7 @@
     src/core/lib/support/env_linux.cc \
     src/core/lib/support/env_posix.cc \
     src/core/lib/support/env_windows.cc \
-    src/core/lib/support/histogram.cc \
+    src/core/lib/support/fork.cc \
     src/core/lib/support/host_port.cc \
     src/core/lib/support/log.cc \
     src/core/lib/support/log_android.cc \
@@ -62,7 +62,6 @@
     src/core/lib/support/log_windows.cc \
     src/core/lib/support/mpscq.cc \
     src/core/lib/support/murmur_hash.cc \
-    src/core/lib/support/stack_lockfree.cc \
     src/core/lib/support/string.cc \
     src/core/lib/support/string_posix.cc \
     src/core/lib/support/string_util_windows.cc \
@@ -118,6 +117,8 @@
     src/core/lib/iomgr/ev_windows.cc \
     src/core/lib/iomgr/exec_ctx.cc \
     src/core/lib/iomgr/executor.cc \
+    src/core/lib/iomgr/fork_posix.cc \
+    src/core/lib/iomgr/fork_windows.cc \
     src/core/lib/iomgr/gethostname_fallback.cc \
     src/core/lib/iomgr/gethostname_host_name_max.cc \
     src/core/lib/iomgr/gethostname_sysconf.cc \
diff --git a/config.w32 b/config.w32
index 8a71375..cd3a16a 100644
--- a/config.w32
+++ b/config.w32
@@ -30,7 +30,7 @@
     "src\\core\\lib\\support\\env_linux.cc " +
     "src\\core\\lib\\support\\env_posix.cc " +
     "src\\core\\lib\\support\\env_windows.cc " +
-    "src\\core\\lib\\support\\histogram.cc " +
+    "src\\core\\lib\\support\\fork.cc " +
     "src\\core\\lib\\support\\host_port.cc " +
     "src\\core\\lib\\support\\log.cc " +
     "src\\core\\lib\\support\\log_android.cc " +
@@ -39,7 +39,6 @@
     "src\\core\\lib\\support\\log_windows.cc " +
     "src\\core\\lib\\support\\mpscq.cc " +
     "src\\core\\lib\\support\\murmur_hash.cc " +
-    "src\\core\\lib\\support\\stack_lockfree.cc " +
     "src\\core\\lib\\support\\string.cc " +
     "src\\core\\lib\\support\\string_posix.cc " +
     "src\\core\\lib\\support\\string_util_windows.cc " +
@@ -95,6 +94,8 @@
     "src\\core\\lib\\iomgr\\ev_windows.cc " +
     "src\\core\\lib\\iomgr\\exec_ctx.cc " +
     "src\\core\\lib\\iomgr\\executor.cc " +
+    "src\\core\\lib\\iomgr\\fork_posix.cc " +
+    "src\\core\\lib\\iomgr\\fork_windows.cc " +
     "src\\core\\lib\\iomgr\\gethostname_fallback.cc " +
     "src\\core\\lib\\iomgr\\gethostname_host_name_max.cc " +
     "src\\core\\lib\\iomgr\\gethostname_sysconf.cc " +
diff --git a/doc/core/transport_explainer.md b/doc/core/transport_explainer.md
new file mode 100644
index 0000000..f48fa0f
--- /dev/null
+++ b/doc/core/transport_explainer.md
@@ -0,0 +1,197 @@
+# Transport Explainer
+
+@vjpai
+
+## Existing Transports
+
+[gRPC
+transports](https://github.com/grpc/grpc/tree/master/src/core/ext/transport)
+plug in below the core API (one level below the C++ or other wrapped-language
+API). You can write your transport in C or C++ though; currently (Nov 2017) all
+the transports are nominally written in C++ though they are idiomatically C. The
+existing transports are:
+
+* [HTTP/2](https://github.com/grpc/grpc/tree/master/src/core/ext/transport/chttp2)
+* [Cronet](https://github.com/grpc/grpc/tree/master/src/core/ext/transport/cronet)
+* [In-process](https://github.com/grpc/grpc/tree/master/src/core/ext/transport/inproc)
+
+Among these, the in-process is likely the easiest to understand, though arguably
+also the least similar to a "real" sockets-based transport since it is only used
+in a single process.
+
+## Transport stream ops
+
+In the gRPC core implementation, a fundamental struct is the
+`grpc_transport_stream_op_batch` which represents a collection of stream
+operations sent to a transport. (Note that in gRPC, _stream_ and _RPC_ are used
+synonymously since all RPCs are actually streams internally.) The ops in a batch
+can include:
+
+* send\_initial\_metadata
+  - Client: initate an RPC
+  - Server: supply response headers
+* recv\_initial\_metadata
+  - Client: get response headers
+  - Server: accept an RPC
+* send\_message (zero or more) : send a data buffer
+* recv\_message (zero or more) : receive a data buffer
+* send\_trailing\_metadata
+  - Client: half-close indicating that no more messages will be coming
+  - Server: full-close providing final status for the RPC
+* recv\_trailing\_metadata: get final status for the RPC
+  - Server extra: This op shouldn't actually be considered complete until the
+    server has also sent trailing metadata to provide the other side with final
+    status
+* cancel\_stream: Attempt to cancel an RPC
+* collect\_stats: Get stats
+
+The fundamental responsibility of the transport is to transform between this
+internal format and an actual wire format, so the processing of these operations
+is largely transport-specific.
+
+One or more of these ops are grouped into a batch. Applications can start all of
+a call's ops in a single batch, or they can split them up into multiple
+batches. Results of each batch are returned asynchronously via a completion
+queue.
+
+Internally, we use callbacks to indicate completion. The surface layer creates a
+callback when starting a new batch and sends it down the filter stack along with
+the batch. The transport must invoke this callback when the batch is complete,
+and then the surface layer returns an event to the application via the
+completion queue. Each batch can have up to 3 callbacks:
+
+* recv\_initial\_metadata\_ready (called by the transport when the
+  recv\_initial\_metadata op is complete)
+* recv\_message\_ready (called by the transport when the recv_message op is
+  complete)
+* on\_complete (called by the transport when the entire batch is complete)
+
+## Timelines of transport stream op batches
+
+The transport's job is to sequence and interpret various possible interleavings
+of the basic stream ops. For example, a sample timeline of batches would be:
+
+1. Client send\_initial\_metadata: Initiate an RPC with a path (method) and authority
+1. Server recv\_initial\_metadata: accept an RPC
+1. Client send\_message: Supply the input proto for the RPC
+1. Server recv\_message: Get the input proto from the RPC
+1. Client send\_trailing\_metadata: This is a half-close indicating that the
+   client will not be sending any more messages
+1. Server recv\_trailing\_metadata: The server sees this from the client and
+   knows that it will not get any more messages. This won't complete yet though,
+   as described above.
+1. Server send\_initial\_metadata, send\_message, send\_trailing\_metadata: A
+   batch can contain multiple ops, and this batch provides the RPC response
+   headers, response content, and status. Note that sending the trailing
+   metadata will also complete the server's receive of trailing metadata.
+1. Client recv\_initial\_metadata: The number of ops in one side of the batch
+   has no relation with the number of ops on the other side of the batch. In
+   this case, the client is just collecting the response headers.
+1. Client recv\_message, recv\_trailing\_metadata: Get the data response and
+   status
+
+
+There are other possible sample timelines. For example, for client-side streaming, a "typical" sequence would be:
+
+1. Server: recv\_initial\_metadata
+   - At API-level, that would be the server requesting an RPC
+1. Server: recv\_trailing\_metadata
+   - This is for when the server wants to know the final completion of the RPC
+     through an `AsyncNotifyWhenDone` API in C++
+1. Client: send\_initial\_metadata, recv\_message, recv\_trailing\_metadata
+   - At API-level, that's a client invoking a client-side streaming call. The
+     send\_initial\_metadata is the call invocation, the recv\_message colects
+     the final response from the server, and the recv\_trailing\_metadata gets
+     the `grpc::Status` value that will be returned from the call
+1. Client: send\_message / Server: recv\_message
+   - Repeat the above step numerous times; these correspond to a client issuing
+     `Write` in a loop and a server doing `Read` in a loop until `Read` fails
+1. Client: send\_trailing\_metadata / Server: recv\_message that indicates doneness (NULL)
+   - These correspond to a client issuing `WritesDone` which causes the server's
+     `Read` to fail
+1. Server: send\_message, send\_trailing\_metadata
+   - These correpond to the server doing `Finish`
+
+The sends on one side will call their own callbacks when complete, and they will
+in turn trigger actions that cause the other side's recv operations to
+complete. In some transports, a send can sometimes complete before the recv on
+the other side (e.g., in HTTP/2 if there is sufficient flow-control buffer space
+available)
+
+## Other transport duties
+
+In addition to these basic stream ops, the transport must handle cancellations
+of a stream at any time and pass their effects to the other side. For example,
+in HTTP/2, this triggers a `RST_STREAM` being sent on the wire. The transport
+must perform operations like pings and statistics that are used to shape
+transport-level characteristics like flow control (see, for example, their use
+in the HTTP/2 transport).
+
+## Putting things together with detail: Sending Metadata
+
+* API layer: `map<string, string>` that is specific to this RPC
+* Core surface layer: array of `{slice, slice}` pairs where each slice
+  references an underlying string
+* [Core transport
+  layer](https://github.com/grpc/grpc/tree/master/src/core/lib/transport): list
+  of `{slice, slice}` pairs that includes the above plus possibly some general
+  metadata (e.g., Method and Authority for initial metadata)
+* [Specific transport
+  layer](https://github.com/grpc/grpc/tree/master/src/core/ext/transport):
+  - Either send it to the other side using transport-specific API (e.g., Cronet)
+  - Or have it sent through the [iomgr/endpoint
+    layer](https://github.com/grpc/grpc/tree/master/src/core/lib/iomgr) (e.g.,
+    HTTP/2)
+  - Or just manipulate pointers to get it from one side to the other (e.g.,
+    In-process)
+
+## Requirements for any transport
+
+Each transport implements several operations in a vtbl (may change to actual
+virtual functions as transport moves to idiomatic C++).
+
+The most important and common one is `perform_stream_op`. This function
+processes a single stream op batch on a specific stream that is associated with
+a specific transport:
+
+* Gets the 6 ops/cancel passed down from the surface
+* Pass metadata from one side to the other as described above
+* Transform messages between slice buffer structure and stream of bytes to pass
+  to other side
+  - May require insertion of extra bytes (e.g., per-message headers in HTTP/2)
+* React to metadata to preserve expected orderings (*)
+* Schedule invocation of completion callbacks
+
+There are other functions in the vtbl as well.
+
+* `perform_transport_op`
+  - Configure the transport instance for the connectivity state change notifier
+    or the server-side accept callback
+  - Disconnect transport or set up a goaway for later streams
+* `init_stream`
+  - Starts a stream from the client-side
+  - (*) Server-side of the transport must call `accept_stream_cb` when a new
+  stream is available
+    * Triggers request-matcher
+* `destroy_stream`, `destroy_transport`
+  - Free up data related to a stream or transport
+* `set_pollset`, `set_pollset_set`, `get_endpoint`
+  - Map each specific instance of the transport to FDs being used by iomgr (for
+    HTTP/2)
+  - Get a pointer to the endpoint structure that actually moves the data
+    (wrapper around a socket for HTTP/2)
+
+## Book-keeping responsibilities of the transport layer
+
+A given transport must keep all of its transport and streams ref-counted. This
+is essential to make sure that no struct disappears before it is done being
+used.
+
+A transport must also preserve relevant orders for the different categories of
+ops on a stream, as described above. A transport must also make sure that all
+relevant batch operations have completed before scheduling the `on_complete`
+closure for a batch. Further examples include the idea that the server logic
+expects to not complete recv\_trailing\_metadata until after it actually sends
+trailing metadata since it would have already found this out by seeing a NULL’ed
+recv\_message. This is considered part of the transport's duties in preserving
+orders.
diff --git a/doc/g_stands_for.md b/doc/g_stands_for.md
index 4e2ca33..edc6dc1 100644
--- a/doc/g_stands_for.md
+++ b/doc/g_stands_for.md
@@ -12,3 +12,4 @@
 - 1.6 'g' stands for 'garcia'
 - 1.7 'g' stands for 'gambit'
 - 1.8 'g' stands for 'generous'
+- 1.9 'g' stands for 'glossy'
diff --git a/doc/service_config.md b/doc/service_config.md
index 0abbd7f..dd1cbc5 100644
--- a/doc/service_config.md
+++ b/doc/service_config.md
@@ -12,7 +12,7 @@
 
 ```
 {
-  // Load balancing policy name.
+  // Load balancing policy name (case insensitive).
   // Currently, the only selectable client-side policy provided with gRPC
   // is 'round_robin', but third parties may add their own policies.
   // This field is optional; if unset, the default behavior is to pick
diff --git a/examples/BUILD b/examples/BUILD
index 3e9e508..0f18cfa 100644
--- a/examples/BUILD
+++ b/examples/BUILD
@@ -42,12 +42,12 @@
     name = "greeter_client",
     srcs = ["cpp/helloworld/greeter_client.cc"],
     defines = ["BAZEL_BUILD"],
-    deps = [":helloworld"],
+    deps = [":helloworld", "//:grpc++"],
 )
 
 cc_binary(
     name = "greeter_server",
     srcs = ["cpp/helloworld/greeter_server.cc"],
     defines = ["BAZEL_BUILD"],
-    deps = [":helloworld"],
+    deps = [":helloworld", "//:grpc++"],
 )
diff --git a/examples/cpp/helloworld/CMakeLists.txt b/examples/cpp/helloworld/CMakeLists.txt
index 71a8db4..49684a1 100644
--- a/examples/cpp/helloworld/CMakeLists.txt
+++ b/examples/cpp/helloworld/CMakeLists.txt
@@ -6,13 +6,29 @@
 

 if(NOT MSVC)

   set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")

+else()

+  add_definitions(-D_WIN32_WINNT=0x600)

 endif()

 

 # Protobuf

-set(protobuf_MODULE_COMPATIBLE TRUE)

-find_package(protobuf CONFIG REQUIRED)

+# NOTE: we cannot use "CONFIG" mode here because protobuf-config.cmake

+# is broken when used with CMAKE_INSTALL_PREFIX

+find_package(Protobuf REQUIRED)

 message(STATUS "Using protobuf ${protobuf_VERSION}")

 

+if(Protobuf_FOUND)

+  # Protobuf_FOUND is set for package type "CONFIG"

+  set(_PROTOBUF_LIBPROTOBUF protobuf::libprotobuf)

+  set(_PROTOBUF_PROTOC protobuf::protoc)

+elseif(PROTOBUF_FOUND)

+  # PROTOBUF_FOUND is set for package type "MODULE"

+  set(_PROTOBUF_LIBPROTOBUF ${PROTOBUF_LIBRARIES})

+  set(_PROTOBUF_PROTOC ${PROTOBUF_PROTOC_EXECUTABLE})

+  include_directories(${PROTOBUF_INCLUDE_DIRS})

+else()

+  message(WARNING "Failed to locate libprotobuf and protoc!")

+endif()

+

 # gRPC

 find_package(gRPC CONFIG REQUIRED)

 message(STATUS "Using gRPC ${gRPC_VERSION}")

@@ -31,7 +47,7 @@
 set(hw_grpc_hdrs "${CMAKE_CURRENT_BINARY_DIR}/helloworld.grpc.pb.h")

 add_custom_command(

       OUTPUT "${hw_grpc_srcs}" "${hw_grpc_hdrs}"

-      COMMAND protobuf::protoc

+      COMMAND ${_PROTOBUF_PROTOC}

       ARGS --grpc_out "${CMAKE_CURRENT_BINARY_DIR}" -I "${hw_proto_path}"

         --plugin=protoc-gen-grpc="${gRPC_CPP_PLUGIN_EXECUTABLE}"

         "${hw_proto}"

@@ -48,6 +64,6 @@
     ${hw_proto_srcs}

     ${hw_grpc_srcs})

   target_link_libraries(${_target}

-    protobuf::libprotobuf

+    ${_PROTOBUF_LIBPROTOBUF}

     gRPC::grpc++_unsecure)

 endforeach()

diff --git a/examples/python/route_guide/route_guide_client.py b/examples/python/route_guide/route_guide_client.py
index 653f0d0..a0e32fb 100644
--- a/examples/python/route_guide/route_guide_client.py
+++ b/examples/python/route_guide/route_guide_client.py
@@ -17,7 +17,6 @@
 from __future__ import print_function
 
 import random
-import time
 
 import grpc
 
@@ -66,7 +65,6 @@
     random_feature = feature_list[random.randint(0, len(feature_list) - 1)]
     print("Visiting point %s" % random_feature.location)
     yield random_feature.location
-    time.sleep(random.uniform(0.5, 1.5))
 
 
 def guide_record_route(stub):
@@ -91,7 +89,6 @@
   for msg in messages:
     print("Sending %s at %s" % (msg.message, msg.location))
     yield msg
-    time.sleep(random.uniform(0.5, 1.0))
 
 
 def guide_route_chat(stub):
diff --git a/gRPC-Core.podspec b/gRPC-Core.podspec
index 02c6a64..39b8484 100644
--- a/gRPC-Core.podspec
+++ b/gRPC-Core.podspec
@@ -22,7 +22,7 @@
 
 Pod::Spec.new do |s|
   s.name     = 'gRPC-Core'
-  version = '1.8.0-dev'
+  version = '1.9.0-dev'
   s.version  = version
   s.summary  = 'Core cross-platform gRPC library, written in C'
   s.homepage = 'https://grpc.io'
@@ -85,6 +85,7 @@
     'USE_HEADERMAP' => 'NO',
     'ALWAYS_SEARCH_USER_PATHS' => 'NO',
     'GCC_PREPROCESSOR_DEFINITIONS' => '"$(inherited)" "COCOAPODS=1" "PB_NO_PACKED_STRUCTS=1"',
+    'CLANG_WARN_STRICT_PROTOTYPES' => 'NO',
   }
 
   s.default_subspecs = 'Interface', 'Implementation'
@@ -112,7 +113,6 @@
                       'include/grpc/support/avl.h',
                       'include/grpc/support/cmdline.h',
                       'include/grpc/support/cpu.h',
-                      'include/grpc/support/histogram.h',
                       'include/grpc/support/host_port.h',
                       'include/grpc/support/log.h',
                       'include/grpc/support/log_windows.h',
@@ -135,6 +135,7 @@
                       '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/fork.h',
                       'include/grpc/impl/codegen/gpr_slice.h',
                       'include/grpc/impl/codegen/gpr_types.h',
                       'include/grpc/impl/codegen/port_platform.h',
@@ -156,6 +157,7 @@
                       '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/fork.h',
                       'include/grpc/impl/codegen/gpr_slice.h',
                       'include/grpc/impl/codegen/gpr_types.h',
                       'include/grpc/impl/codegen/port_platform.h',
@@ -168,6 +170,7 @@
                       'include/grpc/byte_buffer.h',
                       'include/grpc/byte_buffer_reader.h',
                       'include/grpc/compression.h',
+                      'include/grpc/fork.h',
                       'include/grpc/grpc.h',
                       'include/grpc/grpc_posix.h',
                       'include/grpc/grpc_security_constants.h',
@@ -187,19 +190,21 @@
 
     # 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/abstract.h',
                       'src/core/lib/support/arena.h',
                       'src/core/lib/support/atomic.h',
                       'src/core/lib/support/atomic_with_atm.h',
                       'src/core/lib/support/atomic_with_std.h',
                       'src/core/lib/support/env.h',
+                      'src/core/lib/support/fork.h',
                       'src/core/lib/support/manual_constructor.h',
                       'src/core/lib/support/memory.h',
                       'src/core/lib/support/mpscq.h',
                       'src/core/lib/support/murmur_hash.h',
                       'src/core/lib/support/spinlock.h',
-                      'src/core/lib/support/stack_lockfree.h',
                       'src/core/lib/support/string.h',
                       'src/core/lib/support/string_windows.h',
+                      'src/core/lib/support/thd_internal.h',
                       'src/core/lib/support/time_precise.h',
                       'src/core/lib/support/tmpfile.h',
                       'src/core/lib/profiling/basic_timers.cc',
@@ -216,7 +221,7 @@
                       'src/core/lib/support/env_linux.cc',
                       'src/core/lib/support/env_posix.cc',
                       'src/core/lib/support/env_windows.cc',
-                      'src/core/lib/support/histogram.cc',
+                      'src/core/lib/support/fork.cc',
                       'src/core/lib/support/host_port.cc',
                       'src/core/lib/support/log.cc',
                       'src/core/lib/support/log_android.cc',
@@ -225,7 +230,6 @@
                       'src/core/lib/support/log_windows.cc',
                       'src/core/lib/support/mpscq.cc',
                       'src/core/lib/support/murmur_hash.cc',
-                      'src/core/lib/support/stack_lockfree.cc',
                       'src/core/lib/support/string.cc',
                       'src/core/lib/support/string_posix.cc',
                       'src/core/lib/support/string_util_windows.cc',
@@ -412,7 +416,9 @@
                       'src/core/lib/slice/slice_hash_table.h',
                       'src/core/lib/slice/slice_internal.h',
                       'src/core/lib/slice/slice_string_helpers.h',
-                      'src/core/lib/support/vector.h',
+                      'src/core/lib/support/debug_location.h',
+                      'src/core/lib/support/ref_counted.h',
+                      'src/core/lib/support/ref_counted_ptr.h',
                       'src/core/lib/surface/alarm_internal.h',
                       'src/core/lib/surface/api_trace.h',
                       'src/core/lib/surface/call.h',
@@ -492,6 +498,8 @@
                       'src/core/lib/iomgr/ev_windows.cc',
                       'src/core/lib/iomgr/exec_ctx.cc',
                       'src/core/lib/iomgr/executor.cc',
+                      'src/core/lib/iomgr/fork_posix.cc',
+                      'src/core/lib/iomgr/fork_windows.cc',
                       'src/core/lib/iomgr/gethostname_fallback.cc',
                       'src/core/lib/iomgr/gethostname_host_name_max.cc',
                       'src/core/lib/iomgr/gethostname_sysconf.cc',
@@ -706,19 +714,21 @@
                       'src/core/plugin_registry/grpc_plugin_registry.cc'
 
     ss.private_header_files = 'src/core/lib/profiling/timers.h',
+                              'src/core/lib/support/abstract.h',
                               'src/core/lib/support/arena.h',
                               'src/core/lib/support/atomic.h',
                               'src/core/lib/support/atomic_with_atm.h',
                               'src/core/lib/support/atomic_with_std.h',
                               'src/core/lib/support/env.h',
+                              'src/core/lib/support/fork.h',
                               'src/core/lib/support/manual_constructor.h',
                               'src/core/lib/support/memory.h',
                               'src/core/lib/support/mpscq.h',
                               'src/core/lib/support/murmur_hash.h',
                               'src/core/lib/support/spinlock.h',
-                              'src/core/lib/support/stack_lockfree.h',
                               'src/core/lib/support/string.h',
                               'src/core/lib/support/string_windows.h',
+                              'src/core/lib/support/thd_internal.h',
                               'src/core/lib/support/time_precise.h',
                               'src/core/lib/support/tmpfile.h',
                               'src/core/ext/transport/chttp2/transport/bin_decoder.h',
@@ -886,7 +896,9 @@
                               'src/core/lib/slice/slice_hash_table.h',
                               'src/core/lib/slice/slice_internal.h',
                               'src/core/lib/slice/slice_string_helpers.h',
-                              'src/core/lib/support/vector.h',
+                              'src/core/lib/support/debug_location.h',
+                              'src/core/lib/support/ref_counted.h',
+                              'src/core/lib/support/ref_counted_ptr.h',
                               'src/core/lib/surface/alarm_internal.h',
                               'src/core/lib/surface/api_trace.h',
                               'src/core/lib/surface/call.h',
diff --git a/gRPC-ProtoRPC.podspec b/gRPC-ProtoRPC.podspec
index db1e8db..cb1c548 100644
--- a/gRPC-ProtoRPC.podspec
+++ b/gRPC-ProtoRPC.podspec
@@ -21,7 +21,7 @@
 
 Pod::Spec.new do |s|
   s.name     = 'gRPC-ProtoRPC'
-  version = '1.8.0-dev'
+  version = '1.9.0-dev'
   s.version  = version
   s.summary  = 'RPC library for Protocol Buffers, based on gRPC'
   s.homepage = 'https://grpc.io'
@@ -52,5 +52,6 @@
     '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',
+    'CLANG_WARN_STRICT_PROTOTYPES' => 'NO',
   }
 end
diff --git a/gRPC-RxLibrary.podspec b/gRPC-RxLibrary.podspec
index 3689779..0f9abb6 100644
--- a/gRPC-RxLibrary.podspec
+++ b/gRPC-RxLibrary.podspec
@@ -21,7 +21,7 @@
 
 Pod::Spec.new do |s|
   s.name     = 'gRPC-RxLibrary'
-  version = '1.8.0-dev'
+  version = '1.9.0-dev'
   s.version  = version
   s.summary  = 'Reactive Extensions library for iOS/OSX.'
   s.homepage = 'https://grpc.io'
@@ -44,4 +44,8 @@
   s.source_files = "#{src_dir}/*.{h,m}", "#{src_dir}/**/*.{h,m}"
   s.private_header_files = "#{src_dir}/private/*.h"
   s.header_mappings_dir = "#{src_dir}"
+
+  s.pod_target_xcconfig = {
+    'CLANG_WARN_STRICT_PROTOTYPES' => 'NO',
+  }
 end
diff --git a/gRPC.podspec b/gRPC.podspec
index 4c6cd35..1f3a0a9 100644
--- a/gRPC.podspec
+++ b/gRPC.podspec
@@ -20,7 +20,7 @@
 
 Pod::Spec.new do |s|
   s.name     = 'gRPC'
-  version = '1.8.0-dev'
+  version = '1.9.0-dev'
   s.version  = version
   s.summary  = 'gRPC client library for iOS/OSX'
   s.homepage = 'https://grpc.io'
@@ -50,6 +50,7 @@
   s.pod_target_xcconfig = {
     # This is needed by all pods that depend on gRPC-RxLibrary:
     'CLANG_ALLOW_NON_MODULAR_INCLUDES_IN_FRAMEWORK_MODULES' => 'YES',
+    'CLANG_WARN_STRICT_PROTOTYPES' => 'NO',
   }
 
   s.subspec 'Main' do |ss|
diff --git a/grpc.def b/grpc.def
index 07c0b3e..d4a18cc 100644
--- a/grpc.def
+++ b/grpc.def
@@ -200,21 +200,6 @@
     gpr_cmdline_usage_string
     gpr_cpu_num_cores
     gpr_cpu_current_cpu
-    gpr_histogram_create
-    gpr_histogram_destroy
-    gpr_histogram_add
-    gpr_histogram_merge
-    gpr_histogram_percentile
-    gpr_histogram_mean
-    gpr_histogram_stddev
-    gpr_histogram_variance
-    gpr_histogram_maximum
-    gpr_histogram_minimum
-    gpr_histogram_count
-    gpr_histogram_sum
-    gpr_histogram_sum_of_squares
-    gpr_histogram_get_contents
-    gpr_histogram_merge_contents
     gpr_join_host_port
     gpr_split_host_port
     gpr_log_severity_string
diff --git a/grpc.gemspec b/grpc.gemspec
index d674c09..d185995 100644
--- a/grpc.gemspec
+++ b/grpc.gemspec
@@ -52,7 +52,6 @@
   s.files += %w( include/grpc/support/avl.h )
   s.files += %w( include/grpc/support/cmdline.h )
   s.files += %w( include/grpc/support/cpu.h )
-  s.files += %w( include/grpc/support/histogram.h )
   s.files += %w( include/grpc/support/host_port.h )
   s.files += %w( include/grpc/support/log.h )
   s.files += %w( include/grpc/support/log_windows.h )
@@ -75,6 +74,7 @@
   s.files += %w( include/grpc/impl/codegen/atm_gcc_atomic.h )
   s.files += %w( include/grpc/impl/codegen/atm_gcc_sync.h )
   s.files += %w( include/grpc/impl/codegen/atm_windows.h )
+  s.files += %w( include/grpc/impl/codegen/fork.h )
   s.files += %w( include/grpc/impl/codegen/gpr_slice.h )
   s.files += %w( include/grpc/impl/codegen/gpr_types.h )
   s.files += %w( include/grpc/impl/codegen/port_platform.h )
@@ -84,19 +84,21 @@
   s.files += %w( include/grpc/impl/codegen/sync_posix.h )
   s.files += %w( include/grpc/impl/codegen/sync_windows.h )
   s.files += %w( src/core/lib/profiling/timers.h )
+  s.files += %w( src/core/lib/support/abstract.h )
   s.files += %w( src/core/lib/support/arena.h )
   s.files += %w( src/core/lib/support/atomic.h )
   s.files += %w( src/core/lib/support/atomic_with_atm.h )
   s.files += %w( src/core/lib/support/atomic_with_std.h )
   s.files += %w( src/core/lib/support/env.h )
+  s.files += %w( src/core/lib/support/fork.h )
   s.files += %w( src/core/lib/support/manual_constructor.h )
   s.files += %w( src/core/lib/support/memory.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/spinlock.h )
-  s.files += %w( src/core/lib/support/stack_lockfree.h )
   s.files += %w( src/core/lib/support/string.h )
   s.files += %w( src/core/lib/support/string_windows.h )
+  s.files += %w( src/core/lib/support/thd_internal.h )
   s.files += %w( src/core/lib/support/time_precise.h )
   s.files += %w( src/core/lib/support/tmpfile.h )
   s.files += %w( src/core/lib/profiling/basic_timers.cc )
@@ -113,7 +115,7 @@
   s.files += %w( src/core/lib/support/env_linux.cc )
   s.files += %w( src/core/lib/support/env_posix.cc )
   s.files += %w( src/core/lib/support/env_windows.cc )
-  s.files += %w( src/core/lib/support/histogram.cc )
+  s.files += %w( src/core/lib/support/fork.cc )
   s.files += %w( src/core/lib/support/host_port.cc )
   s.files += %w( src/core/lib/support/log.cc )
   s.files += %w( src/core/lib/support/log_android.cc )
@@ -122,7 +124,6 @@
   s.files += %w( src/core/lib/support/log_windows.cc )
   s.files += %w( src/core/lib/support/mpscq.cc )
   s.files += %w( src/core/lib/support/murmur_hash.cc )
-  s.files += %w( src/core/lib/support/stack_lockfree.cc )
   s.files += %w( src/core/lib/support/string.cc )
   s.files += %w( src/core/lib/support/string_posix.cc )
   s.files += %w( src/core/lib/support/string_util_windows.cc )
@@ -157,6 +158,7 @@
   s.files += %w( include/grpc/impl/codegen/atm_gcc_atomic.h )
   s.files += %w( include/grpc/impl/codegen/atm_gcc_sync.h )
   s.files += %w( include/grpc/impl/codegen/atm_windows.h )
+  s.files += %w( include/grpc/impl/codegen/fork.h )
   s.files += %w( include/grpc/impl/codegen/gpr_slice.h )
   s.files += %w( include/grpc/impl/codegen/gpr_types.h )
   s.files += %w( include/grpc/impl/codegen/port_platform.h )
@@ -169,6 +171,7 @@
   s.files += %w( include/grpc/byte_buffer.h )
   s.files += %w( include/grpc/byte_buffer_reader.h )
   s.files += %w( include/grpc/compression.h )
+  s.files += %w( include/grpc/fork.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 )
@@ -343,7 +346,9 @@
   s.files += %w( src/core/lib/slice/slice_hash_table.h )
   s.files += %w( src/core/lib/slice/slice_internal.h )
   s.files += %w( src/core/lib/slice/slice_string_helpers.h )
-  s.files += %w( src/core/lib/support/vector.h )
+  s.files += %w( src/core/lib/support/debug_location.h )
+  s.files += %w( src/core/lib/support/ref_counted.h )
+  s.files += %w( src/core/lib/support/ref_counted_ptr.h )
   s.files += %w( src/core/lib/surface/alarm_internal.h )
   s.files += %w( src/core/lib/surface/api_trace.h )
   s.files += %w( src/core/lib/surface/call.h )
@@ -427,6 +432,8 @@
   s.files += %w( src/core/lib/iomgr/ev_windows.cc )
   s.files += %w( src/core/lib/iomgr/exec_ctx.cc )
   s.files += %w( src/core/lib/iomgr/executor.cc )
+  s.files += %w( src/core/lib/iomgr/fork_posix.cc )
+  s.files += %w( src/core/lib/iomgr/fork_windows.cc )
   s.files += %w( src/core/lib/iomgr/gethostname_fallback.cc )
   s.files += %w( src/core/lib/iomgr/gethostname_host_name_max.cc )
   s.files += %w( src/core/lib/iomgr/gethostname_sysconf.cc )
diff --git a/grpc.gyp b/grpc.gyp
index de7af7b..c34206b 100644
--- a/grpc.gyp
+++ b/grpc.gyp
@@ -57,7 +57,6 @@
       '-Wno-long-long',
       '-Wno-unused-parameter',
       '-DOSATOMIC_USE_INLINED=1',
-      '-Ithird_party/abseil-cpp',
     ],
     'ldflags': [
       '-g',
@@ -135,7 +134,6 @@
             '-Wno-long-long',
             '-Wno-unused-parameter',
             '-DOSATOMIC_USE_INLINED=1',
-            '-Ithird_party/abseil-cpp',
           ],
           'OTHER_CPLUSPLUSFLAGS': [
             '-g',
@@ -145,7 +143,6 @@
             '-Wno-long-long',
             '-Wno-unused-parameter',
             '-DOSATOMIC_USE_INLINED=1',
-            '-Ithird_party/abseil-cpp',
             '-stdlib=libc++',
             '-std=c++11',
             '-Wno-error=deprecated-declarations'
@@ -175,7 +172,7 @@
         'src/core/lib/support/env_linux.cc',
         'src/core/lib/support/env_posix.cc',
         'src/core/lib/support/env_windows.cc',
-        'src/core/lib/support/histogram.cc',
+        'src/core/lib/support/fork.cc',
         'src/core/lib/support/host_port.cc',
         'src/core/lib/support/log.cc',
         'src/core/lib/support/log_android.cc',
@@ -184,7 +181,6 @@
         'src/core/lib/support/log_windows.cc',
         'src/core/lib/support/mpscq.cc',
         'src/core/lib/support/murmur_hash.cc',
-        'src/core/lib/support/stack_lockfree.cc',
         'src/core/lib/support/string.cc',
         'src/core/lib/support/string_posix.cc',
         'src/core/lib/support/string_util_windows.cc',
@@ -259,6 +255,8 @@
         'src/core/lib/iomgr/ev_windows.cc',
         'src/core/lib/iomgr/exec_ctx.cc',
         'src/core/lib/iomgr/executor.cc',
+        'src/core/lib/iomgr/fork_posix.cc',
+        'src/core/lib/iomgr/fork_windows.cc',
         'src/core/lib/iomgr/gethostname_fallback.cc',
         'src/core/lib/iomgr/gethostname_host_name_max.cc',
         'src/core/lib/iomgr/gethostname_sysconf.cc',
@@ -507,13 +505,16 @@
         'test/core/iomgr/endpoint_tests.cc',
         'test/core/util/debugger_macros.cc',
         'test/core/util/grpc_profiler.cc',
+        'test/core/util/histogram.cc',
         'test/core/util/memory_counters.cc',
         'test/core/util/mock_endpoint.cc',
         'test/core/util/parse_hexstring.cc',
         'test/core/util/passthru_endpoint.cc',
         'test/core/util/port.cc',
+        'test/core/util/port_isolated_runtime_environment.cc',
         'test/core/util/port_server_client.cc',
         'test/core/util/slice_splitter.cc',
+        'test/core/util/tracer_util.cc',
         'test/core/util/trickle_endpoint.cc',
         'src/core/lib/backoff/backoff.cc',
         'src/core/lib/channel/channel_args.cc',
@@ -548,6 +549,8 @@
         'src/core/lib/iomgr/ev_windows.cc',
         'src/core/lib/iomgr/exec_ctx.cc',
         'src/core/lib/iomgr/executor.cc',
+        'src/core/lib/iomgr/fork_posix.cc',
+        'src/core/lib/iomgr/fork_windows.cc',
         'src/core/lib/iomgr/gethostname_fallback.cc',
         'src/core/lib/iomgr/gethostname_host_name_max.cc',
         'src/core/lib/iomgr/gethostname_sysconf.cc',
@@ -714,13 +717,16 @@
         'test/core/iomgr/endpoint_tests.cc',
         'test/core/util/debugger_macros.cc',
         'test/core/util/grpc_profiler.cc',
+        'test/core/util/histogram.cc',
         'test/core/util/memory_counters.cc',
         'test/core/util/mock_endpoint.cc',
         'test/core/util/parse_hexstring.cc',
         'test/core/util/passthru_endpoint.cc',
         'test/core/util/port.cc',
+        'test/core/util/port_isolated_runtime_environment.cc',
         'test/core/util/port_server_client.cc',
         'test/core/util/slice_splitter.cc',
+        'test/core/util/tracer_util.cc',
         'test/core/util/trickle_endpoint.cc',
         'src/core/lib/backoff/backoff.cc',
         'src/core/lib/channel/channel_args.cc',
@@ -755,6 +761,8 @@
         'src/core/lib/iomgr/ev_windows.cc',
         'src/core/lib/iomgr/exec_ctx.cc',
         'src/core/lib/iomgr/executor.cc',
+        'src/core/lib/iomgr/fork_posix.cc',
+        'src/core/lib/iomgr/fork_windows.cc',
         'src/core/lib/iomgr/gethostname_fallback.cc',
         'src/core/lib/iomgr/gethostname_host_name_max.cc',
         'src/core/lib/iomgr/gethostname_sysconf.cc',
@@ -947,6 +955,8 @@
         'src/core/lib/iomgr/ev_windows.cc',
         'src/core/lib/iomgr/exec_ctx.cc',
         'src/core/lib/iomgr/executor.cc',
+        'src/core/lib/iomgr/fork_posix.cc',
+        'src/core/lib/iomgr/fork_windows.cc',
         'src/core/lib/iomgr/gethostname_fallback.cc',
         'src/core/lib/iomgr/gethostname_host_name_max.cc',
         'src/core/lib/iomgr/gethostname_sysconf.cc',
diff --git a/include/grpc++/impl/codegen/call.h b/include/grpc++/impl/codegen/call.h
index 1a98829..af2c2b5 100644
--- a/include/grpc++/impl/codegen/call.h
+++ b/include/grpc++/impl/codegen/call.h
@@ -313,11 +313,6 @@
   WriteOptions write_options_;
 };
 
-namespace internal {
-template <class T>
-T Example();
-}  // namespace internal
-
 template <class M>
 Status CallOpSendMessage::SendMessage(const M& message, WriteOptions options) {
   write_options_ = options;
@@ -579,6 +574,7 @@
     op->data.recv_status_on_client.trailing_metadata = metadata_map_->arr();
     op->data.recv_status_on_client.status = &status_code_;
     op->data.recv_status_on_client.status_details = &error_message_;
+    op->data.recv_status_on_client.error_string = nullptr;
     op->flags = 0;
     op->reserved = NULL;
   }
diff --git a/include/grpc++/impl/codegen/core_codegen_interface.h b/include/grpc++/impl/codegen/core_codegen_interface.h
index 1949cda..d7ad7a4 100644
--- a/include/grpc++/impl/codegen/core_codegen_interface.h
+++ b/include/grpc++/impl/codegen/core_codegen_interface.h
@@ -25,10 +25,6 @@
 #include <grpc/impl/codegen/grpc_types.h>
 #include <grpc/impl/codegen/sync.h>
 
-extern "C" {
-struct grpc_byte_buffer;
-}
-
 namespace grpc {
 
 /// Interface between the codegen library and the minimal subset of core
diff --git a/include/grpc++/server_builder.h b/include/grpc++/server_builder.h
index 0888bef..e2bae4b 100644
--- a/include/grpc++/server_builder.h
+++ b/include/grpc++/server_builder.h
@@ -55,13 +55,18 @@
   ServerBuilder();
   ~ServerBuilder();
 
-  /// Options for synchronous servers.
-  enum SyncServerOption {
-    NUM_CQS,         ///< Number of completion queues.
-    MIN_POLLERS,     ///< Minimum number of polling threads.
-    MAX_POLLERS,     ///< Maximum number of polling threads.
-    CQ_TIMEOUT_MSEC  ///< Completion queue timeout in milliseconds.
-  };
+  //////////////////////////////////////////////////////////////////////////////
+  // Primary API's
+
+  /// Return a running server which is ready for processing calls.
+  /// Before calling, one typically needs to ensure that:
+  ///  1. a service is registered - so that the server knows what to serve
+  ///     (via RegisterService, or RegisterAsyncGenericService)
+  ///  2. a listening port has been added - so the server knows where to receive
+  ///     traffic (via AddListeningPort)
+  ///  3. [for async api only] completion queues have been added via
+  ///     AddCompletionQueue
+  std::unique_ptr<Server> BuildAndStart();
 
   /// Register a service. This call does not take ownership of the service.
   /// The service must exist for the lifetime of the \a Server instance returned
@@ -69,9 +74,60 @@
   /// Matches requests with any :authority
   ServerBuilder& RegisterService(Service* service);
 
-  /// Register a generic service.
-  /// Matches requests with any :authority
-  ServerBuilder& RegisterAsyncGenericService(AsyncGenericService* service);
+  /// Enlists an endpoint \a addr (port with an optional IP address) to
+  /// bind the \a grpc::Server object to be created to.
+  ///
+  /// It can be invoked multiple times.
+  ///
+  /// \param addr_uri The address to try to bind to the server in URI form. If
+  /// the scheme name is omitted, "dns:///" is assumed. To bind to any address,
+  /// please use IPv6 any, i.e., [::]:<port>, which also accepts IPv4
+  /// connections.  Valid values include dns:///localhost:1234, /
+  /// 192.168.1.1:31416, dns:///[::1]:27182, etc.).
+  /// \param creds The credentials associated with the server.
+  /// \param selected_port[out] If not `nullptr`, gets populated with the port
+  /// number bound to the \a grpc::Server for the corresponding endpoint after
+  /// it is successfully bound, 0 otherwise.
+  ///
+  ServerBuilder& AddListeningPort(const grpc::string& addr_uri,
+                                  std::shared_ptr<ServerCredentials> creds,
+                                  int* selected_port = nullptr);
+
+  /// Add a completion queue for handling asynchronous services.
+  ///
+  /// Best performance is typically obtained by using one thread per polling
+  /// completion queue.
+  ///
+  /// Caller is required to shutdown the server prior to shutting down the
+  /// returned completion queue. Caller is also required to drain the
+  /// completion queue after shutting it down. A typical usage scenario:
+  ///
+  /// // While building the server:
+  /// ServerBuilder builder;
+  /// ...
+  /// cq_ = builder.AddCompletionQueue();
+  /// server_ = builder.BuildAndStart();
+  ///
+  /// // While shutting down the server;
+  /// server_->Shutdown();
+  /// cq_->Shutdown();  // Always *after* the associated server's Shutdown()!
+  /// // Drain the cq_ that was created
+  /// void* ignored_tag;
+  /// bool ignored_ok;
+  /// while (cq_->Next(&ignored_tag, &ignored_ok)) { }
+  ///
+  /// \param is_frequently_polled This is an optional parameter to inform gRPC
+  /// library about whether this completion queue would be frequently polled
+  /// (i.e. by calling \a Next() or \a AsyncNext()). The default value is
+  /// 'true' and is the recommended setting. Setting this to 'false' (i.e.
+  /// not polling the completion queue frequently) will have a significantly
+  /// negative performance impact and hence should not be used in production
+  /// use cases.
+  std::unique_ptr<ServerCompletionQueue> AddCompletionQueue(
+      bool is_frequently_polled = true);
+
+  //////////////////////////////////////////////////////////////////////////////
+  // Less commonly used RegisterService variants
 
   /// Register a service. This call does not take ownership of the service.
   /// The service must exist for the lifetime of the \a Server instance returned
@@ -79,6 +135,15 @@
   /// Only matches requests with :authority \a host
   ServerBuilder& RegisterService(const grpc::string& host, Service* service);
 
+  /// Register a generic service.
+  /// Matches requests with any :authority
+  /// This is mostly useful for writing generic gRPC Proxies where the exact
+  /// serialization format is unknown
+  ServerBuilder& RegisterAsyncGenericService(AsyncGenericService* service);
+
+  //////////////////////////////////////////////////////////////////////////////
+  // Fine control knobs
+
   /// Set max receive message size in bytes.
   ServerBuilder& SetMaxReceiveMessageSize(int max_receive_message_size) {
     max_receive_message_size_ = max_receive_message_size;
@@ -119,6 +184,14 @@
 
   ServerBuilder& SetOption(std::unique_ptr<ServerBuilderOption> option);
 
+  /// Options for synchronous servers.
+  enum SyncServerOption {
+    NUM_CQS,         ///< Number of completion queues.
+    MIN_POLLERS,     ///< Minimum number of polling threads.
+    MAX_POLLERS,     ///< Maximum number of polling threads.
+    CQ_TIMEOUT_MSEC  ///< Completion queue timeout in milliseconds.
+  };
+
   /// Only useful if this is a Synchronous server.
   ServerBuilder& SetSyncServerOption(SyncServerOption option, int value);
 
@@ -129,59 +202,6 @@
     return SetOption(MakeChannelArgumentOption(arg, value));
   }
 
-  /// Enlists an endpoint \a addr (port with an optional IP address) to
-  /// bind the \a grpc::Server object to be created to.
-  ///
-  /// It can be invoked multiple times.
-  ///
-  /// \param addr_uri The address to try to bind to the server in URI form. If
-  /// the scheme name is omitted, "dns:///" is assumed. To bind to any address,
-  /// please use IPv6 any, i.e., [::]:<port>, which also accepts IPv4
-  /// connections.  Valid values include dns:///localhost:1234, /
-  /// 192.168.1.1:31416, dns:///[::1]:27182, etc.).
-  /// \param creds The credentials associated with the server.
-  /// \param selected_port[out] If not `nullptr`, gets populated with the port
-  /// number bound to the \a grpc::Server for the corresponding endpoint after
-  /// it is successfully bound, 0 otherwise.
-  ///
-  // TODO(dgq): the "port" part seems to be a misnomer.
-  ServerBuilder& AddListeningPort(const grpc::string& addr_uri,
-                                  std::shared_ptr<ServerCredentials> creds,
-                                  int* selected_port = nullptr);
-
-  /// Add a completion queue for handling asynchronous services.
-  ///
-  /// Caller is required to shutdown the server prior to shutting down the
-  /// returned completion queue. Caller is also required to drain the
-  /// completion queue after shutting it down. A typical usage scenario:
-  ///
-  /// // While building the server:
-  /// ServerBuilder builder;
-  /// ...
-  /// cq_ = builder.AddCompletionQueue();
-  /// server_ = builder.BuildAndStart();
-  ///
-  /// // While shutting down the server;
-  /// server_->Shutdown();
-  /// cq_->Shutdown();  // Always *after* the associated server's Shutdown()!
-  /// // Drain the cq_ that was created
-  /// void* ignored_tag;
-  /// bool ignored_ok;
-  /// while (cq_->Next(&ignored_tag, &ignored_ok)) { }
-  ///
-  /// \param is_frequently_polled This is an optional parameter to inform gRPC
-  /// library about whether this completion queue would be frequently polled
-  /// (i.e. by calling \a Next() or \a AsyncNext()). The default value is
-  /// 'true' and is the recommended setting. Setting this to 'false' (i.e.
-  /// not polling the completion queue frequently) will have a significantly
-  /// negative performance impact and hence should not be used in production
-  /// use cases.
-  std::unique_ptr<ServerCompletionQueue> AddCompletionQueue(
-      bool is_frequently_polled = true);
-
-  /// Return a running server which is ready for processing calls.
-  std::unique_ptr<Server> BuildAndStart();
-
   /// For internal use only: Register a ServerBuilderPlugin factory function.
   static void InternalAddPluginFactory(
       std::unique_ptr<ServerBuilderPlugin> (*CreatePlugin)());
diff --git a/include/grpc/fork.h b/include/grpc/fork.h
new file mode 100644
index 0000000..ca45e11
--- /dev/null
+++ b/include/grpc/fork.h
@@ -0,0 +1,24 @@
+/*
+ *
+ * Copyright 2017 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#ifndef GRPC_FORK_H
+#define GRPC_FORK_H
+
+#include <grpc/impl/codegen/fork.h>
+
+#endif /* GRPC_FORK_H */
diff --git a/include/grpc/grpc_security.h b/include/grpc/grpc_security.h
index 7e87217..bae07ac 100644
--- a/include/grpc/grpc_security.h
+++ b/include/grpc/grpc_security.h
@@ -185,7 +185,7 @@
 GRPCAPI grpc_call_credentials* grpc_google_compute_engine_credentials_create(
     void* reserved);
 
-GRPCAPI gpr_timespec grpc_max_auth_token_lifetime();
+GRPCAPI gpr_timespec grpc_max_auth_token_lifetime(void);
 
 /** Creates a JWT credentials object. May return NULL if the input is invalid.
    - json_key is the JSON key string containing the client's private key.
diff --git a/include/grpc/impl/codegen/fork.h b/include/grpc/impl/codegen/fork.h
new file mode 100644
index 0000000..baec7a2
--- /dev/null
+++ b/include/grpc/impl/codegen/fork.h
@@ -0,0 +1,48 @@
+/*
+ *
+ * Copyright 2017 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#ifndef GRPC_IMPL_CODEGEN_FORK_H
+#define GRPC_IMPL_CODEGEN_FORK_H
+
+/**
+ * gRPC applications should call this before calling fork().  There should be no
+ * active gRPC function calls between calling grpc_prefork() and
+ * grpc_postfork_parent()/grpc_postfork_child().
+ *
+ *
+ * Typical use:
+ * grpc_prefork();
+ * int pid = fork();
+ * if (pid) {
+ *  grpc_postfork_parent();
+ *  // Parent process..
+ * } else {
+ *  grpc_postfork_child();
+ *  // Child process...
+ * }
+ */
+
+void grpc_prefork();
+
+void grpc_postfork_parent();
+
+void grpc_postfork_child();
+
+void grpc_fork_handlers_auto_register();
+
+#endif /* GRPC_IMPL_CODEGEN_FORK_H */
diff --git a/include/grpc/impl/codegen/grpc_types.h b/include/grpc/impl/codegen/grpc_types.h
index 03be610..ad668b4 100644
--- a/include/grpc/impl/codegen/grpc_types.h
+++ b/include/grpc/impl/codegen/grpc_types.h
@@ -558,6 +558,10 @@
       grpc_metadata_array* trailing_metadata;
       grpc_status_code* status;
       grpc_slice* status_details;
+      /** If this is not nullptr, it will be populated with the full fidelity
+       * error string for debugging purposes. The application is responsible
+       * for freeing the data by using gpr_free(). */
+      const char** error_string;
     } recv_status_on_client;
     struct grpc_op_recv_close_on_server {
       /** out argument, set to 1 if the call failed in any way (seen as a
diff --git a/include/grpc/impl/codegen/port_platform.h b/include/grpc/impl/codegen/port_platform.h
index fb4bfc3..1906886 100644
--- a/include/grpc/impl/codegen/port_platform.h
+++ b/include/grpc/impl/codegen/port_platform.h
@@ -297,6 +297,27 @@
 #endif
 #endif /* GPR_NO_AUTODETECT_PLATFORM */
 
+/*
+ *  There are platforms for which TLS should not be used even though the
+ * compiler makes it seem like it's supported (Android NDK < r12b for example).
+ * This is primarily because of linker problems and toolchain misconfiguration:
+ * TLS isn't supported until NDK r12b per
+ * https://developer.android.com/ndk/downloads/revision_history.html
+ * Since NDK r16, `__NDK_MAJOR__` and `__NDK_MINOR__` are defined in
+ * <android/ndk-version.h>. For NDK < r16, users should define these macros,
+ * e.g. `-D__NDK_MAJOR__=11 -D__NKD_MINOR__=0` for NDK r11. */
+#if defined(__ANDROID__) && defined(__clang__) && defined(GPR_GCC_TLS)
+#if __has_include(<android/ndk-version.h>)
+#include <android/ndk-version.h>
+#endif /* __has_include(<android/ndk-version.h>) */
+#if defined(__ANDROID__) && defined(__clang__) && defined(__NDK_MAJOR__) && \
+    defined(__NDK_MINOR__) &&                                               \
+    ((__NDK_MAJOR__ < 12) || ((__NDK_MAJOR__ == 12) && (__NDK_MINOR__ < 1)))
+#undef GPR_GCC_TLS
+#define GPR_PTHREAD_TLS 1
+#endif
+#endif /*defined(__ANDROID__) && defined(__clang__) && defined(GPR_GCC_TLS) */
+
 #if defined(__has_include)
 #if __has_include(<atomic>)
 #define GRPC_HAS_CXX11_ATOMIC
diff --git a/include/grpc/module.modulemap b/include/grpc/module.modulemap
index 342adc0..67136cb 100644
--- a/include/grpc/module.modulemap
+++ b/include/grpc/module.modulemap
@@ -7,7 +7,6 @@
   header "support/avl.h"
   header "support/cmdline.h"
   header "support/cpu.h"
-  header "support/histogram.h"
   header "support/host_port.h"
   header "support/log.h"
   header "support/log_windows.h"
@@ -21,6 +20,7 @@
   header "support/tls.h"
   header "support/useful.h"
   header "impl/codegen/atm.h"
+  header "impl/codegen/fork.h"
   header "impl/codegen/gpr_slice.h"
   header "impl/codegen/gpr_types.h"
   header "impl/codegen/port_platform.h"
@@ -36,6 +36,7 @@
   header "impl/codegen/slice.h"
   header "impl/codegen/status.h"
   header "impl/codegen/atm.h"
+  header "impl/codegen/fork.h"
   header "impl/codegen/gpr_slice.h"
   header "impl/codegen/gpr_types.h"
   header "impl/codegen/port_platform.h"
@@ -45,6 +46,7 @@
   header "byte_buffer.h"
   header "byte_buffer_reader.h"
   header "compression.h"
+  header "fork.h"
   header "grpc.h"
   header "grpc_posix.h"
   header "grpc_security_constants.h"
diff --git a/include/grpc/support/alloc.h b/include/grpc/support/alloc.h
index 31cb225..c559198 100644
--- a/include/grpc/support/alloc.h
+++ b/include/grpc/support/alloc.h
@@ -58,7 +58,7 @@
 GPRAPI void gpr_set_allocation_functions(gpr_allocation_functions functions);
 
 /** Return the family of allocation functions currently in effect. */
-GPRAPI gpr_allocation_functions gpr_get_allocation_functions();
+GPRAPI gpr_allocation_functions gpr_get_allocation_functions(void);
 
 #ifdef __cplusplus
 }
diff --git a/include/grpc/support/histogram.h b/include/grpc/support/histogram.h
deleted file mode 100644
index d2794d8..0000000
--- a/include/grpc/support/histogram.h
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- *
- * Copyright 2015 gRPC authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-#ifndef GRPC_SUPPORT_HISTOGRAM_H
-#define GRPC_SUPPORT_HISTOGRAM_H
-
-#include <grpc/support/port_platform.h>
-#include <stddef.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-typedef struct gpr_histogram gpr_histogram;
-
-GPRAPI gpr_histogram* gpr_histogram_create(double resolution,
-                                           double max_bucket_start);
-GPRAPI void gpr_histogram_destroy(gpr_histogram* h);
-GPRAPI void gpr_histogram_add(gpr_histogram* h, double x);
-
-/** The following merges the second histogram into the first. It only works
-   if they have the same buckets and resolution. Returns 0 on failure, 1
-   on success */
-GPRAPI int gpr_histogram_merge(gpr_histogram* dst, const gpr_histogram* src);
-
-GPRAPI double gpr_histogram_percentile(gpr_histogram* histogram,
-                                       double percentile);
-GPRAPI double gpr_histogram_mean(gpr_histogram* histogram);
-GPRAPI double gpr_histogram_stddev(gpr_histogram* histogram);
-GPRAPI double gpr_histogram_variance(gpr_histogram* histogram);
-GPRAPI double gpr_histogram_maximum(gpr_histogram* histogram);
-GPRAPI double gpr_histogram_minimum(gpr_histogram* histogram);
-GPRAPI double gpr_histogram_count(gpr_histogram* histogram);
-GPRAPI double gpr_histogram_sum(gpr_histogram* histogram);
-GPRAPI double gpr_histogram_sum_of_squares(gpr_histogram* histogram);
-
-GPRAPI const uint32_t* gpr_histogram_get_contents(gpr_histogram* histogram,
-                                                  size_t* count);
-GPRAPI void gpr_histogram_merge_contents(gpr_histogram* histogram,
-                                         const uint32_t* data,
-                                         size_t data_count, double min_seen,
-                                         double max_seen, double sum,
-                                         double sum_of_squares, double count);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* GRPC_SUPPORT_HISTOGRAM_H */
diff --git a/include/grpc/support/log.h b/include/grpc/support/log.h
index 497cca9..9cce4b1 100644
--- a/include/grpc/support/log.h
+++ b/include/grpc/support/log.h
@@ -68,7 +68,7 @@
 /** Set global log verbosity */
 GPRAPI void gpr_set_log_verbosity(gpr_log_severity min_severity_to_print);
 
-GPRAPI void gpr_log_verbosity_init();
+GPRAPI void gpr_log_verbosity_init(void);
 
 /** Log overrides: applications can use this API to intercept logging calls
    and use their own implementations */
diff --git a/include/grpc/support/tls_gcc.h b/include/grpc/support/tls_gcc.h
index 019acdf..1b91d22 100644
--- a/include/grpc/support/tls_gcc.h
+++ b/include/grpc/support/tls_gcc.h
@@ -26,44 +26,6 @@
 /** Thread local storage based on gcc compiler primitives.
    #include tls.h to use this - and see that file for documentation */
 
-#ifndef NDEBUG
-
-struct gpr_gcc_thread_local {
-  intptr_t value;
-  bool* inited;
-};
-
-#define GPR_TLS_DECL(name)           \
-  static bool name##_inited = false; \
-  static __thread struct gpr_gcc_thread_local name = {0, &(name##_inited)}
-
-#define gpr_tls_init(tls)                  \
-  do {                                     \
-    GPR_ASSERT(*((tls)->inited) == false); \
-    *((tls)->inited) = true;               \
-  } while (0)
-
-/** It is allowed to call gpr_tls_init after gpr_tls_destroy is called. */
-#define gpr_tls_destroy(tls)      \
-  do {                            \
-    GPR_ASSERT(*((tls)->inited)); \
-    *((tls)->inited) = false;     \
-  } while (0)
-
-#define gpr_tls_set(tls, new_value) \
-  do {                              \
-    GPR_ASSERT(*((tls)->inited));   \
-    (tls)->value = (new_value);     \
-  } while (0)
-
-#define gpr_tls_get(tls)          \
-  ({                              \
-    GPR_ASSERT(*((tls)->inited)); \
-    (tls)->value;                 \
-  })
-
-#else /* NDEBUG */
-
 struct gpr_gcc_thread_local {
   intptr_t value;
 };
@@ -80,6 +42,4 @@
 #define gpr_tls_set(tls, new_value) (((tls)->value) = (new_value))
 #define gpr_tls_get(tls) ((tls)->value)
 
-#endif /* NDEBUG */
-
 #endif /* GRPC_SUPPORT_TLS_GCC_H */
diff --git a/package.json b/package.json
new file mode 100644
index 0000000..2b7930c
--- /dev/null
+++ b/package.json
@@ -0,0 +1,103 @@
+{
+  "name": "grpc",
+  "version": "1.7.2",
+  "author": "Google Inc.",
+  "description": "gRPC Library for Node",
+  "homepage": "https://grpc.io/",
+  "repository": {
+    "type": "git",
+    "url": "https://github.com/grpc/grpc.git"
+  },
+  "bugs": "https://github.com/grpc/grpc/issues",
+  "contributors": [
+    {
+      "name": "Michael Lumish",
+      "email": "mlumish@google.com"
+    }
+  ],
+  "directories": {
+    "lib": "src/node/src"
+  },
+  "scripts": {
+    "lint": "node ./node_modules/jshint/bin/jshint src/node/src src/node/test src/node/interop src/node/index.js --exclude-path=src/node/.jshintignore",
+    "test": "./node_modules/.bin/mocha src/node/test && npm run-script lint",
+    "electron-build": "./node_modules/.bin/node-pre-gyp configure build --runtime=electron --disturl=https://atom.io/download/atom-shell",
+    "gen_docs": "./node_modules/.bin/jsdoc -c src/node/jsdoc_conf.json",
+    "coverage": "./node_modules/.bin/istanbul cover ./node_modules/.bin/_mocha src/node/test",
+    "install": "./node_modules/.bin/node-pre-gyp install --fallback-to-build --library=static_library"
+  },
+  "bundledDependencies": [
+    "node-pre-gyp"
+  ],
+  "dependencies": {
+    "arguejs": "^0.2.3",
+    "lodash": "^4.15.0",
+    "nan": "^2.0.0",
+    "node-pre-gyp": "^0.6.35",
+    "protobufjs": "^5.0.0"
+  },
+  "devDependencies": {
+    "async": "^2.0.1",
+    "body-parser": "^1.15.2",
+    "electron-mocha": "^3.1.1",
+    "express": "^4.14.0",
+    "google-auth-library": "^0.9.2",
+    "google-protobuf": "^3.0.0",
+    "istanbul": "^0.4.4",
+    "jsdoc": "^3.3.2",
+    "jshint": "^2.5.0",
+    "minimist": "^1.1.0",
+    "mocha": "^3.0.2",
+    "mocha-jenkins-reporter": "^0.2.3",
+    "poisson-process": "^0.2.1"
+  },
+  "engines": {
+    "node": ">=4"
+  },
+  "binary": {
+    "module_name": "grpc_node",
+    "module_path": "src/node/extension_binary/{node_abi}-{platform}-{arch}",
+    "host": "https://storage.googleapis.com/",
+    "remote_path": "grpc-precompiled-binaries/node/{name}/v{version}",
+    "package_name": "{node_abi}-{platform}-{arch}.tar.gz"
+  },
+  "files": [
+    "LICENSE",
+    "src/node/README.md",
+    "src/proto",
+    "etc",
+    "src/node/index.js",
+    "src/node/src",
+    "src/node/ext",
+    "include/grpc",
+    "src/core",
+    "src/boringssl",
+    "src/zlib",
+    "third_party/nanopb",
+    "third_party/zlib",
+    "third_party/boringssl",
+    "binding.gyp"
+  ],
+  "main": "src/node/index.js",
+  "license": "Apache-2.0",
+  "jshintConfig": {
+    "bitwise": true,
+    "curly": true,
+    "eqeqeq": true,
+    "esnext": true,
+    "freeze": true,
+    "immed": true,
+    "indent": 2,
+    "latedef": "nofunc",
+    "maxlen": 80,
+    "mocha": true,
+    "newcap": true,
+    "node": true,
+    "noarg": true,
+    "quotmark": "single",
+    "strict": true,
+    "trailing": true,
+    "undef": true,
+    "unused": "vars"
+  }
+}
diff --git a/package.xml b/package.xml
index 3356c27..b4d8c88 100644
--- a/package.xml
+++ b/package.xml
@@ -13,8 +13,8 @@
  <date>2017-08-24</date>
  <time>16:06:07</time>
  <version>
-  <release>1.8.0dev</release>
-  <api>1.8.0dev</api>
+  <release>1.9.0dev</release>
+  <api>1.9.0dev</api>
  </version>
  <stability>
   <release>beta</release>
@@ -64,7 +64,6 @@
     <file baseinstalldir="/" name="include/grpc/support/avl.h" role="src" />
     <file baseinstalldir="/" name="include/grpc/support/cmdline.h" role="src" />
     <file baseinstalldir="/" name="include/grpc/support/cpu.h" role="src" />
-    <file baseinstalldir="/" name="include/grpc/support/histogram.h" role="src" />
     <file baseinstalldir="/" name="include/grpc/support/host_port.h" role="src" />
     <file baseinstalldir="/" name="include/grpc/support/log.h" role="src" />
     <file baseinstalldir="/" name="include/grpc/support/log_windows.h" role="src" />
@@ -87,6 +86,7 @@
     <file baseinstalldir="/" name="include/grpc/impl/codegen/atm_gcc_atomic.h" role="src" />
     <file baseinstalldir="/" name="include/grpc/impl/codegen/atm_gcc_sync.h" role="src" />
     <file baseinstalldir="/" name="include/grpc/impl/codegen/atm_windows.h" role="src" />
+    <file baseinstalldir="/" name="include/grpc/impl/codegen/fork.h" role="src" />
     <file baseinstalldir="/" name="include/grpc/impl/codegen/gpr_slice.h" role="src" />
     <file baseinstalldir="/" name="include/grpc/impl/codegen/gpr_types.h" role="src" />
     <file baseinstalldir="/" name="include/grpc/impl/codegen/port_platform.h" role="src" />
@@ -96,19 +96,21 @@
     <file baseinstalldir="/" name="include/grpc/impl/codegen/sync_posix.h" role="src" />
     <file baseinstalldir="/" name="include/grpc/impl/codegen/sync_windows.h" role="src" />
     <file baseinstalldir="/" name="src/core/lib/profiling/timers.h" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/support/abstract.h" role="src" />
     <file baseinstalldir="/" name="src/core/lib/support/arena.h" role="src" />
     <file baseinstalldir="/" name="src/core/lib/support/atomic.h" role="src" />
     <file baseinstalldir="/" name="src/core/lib/support/atomic_with_atm.h" role="src" />
     <file baseinstalldir="/" name="src/core/lib/support/atomic_with_std.h" role="src" />
     <file baseinstalldir="/" name="src/core/lib/support/env.h" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/support/fork.h" role="src" />
     <file baseinstalldir="/" name="src/core/lib/support/manual_constructor.h" role="src" />
     <file baseinstalldir="/" name="src/core/lib/support/memory.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/spinlock.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" />
     <file baseinstalldir="/" name="src/core/lib/support/string_windows.h" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/support/thd_internal.h" role="src" />
     <file baseinstalldir="/" name="src/core/lib/support/time_precise.h" role="src" />
     <file baseinstalldir="/" name="src/core/lib/support/tmpfile.h" role="src" />
     <file baseinstalldir="/" name="src/core/lib/profiling/basic_timers.cc" role="src" />
@@ -125,7 +127,7 @@
     <file baseinstalldir="/" name="src/core/lib/support/env_linux.cc" role="src" />
     <file baseinstalldir="/" name="src/core/lib/support/env_posix.cc" role="src" />
     <file baseinstalldir="/" name="src/core/lib/support/env_windows.cc" role="src" />
-    <file baseinstalldir="/" name="src/core/lib/support/histogram.cc" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/support/fork.cc" role="src" />
     <file baseinstalldir="/" name="src/core/lib/support/host_port.cc" role="src" />
     <file baseinstalldir="/" name="src/core/lib/support/log.cc" role="src" />
     <file baseinstalldir="/" name="src/core/lib/support/log_android.cc" role="src" />
@@ -134,7 +136,6 @@
     <file baseinstalldir="/" name="src/core/lib/support/log_windows.cc" role="src" />
     <file baseinstalldir="/" name="src/core/lib/support/mpscq.cc" role="src" />
     <file baseinstalldir="/" name="src/core/lib/support/murmur_hash.cc" role="src" />
-    <file baseinstalldir="/" name="src/core/lib/support/stack_lockfree.cc" role="src" />
     <file baseinstalldir="/" name="src/core/lib/support/string.cc" role="src" />
     <file baseinstalldir="/" name="src/core/lib/support/string_posix.cc" role="src" />
     <file baseinstalldir="/" name="src/core/lib/support/string_util_windows.cc" role="src" />
@@ -169,6 +170,7 @@
     <file baseinstalldir="/" name="include/grpc/impl/codegen/atm_gcc_atomic.h" role="src" />
     <file baseinstalldir="/" name="include/grpc/impl/codegen/atm_gcc_sync.h" role="src" />
     <file baseinstalldir="/" name="include/grpc/impl/codegen/atm_windows.h" role="src" />
+    <file baseinstalldir="/" name="include/grpc/impl/codegen/fork.h" role="src" />
     <file baseinstalldir="/" name="include/grpc/impl/codegen/gpr_slice.h" role="src" />
     <file baseinstalldir="/" name="include/grpc/impl/codegen/gpr_types.h" role="src" />
     <file baseinstalldir="/" name="include/grpc/impl/codegen/port_platform.h" role="src" />
@@ -181,6 +183,7 @@
     <file baseinstalldir="/" name="include/grpc/byte_buffer.h" role="src" />
     <file baseinstalldir="/" name="include/grpc/byte_buffer_reader.h" role="src" />
     <file baseinstalldir="/" name="include/grpc/compression.h" role="src" />
+    <file baseinstalldir="/" name="include/grpc/fork.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" />
@@ -355,7 +358,9 @@
     <file baseinstalldir="/" name="src/core/lib/slice/slice_hash_table.h" role="src" />
     <file baseinstalldir="/" name="src/core/lib/slice/slice_internal.h" role="src" />
     <file baseinstalldir="/" name="src/core/lib/slice/slice_string_helpers.h" role="src" />
-    <file baseinstalldir="/" name="src/core/lib/support/vector.h" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/support/debug_location.h" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/support/ref_counted.h" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/support/ref_counted_ptr.h" role="src" />
     <file baseinstalldir="/" name="src/core/lib/surface/alarm_internal.h" role="src" />
     <file baseinstalldir="/" name="src/core/lib/surface/api_trace.h" role="src" />
     <file baseinstalldir="/" name="src/core/lib/surface/call.h" role="src" />
@@ -439,6 +444,8 @@
     <file baseinstalldir="/" name="src/core/lib/iomgr/ev_windows.cc" role="src" />
     <file baseinstalldir="/" name="src/core/lib/iomgr/exec_ctx.cc" role="src" />
     <file baseinstalldir="/" name="src/core/lib/iomgr/executor.cc" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/iomgr/fork_posix.cc" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/iomgr/fork_windows.cc" role="src" />
     <file baseinstalldir="/" name="src/core/lib/iomgr/gethostname_fallback.cc" role="src" />
     <file baseinstalldir="/" name="src/core/lib/iomgr/gethostname_host_name_max.cc" role="src" />
     <file baseinstalldir="/" name="src/core/lib/iomgr/gethostname_sysconf.cc" role="src" />
diff --git a/requirements.txt b/requirements.txt
index 1296995..c976cef 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -3,6 +3,6 @@
 cython>=0.23
 enum34>=1.0.4
 futures>=2.2.0
-protobuf>=3.2.0
+protobuf>=3.5.0.post1
 six>=1.10
 wheel>=0.29
diff --git a/setup.py b/setup.py
index bf8aea6..73af9eb 100644
--- a/setup.py
+++ b/setup.py
@@ -173,7 +173,7 @@
     # on msvc, but only for 32 bits
     DEFINE_MACROS += (('NTDDI_VERSION', 0x06000000),)
 else:
-  DEFINE_MACROS += (('HAVE_CONFIG_H', 1),)
+  DEFINE_MACROS += (('HAVE_CONFIG_H', 1), ('GRPC_ENABLE_FORK_SUPPORT', 1),)
 
 LDFLAGS = tuple(EXTRA_LINK_ARGS)
 CFLAGS = tuple(EXTRA_COMPILE_ARGS)
@@ -181,6 +181,7 @@
   pymodinit_type = 'PyObject*' if PY3 else 'void'
   pymodinit = '__attribute__((visibility ("default"))) {}'.format(pymodinit_type)
   DEFINE_MACROS += (('PyMODINIT_FUNC', pymodinit),)
+  DEFINE_MACROS += (('GRPC_POSIX_FORK_ALLOW_PTHREAD_ATFORK', 1),)
 
 # By default, Python3 distutils enforces compatibility of
 # c plugins (.so files) with the OSX version Python3 was built with.
@@ -237,7 +238,7 @@
     'six>=1.5.2',
     # TODO(atash): eventually split the grpcio package into a metapackage
     # depending on protobuf and the runtime component (independent of protobuf)
-    'protobuf>=3.3.0',
+    'protobuf>=3.5.0.post1',
 )
 
 if not PY3:
diff --git a/src/compiler/cpp_generator.cc b/src/compiler/cpp_generator.cc
index 3adf0fa..dec8cd0 100644
--- a/src/compiler/cpp_generator.cc
+++ b/src/compiler/cpp_generator.cc
@@ -104,7 +104,7 @@
     grpc::string leading_comments = file->GetLeadingComments("//");
     if (!leading_comments.empty()) {
       printer->Print(vars, "// Original file comments:\n");
-      printer->Print(leading_comments.c_str());
+      printer->PrintRaw(leading_comments.c_str());
     }
     printer->Print(vars, "#ifndef GRPC_$filename_identifier$__INCLUDED\n");
     printer->Print(vars, "#define GRPC_$filename_identifier$__INCLUDED\n");
diff --git a/src/compiler/csharp_generator.cc b/src/compiler/csharp_generator.cc
index e0957bf..40fe0b0 100644
--- a/src/compiler/csharp_generator.cc
+++ b/src/compiler/csharp_generator.cc
@@ -666,7 +666,7 @@
     grpc::string leading_comments = GetCsharpComments(file, true);
     if (!leading_comments.empty()) {
       out.Print("// Original file comments:\n");
-      out.Print(leading_comments.c_str());
+      out.PrintRaw(leading_comments.c_str());
     }
 
     out.Print("#pragma warning disable 1591\n");
diff --git a/src/compiler/node_generator.cc b/src/compiler/node_generator.cc
index ed835b4..661587c 100644
--- a/src/compiler/node_generator.cc
+++ b/src/compiler/node_generator.cc
@@ -250,7 +250,7 @@
     grpc::string leading_comments = GetNodeComments(file, true);
     if (!leading_comments.empty()) {
       out.Print("// Original file comments:\n");
-      out.Print(leading_comments.c_str());
+      out.PrintRaw(leading_comments.c_str());
     }
 
     out.Print("'use strict';\n");
diff --git a/src/compiler/objective_c_generator.cc b/src/compiler/objective_c_generator.cc
index 349f1dc..ab7d869 100644
--- a/src/compiler/objective_c_generator.cc
+++ b/src/compiler/objective_c_generator.cc
@@ -28,6 +28,7 @@
 
 using ::google::protobuf::compiler::objectivec::ClassName;
 using ::grpc::protobuf::FileDescriptor;
+using ::grpc::protobuf::FileDescriptor;
 using ::grpc::protobuf::MethodDescriptor;
 using ::grpc::protobuf::ServiceDescriptor;
 using ::grpc::protobuf::io::Printer;
@@ -65,7 +66,7 @@
     printer->Print(" * ");
     size_t start_pos = it->find_first_not_of(' ');
     if (start_pos != grpc::string::npos) {
-      printer->Print(it->c_str() + start_pos);
+      printer->PrintRaw(it->c_str() + start_pos);
     }
     printer->Print("\n");
   }
diff --git a/src/compiler/objective_c_generator.h b/src/compiler/objective_c_generator.h
index 2337aba..d3aed76 100644
--- a/src/compiler/objective_c_generator.h
+++ b/src/compiler/objective_c_generator.h
@@ -24,6 +24,7 @@
 namespace grpc_objective_c_generator {
 
 using ::grpc::protobuf::FileDescriptor;
+using ::grpc::protobuf::FileDescriptor;
 using ::grpc::protobuf::ServiceDescriptor;
 using ::grpc::string;
 
diff --git a/src/compiler/objective_c_plugin.cc b/src/compiler/objective_c_plugin.cc
index 53ff81f..d5d488e 100644
--- a/src/compiler/objective_c_plugin.cc
+++ b/src/compiler/objective_c_plugin.cc
@@ -51,12 +51,15 @@
     {
       // Generate .pbrpc.h
 
-      ::grpc::string imports = ::grpc::string("#import \"") + file_name +
-                               ".pbobjc.h\"\n\n"
-                               "#import <ProtoRPC/ProtoService.h>\n"
-                               "#import <ProtoRPC/ProtoRPC.h>\n"
-                               "#import <RxLibrary/GRXWriteable.h>\n"
-                               "#import <RxLibrary/GRXWriter.h>\n";
+      ::grpc::string imports =
+          ::grpc::string("#if !GPB_GRPC_FORWARD_DECLARE_MESSAGE_PROTO\n") +
+          "#import \"" + file_name +
+          ".pbobjc.h\"\n"
+          "#endif\n\n"
+          "#import <ProtoRPC/ProtoService.h>\n"
+          "#import <ProtoRPC/ProtoRPC.h>\n"
+          "#import <RxLibrary/GRXWriteable.h>\n"
+          "#import <RxLibrary/GRXWriter.h>\n";
 
       ::grpc::string proto_imports;
       proto_imports += "#if GPB_GRPC_FORWARD_DECLARE_MESSAGE_PROTO\n" +
@@ -105,7 +108,10 @@
       // Generate .pbrpc.m
 
       ::grpc::string imports = ::grpc::string("#import \"") + file_name +
-                               ".pbrpc.h\"\n\n"
+                               ".pbrpc.h\"\n"
+                               "#import \"" +
+                               file_name +
+                               ".pbobjc.h\"\n\n"
                                "#import <ProtoRPC/ProtoRPC.h>\n"
                                "#import <RxLibrary/GRXWriter+Immediate.h>\n";
       for (int i = 0; i < file->dependency_count(); i++) {
diff --git a/src/compiler/php_generator.cc b/src/compiler/php_generator.cc
index 1ff9520..d9705e8 100644
--- a/src/compiler/php_generator.cc
+++ b/src/compiler/php_generator.cc
@@ -164,7 +164,7 @@
     grpc::string leading_comments = GetPHPComments(file, "//");
     if (!leading_comments.empty()) {
       out.Print("// Original file comments:\n");
-      out.Print(leading_comments.c_str());
+      out.PrintRaw(leading_comments.c_str());
     }
 
     map<grpc::string, grpc::string> vars;
diff --git a/src/compiler/protobuf_plugin.h b/src/compiler/protobuf_plugin.h
index 1551908..b971af1 100644
--- a/src/compiler/protobuf_plugin.h
+++ b/src/compiler/protobuf_plugin.h
@@ -141,6 +141,7 @@
   }
 
   void Print(const char* string) { printer_.Print(string); }
+  void PrintRaw(const char* string) { printer_.PrintRaw(string); }
   void Indent() { printer_.Indent(); }
   void Outdent() { printer_.Outdent(); }
 
diff --git a/src/compiler/python_generator.cc b/src/compiler/python_generator.cc
index c1ae7d3..8a0b889 100644
--- a/src/compiler/python_generator.cc
+++ b/src/compiler/python_generator.cc
@@ -101,7 +101,7 @@
        ++it) {
     size_t start_pos = it->find_first_not_of(' ');
     if (start_pos != grpc::string::npos) {
-      out->Print(it->c_str() + start_pos);
+      out->PrintRaw(it->c_str() + start_pos);
     }
     out->Print("\n");
   }
diff --git a/src/compiler/ruby_generator.cc b/src/compiler/ruby_generator.cc
index ed7e074..e81dea6 100644
--- a/src/compiler/ruby_generator.cc
+++ b/src/compiler/ruby_generator.cc
@@ -174,7 +174,7 @@
     grpc::string leading_comments = GetRubyComments(file, true);
     if (!leading_comments.empty()) {
       out.Print("# Original file comments:\n");
-      out.Print(leading_comments.c_str());
+      out.PrintRaw(leading_comments.c_str());
     }
 
     out.Print("\n");
diff --git a/src/compiler/schema_interface.h b/src/compiler/schema_interface.h
index b2021f2..c000478 100644
--- a/src/compiler/schema_interface.h
+++ b/src/compiler/schema_interface.h
@@ -86,6 +86,7 @@
   virtual void Print(const std::map<grpc::string, grpc::string>& vars,
                      const char* template_string) = 0;
   virtual void Print(const char* string) = 0;
+  virtual void PrintRaw(const char* string) = 0;
   virtual void Indent() = 0;
   virtual void Outdent() = 0;
 };
diff --git a/src/core/ext/filters/client_channel/channel_connectivity.cc b/src/core/ext/filters/client_channel/channel_connectivity.cc
index d3627a2..7eaf5d9 100644
--- a/src/core/ext/filters/client_channel/channel_connectivity.cc
+++ b/src/core/ext/filters/client_channel/channel_connectivity.cc
@@ -122,7 +122,7 @@
   gpr_mu_lock(&w->mu);
 
   if (due_to_completion) {
-    if (GRPC_TRACER_ON(grpc_trace_operation_failures)) {
+    if (grpc_trace_operation_failures.enabled()) {
       GRPC_LOG_IF_ERROR("watch_completion_error", GRPC_ERROR_REF(error));
     }
     GRPC_ERROR_UNREF(error);
diff --git a/src/core/ext/filters/client_channel/client_channel.cc b/src/core/ext/filters/client_channel/client_channel.cc
index 8b8d512..58496dc 100644
--- a/src/core/ext/filters/client_channel/client_channel.cc
+++ b/src/core/ext/filters/client_channel/client_channel.cc
@@ -56,8 +56,7 @@
 
 /* Client channel implementation */
 
-grpc_tracer_flag grpc_client_channel_trace =
-    GRPC_TRACER_INITIALIZER(false, "client_channel");
+grpc_core::TraceFlag grpc_client_channel_trace(false, "client_channel");
 
 /*************************************************************************
  * METHOD-CONFIG TABLE
@@ -248,7 +247,7 @@
                                          GRPC_ERROR_REF(error));
     }
   }
-  if (GRPC_TRACER_ON(grpc_client_channel_trace)) {
+  if (grpc_client_channel_trace.enabled()) {
     gpr_log(GPR_DEBUG, "chand=%p: setting connectivity state to %s", chand,
             grpc_connectivity_state_name(state));
   }
@@ -262,7 +261,7 @@
   grpc_connectivity_state publish_state = w->state;
   /* check if the notification is for the latest policy */
   if (w->lb_policy == w->chand->lb_policy) {
-    if (GRPC_TRACER_ON(grpc_client_channel_trace)) {
+    if (grpc_client_channel_trace.enabled()) {
       gpr_log(GPR_DEBUG, "chand=%p: lb_policy=%p state changed to %s", w->chand,
               w->lb_policy, grpc_connectivity_state_name(w->state));
     }
@@ -300,7 +299,7 @@
 
 static void start_resolving_locked(grpc_exec_ctx* exec_ctx,
                                    channel_data* chand) {
-  if (GRPC_TRACER_ON(grpc_client_channel_trace)) {
+  if (grpc_client_channel_trace.enabled()) {
     gpr_log(GPR_DEBUG, "chand=%p: starting name resolution", chand);
   }
   GPR_ASSERT(!chand->started_resolving);
@@ -373,7 +372,7 @@
 static void on_resolver_result_changed_locked(grpc_exec_ctx* exec_ctx,
                                               void* arg, grpc_error* error) {
   channel_data* chand = (channel_data*)arg;
-  if (GRPC_TRACER_ON(grpc_client_channel_trace)) {
+  if (grpc_client_channel_trace.enabled()) {
     gpr_log(GPR_DEBUG, "chand=%p: got resolver result: error=%s", chand,
             grpc_error_string(error));
   }
@@ -433,7 +432,7 @@
     // once at any given time.
     lb_policy_name_changed =
         chand->info_lb_policy_name == nullptr ||
-        strcmp(chand->info_lb_policy_name, lb_policy_name) != 0;
+        gpr_stricmp(chand->info_lb_policy_name, lb_policy_name) != 0;
     if (chand->lb_policy != nullptr && !lb_policy_name_changed) {
       // Continue using the same LB policy.  Update with new addresses.
       lb_policy_updated = true;
@@ -483,7 +482,7 @@
     grpc_channel_args_destroy(exec_ctx, chand->resolver_result);
     chand->resolver_result = nullptr;
   }
-  if (GRPC_TRACER_ON(grpc_client_channel_trace)) {
+  if (grpc_client_channel_trace.enabled()) {
     gpr_log(GPR_DEBUG,
             "chand=%p: resolver result: lb_policy_name=\"%s\"%s, "
             "service_config=\"%s\"",
@@ -524,7 +523,7 @@
   if (new_lb_policy != nullptr || error != GRPC_ERROR_NONE ||
       chand->resolver == nullptr) {
     if (chand->lb_policy != nullptr) {
-      if (GRPC_TRACER_ON(grpc_client_channel_trace)) {
+      if (grpc_client_channel_trace.enabled()) {
         gpr_log(GPR_DEBUG, "chand=%p: unreffing lb_policy=%p", chand,
                 chand->lb_policy);
       }
@@ -538,11 +537,11 @@
   // Now that we've swapped out the relevant fields of chand, check for
   // error or shutdown.
   if (error != GRPC_ERROR_NONE || chand->resolver == nullptr) {
-    if (GRPC_TRACER_ON(grpc_client_channel_trace)) {
+    if (grpc_client_channel_trace.enabled()) {
       gpr_log(GPR_DEBUG, "chand=%p: shutting down", chand);
     }
     if (chand->resolver != nullptr) {
-      if (GRPC_TRACER_ON(grpc_client_channel_trace)) {
+      if (grpc_client_channel_trace.enabled()) {
         gpr_log(GPR_DEBUG, "chand=%p: shutting down resolver", chand);
       }
       grpc_resolver_shutdown_locked(exec_ctx, chand->resolver);
@@ -565,7 +564,7 @@
     grpc_error* state_error =
         GRPC_ERROR_CREATE_FROM_STATIC_STRING("No load balancing policy");
     if (new_lb_policy != nullptr) {
-      if (GRPC_TRACER_ON(grpc_client_channel_trace)) {
+      if (grpc_client_channel_trace.enabled()) {
         gpr_log(GPR_DEBUG, "chand=%p: initializing new LB policy", chand);
       }
       GRPC_ERROR_UNREF(state_error);
@@ -899,7 +898,7 @@
                                           grpc_call_element* elem,
                                           grpc_error* error) {
   call_data* calld = (call_data*)elem->call_data;
-  if (GRPC_TRACER_ON(grpc_client_channel_trace)) {
+  if (grpc_client_channel_trace.enabled()) {
     gpr_log(GPR_DEBUG,
             "chand=%p calld=%p: failing %" PRIuPTR " pending batches: %s",
             elem->channel_data, calld, calld->waiting_for_pick_batches_count,
@@ -942,7 +941,7 @@
                                             grpc_call_element* elem) {
   channel_data* chand = (channel_data*)elem->channel_data;
   call_data* calld = (call_data*)elem->call_data;
-  if (GRPC_TRACER_ON(grpc_client_channel_trace)) {
+  if (grpc_client_channel_trace.enabled()) {
     gpr_log(GPR_DEBUG,
             "chand=%p calld=%p: sending %" PRIuPTR
             " pending batches to subchannel_call=%p",
@@ -969,7 +968,7 @@
                                                 grpc_call_element* elem) {
   channel_data* chand = (channel_data*)elem->channel_data;
   call_data* calld = (call_data*)elem->call_data;
-  if (GRPC_TRACER_ON(grpc_client_channel_trace)) {
+  if (grpc_client_channel_trace.enabled()) {
     gpr_log(GPR_DEBUG, "chand=%p calld=%p: applying service config to call",
             chand, calld);
   }
@@ -1015,7 +1014,7 @@
   grpc_error* new_error = grpc_connected_subchannel_create_call(
       exec_ctx, calld->connected_subchannel, &call_args,
       &calld->subchannel_call);
-  if (GRPC_TRACER_ON(grpc_client_channel_trace)) {
+  if (grpc_client_channel_trace.enabled()) {
     gpr_log(GPR_DEBUG, "chand=%p calld=%p: create subchannel_call=%p: error=%s",
             chand, calld, calld->subchannel_call, grpc_error_string(new_error));
   }
@@ -1041,7 +1040,7 @@
                              "Call dropped by load balancing policy")
                        : GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING(
                              "Failed to create subchannel", &error, 1);
-    if (GRPC_TRACER_ON(grpc_client_channel_trace)) {
+    if (grpc_client_channel_trace.enabled()) {
       gpr_log(GPR_DEBUG,
               "chand=%p calld=%p: failed to create subchannel: error=%s", chand,
               calld, grpc_error_string(calld->error));
@@ -1075,7 +1074,7 @@
   channel_data* chand = (channel_data*)elem->channel_data;
   call_data* calld = (call_data*)elem->call_data;
   if (calld->lb_policy != nullptr) {
-    if (GRPC_TRACER_ON(grpc_client_channel_trace)) {
+    if (grpc_client_channel_trace.enabled()) {
       gpr_log(GPR_DEBUG, "chand=%p calld=%p: cancelling pick from LB policy %p",
               chand, calld, calld->lb_policy);
     }
@@ -1093,7 +1092,7 @@
   grpc_call_element* elem = (grpc_call_element*)arg;
   channel_data* chand = (channel_data*)elem->channel_data;
   call_data* calld = (call_data*)elem->call_data;
-  if (GRPC_TRACER_ON(grpc_client_channel_trace)) {
+  if (grpc_client_channel_trace.enabled()) {
     gpr_log(GPR_DEBUG, "chand=%p calld=%p: pick completed asynchronously",
             chand, calld);
   }
@@ -1110,7 +1109,7 @@
                                        grpc_call_element* elem) {
   channel_data* chand = (channel_data*)elem->channel_data;
   call_data* calld = (call_data*)elem->call_data;
-  if (GRPC_TRACER_ON(grpc_client_channel_trace)) {
+  if (grpc_client_channel_trace.enabled()) {
     gpr_log(GPR_DEBUG, "chand=%p calld=%p: starting pick on lb_policy=%p",
             chand, calld, chand->lb_policy);
   }
@@ -1148,7 +1147,7 @@
       calld->subchannel_call_context, nullptr, &calld->lb_pick_closure);
   if (pick_done) {
     /* synchronous grpc_lb_policy_pick call. Unref the LB policy. */
-    if (GRPC_TRACER_ON(grpc_client_channel_trace)) {
+    if (grpc_client_channel_trace.enabled()) {
       gpr_log(GPR_DEBUG, "chand=%p calld=%p: pick completed synchronously",
               chand, calld);
     }
@@ -1193,7 +1192,7 @@
   grpc_call_element* elem = args->elem;
   channel_data* chand = (channel_data*)elem->channel_data;
   call_data* calld = (call_data*)elem->call_data;
-  if (GRPC_TRACER_ON(grpc_client_channel_trace)) {
+  if (grpc_client_channel_trace.enabled()) {
     gpr_log(GPR_DEBUG,
             "chand=%p calld=%p: cancelling pick waiting for resolver result",
             chand, calld);
@@ -1217,7 +1216,7 @@
   pick_after_resolver_result_args* args = (pick_after_resolver_result_args*)arg;
   if (args->finished) {
     /* cancelled, do nothing */
-    if (GRPC_TRACER_ON(grpc_client_channel_trace)) {
+    if (grpc_client_channel_trace.enabled()) {
       gpr_log(GPR_DEBUG, "call cancelled before resolver result");
     }
     gpr_free(args);
@@ -1228,13 +1227,13 @@
   channel_data* chand = (channel_data*)elem->channel_data;
   call_data* calld = (call_data*)elem->call_data;
   if (error != GRPC_ERROR_NONE) {
-    if (GRPC_TRACER_ON(grpc_client_channel_trace)) {
+    if (grpc_client_channel_trace.enabled()) {
       gpr_log(GPR_DEBUG, "chand=%p calld=%p: resolver failed to return data",
               chand, calld);
     }
     async_pick_done_locked(exec_ctx, elem, GRPC_ERROR_REF(error));
   } else if (chand->lb_policy != nullptr) {
-    if (GRPC_TRACER_ON(grpc_client_channel_trace)) {
+    if (grpc_client_channel_trace.enabled()) {
       gpr_log(GPR_DEBUG, "chand=%p calld=%p: resolver returned, doing pick",
               chand, calld);
     }
@@ -1256,7 +1255,7 @@
   // right way to deal with it.
   else if (chand->resolver != nullptr) {
     // No LB policy, so try again.
-    if (GRPC_TRACER_ON(grpc_client_channel_trace)) {
+    if (grpc_client_channel_trace.enabled()) {
       gpr_log(GPR_DEBUG,
               "chand=%p calld=%p: resolver returned but no LB policy, "
               "trying again",
@@ -1264,7 +1263,7 @@
     }
     pick_after_resolver_result_start_locked(exec_ctx, elem);
   } else {
-    if (GRPC_TRACER_ON(grpc_client_channel_trace)) {
+    if (grpc_client_channel_trace.enabled()) {
       gpr_log(GPR_DEBUG, "chand=%p calld=%p: resolver disconnected", chand,
               calld);
     }
@@ -1277,7 +1276,7 @@
                                                     grpc_call_element* elem) {
   channel_data* chand = (channel_data*)elem->channel_data;
   call_data* calld = (call_data*)elem->call_data;
-  if (GRPC_TRACER_ON(grpc_client_channel_trace)) {
+  if (grpc_client_channel_trace.enabled()) {
     gpr_log(GPR_DEBUG,
             "chand=%p calld=%p: deferring pick pending resolver result", chand,
             calld);
@@ -1362,7 +1361,7 @@
   GPR_TIMER_BEGIN("cc_start_transport_stream_op_batch", 0);
   // If we've previously been cancelled, immediately fail any new batches.
   if (calld->error != GRPC_ERROR_NONE) {
-    if (GRPC_TRACER_ON(grpc_client_channel_trace)) {
+    if (grpc_client_channel_trace.enabled()) {
       gpr_log(GPR_DEBUG, "chand=%p calld=%p: failing batch with error: %s",
               chand, calld, grpc_error_string(calld->error));
     }
@@ -1378,7 +1377,7 @@
     // error to the caller when the first batch does get passed down.
     GRPC_ERROR_UNREF(calld->error);
     calld->error = GRPC_ERROR_REF(batch->payload->cancel_stream.cancel_error);
-    if (GRPC_TRACER_ON(grpc_client_channel_trace)) {
+    if (grpc_client_channel_trace.enabled()) {
       gpr_log(GPR_DEBUG, "chand=%p calld=%p: recording cancel_error=%s", chand,
               calld, grpc_error_string(calld->error));
     }
@@ -1407,7 +1406,7 @@
   // the channel combiner, which is more efficient (especially for
   // streaming calls).
   if (calld->subchannel_call != nullptr) {
-    if (GRPC_TRACER_ON(grpc_client_channel_trace)) {
+    if (grpc_client_channel_trace.enabled()) {
       gpr_log(GPR_DEBUG,
               "chand=%p calld=%p: sending batch to subchannel_call=%p", chand,
               calld, calld->subchannel_call);
@@ -1421,7 +1420,7 @@
   // For batches containing a send_initial_metadata op, enter the channel
   // combiner to start a pick.
   if (batch->send_initial_metadata) {
-    if (GRPC_TRACER_ON(grpc_client_channel_trace)) {
+    if (grpc_client_channel_trace.enabled()) {
       gpr_log(GPR_DEBUG, "chand=%p calld=%p: entering client_channel combiner",
               chand, calld);
     }
@@ -1432,7 +1431,7 @@
         GRPC_ERROR_NONE);
   } else {
     // For all other batches, release the call combiner.
-    if (GRPC_TRACER_ON(grpc_client_channel_trace)) {
+    if (grpc_client_channel_trace.enabled()) {
       gpr_log(GPR_DEBUG,
               "chand=%p calld=%p: saved batch, yeilding call combiner", chand,
               calld);
diff --git a/src/core/ext/filters/client_channel/client_channel.h b/src/core/ext/filters/client_channel/client_channel.h
index 27862cf..48e4637 100644
--- a/src/core/ext/filters/client_channel/client_channel.h
+++ b/src/core/ext/filters/client_channel/client_channel.h
@@ -23,15 +23,11 @@
 #include "src/core/ext/filters/client_channel/resolver.h"
 #include "src/core/lib/channel/channel_stack.h"
 
-extern grpc_tracer_flag grpc_client_channel_trace;
+extern grpc_core::TraceFlag grpc_client_channel_trace;
 
 // Channel arg key for server URI string.
 #define GRPC_ARG_SERVER_URI "grpc.server_uri"
 
-#ifdef __cplusplus
-extern "C" {
-#endif
-
 /* A client channel is a channel that begins disconnected, and can connect
    to some endpoint on demand. If that endpoint disconnects, it will be
    connected to again later.
@@ -56,8 +52,4 @@
 grpc_subchannel_call* grpc_client_channel_get_subchannel_call(
     grpc_call_element* elem);
 
-#ifdef __cplusplus
-}
-#endif
-
 #endif /* GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_CLIENT_CHANNEL_H */
diff --git a/src/core/ext/filters/client_channel/client_channel_factory.h b/src/core/ext/filters/client_channel/client_channel_factory.h
index db8645c..db82b73 100644
--- a/src/core/ext/filters/client_channel/client_channel_factory.h
+++ b/src/core/ext/filters/client_channel/client_channel_factory.h
@@ -27,10 +27,6 @@
 // Channel arg key for client channel factory.
 #define GRPC_ARG_CLIENT_CHANNEL_FACTORY "grpc.client_channel_factory"
 
-#ifdef __cplusplus
-extern "C" {
-#endif
-
 typedef struct grpc_client_channel_factory grpc_client_channel_factory;
 typedef struct grpc_client_channel_factory_vtable
     grpc_client_channel_factory_vtable;
@@ -78,8 +74,4 @@
 grpc_arg grpc_client_channel_factory_create_channel_arg(
     grpc_client_channel_factory* factory);
 
-#ifdef __cplusplus
-}
-#endif
-
 #endif /* GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_CLIENT_CHANNEL_FACTORY_H */
diff --git a/src/core/ext/filters/client_channel/client_channel_plugin.cc b/src/core/ext/filters/client_channel/client_channel_plugin.cc
index eebef68..7a5bb18 100644
--- a/src/core/ext/filters/client_channel/client_channel_plugin.cc
+++ b/src/core/ext/filters/client_channel/client_channel_plugin.cc
@@ -65,7 +65,7 @@
   return true;
 }
 
-extern "C" void grpc_client_channel_init(void) {
+void grpc_client_channel_init(void) {
   grpc_lb_policy_registry_init();
   grpc_resolver_registry_init();
   grpc_retry_throttle_map_init();
@@ -78,13 +78,9 @@
       GRPC_CLIENT_CHANNEL, GRPC_CHANNEL_INIT_BUILTIN_PRIORITY, append_filter,
       (void*)&grpc_client_channel_filter);
   grpc_http_connect_register_handshaker_factory();
-  grpc_register_tracer(&grpc_client_channel_trace);
-#ifndef NDEBUG
-  grpc_register_tracer(&grpc_trace_resolver_refcount);
-#endif
 }
 
-extern "C" void grpc_client_channel_shutdown(void) {
+void grpc_client_channel_shutdown(void) {
   grpc_subchannel_index_shutdown();
   grpc_channel_init_shutdown();
   grpc_proxy_mapper_registry_shutdown();
diff --git a/src/core/ext/filters/client_channel/connector.h b/src/core/ext/filters/client_channel/connector.h
index 12dc59b..239ed8a 100644
--- a/src/core/ext/filters/client_channel/connector.h
+++ b/src/core/ext/filters/client_channel/connector.h
@@ -23,10 +23,6 @@
 #include "src/core/lib/iomgr/resolve_address.h"
 #include "src/core/lib/transport/transport.h"
 
-#ifdef __cplusplus
-extern "C" {
-#endif
-
 typedef struct grpc_connector grpc_connector;
 typedef struct grpc_connector_vtable grpc_connector_vtable;
 
@@ -74,8 +70,4 @@
 void grpc_connector_shutdown(grpc_exec_ctx* exec_ctx, grpc_connector* connector,
                              grpc_error* why);
 
-#ifdef __cplusplus
-}
-#endif
-
 #endif /* GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_CONNECTOR_H */
diff --git a/src/core/ext/filters/client_channel/http_connect_handshaker.h b/src/core/ext/filters/client_channel/http_connect_handshaker.h
index 05a23cd..928a23d 100644
--- a/src/core/ext/filters/client_channel/http_connect_handshaker.h
+++ b/src/core/ext/filters/client_channel/http_connect_handshaker.h
@@ -28,15 +28,7 @@
 /// seperated by colons.
 #define GRPC_ARG_HTTP_CONNECT_HEADERS "grpc.http_connect_headers"
 
-#ifdef __cplusplus
-extern "C" {
-#endif
-
 /// Registers handshaker factory.
 void grpc_http_connect_register_handshaker_factory();
 
-#ifdef __cplusplus
-}
-#endif
-
 #endif /* GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_HTTP_CONNECT_HANDSHAKER_H */
diff --git a/src/core/ext/filters/client_channel/http_proxy.h b/src/core/ext/filters/client_channel/http_proxy.h
index bdad03d..3469493 100644
--- a/src/core/ext/filters/client_channel/http_proxy.h
+++ b/src/core/ext/filters/client_channel/http_proxy.h
@@ -19,14 +19,6 @@
 #ifndef GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_HTTP_PROXY_H
 #define GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_HTTP_PROXY_H
 
-#ifdef __cplusplus
-extern "C" {
-#endif
-
 void grpc_register_http_proxy_mapper();
 
-#ifdef __cplusplus
-}
-#endif
-
 #endif /* GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_HTTP_PROXY_H */
diff --git a/src/core/ext/filters/client_channel/lb_policy.cc b/src/core/ext/filters/client_channel/lb_policy.cc
index 387c26e..6276c3e 100644
--- a/src/core/ext/filters/client_channel/lb_policy.cc
+++ b/src/core/ext/filters/client_channel/lb_policy.cc
@@ -21,10 +21,8 @@
 
 #define WEAK_REF_BITS 16
 
-#ifndef NDEBUG
-grpc_tracer_flag grpc_trace_lb_policy_refcount =
-    GRPC_TRACER_INITIALIZER(false, "lb_policy_refcount");
-#endif
+grpc_core::DebugOnlyTraceFlag grpc_trace_lb_policy_refcount(
+    false, "lb_policy_refcount");
 
 void grpc_lb_policy_init(grpc_lb_policy* policy,
                          const grpc_lb_policy_vtable* vtable,
@@ -52,7 +50,7 @@
   gpr_atm old_val = barrier ? gpr_atm_full_fetch_add(&c->ref_pair, delta)
                             : gpr_atm_no_barrier_fetch_add(&c->ref_pair, delta);
 #ifndef NDEBUG
-  if (GRPC_TRACER_ON(grpc_trace_lb_policy_refcount)) {
+  if (grpc_trace_lb_policy_refcount.enabled()) {
     gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG,
             "LB_POLICY: %p %12s 0x%" PRIxPTR " -> 0x%" PRIxPTR " [%s]", c,
             purpose, old_val, old_val + delta, reason);
diff --git a/src/core/ext/filters/client_channel/lb_policy.h b/src/core/ext/filters/client_channel/lb_policy.h
index 590094e..72d0279 100644
--- a/src/core/ext/filters/client_channel/lb_policy.h
+++ b/src/core/ext/filters/client_channel/lb_policy.h
@@ -23,19 +23,13 @@
 #include "src/core/lib/iomgr/polling_entity.h"
 #include "src/core/lib/transport/connectivity_state.h"
 
-#ifdef __cplusplus
-extern "C" {
-#endif
-
 /** A load balancing policy: specified by a vtable and a struct (which
     is expected to be extended to contain some parameters) */
 typedef struct grpc_lb_policy grpc_lb_policy;
 typedef struct grpc_lb_policy_vtable grpc_lb_policy_vtable;
 typedef struct grpc_lb_policy_args grpc_lb_policy_args;
 
-#ifndef NDEBUG
-extern grpc_tracer_flag grpc_trace_lb_policy_refcount;
-#endif
+extern grpc_core::DebugOnlyTraceFlag grpc_trace_lb_policy_refcount;
 
 struct grpc_lb_policy {
   const grpc_lb_policy_vtable* vtable;
@@ -208,8 +202,4 @@
                                   grpc_lb_policy* policy,
                                   const grpc_lb_policy_args* lb_policy_args);
 
-#ifdef __cplusplus
-}
-#endif
-
 #endif /* GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_LB_POLICY_H */
diff --git a/src/core/ext/filters/client_channel/lb_policy/grpclb/client_load_reporting_filter.h b/src/core/ext/filters/client_channel/lb_policy/grpclb/client_load_reporting_filter.h
index abf613a..04de7a0 100644
--- a/src/core/ext/filters/client_channel/lb_policy/grpclb/client_load_reporting_filter.h
+++ b/src/core/ext/filters/client_channel/lb_policy/grpclb/client_load_reporting_filter.h
@@ -21,15 +21,7 @@
 
 #include "src/core/lib/channel/channel_stack.h"
 
-#ifdef __cplusplus
-extern "C" {
-#endif
-
 extern const grpc_channel_filter grpc_client_load_reporting_filter;
 
-#ifdef __cplusplus
-}
-#endif
-
 #endif /* GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_LB_POLICY_GRPCLB_CLIENT_LOAD_REPORTING_FILTER_H \
         */
diff --git a/src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb.cc b/src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb.cc
index ad9a2bb..2f8e0c9 100644
--- a/src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb.cc
+++ b/src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb.cc
@@ -126,7 +126,7 @@
 #define GRPC_GRPCLB_RECONNECT_JITTER 0.2
 #define GRPC_GRPCLB_DEFAULT_FALLBACK_TIMEOUT_MS 10000
 
-grpc_tracer_flag grpc_lb_glb_trace = GRPC_TRACER_INITIALIZER(false, "glb");
+grpc_core::TraceFlag grpc_lb_glb_trace(false, "glb");
 
 /* add lb_token of selected subchannel (address) to the call's initial
  * metadata */
@@ -217,7 +217,7 @@
     } else {
       grpc_grpclb_client_stats_unref(wc_arg->client_stats);
     }
-    if (GRPC_TRACER_ON(grpc_lb_glb_trace)) {
+    if (grpc_lb_glb_trace.enabled()) {
       gpr_log(GPR_INFO, "[grpclb %p] Unreffing RR %p", wc_arg->glb_policy,
               wc_arg->rr_policy);
     }
@@ -623,7 +623,7 @@
       GPR_ASSERT(rr_state_error == GRPC_ERROR_NONE);
   }
 
-  if (GRPC_TRACER_ON(grpc_lb_glb_trace)) {
+  if (grpc_lb_glb_trace.enabled()) {
     gpr_log(
         GPR_INFO,
         "[grpclb %p] Setting grpclb's state to %s from new RR policy %p state.",
@@ -654,7 +654,7 @@
     }
     if (server->drop) {
       // Not using the RR policy, so unref it.
-      if (GRPC_TRACER_ON(grpc_lb_glb_trace)) {
+      if (grpc_lb_glb_trace.enabled()) {
         gpr_log(GPR_INFO, "[grpclb %p] Unreffing RR %p for drop", glb_policy,
                 wc_arg->rr_policy);
       }
@@ -684,7 +684,7 @@
       (void**)&wc_arg->lb_token, &wc_arg->wrapper_closure);
   if (pick_done) {
     /* synchronous grpc_lb_policy_pick call. Unref the RR policy. */
-    if (GRPC_TRACER_ON(grpc_lb_glb_trace)) {
+    if (grpc_lb_glb_trace.enabled()) {
       gpr_log(GPR_INFO, "[grpclb %p] Unreffing RR %p", glb_policy,
               wc_arg->rr_policy);
     }
@@ -806,7 +806,7 @@
     pp->wrapped_on_complete_arg.rr_policy = glb_policy->rr_policy;
     pp->wrapped_on_complete_arg.client_stats =
         grpc_grpclb_client_stats_ref(glb_policy->client_stats);
-    if (GRPC_TRACER_ON(grpc_lb_glb_trace)) {
+    if (grpc_lb_glb_trace.enabled()) {
       gpr_log(GPR_INFO,
               "[grpclb %p] Pending pick about to (async) PICK from RR %p",
               glb_policy, glb_policy->rr_policy);
@@ -821,7 +821,7 @@
     glb_policy->pending_pings = pping->next;
     GRPC_LB_POLICY_REF(glb_policy->rr_policy, "rr_handover_pending_ping");
     pping->wrapped_notify_arg.rr_policy = glb_policy->rr_policy;
-    if (GRPC_TRACER_ON(grpc_lb_glb_trace)) {
+    if (grpc_lb_glb_trace.enabled()) {
       gpr_log(GPR_INFO, "[grpclb %p] Pending ping about to PING from RR %p",
               glb_policy, glb_policy->rr_policy);
     }
@@ -837,14 +837,14 @@
   grpc_lb_policy_args* args = lb_policy_args_create(exec_ctx, glb_policy);
   GPR_ASSERT(args != nullptr);
   if (glb_policy->rr_policy != nullptr) {
-    if (GRPC_TRACER_ON(grpc_lb_glb_trace)) {
+    if (grpc_lb_glb_trace.enabled()) {
       gpr_log(GPR_DEBUG, "[grpclb %p] Updating RR policy %p", glb_policy,
               glb_policy->rr_policy);
     }
     grpc_lb_policy_update_locked(exec_ctx, glb_policy->rr_policy, args);
   } else {
     create_rr_locked(exec_ctx, glb_policy, args);
-    if (GRPC_TRACER_ON(grpc_lb_glb_trace)) {
+    if (grpc_lb_glb_trace.enabled()) {
       gpr_log(GPR_DEBUG, "[grpclb %p] Created new RR policy %p", glb_policy,
               glb_policy->rr_policy);
     }
@@ -1186,7 +1186,7 @@
     // need to make sure we aren't trying to pick from a RR policy instance
     // that's in shutdown.
     if (rr_connectivity_state == GRPC_CHANNEL_SHUTDOWN) {
-      if (GRPC_TRACER_ON(grpc_lb_glb_trace)) {
+      if (grpc_lb_glb_trace.enabled()) {
         gpr_log(GPR_INFO,
                 "[grpclb %p] NOT picking from from RR %p: RR conn state=%s",
                 glb_policy, glb_policy->rr_policy,
@@ -1196,7 +1196,7 @@
                        on_complete);
       pick_done = false;
     } else {  // RR not in shutdown
-      if (GRPC_TRACER_ON(grpc_lb_glb_trace)) {
+      if (grpc_lb_glb_trace.enabled()) {
         gpr_log(GPR_INFO, "[grpclb %p] about to PICK from RR %p", glb_policy,
                 glb_policy->rr_policy);
       }
@@ -1221,7 +1221,7 @@
                                        false /* force_async */, target, wc_arg);
     }
   } else {  // glb_policy->rr_policy == NULL
-    if (GRPC_TRACER_ON(grpc_lb_glb_trace)) {
+    if (grpc_lb_glb_trace.enabled()) {
       gpr_log(GPR_DEBUG,
               "[grpclb %p] No RR policy. Adding to grpclb's pending picks",
               glb_policy);
@@ -1272,7 +1272,7 @@
   glb_policy->retry_timer_active = false;
   if (!glb_policy->shutting_down && glb_policy->lb_call == nullptr &&
       error == GRPC_ERROR_NONE) {
-    if (GRPC_TRACER_ON(grpc_lb_glb_trace)) {
+    if (grpc_lb_glb_trace.enabled()) {
       gpr_log(GPR_INFO, "[grpclb %p] Restarting call to LB server", glb_policy);
     }
     query_for_backends_locked(exec_ctx, glb_policy);
@@ -1293,7 +1293,7 @@
     grpc_millis next_try =
         grpc_backoff_step(exec_ctx, &glb_policy->lb_call_backoff_state)
             .next_attempt_start_time;
-    if (GRPC_TRACER_ON(grpc_lb_glb_trace)) {
+    if (grpc_lb_glb_trace.enabled()) {
       gpr_log(GPR_DEBUG, "[grpclb %p] Connection to LB server lost...",
               glb_policy);
       grpc_millis timeout = next_try - grpc_exec_ctx_now(exec_ctx);
@@ -1499,7 +1499,7 @@
 
   lb_call_init_locked(exec_ctx, glb_policy);
 
-  if (GRPC_TRACER_ON(grpc_lb_glb_trace)) {
+  if (grpc_lb_glb_trace.enabled()) {
     gpr_log(GPR_INFO,
             "[grpclb %p] Query for backends (lb_channel: %p, lb_call: %p)",
             glb_policy, glb_policy->lb_channel, glb_policy->lb_call);
@@ -1590,7 +1590,7 @@
         glb_policy->client_stats_report_interval = GPR_MAX(
             GPR_MS_PER_SEC, grpc_grpclb_duration_to_millis(
                                 &response->client_stats_report_interval));
-        if (GRPC_TRACER_ON(grpc_lb_glb_trace)) {
+        if (grpc_lb_glb_trace.enabled()) {
           gpr_log(GPR_INFO,
                   "[grpclb %p] Received initial LB response message; "
                   "client load reporting interval = %" PRIdPTR " milliseconds",
@@ -1602,7 +1602,7 @@
         glb_policy->client_load_report_timer_pending = true;
         GRPC_LB_POLICY_WEAK_REF(&glb_policy->base, "client_load_report");
         schedule_next_client_load_report(exec_ctx, glb_policy);
-      } else if (GRPC_TRACER_ON(grpc_lb_glb_trace)) {
+      } else if (grpc_lb_glb_trace.enabled()) {
         gpr_log(GPR_INFO,
                 "[grpclb %p] Received initial LB response message; client load "
                 "reporting NOT enabled",
@@ -1615,7 +1615,7 @@
           grpc_grpclb_response_parse_serverlist(response_slice);
       if (serverlist != nullptr) {
         GPR_ASSERT(glb_policy->lb_call != nullptr);
-        if (GRPC_TRACER_ON(grpc_lb_glb_trace)) {
+        if (grpc_lb_glb_trace.enabled()) {
           gpr_log(GPR_INFO,
                   "[grpclb %p] Serverlist with %" PRIuPTR " servers received",
                   glb_policy, serverlist->num_servers);
@@ -1633,7 +1633,7 @@
         if (serverlist->num_servers > 0) {
           if (grpc_grpclb_serverlist_equals(glb_policy->serverlist,
                                             serverlist)) {
-            if (GRPC_TRACER_ON(grpc_lb_glb_trace)) {
+            if (grpc_lb_glb_trace.enabled()) {
               gpr_log(GPR_INFO,
                       "[grpclb %p] Incoming server list identical to current, "
                       "ignoring.",
@@ -1662,7 +1662,7 @@
             rr_handover_locked(exec_ctx, glb_policy);
           }
         } else {
-          if (GRPC_TRACER_ON(grpc_lb_glb_trace)) {
+          if (grpc_lb_glb_trace.enabled()) {
             gpr_log(GPR_INFO,
                     "[grpclb %p] Received empty server list, ignoring.",
                     glb_policy);
@@ -1710,7 +1710,7 @@
    * actually runs, don't fall back. */
   if (glb_policy->serverlist == nullptr) {
     if (!glb_policy->shutting_down && error == GRPC_ERROR_NONE) {
-      if (GRPC_TRACER_ON(grpc_lb_glb_trace)) {
+      if (grpc_lb_glb_trace.enabled()) {
         gpr_log(GPR_INFO,
                 "[grpclb %p] Falling back to use backends from resolver",
                 glb_policy);
@@ -1727,7 +1727,7 @@
                                                 void* arg, grpc_error* error) {
   glb_lb_policy* glb_policy = (glb_lb_policy*)arg;
   GPR_ASSERT(glb_policy->lb_call != nullptr);
-  if (GRPC_TRACER_ON(grpc_lb_glb_trace)) {
+  if (grpc_lb_glb_trace.enabled()) {
     char* status_details =
         grpc_slice_to_c_string(glb_policy->lb_call_status_details);
     gpr_log(GPR_INFO,
@@ -1909,7 +1909,7 @@
   GPR_ASSERT(uri->path[0] != '\0');
   glb_policy->server_name =
       gpr_strdup(uri->path[0] == '/' ? uri->path + 1 : uri->path);
-  if (GRPC_TRACER_ON(grpc_lb_glb_trace)) {
+  if (grpc_lb_glb_trace.enabled()) {
     gpr_log(GPR_INFO,
             "[grpclb %p] Will use '%s' as the server name for LB request.",
             glb_policy, glb_policy->server_name);
@@ -2001,16 +2001,12 @@
   return true;
 }
 
-extern "C" void grpc_lb_policy_grpclb_init() {
+void grpc_lb_policy_grpclb_init() {
   grpc_register_lb_policy(grpc_glb_lb_factory_create());
-  grpc_register_tracer(&grpc_lb_glb_trace);
-#ifndef NDEBUG
-  grpc_register_tracer(&grpc_trace_lb_policy_refcount);
-#endif
   grpc_channel_init_register_stage(GRPC_CLIENT_SUBCHANNEL,
                                    GRPC_CHANNEL_INIT_BUILTIN_PRIORITY,
                                    maybe_add_client_load_reporting_filter,
                                    (void*)&grpc_client_load_reporting_filter);
 }
 
-extern "C" void grpc_lb_policy_grpclb_shutdown() {}
+void grpc_lb_policy_grpclb_shutdown() {}
diff --git a/src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb.h b/src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb.h
index b6135a4..0a2edb0 100644
--- a/src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb.h
+++ b/src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb.h
@@ -21,17 +21,9 @@
 
 #include "src/core/ext/filters/client_channel/lb_policy_factory.h"
 
-#ifdef __cplusplus
-extern "C" {
-#endif
-
 /** Returns a load balancing factory for the glb policy, which tries to connect
  * to a load balancing server to decide the next successfully connected
  * subchannel to pick. */
 grpc_lb_policy_factory* grpc_glb_lb_factory_create();
 
-#ifdef __cplusplus
-}
-#endif
-
 #endif /* GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_LB_POLICY_GRPCLB_GRPCLB_H */
diff --git a/src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_channel.h b/src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_channel.h
index 39cbf53..70b1c28 100644
--- a/src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_channel.h
+++ b/src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_channel.h
@@ -23,10 +23,6 @@
 #include "src/core/ext/filters/client_channel/resolver/fake/fake_resolver.h"
 #include "src/core/lib/slice/slice_hash_table.h"
 
-#ifdef __cplusplus
-extern "C" {
-#endif
-
 /** Create the channel used for communicating with an LB service.
  * Note that an LB *service* may be comprised of several LB *servers*.
  *
@@ -44,9 +40,5 @@
     grpc_fake_resolver_response_generator* response_generator,
     const grpc_channel_args* args);
 
-#ifdef __cplusplus
-}
-#endif
-
 #endif /* GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_LB_POLICY_GRPCLB_GRPCLB_CHANNEL_H \
         */
diff --git a/src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_client_stats.h b/src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_client_stats.h
index ce88cf9..d4b9d06 100644
--- a/src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_client_stats.h
+++ b/src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_client_stats.h
@@ -23,10 +23,6 @@
 
 #include <grpc/impl/codegen/grpc_types.h>
 
-#ifdef __cplusplus
-extern "C" {
-#endif
-
 typedef struct grpc_grpclb_client_stats grpc_grpclb_client_stats;
 
 typedef struct {
@@ -65,9 +61,5 @@
 void grpc_grpclb_dropped_call_counts_destroy(
     grpc_grpclb_dropped_call_counts* drop_entries);
 
-#ifdef __cplusplus
-}
-#endif
-
 #endif /* GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_LB_POLICY_GRPCLB_GRPCLB_CLIENT_STATS_H \
         */
diff --git a/src/core/ext/filters/client_channel/lb_policy/grpclb/load_balancer_api.h b/src/core/ext/filters/client_channel/lb_policy/grpclb/load_balancer_api.h
index 138012c..017c40e 100644
--- a/src/core/ext/filters/client_channel/lb_policy/grpclb/load_balancer_api.h
+++ b/src/core/ext/filters/client_channel/lb_policy/grpclb/load_balancer_api.h
@@ -25,10 +25,6 @@
 #include "src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.h"
 #include "src/core/ext/filters/client_channel/lb_policy_factory.h"
 
-#ifdef __cplusplus
-extern "C" {
-#endif
-
 #define GRPC_GRPCLB_SERVICE_NAME_MAX_LENGTH 128
 
 typedef grpc_lb_v1_Server_ip_address_t grpc_grpclb_ip_address;
@@ -87,9 +83,5 @@
 void grpc_grpclb_initial_response_destroy(
     grpc_grpclb_initial_response* response);
 
-#ifdef __cplusplus
-}
-#endif
-
 #endif /* GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_LB_POLICY_GRPCLB_LOAD_BALANCER_API_H \
         */
diff --git a/src/core/ext/filters/client_channel/lb_policy/pick_first/pick_first.cc b/src/core/ext/filters/client_channel/lb_policy/pick_first/pick_first.cc
index dbd4754..6cfc37e 100644
--- a/src/core/ext/filters/client_channel/lb_policy/pick_first/pick_first.cc
+++ b/src/core/ext/filters/client_channel/lb_policy/pick_first/pick_first.cc
@@ -29,8 +29,7 @@
 #include "src/core/lib/iomgr/sockaddr_utils.h"
 #include "src/core/lib/transport/connectivity_state.h"
 
-grpc_tracer_flag grpc_lb_pick_first_trace =
-    GRPC_TRACER_INITIALIZER(false, "pick_first");
+grpc_core::TraceFlag grpc_lb_pick_first_trace(false, "pick_first");
 
 typedef struct pending_pick {
   struct pending_pick* next;
@@ -66,14 +65,14 @@
   grpc_connectivity_state_destroy(exec_ctx, &p->state_tracker);
   gpr_free(p);
   grpc_subchannel_index_unref();
-  if (GRPC_TRACER_ON(grpc_lb_pick_first_trace)) {
+  if (grpc_lb_pick_first_trace.enabled()) {
     gpr_log(GPR_DEBUG, "Pick First %p destroyed.", (void*)p);
   }
 }
 
 static void shutdown_locked(grpc_exec_ctx* exec_ctx, pick_first_lb_policy* p,
                             grpc_error* error) {
-  if (GRPC_TRACER_ON(grpc_lb_pick_first_trace)) {
+  if (grpc_lb_pick_first_trace.enabled()) {
     gpr_log(GPR_DEBUG, "Pick First %p Shutting down", p);
   }
   p->shutdown = true;
@@ -261,7 +260,7 @@
   }
   const grpc_lb_addresses* addresses =
       (const grpc_lb_addresses*)arg->value.pointer.p;
-  if (GRPC_TRACER_ON(grpc_lb_pick_first_trace)) {
+  if (grpc_lb_pick_first_trace.enabled()) {
     gpr_log(GPR_INFO, "Pick First %p received update with %lu addresses",
             (void*)p, (unsigned long)addresses->num_addresses);
   }
@@ -298,7 +297,7 @@
       grpc_lb_subchannel_data* sd = &subchannel_list->subchannels[i];
       if (sd->subchannel == p->selected->subchannel) {
         // The currently selected subchannel is in the update: we are done.
-        if (GRPC_TRACER_ON(grpc_lb_pick_first_trace)) {
+        if (grpc_lb_pick_first_trace.enabled()) {
           gpr_log(GPR_INFO,
                   "Pick First %p found already selected subchannel %p "
                   "at update index %" PRIuPTR " of %" PRIuPTR "; update done",
@@ -336,7 +335,7 @@
     // for it to report READY before swapping it into the current
     // subchannel list.
     if (p->latest_pending_subchannel_list != nullptr) {
-      if (GRPC_TRACER_ON(grpc_lb_pick_first_trace)) {
+      if (grpc_lb_pick_first_trace.enabled()) {
         gpr_log(GPR_DEBUG,
                 "Pick First %p Shutting down latest pending subchannel list "
                 "%p, about to be replaced by newer latest %p",
@@ -363,7 +362,7 @@
                                            grpc_error* error) {
   grpc_lb_subchannel_data* sd = (grpc_lb_subchannel_data*)arg;
   pick_first_lb_policy* p = (pick_first_lb_policy*)sd->subchannel_list->policy;
-  if (GRPC_TRACER_ON(grpc_lb_pick_first_trace)) {
+  if (grpc_lb_pick_first_trace.enabled()) {
     gpr_log(GPR_DEBUG,
             "Pick First %p connectivity changed for subchannel %p (%" PRIuPTR
             " of %" PRIuPTR
@@ -460,7 +459,7 @@
           grpc_subchannel_get_connected_subchannel(sd->subchannel),
           "connected");
       p->selected = sd;
-      if (GRPC_TRACER_ON(grpc_lb_pick_first_trace)) {
+      if (grpc_lb_pick_first_trace.enabled()) {
         gpr_log(GPR_INFO, "Pick First %p selected subchannel %p", (void*)p,
                 (void*)sd->subchannel);
       }
@@ -472,7 +471,7 @@
         p->pending_picks = pp->next;
         *pp->target = GRPC_CONNECTED_SUBCHANNEL_REF(
             p->selected->connected_subchannel, "picked");
-        if (GRPC_TRACER_ON(grpc_lb_pick_first_trace)) {
+        if (grpc_lb_pick_first_trace.enabled()) {
           gpr_log(GPR_INFO,
                   "Servicing pending pick with selected subchannel %p",
                   (void*)p->selected);
@@ -571,7 +570,7 @@
                                          grpc_lb_policy_args* args) {
   GPR_ASSERT(args->client_channel_factory != nullptr);
   pick_first_lb_policy* p = (pick_first_lb_policy*)gpr_zalloc(sizeof(*p));
-  if (GRPC_TRACER_ON(grpc_lb_pick_first_trace)) {
+  if (grpc_lb_pick_first_trace.enabled()) {
     gpr_log(GPR_DEBUG, "Pick First %p created.", (void*)p);
   }
   pf_update_locked(exec_ctx, &p->base, args);
@@ -593,9 +592,8 @@
 
 /* Plugin registration */
 
-extern "C" void grpc_lb_policy_pick_first_init() {
+void grpc_lb_policy_pick_first_init() {
   grpc_register_lb_policy(pick_first_lb_factory_create());
-  grpc_register_tracer(&grpc_lb_pick_first_trace);
 }
 
-extern "C" void grpc_lb_policy_pick_first_shutdown() {}
+void grpc_lb_policy_pick_first_shutdown() {}
diff --git a/src/core/ext/filters/client_channel/lb_policy/round_robin/round_robin.cc b/src/core/ext/filters/client_channel/lb_policy/round_robin/round_robin.cc
index 6ea1f02..23a4cc4 100644
--- a/src/core/ext/filters/client_channel/lb_policy/round_robin/round_robin.cc
+++ b/src/core/ext/filters/client_channel/lb_policy/round_robin/round_robin.cc
@@ -39,8 +39,7 @@
 #include "src/core/lib/transport/connectivity_state.h"
 #include "src/core/lib/transport/static_metadata.h"
 
-grpc_tracer_flag grpc_lb_round_robin_trace =
-    GRPC_TRACER_INITIALIZER(false, "round_robin");
+grpc_core::TraceFlag grpc_lb_round_robin_trace(false, "round_robin");
 
 /** List of entities waiting for a pick.
  *
@@ -101,7 +100,7 @@
 static size_t get_next_ready_subchannel_index_locked(
     const round_robin_lb_policy* p) {
   GPR_ASSERT(p->subchannel_list != nullptr);
-  if (GRPC_TRACER_ON(grpc_lb_round_robin_trace)) {
+  if (grpc_lb_round_robin_trace.enabled()) {
     gpr_log(GPR_INFO,
             "[RR %p] getting next ready subchannel (out of %lu), "
             "last_ready_subchannel_index=%lu",
@@ -111,7 +110,7 @@
   for (size_t i = 0; i < p->subchannel_list->num_subchannels; ++i) {
     const size_t index = (i + p->last_ready_subchannel_index + 1) %
                          p->subchannel_list->num_subchannels;
-    if (GRPC_TRACER_ON(grpc_lb_round_robin_trace)) {
+    if (grpc_lb_round_robin_trace.enabled()) {
       gpr_log(
           GPR_DEBUG,
           "[RR %p] checking subchannel %p, subchannel_list %p, index %lu: "
@@ -123,7 +122,7 @@
     }
     if (p->subchannel_list->subchannels[index].curr_connectivity_state ==
         GRPC_CHANNEL_READY) {
-      if (GRPC_TRACER_ON(grpc_lb_round_robin_trace)) {
+      if (grpc_lb_round_robin_trace.enabled()) {
         gpr_log(GPR_DEBUG,
                 "[RR %p] found next ready subchannel (%p) at index %lu of "
                 "subchannel_list %p",
@@ -134,7 +133,7 @@
       return index;
     }
   }
-  if (GRPC_TRACER_ON(grpc_lb_round_robin_trace)) {
+  if (grpc_lb_round_robin_trace.enabled()) {
     gpr_log(GPR_DEBUG, "[RR %p] no subchannels in ready state", (void*)p);
   }
   return p->subchannel_list->num_subchannels;
@@ -145,7 +144,7 @@
                                                       size_t last_ready_index) {
   GPR_ASSERT(last_ready_index < p->subchannel_list->num_subchannels);
   p->last_ready_subchannel_index = last_ready_index;
-  if (GRPC_TRACER_ON(grpc_lb_round_robin_trace)) {
+  if (grpc_lb_round_robin_trace.enabled()) {
     gpr_log(GPR_DEBUG,
             "[RR %p] setting last_ready_subchannel_index=%lu (SC %p, CSC %p)",
             (void*)p, (unsigned long)last_ready_index,
@@ -157,7 +156,7 @@
 
 static void rr_destroy(grpc_exec_ctx* exec_ctx, grpc_lb_policy* pol) {
   round_robin_lb_policy* p = (round_robin_lb_policy*)pol;
-  if (GRPC_TRACER_ON(grpc_lb_round_robin_trace)) {
+  if (grpc_lb_round_robin_trace.enabled()) {
     gpr_log(GPR_DEBUG, "[RR %p] Destroying Round Robin policy at %p",
             (void*)pol, (void*)pol);
   }
@@ -170,7 +169,7 @@
 
 static void shutdown_locked(grpc_exec_ctx* exec_ctx, round_robin_lb_policy* p,
                             grpc_error* error) {
-  if (GRPC_TRACER_ON(grpc_lb_round_robin_trace)) {
+  if (grpc_lb_round_robin_trace.enabled()) {
     gpr_log(GPR_DEBUG, "[RR %p] Shutting down", p);
   }
   p->shutdown = true;
@@ -276,7 +275,7 @@
                           grpc_call_context_element* context, void** user_data,
                           grpc_closure* on_complete) {
   round_robin_lb_policy* p = (round_robin_lb_policy*)pol;
-  if (GRPC_TRACER_ON(grpc_lb_round_robin_trace)) {
+  if (grpc_lb_round_robin_trace.enabled()) {
     gpr_log(GPR_INFO, "[RR %p] Trying to pick (shutdown: %d)", (void*)pol,
             p->shutdown);
   }
@@ -292,7 +291,7 @@
       if (user_data != nullptr) {
         *user_data = sd->user_data;
       }
-      if (GRPC_TRACER_ON(grpc_lb_round_robin_trace)) {
+      if (grpc_lb_round_robin_trace.enabled()) {
         gpr_log(
             GPR_DEBUG,
             "[RR %p] Picked target <-- Subchannel %p (connected %p) (sl %p, "
@@ -393,7 +392,7 @@
                                 "rr_shutdown");
     p->shutdown = true;
     new_state = GRPC_CHANNEL_SHUTDOWN;
-    if (GRPC_TRACER_ON(grpc_lb_round_robin_trace)) {
+    if (grpc_lb_round_robin_trace.enabled()) {
       gpr_log(GPR_INFO,
               "[RR %p] Shutting down: all subchannels have gone into shutdown",
               (void*)p);
@@ -419,7 +418,7 @@
   grpc_lb_subchannel_data* sd = (grpc_lb_subchannel_data*)arg;
   round_robin_lb_policy* p =
       (round_robin_lb_policy*)sd->subchannel_list->policy;
-  if (GRPC_TRACER_ON(grpc_lb_round_robin_trace)) {
+  if (grpc_lb_round_robin_trace.enabled()) {
     gpr_log(
         GPR_DEBUG,
         "[RR %p] connectivity changed for subchannel %p, subchannel_list %p: "
@@ -484,7 +483,7 @@
         // for sds belonging to outdated subchannel lists.
         GPR_ASSERT(sd->subchannel_list == p->latest_pending_subchannel_list);
         GPR_ASSERT(!sd->subchannel_list->shutting_down);
-        if (GRPC_TRACER_ON(grpc_lb_round_robin_trace)) {
+        if (grpc_lb_round_robin_trace.enabled()) {
           const unsigned long num_subchannels =
               p->subchannel_list != nullptr
                   ? (unsigned long)p->subchannel_list->num_subchannels
@@ -523,7 +522,7 @@
         if (pp->user_data != nullptr) {
           *pp->user_data = selected->user_data;
         }
-        if (GRPC_TRACER_ON(grpc_lb_round_robin_trace)) {
+        if (grpc_lb_round_robin_trace.enabled()) {
           gpr_log(GPR_DEBUG,
                   "[RR %p] Fulfilling pending pick. Target <-- subchannel %p "
                   "(subchannel_list %p, index %lu)",
@@ -590,7 +589,7 @@
     return;
   }
   grpc_lb_addresses* addresses = (grpc_lb_addresses*)arg->value.pointer.p;
-  if (GRPC_TRACER_ON(grpc_lb_round_robin_trace)) {
+  if (grpc_lb_round_robin_trace.enabled()) {
     gpr_log(GPR_DEBUG, "[RR %p] received update with %" PRIuPTR " addresses", p,
             addresses->num_addresses);
   }
@@ -611,7 +610,7 @@
   }
   if (p->started_picking) {
     if (p->latest_pending_subchannel_list != nullptr) {
-      if (GRPC_TRACER_ON(grpc_lb_round_robin_trace)) {
+      if (grpc_lb_round_robin_trace.enabled()) {
         gpr_log(GPR_DEBUG,
                 "[RR %p] Shutting down latest pending subchannel list %p, "
                 "about to be replaced by newer latest %p",
@@ -669,7 +668,7 @@
   grpc_connectivity_state_init(&p->state_tracker, GRPC_CHANNEL_IDLE,
                                "round_robin");
   rr_update_locked(exec_ctx, &p->base, args);
-  if (GRPC_TRACER_ON(grpc_lb_round_robin_trace)) {
+  if (grpc_lb_round_robin_trace.enabled()) {
     gpr_log(GPR_DEBUG, "[RR %p] Created with %lu subchannels", (void*)p,
             (unsigned long)p->subchannel_list->num_subchannels);
   }
@@ -689,9 +688,8 @@
 
 /* Plugin registration */
 
-extern "C" void grpc_lb_policy_round_robin_init() {
+void grpc_lb_policy_round_robin_init() {
   grpc_register_lb_policy(round_robin_lb_factory_create());
-  grpc_register_tracer(&grpc_lb_round_robin_trace);
 }
 
-extern "C" void grpc_lb_policy_round_robin_shutdown() {}
+void grpc_lb_policy_round_robin_shutdown() {}
diff --git a/src/core/ext/filters/client_channel/lb_policy/subchannel_list.cc b/src/core/ext/filters/client_channel/lb_policy/subchannel_list.cc
index 27d9598..b6fce4d 100644
--- a/src/core/ext/filters/client_channel/lb_policy/subchannel_list.cc
+++ b/src/core/ext/filters/client_channel/lb_policy/subchannel_list.cc
@@ -32,11 +32,11 @@
                                               grpc_lb_subchannel_data* sd,
                                               const char* reason) {
   if (sd->subchannel != nullptr) {
-    if (GRPC_TRACER_ON(*sd->subchannel_list->tracer)) {
+    if (sd->subchannel_list->tracer->enabled()) {
       gpr_log(GPR_DEBUG,
               "[%s %p] subchannel list %p index %" PRIuPTR " of %" PRIuPTR
               " (subchannel %p): unreffing subchannel",
-              sd->subchannel_list->tracer->name, sd->subchannel_list->policy,
+              sd->subchannel_list->tracer->name(), sd->subchannel_list->policy,
               sd->subchannel_list,
               (size_t)(sd - sd->subchannel_list->subchannels),
               sd->subchannel_list->num_subchannels, sd->subchannel);
@@ -58,11 +58,11 @@
 
 void grpc_lb_subchannel_data_start_connectivity_watch(
     grpc_exec_ctx* exec_ctx, grpc_lb_subchannel_data* sd) {
-  if (GRPC_TRACER_ON(*sd->subchannel_list->tracer)) {
+  if (sd->subchannel_list->tracer->enabled()) {
     gpr_log(GPR_DEBUG,
             "[%s %p] subchannel list %p index %" PRIuPTR " of %" PRIuPTR
             " (subchannel %p): requesting connectivity change notification",
-            sd->subchannel_list->tracer->name, sd->subchannel_list->policy,
+            sd->subchannel_list->tracer->name(), sd->subchannel_list->policy,
             sd->subchannel_list,
             (size_t)(sd - sd->subchannel_list->subchannels),
             sd->subchannel_list->num_subchannels, sd->subchannel);
@@ -76,11 +76,11 @@
 
 void grpc_lb_subchannel_data_stop_connectivity_watch(
     grpc_exec_ctx* exec_ctx, grpc_lb_subchannel_data* sd) {
-  if (GRPC_TRACER_ON(*sd->subchannel_list->tracer)) {
+  if (sd->subchannel_list->tracer->enabled()) {
     gpr_log(GPR_DEBUG,
             "[%s %p] subchannel list %p index %" PRIuPTR " of %" PRIuPTR
             " (subchannel %p): stopping connectivity watch",
-            sd->subchannel_list->tracer->name, sd->subchannel_list->policy,
+            sd->subchannel_list->tracer->name(), sd->subchannel_list->policy,
             sd->subchannel_list,
             (size_t)(sd - sd->subchannel_list->subchannels),
             sd->subchannel_list->num_subchannels, sd->subchannel);
@@ -90,15 +90,15 @@
 }
 
 grpc_lb_subchannel_list* grpc_lb_subchannel_list_create(
-    grpc_exec_ctx* exec_ctx, grpc_lb_policy* p, grpc_tracer_flag* tracer,
+    grpc_exec_ctx* exec_ctx, grpc_lb_policy* p, grpc_core::TraceFlag* tracer,
     const grpc_lb_addresses* addresses, const grpc_lb_policy_args* args,
     grpc_iomgr_cb_func connectivity_changed_cb) {
   grpc_lb_subchannel_list* subchannel_list =
       (grpc_lb_subchannel_list*)gpr_zalloc(sizeof(*subchannel_list));
-  if (GRPC_TRACER_ON(*tracer)) {
+  if (tracer->enabled()) {
     gpr_log(GPR_DEBUG,
             "[%s %p] Creating subchannel list %p for %" PRIuPTR " subchannels",
-            tracer->name, p, subchannel_list, addresses->num_addresses);
+            tracer->name(), p, subchannel_list, addresses->num_addresses);
   }
   subchannel_list->policy = p;
   subchannel_list->tracer = tracer;
@@ -128,24 +128,24 @@
     grpc_channel_args_destroy(exec_ctx, new_args);
     if (subchannel == nullptr) {
       // Subchannel could not be created.
-      if (GRPC_TRACER_ON(*tracer)) {
+      if (tracer->enabled()) {
         char* address_uri =
             grpc_sockaddr_to_uri(&addresses->addresses[i].address);
         gpr_log(GPR_DEBUG,
                 "[%s %p] could not create subchannel for address uri %s, "
                 "ignoring",
-                tracer->name, subchannel_list->policy, address_uri);
+                tracer->name(), subchannel_list->policy, address_uri);
         gpr_free(address_uri);
       }
       continue;
     }
-    if (GRPC_TRACER_ON(*tracer)) {
+    if (tracer->enabled()) {
       char* address_uri =
           grpc_sockaddr_to_uri(&addresses->addresses[i].address);
       gpr_log(GPR_DEBUG,
               "[%s %p] subchannel list %p index %" PRIuPTR
               ": Created subchannel %p for address uri %s",
-              tracer->name, p, subchannel_list, subchannel_index, subchannel,
+              tracer->name(), p, subchannel_list, subchannel_index, subchannel,
               address_uri);
       gpr_free(address_uri);
     }
@@ -174,9 +174,9 @@
 
 static void subchannel_list_destroy(grpc_exec_ctx* exec_ctx,
                                     grpc_lb_subchannel_list* subchannel_list) {
-  if (GRPC_TRACER_ON(*subchannel_list->tracer)) {
+  if (subchannel_list->tracer->enabled()) {
     gpr_log(GPR_DEBUG, "[%s %p] Destroying subchannel_list %p",
-            subchannel_list->tracer->name, subchannel_list->policy,
+            subchannel_list->tracer->name(), subchannel_list->policy,
             subchannel_list);
   }
   for (size_t i = 0; i < subchannel_list->num_subchannels; i++) {
@@ -191,10 +191,10 @@
 void grpc_lb_subchannel_list_ref(grpc_lb_subchannel_list* subchannel_list,
                                  const char* reason) {
   gpr_ref_non_zero(&subchannel_list->refcount);
-  if (GRPC_TRACER_ON(*subchannel_list->tracer)) {
+  if (subchannel_list->tracer->enabled()) {
     const gpr_atm count = gpr_atm_acq_load(&subchannel_list->refcount.count);
     gpr_log(GPR_DEBUG, "[%s %p] subchannel_list %p REF %lu->%lu (%s)",
-            subchannel_list->tracer->name, subchannel_list->policy,
+            subchannel_list->tracer->name(), subchannel_list->policy,
             subchannel_list, (unsigned long)(count - 1), (unsigned long)count,
             reason);
   }
@@ -204,10 +204,10 @@
                                    grpc_lb_subchannel_list* subchannel_list,
                                    const char* reason) {
   const bool done = gpr_unref(&subchannel_list->refcount);
-  if (GRPC_TRACER_ON(*subchannel_list->tracer)) {
+  if (subchannel_list->tracer->enabled()) {
     const gpr_atm count = gpr_atm_acq_load(&subchannel_list->refcount.count);
     gpr_log(GPR_DEBUG, "[%s %p] subchannel_list %p UNREF %lu->%lu (%s)",
-            subchannel_list->tracer->name, subchannel_list->policy,
+            subchannel_list->tracer->name(), subchannel_list->policy,
             subchannel_list, (unsigned long)(count + 1), (unsigned long)count,
             reason);
   }
@@ -231,11 +231,11 @@
 
 static void subchannel_data_cancel_connectivity_watch(
     grpc_exec_ctx* exec_ctx, grpc_lb_subchannel_data* sd, const char* reason) {
-  if (GRPC_TRACER_ON(*sd->subchannel_list->tracer)) {
+  if (sd->subchannel_list->tracer->enabled()) {
     gpr_log(GPR_DEBUG,
             "[%s %p] subchannel list %p index %" PRIuPTR " of %" PRIuPTR
             " (subchannel %p): canceling connectivity watch (%s)",
-            sd->subchannel_list->tracer->name, sd->subchannel_list->policy,
+            sd->subchannel_list->tracer->name(), sd->subchannel_list->policy,
             sd->subchannel_list,
             (size_t)(sd - sd->subchannel_list->subchannels),
             sd->subchannel_list->num_subchannels, sd->subchannel, reason);
@@ -248,9 +248,9 @@
 void grpc_lb_subchannel_list_shutdown_and_unref(
     grpc_exec_ctx* exec_ctx, grpc_lb_subchannel_list* subchannel_list,
     const char* reason) {
-  if (GRPC_TRACER_ON(*subchannel_list->tracer)) {
+  if (subchannel_list->tracer->enabled()) {
     gpr_log(GPR_DEBUG, "[%s %p] Shutting down subchannel_list %p (%s)",
-            subchannel_list->tracer->name, subchannel_list->policy,
+            subchannel_list->tracer->name(), subchannel_list->policy,
             subchannel_list, reason);
   }
   GPR_ASSERT(!subchannel_list->shutting_down);
diff --git a/src/core/ext/filters/client_channel/lb_policy/subchannel_list.h b/src/core/ext/filters/client_channel/lb_policy/subchannel_list.h
index e18ad49..e3e5eba 100644
--- a/src/core/ext/filters/client_channel/lb_policy/subchannel_list.h
+++ b/src/core/ext/filters/client_channel/lb_policy/subchannel_list.h
@@ -36,10 +36,6 @@
 // round_robin that could be refactored and moved here.  In a future PR,
 // need to clean this up.
 
-#ifdef __cplusplus
-extern "C" {
-#endif
-
 typedef struct grpc_lb_subchannel_list grpc_lb_subchannel_list;
 
 typedef struct {
@@ -88,7 +84,7 @@
   /** backpointer to owning policy */
   grpc_lb_policy* policy;
 
-  grpc_tracer_flag* tracer;
+  grpc_core::TraceFlag* tracer;
 
   /** all our subchannels */
   size_t num_subchannels;
@@ -121,7 +117,7 @@
 };
 
 grpc_lb_subchannel_list* grpc_lb_subchannel_list_create(
-    grpc_exec_ctx* exec_ctx, grpc_lb_policy* p, grpc_tracer_flag* tracer,
+    grpc_exec_ctx* exec_ctx, grpc_lb_policy* p, grpc_core::TraceFlag* tracer,
     const grpc_lb_addresses* addresses, const grpc_lb_policy_args* args,
     grpc_iomgr_cb_func connectivity_changed_cb);
 
@@ -146,8 +142,4 @@
     grpc_exec_ctx* exec_ctx, grpc_lb_subchannel_list* subchannel_list,
     const char* reason);
 
-#ifdef __cplusplus
-}
-#endif
-
 #endif /* GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_LB_POLICY_SUBCHANNEL_LIST_H */
diff --git a/src/core/ext/filters/client_channel/lb_policy_factory.h b/src/core/ext/filters/client_channel/lb_policy_factory.h
index 360a42b..8f6d8c1 100644
--- a/src/core/ext/filters/client_channel/lb_policy_factory.h
+++ b/src/core/ext/filters/client_channel/lb_policy_factory.h
@@ -29,10 +29,6 @@
 // Channel arg key for grpc_lb_addresses.
 #define GRPC_ARG_LB_ADDRESSES "grpc.lb_addresses"
 
-#ifdef __cplusplus
-extern "C" {
-#endif
-
 typedef struct grpc_lb_policy_factory grpc_lb_policy_factory;
 typedef struct grpc_lb_policy_factory_vtable grpc_lb_policy_factory_vtable;
 
@@ -134,8 +130,4 @@
     grpc_exec_ctx* exec_ctx, grpc_lb_policy_factory* factory,
     grpc_lb_policy_args* args);
 
-#ifdef __cplusplus
-}
-#endif
-
 #endif /* GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_LB_POLICY_FACTORY_H */
diff --git a/src/core/ext/filters/client_channel/lb_policy_registry.h b/src/core/ext/filters/client_channel/lb_policy_registry.h
index 055f751..acddc90 100644
--- a/src/core/ext/filters/client_channel/lb_policy_registry.h
+++ b/src/core/ext/filters/client_channel/lb_policy_registry.h
@@ -22,10 +22,6 @@
 #include "src/core/ext/filters/client_channel/lb_policy_factory.h"
 #include "src/core/lib/iomgr/exec_ctx.h"
 
-#ifdef __cplusplus
-extern "C" {
-#endif
-
 /** Initialize the registry and set \a default_factory as the factory to be
  * returned when no name is provided in a lookup */
 void grpc_lb_policy_registry_init(void);
@@ -41,8 +37,4 @@
 grpc_lb_policy* grpc_lb_policy_create(grpc_exec_ctx* exec_ctx, const char* name,
                                       grpc_lb_policy_args* args);
 
-#ifdef __cplusplus
-}
-#endif
-
 #endif /* GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_LB_POLICY_REGISTRY_H */
diff --git a/src/core/ext/filters/client_channel/parse_address.h b/src/core/ext/filters/client_channel/parse_address.h
index b45859f..ca0a0d1 100644
--- a/src/core/ext/filters/client_channel/parse_address.h
+++ b/src/core/ext/filters/client_channel/parse_address.h
@@ -24,10 +24,6 @@
 #include "src/core/ext/filters/client_channel/uri_parser.h"
 #include "src/core/lib/iomgr/resolve_address.h"
 
-#ifdef __cplusplus
-extern "C" {
-#endif
-
 /** Populate \a resolved_addr from \a uri, whose path is expected to contain a
  * unix socket path. Returns true upon success. */
 bool grpc_parse_unix(const grpc_uri* uri, grpc_resolved_address* resolved_addr);
@@ -49,8 +45,4 @@
 bool grpc_parse_ipv6_hostport(const char* hostport, grpc_resolved_address* addr,
                               bool log_errors);
 
-#ifdef __cplusplus
-}
-#endif
-
 #endif /* GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_PARSE_ADDRESS_H */
diff --git a/src/core/ext/filters/client_channel/proxy_mapper.h b/src/core/ext/filters/client_channel/proxy_mapper.h
index bb8259f..a13861c 100644
--- a/src/core/ext/filters/client_channel/proxy_mapper.h
+++ b/src/core/ext/filters/client_channel/proxy_mapper.h
@@ -25,10 +25,6 @@
 
 #include "src/core/lib/iomgr/resolve_address.h"
 
-#ifdef __cplusplus
-extern "C" {
-#endif
-
 typedef struct grpc_proxy_mapper grpc_proxy_mapper;
 
 typedef struct {
@@ -75,8 +71,4 @@
 
 void grpc_proxy_mapper_destroy(grpc_proxy_mapper* mapper);
 
-#ifdef __cplusplus
-}
-#endif
-
 #endif /* GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_PROXY_MAPPER_H */
diff --git a/src/core/ext/filters/client_channel/proxy_mapper_registry.h b/src/core/ext/filters/client_channel/proxy_mapper_registry.h
index 39c607c..99e54d1 100644
--- a/src/core/ext/filters/client_channel/proxy_mapper_registry.h
+++ b/src/core/ext/filters/client_channel/proxy_mapper_registry.h
@@ -21,10 +21,6 @@
 
 #include "src/core/ext/filters/client_channel/proxy_mapper.h"
 
-#ifdef __cplusplus
-extern "C" {
-#endif
-
 void grpc_proxy_mapper_registry_init();
 void grpc_proxy_mapper_registry_shutdown();
 
@@ -45,8 +41,4 @@
                                     grpc_resolved_address** new_address,
                                     grpc_channel_args** new_args);
 
-#ifdef __cplusplus
-}
-#endif
-
 #endif /* GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_PROXY_MAPPER_REGISTRY_H */
diff --git a/src/core/ext/filters/client_channel/resolver.cc b/src/core/ext/filters/client_channel/resolver.cc
index 7e84b98..c16b151 100644
--- a/src/core/ext/filters/client_channel/resolver.cc
+++ b/src/core/ext/filters/client_channel/resolver.cc
@@ -19,10 +19,8 @@
 #include "src/core/ext/filters/client_channel/resolver.h"
 #include "src/core/lib/iomgr/combiner.h"
 
-#ifndef NDEBUG
-grpc_tracer_flag grpc_trace_resolver_refcount =
-    GRPC_TRACER_INITIALIZER(false, "resolver_refcount");
-#endif
+grpc_core::DebugOnlyTraceFlag grpc_trace_resolver_refcount(false,
+                                                           "resolver_refcount");
 
 void grpc_resolver_init(grpc_resolver* resolver,
                         const grpc_resolver_vtable* vtable,
@@ -35,7 +33,7 @@
 #ifndef NDEBUG
 void grpc_resolver_ref(grpc_resolver* resolver, const char* file, int line,
                        const char* reason) {
-  if (GRPC_TRACER_ON(grpc_trace_resolver_refcount)) {
+  if (grpc_trace_resolver_refcount.enabled()) {
     gpr_atm old_refs = gpr_atm_no_barrier_load(&resolver->refs.count);
     gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG,
             "RESOLVER:%p   ref %" PRIdPTR " -> %" PRIdPTR " %s", resolver,
@@ -50,7 +48,7 @@
 #ifndef NDEBUG
 void grpc_resolver_unref(grpc_exec_ctx* exec_ctx, grpc_resolver* resolver,
                          const char* file, int line, const char* reason) {
-  if (GRPC_TRACER_ON(grpc_trace_resolver_refcount)) {
+  if (grpc_trace_resolver_refcount.enabled()) {
     gpr_atm old_refs = gpr_atm_no_barrier_load(&resolver->refs.count);
     gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG,
             "RESOLVER:%p unref %" PRIdPTR " -> %" PRIdPTR " %s", resolver,
diff --git a/src/core/ext/filters/client_channel/resolver.h b/src/core/ext/filters/client_channel/resolver.h
index a0eb0bc..4e8cfbe 100644
--- a/src/core/ext/filters/client_channel/resolver.h
+++ b/src/core/ext/filters/client_channel/resolver.h
@@ -22,16 +22,10 @@
 #include "src/core/ext/filters/client_channel/subchannel.h"
 #include "src/core/lib/iomgr/iomgr.h"
 
-#ifdef __cplusplus
-extern "C" {
-#endif
-
 typedef struct grpc_resolver grpc_resolver;
 typedef struct grpc_resolver_vtable grpc_resolver_vtable;
 
-#ifndef NDEBUG
-extern grpc_tracer_flag grpc_trace_resolver_refcount;
-#endif
+extern grpc_core::DebugOnlyTraceFlag grpc_trace_resolver_refcount;
 
 /** \a grpc_resolver provides \a grpc_channel_args objects to its caller */
 struct grpc_resolver {
@@ -91,8 +85,4 @@
                                grpc_channel_args** result,
                                grpc_closure* on_complete);
 
-#ifdef __cplusplus
-}
-#endif
-
 #endif /* GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_RESOLVER_H */
diff --git a/src/core/ext/filters/client_channel/resolver/dns/c_ares/dns_resolver_ares.cc b/src/core/ext/filters/client_channel/resolver/dns/c_ares/dns_resolver_ares.cc
index 07737b1..3a16b34 100644
--- a/src/core/ext/filters/client_channel/resolver/dns/c_ares/dns_resolver_ares.cc
+++ b/src/core/ext/filters/client_channel/resolver/dns/c_ares/dns_resolver_ares.cc
@@ -425,7 +425,7 @@
   return &dns_resolver_factory;
 }
 
-extern "C" void grpc_resolver_dns_ares_init(void) {
+void grpc_resolver_dns_ares_init(void) {
   char* resolver = gpr_getenv("GRPC_DNS_RESOLVER");
   /* TODO(zyc): Turn on c-ares based resolver by default after the address
      sorter and the CNAME support are added. */
@@ -441,7 +441,7 @@
   gpr_free(resolver);
 }
 
-extern "C" void grpc_resolver_dns_ares_shutdown(void) {
+void grpc_resolver_dns_ares_shutdown(void) {
   char* resolver = gpr_getenv("GRPC_DNS_RESOLVER");
   if (resolver != nullptr && gpr_stricmp(resolver, "ares") == 0) {
     grpc_ares_cleanup();
@@ -451,8 +451,8 @@
 
 #else /* GRPC_ARES == 1 && !defined(GRPC_UV) */
 
-extern "C" void grpc_resolver_dns_ares_init(void) {}
+void grpc_resolver_dns_ares_init(void) {}
 
-extern "C" void grpc_resolver_dns_ares_shutdown(void) {}
+void grpc_resolver_dns_ares_shutdown(void) {}
 
 #endif /* GRPC_ARES == 1 && !defined(GRPC_UV) */
diff --git a/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver.h b/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver.h
index 0062aa5..03ea36b 100644
--- a/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver.h
+++ b/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver.h
@@ -23,10 +23,6 @@
 #include "src/core/lib/iomgr/exec_ctx.h"
 #include "src/core/lib/iomgr/pollset_set.h"
 
-#ifdef __cplusplus
-extern "C" {
-#endif
-
 typedef struct grpc_ares_ev_driver grpc_ares_ev_driver;
 
 /* Start \a ev_driver. It will keep working until all IO on its ares_channel is
@@ -54,9 +50,5 @@
 void grpc_ares_ev_driver_shutdown(grpc_exec_ctx* exec_ctx,
                                   grpc_ares_ev_driver* ev_driver);
 
-#ifdef __cplusplus
-}
-#endif
-
 #endif /* GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_RESOLVER_DNS_C_ARES_GRPC_ARES_EV_DRIVER_H \
         */
diff --git a/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.h b/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.h
index 6882b7b..72db622 100644
--- a/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.h
+++ b/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.h
@@ -25,10 +25,6 @@
 #include "src/core/lib/iomgr/polling_entity.h"
 #include "src/core/lib/iomgr/resolve_address.h"
 
-#ifdef __cplusplus
-extern "C" {
-#endif
-
 typedef struct grpc_ares_request grpc_ares_request;
 
 /* Asynchronously resolve \a name. Use \a default_port if a port isn't
@@ -69,9 +65,5 @@
    it has been called the same number of times as grpc_ares_init(). */
 void grpc_ares_cleanup(void);
 
-#ifdef __cplusplus
-}
-#endif
-
 #endif /* GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_RESOLVER_DNS_C_ARES_GRPC_ARES_WRAPPER_H \
         */
diff --git a/src/core/ext/filters/client_channel/resolver/dns/native/dns_resolver.cc b/src/core/ext/filters/client_channel/resolver/dns/native/dns_resolver.cc
index 589c748..fc40ce6 100644
--- a/src/core/ext/filters/client_channel/resolver/dns/native/dns_resolver.cc
+++ b/src/core/ext/filters/client_channel/resolver/dns/native/dns_resolver.cc
@@ -295,7 +295,7 @@
   return &dns_resolver_factory;
 }
 
-extern "C" void grpc_resolver_dns_native_init(void) {
+void grpc_resolver_dns_native_init(void) {
   char* resolver = gpr_getenv("GRPC_DNS_RESOLVER");
   if (resolver != nullptr && gpr_stricmp(resolver, "native") == 0) {
     gpr_log(GPR_DEBUG, "Using native dns resolver");
@@ -313,4 +313,4 @@
   gpr_free(resolver);
 }
 
-extern "C" void grpc_resolver_dns_native_shutdown(void) {}
+void grpc_resolver_dns_native_shutdown(void) {}
diff --git a/src/core/ext/filters/client_channel/resolver/fake/fake_resolver.cc b/src/core/ext/filters/client_channel/resolver/fake/fake_resolver.cc
index 85d7090..44798ca 100644
--- a/src/core/ext/filters/client_channel/resolver/fake/fake_resolver.cc
+++ b/src/core/ext/filters/client_channel/resolver/fake/fake_resolver.cc
@@ -258,8 +258,8 @@
 static grpc_resolver_factory fake_resolver_factory = {
     &fake_resolver_factory_vtable};
 
-extern "C" void grpc_resolver_fake_init(void) {
+void grpc_resolver_fake_init(void) {
   grpc_register_resolver_type(&fake_resolver_factory);
 }
 
-extern "C" void grpc_resolver_fake_shutdown(void) {}
+void grpc_resolver_fake_shutdown(void) {}
diff --git a/src/core/ext/filters/client_channel/resolver/fake/fake_resolver.h b/src/core/ext/filters/client_channel/resolver/fake/fake_resolver.h
index 3f341fa..7035cdd 100644
--- a/src/core/ext/filters/client_channel/resolver/fake/fake_resolver.h
+++ b/src/core/ext/filters/client_channel/resolver/fake/fake_resolver.h
@@ -21,10 +21,6 @@
 #include "src/core/ext/filters/client_channel/uri_parser.h"
 #include "src/core/lib/channel/channel_args.h"
 
-#ifdef __cplusplus
-extern "C" {
-#endif
-
 #define GRPC_ARG_FAKE_RESOLVER_RESPONSE_GENERATOR \
   "grpc.fake_resolver.response_generator"
 
@@ -60,9 +56,5 @@
 void grpc_fake_resolver_response_generator_unref(
     grpc_fake_resolver_response_generator* generator);
 
-#ifdef __cplusplus
-}
-#endif
-
 #endif /* GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_RESOLVER_FAKE_FAKE_RESOLVER_H \
         */
diff --git a/src/core/ext/filters/client_channel/resolver/sockaddr/sockaddr_resolver.cc b/src/core/ext/filters/client_channel/resolver/sockaddr/sockaddr_resolver.cc
index 1da8ab9..f0934b5 100644
--- a/src/core/ext/filters/client_channel/resolver/sockaddr/sockaddr_resolver.cc
+++ b/src/core/ext/filters/client_channel/resolver/sockaddr/sockaddr_resolver.cc
@@ -211,7 +211,7 @@
 DECL_FACTORY(ipv4);
 DECL_FACTORY(ipv6);
 
-extern "C" void grpc_resolver_sockaddr_init(void) {
+void grpc_resolver_sockaddr_init(void) {
   grpc_register_resolver_type(&ipv4_resolver_factory);
   grpc_register_resolver_type(&ipv6_resolver_factory);
 #ifdef GRPC_HAVE_UNIX_SOCKET
@@ -219,4 +219,4 @@
 #endif
 }
 
-extern "C" void grpc_resolver_sockaddr_shutdown(void) {}
+void grpc_resolver_sockaddr_shutdown(void) {}
diff --git a/src/core/ext/filters/client_channel/resolver_factory.h b/src/core/ext/filters/client_channel/resolver_factory.h
index 62555a4..fcf8ec4 100644
--- a/src/core/ext/filters/client_channel/resolver_factory.h
+++ b/src/core/ext/filters/client_channel/resolver_factory.h
@@ -24,10 +24,6 @@
 #include "src/core/ext/filters/client_channel/uri_parser.h"
 #include "src/core/lib/iomgr/pollset_set.h"
 
-#ifdef __cplusplus
-extern "C" {
-#endif
-
 typedef struct grpc_resolver_factory grpc_resolver_factory;
 typedef struct grpc_resolver_factory_vtable grpc_resolver_factory_vtable;
 
@@ -71,8 +67,4 @@
 char* grpc_resolver_factory_get_default_authority(
     grpc_resolver_factory* factory, grpc_uri* uri);
 
-#ifdef __cplusplus
-}
-#endif
-
 #endif /* GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_RESOLVER_FACTORY_H */
diff --git a/src/core/ext/filters/client_channel/resolver_registry.h b/src/core/ext/filters/client_channel/resolver_registry.h
index 01a2d0b..ecc9f82 100644
--- a/src/core/ext/filters/client_channel/resolver_registry.h
+++ b/src/core/ext/filters/client_channel/resolver_registry.h
@@ -22,10 +22,6 @@
 #include "src/core/ext/filters/client_channel/resolver_factory.h"
 #include "src/core/lib/iomgr/pollset_set.h"
 
-#ifdef __cplusplus
-extern "C" {
-#endif
-
 void grpc_resolver_registry_init();
 void grpc_resolver_registry_shutdown(void);
 
@@ -70,8 +66,4 @@
 char* grpc_resolver_factory_add_default_prefix_if_needed(
     grpc_exec_ctx* exec_ctx, const char* target);
 
-#ifdef __cplusplus
-}
-#endif
-
 #endif /* GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_RESOLVER_REGISTRY_H */
diff --git a/src/core/ext/filters/client_channel/retry_throttle.h b/src/core/ext/filters/client_channel/retry_throttle.h
index 399383d..bf99297 100644
--- a/src/core/ext/filters/client_channel/retry_throttle.h
+++ b/src/core/ext/filters/client_channel/retry_throttle.h
@@ -21,10 +21,6 @@
 
 #include <stdbool.h>
 
-#ifdef __cplusplus
-extern "C" {
-#endif
-
 /// Tracks retry throttling data for an individual server name.
 typedef struct grpc_server_retry_throttle_data grpc_server_retry_throttle_data;
 
@@ -51,8 +47,4 @@
 grpc_server_retry_throttle_data* grpc_retry_throttle_map_get_data_for_server(
     const char* server_name, int max_milli_tokens, int milli_token_ratio);
 
-#ifdef __cplusplus
-}
-#endif
-
 #endif /* GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_RETRY_THROTTLE_H */
diff --git a/src/core/ext/filters/client_channel/subchannel.cc b/src/core/ext/filters/client_channel/subchannel.cc
index 2720e68..58e294d 100644
--- a/src/core/ext/filters/client_channel/subchannel.cc
+++ b/src/core/ext/filters/client_channel/subchannel.cc
@@ -199,7 +199,7 @@
   gpr_atm old_val = barrier ? gpr_atm_full_fetch_add(&c->ref_pair, delta)
                             : gpr_atm_no_barrier_fetch_add(&c->ref_pair, delta);
 #ifndef NDEBUG
-  if (GRPC_TRACER_ON(grpc_trace_stream_refcount)) {
+  if (grpc_trace_stream_refcount.enabled()) {
     gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG,
             "SUBCHANNEL: %p %12s 0x%" PRIxPTR " -> 0x%" PRIxPTR " [%s]", c,
             purpose, old_val, old_val + delta, reason);
diff --git a/src/core/ext/filters/client_channel/subchannel.h b/src/core/ext/filters/client_channel/subchannel.h
index 970f182..1f326fc 100644
--- a/src/core/ext/filters/client_channel/subchannel.h
+++ b/src/core/ext/filters/client_channel/subchannel.h
@@ -26,10 +26,6 @@
 #include "src/core/lib/transport/connectivity_state.h"
 #include "src/core/lib/transport/metadata.h"
 
-#ifdef __cplusplus
-extern "C" {
-#endif
-
 // Channel arg containing a grpc_resolved_address to connect to.
 #define GRPC_ARG_SUBCHANNEL_ADDRESS "grpc.subchannel_address"
 
@@ -192,8 +188,4 @@
 /// Caller is responsible for freeing the string.
 grpc_arg grpc_create_subchannel_address_arg(const grpc_resolved_address* addr);
 
-#ifdef __cplusplus
-}
-#endif
-
 #endif /* GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_SUBCHANNEL_H */
diff --git a/src/core/ext/filters/client_channel/subchannel_index.cc b/src/core/ext/filters/client_channel/subchannel_index.cc
index ae39ca3..1624643 100644
--- a/src/core/ext/filters/client_channel/subchannel_index.cc
+++ b/src/core/ext/filters/client_channel/subchannel_index.cc
@@ -163,7 +163,7 @@
                                                 grpc_subchannel_key* key,
                                                 grpc_subchannel* constructed) {
   grpc_subchannel* c = nullptr;
-  bool need_to_unref_constructed;
+  bool need_to_unref_constructed = false;
 
   while (c == nullptr) {
     need_to_unref_constructed = false;
diff --git a/src/core/ext/filters/client_channel/subchannel_index.h b/src/core/ext/filters/client_channel/subchannel_index.h
index 47f9c7b..6a4d06e 100644
--- a/src/core/ext/filters/client_channel/subchannel_index.h
+++ b/src/core/ext/filters/client_channel/subchannel_index.h
@@ -21,10 +21,6 @@
 
 #include "src/core/ext/filters/client_channel/subchannel.h"
 
-#ifdef __cplusplus
-extern "C" {
-#endif
-
 /** \file Provides an index of active subchannels so that they can be
     shared amongst channels */
 
@@ -82,8 +78,4 @@
  * force_creation set. */
 void grpc_subchannel_index_test_only_set_force_creation(bool force_creation);
 
-#ifdef __cplusplus
-}
-#endif
-
 #endif /* GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_SUBCHANNEL_INDEX_H */
diff --git a/src/core/ext/filters/client_channel/uri_parser.h b/src/core/ext/filters/client_channel/uri_parser.h
index cd877ad..8475290 100644
--- a/src/core/ext/filters/client_channel/uri_parser.h
+++ b/src/core/ext/filters/client_channel/uri_parser.h
@@ -22,10 +22,6 @@
 #include <stddef.h>
 #include "src/core/lib/iomgr/exec_ctx.h"
 
-#ifdef __cplusplus
-extern "C" {
-#endif
-
 typedef struct {
   char* scheme;
   char* authority;
@@ -51,8 +47,4 @@
 /** destroy a uri */
 void grpc_uri_destroy(grpc_uri* uri);
 
-#ifdef __cplusplus
-}
-#endif
-
 #endif /* GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_URI_PARSER_H */
diff --git a/src/core/ext/filters/deadline/deadline_filter.cc b/src/core/ext/filters/deadline/deadline_filter.cc
index 849ce71..5db7584 100644
--- a/src/core/ext/filters/deadline/deadline_filter.cc
+++ b/src/core/ext/filters/deadline/deadline_filter.cc
@@ -382,7 +382,7 @@
              : true;
 }
 
-extern "C" void grpc_deadline_filter_init(void) {
+void grpc_deadline_filter_init(void) {
   grpc_channel_init_register_stage(
       GRPC_CLIENT_DIRECT_CHANNEL, GRPC_CHANNEL_INIT_BUILTIN_PRIORITY,
       maybe_add_deadline_filter, (void*)&grpc_client_deadline_filter);
@@ -391,4 +391,4 @@
       maybe_add_deadline_filter, (void*)&grpc_server_deadline_filter);
 }
 
-extern "C" void grpc_deadline_filter_shutdown(void) {}
+void grpc_deadline_filter_shutdown(void) {}
diff --git a/src/core/ext/filters/deadline/deadline_filter.h b/src/core/ext/filters/deadline/deadline_filter.h
index e665dc5..8d835d0 100644
--- a/src/core/ext/filters/deadline/deadline_filter.h
+++ b/src/core/ext/filters/deadline/deadline_filter.h
@@ -20,10 +20,6 @@
 #include "src/core/lib/channel/channel_stack.h"
 #include "src/core/lib/iomgr/timer.h"
 
-#ifdef __cplusplus
-extern "C" {
-#endif
-
 typedef enum grpc_deadline_timer_state {
   GRPC_DEADLINE_STATE_INITIAL,
   GRPC_DEADLINE_STATE_PENDING,
@@ -94,8 +90,4 @@
 extern const grpc_channel_filter grpc_client_deadline_filter;
 extern const grpc_channel_filter grpc_server_deadline_filter;
 
-#ifdef __cplusplus
-}
-#endif
-
 #endif /* GRPC_CORE_EXT_FILTERS_DEADLINE_DEADLINE_FILTER_H */
diff --git a/src/core/ext/filters/http/client/http_client_filter.h b/src/core/ext/filters/http/client/http_client_filter.h
index 9ed8e76..ec8177c 100644
--- a/src/core/ext/filters/http/client/http_client_filter.h
+++ b/src/core/ext/filters/http/client/http_client_filter.h
@@ -20,18 +20,10 @@
 
 #include "src/core/lib/channel/channel_stack.h"
 
-#ifdef __cplusplus
-extern "C" {
-#endif
-
 /* Processes metadata on the client side for HTTP2 transports */
 extern const grpc_channel_filter grpc_http_client_filter;
 
 /* 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"
 
-#ifdef __cplusplus
-}
-#endif
-
 #endif /* GRPC_CORE_EXT_FILTERS_HTTP_CLIENT_HTTP_CLIENT_FILTER_H */
diff --git a/src/core/ext/filters/http/http_filters_plugin.cc b/src/core/ext/filters/http/http_filters_plugin.cc
index 69dbde4..483eb02 100644
--- a/src/core/ext/filters/http/http_filters_plugin.cc
+++ b/src/core/ext/filters/http/http_filters_plugin.cc
@@ -64,8 +64,7 @@
              : true;
 }
 
-extern "C" void grpc_http_filters_init(void) {
-  grpc_register_tracer(&grpc_compression_trace);
+void grpc_http_filters_init(void) {
   grpc_channel_init_register_stage(GRPC_CLIENT_SUBCHANNEL,
                                    GRPC_CHANNEL_INIT_BUILTIN_PRIORITY,
                                    maybe_add_optional_filter, &compress_filter);
@@ -86,4 +85,4 @@
       maybe_add_required_filter, (void*)&grpc_http_server_filter);
 }
 
-extern "C" void grpc_http_filters_shutdown(void) {}
+void grpc_http_filters_shutdown(void) {}
diff --git a/src/core/ext/filters/http/message_compress/message_compress_filter.cc b/src/core/ext/filters/http/message_compress/message_compress_filter.cc
index 8d95133..d070b56 100644
--- a/src/core/ext/filters/http/message_compress/message_compress_filter.cc
+++ b/src/core/ext/filters/http/message_compress/message_compress_filter.cc
@@ -243,7 +243,7 @@
   bool did_compress = grpc_msg_compress(exec_ctx, calld->compression_algorithm,
                                         &calld->slices, &tmp);
   if (did_compress) {
-    if (GRPC_TRACER_ON(grpc_compression_trace)) {
+    if (grpc_compression_trace.enabled()) {
       const char* algo_name;
       const size_t before_size = calld->slices.length;
       const size_t after_size = tmp.length;
@@ -258,7 +258,7 @@
     grpc_slice_buffer_swap(&calld->slices, &tmp);
     send_flags |= GRPC_WRITE_INTERNAL_COMPRESS;
   } else {
-    if (GRPC_TRACER_ON(grpc_compression_trace)) {
+    if (grpc_compression_trace.enabled()) {
       const char* algo_name;
       GPR_ASSERT(grpc_compression_algorithm_name(calld->compression_algorithm,
                                                  &algo_name));
diff --git a/src/core/ext/filters/http/message_compress/message_compress_filter.h b/src/core/ext/filters/http/message_compress/message_compress_filter.h
index 79a2815..6220791 100644
--- a/src/core/ext/filters/http/message_compress/message_compress_filter.h
+++ b/src/core/ext/filters/http/message_compress/message_compress_filter.h
@@ -23,10 +23,6 @@
 
 #include "src/core/lib/channel/channel_stack.h"
 
-#ifdef __cplusplus
-extern "C" {
-#endif
-
 /** Compression filter for outgoing data.
  *
  * See <grpc/compression.h> for the available compression settings.
@@ -51,9 +47,5 @@
 
 extern const grpc_channel_filter grpc_message_compress_filter;
 
-#ifdef __cplusplus
-}
-#endif
-
 #endif /* GRPC_CORE_EXT_FILTERS_HTTP_MESSAGE_COMPRESS_MESSAGE_COMPRESS_FILTER_H \
         */
diff --git a/src/core/ext/filters/http/server/http_server_filter.h b/src/core/ext/filters/http/server/http_server_filter.h
index 4b38cc5..c0f678a 100644
--- a/src/core/ext/filters/http/server/http_server_filter.h
+++ b/src/core/ext/filters/http/server/http_server_filter.h
@@ -21,15 +21,7 @@
 
 #include "src/core/lib/channel/channel_stack.h"
 
-#ifdef __cplusplus
-extern "C" {
-#endif
-
 /* Processes metadata on the client side for HTTP2 transports */
 extern const grpc_channel_filter grpc_http_server_filter;
 
-#ifdef __cplusplus
-}
-#endif
-
 #endif /* GRPC_CORE_EXT_FILTERS_HTTP_SERVER_HTTP_SERVER_FILTER_H */
diff --git a/src/core/ext/filters/load_reporting/server_load_reporting_filter.h b/src/core/ext/filters/load_reporting/server_load_reporting_filter.h
index 356f8b8..1baee5e 100644
--- a/src/core/ext/filters/load_reporting/server_load_reporting_filter.h
+++ b/src/core/ext/filters/load_reporting/server_load_reporting_filter.h
@@ -22,15 +22,7 @@
 #include "src/core/ext/filters/load_reporting/server_load_reporting_plugin.h"
 #include "src/core/lib/channel/channel_stack.h"
 
-#ifdef __cplusplus
-extern "C" {
-#endif
-
 extern const grpc_channel_filter grpc_server_load_reporting_filter;
 
-#ifdef __cplusplus
-}
-#endif
-
 #endif /* GRPC_CORE_EXT_FILTERS_LOAD_REPORTING_SERVER_LOAD_REPORTING_FILTER_H \
         */
diff --git a/src/core/ext/filters/load_reporting/server_load_reporting_plugin.cc b/src/core/ext/filters/load_reporting/server_load_reporting_plugin.cc
index ab83879..accb779 100644
--- a/src/core/ext/filters/load_reporting/server_load_reporting_plugin.cc
+++ b/src/core/ext/filters/load_reporting/server_load_reporting_plugin.cc
@@ -61,10 +61,10 @@
 
 /* Plugin registration */
 
-extern "C" void grpc_server_load_reporting_plugin_init(void) {
+void grpc_server_load_reporting_plugin_init(void) {
   grpc_channel_init_register_stage(GRPC_SERVER_CHANNEL, INT_MAX,
                                    maybe_add_server_load_reporting_filter,
                                    (void*)&grpc_server_load_reporting_filter);
 }
 
-extern "C" void grpc_server_load_reporting_plugin_shutdown() {}
+void grpc_server_load_reporting_plugin_shutdown() {}
diff --git a/src/core/ext/filters/load_reporting/server_load_reporting_plugin.h b/src/core/ext/filters/load_reporting/server_load_reporting_plugin.h
index a6448ce..4b694d3 100644
--- a/src/core/ext/filters/load_reporting/server_load_reporting_plugin.h
+++ b/src/core/ext/filters/load_reporting/server_load_reporting_plugin.h
@@ -23,10 +23,6 @@
 
 #include "src/core/lib/channel/channel_stack.h"
 
-#ifdef __cplusplus
-extern "C" {
-#endif
-
 /** Identifiers for the invocation point of the users LR callback */
 typedef enum grpc_load_reporting_source {
   GRPC_LR_POINT_UNKNOWN = 0,
@@ -59,9 +55,5 @@
 /** Return a \a grpc_arg enabling load reporting */
 grpc_arg grpc_load_reporting_enable_arg();
 
-#ifdef __cplusplus
-}
-#endif
-
 #endif /* GRPC_CORE_EXT_FILTERS_LOAD_REPORTING_SERVER_LOAD_REPORTING_PLUGIN_H \
         */
diff --git a/src/core/ext/filters/max_age/max_age_filter.cc b/src/core/ext/filters/max_age/max_age_filter.cc
index 001f9f3..917fbd9 100644
--- a/src/core/ext/filters/max_age/max_age_filter.cc
+++ b/src/core/ext/filters/max_age/max_age_filter.cc
@@ -127,7 +127,7 @@
                   &chand->close_max_age_channel);
   gpr_mu_unlock(&chand->max_age_timer_mu);
   grpc_transport_op* op = grpc_make_transport_op(nullptr);
-  op->on_connectivity_state_change = &chand->channel_connectivity_changed,
+  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(chand->channel_stack, 0), op);
@@ -222,7 +222,7 @@
   channel_data* chand = (channel_data*)arg;
   if (chand->connectivity_state != GRPC_CHANNEL_SHUTDOWN) {
     grpc_transport_op* op = grpc_make_transport_op(nullptr);
-    op->on_connectivity_state_change = &chand->channel_connectivity_changed,
+    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(chand->channel_stack, 0), op);
@@ -404,10 +404,10 @@
   }
 }
 
-extern "C" void grpc_max_age_filter_init(void) {
+void grpc_max_age_filter_init(void) {
   grpc_channel_init_register_stage(GRPC_SERVER_CHANNEL,
                                    GRPC_CHANNEL_INIT_BUILTIN_PRIORITY,
                                    maybe_add_max_age_filter, nullptr);
 }
 
-extern "C" void grpc_max_age_filter_shutdown(void) {}
+void grpc_max_age_filter_shutdown(void) {}
diff --git a/src/core/ext/filters/max_age/max_age_filter.h b/src/core/ext/filters/max_age/max_age_filter.h
index eeeefd6..68fb4a4 100644
--- a/src/core/ext/filters/max_age/max_age_filter.h
+++ b/src/core/ext/filters/max_age/max_age_filter.h
@@ -19,14 +19,6 @@
 
 #include "src/core/lib/channel/channel_stack.h"
 
-#ifdef __cplusplus
-extern "C" {
-#endif
-
 extern const grpc_channel_filter grpc_max_age_filter;
 
-#ifdef __cplusplus
-}
-#endif
-
 #endif /* GRPC_CORE_EXT_FILTERS_MAX_AGE_MAX_AGE_FILTER_H */
diff --git a/src/core/ext/filters/message_size/message_size_filter.cc b/src/core/ext/filters/message_size/message_size_filter.cc
index 2e81d09..3d2252a 100644
--- a/src/core/ext/filters/message_size/message_size_filter.cc
+++ b/src/core/ext/filters/message_size/message_size_filter.cc
@@ -310,7 +310,7 @@
   }
 }
 
-extern "C" void grpc_message_size_filter_init(void) {
+void grpc_message_size_filter_init(void) {
   grpc_channel_init_register_stage(GRPC_CLIENT_SUBCHANNEL,
                                    GRPC_CHANNEL_INIT_BUILTIN_PRIORITY,
                                    maybe_add_message_size_filter, nullptr);
@@ -322,4 +322,4 @@
                                    maybe_add_message_size_filter, nullptr);
 }
 
-extern "C" void grpc_message_size_filter_shutdown(void) {}
+void grpc_message_size_filter_shutdown(void) {}
diff --git a/src/core/ext/filters/message_size/message_size_filter.h b/src/core/ext/filters/message_size/message_size_filter.h
index da325d6..d3667f7 100644
--- a/src/core/ext/filters/message_size/message_size_filter.h
+++ b/src/core/ext/filters/message_size/message_size_filter.h
@@ -19,14 +19,6 @@
 
 #include "src/core/lib/channel/channel_stack.h"
 
-#ifdef __cplusplus
-extern "C" {
-#endif
-
 extern const grpc_channel_filter grpc_message_size_filter;
 
-#ifdef __cplusplus
-}
-#endif
-
 #endif /* GRPC_CORE_EXT_FILTERS_MESSAGE_SIZE_MESSAGE_SIZE_FILTER_H */
diff --git a/src/core/ext/filters/workarounds/workaround_cronet_compression_filter.cc b/src/core/ext/filters/workarounds/workaround_cronet_compression_filter.cc
index 6bbb4d5..4ab1ee4 100644
--- a/src/core/ext/filters/workarounds/workaround_cronet_compression_filter.cc
+++ b/src/core/ext/filters/workarounds/workaround_cronet_compression_filter.cc
@@ -139,7 +139,7 @@
   bool grpc_objc_specifier_seen = false;
   bool cronet_specifier_seen = false;
   char *major_version_str = user_agent_str, *minor_version_str;
-  long major_version, minor_version;
+  long major_version = 0, minor_version = 0;
 
   char* head = strtok(user_agent_str, " ");
   while (head != nullptr) {
@@ -196,7 +196,7 @@
       builder, &grpc_workaround_cronet_compression_filter, nullptr, nullptr);
 }
 
-extern "C" void grpc_workaround_cronet_compression_filter_init(void) {
+void grpc_workaround_cronet_compression_filter_init(void) {
   grpc_channel_init_register_stage(
       GRPC_SERVER_CHANNEL, GRPC_WORKAROUND_PRIORITY_HIGH,
       register_workaround_cronet_compression, nullptr);
@@ -204,4 +204,4 @@
                            parse_user_agent);
 }
 
-extern "C" void grpc_workaround_cronet_compression_filter_shutdown(void) {}
+void grpc_workaround_cronet_compression_filter_shutdown(void) {}
diff --git a/src/core/ext/filters/workarounds/workaround_cronet_compression_filter.h b/src/core/ext/filters/workarounds/workaround_cronet_compression_filter.h
index c8b07df..9dae4f0 100644
--- a/src/core/ext/filters/workarounds/workaround_cronet_compression_filter.h
+++ b/src/core/ext/filters/workarounds/workaround_cronet_compression_filter.h
@@ -19,15 +19,7 @@
 
 #include "src/core/lib/channel/channel_stack.h"
 
-#ifdef __cplusplus
-extern "C" {
-#endif
-
 extern const grpc_channel_filter grpc_workaround_cronet_compression_filter;
 
-#ifdef __cplusplus
-}
-#endif
-
 #endif /* GRPC_CORE_EXT_FILTERS_WORKAROUNDS_WORKAROUND_CRONET_COMPRESSION_FILTER_H \
         */
diff --git a/src/core/ext/filters/workarounds/workaround_utils.h b/src/core/ext/filters/workarounds/workaround_utils.h
index a954ad4..d6ef5e8 100644
--- a/src/core/ext/filters/workarounds/workaround_utils.h
+++ b/src/core/ext/filters/workarounds/workaround_utils.h
@@ -24,10 +24,6 @@
 #define GRPC_WORKAROUND_PRIORITY_HIGH 10001
 #define GRPC_WORKAROUND_PROIRITY_LOW 9999
 
-#ifdef __cplusplus
-extern "C" {
-#endif
-
 typedef struct grpc_workaround_user_agent_md {
   bool workaround_active[GRPC_MAX_WORKAROUND_ID];
 } grpc_workaround_user_agent_md;
@@ -38,8 +34,4 @@
 
 void grpc_register_workaround(uint32_t id, user_agent_parser parser);
 
-#ifdef __cplusplus
-}
-#endif
-
 #endif /* GRPC_CORE_EXT_FILTERS_WORKAROUNDS_WORKAROUND_UTILS_H */
diff --git a/src/core/ext/transport/chttp2/alpn/alpn.h b/src/core/ext/transport/chttp2/alpn/alpn.h
index 4a420e8..fd7513c 100644
--- a/src/core/ext/transport/chttp2/alpn/alpn.h
+++ b/src/core/ext/transport/chttp2/alpn/alpn.h
@@ -21,10 +21,6 @@
 
 #include <string.h>
 
-#ifdef __cplusplus
-extern "C" {
-#endif
-
 /* Retuns 1 if the version is supported, 0 otherwise. */
 int grpc_chttp2_is_alpn_version_supported(const char* version, size_t size);
 
@@ -35,8 +31,4 @@
  * grpc_chttp2_num_alpn_versions()) */
 const char* grpc_chttp2_get_alpn_version_index(size_t i);
 
-#ifdef __cplusplus
-}
-#endif
-
 #endif /* GRPC_CORE_EXT_TRANSPORT_CHTTP2_ALPN_ALPN_H */
diff --git a/src/core/ext/transport/chttp2/client/chttp2_connector.h b/src/core/ext/transport/chttp2/client/chttp2_connector.h
index 63f264e..e258892 100644
--- a/src/core/ext/transport/chttp2/client/chttp2_connector.h
+++ b/src/core/ext/transport/chttp2/client/chttp2_connector.h
@@ -19,16 +19,8 @@
 #ifndef GRPC_CORE_EXT_TRANSPORT_CHTTP2_CLIENT_CHTTP2_CONNECTOR_H
 #define GRPC_CORE_EXT_TRANSPORT_CHTTP2_CLIENT_CHTTP2_CONNECTOR_H
 
-#ifdef __cplusplus
-extern "C" {
-#endif
-
 #include "src/core/ext/filters/client_channel/connector.h"
 
 grpc_connector* grpc_chttp2_connector_create();
 
-#ifdef __cplusplus
-}
-#endif
-
 #endif /* GRPC_CORE_EXT_TRANSPORT_CHTTP2_CLIENT_CHTTP2_CONNECTOR_H */
diff --git a/src/core/ext/transport/chttp2/server/chttp2_server.h b/src/core/ext/transport/chttp2/server/chttp2_server.h
index 4e0e7aa..68304fd 100644
--- a/src/core/ext/transport/chttp2/server/chttp2_server.h
+++ b/src/core/ext/transport/chttp2/server/chttp2_server.h
@@ -23,18 +23,10 @@
 
 #include "src/core/lib/iomgr/exec_ctx.h"
 
-#ifdef __cplusplus
-extern "C" {
-#endif
-
 /// Adds a port to \a server.  Sets \a port_num to the port number.
 /// Takes ownership of \a args.
 grpc_error* grpc_chttp2_server_add_port(grpc_exec_ctx* exec_ctx,
                                         grpc_server* server, const char* addr,
                                         grpc_channel_args* args, int* port_num);
 
-#ifdef __cplusplus
-}
-#endif
-
 #endif /* GRPC_CORE_EXT_TRANSPORT_CHTTP2_SERVER_CHTTP2_SERVER_H */
diff --git a/src/core/ext/transport/chttp2/transport/bin_decoder.h b/src/core/ext/transport/chttp2/transport/bin_decoder.h
index a9c4c9a..a78c305 100644
--- a/src/core/ext/transport/chttp2/transport/bin_decoder.h
+++ b/src/core/ext/transport/chttp2/transport/bin_decoder.h
@@ -22,10 +22,6 @@
 #include <grpc/slice.h>
 #include <stdbool.h>
 
-#ifdef __cplusplus
-extern "C" {
-#endif
-
 struct grpc_base64_decode_context {
   /* input/output: */
   uint8_t* input_cur;
@@ -53,8 +49,4 @@
                                                  grpc_slice input,
                                                  size_t output_length);
 
-#ifdef __cplusplus
-}
-#endif
-
 #endif /* GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_BIN_DECODER_H */
diff --git a/src/core/ext/transport/chttp2/transport/bin_encoder.h b/src/core/ext/transport/chttp2/transport/bin_encoder.h
index 0be3633..a8f36a3 100644
--- a/src/core/ext/transport/chttp2/transport/bin_encoder.h
+++ b/src/core/ext/transport/chttp2/transport/bin_encoder.h
@@ -21,10 +21,6 @@
 
 #include <grpc/slice.h>
 
-#ifdef __cplusplus
-extern "C" {
-#endif
-
 /* base64 encode a slice. Returns a new slice, does not take ownership of the
    input */
 grpc_slice grpc_chttp2_base64_encode(grpc_slice input);
@@ -40,8 +36,4 @@
    return y; */
 grpc_slice grpc_chttp2_base64_encode_and_huffman_compress(grpc_slice input);
 
-#ifdef __cplusplus
-}
-#endif
-
 #endif /* GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_BIN_ENCODER_H */
diff --git a/src/core/ext/transport/chttp2/transport/chttp2_plugin.cc b/src/core/ext/transport/chttp2/transport/chttp2_plugin.cc
index ac9ae5c..97c1878 100644
--- a/src/core/ext/transport/chttp2/transport/chttp2_plugin.cc
+++ b/src/core/ext/transport/chttp2/transport/chttp2_plugin.cc
@@ -20,13 +20,6 @@
 #include "src/core/lib/debug/trace.h"
 #include "src/core/lib/transport/metadata.h"
 
-extern "C" void grpc_chttp2_plugin_init(void) {
-  grpc_register_tracer(&grpc_http_trace);
-  grpc_register_tracer(&grpc_flowctl_trace);
-  grpc_register_tracer(&grpc_trace_http2_stream_state);
-#ifndef NDEBUG
-  grpc_register_tracer(&grpc_trace_chttp2_refcount);
-#endif
-}
+void grpc_chttp2_plugin_init(void) {}
 
-extern "C" void grpc_chttp2_plugin_shutdown(void) {}
+void grpc_chttp2_plugin_shutdown(void) {}
diff --git a/src/core/ext/transport/chttp2/transport/chttp2_transport.cc b/src/core/ext/transport/chttp2/transport/chttp2_transport.cc
index 43788bf..5a7830b 100644
--- a/src/core/ext/transport/chttp2/transport/chttp2_transport.cc
+++ b/src/core/ext/transport/chttp2/transport/chttp2_transport.cc
@@ -90,13 +90,9 @@
 static int g_default_max_ping_strikes = DEFAULT_MAX_PING_STRIKES;
 
 #define MAX_CLIENT_STREAM_ID 0x7fffffffu
-grpc_tracer_flag grpc_http_trace = GRPC_TRACER_INITIALIZER(false, "http");
-grpc_tracer_flag grpc_flowctl_trace = GRPC_TRACER_INITIALIZER(false, "flowctl");
-
-#ifndef NDEBUG
-grpc_tracer_flag grpc_trace_chttp2_refcount =
-    GRPC_TRACER_INITIALIZER(false, "chttp2_refcount");
-#endif
+grpc_core::TraceFlag grpc_http_trace(false, "http");
+grpc_core::DebugOnlyTraceFlag grpc_trace_chttp2_refcount(false,
+                                                         "chttp2_refcount");
 
 /* forward declarations of various callbacks that we'll build closures around */
 static void write_action_begin_locked(grpc_exec_ctx* exec_ctx, void* t,
@@ -235,7 +231,7 @@
 void grpc_chttp2_unref_transport(grpc_exec_ctx* exec_ctx,
                                  grpc_chttp2_transport* t, const char* reason,
                                  const char* file, int line) {
-  if (GRPC_TRACER_ON(grpc_trace_chttp2_refcount)) {
+  if (grpc_trace_chttp2_refcount.enabled()) {
     gpr_atm val = gpr_atm_no_barrier_load(&t->refs.count);
     gpr_log(GPR_DEBUG, "chttp2:unref:%p %" PRIdPTR "->%" PRIdPTR " %s [%s:%d]",
             t, val, val - 1, reason, file, line);
@@ -246,7 +242,7 @@
 
 void grpc_chttp2_ref_transport(grpc_chttp2_transport* t, const char* reason,
                                const char* file, int line) {
-  if (GRPC_TRACER_ON(grpc_trace_chttp2_refcount)) {
+  if (grpc_trace_chttp2_refcount.enabled()) {
     gpr_atm val = gpr_atm_no_barrier_load(&t->refs.count);
     gpr_log(GPR_DEBUG, "chttp2:  ref:%p %" PRIdPTR "->%" PRIdPTR " %s [%s:%d]",
             t, val, val + 1, reason, file, line);
@@ -553,6 +549,7 @@
   /* No pings allowed before receiving a header or data frame. */
   t->ping_state.pings_before_data_required = 0;
   t->ping_state.is_delayed_ping_timer_set = false;
+  t->ping_state.last_ping_sent_time = GRPC_MILLIS_INF_PAST;
 
   t->ping_recv_state.last_ping_recv_time = GRPC_MILLIS_INF_PAST;
   t->ping_recv_state.ping_strikes = 0;
@@ -1237,7 +1234,7 @@
     return;
   }
   closure->next_data.scratch -= CLOSURE_BARRIER_FIRST_REF_BIT;
-  if (GRPC_TRACER_ON(grpc_http_trace)) {
+  if (grpc_http_trace.enabled()) {
     const char* errstr = grpc_error_string(error);
     gpr_log(
         GPR_DEBUG,
@@ -1396,7 +1393,7 @@
 
   GRPC_STATS_INC_HTTP2_OP_BATCHES(exec_ctx);
 
-  if (GRPC_TRACER_ON(grpc_http_trace)) {
+  if (grpc_http_trace.enabled()) {
     char* str = grpc_transport_stream_op_batch_string(op);
     gpr_log(GPR_DEBUG, "perform_stream_op_locked: %s; on_complete = %p", str,
             op->on_complete);
@@ -1686,7 +1683,7 @@
     }
   }
 
-  if (GRPC_TRACER_ON(grpc_http_trace)) {
+  if (grpc_http_trace.enabled()) {
     char* str = grpc_transport_stream_op_batch_string(op);
     gpr_log(GPR_DEBUG, "perform_stream_op[s=%p]: %s", s, str);
     gpr_free(str);
@@ -1762,7 +1759,7 @@
   grpc_http2_error_code http_error;
   grpc_slice slice;
   grpc_error_get_status(exec_ctx, error, GRPC_MILLIS_INF_FUTURE, nullptr,
-                        &slice, &http_error);
+                        &slice, &http_error, nullptr);
   grpc_chttp2_goaway_append(t->last_new_stream_id, (uint32_t)http_error,
                             grpc_slice_ref_internal(slice), &t->qbuf);
   grpc_chttp2_initiate_write(exec_ctx, t,
@@ -2065,7 +2062,7 @@
     if (s->id != 0) {
       grpc_http2_error_code http_error;
       grpc_error_get_status(exec_ctx, due_to_error, s->deadline, nullptr,
-                            nullptr, &http_error);
+                            nullptr, &http_error, nullptr);
       grpc_slice_buffer_add(
           &t->qbuf, grpc_chttp2_rst_stream_create(s->id, (uint32_t)http_error,
                                                   &s->stats.outgoing));
@@ -2083,7 +2080,8 @@
                              grpc_chttp2_stream* s, grpc_error* error) {
   grpc_status_code status;
   grpc_slice slice;
-  grpc_error_get_status(exec_ctx, error, s->deadline, &status, &slice, nullptr);
+  grpc_error_get_status(exec_ctx, error, s->deadline, &status, &slice, nullptr,
+                        nullptr);
   if (status != GRPC_STATUS_OK) {
     s->seen_error = true;
   }
@@ -2248,7 +2246,7 @@
   grpc_status_code grpc_status;
   grpc_slice slice;
   grpc_error_get_status(exec_ctx, error, s->deadline, &grpc_status, &slice,
-                        nullptr);
+                        nullptr, nullptr);
 
   GPR_ASSERT(grpc_status >= 0 && (int)grpc_status < 100);
 
@@ -2594,7 +2592,7 @@
 static void start_bdp_ping_locked(grpc_exec_ctx* exec_ctx, void* tp,
                                   grpc_error* error) {
   grpc_chttp2_transport* t = (grpc_chttp2_transport*)tp;
-  if (GRPC_TRACER_ON(grpc_http_trace)) {
+  if (grpc_http_trace.enabled()) {
     gpr_log(GPR_DEBUG, "%s: Start BDP ping err=%s", t->peer_string,
             grpc_error_string(error));
   }
@@ -2608,7 +2606,7 @@
 static void finish_bdp_ping_locked(grpc_exec_ctx* exec_ctx, void* tp,
                                    grpc_error* error) {
   grpc_chttp2_transport* t = (grpc_chttp2_transport*)tp;
-  if (GRPC_TRACER_ON(grpc_http_trace)) {
+  if (grpc_http_trace.enabled()) {
     gpr_log(GPR_DEBUG, "%s: Complete BDP ping err=%s", t->peer_string,
             grpc_error_string(error));
   }
@@ -3109,7 +3107,7 @@
       grpc_chttp2_stream_map_size(&t->stream_map) == 0) {
     /* Channel with no active streams: send a goaway to try and make it
      * disconnect cleanly */
-    if (GRPC_TRACER_ON(grpc_resource_quota_trace)) {
+    if (grpc_resource_quota_trace.enabled()) {
       gpr_log(GPR_DEBUG, "HTTP2: %s - send goaway to free memory",
               t->peer_string);
     }
@@ -3117,8 +3115,7 @@
                 grpc_error_set_int(
                     GRPC_ERROR_CREATE_FROM_STATIC_STRING("Buffers full"),
                     GRPC_ERROR_INT_HTTP2_ERROR, GRPC_HTTP2_ENHANCE_YOUR_CALM));
-  } else if (error == GRPC_ERROR_NONE &&
-             GRPC_TRACER_ON(grpc_resource_quota_trace)) {
+  } else if (error == GRPC_ERROR_NONE && grpc_resource_quota_trace.enabled()) {
     gpr_log(GPR_DEBUG,
             "HTTP2: %s - skip benign reclamation, there are still %" PRIdPTR
             " streams",
@@ -3140,7 +3137,7 @@
   if (error == GRPC_ERROR_NONE && n > 0) {
     grpc_chttp2_stream* s =
         (grpc_chttp2_stream*)grpc_chttp2_stream_map_rand(&t->stream_map);
-    if (GRPC_TRACER_ON(grpc_resource_quota_trace)) {
+    if (grpc_resource_quota_trace.enabled()) {
       gpr_log(GPR_DEBUG, "HTTP2: %s - abandon stream id %d", t->peer_string,
               s->id);
     }
diff --git a/src/core/ext/transport/chttp2/transport/chttp2_transport.h b/src/core/ext/transport/chttp2/transport/chttp2_transport.h
index 972104f..369dc34 100644
--- a/src/core/ext/transport/chttp2/transport/chttp2_transport.h
+++ b/src/core/ext/transport/chttp2/transport/chttp2_transport.h
@@ -23,17 +23,9 @@
 #include "src/core/lib/iomgr/endpoint.h"
 #include "src/core/lib/transport/transport.h"
 
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-extern grpc_tracer_flag grpc_http_trace;
-extern grpc_tracer_flag grpc_flowctl_trace;
-extern grpc_tracer_flag grpc_trace_http2_stream_state;
-
-#ifndef NDEBUG
-extern grpc_tracer_flag grpc_trace_chttp2_refcount;
-#endif
+extern grpc_core::TraceFlag grpc_http_trace;
+extern grpc_core::TraceFlag grpc_trace_http2_stream_state;
+extern grpc_core::DebugOnlyTraceFlag grpc_trace_chttp2_refcount;
 
 grpc_transport* grpc_create_chttp2_transport(
     grpc_exec_ctx* exec_ctx, const grpc_channel_args* channel_args,
@@ -45,8 +37,4 @@
                                          grpc_transport* transport,
                                          grpc_slice_buffer* read_buffer);
 
-#ifdef __cplusplus
-}
-#endif
-
 #endif /* GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_CHTTP2_TRANSPORT_H */
diff --git a/src/core/ext/transport/chttp2/transport/flow_control.cc b/src/core/ext/transport/chttp2/transport/flow_control.cc
index 64f6b3c..8a057bd 100644
--- a/src/core/ext/transport/chttp2/transport/flow_control.cc
+++ b/src/core/ext/transport/chttp2/transport/flow_control.cc
@@ -31,6 +31,8 @@
 #include "src/core/ext/transport/chttp2/transport/internal.h"
 #include "src/core/lib/support/string.h"
 
+grpc_core::TraceFlag grpc_flowctl_trace(false, "flowctl");
+
 namespace grpc_core {
 namespace chttp2 {
 
@@ -312,7 +314,9 @@
   double bdp_error = value - pid_controller_.last_control_value();
   const double dt = (double)(now - last_pid_update_) * 1e-3;
   last_pid_update_ = now;
-  return pid_controller_.Update(bdp_error, dt);
+  // Limit dt to 100ms
+  const double kMaxDt = 0.1;
+  return pid_controller_.Update(bdp_error, dt > kMaxDt ? kMaxDt : dt);
 }
 
 FlowControlAction::Urgency TransportFlowControl::DeltaUrgency(
diff --git a/src/core/ext/transport/chttp2/transport/flow_control.h b/src/core/ext/transport/chttp2/transport/flow_control.h
index 7dd348e..2515c94 100644
--- a/src/core/ext/transport/chttp2/transport/flow_control.h
+++ b/src/core/ext/transport/chttp2/transport/flow_control.h
@@ -19,6 +19,7 @@
 #ifndef GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_FLOW_CONTROL_H
 #define GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_FLOW_CONTROL_H
 
+#include <grpc/support/port_platform.h>
 #include <stdint.h>
 
 #include <grpc/support/useful.h>
@@ -30,7 +31,7 @@
 struct grpc_chttp2_transport;
 struct grpc_chttp2_stream;
 
-extern "C" grpc_tracer_flag grpc_flowctl_trace;
+extern grpc_core::TraceFlag grpc_flowctl_trace;
 
 namespace grpc {
 namespace testing {
@@ -118,7 +119,7 @@
             StreamFlowControl* sfc);
   void Finish();
 
-  const bool enabled_ = GRPC_TRACER_ON(grpc_flowctl_trace);
+  const bool enabled_ = grpc_flowctl_trace.enabled();
 
   TransportFlowControl* tfc_;
   StreamFlowControl* sfc_;
diff --git a/src/core/ext/transport/chttp2/transport/frame.h b/src/core/ext/transport/chttp2/transport/frame.h
index e7debda..dba4c00 100644
--- a/src/core/ext/transport/chttp2/transport/frame.h
+++ b/src/core/ext/transport/chttp2/transport/frame.h
@@ -24,10 +24,6 @@
 
 #include "src/core/lib/iomgr/error.h"
 
-#ifdef __cplusplus
-extern "C" {
-#endif
-
 /* defined in internal.h */
 typedef struct grpc_chttp2_stream grpc_chttp2_stream;
 typedef struct grpc_chttp2_transport grpc_chttp2_transport;
@@ -47,8 +43,4 @@
 #define GRPC_CHTTP2_DATA_FLAG_PADDED 8
 #define GRPC_CHTTP2_FLAG_HAS_PRIORITY 0x20
 
-#ifdef __cplusplus
-}
-#endif
-
 #endif /* GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_FRAME_H */
diff --git a/src/core/ext/transport/chttp2/transport/frame_data.h b/src/core/ext/transport/chttp2/transport/frame_data.h
index 96f823a..4de553e 100644
--- a/src/core/ext/transport/chttp2/transport/frame_data.h
+++ b/src/core/ext/transport/chttp2/transport/frame_data.h
@@ -28,10 +28,6 @@
 #include "src/core/lib/transport/byte_stream.h"
 #include "src/core/lib/transport/transport.h"
 
-#ifdef __cplusplus
-extern "C" {
-#endif
-
 typedef enum {
   GRPC_CHTTP2_DATA_FH_0,
   GRPC_CHTTP2_DATA_FH_1,
@@ -84,8 +80,4 @@
     grpc_slice_buffer* slices, grpc_slice* slice_out,
     grpc_byte_stream** stream_out);
 
-#ifdef __cplusplus
-}
-#endif
-
 #endif /* GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_FRAME_DATA_H */
diff --git a/src/core/ext/transport/chttp2/transport/frame_goaway.h b/src/core/ext/transport/chttp2/transport/frame_goaway.h
index 9790d0b..743e763 100644
--- a/src/core/ext/transport/chttp2/transport/frame_goaway.h
+++ b/src/core/ext/transport/chttp2/transport/frame_goaway.h
@@ -25,10 +25,6 @@
 #include "src/core/ext/transport/chttp2/transport/frame.h"
 #include "src/core/lib/iomgr/exec_ctx.h"
 
-#ifdef __cplusplus
-extern "C" {
-#endif
-
 typedef enum {
   GRPC_CHTTP2_GOAWAY_LSI0,
   GRPC_CHTTP2_GOAWAY_LSI1,
@@ -64,8 +60,4 @@
                                grpc_slice debug_data,
                                grpc_slice_buffer* slice_buffer);
 
-#ifdef __cplusplus
-}
-#endif
-
 #endif /* GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_FRAME_GOAWAY_H */
diff --git a/src/core/ext/transport/chttp2/transport/frame_ping.h b/src/core/ext/transport/chttp2/transport/frame_ping.h
index 034aad0..76ca397 100644
--- a/src/core/ext/transport/chttp2/transport/frame_ping.h
+++ b/src/core/ext/transport/chttp2/transport/frame_ping.h
@@ -23,10 +23,6 @@
 #include "src/core/ext/transport/chttp2/transport/frame.h"
 #include "src/core/lib/iomgr/exec_ctx.h"
 
-#ifdef __cplusplus
-extern "C" {
-#endif
-
 typedef struct {
   uint8_t byte;
   uint8_t is_ack;
@@ -45,8 +41,4 @@
 /* Test-only function for disabling ping ack */
 void grpc_set_disable_ping_ack(bool disable_ping_ack);
 
-#ifdef __cplusplus
-}
-#endif
-
 #endif /* GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_FRAME_PING_H */
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 3f5417e..7dfc5d4 100644
--- a/src/core/ext/transport/chttp2/transport/frame_rst_stream.h
+++ b/src/core/ext/transport/chttp2/transport/frame_rst_stream.h
@@ -24,10 +24,6 @@
 #include "src/core/lib/iomgr/exec_ctx.h"
 #include "src/core/lib/transport/transport.h"
 
-#ifdef __cplusplus
-extern "C" {
-#endif
-
 typedef struct {
   uint8_t byte;
   uint8_t reason_bytes[4];
@@ -44,8 +40,4 @@
                                                 grpc_chttp2_stream* s,
                                                 grpc_slice slice, int is_last);
 
-#ifdef __cplusplus
-}
-#endif
-
 #endif /* GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_FRAME_RST_STREAM_H */
diff --git a/src/core/ext/transport/chttp2/transport/frame_settings.cc b/src/core/ext/transport/chttp2/transport/frame_settings.cc
index d33da72..75bb78d 100644
--- a/src/core/ext/transport/chttp2/transport/frame_settings.cc
+++ b/src/core/ext/transport/chttp2/transport/frame_settings.cc
@@ -204,20 +204,19 @@
               parser->incoming_settings[id] != parser->value) {
             t->initial_window_update +=
                 (int64_t)parser->value - parser->incoming_settings[id];
-            if (GRPC_TRACER_ON(grpc_http_trace) ||
-                GRPC_TRACER_ON(grpc_flowctl_trace)) {
+            if (grpc_http_trace.enabled() || grpc_flowctl_trace.enabled()) {
               gpr_log(GPR_DEBUG, "%p[%s] adding %d for initial_window change",
                       t, t->is_client ? "cli" : "svr",
                       (int)t->initial_window_update);
             }
           }
           parser->incoming_settings[id] = parser->value;
-          if (GRPC_TRACER_ON(grpc_http_trace)) {
+          if (grpc_http_trace.enabled()) {
             gpr_log(GPR_DEBUG, "CHTTP2:%s:%s: got setting %s = %d",
                     t->is_client ? "CLI" : "SVR", t->peer_string, sp->name,
                     parser->value);
           }
-        } else if (GRPC_TRACER_ON(grpc_http_trace)) {
+        } else if (grpc_http_trace.enabled()) {
           gpr_log(GPR_ERROR, "CHTTP2: Ignoring unknown setting %d (value %d)",
                   parser->id, parser->value);
         }
diff --git a/src/core/ext/transport/chttp2/transport/frame_settings.h b/src/core/ext/transport/chttp2/transport/frame_settings.h
index 18bde92..36e2ca8 100644
--- a/src/core/ext/transport/chttp2/transport/frame_settings.h
+++ b/src/core/ext/transport/chttp2/transport/frame_settings.h
@@ -25,10 +25,6 @@
 #include "src/core/ext/transport/chttp2/transport/http2_settings.h"
 #include "src/core/lib/iomgr/exec_ctx.h"
 
-#ifdef __cplusplus
-extern "C" {
-#endif
-
 typedef enum {
   GRPC_CHTTP2_SPS_ID0,
   GRPC_CHTTP2_SPS_ID1,
@@ -62,8 +58,4 @@
                                               grpc_chttp2_stream* s,
                                               grpc_slice slice, int is_last);
 
-#ifdef __cplusplus
-}
-#endif
-
 #endif /* GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_FRAME_SETTINGS_H */
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 daf7d2d..e031b58 100644
--- a/src/core/ext/transport/chttp2/transport/frame_window_update.h
+++ b/src/core/ext/transport/chttp2/transport/frame_window_update.h
@@ -24,10 +24,6 @@
 #include "src/core/lib/iomgr/exec_ctx.h"
 #include "src/core/lib/transport/transport.h"
 
-#ifdef __cplusplus
-extern "C" {
-#endif
-
 typedef struct {
   uint8_t byte;
   uint8_t is_connection_update;
@@ -43,8 +39,4 @@
     grpc_exec_ctx* exec_ctx, void* parser, grpc_chttp2_transport* t,
     grpc_chttp2_stream* s, grpc_slice slice, int is_last);
 
-#ifdef __cplusplus
-}
-#endif
-
 #endif /* GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_FRAME_WINDOW_UPDATE_H */
diff --git a/src/core/ext/transport/chttp2/transport/hpack_encoder.cc b/src/core/ext/transport/chttp2/transport/hpack_encoder.cc
index e6e4ff2..e76d92e 100644
--- a/src/core/ext/transport/chttp2/transport/hpack_encoder.cc
+++ b/src/core/ext/transport/chttp2/transport/hpack_encoder.cc
@@ -57,8 +57,6 @@
     {{nullptr, 0}}            /* data.refcounted */
 };
 
-extern "C" grpc_tracer_flag grpc_http_trace;
-
 typedef struct {
   int is_first_frame;
   /* number of bytes in 'output' when we started the frame - used to calculate
@@ -475,7 +473,7 @@
         "Reserved header (colon-prefixed) happening after regular ones.");
   }
 
-  if (GRPC_TRACER_ON(grpc_http_trace)) {
+  if (grpc_http_trace.enabled()) {
     char* k = grpc_slice_to_c_string(GRPC_MDKEY(elem));
     char* v = nullptr;
     if (grpc_is_binary_header(GRPC_MDKEY(elem))) {
@@ -669,7 +667,7 @@
     }
   }
   c->advertise_table_size_change = 1;
-  if (GRPC_TRACER_ON(grpc_http_trace)) {
+  if (grpc_http_trace.enabled()) {
     gpr_log(GPR_DEBUG, "set max table size from encoder to %d", max_table_size);
   }
 }
diff --git a/src/core/ext/transport/chttp2/transport/hpack_encoder.h b/src/core/ext/transport/chttp2/transport/hpack_encoder.h
index fd01d16..08921b1 100644
--- a/src/core/ext/transport/chttp2/transport/hpack_encoder.h
+++ b/src/core/ext/transport/chttp2/transport/hpack_encoder.h
@@ -34,9 +34,7 @@
 /* maximum table size we'll actually use */
 #define GRPC_CHTTP2_HPACKC_MAX_TABLE_SIZE (1024 * 1024)
 
-#ifdef __cplusplus
-extern "C" {
-#endif
+extern grpc_core::TraceFlag grpc_http_trace;
 
 typedef struct {
   uint32_t filter_elems_sum;
@@ -95,8 +93,4 @@
                                const grpc_encode_header_options* options,
                                grpc_slice_buffer* outbuf);
 
-#ifdef __cplusplus
-}
-#endif
-
 #endif /* GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_HPACK_ENCODER_H */
diff --git a/src/core/ext/transport/chttp2/transport/hpack_parser.cc b/src/core/ext/transport/chttp2/transport/hpack_parser.cc
index 960610e..18cb27f 100644
--- a/src/core/ext/transport/chttp2/transport/hpack_parser.cc
+++ b/src/core/ext/transport/chttp2/transport/hpack_parser.cc
@@ -651,7 +651,7 @@
 /* emission helpers */
 static grpc_error* on_hdr(grpc_exec_ctx* exec_ctx, grpc_chttp2_hpack_parser* p,
                           grpc_mdelem md, int add_to_table) {
-  if (GRPC_TRACER_ON(grpc_http_trace)) {
+  if (grpc_http_trace.enabled()) {
     char* k = grpc_slice_to_c_string(GRPC_MDKEY(md));
     char* v = nullptr;
     if (grpc_is_binary_header(GRPC_MDKEY(md))) {
@@ -1047,7 +1047,7 @@
 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_TRACER_ON(grpc_http_trace)) {
+  if (grpc_http_trace.enabled()) {
     gpr_log(GPR_INFO, "MAX TABLE SIZE: %d", p->index);
   }
   grpc_error* err =
diff --git a/src/core/ext/transport/chttp2/transport/hpack_parser.h b/src/core/ext/transport/chttp2/transport/hpack_parser.h
index 838c482..b4a2b14 100644
--- a/src/core/ext/transport/chttp2/transport/hpack_parser.h
+++ b/src/core/ext/transport/chttp2/transport/hpack_parser.h
@@ -27,10 +27,6 @@
 #include "src/core/lib/iomgr/exec_ctx.h"
 #include "src/core/lib/transport/metadata.h"
 
-#ifdef __cplusplus
-extern "C" {
-#endif
-
 typedef struct grpc_chttp2_hpack_parser grpc_chttp2_hpack_parser;
 
 typedef grpc_error* (*grpc_chttp2_hpack_parser_state)(
@@ -115,8 +111,4 @@
                                             grpc_chttp2_stream* s,
                                             grpc_slice slice, int is_last);
 
-#ifdef __cplusplus
-}
-#endif
-
 #endif /* GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_HPACK_PARSER_H */
diff --git a/src/core/ext/transport/chttp2/transport/hpack_table.cc b/src/core/ext/transport/chttp2/transport/hpack_table.cc
index 7970d2a..75b83b8 100644
--- a/src/core/ext/transport/chttp2/transport/hpack_table.cc
+++ b/src/core/ext/transport/chttp2/transport/hpack_table.cc
@@ -28,7 +28,7 @@
 #include "src/core/lib/debug/trace.h"
 #include "src/core/lib/support/murmur_hash.h"
 
-extern "C" grpc_tracer_flag grpc_http_trace;
+extern grpc_core::TraceFlag grpc_http_trace;
 
 static struct {
   const char* key;
@@ -246,7 +246,7 @@
   if (tbl->max_bytes == max_bytes) {
     return;
   }
-  if (GRPC_TRACER_ON(grpc_http_trace)) {
+  if (grpc_http_trace.enabled()) {
     gpr_log(GPR_DEBUG, "Update hpack parser max size to %d", max_bytes);
   }
   while (tbl->mem_used > max_bytes) {
@@ -270,7 +270,7 @@
     gpr_free(msg);
     return err;
   }
-  if (GRPC_TRACER_ON(grpc_http_trace)) {
+  if (grpc_http_trace.enabled()) {
     gpr_log(GPR_DEBUG, "Update hpack parser table size to %d", bytes);
   }
   while (tbl->mem_used > bytes) {
diff --git a/src/core/ext/transport/chttp2/transport/hpack_table.h b/src/core/ext/transport/chttp2/transport/hpack_table.h
index ddc8888..aed7b13 100644
--- a/src/core/ext/transport/chttp2/transport/hpack_table.h
+++ b/src/core/ext/transport/chttp2/transport/hpack_table.h
@@ -24,10 +24,6 @@
 #include "src/core/lib/iomgr/error.h"
 #include "src/core/lib/transport/metadata.h"
 
-#ifdef __cplusplus
-extern "C" {
-#endif
-
 /* HPACK header table */
 
 /* last index in the static table */
@@ -98,8 +94,4 @@
 grpc_chttp2_hptbl_find_result grpc_chttp2_hptbl_find(
     const grpc_chttp2_hptbl* tbl, grpc_mdelem md);
 
-#ifdef __cplusplus
-}
-#endif
-
 #endif /* GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_HPACK_TABLE_H */
diff --git a/src/core/ext/transport/chttp2/transport/http2_settings.h b/src/core/ext/transport/chttp2/transport/http2_settings.h
index 86069b4..fd15b69 100644
--- a/src/core/ext/transport/chttp2/transport/http2_settings.h
+++ b/src/core/ext/transport/chttp2/transport/http2_settings.h
@@ -36,9 +36,6 @@
 
 #define GRPC_CHTTP2_NUM_SETTINGS 7
 
-#ifdef __cplusplus
-extern "C" {
-#endif
 extern const uint16_t grpc_setting_id_to_wire_id[];
 
 bool grpc_wire_id_to_setting_id(uint32_t wire_id, grpc_chttp2_setting_id* out);
@@ -60,8 +57,4 @@
 extern const grpc_chttp2_setting_parameters
     grpc_chttp2_settings_parameters[GRPC_CHTTP2_NUM_SETTINGS];
 
-#ifdef __cplusplus
-}
-#endif
-
 #endif /* GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_HTTP2_SETTINGS_H */
diff --git a/src/core/ext/transport/chttp2/transport/huffsyms.h b/src/core/ext/transport/chttp2/transport/huffsyms.h
index 4002706..2e2a5da 100644
--- a/src/core/ext/transport/chttp2/transport/huffsyms.h
+++ b/src/core/ext/transport/chttp2/transport/huffsyms.h
@@ -19,10 +19,6 @@
 #ifndef GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_HUFFSYMS_H
 #define GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_HUFFSYMS_H
 
-#ifdef __cplusplus
-extern "C" {
-#endif
-
 /* HPACK static huffman table */
 
 #define GRPC_CHTTP2_NUM_HUFFSYMS 257
@@ -34,8 +30,4 @@
 
 extern const grpc_chttp2_huffsym grpc_chttp2_huffsyms[GRPC_CHTTP2_NUM_HUFFSYMS];
 
-#ifdef __cplusplus
-}
-#endif
-
 #endif /* GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_HUFFSYMS_H */
diff --git a/src/core/ext/transport/chttp2/transport/incoming_metadata.h b/src/core/ext/transport/chttp2/transport/incoming_metadata.h
index 7ccb4a0..6f2b81e 100644
--- a/src/core/ext/transport/chttp2/transport/incoming_metadata.h
+++ b/src/core/ext/transport/chttp2/transport/incoming_metadata.h
@@ -21,10 +21,6 @@
 
 #include "src/core/lib/transport/transport.h"
 
-#ifdef __cplusplus
-extern "C" {
-#endif
-
 typedef struct {
   gpr_arena* arena;
   grpc_metadata_batch batch;
@@ -49,8 +45,4 @@
 void grpc_chttp2_incoming_metadata_buffer_set_deadline(
     grpc_chttp2_incoming_metadata_buffer* buffer, grpc_millis deadline);
 
-#ifdef __cplusplus
-}
-#endif
-
 #endif /* GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_INCOMING_METADATA_H */
diff --git a/src/core/ext/transport/chttp2/transport/internal.h b/src/core/ext/transport/chttp2/transport/internal.h
index 60cc280..9404213 100644
--- a/src/core/ext/transport/chttp2/transport/internal.h
+++ b/src/core/ext/transport/chttp2/transport/internal.h
@@ -42,10 +42,6 @@
 #include "src/core/lib/transport/connectivity_state.h"
 #include "src/core/lib/transport/transport_impl.h"
 
-#ifdef __cplusplus
-extern "C" {
-#endif
-
 /* streams are kept in various linked lists depending on what things need to
    happen to them... this enum labels each list */
 typedef enum {
@@ -674,13 +670,13 @@
 #define GRPC_CHTTP2_CLIENT_CONNECT_STRLEN \
   (sizeof(GRPC_CHTTP2_CLIENT_CONNECT_STRING) - 1)
 
-extern grpc_tracer_flag grpc_http_trace;
-extern grpc_tracer_flag grpc_flowctl_trace;
+// extern grpc_core::TraceFlag grpc_http_trace;
+// extern grpc_core::TraceFlag grpc_flowctl_trace;
 
-#define GRPC_CHTTP2_IF_TRACING(stmt)      \
-  if (!(GRPC_TRACER_ON(grpc_http_trace))) \
-    ;                                     \
-  else                                    \
+#define GRPC_CHTTP2_IF_TRACING(stmt) \
+  if (!(grpc_http_trace.enabled()))  \
+    ;                                \
+  else                               \
     stmt
 
 void grpc_chttp2_fake_status(grpc_exec_ctx* exec_ctx, grpc_chttp2_transport* t,
@@ -778,8 +774,4 @@
 void grpc_chttp2_config_default_keepalive_args(grpc_channel_args* args,
                                                bool is_client);
 
-#ifdef __cplusplus
-}
-#endif
-
 #endif /* GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_INTERNAL_H */
diff --git a/src/core/ext/transport/chttp2/transport/parsing.cc b/src/core/ext/transport/chttp2/transport/parsing.cc
index 5f07dec..46ec3fb 100644
--- a/src/core/ext/transport/chttp2/transport/parsing.cc
+++ b/src/core/ext/transport/chttp2/transport/parsing.cc
@@ -312,7 +312,7 @@
     case GRPC_CHTTP2_FRAME_GOAWAY:
       return init_goaway_parser(exec_ctx, t);
     default:
-      if (GRPC_TRACER_ON(grpc_http_trace)) {
+      if (grpc_http_trace.enabled()) {
         gpr_log(GPR_ERROR, "Unknown frame type %02x", t->incoming_frame_type);
       }
       return init_skip_frame_parser(exec_ctx, t, 0);
@@ -417,7 +417,7 @@
 
   GPR_ASSERT(s != nullptr);
 
-  if (GRPC_TRACER_ON(grpc_http_trace)) {
+  if (grpc_http_trace.enabled()) {
     char* key = grpc_slice_to_c_string(GRPC_MDKEY(md));
     char* value =
         grpc_dump_slice(GRPC_MDVALUE(md), GPR_DUMP_HEX | GPR_DUMP_ASCII);
@@ -501,7 +501,7 @@
 
   GPR_ASSERT(s != nullptr);
 
-  if (GRPC_TRACER_ON(grpc_http_trace)) {
+  if (grpc_http_trace.enabled()) {
     char* key = grpc_slice_to_c_string(GRPC_MDKEY(md));
     char* value =
         grpc_dump_slice(GRPC_MDVALUE(md), GPR_DUMP_HEX | GPR_DUMP_ASCII);
@@ -758,7 +758,7 @@
   if (err == GRPC_ERROR_NONE) {
     return err;
   } else if (grpc_error_get_int(err, GRPC_ERROR_INT_STREAM_ID, nullptr)) {
-    if (GRPC_TRACER_ON(grpc_http_trace)) {
+    if (grpc_http_trace.enabled()) {
       const char* msg = grpc_error_string(err);
       gpr_log(GPR_ERROR, "%s", msg);
     }
diff --git a/src/core/ext/transport/chttp2/transport/stream_lists.cc b/src/core/ext/transport/chttp2/transport/stream_lists.cc
index d92527f..c95d025 100644
--- a/src/core/ext/transport/chttp2/transport/stream_lists.cc
+++ b/src/core/ext/transport/chttp2/transport/stream_lists.cc
@@ -39,8 +39,7 @@
   GPR_UNREACHABLE_CODE(return "unknown");
 }
 
-grpc_tracer_flag grpc_trace_http2_stream_state =
-    GRPC_TRACER_INITIALIZER(false, "http2_stream_state");
+grpc_core::TraceFlag grpc_trace_http2_stream_state(false, "http2_stream_state");
 
 /* core list management */
 
@@ -66,7 +65,7 @@
     s->included[id] = 0;
   }
   *stream = s;
-  if (s && GRPC_TRACER_ON(grpc_trace_http2_stream_state)) {
+  if (s && grpc_trace_http2_stream_state.enabled()) {
     gpr_log(GPR_DEBUG, "%p[%d][%s]: pop from %s", t, s->id,
             t->is_client ? "cli" : "svr", stream_list_id_string(id));
   }
@@ -88,7 +87,7 @@
   } else {
     t->lists[id].tail = s->links[id].prev;
   }
-  if (GRPC_TRACER_ON(grpc_trace_http2_stream_state)) {
+  if (grpc_trace_http2_stream_state.enabled()) {
     gpr_log(GPR_DEBUG, "%p[%d][%s]: remove from %s", t, s->id,
             t->is_client ? "cli" : "svr", stream_list_id_string(id));
   }
@@ -120,7 +119,7 @@
   }
   t->lists[id].tail = s;
   s->included[id] = 1;
-  if (GRPC_TRACER_ON(grpc_trace_http2_stream_state)) {
+  if (grpc_trace_http2_stream_state.enabled()) {
     gpr_log(GPR_DEBUG, "%p[%d][%s]: add to %s", t, s->id,
             t->is_client ? "cli" : "svr", stream_list_id_string(id));
   }
diff --git a/src/core/ext/transport/chttp2/transport/stream_map.h b/src/core/ext/transport/chttp2/transport/stream_map.h
index c89d200..9fb8826 100644
--- a/src/core/ext/transport/chttp2/transport/stream_map.h
+++ b/src/core/ext/transport/chttp2/transport/stream_map.h
@@ -23,10 +23,6 @@
 
 #include <stddef.h>
 
-#ifdef __cplusplus
-extern "C" {
-#endif
-
 /* Data structure to map a uint32_t to a data object (represented by a void*)
 
    Represented as a sorted array of keys, and a corresponding array of values.
@@ -69,8 +65,4 @@
                                                void* value),
                                      void* user_data);
 
-#ifdef __cplusplus
-}
-#endif
-
 #endif /* GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_STREAM_MAP_H */
diff --git a/src/core/ext/transport/chttp2/transport/varint.h b/src/core/ext/transport/chttp2/transport/varint.h
index d3a9d90..5a2b670 100644
--- a/src/core/ext/transport/chttp2/transport/varint.h
+++ b/src/core/ext/transport/chttp2/transport/varint.h
@@ -21,10 +21,6 @@
 
 #include <grpc/support/port_platform.h>
 
-#ifdef __cplusplus
-extern "C" {
-#endif
-
 /* Helpers for hpack varint encoding */
 
 /* length of a value that needs varint tail encoding (it's bigger than can be
@@ -61,8 +57,4 @@
     }                                                                         \
   } while (0)
 
-#ifdef __cplusplus
-}
-#endif
-
 #endif /* GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_VARINT_H */
diff --git a/src/core/ext/transport/chttp2/transport/writing.cc b/src/core/ext/transport/chttp2/transport/writing.cc
index 61a2598..204b5a7 100644
--- a/src/core/ext/transport/chttp2/transport/writing.cc
+++ b/src/core/ext/transport/chttp2/transport/writing.cc
@@ -51,8 +51,7 @@
   }
   if (!grpc_closure_list_empty(pq->lists[GRPC_CHTTP2_PCL_INFLIGHT])) {
     /* ping already in-flight: wait */
-    if (GRPC_TRACER_ON(grpc_http_trace) ||
-        GRPC_TRACER_ON(grpc_bdp_estimator_trace)) {
+    if (grpc_http_trace.enabled() || grpc_bdp_estimator_trace.enabled()) {
       gpr_log(GPR_DEBUG, "%s: Ping delayed [%p]: already pinging",
               t->is_client ? "CLIENT" : "SERVER", t->peer_string);
     }
@@ -61,8 +60,7 @@
   if (t->ping_state.pings_before_data_required == 0 &&
       t->ping_policy.max_pings_without_data != 0) {
     /* need to receive something of substance before sending a ping again */
-    if (GRPC_TRACER_ON(grpc_http_trace) ||
-        GRPC_TRACER_ON(grpc_bdp_estimator_trace)) {
+    if (grpc_http_trace.enabled() || grpc_bdp_estimator_trace.enabled()) {
       gpr_log(GPR_DEBUG, "%s: Ping delayed [%p]: too many recent pings: %d/%d",
               t->is_client ? "CLIENT" : "SERVER", t->peer_string,
               t->ping_state.pings_before_data_required,
@@ -81,11 +79,13 @@
   }
   if (next_allowed_ping > now) {
     /* not enough elapsed time between successive pings */
-    if (GRPC_TRACER_ON(grpc_http_trace) ||
-        GRPC_TRACER_ON(grpc_bdp_estimator_trace)) {
+    if (grpc_http_trace.enabled() || grpc_bdp_estimator_trace.enabled()) {
       gpr_log(GPR_DEBUG,
-              "%s: Ping delayed [%p]: not enough time elapsed since last ping",
-              t->is_client ? "CLIENT" : "SERVER", t->peer_string);
+              "%s: Ping delayed [%p]: not enough time elapsed since last ping. "
+              " Last ping %f: Next ping %f: Now %f",
+              t->is_client ? "CLIENT" : "SERVER", t->peer_string,
+              (double)t->ping_state.last_ping_sent_time,
+              (double)next_allowed_ping, (double)now);
     }
     if (!t->ping_state.is_delayed_ping_timer_set) {
       t->ping_state.is_delayed_ping_timer_set = true;
@@ -94,6 +94,7 @@
     }
     return;
   }
+
   pq->inflight_id = t->ping_ctr;
   t->ping_ctr++;
   GRPC_CLOSURE_LIST_SCHED(exec_ctx, &pq->lists[GRPC_CHTTP2_PCL_INITIATE]);
@@ -103,8 +104,7 @@
                         grpc_chttp2_ping_create(false, pq->inflight_id));
   GRPC_STATS_INC_HTTP2_PINGS_SENT(exec_ctx);
   t->ping_state.last_ping_sent_time = now;
-  if (GRPC_TRACER_ON(grpc_http_trace) ||
-      GRPC_TRACER_ON(grpc_bdp_estimator_trace)) {
+  if (grpc_http_trace.enabled() || grpc_bdp_estimator_trace.enabled()) {
     gpr_log(GPR_DEBUG, "%s: Ping sent [%p]: %d/%d",
             t->is_client ? "CLIENT" : "SERVER", t->peer_string,
             t->ping_state.pings_before_data_required,
@@ -322,7 +322,7 @@
         GPR_MIN(stream_remote_window(), t_->flow_control->remote_window()));
   }
 
-  bool AnyOutgoing() const { return max_outgoing() != 0; }
+  bool AnyOutgoing() const { return max_outgoing() > 0; }
 
   void FlushCompressedBytes() {
     uint32_t send_bytes =
diff --git a/src/core/ext/transport/cronet/transport/cronet_transport.h b/src/core/ext/transport/cronet/transport/cronet_transport.h
index 7643fdb..d9ff913 100644
--- a/src/core/ext/transport/cronet/transport/cronet_transport.h
+++ b/src/core/ext/transport/cronet/transport/cronet_transport.h
@@ -21,16 +21,8 @@
 
 #include "src/core/lib/transport/transport.h"
 
-#ifdef __cplusplus
-extern "C" {
-#endif
-
 grpc_transport* grpc_create_cronet_transport(void* engine, const char* target,
                                              const grpc_channel_args* args,
                                              void* reserved);
 
-#ifdef __cplusplus
-}
-#endif
-
 #endif /* GRPC_CORE_EXT_TRANSPORT_CRONET_TRANSPORT_CRONET_TRANSPORT_H */
diff --git a/src/core/ext/transport/inproc/inproc_plugin.cc b/src/core/ext/transport/inproc/inproc_plugin.cc
index 5d8a1c7..83a7d8d 100644
--- a/src/core/ext/transport/inproc/inproc_plugin.cc
+++ b/src/core/ext/transport/inproc/inproc_plugin.cc
@@ -19,13 +19,8 @@
 #include "src/core/ext/transport/inproc/inproc_transport.h"
 #include "src/core/lib/debug/trace.h"
 
-grpc_tracer_flag grpc_inproc_trace = GRPC_TRACER_INITIALIZER(false, "inproc");
+grpc_core::TraceFlag grpc_inproc_trace(false, "inproc");
 
-extern "C" void grpc_inproc_plugin_init(void) {
-  grpc_register_tracer(&grpc_inproc_trace);
-  grpc_inproc_transport_init();
-}
+void grpc_inproc_plugin_init(void) { grpc_inproc_transport_init(); }
 
-extern "C" void grpc_inproc_plugin_shutdown(void) {
-  grpc_inproc_transport_shutdown();
-}
+void grpc_inproc_plugin_shutdown(void) { grpc_inproc_transport_shutdown(); }
diff --git a/src/core/ext/transport/inproc/inproc_transport.cc b/src/core/ext/transport/inproc/inproc_transport.cc
index 7ea08b0..2579060 100644
--- a/src/core/ext/transport/inproc/inproc_transport.cc
+++ b/src/core/ext/transport/inproc/inproc_transport.cc
@@ -32,9 +32,9 @@
 #include "src/core/lib/transport/error_utils.h"
 #include "src/core/lib/transport/transport_impl.h"
 
-#define INPROC_LOG(...)                                          \
-  do {                                                           \
-    if (GRPC_TRACER_ON(grpc_inproc_trace)) gpr_log(__VA_ARGS__); \
+#define INPROC_LOG(...)                                    \
+  do {                                                     \
+    if (grpc_inproc_trace.enabled()) gpr_log(__VA_ARGS__); \
   } while (0)
 
 static grpc_slice g_empty_slice;
@@ -199,7 +199,7 @@
                                     const grpc_metadata_batch* metadata,
                                     uint32_t flags, grpc_metadata_batch* out_md,
                                     uint32_t* outflags, bool* markfilled) {
-  if (GRPC_TRACER_ON(grpc_inproc_trace)) {
+  if (grpc_inproc_trace.enabled()) {
     log_metadata(metadata, s->t->is_client, outflags != nullptr);
   }
 
@@ -873,7 +873,7 @@
   gpr_mu* mu = &s->t->mu->mu;  // save aside in case s gets closed
   gpr_mu_lock(mu);
 
-  if (GRPC_TRACER_ON(grpc_inproc_trace)) {
+  if (grpc_inproc_trace.enabled()) {
     if (op->send_initial_metadata) {
       log_metadata(op->payload->send_initial_metadata.send_initial_metadata,
                    s->t->is_client, true);
diff --git a/src/core/ext/transport/inproc/inproc_transport.h b/src/core/ext/transport/inproc/inproc_transport.h
index 6e83af3..7c0453e 100644
--- a/src/core/ext/transport/inproc/inproc_transport.h
+++ b/src/core/ext/transport/inproc/inproc_transport.h
@@ -21,21 +21,13 @@
 
 #include "src/core/lib/transport/transport_impl.h"
 
-#ifdef __cplusplus
-extern "C" {
-#endif
-
 grpc_channel* grpc_inproc_channel_create(grpc_server* server,
                                          grpc_channel_args* args,
                                          void* reserved);
 
-extern grpc_tracer_flag grpc_inproc_trace;
+extern grpc_core::TraceFlag grpc_inproc_trace;
 
 void grpc_inproc_transport_init(void);
 void grpc_inproc_transport_shutdown(void);
 
-#ifdef __cplusplus
-}
-#endif
-
 #endif /* GRPC_CORE_EXT_TRANSPORT_INPROC_INPROC_TRANSPORT_H */
diff --git a/src/core/lib/backoff/backoff.h b/src/core/lib/backoff/backoff.h
index 1067281..0da9082 100644
--- a/src/core/lib/backoff/backoff.h
+++ b/src/core/lib/backoff/backoff.h
@@ -21,10 +21,6 @@
 
 #include "src/core/lib/iomgr/exec_ctx.h"
 
-#ifdef __cplusplus
-extern "C" {
-#endif
-
 typedef struct {
   /// const:  how long to wait after the first failure before retrying
   grpc_millis initial_backoff;
@@ -76,8 +72,4 @@
 /// grpc_backoff_begin.
 void grpc_backoff_reset(grpc_backoff* backoff);
 
-#ifdef __cplusplus
-}
-#endif
-
 #endif /* GRPC_CORE_LIB_BACKOFF_BACKOFF_H */
diff --git a/src/core/lib/channel/channel_args.h b/src/core/lib/channel/channel_args.h
index d36761d..f6cb7fa 100644
--- a/src/core/lib/channel/channel_args.h
+++ b/src/core/lib/channel/channel_args.h
@@ -23,10 +23,6 @@
 #include <grpc/grpc.h>
 #include "src/core/lib/iomgr/socket_mutator.h"
 
-#ifdef __cplusplus
-extern "C" {
-#endif
-
 // Channel args are intentionally immutable, to avoid the need for locking.
 
 /** Copy the arguments in \a src into a new instance */
@@ -153,8 +149,4 @@
 grpc_arg grpc_channel_arg_pointer_create(char* name, void* value,
                                          const grpc_arg_pointer_vtable* vtable);
 
-#ifdef __cplusplus
-}
-#endif
-
 #endif /* GRPC_CORE_LIB_CHANNEL_CHANNEL_ARGS_H */
diff --git a/src/core/lib/channel/channel_stack.cc b/src/core/lib/channel/channel_stack.cc
index 6e50809..7629d18 100644
--- a/src/core/lib/channel/channel_stack.cc
+++ b/src/core/lib/channel/channel_stack.cc
@@ -23,7 +23,7 @@
 #include <stdlib.h>
 #include <string.h>
 
-grpc_tracer_flag grpc_trace_channel = GRPC_TRACER_INITIALIZER(false, "channel");
+grpc_core::TraceFlag grpc_trace_channel(false, "channel");
 
 /* Memory layouts.
 
diff --git a/src/core/lib/channel/channel_stack.h b/src/core/lib/channel/channel_stack.h
index aa99311..1b6e539 100644
--- a/src/core/lib/channel/channel_stack.h
+++ b/src/core/lib/channel/channel_stack.h
@@ -45,10 +45,6 @@
 #include "src/core/lib/support/arena.h"
 #include "src/core/lib/transport/transport.h"
 
-#ifdef __cplusplus
-extern "C" {
-#endif
-
 typedef struct grpc_channel_element grpc_channel_element;
 typedef struct grpc_call_element grpc_call_element;
 
@@ -84,6 +80,7 @@
 typedef struct {
   grpc_call_stats stats;
   grpc_status_code final_status;
+  const char** error_string;
 } grpc_call_final_info;
 
 /* Channel filters specify:
@@ -285,13 +282,9 @@
                       grpc_call_element* elem,
                       grpc_transport_stream_op_batch* op);
 
-extern grpc_tracer_flag grpc_trace_channel;
+extern grpc_core::TraceFlag grpc_trace_channel;
 
 #define GRPC_CALL_LOG_OP(sev, elem, op) \
-  if (GRPC_TRACER_ON(grpc_trace_channel)) grpc_call_log_op(sev, elem, op)
-
-#ifdef __cplusplus
-}
-#endif
+  if (grpc_trace_channel.enabled()) grpc_call_log_op(sev, elem, op)
 
 #endif /* GRPC_CORE_LIB_CHANNEL_CHANNEL_STACK_H */
diff --git a/src/core/lib/channel/channel_stack_builder.cc b/src/core/lib/channel/channel_stack_builder.cc
index 1e553bf..77b7854 100644
--- a/src/core/lib/channel/channel_stack_builder.cc
+++ b/src/core/lib/channel/channel_stack_builder.cc
@@ -23,8 +23,8 @@
 #include <grpc/support/alloc.h>
 #include <grpc/support/string_util.h>
 
-grpc_tracer_flag grpc_trace_channel_stack_builder =
-    GRPC_TRACER_INITIALIZER(false, "channel_stack_builder");
+grpc_core::TraceFlag grpc_trace_channel_stack_builder(false,
+                                                      "channel_stack_builder");
 
 typedef struct filter_node {
   struct filter_node* next;
diff --git a/src/core/lib/channel/channel_stack_builder.h b/src/core/lib/channel/channel_stack_builder.h
index 23134b7..1001954 100644
--- a/src/core/lib/channel/channel_stack_builder.h
+++ b/src/core/lib/channel/channel_stack_builder.h
@@ -24,10 +24,6 @@
 #include "src/core/lib/channel/channel_args.h"
 #include "src/core/lib/channel/channel_stack.h"
 
-#ifdef __cplusplus
-extern "C" {
-#endif
-
 /// grpc_channel_stack_builder offers a programmatic interface to selected
 /// and order channel filters
 typedef struct grpc_channel_stack_builder grpc_channel_stack_builder;
@@ -160,10 +156,6 @@
 void grpc_channel_stack_builder_destroy(grpc_exec_ctx* exec_ctx,
                                         grpc_channel_stack_builder* builder);
 
-extern grpc_tracer_flag grpc_trace_channel_stack_builder;
-
-#ifdef __cplusplus
-}
-#endif
+extern grpc_core::TraceFlag grpc_trace_channel_stack_builder;
 
 #endif /* GRPC_CORE_LIB_CHANNEL_CHANNEL_STACK_BUILDER_H */
diff --git a/src/core/lib/channel/connected_channel.h b/src/core/lib/channel/connected_channel.h
index cca1973..cab8aad 100644
--- a/src/core/lib/channel/connected_channel.h
+++ b/src/core/lib/channel/connected_channel.h
@@ -21,10 +21,6 @@
 
 #include "src/core/lib/channel/channel_stack_builder.h"
 
-#ifdef __cplusplus
-extern "C" {
-#endif
-
 extern const grpc_channel_filter grpc_connected_filter;
 
 bool grpc_add_connected_filter(grpc_exec_ctx* exec_ctx,
@@ -34,8 +30,4 @@
 /* Debug helper to dig the transport stream out of a call element */
 grpc_stream* grpc_connected_channel_get_stream(grpc_call_element* elem);
 
-#ifdef __cplusplus
-}
-#endif
-
 #endif /* GRPC_CORE_LIB_CHANNEL_CONNECTED_CHANNEL_H */
diff --git a/src/core/lib/channel/handshaker.h b/src/core/lib/channel/handshaker.h
index 8ed38c1..09b4a27 100644
--- a/src/core/lib/channel/handshaker.h
+++ b/src/core/lib/channel/handshaker.h
@@ -26,10 +26,6 @@
 #include "src/core/lib/iomgr/exec_ctx.h"
 #include "src/core/lib/iomgr/tcp_server.h"
 
-#ifdef __cplusplus
-extern "C" {
-#endif
-
 /// Handshakers are used to perform initial handshakes on a connection
 /// before the client sends the initial request.  Some examples of what
 /// a handshaker can be used for includes support for HTTP CONNECT on
@@ -168,8 +164,4 @@
 void grpc_handshake_manager_pending_list_shutdown_all(
     grpc_exec_ctx* exec_ctx, grpc_handshake_manager* head, grpc_error* why);
 
-#ifdef __cplusplus
-}
-#endif
-
 #endif /* GRPC_CORE_LIB_CHANNEL_HANDSHAKER_H */
diff --git a/src/core/lib/channel/handshaker_factory.h b/src/core/lib/channel/handshaker_factory.h
index 63d9b5a..ca7c26b 100644
--- a/src/core/lib/channel/handshaker_factory.h
+++ b/src/core/lib/channel/handshaker_factory.h
@@ -24,10 +24,6 @@
 #include "src/core/lib/channel/handshaker.h"
 #include "src/core/lib/iomgr/exec_ctx.h"
 
-#ifdef __cplusplus
-extern "C" {
-#endif
-
 // A handshaker factory is used to create handshakers.
 
 typedef struct grpc_handshaker_factory grpc_handshaker_factory;
@@ -52,8 +48,4 @@
 void grpc_handshaker_factory_destroy(
     grpc_exec_ctx* exec_ctx, grpc_handshaker_factory* handshaker_factory);
 
-#ifdef __cplusplus
-}
-#endif
-
 #endif /* GRPC_CORE_LIB_CHANNEL_HANDSHAKER_FACTORY_H */
diff --git a/src/core/lib/channel/handshaker_registry.h b/src/core/lib/channel/handshaker_registry.h
index ddd280b..a3b2ac1 100644
--- a/src/core/lib/channel/handshaker_registry.h
+++ b/src/core/lib/channel/handshaker_registry.h
@@ -24,10 +24,6 @@
 #include "src/core/lib/channel/handshaker_factory.h"
 #include "src/core/lib/iomgr/exec_ctx.h"
 
-#ifdef __cplusplus
-extern "C" {
-#endif
-
 typedef enum {
   HANDSHAKER_CLIENT = 0,
   HANDSHAKER_SERVER,
@@ -49,8 +45,4 @@
                           const grpc_channel_args* args,
                           grpc_handshake_manager* handshake_mgr);
 
-#ifdef __cplusplus
-}
-#endif
-
 #endif /* GRPC_CORE_LIB_CHANNEL_HANDSHAKER_REGISTRY_H */
diff --git a/src/core/lib/compression/algorithm_metadata.h b/src/core/lib/compression/algorithm_metadata.h
index 17caf58..08feafc 100644
--- a/src/core/lib/compression/algorithm_metadata.h
+++ b/src/core/lib/compression/algorithm_metadata.h
@@ -22,10 +22,6 @@
 #include <grpc/compression.h>
 #include "src/core/lib/transport/metadata.h"
 
-#ifdef __cplusplus
-extern "C" {
-#endif
-
 /** Return compression algorithm based metadata value */
 grpc_slice grpc_compression_algorithm_slice(
     grpc_compression_algorithm algorithm);
@@ -53,8 +49,4 @@
 grpc_stream_compression_algorithm grpc_stream_compression_algorithm_from_slice(
     grpc_slice str);
 
-#ifdef __cplusplus
-}
-#endif
-
 #endif /* GRPC_CORE_LIB_COMPRESSION_ALGORITHM_METADATA_H */
diff --git a/src/core/lib/compression/message_compress.h b/src/core/lib/compression/message_compress.h
index fffe175..ca8ca37 100644
--- a/src/core/lib/compression/message_compress.h
+++ b/src/core/lib/compression/message_compress.h
@@ -22,10 +22,6 @@
 #include <grpc/compression.h>
 #include <grpc/slice_buffer.h>
 
-#ifdef __cplusplus
-extern "C" {
-#endif
-
 /* compress 'input' to 'output' using 'algorithm'.
    On success, appends compressed slices to output and returns 1.
    On failure, appends uncompressed slices to output and returns 0. */
@@ -40,8 +36,4 @@
                         grpc_compression_algorithm algorithm,
                         grpc_slice_buffer* input, grpc_slice_buffer* output);
 
-#ifdef __cplusplus
-}
-#endif
-
 #endif /* GRPC_CORE_LIB_COMPRESSION_MESSAGE_COMPRESS_H */
diff --git a/src/core/lib/compression/stream_compression.cc b/src/core/lib/compression/stream_compression.cc
index 1ccbe16..b4b3e52 100644
--- a/src/core/lib/compression/stream_compression.cc
+++ b/src/core/lib/compression/stream_compression.cc
@@ -21,7 +21,7 @@
 #include "src/core/lib/compression/stream_compression.h"
 #include "src/core/lib/compression/stream_compression_gzip.h"
 
-extern "C" const grpc_stream_compression_vtable
+extern const grpc_stream_compression_vtable
     grpc_stream_compression_identity_vtable;
 
 bool grpc_stream_compress(grpc_stream_compression_context* ctx,
diff --git a/src/core/lib/compression/stream_compression.h b/src/core/lib/compression/stream_compression.h
index b56c142..8322835 100644
--- a/src/core/lib/compression/stream_compression.h
+++ b/src/core/lib/compression/stream_compression.h
@@ -26,10 +26,6 @@
 
 #include "src/core/lib/transport/static_metadata.h"
 
-#ifdef __cplusplus
-extern "C" {
-#endif
-
 typedef struct grpc_stream_compression_vtable grpc_stream_compression_vtable;
 
 /* Stream compression/decompression context */
@@ -115,8 +111,4 @@
 int grpc_stream_compression_method_parse(
     grpc_slice value, bool is_compress, grpc_stream_compression_method* method);
 
-#ifdef __cplusplus
-}
-#endif
-
 #endif
diff --git a/src/core/lib/compression/stream_compression_gzip.h b/src/core/lib/compression/stream_compression_gzip.h
index a3f1b04..7cf49a0 100644
--- a/src/core/lib/compression/stream_compression_gzip.h
+++ b/src/core/lib/compression/stream_compression_gzip.h
@@ -21,14 +21,6 @@
 
 #include "src/core/lib/compression/stream_compression.h"
 
-#ifdef __cplusplus
-extern "C" {
-#endif
-
 extern const grpc_stream_compression_vtable grpc_stream_compression_gzip_vtable;
 
-#ifdef __cplusplus
-}
-#endif
-
 #endif
diff --git a/src/core/lib/compression/stream_compression_identity.h b/src/core/lib/compression/stream_compression_identity.h
index 3a729fa..41926e9 100644
--- a/src/core/lib/compression/stream_compression_identity.h
+++ b/src/core/lib/compression/stream_compression_identity.h
@@ -21,15 +21,7 @@
 
 #include "src/core/lib/compression/stream_compression.h"
 
-#ifdef __cplusplus
-extern "C" {
-#endif
-
 extern const grpc_stream_compression_vtable
     grpc_stream_compression_identity_vtable;
 
-#ifdef __cplusplus
-}
-#endif
-
 #endif
diff --git a/src/core/lib/debug/stats.h b/src/core/lib/debug/stats.h
index 1c19e72..55db44e 100644
--- a/src/core/lib/debug/stats.h
+++ b/src/core/lib/debug/stats.h
@@ -23,10 +23,6 @@
 #include "src/core/lib/debug/stats_data.h"
 #include "src/core/lib/iomgr/exec_ctx.h"
 
-#ifdef __cplusplus
-extern "C" {
-#endif
-
 typedef struct grpc_stats_data {
   gpr_atm counters[GRPC_STATS_COUNTER_COUNT];
   gpr_atm histograms[GRPC_STATS_HISTOGRAM_BUCKETS];
@@ -62,8 +58,4 @@
 size_t grpc_stats_histo_count(const grpc_stats_data* data,
                               grpc_stats_histograms histogram);
 
-#ifdef __cplusplus
-}
-#endif
-
 #endif
diff --git a/src/core/lib/debug/stats_data.h b/src/core/lib/debug/stats_data.h
index fbfcce8..8a5bc97 100644
--- a/src/core/lib/debug/stats_data.h
+++ b/src/core/lib/debug/stats_data.h
@@ -24,10 +24,6 @@
 #include <inttypes.h>
 #include "src/core/lib/iomgr/exec_ctx.h"
 
-#ifdef __cplusplus
-extern "C" {
-#endif
-
 typedef enum {
   GRPC_STATS_COUNTER_CLIENT_CALLS_CREATED,
   GRPC_STATS_COUNTER_SERVER_CALLS_CREATED,
@@ -502,8 +498,4 @@
 extern void (*const grpc_stats_inc_histogram[13])(grpc_exec_ctx* exec_ctx,
                                                   int x);
 
-#ifdef __cplusplus
-}
-#endif
-
 #endif /* GRPC_CORE_LIB_DEBUG_STATS_DATA_H */
diff --git a/src/core/lib/debug/trace.cc b/src/core/lib/debug/trace.cc
index 9c75ef1..a76c1af 100644
--- a/src/core/lib/debug/trace.cc
+++ b/src/core/lib/debug/trace.cc
@@ -27,26 +27,61 @@
 
 int grpc_tracer_set_enabled(const char* name, int enabled);
 
-typedef struct tracer {
-  grpc_tracer_flag* flag;
-  struct tracer* next;
-} tracer;
-static tracer* tracers;
+namespace grpc_core {
 
-#ifdef GRPC_THREADSAFE_TRACER
-#define TRACER_SET(flag, on) gpr_atm_no_barrier_store(&(flag).value, (on))
-#else
-#define TRACER_SET(flag, on) (flag).value = (on)
-#endif
+TraceFlag* TraceFlagList::root_tracer_ = nullptr;
 
-void grpc_register_tracer(grpc_tracer_flag* flag) {
-  tracer* t = (tracer*)gpr_malloc(sizeof(*t));
-  t->flag = flag;
-  t->next = tracers;
-  TRACER_SET(*flag, false);
-  tracers = t;
+bool TraceFlagList::Set(const char* name, bool enabled) {
+  TraceFlag* t;
+  if (0 == strcmp(name, "all")) {
+    for (t = root_tracer_; t; t = t->next_tracer_) {
+      t->set_enabled(enabled);
+    }
+  } else if (0 == strcmp(name, "list_tracers")) {
+    LogAllTracers();
+  } else if (0 == strcmp(name, "refcount")) {
+    for (t = root_tracer_; t; t = t->next_tracer_) {
+      if (strstr(t->name_, "refcount") != nullptr) {
+        t->set_enabled(enabled);
+      }
+    }
+  } else {
+    bool found = false;
+    for (t = root_tracer_; t; t = t->next_tracer_) {
+      if (0 == strcmp(name, t->name_)) {
+        t->set_enabled(enabled);
+        found = true;
+      }
+    }
+    if (!found) {
+      gpr_log(GPR_ERROR, "Unknown trace var: '%s'", name);
+      return false; /* early return */
+    }
+  }
+  return true;
 }
 
+void TraceFlagList::Add(TraceFlag* flag) {
+  flag->next_tracer_ = root_tracer_;
+  root_tracer_ = flag;
+}
+
+void TraceFlagList::LogAllTracers() {
+  gpr_log(GPR_DEBUG, "available tracers:");
+  TraceFlag* t;
+  for (t = root_tracer_; t != nullptr; t = t->next_tracer_) {
+    gpr_log(GPR_DEBUG, "\t%s", t->name_);
+  }
+}
+
+// Flags register themselves on the list during construction
+TraceFlag::TraceFlag(bool default_enabled, const char* name) : name_(name) {
+  set_enabled(default_enabled);
+  TraceFlagList::Add(this);
+}
+
+}  // namespace grpc_core
+
 static void add(const char* beg, const char* end, char*** ss, size_t* ns) {
   size_t n = *ns;
   size_t np = n + 1;
@@ -80,9 +115,9 @@
 
   for (i = 0; i < nstrings; i++) {
     if (strings[i][0] == '-') {
-      grpc_tracer_set_enabled(strings[i] + 1, 0);
+      grpc_core::TraceFlagList::Set(strings[i] + 1, false);
     } else {
-      grpc_tracer_set_enabled(strings[i], 1);
+      grpc_core::TraceFlagList::Set(strings[i], true);
     }
   }
 
@@ -92,14 +127,6 @@
   gpr_free(strings);
 }
 
-static void list_tracers() {
-  gpr_log(GPR_DEBUG, "available tracers:");
-  tracer* t;
-  for (t = tracers; t; t = t->next) {
-    gpr_log(GPR_DEBUG, "\t%s", t->flag->name);
-  }
-}
-
 void grpc_tracer_init(const char* env_var) {
   char* e = gpr_getenv(env_var);
   if (e != nullptr) {
@@ -108,40 +135,8 @@
   }
 }
 
-void grpc_tracer_shutdown(void) {
-  while (tracers) {
-    tracer* t = tracers;
-    tracers = t->next;
-    gpr_free(t);
-  }
-}
+void grpc_tracer_shutdown(void) {}
 
 int grpc_tracer_set_enabled(const char* name, int enabled) {
-  tracer* t;
-  if (0 == strcmp(name, "all")) {
-    for (t = tracers; t; t = t->next) {
-      TRACER_SET(*t->flag, enabled);
-    }
-  } else if (0 == strcmp(name, "list_tracers")) {
-    list_tracers();
-  } else if (0 == strcmp(name, "refcount")) {
-    for (t = tracers; t; t = t->next) {
-      if (strstr(t->flag->name, "refcount") != nullptr) {
-        TRACER_SET(*t->flag, enabled);
-      }
-    }
-  } else {
-    int found = 0;
-    for (t = tracers; t; t = t->next) {
-      if (0 == strcmp(name, t->flag->name)) {
-        TRACER_SET(*t->flag, enabled);
-        found = 1;
-      }
-    }
-    if (!found) {
-      gpr_log(GPR_ERROR, "Unknown trace var: '%s'", name);
-      return 0; /* early return */
-    }
-  }
-  return 1;
+  return grpc_core::TraceFlagList::Set(name, enabled != 0);
 }
diff --git a/src/core/lib/debug/trace.h b/src/core/lib/debug/trace.h
index 7447d5d..69ddd80 100644
--- a/src/core/lib/debug/trace.h
+++ b/src/core/lib/debug/trace.h
@@ -23,9 +23,8 @@
 #include <grpc/support/port_platform.h>
 #include <stdbool.h>
 
-#ifdef __cplusplus
-extern "C" {
-#endif
+void grpc_tracer_init(const char* env_var_name);
+void grpc_tracer_shutdown(void);
 
 #if defined(__has_feature)
 #if __has_feature(thread_sanitizer)
@@ -33,31 +32,72 @@
 #endif
 #endif
 
-typedef struct {
-#ifdef GRPC_THREADSAFE_TRACER
-  gpr_atm value;
-#else
-  bool value;
-#endif
-  const char* name;
-} grpc_tracer_flag;
+namespace grpc_core {
 
-#ifdef GRPC_THREADSAFE_TRACER
-#define GRPC_TRACER_ON(flag) (gpr_atm_no_barrier_load(&(flag).value) != 0)
-#define GRPC_TRACER_INITIALIZER(on, name) \
-  { (gpr_atm)(on), (name) }
-#else
-#define GRPC_TRACER_ON(flag) ((flag).value)
-#define GRPC_TRACER_INITIALIZER(on, name) \
-  { (on), (name) }
-#endif
+class TraceFlag;
+class TraceFlagList {
+ public:
+  static bool Set(const char* name, bool enabled);
+  static void Add(TraceFlag* flag);
 
-void grpc_register_tracer(grpc_tracer_flag* flag);
-void grpc_tracer_init(const char* env_var_name);
-void grpc_tracer_shutdown(void);
+ private:
+  static void LogAllTracers();
+  static TraceFlag* root_tracer_;
+};
 
-#ifdef __cplusplus
+namespace testing {
+void grpc_tracer_enable_flag(grpc_core::TraceFlag* flag);
 }
+
+class TraceFlag {
+ public:
+  TraceFlag(bool default_enabled, const char* name);
+  ~TraceFlag() {}
+
+  const char* name() const { return name_; }
+
+  bool enabled() {
+#ifdef GRPC_THREADSAFE_TRACER
+    return gpr_atm_no_barrier_load(&value_) != 0;
+#else
+    return value_;
 #endif
+  }
+
+ private:
+  friend void grpc_core::testing::grpc_tracer_enable_flag(TraceFlag* flag);
+  friend class TraceFlagList;
+
+  void set_enabled(bool enabled) {
+#ifdef GRPC_THREADSAFE_TRACER
+    gpr_atm_no_barrier_store(&value_, enabled);
+#else
+    value_ = enabled;
+#endif
+  }
+
+  TraceFlag* next_tracer_;
+  const char* const name_;
+#ifdef GRPC_THREADSAFE_TRACER
+  gpr_atm value_;
+#else
+  bool value_;
+#endif
+};
+
+#ifndef NDEBUG
+typedef TraceFlag DebugOnlyTraceFlag;
+#else
+class DebugOnlyTraceFlag {
+ public:
+  DebugOnlyTraceFlag(bool default_enabled, const char* name) {}
+  bool enabled() { return false; }
+
+ private:
+  void set_enabled(bool enabled) {}
+};
+#endif
+
+}  // namespace grpc_core
 
 #endif /* GRPC_CORE_LIB_DEBUG_TRACE_H */
diff --git a/src/core/lib/http/format_request.h b/src/core/lib/http/format_request.h
index 3205480..c191965 100644
--- a/src/core/lib/http/format_request.h
+++ b/src/core/lib/http/format_request.h
@@ -22,10 +22,6 @@
 #include <grpc/slice.h>
 #include "src/core/lib/http/httpcli.h"
 
-#ifdef __cplusplus
-extern "C" {
-#endif
-
 grpc_slice grpc_httpcli_format_get_request(const grpc_httpcli_request* request);
 grpc_slice grpc_httpcli_format_post_request(const grpc_httpcli_request* request,
                                             const char* body_bytes,
@@ -33,8 +29,4 @@
 grpc_slice grpc_httpcli_format_connect_request(
     const grpc_httpcli_request* request);
 
-#ifdef __cplusplus
-}
-#endif
-
 #endif /* GRPC_CORE_LIB_HTTP_FORMAT_REQUEST_H */
diff --git a/src/core/lib/http/httpcli.h b/src/core/lib/http/httpcli.h
index a341134..6f67556 100644
--- a/src/core/lib/http/httpcli.h
+++ b/src/core/lib/http/httpcli.h
@@ -32,10 +32,6 @@
 /* User agent this library reports */
 #define GRPC_HTTPCLI_USER_AGENT "grpc-httpcli/0.0"
 
-#ifdef __cplusplus
-extern "C" {
-#endif
-
 /* Tracks in-progress http requests
    TODO(ctiller): allow caching and capturing multiple requests for the
                   same content and combining them */
@@ -127,8 +123,4 @@
 void grpc_httpcli_set_override(grpc_httpcli_get_override get,
                                grpc_httpcli_post_override post);
 
-#ifdef __cplusplus
-}
-#endif
-
 #endif /* GRPC_CORE_LIB_HTTP_HTTPCLI_H */
diff --git a/src/core/lib/http/parser.cc b/src/core/lib/http/parser.cc
index 9134b0c..fb4eb23 100644
--- a/src/core/lib/http/parser.cc
+++ b/src/core/lib/http/parser.cc
@@ -25,7 +25,7 @@
 #include <grpc/support/log.h>
 #include <grpc/support/useful.h>
 
-grpc_tracer_flag grpc_http1_trace = GRPC_TRACER_INITIALIZER(false, "http1");
+grpc_core::TraceFlag grpc_http1_trace(false, "http1");
 
 static char* buf2str(void* buffer, size_t length) {
   char* out = (char*)gpr_malloc(length + 1);
@@ -294,7 +294,7 @@
     case GRPC_HTTP_FIRST_LINE:
     case GRPC_HTTP_HEADERS:
       if (parser->cur_line_length >= GRPC_HTTP_PARSER_MAX_HEADER_LENGTH) {
-        if (GRPC_TRACER_ON(grpc_http1_trace))
+        if (grpc_http1_trace.enabled())
           gpr_log(GPR_ERROR, "HTTP header max line length (%d) exceeded",
                   GRPC_HTTP_PARSER_MAX_HEADER_LENGTH);
         return GRPC_ERROR_CREATE_FROM_STATIC_STRING(
diff --git a/src/core/lib/http/parser.h b/src/core/lib/http/parser.h
index 3d28481..5fef448 100644
--- a/src/core/lib/http/parser.h
+++ b/src/core/lib/http/parser.h
@@ -27,10 +27,6 @@
 /* Maximum length of a header string of the form 'Key: Value\r\n' */
 #define GRPC_HTTP_PARSER_MAX_HEADER_LENGTH 4096
 
-#ifdef __cplusplus
-extern "C" {
-#endif
-
 /* A single header to be passed in a request */
 typedef struct grpc_http_header {
   char* key;
@@ -111,10 +107,6 @@
 void grpc_http_request_destroy(grpc_http_request* request);
 void grpc_http_response_destroy(grpc_http_response* response);
 
-extern grpc_tracer_flag grpc_http1_trace;
-
-#ifdef __cplusplus
-}
-#endif
+extern grpc_core::TraceFlag grpc_http1_trace;
 
 #endif /* GRPC_CORE_LIB_HTTP_PARSER_H */
diff --git a/src/core/lib/iomgr/block_annotate.h b/src/core/lib/iomgr/block_annotate.h
index fcbfe9e..340ebcb 100644
--- a/src/core/lib/iomgr/block_annotate.h
+++ b/src/core/lib/iomgr/block_annotate.h
@@ -19,17 +19,9 @@
 #ifndef GRPC_CORE_LIB_IOMGR_BLOCK_ANNOTATE_H
 #define GRPC_CORE_LIB_IOMGR_BLOCK_ANNOTATE_H
 
-#ifdef __cplusplus
-extern "C" {
-#endif
-
 void gpr_thd_start_blocking_region();
 void gpr_thd_end_blocking_region();
 
-#ifdef __cplusplus
-}
-#endif
-
 /* These annotations identify the beginning and end of regions where
    the code may block for reasons other than synchronization functions.
    These include poll, epoll, and getaddrinfo. */
diff --git a/src/core/lib/iomgr/call_combiner.cc b/src/core/lib/iomgr/call_combiner.cc
index 74b077d..b5910b4 100644
--- a/src/core/lib/iomgr/call_combiner.cc
+++ b/src/core/lib/iomgr/call_combiner.cc
@@ -24,8 +24,7 @@
 #include "src/core/lib/debug/stats.h"
 #include "src/core/lib/profiling/timers.h"
 
-grpc_tracer_flag grpc_call_combiner_trace =
-    GRPC_TRACER_INITIALIZER(false, "call_combiner");
+grpc_core::TraceFlag grpc_call_combiner_trace(false, "call_combiner");
 
 static grpc_error* decode_cancel_state_error(gpr_atm cancel_state) {
   if (cancel_state & 1) {
@@ -63,7 +62,7 @@
                               grpc_error* error DEBUG_ARGS,
                               const char* reason) {
   GPR_TIMER_BEGIN("call_combiner_start", 0);
-  if (GRPC_TRACER_ON(grpc_call_combiner_trace)) {
+  if (grpc_call_combiner_trace.enabled()) {
     gpr_log(GPR_DEBUG,
             "==> grpc_call_combiner_start() [%p] closure=%p [" DEBUG_FMT_STR
             "%s] error=%s",
@@ -72,7 +71,7 @@
   }
   size_t prev_size =
       (size_t)gpr_atm_full_fetch_add(&call_combiner->size, (gpr_atm)1);
-  if (GRPC_TRACER_ON(grpc_call_combiner_trace)) {
+  if (grpc_call_combiner_trace.enabled()) {
     gpr_log(GPR_DEBUG, "  size: %" PRIdPTR " -> %" PRIdPTR, prev_size,
             prev_size + 1);
   }
@@ -80,13 +79,13 @@
   if (prev_size == 0) {
     GRPC_STATS_INC_CALL_COMBINER_LOCKS_INITIATED(exec_ctx);
     GPR_TIMER_MARK("call_combiner_initiate", 0);
-    if (GRPC_TRACER_ON(grpc_call_combiner_trace)) {
+    if (grpc_call_combiner_trace.enabled()) {
       gpr_log(GPR_DEBUG, "  EXECUTING IMMEDIATELY");
     }
     // Queue was empty, so execute this closure immediately.
     GRPC_CLOSURE_SCHED(exec_ctx, closure, error);
   } else {
-    if (GRPC_TRACER_ON(grpc_call_combiner_trace)) {
+    if (grpc_call_combiner_trace.enabled()) {
       gpr_log(GPR_INFO, "  QUEUING");
     }
     // Queue was not empty, so add closure to queue.
@@ -100,21 +99,21 @@
                              grpc_call_combiner* call_combiner DEBUG_ARGS,
                              const char* reason) {
   GPR_TIMER_BEGIN("call_combiner_stop", 0);
-  if (GRPC_TRACER_ON(grpc_call_combiner_trace)) {
+  if (grpc_call_combiner_trace.enabled()) {
     gpr_log(GPR_DEBUG,
             "==> grpc_call_combiner_stop() [%p] [" DEBUG_FMT_STR "%s]",
             call_combiner DEBUG_FMT_ARGS, reason);
   }
   size_t prev_size =
       (size_t)gpr_atm_full_fetch_add(&call_combiner->size, (gpr_atm)-1);
-  if (GRPC_TRACER_ON(grpc_call_combiner_trace)) {
+  if (grpc_call_combiner_trace.enabled()) {
     gpr_log(GPR_DEBUG, "  size: %" PRIdPTR " -> %" PRIdPTR, prev_size,
             prev_size - 1);
   }
   GPR_ASSERT(prev_size >= 1);
   if (prev_size > 1) {
     while (true) {
-      if (GRPC_TRACER_ON(grpc_call_combiner_trace)) {
+      if (grpc_call_combiner_trace.enabled()) {
         gpr_log(GPR_DEBUG, "  checking queue");
       }
       bool empty;
@@ -123,19 +122,19 @@
       if (closure == nullptr) {
         // This can happen either due to a race condition within the mpscq
         // code or because of a race with grpc_call_combiner_start().
-        if (GRPC_TRACER_ON(grpc_call_combiner_trace)) {
+        if (grpc_call_combiner_trace.enabled()) {
           gpr_log(GPR_DEBUG, "  queue returned no result; checking again");
         }
         continue;
       }
-      if (GRPC_TRACER_ON(grpc_call_combiner_trace)) {
+      if (grpc_call_combiner_trace.enabled()) {
         gpr_log(GPR_DEBUG, "  EXECUTING FROM QUEUE: closure=%p error=%s",
                 closure, grpc_error_string(closure->error_data.error));
       }
       GRPC_CLOSURE_SCHED(exec_ctx, closure, closure->error_data.error);
       break;
     }
-  } else if (GRPC_TRACER_ON(grpc_call_combiner_trace)) {
+  } else if (grpc_call_combiner_trace.enabled()) {
     gpr_log(GPR_DEBUG, "  queue empty");
   }
   GPR_TIMER_END("call_combiner_stop", 0);
@@ -152,7 +151,7 @@
     // If error is set, invoke the cancellation closure immediately.
     // Otherwise, store the new closure.
     if (original_error != GRPC_ERROR_NONE) {
-      if (GRPC_TRACER_ON(grpc_call_combiner_trace)) {
+      if (grpc_call_combiner_trace.enabled()) {
         gpr_log(GPR_DEBUG,
                 "call_combiner=%p: scheduling notify_on_cancel callback=%p "
                 "for pre-existing cancellation",
@@ -163,7 +162,7 @@
     } else {
       if (gpr_atm_full_cas(&call_combiner->cancel_state, original_state,
                            (gpr_atm)closure)) {
-        if (GRPC_TRACER_ON(grpc_call_combiner_trace)) {
+        if (grpc_call_combiner_trace.enabled()) {
           gpr_log(GPR_DEBUG, "call_combiner=%p: setting notify_on_cancel=%p",
                   call_combiner, closure);
         }
@@ -172,7 +171,7 @@
         // up any resources they may be holding for the callback.
         if (original_state != 0) {
           closure = (grpc_closure*)original_state;
-          if (GRPC_TRACER_ON(grpc_call_combiner_trace)) {
+          if (grpc_call_combiner_trace.enabled()) {
             gpr_log(GPR_DEBUG,
                     "call_combiner=%p: scheduling old cancel callback=%p",
                     call_combiner, closure);
@@ -201,7 +200,7 @@
                          encode_cancel_state_error(error))) {
       if (original_state != 0) {
         grpc_closure* notify_on_cancel = (grpc_closure*)original_state;
-        if (GRPC_TRACER_ON(grpc_call_combiner_trace)) {
+        if (grpc_call_combiner_trace.enabled()) {
           gpr_log(GPR_DEBUG,
                   "call_combiner=%p: scheduling notify_on_cancel callback=%p",
                   call_combiner, notify_on_cancel);
diff --git a/src/core/lib/iomgr/call_combiner.h b/src/core/lib/iomgr/call_combiner.h
index 527f84f..c07af51 100644
--- a/src/core/lib/iomgr/call_combiner.h
+++ b/src/core/lib/iomgr/call_combiner.h
@@ -27,10 +27,6 @@
 #include "src/core/lib/iomgr/exec_ctx.h"
 #include "src/core/lib/support/mpscq.h"
 
-#ifdef __cplusplus
-extern "C" {
-#endif
-
 // A simple, lock-free mechanism for serializing activity related to a
 // single call.  This is similar to a combiner but is more lightweight.
 //
@@ -40,7 +36,7 @@
 // when it is done with the action that was kicked off by the original
 // callback.
 
-extern grpc_tracer_flag grpc_call_combiner_trace;
+extern grpc_core::TraceFlag grpc_call_combiner_trace;
 
 typedef struct {
   gpr_atm size;  // size_t, num closures in queue or currently executing
@@ -122,8 +118,4 @@
                                grpc_call_combiner* call_combiner,
                                grpc_error* error);
 
-#ifdef __cplusplus
-}
-#endif
-
 #endif /* GRPC_CORE_LIB_IOMGR_CALL_COMBINER_H */
diff --git a/src/core/lib/iomgr/closure.h b/src/core/lib/iomgr/closure.h
index 8b99d4a..46793dd 100644
--- a/src/core/lib/iomgr/closure.h
+++ b/src/core/lib/iomgr/closure.h
@@ -33,9 +33,7 @@
 struct grpc_closure;
 typedef struct grpc_closure grpc_closure;
 
-#ifndef NDEBUG
-extern grpc_tracer_flag grpc_trace_closure;
-#endif
+extern grpc_core::DebugOnlyTraceFlag grpc_trace_closure;
 
 typedef struct grpc_closure_list {
   grpc_closure* head;
diff --git a/src/core/lib/iomgr/combiner.cc b/src/core/lib/iomgr/combiner.cc
index b28ca34..15c009d 100644
--- a/src/core/lib/iomgr/combiner.cc
+++ b/src/core/lib/iomgr/combiner.cc
@@ -29,14 +29,13 @@
 #include "src/core/lib/iomgr/executor.h"
 #include "src/core/lib/profiling/timers.h"
 
-grpc_tracer_flag grpc_combiner_trace =
-    GRPC_TRACER_INITIALIZER(false, "combiner");
+grpc_core::TraceFlag grpc_combiner_trace(false, "combiner");
 
-#define GRPC_COMBINER_TRACE(fn)                \
-  do {                                         \
-    if (GRPC_TRACER_ON(grpc_combiner_trace)) { \
-      fn;                                      \
-    }                                          \
+#define GRPC_COMBINER_TRACE(fn)          \
+  do {                                   \
+    if (grpc_combiner_trace.enabled()) { \
+      fn;                                \
+    }                                    \
   } while (0)
 
 #define STATE_UNORPHANED 1
@@ -106,7 +105,7 @@
 
 #ifndef NDEBUG
 #define GRPC_COMBINER_DEBUG_SPAM(op, delta)                                \
-  if (GRPC_TRACER_ON(grpc_combiner_trace)) {                               \
+  if (grpc_combiner_trace.enabled()) {                                     \
     gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG,                            \
             "C:%p %s %" PRIdPTR " --> %" PRIdPTR " %s", lock, (op),        \
             gpr_atm_no_barrier_load(&lock->refs.count),                    \
diff --git a/src/core/lib/iomgr/combiner.h b/src/core/lib/iomgr/combiner.h
index f8a8b9d..0c05511 100644
--- a/src/core/lib/iomgr/combiner.h
+++ b/src/core/lib/iomgr/combiner.h
@@ -26,10 +26,6 @@
 #include "src/core/lib/iomgr/exec_ctx.h"
 #include "src/core/lib/support/mpscq.h"
 
-#ifdef __cplusplus
-extern "C" {
-#endif
-
 // 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
@@ -65,10 +61,6 @@
 
 bool grpc_combiner_continue_exec_ctx(grpc_exec_ctx* exec_ctx);
 
-extern grpc_tracer_flag grpc_combiner_trace;
-
-#ifdef __cplusplus
-}
-#endif
+extern grpc_core::TraceFlag grpc_combiner_trace;
 
 #endif /* GRPC_CORE_LIB_IOMGR_COMBINER_H */
diff --git a/src/core/lib/iomgr/endpoint.h b/src/core/lib/iomgr/endpoint.h
index 1b0a9e7..6ab0a65 100644
--- a/src/core/lib/iomgr/endpoint.h
+++ b/src/core/lib/iomgr/endpoint.h
@@ -26,10 +26,6 @@
 #include "src/core/lib/iomgr/pollset_set.h"
 #include "src/core/lib/iomgr/resource_quota.h"
 
-#ifdef __cplusplus
-extern "C" {
-#endif
-
 /* An endpoint caps a streaming channel between two communicating processes.
    Examples may be: a tcp socket, <stdin+stdout>, or some shared memory. */
 
@@ -106,8 +102,4 @@
   const grpc_endpoint_vtable* vtable;
 };
 
-#ifdef __cplusplus
-}
-#endif
-
 #endif /* GRPC_CORE_LIB_IOMGR_ENDPOINT_H */
diff --git a/src/core/lib/iomgr/endpoint_pair.h b/src/core/lib/iomgr/endpoint_pair.h
index 219eea8..506ffc8 100644
--- a/src/core/lib/iomgr/endpoint_pair.h
+++ b/src/core/lib/iomgr/endpoint_pair.h
@@ -21,10 +21,6 @@
 
 #include "src/core/lib/iomgr/endpoint.h"
 
-#ifdef __cplusplus
-extern "C" {
-#endif
-
 typedef struct {
   grpc_endpoint* client;
   grpc_endpoint* server;
@@ -33,8 +29,4 @@
 grpc_endpoint_pair grpc_iomgr_create_endpoint_pair(const char* name,
                                                    grpc_channel_args* args);
 
-#ifdef __cplusplus
-}
-#endif
-
 #endif /* GRPC_CORE_LIB_IOMGR_ENDPOINT_PAIR_H */
diff --git a/src/core/lib/iomgr/error.cc b/src/core/lib/iomgr/error.cc
index f3dfac3..e6d640c 100644
--- a/src/core/lib/iomgr/error.cc
+++ b/src/core/lib/iomgr/error.cc
@@ -37,11 +37,9 @@
 #include "src/core/lib/profiling/timers.h"
 #include "src/core/lib/slice/slice_internal.h"
 
-#ifndef NDEBUG
-grpc_tracer_flag grpc_trace_error_refcount =
-    GRPC_TRACER_INITIALIZER(false, "error_refcount");
-grpc_tracer_flag grpc_trace_closure = GRPC_TRACER_INITIALIZER(false, "closure");
-#endif
+grpc_core::DebugOnlyTraceFlag grpc_trace_error_refcount(false,
+                                                        "error_refcount");
+grpc_core::DebugOnlyTraceFlag grpc_trace_closure(false, "closure");
 
 static const char* error_int_name(grpc_error_ints key) {
   switch (key) {
@@ -131,7 +129,7 @@
 #ifndef NDEBUG
 grpc_error* grpc_error_ref(grpc_error* err, const char* file, int line) {
   if (grpc_error_is_special(err)) return err;
-  if (GRPC_TRACER_ON(grpc_trace_error_refcount)) {
+  if (grpc_trace_error_refcount.enabled()) {
     gpr_log(GPR_DEBUG, "%p: %" PRIdPTR " -> %" PRIdPTR " [%s:%d]", err,
             gpr_atm_no_barrier_load(&err->atomics.refs.count),
             gpr_atm_no_barrier_load(&err->atomics.refs.count) + 1, file, line);
@@ -184,7 +182,7 @@
 #ifndef NDEBUG
 void grpc_error_unref(grpc_error* err, const char* file, int line) {
   if (grpc_error_is_special(err)) return;
-  if (GRPC_TRACER_ON(grpc_trace_error_refcount)) {
+  if (grpc_trace_error_refcount.enabled()) {
     gpr_log(GPR_DEBUG, "%p: %" PRIdPTR " -> %" PRIdPTR " [%s:%d]", err,
             gpr_atm_no_barrier_load(&err->atomics.refs.count),
             gpr_atm_no_barrier_load(&err->atomics.refs.count) - 1, file, line);
@@ -217,7 +215,7 @@
     *err = (grpc_error*)gpr_realloc(
         *err, sizeof(grpc_error) + (*err)->arena_capacity * sizeof(intptr_t));
 #ifndef NDEBUG
-    if (GRPC_TRACER_ON(grpc_trace_error_refcount)) {
+    if (grpc_trace_error_refcount.enabled()) {
       if (*err != orig) {
         gpr_log(GPR_DEBUG, "realloc %p -> %p", orig, *err);
       }
@@ -330,7 +328,7 @@
     return GRPC_ERROR_OOM;
   }
 #ifndef NDEBUG
-  if (GRPC_TRACER_ON(grpc_trace_error_refcount)) {
+  if (grpc_trace_error_refcount.enabled()) {
     gpr_log(GPR_DEBUG, "%p create [%s:%d]", err, file, line);
   }
 #endif
@@ -412,7 +410,7 @@
     out = (grpc_error*)gpr_malloc(sizeof(*in) +
                                   new_arena_capacity * sizeof(intptr_t));
 #ifndef NDEBUG
-    if (GRPC_TRACER_ON(grpc_trace_error_refcount)) {
+    if (grpc_trace_error_refcount.enabled()) {
       gpr_log(GPR_DEBUG, "%p create copying %p", out, in);
     }
 #endif
diff --git a/src/core/lib/iomgr/error.h b/src/core/lib/iomgr/error.h
index 8d7aea4..4759ee0 100644
--- a/src/core/lib/iomgr/error.h
+++ b/src/core/lib/iomgr/error.h
@@ -29,19 +29,13 @@
 
 #include "src/core/lib/debug/trace.h"
 
-#ifdef __cplusplus
-extern "C" {
-#endif
-
 /// Opaque representation of an error.
 /// See https://github.com/grpc/grpc/blob/master/doc/core/grpc-error.md for a
 /// full write up of this object.
 
 typedef struct grpc_error grpc_error;
 
-#ifndef NDEBUG
-extern grpc_tracer_flag grpc_trace_error_refcount;
-#endif
+extern grpc_core::DebugOnlyTraceFlag grpc_trace_error_refcount;
 
 typedef enum {
   /// 'errno' from the operating system
@@ -205,8 +199,4 @@
 #define GRPC_LOG_IF_ERROR(what, error) \
   grpc_log_if_error((what), (error), __FILE__, __LINE__)
 
-#ifdef __cplusplus
-}
-#endif
-
 #endif /* GRPC_CORE_LIB_IOMGR_ERROR_H */
diff --git a/src/core/lib/iomgr/error_internal.h b/src/core/lib/iomgr/error_internal.h
index d5ccbae..6cb09c2 100644
--- a/src/core/lib/iomgr/error_internal.h
+++ b/src/core/lib/iomgr/error_internal.h
@@ -25,10 +25,6 @@
 #include <grpc/support/sync.h>
 #include "src/core/lib/iomgr/error.h"
 
-#ifdef __cplusplus
-extern "C" {
-#endif
-
 typedef struct grpc_linked_error grpc_linked_error;
 
 struct grpc_linked_error {
@@ -62,8 +58,4 @@
 
 bool grpc_error_is_special(struct grpc_error* err);
 
-#ifdef __cplusplus
-}
-#endif
-
 #endif /* GRPC_CORE_LIB_IOMGR_ERROR_INTERNAL_H */
diff --git a/src/core/lib/iomgr/ev_epoll1_linux.cc b/src/core/lib/iomgr/ev_epoll1_linux.cc
index 918bc6f..0dda1d9 100644
--- a/src/core/lib/iomgr/ev_epoll1_linux.cc
+++ b/src/core/lib/iomgr/ev_epoll1_linux.cc
@@ -263,11 +263,13 @@
 
   if (new_fd == nullptr) {
     new_fd = (grpc_fd*)gpr_malloc(sizeof(grpc_fd));
+    new_fd->read_closure.Init();
+    new_fd->write_closure.Init();
   }
 
   new_fd->fd = fd;
-  new_fd->read_closure.Init();
-  new_fd->write_closure.Init();
+  new_fd->read_closure->InitEvent();
+  new_fd->write_closure->InitEvent();
   gpr_atm_no_barrier_store(&new_fd->read_notifier_pollset, (gpr_atm)NULL);
 
   new_fd->freelist_next = nullptr;
@@ -276,7 +278,7 @@
   gpr_asprintf(&fd_name, "%s fd=%d", name, fd);
   grpc_iomgr_register_object(&new_fd->iomgr_object, fd_name);
 #ifndef NDEBUG
-  if (GRPC_TRACER_ON(grpc_trace_fd_refcount)) {
+  if (grpc_trace_fd_refcount.enabled()) {
     gpr_log(GPR_DEBUG, "FD %d %p create %s", fd, new_fd, fd_name);
   }
 #endif
@@ -336,8 +338,8 @@
   GRPC_CLOSURE_SCHED(exec_ctx, on_done, GRPC_ERROR_REF(error));
 
   grpc_iomgr_unregister_object(&fd->iomgr_object);
-  fd->read_closure.Destroy();
-  fd->write_closure.Destroy();
+  fd->read_closure->DestroyEvent();
+  fd->write_closure->DestroyEvent();
 
   gpr_mu_lock(&fd_freelist_mu);
   fd->freelist_next = fd_freelist;
@@ -651,7 +653,7 @@
 
   GRPC_STATS_INC_POLL_EVENTS_RETURNED(exec_ctx, r);
 
-  if (GRPC_TRACER_ON(grpc_polling_trace)) {
+  if (grpc_polling_trace.enabled()) {
     gpr_log(GPR_DEBUG, "ps: %p poll got %d events", ps, r);
   }
 
@@ -673,7 +675,7 @@
   worker->schedule_on_end_work = (grpc_closure_list)GRPC_CLOSURE_LIST_INIT;
   pollset->begin_refs++;
 
-  if (GRPC_TRACER_ON(grpc_polling_trace)) {
+  if (grpc_polling_trace.enabled()) {
     gpr_log(GPR_ERROR, "PS:%p BEGIN_STARTS:%p", pollset, worker);
   }
 
@@ -692,7 +694,7 @@
   retry_lock_neighborhood:
     gpr_mu_lock(&neighborhood->mu);
     gpr_mu_lock(&pollset->mu);
-    if (GRPC_TRACER_ON(grpc_polling_trace)) {
+    if (grpc_polling_trace.enabled()) {
       gpr_log(GPR_ERROR, "PS:%p BEGIN_REORG:%p kick_state=%s is_reassigning=%d",
               pollset, worker, kick_state_string(worker->state),
               is_reassigning);
@@ -744,7 +746,7 @@
     worker->initialized_cv = true;
     gpr_cv_init(&worker->cv);
     while (worker->state == UNKICKED && !pollset->shutting_down) {
-      if (GRPC_TRACER_ON(grpc_polling_trace)) {
+      if (grpc_polling_trace.enabled()) {
         gpr_log(GPR_ERROR, "PS:%p BEGIN_WAIT:%p kick_state=%s shutdown=%d",
                 pollset, worker, kick_state_string(worker->state),
                 pollset->shutting_down);
@@ -761,7 +763,7 @@
     grpc_exec_ctx_invalidate_now(exec_ctx);
   }
 
-  if (GRPC_TRACER_ON(grpc_polling_trace)) {
+  if (grpc_polling_trace.enabled()) {
     gpr_log(GPR_ERROR,
             "PS:%p BEGIN_DONE:%p kick_state=%s shutdown=%d "
             "kicked_without_poller: %d",
@@ -806,7 +808,7 @@
           case UNKICKED:
             if (gpr_atm_no_barrier_cas(&g_active_poller, 0,
                                        (gpr_atm)inspect_worker)) {
-              if (GRPC_TRACER_ON(grpc_polling_trace)) {
+              if (grpc_polling_trace.enabled()) {
                 gpr_log(GPR_DEBUG, " .. choose next poller to be %p",
                         inspect_worker);
               }
@@ -817,7 +819,7 @@
                 gpr_cv_signal(&inspect_worker->cv);
               }
             } else {
-              if (GRPC_TRACER_ON(grpc_polling_trace)) {
+              if (grpc_polling_trace.enabled()) {
                 gpr_log(GPR_DEBUG, " .. beaten to choose next poller");
               }
             }
@@ -835,7 +837,7 @@
       } while (!found_worker && inspect_worker != inspect->root_worker);
     }
     if (!found_worker) {
-      if (GRPC_TRACER_ON(grpc_polling_trace)) {
+      if (grpc_polling_trace.enabled()) {
         gpr_log(GPR_DEBUG, " .. mark pollset %p inactive", inspect);
       }
       inspect->seen_inactive = true;
@@ -857,7 +859,7 @@
                        grpc_pollset_worker* worker,
                        grpc_pollset_worker** worker_hdl) {
   GPR_TIMER_BEGIN("end_worker", 0);
-  if (GRPC_TRACER_ON(grpc_polling_trace)) {
+  if (grpc_polling_trace.enabled()) {
     gpr_log(GPR_DEBUG, "PS:%p END_WORKER:%p", pollset, worker);
   }
   if (worker_hdl != nullptr) *worker_hdl = nullptr;
@@ -867,7 +869,7 @@
                          &exec_ctx->closure_list);
   if (gpr_atm_no_barrier_load(&g_active_poller) == (gpr_atm)worker) {
     if (worker->next != worker && worker->next->state == UNKICKED) {
-      if (GRPC_TRACER_ON(grpc_polling_trace)) {
+      if (grpc_polling_trace.enabled()) {
         gpr_log(GPR_DEBUG, " .. choose next poller to be peer %p", worker);
       }
       GPR_ASSERT(worker->next->initialized_cv);
@@ -921,7 +923,7 @@
   if (worker->initialized_cv) {
     gpr_cv_destroy(&worker->cv);
   }
-  if (GRPC_TRACER_ON(grpc_polling_trace)) {
+  if (grpc_polling_trace.enabled()) {
     gpr_log(GPR_DEBUG, " .. remove worker");
   }
   if (EMPTIED == worker_remove(pollset, worker)) {
@@ -993,7 +995,7 @@
   GPR_TIMER_BEGIN("pollset_kick", 0);
   GRPC_STATS_INC_POLLSET_KICK(exec_ctx);
   grpc_error* ret_err = GRPC_ERROR_NONE;
-  if (GRPC_TRACER_ON(grpc_polling_trace)) {
+  if (grpc_polling_trace.enabled()) {
     gpr_strvec log;
     gpr_strvec_init(&log);
     char* tmp;
@@ -1026,7 +1028,7 @@
       if (root_worker == nullptr) {
         GRPC_STATS_INC_POLLSET_KICKED_WITHOUT_POLLER(exec_ctx);
         pollset->kicked_without_poller = true;
-        if (GRPC_TRACER_ON(grpc_polling_trace)) {
+        if (grpc_polling_trace.enabled()) {
           gpr_log(GPR_ERROR, " .. kicked_without_poller");
         }
         goto done;
@@ -1034,14 +1036,14 @@
       grpc_pollset_worker* next_worker = root_worker->next;
       if (root_worker->state == KICKED) {
         GRPC_STATS_INC_POLLSET_KICKED_AGAIN(exec_ctx);
-        if (GRPC_TRACER_ON(grpc_polling_trace)) {
+        if (grpc_polling_trace.enabled()) {
           gpr_log(GPR_ERROR, " .. already kicked %p", root_worker);
         }
         SET_KICK_STATE(root_worker, KICKED);
         goto done;
       } else if (next_worker->state == KICKED) {
         GRPC_STATS_INC_POLLSET_KICKED_AGAIN(exec_ctx);
-        if (GRPC_TRACER_ON(grpc_polling_trace)) {
+        if (grpc_polling_trace.enabled()) {
           gpr_log(GPR_ERROR, " .. already kicked %p", next_worker);
         }
         SET_KICK_STATE(next_worker, KICKED);
@@ -1052,7 +1054,7 @@
                  root_worker == (grpc_pollset_worker*)gpr_atm_no_barrier_load(
                                     &g_active_poller)) {
         GRPC_STATS_INC_POLLSET_KICK_WAKEUP_FD(exec_ctx);
-        if (GRPC_TRACER_ON(grpc_polling_trace)) {
+        if (grpc_polling_trace.enabled()) {
           gpr_log(GPR_ERROR, " .. kicked %p", root_worker);
         }
         SET_KICK_STATE(root_worker, KICKED);
@@ -1060,7 +1062,7 @@
         goto done;
       } else if (next_worker->state == UNKICKED) {
         GRPC_STATS_INC_POLLSET_KICK_WAKEUP_CV(exec_ctx);
-        if (GRPC_TRACER_ON(grpc_polling_trace)) {
+        if (grpc_polling_trace.enabled()) {
           gpr_log(GPR_ERROR, " .. kicked %p", next_worker);
         }
         GPR_ASSERT(next_worker->initialized_cv);
@@ -1069,7 +1071,7 @@
         goto done;
       } else if (next_worker->state == DESIGNATED_POLLER) {
         if (root_worker->state != DESIGNATED_POLLER) {
-          if (GRPC_TRACER_ON(grpc_polling_trace)) {
+          if (grpc_polling_trace.enabled()) {
             gpr_log(
                 GPR_ERROR,
                 " .. kicked root non-poller %p (initialized_cv=%d) (poller=%p)",
@@ -1083,7 +1085,7 @@
           goto done;
         } else {
           GRPC_STATS_INC_POLLSET_KICK_WAKEUP_FD(exec_ctx);
-          if (GRPC_TRACER_ON(grpc_polling_trace)) {
+          if (grpc_polling_trace.enabled()) {
             gpr_log(GPR_ERROR, " .. non-root poller %p (root=%p)", next_worker,
                     root_worker);
           }
@@ -1099,7 +1101,7 @@
       }
     } else {
       GRPC_STATS_INC_POLLSET_KICK_OWN_THREAD(exec_ctx);
-      if (GRPC_TRACER_ON(grpc_polling_trace)) {
+      if (grpc_polling_trace.enabled()) {
         gpr_log(GPR_ERROR, " .. kicked while waking up");
       }
       goto done;
@@ -1109,14 +1111,14 @@
   }
 
   if (specific_worker->state == KICKED) {
-    if (GRPC_TRACER_ON(grpc_polling_trace)) {
+    if (grpc_polling_trace.enabled()) {
       gpr_log(GPR_ERROR, " .. specific worker already kicked");
     }
     goto done;
   } else if (gpr_tls_get(&g_current_thread_worker) ==
              (intptr_t)specific_worker) {
     GRPC_STATS_INC_POLLSET_KICK_OWN_THREAD(exec_ctx);
-    if (GRPC_TRACER_ON(grpc_polling_trace)) {
+    if (grpc_polling_trace.enabled()) {
       gpr_log(GPR_ERROR, " .. mark %p kicked", specific_worker);
     }
     SET_KICK_STATE(specific_worker, KICKED);
@@ -1124,7 +1126,7 @@
   } else if (specific_worker ==
              (grpc_pollset_worker*)gpr_atm_no_barrier_load(&g_active_poller)) {
     GRPC_STATS_INC_POLLSET_KICK_WAKEUP_FD(exec_ctx);
-    if (GRPC_TRACER_ON(grpc_polling_trace)) {
+    if (grpc_polling_trace.enabled()) {
       gpr_log(GPR_ERROR, " .. kick active poller");
     }
     SET_KICK_STATE(specific_worker, KICKED);
@@ -1132,7 +1134,7 @@
     goto done;
   } else if (specific_worker->initialized_cv) {
     GRPC_STATS_INC_POLLSET_KICK_WAKEUP_CV(exec_ctx);
-    if (GRPC_TRACER_ON(grpc_polling_trace)) {
+    if (grpc_polling_trace.enabled()) {
       gpr_log(GPR_ERROR, " .. kick waiting worker");
     }
     SET_KICK_STATE(specific_worker, KICKED);
@@ -1140,7 +1142,7 @@
     goto done;
   } else {
     GRPC_STATS_INC_POLLSET_KICKED_AGAIN(exec_ctx);
-    if (GRPC_TRACER_ON(grpc_polling_trace)) {
+    if (grpc_polling_trace.enabled()) {
       gpr_log(GPR_ERROR, " .. kick non-waiting worker");
     }
     SET_KICK_STATE(specific_worker, KICKED);
diff --git a/src/core/lib/iomgr/ev_epoll1_linux.h b/src/core/lib/iomgr/ev_epoll1_linux.h
index 3e66747..9a1b96b 100644
--- a/src/core/lib/iomgr/ev_epoll1_linux.h
+++ b/src/core/lib/iomgr/ev_epoll1_linux.h
@@ -22,16 +22,8 @@
 #include "src/core/lib/iomgr/ev_posix.h"
 #include "src/core/lib/iomgr/port.h"
 
-#ifdef __cplusplus
-extern "C" {
-#endif
-
 // a polling engine that utilizes a singleton epoll set and turnstile polling
 
 const grpc_event_engine_vtable* grpc_init_epoll1_linux(bool explicit_request);
 
-#ifdef __cplusplus
-}
-#endif
-
 #endif /* GRPC_CORE_LIB_IOMGR_EV_EPOLL1_LINUX_H */
diff --git a/src/core/lib/iomgr/ev_epollex_linux.cc b/src/core/lib/iomgr/ev_epollex_linux.cc
index bfd2ac4..62643df 100644
--- a/src/core/lib/iomgr/ev_epollex_linux.cc
+++ b/src/core/lib/iomgr/ev_epollex_linux.cc
@@ -59,10 +59,8 @@
 #define MAX_EPOLL_EVENTS 100
 #define MAX_EPOLL_EVENTS_HANDLED_EACH_POLL_CALL 5
 
-#ifndef NDEBUG
-grpc_tracer_flag grpc_trace_pollable_refcount =
-    GRPC_TRACER_INITIALIZER(false, "pollable_refcount");
-#endif
+grpc_core::DebugOnlyTraceFlag grpc_trace_pollable_refcount(false,
+                                                           "pollable_refcount");
 
 /*******************************************************************************
  * pollable Declarations
@@ -263,7 +261,7 @@
   unref_by(ec, fd, n, reason, __FILE__, __LINE__)
 static void ref_by(grpc_fd* fd, int n, const char* reason, const char* file,
                    int line) {
-  if (GRPC_TRACER_ON(grpc_trace_fd_refcount)) {
+  if (grpc_trace_fd_refcount.enabled()) {
     gpr_log(GPR_DEBUG,
             "FD %d %p   ref %d %" PRIdPTR " -> %" PRIdPTR " [%s; %s:%d]",
             fd->fd, fd, n, gpr_atm_no_barrier_load(&fd->refst),
@@ -288,8 +286,8 @@
   fd->freelist_next = fd_freelist;
   fd_freelist = fd;
 
-  fd->read_closure.Destroy();
-  fd->write_closure.Destroy();
+  fd->read_closure->DestroyEvent();
+  fd->write_closure->DestroyEvent();
 
   gpr_mu_unlock(&fd_freelist_mu);
 }
@@ -297,7 +295,7 @@
 #ifndef NDEBUG
 static void unref_by(grpc_exec_ctx* exec_ctx, grpc_fd* fd, int n,
                      const char* reason, const char* file, int line) {
-  if (GRPC_TRACER_ON(grpc_trace_fd_refcount)) {
+  if (grpc_trace_fd_refcount.enabled()) {
     gpr_log(GPR_DEBUG,
             "FD %d %p unref %d %" PRIdPTR " -> %" PRIdPTR " [%s; %s:%d]",
             fd->fd, fd, n, gpr_atm_no_barrier_load(&fd->refst),
@@ -342,6 +340,8 @@
 
   if (new_fd == nullptr) {
     new_fd = (grpc_fd*)gpr_malloc(sizeof(grpc_fd));
+    new_fd->read_closure.Init();
+    new_fd->write_closure.Init();
   }
 
   gpr_mu_init(&new_fd->pollable_mu);
@@ -349,8 +349,8 @@
   new_fd->pollable_obj = nullptr;
   gpr_atm_rel_store(&new_fd->refst, (gpr_atm)1);
   new_fd->fd = fd;
-  new_fd->read_closure.Init();
-  new_fd->write_closure.Init();
+  new_fd->read_closure->InitEvent();
+  new_fd->write_closure->InitEvent();
   gpr_atm_no_barrier_store(&new_fd->read_notifier_pollset, (gpr_atm)NULL);
 
   new_fd->freelist_next = nullptr;
@@ -360,7 +360,7 @@
   gpr_asprintf(&fd_name, "%s fd=%d", name, fd);
   grpc_iomgr_register_object(&new_fd->iomgr_object, fd_name);
 #ifndef NDEBUG
-  if (GRPC_TRACER_ON(grpc_trace_fd_refcount)) {
+  if (grpc_trace_fd_refcount.enabled()) {
     gpr_log(GPR_DEBUG, "FD %d %p create %s", fd, new_fd, fd_name);
   }
 #endif
@@ -483,7 +483,7 @@
 static pollable* pollable_ref(pollable* p) {
 #else
 static pollable* pollable_ref(pollable* p, int line, const char* reason) {
-  if (GRPC_TRACER_ON(grpc_trace_pollable_refcount)) {
+  if (grpc_trace_pollable_refcount.enabled()) {
     int r = (int)gpr_atm_no_barrier_load(&p->refs.count);
     gpr_log(__FILE__, line, GPR_LOG_SEVERITY_DEBUG,
             "POLLABLE:%p   ref %d->%d %s", p, r, r + 1, reason);
@@ -498,7 +498,7 @@
 #else
 static void pollable_unref(pollable* p, int line, const char* reason) {
   if (p == nullptr) return;
-  if (GRPC_TRACER_ON(grpc_trace_pollable_refcount)) {
+  if (grpc_trace_pollable_refcount.enabled()) {
     int r = (int)gpr_atm_no_barrier_load(&p->refs.count);
     gpr_log(__FILE__, line, GPR_LOG_SEVERITY_DEBUG,
             "POLLABLE:%p unref %d->%d %s", p, r, r - 1, reason);
@@ -516,7 +516,7 @@
   static const char* err_desc = "pollable_add_fd";
   const int epfd = p->epfd;
 
-  if (GRPC_TRACER_ON(grpc_polling_trace)) {
+  if (grpc_polling_trace.enabled()) {
     gpr_log(GPR_DEBUG, "add fd %p (%d) to pollable %p", fd, fd->fd, p);
   }
 
@@ -558,7 +558,7 @@
 /* pollset->mu must be held while calling this function */
 static void pollset_maybe_finish_shutdown(grpc_exec_ctx* exec_ctx,
                                           grpc_pollset* pollset) {
-  if (GRPC_TRACER_ON(grpc_polling_trace)) {
+  if (grpc_polling_trace.enabled()) {
     gpr_log(GPR_DEBUG,
             "PS:%p (pollable:%p) maybe_finish_shutdown sc=%p (target:!NULL) "
             "rw=%p (target:NULL) cpsc=%d (target:0)",
@@ -581,14 +581,14 @@
   grpc_core::mu_guard lock(&p->mu);
   GPR_ASSERT(specific_worker != nullptr);
   if (specific_worker->kicked) {
-    if (GRPC_TRACER_ON(grpc_polling_trace)) {
+    if (grpc_polling_trace.enabled()) {
       gpr_log(GPR_DEBUG, "PS:%p kicked_specific_but_already_kicked", p);
     }
     GRPC_STATS_INC_POLLSET_KICKED_AGAIN(exec_ctx);
     return GRPC_ERROR_NONE;
   }
   if (gpr_tls_get(&g_current_thread_worker) == (intptr_t)specific_worker) {
-    if (GRPC_TRACER_ON(grpc_polling_trace)) {
+    if (grpc_polling_trace.enabled()) {
       gpr_log(GPR_DEBUG, "PS:%p kicked_specific_but_awake", p);
     }
     GRPC_STATS_INC_POLLSET_KICK_OWN_THREAD(exec_ctx);
@@ -597,7 +597,7 @@
   }
   if (specific_worker == p->root_worker) {
     GRPC_STATS_INC_POLLSET_KICK_WAKEUP_FD(exec_ctx);
-    if (GRPC_TRACER_ON(grpc_polling_trace)) {
+    if (grpc_polling_trace.enabled()) {
       gpr_log(GPR_DEBUG, "PS:%p kicked_specific_via_wakeup_fd", p);
     }
     specific_worker->kicked = true;
@@ -606,7 +606,7 @@
   }
   if (specific_worker->initialized_cv) {
     GRPC_STATS_INC_POLLSET_KICK_WAKEUP_CV(exec_ctx);
-    if (GRPC_TRACER_ON(grpc_polling_trace)) {
+    if (grpc_polling_trace.enabled()) {
       gpr_log(GPR_DEBUG, "PS:%p kicked_specific_via_cv", p);
     }
     specific_worker->kicked = true;
@@ -621,7 +621,7 @@
 static grpc_error* pollset_kick(grpc_exec_ctx* exec_ctx, grpc_pollset* pollset,
                                 grpc_pollset_worker* specific_worker) {
   GRPC_STATS_INC_POLLSET_KICK(exec_ctx);
-  if (GRPC_TRACER_ON(grpc_polling_trace)) {
+  if (grpc_polling_trace.enabled()) {
     gpr_log(GPR_DEBUG,
             "PS:%p kick %p tls_pollset=%p tls_worker=%p pollset.root_worker=%p",
             pollset, specific_worker,
@@ -631,7 +631,7 @@
   if (specific_worker == nullptr) {
     if (gpr_tls_get(&g_current_thread_pollset) != (intptr_t)pollset) {
       if (pollset->root_worker == nullptr) {
-        if (GRPC_TRACER_ON(grpc_polling_trace)) {
+        if (grpc_polling_trace.enabled()) {
           gpr_log(GPR_DEBUG, "PS:%p kicked_any_without_poller", pollset);
         }
         GRPC_STATS_INC_POLLSET_KICKED_WITHOUT_POLLER(exec_ctx);
@@ -657,7 +657,7 @@
             exec_ctx, pollset->root_worker->links[PWLINK_POLLSET].next);
       }
     } else {
-      if (GRPC_TRACER_ON(grpc_polling_trace)) {
+      if (grpc_polling_trace.enabled()) {
         gpr_log(GPR_DEBUG, "PS:%p kicked_any_but_awake", pollset);
       }
       GRPC_STATS_INC_POLLSET_KICK_OWN_THREAD(exec_ctx);
@@ -765,7 +765,7 @@
     struct epoll_event* ev = &pollable_obj->events[n];
     void* data_ptr = ev->data.ptr;
     if (1 & (intptr_t)data_ptr) {
-      if (GRPC_TRACER_ON(grpc_polling_trace)) {
+      if (grpc_polling_trace.enabled()) {
         gpr_log(GPR_DEBUG, "PS:%p got pollset_wakeup %p", pollset, data_ptr);
       }
       append_error(&error,
@@ -777,7 +777,7 @@
       bool cancel = (ev->events & (EPOLLERR | EPOLLHUP)) != 0;
       bool read_ev = (ev->events & (EPOLLIN | EPOLLPRI)) != 0;
       bool write_ev = (ev->events & EPOLLOUT) != 0;
-      if (GRPC_TRACER_ON(grpc_polling_trace)) {
+      if (grpc_polling_trace.enabled()) {
         gpr_log(GPR_DEBUG,
                 "PS:%p got fd %p: cancel=%d read=%d "
                 "write=%d",
@@ -805,7 +805,7 @@
                                   grpc_millis deadline) {
   int timeout = poll_deadline_to_millis_timeout(exec_ctx, deadline);
 
-  if (GRPC_TRACER_ON(grpc_polling_trace)) {
+  if (grpc_polling_trace.enabled()) {
     char* desc = pollable_desc(p);
     gpr_log(GPR_DEBUG, "POLLABLE:%p[%s] poll for %dms", p, desc, timeout);
     gpr_free(desc);
@@ -825,7 +825,7 @@
 
   if (r < 0) return GRPC_OS_ERROR(errno, "epoll_wait");
 
-  if (GRPC_TRACER_ON(grpc_polling_trace)) {
+  if (grpc_polling_trace.enabled()) {
     gpr_log(GPR_DEBUG, "POLLABLE:%p got %d events", p, r);
   }
 
@@ -893,7 +893,7 @@
     worker->initialized_cv = true;
     gpr_cv_init(&worker->cv);
     gpr_mu_unlock(&pollset->mu);
-    if (GRPC_TRACER_ON(grpc_polling_trace) &&
+    if (grpc_polling_trace.enabled() &&
         worker->pollable_obj->root_worker != worker) {
       gpr_log(GPR_DEBUG, "PS:%p wait %p w=%p for %dms", pollset,
               worker->pollable_obj, worker,
@@ -902,18 +902,18 @@
     while (do_poll && worker->pollable_obj->root_worker != worker) {
       if (gpr_cv_wait(&worker->cv, &worker->pollable_obj->mu,
                       grpc_millis_to_timespec(deadline, GPR_CLOCK_REALTIME))) {
-        if (GRPC_TRACER_ON(grpc_polling_trace)) {
+        if (grpc_polling_trace.enabled()) {
           gpr_log(GPR_DEBUG, "PS:%p timeout_wait %p w=%p", pollset,
                   worker->pollable_obj, worker);
         }
         do_poll = false;
       } else if (worker->kicked) {
-        if (GRPC_TRACER_ON(grpc_polling_trace)) {
+        if (grpc_polling_trace.enabled()) {
           gpr_log(GPR_DEBUG, "PS:%p wakeup %p w=%p", pollset,
                   worker->pollable_obj, worker);
         }
         do_poll = false;
-      } else if (GRPC_TRACER_ON(grpc_polling_trace) &&
+      } else if (grpc_polling_trace.enabled() &&
                  worker->pollable_obj->root_worker != worker) {
         gpr_log(GPR_DEBUG, "PS:%p spurious_wakeup %p w=%p", pollset,
                 worker->pollable_obj, worker);
@@ -984,7 +984,7 @@
 #ifndef NDEBUG
   WORKER_PTR->originator = gettid();
 #endif
-  if (GRPC_TRACER_ON(grpc_polling_trace)) {
+  if (grpc_polling_trace.enabled()) {
     gpr_log(GPR_DEBUG,
             "PS:%p work hdl=%p worker=%p now=%" PRIdPTR " deadline=%" PRIdPTR
             " kwp=%d pollable=%p",
@@ -1027,7 +1027,7 @@
     grpc_exec_ctx* exec_ctx, grpc_pollset* pollset, grpc_fd* fd) {
   static const char* err_desc = "pollset_transition_pollable_from_empty_to_fd";
   grpc_error* error = GRPC_ERROR_NONE;
-  if (GRPC_TRACER_ON(grpc_polling_trace)) {
+  if (grpc_polling_trace.enabled()) {
     gpr_log(GPR_DEBUG,
             "PS:%p add fd %p (%d); transition pollable from empty to fd",
             pollset, fd, fd->fd);
@@ -1043,7 +1043,7 @@
     grpc_exec_ctx* exec_ctx, grpc_pollset* pollset, grpc_fd* and_add_fd) {
   static const char* err_desc = "pollset_transition_pollable_from_fd_to_multi";
   grpc_error* error = GRPC_ERROR_NONE;
-  if (GRPC_TRACER_ON(grpc_polling_trace)) {
+  if (grpc_polling_trace.enabled()) {
     gpr_log(
         GPR_DEBUG,
         "PS:%p add fd %p (%d); transition pollable from fd %p to multipoller",
@@ -1193,7 +1193,7 @@
 
 static void pollset_set_add_fd(grpc_exec_ctx* exec_ctx, grpc_pollset_set* pss,
                                grpc_fd* fd) {
-  if (GRPC_TRACER_ON(grpc_polling_trace)) {
+  if (grpc_polling_trace.enabled()) {
     gpr_log(GPR_DEBUG, "PSS:%p: add fd %p (%d)", pss, fd, fd->fd);
   }
   grpc_error* error = GRPC_ERROR_NONE;
@@ -1217,7 +1217,7 @@
 
 static void pollset_set_del_fd(grpc_exec_ctx* exec_ctx, grpc_pollset_set* pss,
                                grpc_fd* fd) {
-  if (GRPC_TRACER_ON(grpc_polling_trace)) {
+  if (grpc_polling_trace.enabled()) {
     gpr_log(GPR_DEBUG, "PSS:%p: del fd %p", pss, fd);
   }
   pss = pss_lock_adam(pss);
@@ -1238,7 +1238,7 @@
 
 static void pollset_set_del_pollset(grpc_exec_ctx* exec_ctx,
                                     grpc_pollset_set* pss, grpc_pollset* ps) {
-  if (GRPC_TRACER_ON(grpc_polling_trace)) {
+  if (grpc_polling_trace.enabled()) {
     gpr_log(GPR_DEBUG, "PSS:%p: del pollset %p", pss, ps);
   }
   pss = pss_lock_adam(pss);
@@ -1289,7 +1289,7 @@
 
 static void pollset_set_add_pollset(grpc_exec_ctx* exec_ctx,
                                     grpc_pollset_set* pss, grpc_pollset* ps) {
-  if (GRPC_TRACER_ON(grpc_polling_trace)) {
+  if (grpc_polling_trace.enabled()) {
     gpr_log(GPR_DEBUG, "PSS:%p: add pollset %p", pss, ps);
   }
   grpc_error* error = GRPC_ERROR_NONE;
@@ -1326,7 +1326,7 @@
 static void pollset_set_add_pollset_set(grpc_exec_ctx* exec_ctx,
                                         grpc_pollset_set* a,
                                         grpc_pollset_set* b) {
-  if (GRPC_TRACER_ON(grpc_polling_trace)) {
+  if (grpc_polling_trace.enabled()) {
     gpr_log(GPR_DEBUG, "PSS: merge (%p, %p)", a, b);
   }
   grpc_error* error = GRPC_ERROR_NONE;
@@ -1360,7 +1360,7 @@
   if (b_size > a_size) {
     GPR_SWAP(grpc_pollset_set*, a, b);
   }
-  if (GRPC_TRACER_ON(grpc_polling_trace)) {
+  if (grpc_polling_trace.enabled()) {
     gpr_log(GPR_DEBUG, "PSS: parent %p to %p", b, a);
   }
   gpr_ref(&a->refs);
@@ -1461,10 +1461,6 @@
     return nullptr;
   }
 
-#ifndef NDEBUG
-  grpc_register_tracer(&grpc_trace_pollable_refcount);
-#endif
-
   fd_global_init();
 
   if (!GRPC_LOG_IF_ERROR("pollset_global_init", pollset_global_init())) {
diff --git a/src/core/lib/iomgr/ev_epollex_linux.h b/src/core/lib/iomgr/ev_epollex_linux.h
index 22b536c..ffa7fc7 100644
--- a/src/core/lib/iomgr/ev_epollex_linux.h
+++ b/src/core/lib/iomgr/ev_epollex_linux.h
@@ -22,15 +22,7 @@
 #include "src/core/lib/iomgr/ev_posix.h"
 #include "src/core/lib/iomgr/port.h"
 
-#ifdef __cplusplus
-extern "C" {
-#endif
-
 const grpc_event_engine_vtable* grpc_init_epollex_linux(
     bool explicitly_requested);
 
-#ifdef __cplusplus
-}
-#endif
-
 #endif /* GRPC_CORE_LIB_IOMGR_EV_EPOLLEX_LINUX_H */
diff --git a/src/core/lib/iomgr/ev_epollsig_linux.cc b/src/core/lib/iomgr/ev_epollsig_linux.cc
index 5b4a7ba..12c8483 100644
--- a/src/core/lib/iomgr/ev_epollsig_linux.cc
+++ b/src/core/lib/iomgr/ev_epollsig_linux.cc
@@ -54,9 +54,9 @@
 
 #define GRPC_POLLSET_KICK_BROADCAST ((grpc_pollset_worker*)1)
 
-#define GRPC_POLLING_TRACE(...)             \
-  if (GRPC_TRACER_ON(grpc_polling_trace)) { \
-    gpr_log(GPR_INFO, __VA_ARGS__);         \
+#define GRPC_POLLING_TRACE(...)       \
+  if (grpc_polling_trace.enabled()) { \
+    gpr_log(GPR_INFO, __VA_ARGS__);   \
   }
 
 static int grpc_wakeup_signal = -1;
@@ -289,7 +289,7 @@
 #ifndef NDEBUG
 static void pi_add_ref_dbg(polling_island* pi, const char* reason,
                            const char* file, int line) {
-  if (GRPC_TRACER_ON(grpc_polling_trace)) {
+  if (grpc_polling_trace.enabled()) {
     gpr_atm old_cnt = gpr_atm_acq_load(&pi->ref_count);
     gpr_log(GPR_DEBUG,
             "Add ref pi: %p, old:%" PRIdPTR " -> new:%" PRIdPTR
@@ -301,7 +301,7 @@
 
 static void pi_unref_dbg(grpc_exec_ctx* exec_ctx, polling_island* pi,
                          const char* reason, const char* file, int line) {
-  if (GRPC_TRACER_ON(grpc_polling_trace)) {
+  if (grpc_polling_trace.enabled()) {
     gpr_atm old_cnt = gpr_atm_acq_load(&pi->ref_count);
     gpr_log(GPR_DEBUG,
             "Unref pi: %p, old:%" PRIdPTR " -> new:%" PRIdPTR
@@ -733,7 +733,7 @@
 #define UNREF_BY(fd, n, reason) unref_by(fd, n, reason, __FILE__, __LINE__)
 static void ref_by(grpc_fd* fd, int n, const char* reason, const char* file,
                    int line) {
-  if (GRPC_TRACER_ON(grpc_trace_fd_refcount)) {
+  if (grpc_trace_fd_refcount.enabled()) {
     gpr_log(GPR_DEBUG,
             "FD %d %p   ref %d %" PRIdPTR " -> %" PRIdPTR " [%s; %s:%d]",
             fd->fd, fd, n, gpr_atm_no_barrier_load(&fd->refst),
@@ -750,7 +750,7 @@
 #ifndef NDEBUG
 static void unref_by(grpc_fd* fd, int n, const char* reason, const char* file,
                      int line) {
-  if (GRPC_TRACER_ON(grpc_trace_fd_refcount)) {
+  if (grpc_trace_fd_refcount.enabled()) {
     gpr_log(GPR_DEBUG,
             "FD %d %p unref %d %" PRIdPTR " -> %" PRIdPTR " [%s; %s:%d]",
             fd->fd, fd, n, gpr_atm_no_barrier_load(&fd->refst),
@@ -767,8 +767,8 @@
     fd_freelist = fd;
     grpc_iomgr_unregister_object(&fd->iomgr_object);
 
-    fd->read_closure.Destroy();
-    fd->write_closure.Destroy();
+    fd->read_closure->DestroyEvent();
+    fd->write_closure->DestroyEvent();
 
     gpr_mu_unlock(&fd_freelist_mu);
   } else {
@@ -819,6 +819,8 @@
   if (new_fd == nullptr) {
     new_fd = (grpc_fd*)gpr_malloc(sizeof(grpc_fd));
     gpr_mu_init(&new_fd->po.mu);
+    new_fd->read_closure.Init();
+    new_fd->write_closure.Init();
   }
 
   /* Note: It is not really needed to get the new_fd->po.mu lock here. If this
@@ -833,8 +835,8 @@
   gpr_atm_rel_store(&new_fd->refst, (gpr_atm)1);
   new_fd->fd = fd;
   new_fd->orphaned = false;
-  new_fd->read_closure.Init();
-  new_fd->write_closure.Init();
+  new_fd->read_closure->InitEvent();
+  new_fd->write_closure->InitEvent();
   gpr_atm_no_barrier_store(&new_fd->read_notifier_pollset, (gpr_atm)NULL);
 
   new_fd->freelist_next = nullptr;
diff --git a/src/core/lib/iomgr/ev_epollsig_linux.h b/src/core/lib/iomgr/ev_epollsig_linux.h
index ca68595..5b8aba9 100644
--- a/src/core/lib/iomgr/ev_epollsig_linux.h
+++ b/src/core/lib/iomgr/ev_epollsig_linux.h
@@ -22,10 +22,6 @@
 #include "src/core/lib/iomgr/ev_posix.h"
 #include "src/core/lib/iomgr/port.h"
 
-#ifdef __cplusplus
-extern "C" {
-#endif
-
 const grpc_event_engine_vtable* grpc_init_epollsig_linux(bool explicit_request);
 
 #ifdef GRPC_LINUX_EPOLL
@@ -34,8 +30,4 @@
 bool grpc_are_polling_islands_equal(void* p, void* q);
 #endif /* defined(GRPC_LINUX_EPOLL) */
 
-#ifdef __cplusplus
-}
-#endif
-
 #endif /* GRPC_CORE_LIB_IOMGR_EV_EPOLLSIG_LINUX_H */
diff --git a/src/core/lib/iomgr/ev_poll_posix.cc b/src/core/lib/iomgr/ev_poll_posix.cc
index f8b9629..8659559 100644
--- a/src/core/lib/iomgr/ev_poll_posix.cc
+++ b/src/core/lib/iomgr/ev_poll_posix.cc
@@ -288,7 +288,7 @@
 #define UNREF_BY(fd, n, reason) unref_by(fd, n, reason, __FILE__, __LINE__)
 static void ref_by(grpc_fd* fd, int n, const char* reason, const char* file,
                    int line) {
-  if (GRPC_TRACER_ON(grpc_trace_fd_refcount)) {
+  if (grpc_trace_fd_refcount.enabled()) {
     gpr_log(GPR_DEBUG,
             "FD %d %p   ref %d %" PRIdPTR " -> %" PRIdPTR " [%s; %s:%d]",
             fd->fd, fd, n, gpr_atm_no_barrier_load(&fd->refst),
@@ -305,7 +305,7 @@
 #ifndef NDEBUG
 static void unref_by(grpc_fd* fd, int n, const char* reason, const char* file,
                      int line) {
-  if (GRPC_TRACER_ON(grpc_trace_fd_refcount)) {
+  if (grpc_trace_fd_refcount.enabled()) {
     gpr_log(GPR_DEBUG,
             "FD %d %p unref %d %" PRIdPTR " -> %" PRIdPTR " [%s; %s:%d]",
             fd->fd, fd, n, gpr_atm_no_barrier_load(&fd->refst),
@@ -992,7 +992,7 @@
       r = grpc_poll_function(pfds, pfd_count, timeout);
       GRPC_SCHEDULING_END_BLOCKING_REGION_WITH_EXEC_CTX(exec_ctx);
 
-      if (GRPC_TRACER_ON(grpc_polling_trace)) {
+      if (grpc_polling_trace.enabled()) {
         gpr_log(GPR_DEBUG, "%p poll=%d", pollset, r);
       }
 
@@ -1016,7 +1016,7 @@
         }
       } else {
         if (pfds[0].revents & POLLIN_CHECK) {
-          if (GRPC_TRACER_ON(grpc_polling_trace)) {
+          if (grpc_polling_trace.enabled()) {
             gpr_log(GPR_DEBUG, "%p: got_wakeup", pollset);
           }
           work_combine_error(
@@ -1026,7 +1026,7 @@
           if (watchers[i].fd == nullptr) {
             fd_end_poll(exec_ctx, &watchers[i], 0, 0, nullptr);
           } else {
-            if (GRPC_TRACER_ON(grpc_polling_trace)) {
+            if (grpc_polling_trace.enabled()) {
               gpr_log(GPR_DEBUG, "%p got_event: %d r:%d w:%d [%d]", pollset,
                       pfds[i].fd, (pfds[i].revents & POLLIN_CHECK) != 0,
                       (pfds[i].revents & POLLOUT_CHECK) != 0, pfds[i].revents);
diff --git a/src/core/lib/iomgr/ev_poll_posix.h b/src/core/lib/iomgr/ev_poll_posix.h
index 626e95b..f6bc624 100644
--- a/src/core/lib/iomgr/ev_poll_posix.h
+++ b/src/core/lib/iomgr/ev_poll_posix.h
@@ -21,15 +21,7 @@
 
 #include "src/core/lib/iomgr/ev_posix.h"
 
-#ifdef __cplusplus
-extern "C" {
-#endif
-
 const grpc_event_engine_vtable* grpc_init_poll_posix(bool explicit_request);
 const grpc_event_engine_vtable* grpc_init_poll_cv_posix(bool explicit_request);
 
-#ifdef __cplusplus
-}
-#endif
-
 #endif /* GRPC_CORE_LIB_IOMGR_EV_POLL_POSIX_H */
diff --git a/src/core/lib/iomgr/ev_posix.cc b/src/core/lib/iomgr/ev_posix.cc
index 076d2e6..031c975 100644
--- a/src/core/lib/iomgr/ev_posix.cc
+++ b/src/core/lib/iomgr/ev_posix.cc
@@ -36,13 +36,9 @@
 #include "src/core/lib/iomgr/ev_poll_posix.h"
 #include "src/core/lib/support/env.h"
 
-grpc_tracer_flag grpc_polling_trace =
-    GRPC_TRACER_INITIALIZER(false, "polling"); /* Disabled by default */
-
-#ifndef NDEBUG
-grpc_tracer_flag grpc_trace_fd_refcount =
-    GRPC_TRACER_INITIALIZER(false, "fd_refcount");
-#endif
+grpc_core::TraceFlag grpc_polling_trace(false,
+                                        "polling"); /* Disabled by default */
+grpc_core::DebugOnlyTraceFlag grpc_trace_fd_refcount(false, "fd_refcount");
 
 /** Default poll() function - a pointer so that it can be overridden by some
  *  tests */
@@ -63,8 +59,6 @@
 
 namespace {
 
-extern "C" {
-
 grpc_poll_function_type real_poll_function;
 
 int dummy_poll(struct pollfd fds[], nfds_t nfds, int timeout) {
@@ -76,7 +70,6 @@
     return -1;
   }
 }
-}  // extern "C"
 
 const grpc_event_engine_vtable* init_non_polling(bool explicit_request) {
   if (!explicit_request) {
@@ -153,8 +146,6 @@
 const char* grpc_get_poll_strategy_name() { return g_poll_strategy_name; }
 
 void grpc_event_engine_init(void) {
-  grpc_register_tracer(&grpc_polling_trace);
-
   char* s = gpr_getenv("GRPC_POLL_STRATEGY");
   if (s == nullptr) {
     s = gpr_strdup("all");
diff --git a/src/core/lib/iomgr/ev_posix.h b/src/core/lib/iomgr/ev_posix.h
index d719b8f..16fa10c 100644
--- a/src/core/lib/iomgr/ev_posix.h
+++ b/src/core/lib/iomgr/ev_posix.h
@@ -27,11 +27,7 @@
 #include "src/core/lib/iomgr/pollset_set.h"
 #include "src/core/lib/iomgr/wakeup_fd_posix.h"
 
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-extern grpc_tracer_flag grpc_polling_trace; /* Disabled by default */
+extern grpc_core::TraceFlag grpc_polling_trace; /* Disabled by default */
 
 typedef struct grpc_fd grpc_fd;
 
@@ -162,8 +158,4 @@
 void grpc_set_event_engine_test_only(const grpc_event_engine_vtable*);
 const grpc_event_engine_vtable* grpc_get_event_engine_test_only();
 
-#ifdef __cplusplus
-}
-#endif
-
 #endif /* GRPC_CORE_LIB_IOMGR_EV_POSIX_H */
diff --git a/src/core/lib/iomgr/ev_windows.cc b/src/core/lib/iomgr/ev_windows.cc
index c24dfae..697697d 100644
--- a/src/core/lib/iomgr/ev_windows.cc
+++ b/src/core/lib/iomgr/ev_windows.cc
@@ -22,7 +22,7 @@
 
 #include "src/core/lib/debug/trace.h"
 
-grpc_tracer_flag grpc_polling_trace =
-    GRPC_TRACER_INITIALIZER(false, "polling"); /* Disabled by default */
+grpc_core::TraceFlag grpc_polling_trace(false,
+                                        "polling"); /* Disabled by default */
 
 #endif  // GRPC_WINSOCK_SOCKET
diff --git a/src/core/lib/iomgr/exec_ctx.cc b/src/core/lib/iomgr/exec_ctx.cc
index 27c769a..1777456 100644
--- a/src/core/lib/iomgr/exec_ctx.cc
+++ b/src/core/lib/iomgr/exec_ctx.cc
@@ -25,9 +25,6 @@
 #include "src/core/lib/iomgr/combiner.h"
 #include "src/core/lib/profiling/timers.h"
 
-#define GRPC_START_TIME_UPDATE_INTERVAL 10000
-extern "C" grpc_tracer_flag grpc_timer_check_trace;
-
 bool grpc_exec_ctx_ready_to_finish(grpc_exec_ctx* exec_ctx) {
   if ((exec_ctx->flags & GRPC_EXEC_CTX_FLAG_IS_FINISHED) == 0) {
     if (exec_ctx->check_ready_to_finish(exec_ctx,
@@ -63,7 +60,7 @@
                          grpc_error* error) {
 #ifndef NDEBUG
   closure->scheduled = false;
-  if (GRPC_TRACER_ON(grpc_trace_closure)) {
+  if (grpc_trace_closure.enabled()) {
     gpr_log(GPR_DEBUG, "running closure %p: created [%s:%d]: %s [%s:%d]",
             closure, closure->file_created, closure->line_created,
             closure->run ? "run" : "scheduled", closure->file_initiated,
@@ -72,7 +69,7 @@
 #endif
   closure->cb(exec_ctx, closure->cb_arg, error);
 #ifndef NDEBUG
-  if (GRPC_TRACER_ON(grpc_trace_closure)) {
+  if (grpc_trace_closure.enabled()) {
     gpr_log(GPR_DEBUG, "closure %p finished", closure);
   }
 #endif
@@ -107,49 +104,16 @@
   grpc_closure_list_append(&exec_ctx->closure_list, closure, error);
 }
 
-/* This time pair is not entirely thread-safe as store/load of tv_sec and
- * tv_nsec are performed separately. However g_start_time do not need to have
- * sub-second precision, so it is ok if the value of tv_nsec is off in this
- * case. */
-typedef struct time_atm_pair {
-  gpr_atm tv_sec;
-  gpr_atm tv_nsec;
-} time_atm_pair;
-
-static time_atm_pair
-    g_start_time[GPR_TIMESPAN + 1];  // assumes GPR_TIMESPAN is the
-                                     // last enum value in
-                                     // gpr_clock_type
-static grpc_millis g_last_start_time_update;
-
-static gpr_timespec timespec_from_time_atm_pair(const time_atm_pair* src,
-                                                gpr_clock_type clock_type) {
-  gpr_timespec time;
-  time.tv_nsec = (int32_t)gpr_atm_no_barrier_load(&src->tv_nsec);
-  time.tv_sec = (int64_t)gpr_atm_no_barrier_load(&src->tv_sec);
-  time.clock_type = clock_type;
-  return time;
-}
-
-static void time_atm_pair_store(time_atm_pair* dst, const gpr_timespec src) {
-  gpr_atm_no_barrier_store(&dst->tv_sec, src.tv_sec);
-  gpr_atm_no_barrier_store(&dst->tv_nsec, src.tv_nsec);
-}
+static gpr_timespec g_start_time;
 
 void grpc_exec_ctx_global_init(void) {
-  for (int i = 0; i < GPR_TIMESPAN; i++) {
-    time_atm_pair_store(&g_start_time[i], gpr_now((gpr_clock_type)i));
-  }
-  // allows uniform treatment in conversion functions
-  time_atm_pair_store(&g_start_time[GPR_TIMESPAN], gpr_time_0(GPR_TIMESPAN));
+  g_start_time = gpr_now(GPR_CLOCK_MONOTONIC);
 }
 
 void grpc_exec_ctx_global_shutdown(void) {}
 
 static gpr_atm timespec_to_atm_round_down(gpr_timespec ts) {
-  gpr_timespec start_time =
-      timespec_from_time_atm_pair(&g_start_time[ts.clock_type], ts.clock_type);
-  ts = gpr_time_sub(ts, start_time);
+  ts = gpr_time_sub(ts, g_start_time);
   double x =
       GPR_MS_PER_SEC * (double)ts.tv_sec + (double)ts.tv_nsec / GPR_NS_PER_MS;
   if (x < 0) return 0;
@@ -158,9 +122,7 @@
 }
 
 static gpr_atm timespec_to_atm_round_up(gpr_timespec ts) {
-  gpr_timespec start_time =
-      timespec_from_time_atm_pair(&g_start_time[ts.clock_type], ts.clock_type);
-  ts = gpr_time_sub(ts, start_time);
+  ts = gpr_time_sub(ts, g_start_time);
   double x = GPR_MS_PER_SEC * (double)ts.tv_sec +
              (double)ts.tv_nsec / GPR_NS_PER_MS +
              (double)(GPR_NS_PER_SEC - 1) / (double)GPR_NS_PER_SEC;
@@ -195,41 +157,18 @@
   if (clock_type == GPR_TIMESPAN) {
     return gpr_time_from_millis(millis, GPR_TIMESPAN);
   }
-  gpr_timespec start_time =
-      timespec_from_time_atm_pair(&g_start_time[clock_type], clock_type);
-  return gpr_time_add(start_time, gpr_time_from_millis(millis, GPR_TIMESPAN));
+  return gpr_time_add(gpr_convert_clock_type(g_start_time, clock_type),
+                      gpr_time_from_millis(millis, GPR_TIMESPAN));
 }
 
 grpc_millis grpc_timespec_to_millis_round_down(gpr_timespec ts) {
-  return timespec_to_atm_round_down(ts);
+  return timespec_to_atm_round_down(
+      gpr_convert_clock_type(ts, g_start_time.clock_type));
 }
 
 grpc_millis grpc_timespec_to_millis_round_up(gpr_timespec ts) {
-  return timespec_to_atm_round_up(ts);
-}
-
-void grpc_exec_ctx_maybe_update_start_time(grpc_exec_ctx* exec_ctx) {
-  grpc_millis now = grpc_exec_ctx_now(exec_ctx);
-  grpc_millis last_start_time_update =
-      gpr_atm_no_barrier_load(&g_last_start_time_update);
-
-  if (now > last_start_time_update &&
-      now - last_start_time_update > GRPC_START_TIME_UPDATE_INTERVAL) {
-    /* Get the current system time and subtract \a now from it, where \a now is
-     * the relative time from grpc_init() from monotonic clock. This calibrates
-     * the time when grpc_exec_ctx_global_init was called based on current
-     * system clock. */
-    gpr_atm_no_barrier_store(&g_last_start_time_update, now);
-    gpr_timespec real_now = gpr_now(GPR_CLOCK_REALTIME);
-    gpr_timespec real_start_time =
-        gpr_time_sub(real_now, gpr_time_from_millis(now, GPR_TIMESPAN));
-    time_atm_pair_store(&g_start_time[GPR_CLOCK_REALTIME], real_start_time);
-
-    if (GRPC_TRACER_ON(grpc_timer_check_trace)) {
-      gpr_log(GPR_DEBUG, "Update realtime clock start time: %" PRId64 "s %dns",
-              real_start_time.tv_sec, real_start_time.tv_nsec);
-    }
-  }
+  return timespec_to_atm_round_up(
+      gpr_convert_clock_type(ts, g_start_time.clock_type));
 }
 
 static const grpc_closure_scheduler_vtable exec_ctx_scheduler_vtable = {
diff --git a/src/core/lib/iomgr/exec_ctx.h b/src/core/lib/iomgr/exec_ctx.h
index 6035e08..b415d2c 100644
--- a/src/core/lib/iomgr/exec_ctx.h
+++ b/src/core/lib/iomgr/exec_ctx.h
@@ -24,10 +24,6 @@
 
 #include "src/core/lib/iomgr/closure.h"
 
-#ifdef __cplusplus
-extern "C" {
-#endif
-
 typedef gpr_atm grpc_millis;
 
 #define GRPC_MILLIS_INF_FUTURE GPR_ATM_MAX
@@ -124,10 +120,4 @@
 grpc_millis grpc_timespec_to_millis_round_down(gpr_timespec timespec);
 grpc_millis grpc_timespec_to_millis_round_up(gpr_timespec timespec);
 
-void grpc_exec_ctx_maybe_update_start_time(grpc_exec_ctx* exec_ctx);
-
-#ifdef __cplusplus
-}
-#endif
-
 #endif /* GRPC_CORE_LIB_IOMGR_EXEC_CTX_H */
diff --git a/src/core/lib/iomgr/executor.cc b/src/core/lib/iomgr/executor.cc
index 6097d66..d8a195f 100644
--- a/src/core/lib/iomgr/executor.cc
+++ b/src/core/lib/iomgr/executor.cc
@@ -51,8 +51,7 @@
 
 GPR_TLS_DECL(g_this_thread_state);
 
-static grpc_tracer_flag executor_trace =
-    GRPC_TRACER_INITIALIZER(false, "executor");
+grpc_core::TraceFlag executor_trace(false, "executor");
 
 static void executor_thread(void* arg);
 
@@ -63,7 +62,7 @@
   while (c != nullptr) {
     grpc_closure* next = c->next_data.next;
     grpc_error* error = c->error_data.error;
-    if (GRPC_TRACER_ON(executor_trace)) {
+    if (executor_trace.enabled()) {
 #ifndef NDEBUG
       gpr_log(GPR_DEBUG, "EXECUTOR: run %p [created by %s:%d]", c,
               c->file_created, c->line_created);
@@ -134,7 +133,6 @@
 }
 
 void grpc_executor_init(grpc_exec_ctx* exec_ctx) {
-  grpc_register_tracer(&executor_trace);
   gpr_atm_no_barrier_store(&g_cur_threads, 0);
   grpc_executor_set_threading(exec_ctx, true);
 }
@@ -152,7 +150,7 @@
 
   size_t subtract_depth = 0;
   for (;;) {
-    if (GRPC_TRACER_ON(executor_trace)) {
+    if (executor_trace.enabled()) {
       gpr_log(GPR_DEBUG, "EXECUTOR[%d]: step (sub_depth=%" PRIdPTR ")",
               (int)(ts - g_thread_state), subtract_depth);
     }
@@ -163,7 +161,7 @@
       gpr_cv_wait(&ts->cv, &ts->mu, gpr_inf_future(GPR_CLOCK_REALTIME));
     }
     if (ts->shutdown) {
-      if (GRPC_TRACER_ON(executor_trace)) {
+      if (executor_trace.enabled()) {
         gpr_log(GPR_DEBUG, "EXECUTOR[%d]: shutdown",
                 (int)(ts - g_thread_state));
       }
@@ -174,7 +172,7 @@
     grpc_closure_list exec = ts->elems;
     ts->elems = GRPC_CLOSURE_LIST_INIT;
     gpr_mu_unlock(&ts->mu);
-    if (GRPC_TRACER_ON(executor_trace)) {
+    if (executor_trace.enabled()) {
       gpr_log(GPR_DEBUG, "EXECUTOR[%d]: execute", (int)(ts - g_thread_state));
     }
 
@@ -196,7 +194,7 @@
     retry_push = false;
     size_t cur_thread_count = (size_t)gpr_atm_no_barrier_load(&g_cur_threads);
     if (cur_thread_count == 0) {
-      if (GRPC_TRACER_ON(executor_trace)) {
+      if (executor_trace.enabled()) {
 #ifndef NDEBUG
         gpr_log(GPR_DEBUG, "EXECUTOR: schedule %p (created %s:%d) inline",
                 closure, closure->file_created, closure->line_created);
@@ -217,7 +215,7 @@
 
     bool try_new_thread;
     for (;;) {
-      if (GRPC_TRACER_ON(executor_trace)) {
+      if (executor_trace.enabled()) {
 #ifndef NDEBUG
         gpr_log(
             GPR_DEBUG,
diff --git a/src/core/lib/iomgr/executor.h b/src/core/lib/iomgr/executor.h
index 8418ace..d349083 100644
--- a/src/core/lib/iomgr/executor.h
+++ b/src/core/lib/iomgr/executor.h
@@ -21,10 +21,6 @@
 
 #include "src/core/lib/iomgr/closure.h"
 
-#ifdef __cplusplus
-extern "C" {
-#endif
-
 typedef enum {
   GRPC_EXECUTOR_SHORT,
   GRPC_EXECUTOR_LONG
@@ -49,8 +45,4 @@
    grpc_executor_shutdown */
 void grpc_executor_set_threading(grpc_exec_ctx* exec_ctx, bool enable);
 
-#ifdef __cplusplus
-}
-#endif
-
 #endif /* GRPC_CORE_LIB_IOMGR_EXECUTOR_H */
diff --git a/src/core/lib/iomgr/fork_posix.cc b/src/core/lib/iomgr/fork_posix.cc
new file mode 100644
index 0000000..f3cfd14
--- /dev/null
+++ b/src/core/lib/iomgr/fork_posix.cc
@@ -0,0 +1,90 @@
+/*
+ *
+ * Copyright 2017 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include "src/core/lib/iomgr/port.h"
+
+#ifdef GRPC_POSIX_FORK
+
+#include <string.h>
+
+#include <grpc/fork.h>
+#include <grpc/support/log.h>
+#include <grpc/support/thd.h>
+#include <grpc/support/useful.h>
+
+#include "src/core/lib/iomgr/ev_posix.h"
+#include "src/core/lib/iomgr/executor.h"
+#include "src/core/lib/iomgr/timer_manager.h"
+#include "src/core/lib/iomgr/wakeup_fd_posix.h"
+#include "src/core/lib/support/env.h"
+#include "src/core/lib/support/fork.h"
+#include "src/core/lib/support/thd_internal.h"
+#include "src/core/lib/surface/init.h"
+
+/*
+ * NOTE: FORKING IS NOT GENERALLY SUPPORTED, THIS IS ONLY INTENDED TO WORK
+ *       AROUND VERY SPECIFIC USE CASES.
+ */
+
+void grpc_prefork() {
+  if (!grpc_fork_support_enabled()) {
+    gpr_log(GPR_ERROR,
+            "Fork support not enabled; try running with the "
+            "environment variable GRPC_ENABLE_FORK_SUPPORT=1");
+    return;
+  }
+  if (grpc_is_initialized()) {
+    grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+    grpc_timer_manager_set_threading(false);
+    grpc_executor_set_threading(&exec_ctx, false);
+    grpc_exec_ctx_finish(&exec_ctx);
+    if (!gpr_await_threads(
+            gpr_time_add(gpr_now(GPR_CLOCK_REALTIME),
+                         gpr_time_from_seconds(3, GPR_TIMESPAN)))) {
+      gpr_log(GPR_ERROR, "gRPC thread still active! Cannot fork!");
+    }
+  }
+}
+
+void grpc_postfork_parent() {
+  if (grpc_is_initialized()) {
+    grpc_timer_manager_set_threading(true);
+    grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+    grpc_executor_set_threading(&exec_ctx, true);
+    grpc_exec_ctx_finish(&exec_ctx);
+  }
+}
+
+void grpc_postfork_child() {
+  if (grpc_is_initialized()) {
+    grpc_timer_manager_set_threading(true);
+    grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+    grpc_executor_set_threading(&exec_ctx, true);
+    grpc_exec_ctx_finish(&exec_ctx);
+  }
+}
+
+void grpc_fork_handlers_auto_register() {
+  if (grpc_fork_support_enabled()) {
+#ifdef GRPC_POSIX_FORK_ALLOW_PTHREAD_ATFORK
+    pthread_atfork(grpc_prefork, grpc_postfork_parent, grpc_postfork_child);
+#endif  // GRPC_POSIX_FORK_ALLOW_PTHREAD_ATFORK
+  }
+}
+
+#endif  // GRPC_POSIX_FORK
diff --git a/src/core/lib/iomgr/fork_windows.cc b/src/core/lib/iomgr/fork_windows.cc
new file mode 100644
index 0000000..f9986f3
--- /dev/null
+++ b/src/core/lib/iomgr/fork_windows.cc
@@ -0,0 +1,39 @@
+/*
+ *
+ * Copyright 2017 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include "src/core/lib/iomgr/port.h"
+
+#ifndef GRPC_POSIX_FORK
+
+#include <grpc/fork.h>
+#include <grpc/support/log.h>
+
+/*
+ * NOTE: FORKING IS NOT GENERALLY SUPPORTED, THIS IS ONLY INTENDED TO WORK
+ *       AROUND VERY SPECIFIC USE CASES.
+ */
+
+void grpc_prefork() { gpr_log(GPR_ERROR, "Forking not supported on Windows"); }
+
+void grpc_postfork_parent() {}
+
+void grpc_postfork_child() {}
+
+void grpc_fork_handlers_auto_register() {}
+
+#endif  // GRPC_POSIX_FORK
diff --git a/src/core/lib/iomgr/gethostname.h b/src/core/lib/iomgr/gethostname.h
index 2e65b5f..9f10b4a 100644
--- a/src/core/lib/iomgr/gethostname.h
+++ b/src/core/lib/iomgr/gethostname.h
@@ -19,16 +19,8 @@
 #ifndef GRPC_CORE_LIB_IOMGR_GETHOSTNAME_H
 #define GRPC_CORE_LIB_IOMGR_GETHOSTNAME_H
 
-#ifdef __cplusplus
-extern "C" {
-#endif
-
 // Returns the hostname of the local machine.
 // Caller takes ownership of result.
 char* grpc_gethostname();
 
-#ifdef __cplusplus
-}
-#endif
-
 #endif /* GRPC_CORE_LIB_IOMGR_GETHOSTNAME_H */
diff --git a/src/core/lib/iomgr/iocp_windows.h b/src/core/lib/iomgr/iocp_windows.h
index d112c50..0e9c348 100644
--- a/src/core/lib/iomgr/iocp_windows.h
+++ b/src/core/lib/iomgr/iocp_windows.h
@@ -27,10 +27,6 @@
 
 #include "src/core/lib/iomgr/socket_windows.h"
 
-#ifdef __cplusplus
-extern "C" {
-#endif
-
 typedef enum {
   GRPC_IOCP_WORK_WORK,
   GRPC_IOCP_WORK_TIMEOUT,
@@ -45,10 +41,6 @@
 void grpc_iocp_shutdown(void);
 void grpc_iocp_add_socket(grpc_winsocket*);
 
-#ifdef __cplusplus
-}
-#endif
-
 #endif
 
 #endif /* GRPC_CORE_LIB_IOMGR_IOCP_WINDOWS_H */
diff --git a/src/core/lib/iomgr/iomgr.h b/src/core/lib/iomgr/iomgr.h
index d1549c8..2f00c03 100644
--- a/src/core/lib/iomgr/iomgr.h
+++ b/src/core/lib/iomgr/iomgr.h
@@ -22,10 +22,6 @@
 #include <grpc/impl/codegen/exec_ctx_fwd.h>
 #include "src/core/lib/iomgr/port.h"
 
-#ifdef __cplusplus
-extern "C" {
-#endif
-
 /** Initializes the iomgr. */
 void grpc_iomgr_init(grpc_exec_ctx* exec_ctx);
 
@@ -36,8 +32,4 @@
  * exec_ctx. */
 void grpc_iomgr_shutdown(grpc_exec_ctx* exec_ctx);
 
-#ifdef __cplusplus
-}
-#endif
-
 #endif /* GRPC_CORE_LIB_IOMGR_IOMGR_H */
diff --git a/src/core/lib/iomgr/iomgr_internal.h b/src/core/lib/iomgr/iomgr_internal.h
index b818c68..20b3cb7 100644
--- a/src/core/lib/iomgr/iomgr_internal.h
+++ b/src/core/lib/iomgr/iomgr_internal.h
@@ -23,10 +23,6 @@
 
 #include "src/core/lib/iomgr/iomgr.h"
 
-#ifdef __cplusplus
-extern "C" {
-#endif
-
 typedef struct grpc_iomgr_object {
   char* name;
   struct grpc_iomgr_object* next;
@@ -44,8 +40,4 @@
 
 bool grpc_iomgr_abort_on_leaks(void);
 
-#ifdef __cplusplus
-}
-#endif
-
 #endif /* GRPC_CORE_LIB_IOMGR_IOMGR_INTERNAL_H */
diff --git a/src/core/lib/iomgr/iomgr_posix.cc b/src/core/lib/iomgr/iomgr_posix.cc
index f5875a2..f8f6fe2 100644
--- a/src/core/lib/iomgr/iomgr_posix.cc
+++ b/src/core/lib/iomgr/iomgr_posix.cc
@@ -28,7 +28,6 @@
 void grpc_iomgr_platform_init(void) {
   grpc_wakeup_fd_global_init();
   grpc_event_engine_init();
-  grpc_register_tracer(&grpc_tcp_trace);
 }
 
 void grpc_iomgr_platform_flush(void) {}
diff --git a/src/core/lib/iomgr/iomgr_uv.cc b/src/core/lib/iomgr/iomgr_uv.cc
index df5d23a..b8a10f2 100644
--- a/src/core/lib/iomgr/iomgr_uv.cc
+++ b/src/core/lib/iomgr/iomgr_uv.cc
@@ -31,7 +31,7 @@
 void grpc_iomgr_platform_init(void) {
   grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
   grpc_pollset_global_init();
-  grpc_register_tracer(&grpc_tcp_trace);
+
   grpc_executor_set_threading(&exec_ctx, false);
   g_init_thread = gpr_thd_currentid();
   grpc_exec_ctx_finish(&exec_ctx);
diff --git a/src/core/lib/iomgr/iomgr_uv.h b/src/core/lib/iomgr/iomgr_uv.h
index bc42ca8..3b4daaa 100644
--- a/src/core/lib/iomgr/iomgr_uv.h
+++ b/src/core/lib/iomgr/iomgr_uv.h
@@ -23,18 +23,10 @@
 
 #include <grpc/support/thd.h>
 
-#ifdef __cplusplus
-extern "C" {
-#endif
-
 /* The thread ID of the thread on which grpc was initialized. Used to verify
  * that all calls into libuv are made on that same thread */
 extern gpr_thd_id g_init_thread;
 
-#ifdef __cplusplus
-}
-#endif
-
 #ifdef GRPC_UV_THREAD_CHECK
 #define GRPC_UV_ASSERT_SAME_THREAD() \
   GPR_ASSERT(gpr_thd_currentid() == g_init_thread)
diff --git a/src/core/lib/iomgr/load_file.h b/src/core/lib/iomgr/load_file.h
index 5b367c1..a733652 100644
--- a/src/core/lib/iomgr/load_file.h
+++ b/src/core/lib/iomgr/load_file.h
@@ -25,17 +25,9 @@
 
 #include "src/core/lib/iomgr/error.h"
 
-#ifdef __cplusplus
-extern "C" {
-#endif
-
 /* Loads the content of a file into a slice. add_null_terminator will add
    a NULL terminator if non-zero. */
 grpc_error* grpc_load_file(const char* filename, int add_null_terminator,
                            grpc_slice* slice);
 
-#ifdef __cplusplus
-}
-#endif
-
 #endif /* GRPC_CORE_LIB_IOMGR_LOAD_FILE_H */
diff --git a/src/core/lib/iomgr/lockfree_event.cc b/src/core/lib/iomgr/lockfree_event.cc
index 40e2ed6..f0e798e 100644
--- a/src/core/lib/iomgr/lockfree_event.cc
+++ b/src/core/lib/iomgr/lockfree_event.cc
@@ -22,7 +22,7 @@
 
 #include "src/core/lib/debug/trace.h"
 
-extern grpc_tracer_flag grpc_polling_trace;
+extern grpc_core::TraceFlag grpc_polling_trace;
 
 /* 'state' holds the to call when the fd is readable or writable respectively.
    It can contain one of the following values:
@@ -57,7 +57,9 @@
 
 namespace grpc_core {
 
-LockfreeEvent::LockfreeEvent() {
+LockfreeEvent::LockfreeEvent() { InitEvent(); }
+
+void LockfreeEvent::InitEvent() {
   /* Perform an atomic store to start the state machine.
 
      Note carefully that LockfreeEvent *MAY* be used whilst in a destroyed
@@ -67,7 +69,7 @@
   gpr_atm_no_barrier_store(&state_, kClosureNotReady);
 }
 
-LockfreeEvent::~LockfreeEvent() {
+void LockfreeEvent::DestroyEvent() {
   gpr_atm curr;
   do {
     curr = gpr_atm_no_barrier_load(&state_);
@@ -86,7 +88,7 @@
 void LockfreeEvent::NotifyOn(grpc_exec_ctx* exec_ctx, grpc_closure* closure) {
   while (true) {
     gpr_atm curr = gpr_atm_no_barrier_load(&state_);
-    if (GRPC_TRACER_ON(grpc_polling_trace)) {
+    if (grpc_polling_trace.enabled()) {
       gpr_log(GPR_ERROR, "LockfreeEvent::NotifyOn: %p curr=%p closure=%p", this,
               (void*)curr, closure);
     }
@@ -153,7 +155,7 @@
 
   while (true) {
     gpr_atm curr = gpr_atm_no_barrier_load(&state_);
-    if (GRPC_TRACER_ON(grpc_polling_trace)) {
+    if (grpc_polling_trace.enabled()) {
       gpr_log(GPR_ERROR, "LockfreeEvent::SetShutdown: %p curr=%p err=%s",
               &state_, (void*)curr, grpc_error_string(shutdown_err));
     }
@@ -202,7 +204,7 @@
   while (true) {
     gpr_atm curr = gpr_atm_no_barrier_load(&state_);
 
-    if (GRPC_TRACER_ON(grpc_polling_trace)) {
+    if (grpc_polling_trace.enabled()) {
       gpr_log(GPR_ERROR, "LockfreeEvent::SetReady: %p curr=%p", &state_,
               (void*)curr);
     }
diff --git a/src/core/lib/iomgr/lockfree_event.h b/src/core/lib/iomgr/lockfree_event.h
index c667dcd..aec67a3 100644
--- a/src/core/lib/iomgr/lockfree_event.h
+++ b/src/core/lib/iomgr/lockfree_event.h
@@ -30,11 +30,16 @@
 class LockfreeEvent {
  public:
   LockfreeEvent();
-  ~LockfreeEvent();
 
   LockfreeEvent(const LockfreeEvent&) = delete;
   LockfreeEvent& operator=(const LockfreeEvent&) = delete;
 
+  // These methods are used to initialize and destroy the internal state. These
+  // cannot be done in constructor and destructor because SetReady may be called
+  // when the event is destroyed and put in a freelist.
+  void InitEvent();
+  void DestroyEvent();
+
   bool IsShutdown() const {
     return (gpr_atm_no_barrier_load(&state_) & kShutdownBit) != 0;
   }
diff --git a/src/core/lib/iomgr/polling_entity.h b/src/core/lib/iomgr/polling_entity.h
index 867e085..dbe579e 100644
--- a/src/core/lib/iomgr/polling_entity.h
+++ b/src/core/lib/iomgr/polling_entity.h
@@ -22,10 +22,6 @@
 #include "src/core/lib/iomgr/pollset.h"
 #include "src/core/lib/iomgr/pollset_set.h"
 
-#ifdef __cplusplus
-extern "C" {
-#endif
-
 typedef enum grpc_pollset_tag {
   GRPC_POLLS_NONE,
   GRPC_POLLS_POLLSET,
@@ -68,8 +64,5 @@
 void grpc_polling_entity_del_from_pollset_set(grpc_exec_ctx* exec_ctx,
                                               grpc_polling_entity* pollent,
                                               grpc_pollset_set* pss_dst);
-#ifdef __cplusplus
-}
-#endif
 
 #endif /* GRPC_CORE_LIB_IOMGR_POLLING_ENTITY_H */
diff --git a/src/core/lib/iomgr/pollset.h b/src/core/lib/iomgr/pollset.h
index c99b930..d5d78f3 100644
--- a/src/core/lib/iomgr/pollset.h
+++ b/src/core/lib/iomgr/pollset.h
@@ -25,13 +25,7 @@
 
 #include "src/core/lib/iomgr/exec_ctx.h"
 
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#ifndef NDEBUG
-extern grpc_tracer_flag grpc_trace_fd_refcount;
-#endif
+extern grpc_core::DebugOnlyTraceFlag grpc_trace_fd_refcount;
 
 /* A grpc_pollset is a set of file descriptors that a higher level item is
    interested in. For example:
@@ -84,8 +78,4 @@
                               grpc_pollset_worker* specific_worker)
     GRPC_MUST_USE_RESULT;
 
-#ifdef __cplusplus
-}
-#endif
-
 #endif /* GRPC_CORE_LIB_IOMGR_POLLSET_H */
diff --git a/src/core/lib/iomgr/pollset_set.h b/src/core/lib/iomgr/pollset_set.h
index 0167a50..089c15c 100644
--- a/src/core/lib/iomgr/pollset_set.h
+++ b/src/core/lib/iomgr/pollset_set.h
@@ -21,10 +21,6 @@
 
 #include "src/core/lib/iomgr/pollset.h"
 
-#ifdef __cplusplus
-extern "C" {
-#endif
-
 /* A grpc_pollset_set is a set of pollsets that are interested in an
    action. Adding a pollset to a pollset_set automatically adds any
    fd's (etc) that have been registered with the set_set to that pollset.
@@ -48,8 +44,4 @@
                                       grpc_pollset_set* bag,
                                       grpc_pollset_set* item);
 
-#ifdef __cplusplus
-}
-#endif
-
 #endif /* GRPC_CORE_LIB_IOMGR_POLLSET_SET_H */
diff --git a/src/core/lib/iomgr/pollset_uv.cc b/src/core/lib/iomgr/pollset_uv.cc
index 1d54942..16132f3 100644
--- a/src/core/lib/iomgr/pollset_uv.cc
+++ b/src/core/lib/iomgr/pollset_uv.cc
@@ -34,10 +34,7 @@
 
 #include "src/core/lib/debug/trace.h"
 
-#ifndef NDEBUG
-grpc_tracer_flag grpc_trace_fd_refcount =
-    GRPC_TRACER_INITIALIZER(false, "fd_refcount");
-#endif
+grpc_core::DebugOnlyTraceFlag grpc_trace_fd_refcount(false, "fd_refcount");
 
 struct grpc_pollset {
   uv_timer_t* timer;
diff --git a/src/core/lib/iomgr/pollset_uv.h b/src/core/lib/iomgr/pollset_uv.h
index 5cc9faf..566c110 100644
--- a/src/core/lib/iomgr/pollset_uv.h
+++ b/src/core/lib/iomgr/pollset_uv.h
@@ -19,17 +19,9 @@
 #ifndef GRPC_CORE_LIB_IOMGR_POLLSET_UV_H
 #define GRPC_CORE_LIB_IOMGR_POLLSET_UV_H
 
-#ifdef __cplusplus
-extern "C" {
-#endif
-
 extern int grpc_pollset_work_run_loop;
 
 void grpc_pollset_global_init(void);
 void grpc_pollset_global_shutdown(void);
 
-#ifdef __cplusplus
-}
-#endif
-
 #endif /* GRPC_CORE_LIB_IOMGR_POLLSET_UV_H */
diff --git a/src/core/lib/iomgr/pollset_windows.cc b/src/core/lib/iomgr/pollset_windows.cc
index 5998b3f..95dd7d7 100644
--- a/src/core/lib/iomgr/pollset_windows.cc
+++ b/src/core/lib/iomgr/pollset_windows.cc
@@ -30,10 +30,7 @@
 
 #define GRPC_POLLSET_KICK_BROADCAST ((grpc_pollset_worker*)1)
 
-#ifndef NDEBUG
-grpc_tracer_flag grpc_trace_fd_refcount =
-    GRPC_TRACER_INITIALIZER(false, "fd_refcount");
-#endif
+grpc_core::DebugOnlyTraceFlag grpc_trace_fd_refcount(false, "fd_refcount");
 
 gpr_mu grpc_polling_mu;
 static grpc_pollset_worker* g_active_poller;
diff --git a/src/core/lib/iomgr/pollset_windows.h b/src/core/lib/iomgr/pollset_windows.h
index f6da9da..93fe7d6 100644
--- a/src/core/lib/iomgr/pollset_windows.h
+++ b/src/core/lib/iomgr/pollset_windows.h
@@ -26,10 +26,6 @@
 #ifdef GRPC_WINSOCK_SOCKET
 #include "src/core/lib/iomgr/socket_windows.h"
 
-#ifdef __cplusplus
-extern "C" {
-#endif
-
 /* There isn't really any such thing as a pollset under Windows, due to the
    nature of the IO completion ports. A Windows "pollset" is merely a mutex
    used to synchronize with the IOCP, and workers are condition variables
@@ -67,10 +63,6 @@
 void grpc_pollset_global_init(void);
 void grpc_pollset_global_shutdown(void);
 
-#ifdef __cplusplus
-}
-#endif
-
 #endif
 
 #endif /* GRPC_CORE_LIB_IOMGR_POLLSET_WINDOWS_H */
diff --git a/src/core/lib/iomgr/port.h b/src/core/lib/iomgr/port.h
index 1cc6d98..9fae8c0 100644
--- a/src/core/lib/iomgr/port.h
+++ b/src/core/lib/iomgr/port.h
@@ -30,6 +30,7 @@
 #define GRPC_HAVE_IP_PKTINFO 1
 #define GRPC_HAVE_MSG_NOSIGNAL 1
 #define GRPC_HAVE_UNIX_SOCKET 1
+#define GRPC_POSIX_FORK 1
 #define GRPC_POSIX_NO_SPECIAL_WAKEUP_FD 1
 #define GRPC_POSIX_SOCKET 1
 #define GRPC_POSIX_SOCKETADDR 1
@@ -59,6 +60,7 @@
 #define GRPC_HAVE_MSG_NOSIGNAL 1
 #define GRPC_HAVE_UNIX_SOCKET 1
 #define GRPC_LINUX_MULTIPOLL_WITH_EPOLL 1
+#define GRPC_POSIX_FORK 1
 #define GRPC_POSIX_HOST_NAME_MAX 1
 #define GRPC_POSIX_SOCKET 1
 #define GRPC_POSIX_SOCKETADDR 1
@@ -90,6 +92,7 @@
 #define GRPC_HAVE_SO_NOSIGPIPE 1
 #define GRPC_HAVE_UNIX_SOCKET 1
 #define GRPC_MSG_IOVLEN_TYPE int
+#define GRPC_POSIX_FORK 1
 #define GRPC_POSIX_NO_SPECIAL_WAKEUP_FD 1
 #define GRPC_POSIX_SOCKET 1
 #define GRPC_POSIX_SOCKETADDR 1
@@ -103,6 +106,7 @@
 #define GRPC_HAVE_IPV6_RECVPKTINFO 1
 #define GRPC_HAVE_SO_NOSIGPIPE 1
 #define GRPC_HAVE_UNIX_SOCKET 1
+#define GRPC_POSIX_FORK 1
 #define GRPC_POSIX_NO_SPECIAL_WAKEUP_FD 1
 #define GRPC_POSIX_SOCKET 1
 #define GRPC_POSIX_SOCKETADDR 1
diff --git a/src/core/lib/iomgr/resolve_address.h b/src/core/lib/iomgr/resolve_address.h
index 847e10f..5105020 100644
--- a/src/core/lib/iomgr/resolve_address.h
+++ b/src/core/lib/iomgr/resolve_address.h
@@ -25,10 +25,6 @@
 
 #define GRPC_MAX_SOCKADDR_SIZE 128
 
-#ifdef __cplusplus
-extern "C" {
-#endif
-
 typedef struct {
   char addr[GRPC_MAX_SOCKADDR_SIZE];
   size_t len;
@@ -56,8 +52,4 @@
     const char* name, const char* default_port,
     grpc_resolved_addresses** addresses);
 
-#ifdef __cplusplus
-}
-#endif
-
 #endif /* GRPC_CORE_LIB_IOMGR_RESOLVE_ADDRESS_H */
diff --git a/src/core/lib/iomgr/resource_quota.cc b/src/core/lib/iomgr/resource_quota.cc
index 9a44fa2..ccd8d9f 100644
--- a/src/core/lib/iomgr/resource_quota.cc
+++ b/src/core/lib/iomgr/resource_quota.cc
@@ -31,8 +31,7 @@
 
 #include "src/core/lib/iomgr/combiner.h"
 
-grpc_tracer_flag grpc_resource_quota_trace =
-    GRPC_TRACER_INITIALIZER(false, "resource_quota");
+grpc_core::TraceFlag grpc_resource_quota_trace(false, "resource_quota");
 
 #define MEMORY_USAGE_ESTIMATION_MAX 65536
 
@@ -293,7 +292,7 @@
   while ((resource_user = rulist_pop_head(resource_quota,
                                           GRPC_RULIST_AWAITING_ALLOCATION))) {
     gpr_mu_lock(&resource_user->mu);
-    if (GRPC_TRACER_ON(grpc_resource_quota_trace)) {
+    if (grpc_resource_quota_trace.enabled()) {
       gpr_log(GPR_DEBUG,
               "RQ: check allocation for user %p shutdown=%" PRIdPTR
               " free_pool=%" PRId64,
@@ -319,14 +318,14 @@
       resource_user->free_pool = 0;
       resource_quota->free_pool -= amt;
       rq_update_estimate(resource_quota);
-      if (GRPC_TRACER_ON(grpc_resource_quota_trace)) {
+      if (grpc_resource_quota_trace.enabled()) {
         gpr_log(GPR_DEBUG,
                 "RQ %s %s: grant alloc %" PRId64
                 " bytes; rq_free_pool -> %" PRId64,
                 resource_quota->name, resource_user->name, amt,
                 resource_quota->free_pool);
       }
-    } else if (GRPC_TRACER_ON(grpc_resource_quota_trace) &&
+    } else if (grpc_resource_quota_trace.enabled() &&
                resource_user->free_pool >= 0) {
       gpr_log(GPR_DEBUG, "RQ %s %s: discard already satisfied alloc request",
               resource_quota->name, resource_user->name);
@@ -357,7 +356,7 @@
       resource_user->free_pool = 0;
       resource_quota->free_pool += amt;
       rq_update_estimate(resource_quota);
-      if (GRPC_TRACER_ON(grpc_resource_quota_trace)) {
+      if (grpc_resource_quota_trace.enabled()) {
         gpr_log(GPR_DEBUG,
                 "RQ %s %s: reclaim_from_per_user_free_pool %" PRId64
                 " bytes; rq_free_pool -> %" PRId64,
@@ -381,7 +380,7 @@
                                  : GRPC_RULIST_RECLAIMER_BENIGN;
   grpc_resource_user* resource_user = rulist_pop_head(resource_quota, list);
   if (resource_user == nullptr) return false;
-  if (GRPC_TRACER_ON(grpc_resource_quota_trace)) {
+  if (grpc_resource_quota_trace.enabled()) {
     gpr_log(GPR_DEBUG, "RQ %s %s: initiate %s reclamation",
             resource_quota->name, resource_user->name,
             destructive ? "destructive" : "benign");
@@ -515,7 +514,7 @@
 }
 
 static void ru_shutdown(grpc_exec_ctx* exec_ctx, void* ru, grpc_error* error) {
-  if (GRPC_TRACER_ON(grpc_resource_quota_trace)) {
+  if (grpc_resource_quota_trace.enabled()) {
     gpr_log(GPR_DEBUG, "RU shutdown %p", ru);
   }
   grpc_resource_user* resource_user = (grpc_resource_user*)ru;
@@ -813,7 +812,7 @@
   ru_ref_by(resource_user, (gpr_atm)size);
   resource_user->free_pool -= (int64_t)size;
   resource_user->outstanding_allocations += (int64_t)size;
-  if (GRPC_TRACER_ON(grpc_resource_quota_trace)) {
+  if (grpc_resource_quota_trace.enabled()) {
     gpr_log(GPR_DEBUG, "RQ %s %s: alloc %" PRIdPTR "; free_pool -> %" PRId64,
             resource_user->resource_quota->name, resource_user->name, size,
             resource_user->free_pool);
@@ -838,7 +837,7 @@
   gpr_mu_lock(&resource_user->mu);
   bool was_zero_or_negative = resource_user->free_pool <= 0;
   resource_user->free_pool += (int64_t)size;
-  if (GRPC_TRACER_ON(grpc_resource_quota_trace)) {
+  if (grpc_resource_quota_trace.enabled()) {
     gpr_log(GPR_DEBUG, "RQ %s %s: free %" PRIdPTR "; free_pool -> %" PRId64,
             resource_user->resource_quota->name, resource_user->name, size,
             resource_user->free_pool);
@@ -867,7 +866,7 @@
 
 void grpc_resource_user_finish_reclamation(grpc_exec_ctx* exec_ctx,
                                            grpc_resource_user* resource_user) {
-  if (GRPC_TRACER_ON(grpc_resource_quota_trace)) {
+  if (grpc_resource_quota_trace.enabled()) {
     gpr_log(GPR_DEBUG, "RQ %s %s: reclamation complete",
             resource_user->resource_quota->name, resource_user->name);
   }
@@ -896,10 +895,3 @@
   grpc_resource_user_alloc(exec_ctx, slice_allocator->resource_user,
                            count * length, &slice_allocator->on_allocated);
 }
-
-grpc_slice grpc_resource_user_slice_malloc(grpc_exec_ctx* exec_ctx,
-                                           grpc_resource_user* resource_user,
-                                           size_t size) {
-  grpc_resource_user_alloc(exec_ctx, resource_user, size, nullptr);
-  return ru_slice_create(resource_user, size);
-}
diff --git a/src/core/lib/iomgr/resource_quota.h b/src/core/lib/iomgr/resource_quota.h
index fcdf9c2..7873703 100644
--- a/src/core/lib/iomgr/resource_quota.h
+++ b/src/core/lib/iomgr/resource_quota.h
@@ -24,10 +24,6 @@
 #include "src/core/lib/debug/trace.h"
 #include "src/core/lib/iomgr/exec_ctx.h"
 
-#ifdef __cplusplus
-extern "C" {
-#endif
-
 /** \file Tracks resource usage against a pool.
 
     The current implementation tracks only memory usage, but in the future
@@ -65,7 +61,7 @@
     maintain lists of users (which users arrange to leave before they are
     destroyed) */
 
-extern grpc_tracer_flag grpc_resource_quota_trace;
+extern grpc_core::TraceFlag grpc_resource_quota_trace;
 
 grpc_resource_quota* grpc_resource_quota_ref_internal(
     grpc_resource_quota* resource_quota);
@@ -154,8 +150,4 @@
                                            grpc_resource_user* resource_user,
                                            size_t size);
 
-#ifdef __cplusplus
-}
-#endif
-
 #endif /* GRPC_CORE_LIB_IOMGR_RESOURCE_QUOTA_H */
diff --git a/src/core/lib/iomgr/sockaddr_utils.cc b/src/core/lib/iomgr/sockaddr_utils.cc
index 3477fb5..0c0a2fe 100644
--- a/src/core/lib/iomgr/sockaddr_utils.cc
+++ b/src/core/lib/iomgr/sockaddr_utils.cc
@@ -148,7 +148,7 @@
   grpc_resolved_address addr_normalized;
   char ntop_buf[INET6_ADDRSTRLEN];
   const void* ip = nullptr;
-  int port;
+  int port = 0;
   uint32_t sin6_scope_id = 0;
   int ret;
 
diff --git a/src/core/lib/iomgr/sockaddr_utils.h b/src/core/lib/iomgr/sockaddr_utils.h
index 090470d..e3bd51a 100644
--- a/src/core/lib/iomgr/sockaddr_utils.h
+++ b/src/core/lib/iomgr/sockaddr_utils.h
@@ -21,10 +21,6 @@
 
 #include "src/core/lib/iomgr/resolve_address.h"
 
-#ifdef __cplusplus
-extern "C" {
-#endif
-
 /* Returns true if addr is an IPv4-mapped IPv6 address within the
    ::ffff:0.0.0.0/96 range, or false otherwise.
 
@@ -81,8 +77,4 @@
 
 int grpc_sockaddr_get_family(const grpc_resolved_address* resolved_addr);
 
-#ifdef __cplusplus
-}
-#endif
-
 #endif /* GRPC_CORE_LIB_IOMGR_SOCKADDR_UTILS_H */
diff --git a/src/core/lib/iomgr/socket_factory_posix.h b/src/core/lib/iomgr/socket_factory_posix.h
index e8257b0..af57cc5 100644
--- a/src/core/lib/iomgr/socket_factory_posix.h
+++ b/src/core/lib/iomgr/socket_factory_posix.h
@@ -23,10 +23,6 @@
 #include <grpc/support/sync.h>
 #include "src/core/lib/iomgr/resolve_address.h"
 
-#ifdef __cplusplus
-extern "C" {
-#endif
-
 /** The virtual table of grpc_socket_factory */
 typedef struct {
   /** Replacement for socket(2) */
@@ -68,8 +64,4 @@
 grpc_socket_factory* grpc_socket_factory_ref(grpc_socket_factory* factory);
 void grpc_socket_factory_unref(grpc_socket_factory* factory);
 
-#ifdef __cplusplus
-}
-#endif
-
 #endif /* GRPC_CORE_LIB_IOMGR_SOCKET_FACTORY_POSIX_H */
diff --git a/src/core/lib/iomgr/socket_mutator.h b/src/core/lib/iomgr/socket_mutator.h
index b4103f7..0a97cf6 100644
--- a/src/core/lib/iomgr/socket_mutator.h
+++ b/src/core/lib/iomgr/socket_mutator.h
@@ -24,10 +24,6 @@
 
 #include <stdbool.h>
 
-#ifdef __cplusplus
-extern "C" {
-#endif
-
 /** The virtual table of grpc_socket_mutator */
 typedef struct {
   /** Mutates the socket opitons of \a fd */
@@ -60,8 +56,4 @@
 grpc_socket_mutator* grpc_socket_mutator_ref(grpc_socket_mutator* mutator);
 void grpc_socket_mutator_unref(grpc_socket_mutator* mutator);
 
-#ifdef __cplusplus
-}
-#endif
-
 #endif /* GRPC_CORE_LIB_IOMGR_SOCKET_MUTATOR_H */
diff --git a/src/core/lib/iomgr/socket_utils.h b/src/core/lib/iomgr/socket_utils.h
index 4816ab6..9fd141b 100644
--- a/src/core/lib/iomgr/socket_utils.h
+++ b/src/core/lib/iomgr/socket_utils.h
@@ -21,15 +21,7 @@
 
 #include <stddef.h>
 
-#ifdef __cplusplus
-extern "C" {
-#endif
-
 /* A wrapper for inet_ntop on POSIX systems and InetNtop on Windows systems */
 const char* grpc_inet_ntop(int af, const void* src, char* dst, size_t size);
 
-#ifdef __cplusplus
-}
-#endif
-
 #endif /* GRPC_CORE_LIB_IOMGR_SOCKET_UTILS_H */
diff --git a/src/core/lib/iomgr/socket_utils_posix.h b/src/core/lib/iomgr/socket_utils_posix.h
index 7a9c813..77df420 100644
--- a/src/core/lib/iomgr/socket_utils_posix.h
+++ b/src/core/lib/iomgr/socket_utils_posix.h
@@ -29,10 +29,6 @@
 #include "src/core/lib/iomgr/socket_factory_posix.h"
 #include "src/core/lib/iomgr/socket_mutator.h"
 
-#ifdef __cplusplus
-extern "C" {
-#endif
-
 /* a wrapper for accept or accept4 */
 int grpc_accept4(int sockfd, grpc_resolved_address* resolved_addr, int nonblock,
                  int cloexec);
@@ -133,8 +129,4 @@
     grpc_socket_factory* factory, const grpc_resolved_address* addr, int type,
     int protocol, grpc_dualstack_mode* dsmode, int* newfd);
 
-#ifdef __cplusplus
-}
-#endif
-
 #endif /* GRPC_CORE_LIB_IOMGR_SOCKET_UTILS_POSIX_H */
diff --git a/src/core/lib/iomgr/socket_windows.h b/src/core/lib/iomgr/socket_windows.h
index c3ad99d..04e0a89 100644
--- a/src/core/lib/iomgr/socket_windows.h
+++ b/src/core/lib/iomgr/socket_windows.h
@@ -31,10 +31,6 @@
 #include "src/core/lib/iomgr/exec_ctx.h"
 #include "src/core/lib/iomgr/iomgr_internal.h"
 
-#ifdef __cplusplus
-extern "C" {
-#endif
-
 /* This holds the data for an outstanding read or write on a socket.
    The mutex to protect the concurrent access to that data is the one
    inside the winsocket wrapper. */
@@ -114,10 +110,6 @@
                               grpc_winsocket* winsocket,
                               grpc_winsocket_callback_info* ci);
 
-#ifdef __cplusplus
-}
-#endif
-
 #endif
 
 #endif /* GRPC_CORE_LIB_IOMGR_SOCKET_WINDOWS_H */
diff --git a/src/core/lib/iomgr/tcp_client.h b/src/core/lib/iomgr/tcp_client.h
index c18d8a9..75e2fe0 100644
--- a/src/core/lib/iomgr/tcp_client.h
+++ b/src/core/lib/iomgr/tcp_client.h
@@ -25,10 +25,6 @@
 #include "src/core/lib/iomgr/pollset_set.h"
 #include "src/core/lib/iomgr/resolve_address.h"
 
-#ifdef __cplusplus
-extern "C" {
-#endif
-
 /* Asynchronously connect to an address (specified as (addr, len)), and call
    cb with arg and the completed connection when done (or call cb with arg and
    NULL on failure).
@@ -41,8 +37,4 @@
                              const grpc_resolved_address* addr,
                              grpc_millis deadline);
 
-#ifdef __cplusplus
-}
-#endif
-
 #endif /* GRPC_CORE_LIB_IOMGR_TCP_CLIENT_H */
diff --git a/src/core/lib/iomgr/tcp_client_posix.cc b/src/core/lib/iomgr/tcp_client_posix.cc
index cb0f627..4cb2ac4 100644
--- a/src/core/lib/iomgr/tcp_client_posix.cc
+++ b/src/core/lib/iomgr/tcp_client_posix.cc
@@ -43,7 +43,7 @@
 #include "src/core/lib/iomgr/unix_sockets_posix.h"
 #include "src/core/lib/support/string.h"
 
-extern grpc_tracer_flag grpc_tcp_trace;
+extern grpc_core::TraceFlag grpc_tcp_trace;
 
 typedef struct {
   gpr_mu mu;
@@ -99,7 +99,7 @@
 static void tc_on_alarm(grpc_exec_ctx* exec_ctx, void* acp, grpc_error* error) {
   int done;
   async_connect* ac = (async_connect*)acp;
-  if (GRPC_TRACER_ON(grpc_tcp_trace)) {
+  if (grpc_tcp_trace.enabled()) {
     const char* str = grpc_error_string(error);
     gpr_log(GPR_DEBUG, "CLIENT_CONNECT: %s: on_alarm: error=%s", ac->addr_str,
             str);
@@ -138,7 +138,7 @@
 
   GRPC_ERROR_REF(error);
 
-  if (GRPC_TRACER_ON(grpc_tcp_trace)) {
+  if (grpc_tcp_trace.enabled()) {
     const char* str = grpc_error_string(error);
     gpr_log(GPR_DEBUG, "CLIENT_CONNECT: %s: on_writable: error=%s",
             ac->addr_str, str);
@@ -317,7 +317,7 @@
                     grpc_schedule_on_exec_ctx);
   ac->channel_args = grpc_channel_args_copy(channel_args);
 
-  if (GRPC_TRACER_ON(grpc_tcp_trace)) {
+  if (grpc_tcp_trace.enabled()) {
     gpr_log(GPR_DEBUG, "CLIENT_CONNECT: %s: asynchronously connecting fd %p",
             ac->addr_str, fdobj);
   }
@@ -334,13 +334,11 @@
 }
 
 // overridden by api_fuzzer.c
-extern "C" {
 void (*grpc_tcp_client_connect_impl)(
     grpc_exec_ctx* exec_ctx, grpc_closure* closure, grpc_endpoint** ep,
     grpc_pollset_set* interested_parties, const grpc_channel_args* channel_args,
     const grpc_resolved_address* addr,
     grpc_millis deadline) = tcp_client_connect_impl;
-}
 
 void grpc_tcp_client_connect(grpc_exec_ctx* exec_ctx, grpc_closure* closure,
                              grpc_endpoint** ep,
diff --git a/src/core/lib/iomgr/tcp_client_posix.h b/src/core/lib/iomgr/tcp_client_posix.h
index 13d9178..2b1fe79 100644
--- a/src/core/lib/iomgr/tcp_client_posix.h
+++ b/src/core/lib/iomgr/tcp_client_posix.h
@@ -23,16 +23,8 @@
 #include "src/core/lib/iomgr/ev_posix.h"
 #include "src/core/lib/iomgr/tcp_client.h"
 
-#ifdef __cplusplus
-extern "C" {
-#endif
-
 grpc_endpoint* grpc_tcp_client_create_from_fd(
     grpc_exec_ctx* exec_ctx, grpc_fd* fd, const grpc_channel_args* channel_args,
     const char* addr_str);
 
-#ifdef __cplusplus
-}
-#endif
-
 #endif /* GRPC_CORE_LIB_IOMGR_TCP_CLIENT_POSIX_H */
diff --git a/src/core/lib/iomgr/tcp_client_uv.cc b/src/core/lib/iomgr/tcp_client_uv.cc
index 15345c8..5cca0c9 100644
--- a/src/core/lib/iomgr/tcp_client_uv.cc
+++ b/src/core/lib/iomgr/tcp_client_uv.cc
@@ -32,7 +32,7 @@
 #include "src/core/lib/iomgr/tcp_uv.h"
 #include "src/core/lib/iomgr/timer.h"
 
-extern grpc_tracer_flag grpc_tcp_trace;
+extern grpc_core::TraceFlag grpc_tcp_trace;
 
 typedef struct grpc_uv_tcp_connect {
   uv_connect_t connect_req;
@@ -59,7 +59,7 @@
                            grpc_error* error) {
   int done;
   grpc_uv_tcp_connect* connect = (grpc_uv_tcp_connect*)acp;
-  if (GRPC_TRACER_ON(grpc_tcp_trace)) {
+  if (grpc_tcp_trace.enabled()) {
     const char* str = grpc_error_string(error);
     gpr_log(GPR_DEBUG, "CLIENT_CONNECT: %s: on_alarm: error=%s",
             connect->addr_name, str);
@@ -147,7 +147,7 @@
   connect->connect_req.data = connect;
   connect->refs = 2;  // One for the connect operation, one for the timer.
 
-  if (GRPC_TRACER_ON(grpc_tcp_trace)) {
+  if (grpc_tcp_trace.enabled()) {
     gpr_log(GPR_DEBUG, "CLIENT_CONNECT: %s: asynchronously connecting",
             connect->addr_name);
   }
@@ -161,13 +161,11 @@
 }
 
 // overridden by api_fuzzer.c
-extern "C" {
 void (*grpc_tcp_client_connect_impl)(
     grpc_exec_ctx* exec_ctx, grpc_closure* closure, grpc_endpoint** ep,
     grpc_pollset_set* interested_parties, const grpc_channel_args* channel_args,
     const grpc_resolved_address* addr,
     grpc_millis deadline) = tcp_client_connect_impl;
-}
 
 void grpc_tcp_client_connect(grpc_exec_ctx* exec_ctx, grpc_closure* closure,
                              grpc_endpoint** ep,
diff --git a/src/core/lib/iomgr/tcp_client_windows.cc b/src/core/lib/iomgr/tcp_client_windows.cc
index 103e6b7..5e30725 100644
--- a/src/core/lib/iomgr/tcp_client_windows.cc
+++ b/src/core/lib/iomgr/tcp_client_windows.cc
@@ -226,13 +226,11 @@
 }
 
 // overridden by api_fuzzer.c
-extern "C" {
 void (*grpc_tcp_client_connect_impl)(
     grpc_exec_ctx* exec_ctx, grpc_closure* closure, grpc_endpoint** ep,
     grpc_pollset_set* interested_parties, const grpc_channel_args* channel_args,
     const grpc_resolved_address* addr,
     grpc_millis deadline) = tcp_client_connect_impl;
-}
 
 void grpc_tcp_client_connect(grpc_exec_ctx* exec_ctx, grpc_closure* closure,
                              grpc_endpoint** ep,
diff --git a/src/core/lib/iomgr/tcp_posix.cc b/src/core/lib/iomgr/tcp_posix.cc
index cb90933..d09cfca 100644
--- a/src/core/lib/iomgr/tcp_posix.cc
+++ b/src/core/lib/iomgr/tcp_posix.cc
@@ -61,7 +61,7 @@
 typedef size_t msg_iovlen_type;
 #endif
 
-grpc_tracer_flag grpc_tcp_trace = GRPC_TRACER_INITIALIZER(false, "tcp");
+grpc_core::TraceFlag grpc_tcp_trace(false, "tcp");
 
 typedef struct {
   grpc_endpoint base;
@@ -81,9 +81,7 @@
 
   grpc_slice_buffer* incoming_buffer;
   grpc_slice_buffer* outgoing_buffer;
-  /** slice within outgoing_buffer to write next */
-  size_t outgoing_slice_idx;
-  /** byte within outgoing_buffer->slices[outgoing_slice_idx] to write next */
+  /** byte within outgoing_buffer->slices[0] to write next */
   size_t outgoing_byte_idx;
 
   grpc_closure* read_cb;
@@ -121,7 +119,7 @@
 static void done_poller(grpc_exec_ctx* exec_ctx, void* bp,
                         grpc_error* error_ignored) {
   backup_poller* p = (backup_poller*)bp;
-  if (GRPC_TRACER_ON(grpc_tcp_trace)) {
+  if (grpc_tcp_trace.enabled()) {
     gpr_log(GPR_DEBUG, "BACKUP_POLLER:%p destroy", p);
   }
   grpc_pollset_destroy(exec_ctx, BACKUP_POLLER_POLLSET(p));
@@ -131,7 +129,7 @@
 static void run_poller(grpc_exec_ctx* exec_ctx, void* bp,
                        grpc_error* error_ignored) {
   backup_poller* p = (backup_poller*)bp;
-  if (GRPC_TRACER_ON(grpc_tcp_trace)) {
+  if (grpc_tcp_trace.enabled()) {
     gpr_log(GPR_DEBUG, "BACKUP_POLLER:%p run", p);
   }
   gpr_mu_lock(p->pollset_mu);
@@ -147,18 +145,18 @@
       gpr_atm_full_cas(&g_uncovered_notifications_pending, 1, 0)) {
     gpr_mu_lock(p->pollset_mu);
     bool cas_ok = gpr_atm_full_cas(&g_backup_poller, (gpr_atm)p, 0);
-    if (GRPC_TRACER_ON(grpc_tcp_trace)) {
+    if (grpc_tcp_trace.enabled()) {
       gpr_log(GPR_DEBUG, "BACKUP_POLLER:%p done cas_ok=%d", p, cas_ok);
     }
     gpr_mu_unlock(p->pollset_mu);
-    if (GRPC_TRACER_ON(grpc_tcp_trace)) {
+    if (grpc_tcp_trace.enabled()) {
       gpr_log(GPR_DEBUG, "BACKUP_POLLER:%p shutdown", p);
     }
     grpc_pollset_shutdown(exec_ctx, BACKUP_POLLER_POLLSET(p),
                           GRPC_CLOSURE_INIT(&p->run_poller, done_poller, p,
                                             grpc_schedule_on_exec_ctx));
   } else {
-    if (GRPC_TRACER_ON(grpc_tcp_trace)) {
+    if (grpc_tcp_trace.enabled()) {
       gpr_log(GPR_DEBUG, "BACKUP_POLLER:%p reschedule", p);
     }
     GRPC_CLOSURE_SCHED(exec_ctx, &p->run_poller, GRPC_ERROR_NONE);
@@ -169,7 +167,7 @@
   backup_poller* p = (backup_poller*)gpr_atm_acq_load(&g_backup_poller);
   gpr_atm old_count =
       gpr_atm_no_barrier_fetch_add(&g_uncovered_notifications_pending, -1);
-  if (GRPC_TRACER_ON(grpc_tcp_trace)) {
+  if (grpc_tcp_trace.enabled()) {
     gpr_log(GPR_DEBUG, "BACKUP_POLLER:%p uncover cnt %d->%d", p, (int)old_count,
             (int)old_count - 1);
   }
@@ -180,14 +178,14 @@
   backup_poller* p;
   gpr_atm old_count =
       gpr_atm_no_barrier_fetch_add(&g_uncovered_notifications_pending, 2);
-  if (GRPC_TRACER_ON(grpc_tcp_trace)) {
+  if (grpc_tcp_trace.enabled()) {
     gpr_log(GPR_DEBUG, "BACKUP_POLLER: cover cnt %d->%d", (int)old_count,
             2 + (int)old_count);
   }
   if (old_count == 0) {
     GRPC_STATS_INC_TCP_BACKUP_POLLERS_CREATED(exec_ctx);
     p = (backup_poller*)gpr_zalloc(sizeof(*p) + grpc_pollset_size());
-    if (GRPC_TRACER_ON(grpc_tcp_trace)) {
+    if (grpc_tcp_trace.enabled()) {
       gpr_log(GPR_DEBUG, "BACKUP_POLLER:%p create", p);
     }
     grpc_pollset_init(BACKUP_POLLER_POLLSET(p), &p->pollset_mu);
@@ -203,7 +201,7 @@
       // spin waiting for backup poller
     }
   }
-  if (GRPC_TRACER_ON(grpc_tcp_trace)) {
+  if (grpc_tcp_trace.enabled()) {
     gpr_log(GPR_DEBUG, "BACKUP_POLLER:%p add %p", p, tcp);
   }
   grpc_pollset_add_fd(exec_ctx, BACKUP_POLLER_POLLSET(p), tcp->em_fd);
@@ -213,7 +211,7 @@
 }
 
 static void notify_on_read(grpc_exec_ctx* exec_ctx, grpc_tcp* tcp) {
-  if (GRPC_TRACER_ON(grpc_tcp_trace)) {
+  if (grpc_tcp_trace.enabled()) {
     gpr_log(GPR_DEBUG, "TCP:%p notify_on_read", tcp);
   }
   GRPC_CLOSURE_INIT(&tcp->read_done_closure, tcp_handle_read, tcp,
@@ -222,7 +220,7 @@
 }
 
 static void notify_on_write(grpc_exec_ctx* exec_ctx, grpc_tcp* tcp) {
-  if (GRPC_TRACER_ON(grpc_tcp_trace)) {
+  if (grpc_tcp_trace.enabled()) {
     gpr_log(GPR_DEBUG, "TCP:%p notify_on_write", tcp);
   }
   cover_self(exec_ctx, tcp);
@@ -234,7 +232,7 @@
 
 static void tcp_drop_uncovered_then_handle_write(grpc_exec_ctx* exec_ctx,
                                                  void* arg, grpc_error* error) {
-  if (GRPC_TRACER_ON(grpc_tcp_trace)) {
+  if (grpc_tcp_trace.enabled()) {
     gpr_log(GPR_DEBUG, "TCP:%p got_write: %s", arg, grpc_error_string(error));
   }
   drop_uncovered(exec_ctx, (grpc_tcp*)arg);
@@ -311,7 +309,7 @@
 #define TCP_REF(tcp, reason) tcp_ref((tcp), (reason), __FILE__, __LINE__)
 static void tcp_unref(grpc_exec_ctx* exec_ctx, grpc_tcp* tcp,
                       const char* reason, const char* file, int line) {
-  if (GRPC_TRACER_ON(grpc_tcp_trace)) {
+  if (grpc_tcp_trace.enabled()) {
     gpr_atm val = gpr_atm_no_barrier_load(&tcp->refcount.count);
     gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG,
             "TCP unref %p : %s %" PRIdPTR " -> %" PRIdPTR, tcp, reason, val,
@@ -324,7 +322,7 @@
 
 static void tcp_ref(grpc_tcp* tcp, const char* reason, const char* file,
                     int line) {
-  if (GRPC_TRACER_ON(grpc_tcp_trace)) {
+  if (grpc_tcp_trace.enabled()) {
     gpr_atm val = gpr_atm_no_barrier_load(&tcp->refcount.count);
     gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG,
             "TCP   ref %p : %s %" PRIdPTR " -> %" PRIdPTR, tcp, reason, val,
@@ -355,7 +353,7 @@
                          grpc_error* error) {
   grpc_closure* cb = tcp->read_cb;
 
-  if (GRPC_TRACER_ON(grpc_tcp_trace)) {
+  if (grpc_tcp_trace.enabled()) {
     gpr_log(GPR_DEBUG, "TCP:%p call_cb %p %p:%p", tcp, cb, cb->cb, cb->cb_arg);
     size_t i;
     const char* str = grpc_error_string(error);
@@ -451,7 +449,7 @@
 static void tcp_read_allocation_done(grpc_exec_ctx* exec_ctx, void* tcpp,
                                      grpc_error* error) {
   grpc_tcp* tcp = (grpc_tcp*)tcpp;
-  if (GRPC_TRACER_ON(grpc_tcp_trace)) {
+  if (grpc_tcp_trace.enabled()) {
     gpr_log(GPR_DEBUG, "TCP:%p read_allocation_done: %s", tcp,
             grpc_error_string(error));
   }
@@ -470,13 +468,13 @@
   size_t target_read_size = get_target_read_size(tcp);
   if (tcp->incoming_buffer->length < target_read_size &&
       tcp->incoming_buffer->count < MAX_READ_IOVEC) {
-    if (GRPC_TRACER_ON(grpc_tcp_trace)) {
+    if (grpc_tcp_trace.enabled()) {
       gpr_log(GPR_DEBUG, "TCP:%p alloc_slices", tcp);
     }
     grpc_resource_user_alloc_slices(exec_ctx, &tcp->slice_allocator,
                                     target_read_size, 1, tcp->incoming_buffer);
   } else {
-    if (GRPC_TRACER_ON(grpc_tcp_trace)) {
+    if (grpc_tcp_trace.enabled()) {
       gpr_log(GPR_DEBUG, "TCP:%p do_read", tcp);
     }
     tcp_do_read(exec_ctx, tcp);
@@ -487,7 +485,7 @@
                             grpc_error* error) {
   grpc_tcp* tcp = (grpc_tcp*)arg;
   GPR_ASSERT(!tcp->finished_edge);
-  if (GRPC_TRACER_ON(grpc_tcp_trace)) {
+  if (grpc_tcp_trace.enabled()) {
     gpr_log(GPR_DEBUG, "TCP:%p got_read: %s", tcp, grpc_error_string(error));
   }
 
@@ -532,23 +530,26 @@
   size_t unwind_slice_idx;
   size_t unwind_byte_idx;
 
+  // We always start at zero, because we eagerly unref and trim the slice
+  // buffer as we write
+  size_t outgoing_slice_idx = 0;
+
   for (;;) {
     sending_length = 0;
-    unwind_slice_idx = tcp->outgoing_slice_idx;
+    unwind_slice_idx = outgoing_slice_idx;
     unwind_byte_idx = tcp->outgoing_byte_idx;
-    for (iov_size = 0; tcp->outgoing_slice_idx != tcp->outgoing_buffer->count &&
+    for (iov_size = 0; outgoing_slice_idx != tcp->outgoing_buffer->count &&
                        iov_size != MAX_WRITE_IOVEC;
          iov_size++) {
       iov[iov_size].iov_base =
           GRPC_SLICE_START_PTR(
-              tcp->outgoing_buffer->slices[tcp->outgoing_slice_idx]) +
+              tcp->outgoing_buffer->slices[outgoing_slice_idx]) +
           tcp->outgoing_byte_idx;
       iov[iov_size].iov_len =
-          GRPC_SLICE_LENGTH(
-              tcp->outgoing_buffer->slices[tcp->outgoing_slice_idx]) -
+          GRPC_SLICE_LENGTH(tcp->outgoing_buffer->slices[outgoing_slice_idx]) -
           tcp->outgoing_byte_idx;
       sending_length += iov[iov_size].iov_len;
-      tcp->outgoing_slice_idx++;
+      outgoing_slice_idx++;
       tcp->outgoing_byte_idx = 0;
     }
     GPR_ASSERT(iov_size > 0);
@@ -574,16 +575,25 @@
 
     if (sent_length < 0) {
       if (errno == EAGAIN) {
-        tcp->outgoing_slice_idx = unwind_slice_idx;
         tcp->outgoing_byte_idx = unwind_byte_idx;
+        // unref all and forget about all slices that have been written to this
+        // point
+        for (size_t idx = 0; idx < unwind_slice_idx; ++idx) {
+          grpc_slice_unref_internal(
+              exec_ctx, grpc_slice_buffer_take_first(tcp->outgoing_buffer));
+        }
         return false;
       } else if (errno == EPIPE) {
         *error = grpc_error_set_int(GRPC_OS_ERROR(errno, "sendmsg"),
                                     GRPC_ERROR_INT_GRPC_STATUS,
                                     GRPC_STATUS_UNAVAILABLE);
+        grpc_slice_buffer_reset_and_unref_internal(exec_ctx,
+                                                   tcp->outgoing_buffer);
         return true;
       } else {
         *error = tcp_annotate_error(GRPC_OS_ERROR(errno, "sendmsg"), tcp);
+        grpc_slice_buffer_reset_and_unref_internal(exec_ctx,
+                                                   tcp->outgoing_buffer);
         return true;
       }
     }
@@ -593,9 +603,9 @@
     while (trailing > 0) {
       size_t slice_length;
 
-      tcp->outgoing_slice_idx--;
-      slice_length = GRPC_SLICE_LENGTH(
-          tcp->outgoing_buffer->slices[tcp->outgoing_slice_idx]);
+      outgoing_slice_idx--;
+      slice_length =
+          GRPC_SLICE_LENGTH(tcp->outgoing_buffer->slices[outgoing_slice_idx]);
       if (slice_length > trailing) {
         tcp->outgoing_byte_idx = slice_length - trailing;
         break;
@@ -604,11 +614,13 @@
       }
     }
 
-    if (tcp->outgoing_slice_idx == tcp->outgoing_buffer->count) {
+    if (outgoing_slice_idx == tcp->outgoing_buffer->count) {
       *error = GRPC_ERROR_NONE;
+      grpc_slice_buffer_reset_and_unref_internal(exec_ctx,
+                                                 tcp->outgoing_buffer);
       return true;
     }
-  };
+  }
 }
 
 static void tcp_handle_write(grpc_exec_ctx* exec_ctx, void* arg /* grpc_tcp */,
@@ -625,14 +637,14 @@
   }
 
   if (!tcp_flush(exec_ctx, tcp, &error)) {
-    if (GRPC_TRACER_ON(grpc_tcp_trace)) {
+    if (grpc_tcp_trace.enabled()) {
       gpr_log(GPR_DEBUG, "write: delayed");
     }
     notify_on_write(exec_ctx, tcp);
   } else {
     cb = tcp->write_cb;
     tcp->write_cb = nullptr;
-    if (GRPC_TRACER_ON(grpc_tcp_trace)) {
+    if (grpc_tcp_trace.enabled()) {
       const char* str = grpc_error_string(error);
       gpr_log(GPR_DEBUG, "write: %s", str);
     }
@@ -647,7 +659,7 @@
   grpc_tcp* tcp = (grpc_tcp*)ep;
   grpc_error* error = GRPC_ERROR_NONE;
 
-  if (GRPC_TRACER_ON(grpc_tcp_trace)) {
+  if (grpc_tcp_trace.enabled()) {
     size_t i;
 
     for (i = 0; i < buf->count; i++) {
@@ -672,18 +684,17 @@
     return;
   }
   tcp->outgoing_buffer = buf;
-  tcp->outgoing_slice_idx = 0;
   tcp->outgoing_byte_idx = 0;
 
   if (!tcp_flush(exec_ctx, tcp, &error)) {
     TCP_REF(tcp, "write");
     tcp->write_cb = cb;
-    if (GRPC_TRACER_ON(grpc_tcp_trace)) {
+    if (grpc_tcp_trace.enabled()) {
       gpr_log(GPR_DEBUG, "write: delayed");
     }
     notify_on_write(exec_ctx, tcp);
   } else {
-    if (GRPC_TRACER_ON(grpc_tcp_trace)) {
+    if (grpc_tcp_trace.enabled()) {
       const char* str = grpc_error_string(error);
       gpr_log(GPR_DEBUG, "write: %s", str);
     }
diff --git a/src/core/lib/iomgr/tcp_posix.h b/src/core/lib/iomgr/tcp_posix.h
index ff1060b..09051b7 100644
--- a/src/core/lib/iomgr/tcp_posix.h
+++ b/src/core/lib/iomgr/tcp_posix.h
@@ -33,11 +33,7 @@
 #include "src/core/lib/iomgr/endpoint.h"
 #include "src/core/lib/iomgr/ev_posix.h"
 
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-extern grpc_tracer_flag grpc_tcp_trace;
+extern grpc_core::TraceFlag grpc_tcp_trace;
 
 /* Create a tcp endpoint given a file desciptor and a read slice size.
    Takes ownership of fd. */
@@ -57,8 +53,4 @@
 void grpc_tcp_destroy_and_release_fd(grpc_exec_ctx* exec_ctx, grpc_endpoint* ep,
                                      int* fd, grpc_closure* done);
 
-#ifdef __cplusplus
-}
-#endif
-
 #endif /* GRPC_CORE_LIB_IOMGR_TCP_POSIX_H */
diff --git a/src/core/lib/iomgr/tcp_server.h b/src/core/lib/iomgr/tcp_server.h
index ef98319..a1757a2 100644
--- a/src/core/lib/iomgr/tcp_server.h
+++ b/src/core/lib/iomgr/tcp_server.h
@@ -25,10 +25,6 @@
 #include "src/core/lib/iomgr/endpoint.h"
 #include "src/core/lib/iomgr/resolve_address.h"
 
-#ifdef __cplusplus
-extern "C" {
-#endif
-
 /* Forward decl of grpc_tcp_server */
 typedef struct grpc_tcp_server grpc_tcp_server;
 
@@ -102,8 +98,4 @@
 void grpc_tcp_server_shutdown_listeners(grpc_exec_ctx* exec_ctx,
                                         grpc_tcp_server* s);
 
-#ifdef __cplusplus
-}
-#endif
-
 #endif /* GRPC_CORE_LIB_IOMGR_TCP_SERVER_H */
diff --git a/src/core/lib/iomgr/tcp_server_posix.cc b/src/core/lib/iomgr/tcp_server_posix.cc
index f84fa97..6fed13c 100644
--- a/src/core/lib/iomgr/tcp_server_posix.cc
+++ b/src/core/lib/iomgr/tcp_server_posix.cc
@@ -243,7 +243,7 @@
     addr_str = grpc_sockaddr_to_uri(&addr);
     gpr_asprintf(&name, "tcp-server-connection:%s", addr_str);
 
-    if (GRPC_TRACER_ON(grpc_tcp_trace)) {
+    if (grpc_tcp_trace.enabled()) {
       gpr_log(GPR_DEBUG, "SERVER_CONNECT: incoming connection: %s", addr_str);
     }
 
diff --git a/src/core/lib/iomgr/tcp_server_utils_posix.h b/src/core/lib/iomgr/tcp_server_utils_posix.h
index 608fba3..6046f25 100644
--- a/src/core/lib/iomgr/tcp_server_utils_posix.h
+++ b/src/core/lib/iomgr/tcp_server_utils_posix.h
@@ -24,10 +24,6 @@
 #include "src/core/lib/iomgr/socket_utils_posix.h"
 #include "src/core/lib/iomgr/tcp_server.h"
 
-#ifdef __cplusplus
-extern "C" {
-#endif
-
 /* one listening port */
 typedef struct grpc_tcp_listener {
   int fd;
@@ -121,8 +117,4 @@
 /* Ruturn true if the platform supports ifaddrs */
 bool grpc_tcp_server_have_ifaddrs(void);
 
-#ifdef __cplusplus
-}
-#endif
-
 #endif /* GRPC_CORE_LIB_IOMGR_TCP_SERVER_UTILS_POSIX_H */
diff --git a/src/core/lib/iomgr/tcp_server_utils_posix_common.cc b/src/core/lib/iomgr/tcp_server_utils_posix_common.cc
index 72443cc..5139760 100644
--- a/src/core/lib/iomgr/tcp_server_utils_posix_common.cc
+++ b/src/core/lib/iomgr/tcp_server_utils_posix_common.cc
@@ -55,7 +55,7 @@
   if (fgets(buf, sizeof buf, fp)) {
     char* end;
     long i = strtol(buf, &end, 10);
-    if (i > 0 && i <= INT_MAX && end && *end == 0) {
+    if (i > 0 && i <= INT_MAX && end && *end == '\n') {
       n = (int)i;
     }
   }
diff --git a/src/core/lib/iomgr/tcp_server_uv.cc b/src/core/lib/iomgr/tcp_server_uv.cc
index 0eed4d4..2c76fae 100644
--- a/src/core/lib/iomgr/tcp_server_uv.cc
+++ b/src/core/lib/iomgr/tcp_server_uv.cc
@@ -213,7 +213,7 @@
   } else {
     gpr_log(GPR_INFO, "uv_tcp_getpeername error: %s", uv_strerror(err));
   }
-  if (GRPC_TRACER_ON(grpc_tcp_trace)) {
+  if (grpc_tcp_trace.enabled()) {
     if (peer_name_string) {
       gpr_log(GPR_DEBUG, "SERVER_CONNECT: %p accepted connection: %s",
               sp->server, peer_name_string);
@@ -247,7 +247,7 @@
 
   GPR_ASSERT(!sp->has_pending_connection);
 
-  if (GRPC_TRACER_ON(grpc_tcp_trace)) {
+  if (grpc_tcp_trace.enabled()) {
     gpr_log(GPR_DEBUG, "SERVER_CONNECT: %p incoming connection", sp->server);
   }
 
@@ -403,7 +403,7 @@
 
   gpr_free(allocated_addr);
 
-  if (GRPC_TRACER_ON(grpc_tcp_trace)) {
+  if (grpc_tcp_trace.enabled()) {
     char* port_string;
     grpc_sockaddr_to_string(&port_string, addr, 0);
     const char* str = grpc_error_string(error);
@@ -435,7 +435,7 @@
   (void)pollsets;
   (void)pollset_count;
   GRPC_UV_ASSERT_SAME_THREAD();
-  if (GRPC_TRACER_ON(grpc_tcp_trace)) {
+  if (grpc_tcp_trace.enabled()) {
     gpr_log(GPR_DEBUG, "SERVER_START %p", server);
   }
   GPR_ASSERT(on_accept_cb);
diff --git a/src/core/lib/iomgr/tcp_uv.cc b/src/core/lib/iomgr/tcp_uv.cc
index ac9ca4e..40f4006 100644
--- a/src/core/lib/iomgr/tcp_uv.cc
+++ b/src/core/lib/iomgr/tcp_uv.cc
@@ -38,7 +38,7 @@
 #include "src/core/lib/slice/slice_string_helpers.h"
 #include "src/core/lib/support/string.h"
 
-grpc_tracer_flag grpc_tcp_trace = GRPC_TRACER_INITIALIZER(false, "tcp");
+grpc_core::TraceFlag grpc_tcp_trace(false, "tcp");
 
 typedef struct {
   grpc_endpoint base;
@@ -52,12 +52,12 @@
   grpc_closure* read_cb;
   grpc_closure* write_cb;
 
-  grpc_slice read_slice;
   grpc_slice_buffer* read_slices;
   grpc_slice_buffer* write_slices;
   uv_buf_t* write_buffers;
 
   grpc_resource_user* resource_user;
+  grpc_resource_user_slice_allocator slice_allocator;
 
   bool shutting_down;
 
@@ -66,7 +66,6 @@
 } grpc_tcp;
 
 static void tcp_free(grpc_exec_ctx* exec_ctx, grpc_tcp* tcp) {
-  grpc_slice_unref_internal(exec_ctx, tcp->read_slice);
   grpc_resource_user_unref(exec_ctx, tcp->resource_user);
   gpr_free(tcp->handle);
   gpr_free(tcp->peer_string);
@@ -79,7 +78,7 @@
 #define TCP_REF(tcp, reason) tcp_ref((tcp), (reason), __FILE__, __LINE__)
 static void tcp_unref(grpc_exec_ctx* exec_ctx, grpc_tcp* tcp,
                       const char* reason, const char* file, int line) {
-  if (GRPC_TRACER_ON(grpc_tcp_trace)) {
+  if (grpc_tcp_trace.enabled()) {
     gpr_atm val = gpr_atm_no_barrier_load(&tcp->refcount.count);
     gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG,
             "TCP unref %p : %s %" PRIdPTR " -> %" PRIdPTR, tcp, reason, val,
@@ -92,7 +91,7 @@
 
 static void tcp_ref(grpc_tcp* tcp, const char* reason, const char* file,
                     int line) {
-  if (GRPC_TRACER_ON(grpc_tcp_trace)) {
+  if (grpc_tcp_trace.enabled()) {
     gpr_atm val = gpr_atm_no_barrier_load(&tcp->refcount.count);
     gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG,
             "TCP   ref %p : %s %" PRIdPTR " -> %" PRIdPTR, tcp, reason, val,
@@ -119,91 +118,117 @@
   grpc_exec_ctx_finish(&exec_ctx);
 }
 
-static grpc_slice alloc_read_slice(grpc_exec_ctx* exec_ctx,
-                                   grpc_resource_user* resource_user) {
-  return grpc_resource_user_slice_malloc(exec_ctx, resource_user,
-                                         GRPC_TCP_DEFAULT_READ_SLICE_SIZE);
-}
-
 static void alloc_uv_buf(uv_handle_t* handle, size_t suggested_size,
                          uv_buf_t* buf) {
   grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
   grpc_tcp* tcp = (grpc_tcp*)handle->data;
   (void)suggested_size;
-  buf->base = (char*)GRPC_SLICE_START_PTR(tcp->read_slice);
-  buf->len = GRPC_SLICE_LENGTH(tcp->read_slice);
+  /* Before calling uv_read_start, we allocate a buffer with exactly one slice
+   * to tcp->read_slices and wait for the callback indicating that the
+   * allocation was successful. So slices[0] should always exist here */
+  buf->base = (char*)GRPC_SLICE_START_PTR(tcp->read_slices->slices[0]);
+  buf->len = GRPC_SLICE_LENGTH(tcp->read_slices->slices[0]);
   grpc_exec_ctx_finish(&exec_ctx);
 }
 
+static void call_read_cb(grpc_exec_ctx* exec_ctx, grpc_tcp* tcp,
+                         grpc_error* error) {
+  grpc_closure* cb = tcp->read_cb;
+  if (grpc_tcp_trace.enabled()) {
+    gpr_log(GPR_DEBUG, "TCP:%p call_cb %p %p:%p", tcp, cb, cb->cb, cb->cb_arg);
+    size_t i;
+    const char* str = grpc_error_string(error);
+    gpr_log(GPR_DEBUG, "read: error=%s", str);
+
+    for (i = 0; i < tcp->read_slices->count; i++) {
+      char* dump = grpc_dump_slice(tcp->read_slices->slices[i],
+                                   GPR_DUMP_HEX | GPR_DUMP_ASCII);
+      gpr_log(GPR_DEBUG, "READ %p (peer=%s): %s", tcp, tcp->peer_string, dump);
+      gpr_free(dump);
+    }
+  }
+  tcp->read_slices = NULL;
+  tcp->read_cb = NULL;
+  GRPC_CLOSURE_RUN(exec_ctx, cb, error);
+}
+
 static void read_callback(uv_stream_t* stream, ssize_t nread,
                           const uv_buf_t* buf) {
-  grpc_slice sub;
   grpc_error* error;
   grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
   grpc_tcp* tcp = (grpc_tcp*)stream->data;
-  grpc_closure* cb = tcp->read_cb;
+  grpc_slice_buffer garbage;
   if (nread == 0) {
     // Nothing happened. Wait for the next callback
     return;
   }
   TCP_UNREF(&exec_ctx, tcp, "read");
-  tcp->read_cb = NULL;
   // TODO(murgatroid99): figure out what the return value here means
   uv_read_stop(stream);
   if (nread == UV_EOF) {
     error = GRPC_ERROR_CREATE_FROM_STATIC_STRING("EOF");
+    grpc_slice_buffer_reset_and_unref_internal(&exec_ctx, tcp->read_slices);
   } else if (nread > 0) {
     // Successful read
-    sub = grpc_slice_sub_no_ref(tcp->read_slice, 0, (size_t)nread);
-    grpc_slice_buffer_add(tcp->read_slices, sub);
-    tcp->read_slice = alloc_read_slice(&exec_ctx, tcp->resource_user);
     error = GRPC_ERROR_NONE;
-    if (GRPC_TRACER_ON(grpc_tcp_trace)) {
-      size_t i;
-      const char* str = grpc_error_string(error);
-      gpr_log(GPR_DEBUG, "read: error=%s", str);
-
-      for (i = 0; i < tcp->read_slices->count; i++) {
-        char* dump = grpc_dump_slice(tcp->read_slices->slices[i],
-                                     GPR_DUMP_HEX | GPR_DUMP_ASCII);
-        gpr_log(GPR_DEBUG, "READ %p (peer=%s): %s", tcp, tcp->peer_string,
-                dump);
-        gpr_free(dump);
-      }
+    if ((size_t)nread < tcp->read_slices->length) {
+      /* TODO(murgatroid99): Instead of discarding the unused part of the read
+       * buffer, reuse it as the next read buffer. */
+      grpc_slice_buffer_init(&garbage);
+      grpc_slice_buffer_trim_end(
+          tcp->read_slices, tcp->read_slices->length - (size_t)nread, &garbage);
+      grpc_slice_buffer_reset_and_unref_internal(&exec_ctx, &garbage);
     }
   } else {
     // nread < 0: Error
     error = GRPC_ERROR_CREATE_FROM_STATIC_STRING("TCP Read failed");
+    grpc_slice_buffer_reset_and_unref_internal(&exec_ctx, tcp->read_slices);
   }
-  GRPC_CLOSURE_SCHED(&exec_ctx, cb, error);
+  call_read_cb(&exec_ctx, tcp, error);
   grpc_exec_ctx_finish(&exec_ctx);
 }
 
+static void tcp_read_allocation_done(grpc_exec_ctx* exec_ctx, void* tcpp,
+                                     grpc_error* error) {
+  int status;
+  grpc_tcp* tcp = (grpc_tcp*)tcpp;
+  if (grpc_tcp_trace.enabled()) {
+    gpr_log(GPR_DEBUG, "TCP:%p read_allocation_done: %s", tcp,
+            grpc_error_string(error));
+  }
+  if (error == GRPC_ERROR_NONE) {
+    status =
+        uv_read_start((uv_stream_t*)tcp->handle, alloc_uv_buf, read_callback);
+    if (status != 0) {
+      error = GRPC_ERROR_CREATE_FROM_STATIC_STRING("TCP Read failed at start");
+      error = grpc_error_set_str(
+          error, GRPC_ERROR_STR_OS_ERROR,
+          grpc_slice_from_static_string(uv_strerror(status)));
+    }
+  }
+  if (error != GRPC_ERROR_NONE) {
+    grpc_slice_buffer_reset_and_unref_internal(exec_ctx, tcp->read_slices);
+    call_read_cb(exec_ctx, tcp, GRPC_ERROR_REF(error));
+    TCP_UNREF(exec_ctx, tcp, "read");
+  }
+  if (grpc_tcp_trace.enabled()) {
+    const char* str = grpc_error_string(error);
+    gpr_log(GPR_DEBUG, "Initiating read on %p: error=%s", tcp, str);
+  }
+}
+
 static void uv_endpoint_read(grpc_exec_ctx* exec_ctx, grpc_endpoint* ep,
                              grpc_slice_buffer* read_slices, grpc_closure* cb) {
   grpc_tcp* tcp = (grpc_tcp*)ep;
-  int status;
-  grpc_error* error = GRPC_ERROR_NONE;
   GRPC_UV_ASSERT_SAME_THREAD();
   GPR_ASSERT(tcp->read_cb == NULL);
   tcp->read_cb = cb;
   tcp->read_slices = read_slices;
   grpc_slice_buffer_reset_and_unref_internal(exec_ctx, read_slices);
   TCP_REF(tcp, "read");
-  // TODO(murgatroid99): figure out what the return value here means
-  status =
-      uv_read_start((uv_stream_t*)tcp->handle, alloc_uv_buf, read_callback);
-  if (status != 0) {
-    error = GRPC_ERROR_CREATE_FROM_STATIC_STRING("TCP Read failed at start");
-    error =
-        grpc_error_set_str(error, GRPC_ERROR_STR_OS_ERROR,
-                           grpc_slice_from_static_string(uv_strerror(status)));
-    GRPC_CLOSURE_SCHED(exec_ctx, cb, error);
-  }
-  if (GRPC_TRACER_ON(grpc_tcp_trace)) {
-    const char* str = grpc_error_string(error);
-    gpr_log(GPR_DEBUG, "Initiating read on %p: error=%s", tcp, str);
-  }
+  grpc_resource_user_alloc_slices(exec_ctx, &tcp->slice_allocator,
+                                  GRPC_TCP_DEFAULT_READ_SLICE_SIZE, 1,
+                                  tcp->read_slices);
 }
 
 static void write_callback(uv_write_t* req, int status) {
@@ -218,13 +243,11 @@
   } else {
     error = GRPC_ERROR_CREATE_FROM_STATIC_STRING("TCP Write failed");
   }
-  if (GRPC_TRACER_ON(grpc_tcp_trace)) {
+  if (grpc_tcp_trace.enabled()) {
     const char* str = grpc_error_string(error);
     gpr_log(GPR_DEBUG, "write complete on %p: error=%s", tcp, str);
   }
   gpr_free(tcp->write_buffers);
-  grpc_resource_user_free(&exec_ctx, tcp->resource_user,
-                          sizeof(uv_buf_t) * tcp->write_slices->count);
   GRPC_CLOSURE_SCHED(&exec_ctx, cb, error);
   grpc_exec_ctx_finish(&exec_ctx);
 }
@@ -240,7 +263,7 @@
   uv_write_t* write_req;
   GRPC_UV_ASSERT_SAME_THREAD();
 
-  if (GRPC_TRACER_ON(grpc_tcp_trace)) {
+  if (grpc_tcp_trace.enabled()) {
     size_t j;
 
     for (j = 0; j < write_slices->count; j++) {
@@ -271,8 +294,6 @@
   tcp->write_cb = cb;
   buffer_count = (unsigned int)tcp->write_slices->count;
   buffers = (uv_buf_t*)gpr_malloc(sizeof(uv_buf_t) * buffer_count);
-  grpc_resource_user_alloc(exec_ctx, tcp->resource_user,
-                           sizeof(uv_buf_t) * buffer_count, NULL);
   for (i = 0; i < buffer_count; i++) {
     slice = &tcp->write_slices->slices[i];
     buffers[i].base = (char*)GRPC_SLICE_START_PTR(*slice);
@@ -320,7 +341,7 @@
                                  grpc_error* why) {
   grpc_tcp* tcp = (grpc_tcp*)ep;
   if (!tcp->shutting_down) {
-    if (GRPC_TRACER_ON(grpc_tcp_trace)) {
+    if (grpc_tcp_trace.enabled()) {
       const char* str = grpc_error_string(why);
       gpr_log(GPR_DEBUG, "TCP %p shutdown why=%s", tcp->handle, str);
     }
@@ -367,7 +388,7 @@
   grpc_tcp* tcp = (grpc_tcp*)gpr_malloc(sizeof(grpc_tcp));
   grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
 
-  if (GRPC_TRACER_ON(grpc_tcp_trace)) {
+  if (grpc_tcp_trace.enabled()) {
     gpr_log(GPR_DEBUG, "Creating TCP endpoint %p", tcp);
   }
 
@@ -381,8 +402,10 @@
   gpr_ref_init(&tcp->refcount, 1);
   tcp->peer_string = gpr_strdup(peer_string);
   tcp->shutting_down = false;
+  tcp->read_slices = NULL;
   tcp->resource_user = grpc_resource_user_create(resource_quota, peer_string);
-  tcp->read_slice = alloc_read_slice(&exec_ctx, tcp->resource_user);
+  grpc_resource_user_slice_allocator_init(
+      &tcp->slice_allocator, tcp->resource_user, tcp_read_allocation_done, tcp);
   /* Tell network status tracking code about the new endpoint */
   grpc_network_status_register_endpoint(&tcp->base);
 
diff --git a/src/core/lib/iomgr/tcp_uv.h b/src/core/lib/iomgr/tcp_uv.h
index 708e846..fd6d190 100644
--- a/src/core/lib/iomgr/tcp_uv.h
+++ b/src/core/lib/iomgr/tcp_uv.h
@@ -38,22 +38,14 @@
 
 #include <uv.h>
 
-extern grpc_tracer_flag grpc_tcp_trace;
+extern grpc_core::TraceFlag grpc_tcp_trace;
 
 #define GRPC_TCP_DEFAULT_READ_SLICE_SIZE 8192
 
-#ifdef __cplusplus
-extern "C" {
-#endif
-
 grpc_endpoint* grpc_tcp_create(uv_tcp_t* handle,
                                grpc_resource_quota* resource_quota,
                                char* peer_string);
 
-#ifdef __cplusplus
-}
-#endif
-
 #endif /* GRPC_UV */
 
 #endif /* GRPC_CORE_LIB_IOMGR_TCP_UV_H */
diff --git a/src/core/lib/iomgr/tcp_windows.cc b/src/core/lib/iomgr/tcp_windows.cc
index 04922b4..33868cd 100644
--- a/src/core/lib/iomgr/tcp_windows.cc
+++ b/src/core/lib/iomgr/tcp_windows.cc
@@ -49,7 +49,7 @@
 #define GRPC_FIONBIO FIONBIO
 #endif
 
-grpc_tracer_flag grpc_tcp_trace = GRPC_TRACER_INITIALIZER(false, "tcp");
+grpc_core::TraceFlag grpc_tcp_trace(false, "tcp");
 
 static grpc_error* set_non_block(SOCKET sock) {
   int status;
@@ -124,7 +124,7 @@
 #define TCP_REF(tcp, reason) tcp_ref((tcp), (reason), __FILE__, __LINE__)
 static void tcp_unref(grpc_exec_ctx* exec_ctx, grpc_tcp* tcp,
                       const char* reason, const char* file, int line) {
-  if (GRPC_TRACER_ON(grpc_tcp_trace)) {
+  if (grpc_tcp_trace.enabled()) {
     gpr_atm val = gpr_atm_no_barrier_load(&tcp->refcount.count);
     gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG,
             "TCP unref %p : %s %" PRIdPTR " -> %" PRIdPTR, tcp, reason, val,
@@ -137,7 +137,7 @@
 
 static void tcp_ref(grpc_tcp* tcp, const char* reason, const char* file,
                     int line) {
-  if (GRPC_TRACER_ON(grpc_tcp_trace)) {
+  if (grpc_tcp_trace.enabled()) {
     gpr_atm val = gpr_atm_no_barrier_load(&tcp->refcount.count);
     gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG,
             "TCP   ref %p : %s %" PRIdPTR " -> %" PRIdPTR, tcp, reason, val,
diff --git a/src/core/lib/iomgr/tcp_windows.h b/src/core/lib/iomgr/tcp_windows.h
index 9c7ccdf..28287e2 100644
--- a/src/core/lib/iomgr/tcp_windows.h
+++ b/src/core/lib/iomgr/tcp_windows.h
@@ -35,10 +35,6 @@
 #include "src/core/lib/iomgr/endpoint.h"
 #include "src/core/lib/iomgr/socket_windows.h"
 
-#ifdef __cplusplus
-extern "C" {
-#endif
-
 /* Create a tcp endpoint given a winsock handle.
  * Takes ownership of the handle.
  */
@@ -48,10 +44,6 @@
 
 grpc_error* grpc_tcp_prepare_socket(SOCKET sock);
 
-#ifdef __cplusplus
-}
-#endif
-
 #endif
 
 #endif /* GRPC_CORE_LIB_IOMGR_TCP_WINDOWS_H */
diff --git a/src/core/lib/iomgr/time_averaged_stats.h b/src/core/lib/iomgr/time_averaged_stats.h
index d38ed27..8745f7f 100644
--- a/src/core/lib/iomgr/time_averaged_stats.h
+++ b/src/core/lib/iomgr/time_averaged_stats.h
@@ -19,10 +19,6 @@
 #ifndef GRPC_CORE_LIB_IOMGR_TIME_AVERAGED_STATS_H
 #define GRPC_CORE_LIB_IOMGR_TIME_AVERAGED_STATS_H
 
-#ifdef __cplusplus
-extern "C" {
-#endif
-
 /* This tracks a time-decaying weighted average.  It works by collecting
    batches of samples and then mixing their average into a time-decaying
    weighted mean.  It is designed for batch operations where we do many adds
@@ -74,8 +70,4 @@
    value. */
 double grpc_time_averaged_stats_update_average(grpc_time_averaged_stats* stats);
 
-#ifdef __cplusplus
-}
-#endif
-
 #endif /* GRPC_CORE_LIB_IOMGR_TIME_AVERAGED_STATS_H */
diff --git a/src/core/lib/iomgr/timer.h b/src/core/lib/iomgr/timer.h
index cd8334e..b9acce2 100644
--- a/src/core/lib/iomgr/timer.h
+++ b/src/core/lib/iomgr/timer.h
@@ -32,10 +32,6 @@
 #include "src/core/lib/iomgr/exec_ctx.h"
 #include "src/core/lib/iomgr/iomgr.h"
 
-#ifdef __cplusplus
-extern "C" {
-#endif
-
 typedef struct grpc_timer grpc_timer;
 
 /* Initialize *timer. When expired or canceled, closure will be called with
@@ -106,8 +102,4 @@
 
 void grpc_kick_poller(void);
 
-#ifdef __cplusplus
-}
-#endif
-
 #endif /* GRPC_CORE_LIB_IOMGR_TIMER_H */
diff --git a/src/core/lib/iomgr/timer_generic.cc b/src/core/lib/iomgr/timer_generic.cc
index a4bfbcb..fa95c43 100644
--- a/src/core/lib/iomgr/timer_generic.cc
+++ b/src/core/lib/iomgr/timer_generic.cc
@@ -42,11 +42,8 @@
 #define MIN_QUEUE_WINDOW_DURATION 0.01
 #define MAX_QUEUE_WINDOW_DURATION 1
 
-extern "C" {
-grpc_tracer_flag grpc_timer_trace = GRPC_TRACER_INITIALIZER(false, "timer");
-grpc_tracer_flag grpc_timer_check_trace =
-    GRPC_TRACER_INITIALIZER(false, "timer_check");
-}
+grpc_core::TraceFlag grpc_timer_trace(false, "timer");
+grpc_core::TraceFlag grpc_timer_check_trace(false, "timer_check");
 
 /* A "timer shard". Contains a 'heap' and a 'list' of timers. All timers with
  * deadlines earlier than 'queue_deadline" cap are maintained in the heap and
@@ -253,8 +250,6 @@
   g_shared_mutables.min_timer = grpc_exec_ctx_now(exec_ctx);
   gpr_tls_init(&g_last_seen_min_timer);
   gpr_tls_set(&g_last_seen_min_timer, 0);
-  grpc_register_tracer(&grpc_timer_trace);
-  grpc_register_tracer(&grpc_timer_check_trace);
 
   for (i = 0; i < g_num_shards; i++) {
     timer_shard* shard = &g_shards[i];
@@ -339,7 +334,7 @@
   timer->hash_table_next = nullptr;
 #endif
 
-  if (GRPC_TRACER_ON(grpc_timer_trace)) {
+  if (grpc_timer_trace.enabled()) {
     gpr_log(GPR_DEBUG,
             "TIMER %p: SET %" PRIdPTR " now %" PRIdPTR " call %p[%p]", timer,
             deadline, grpc_exec_ctx_now(exec_ctx), closure, closure->cb);
@@ -375,7 +370,7 @@
     timer->heap_index = INVALID_HEAP_INDEX;
     list_join(&shard->list, timer);
   }
-  if (GRPC_TRACER_ON(grpc_timer_trace)) {
+  if (grpc_timer_trace.enabled()) {
     gpr_log(GPR_DEBUG,
             "  .. add to shard %d with queue_deadline_cap=%" PRIdPTR
             " => is_first_timer=%s",
@@ -397,7 +392,7 @@
      grpc_timer_check. */
   if (is_first_timer) {
     gpr_mu_lock(&g_shared_mutables.mu);
-    if (GRPC_TRACER_ON(grpc_timer_trace)) {
+    if (grpc_timer_trace.enabled()) {
       gpr_log(GPR_DEBUG, "  .. old shard min_deadline=%" PRIdPTR,
               shard->min_deadline);
     }
@@ -427,7 +422,7 @@
 
   timer_shard* shard = &g_shards[GPR_HASH_POINTER(timer, g_num_shards)];
   gpr_mu_lock(&shard->mu);
-  if (GRPC_TRACER_ON(grpc_timer_trace)) {
+  if (grpc_timer_trace.enabled()) {
     gpr_log(GPR_DEBUG, "TIMER %p: CANCEL pending=%s", timer,
             timer->pending ? "true" : "false");
   }
@@ -468,7 +463,7 @@
       saturating_add(GPR_MAX(now, shard->queue_deadline_cap),
                      (gpr_atm)(deadline_delta * 1000.0));
 
-  if (GRPC_TRACER_ON(grpc_timer_check_trace)) {
+  if (grpc_timer_check_trace.enabled()) {
     gpr_log(GPR_DEBUG, "  .. shard[%d]->queue_deadline_cap --> %" PRIdPTR,
             (int)(shard - g_shards), shard->queue_deadline_cap);
   }
@@ -476,7 +471,7 @@
     next = timer->next;
 
     if (timer->deadline < shard->queue_deadline_cap) {
-      if (GRPC_TRACER_ON(grpc_timer_check_trace)) {
+      if (grpc_timer_check_trace.enabled()) {
         gpr_log(GPR_DEBUG, "  .. add timer with deadline %" PRIdPTR " to heap",
                 timer->deadline);
       }
@@ -493,7 +488,7 @@
 static grpc_timer* pop_one(timer_shard* shard, gpr_atm now) {
   grpc_timer* timer;
   for (;;) {
-    if (GRPC_TRACER_ON(grpc_timer_check_trace)) {
+    if (grpc_timer_check_trace.enabled()) {
       gpr_log(GPR_DEBUG, "  .. shard[%d]: heap_empty=%s",
               (int)(shard - g_shards),
               grpc_timer_heap_is_empty(&shard->heap) ? "true" : "false");
@@ -503,13 +498,13 @@
       if (!refill_heap(shard, now)) return nullptr;
     }
     timer = grpc_timer_heap_top(&shard->heap);
-    if (GRPC_TRACER_ON(grpc_timer_check_trace)) {
+    if (grpc_timer_check_trace.enabled()) {
       gpr_log(GPR_DEBUG,
               "  .. check top timer deadline=%" PRIdPTR " now=%" PRIdPTR,
               timer->deadline, now);
     }
     if (timer->deadline > now) return nullptr;
-    if (GRPC_TRACER_ON(grpc_timer_trace)) {
+    if (grpc_timer_trace.enabled()) {
       gpr_log(GPR_DEBUG, "TIMER %p: FIRE %" PRIdPTR "ms late via %s scheduler",
               timer, now - timer->deadline,
               timer->closure->scheduler->vtable->name);
@@ -534,7 +529,7 @@
   }
   *new_min_deadline = compute_min_deadline(shard);
   gpr_mu_unlock(&shard->mu);
-  if (GRPC_TRACER_ON(grpc_timer_check_trace)) {
+  if (grpc_timer_check_trace.enabled()) {
     gpr_log(GPR_DEBUG, "  .. shard[%d] popped %" PRIdPTR,
             (int)(shard - g_shards), n);
   }
@@ -558,7 +553,7 @@
     gpr_mu_lock(&g_shared_mutables.mu);
     result = GRPC_TIMERS_CHECKED_AND_EMPTY;
 
-    if (GRPC_TRACER_ON(grpc_timer_check_trace)) {
+    if (grpc_timer_check_trace.enabled()) {
       gpr_log(GPR_DEBUG, "  .. shard[%d]->min_deadline = %" PRIdPTR,
               (int)(g_shard_queue[0] - g_shards),
               g_shard_queue[0]->min_deadline);
@@ -576,7 +571,7 @@
         result = GRPC_TIMERS_FIRED;
       }
 
-      if (GRPC_TRACER_ON(grpc_timer_check_trace)) {
+      if (grpc_timer_check_trace.enabled()) {
         gpr_log(GPR_DEBUG,
                 "  .. result --> %d"
                 ", shard[%d]->min_deadline %" PRIdPTR " --> %" PRIdPTR
@@ -621,7 +616,7 @@
     if (next != nullptr) {
       *next = GPR_MIN(*next, min_timer);
     }
-    if (GRPC_TRACER_ON(grpc_timer_check_trace)) {
+    if (grpc_timer_check_trace.enabled()) {
       gpr_log(GPR_DEBUG,
               "TIMER CHECK SKIP: now=%" PRIdPTR " min_timer=%" PRIdPTR, now,
               min_timer);
@@ -635,7 +630,7 @@
           : GRPC_ERROR_CREATE_FROM_STATIC_STRING("Shutting down timer system");
 
   // tracing
-  if (GRPC_TRACER_ON(grpc_timer_check_trace)) {
+  if (grpc_timer_check_trace.enabled()) {
     char* next_str;
     if (next == nullptr) {
       next_str = gpr_strdup("NULL");
@@ -653,7 +648,7 @@
   grpc_timer_check_result r =
       run_some_expired_timers(exec_ctx, now, next, shutdown_error);
   // tracing
-  if (GRPC_TRACER_ON(grpc_timer_check_trace)) {
+  if (grpc_timer_check_trace.enabled()) {
     char* next_str;
     if (next == nullptr) {
       next_str = gpr_strdup("NULL");
diff --git a/src/core/lib/iomgr/timer_heap.h b/src/core/lib/iomgr/timer_heap.h
index ae56e5a..436eef5 100644
--- a/src/core/lib/iomgr/timer_heap.h
+++ b/src/core/lib/iomgr/timer_heap.h
@@ -21,10 +21,6 @@
 
 #include "src/core/lib/iomgr/timer.h"
 
-#ifdef __cplusplus
-extern "C" {
-#endif
-
 typedef struct {
   grpc_timer** timers;
   uint32_t timer_count;
@@ -43,8 +39,4 @@
 
 int grpc_timer_heap_is_empty(grpc_timer_heap* heap);
 
-#ifdef __cplusplus
-}
-#endif
-
 #endif /* GRPC_CORE_LIB_IOMGR_TIMER_HEAP_H */
diff --git a/src/core/lib/iomgr/timer_manager.cc b/src/core/lib/iomgr/timer_manager.cc
index acc40b6..dac74ae 100644
--- a/src/core/lib/iomgr/timer_manager.cc
+++ b/src/core/lib/iomgr/timer_manager.cc
@@ -33,7 +33,7 @@
   struct completed_thread* next;
 } completed_thread;
 
-extern "C" grpc_tracer_flag grpc_timer_check_trace;
+extern grpc_core::TraceFlag grpc_timer_check_trace;
 
 // global mutex
 static gpr_mu g_mu;
@@ -81,7 +81,7 @@
   ++g_waiter_count;
   ++g_thread_count;
   gpr_mu_unlock(&g_mu);
-  if (GRPC_TRACER_ON(grpc_timer_check_trace)) {
+  if (grpc_timer_check_trace.enabled()) {
     gpr_log(GPR_DEBUG, "Spawn timer thread");
   }
   gpr_thd_options opt = gpr_thd_options_default();
@@ -115,7 +115,7 @@
     // if there's no thread waiting with a timeout, kick an existing
     // waiter so that the next deadline is not missed
     if (!g_has_timed_waiter) {
-      if (GRPC_TRACER_ON(grpc_timer_check_trace)) {
+      if (grpc_timer_check_trace.enabled()) {
         gpr_log(GPR_DEBUG, "kick untimed waiter");
       }
       gpr_cv_signal(&g_cv_wait);
@@ -123,7 +123,7 @@
     gpr_mu_unlock(&g_mu);
   }
   // without our lock, flush the exec_ctx
-  if (GRPC_TRACER_ON(grpc_timer_check_trace)) {
+  if (grpc_timer_check_trace.enabled()) {
     gpr_log(GPR_DEBUG, "flush exec_ctx");
   }
   grpc_exec_ctx_flush(exec_ctx);
@@ -178,7 +178,7 @@
         g_has_timed_waiter = true;
         g_timed_waiter_deadline = next;
 
-        if (GRPC_TRACER_ON(grpc_timer_check_trace)) {
+        if (grpc_timer_check_trace.enabled()) {
           grpc_millis wait_time = next - grpc_exec_ctx_now(exec_ctx);
           gpr_log(GPR_DEBUG, "sleep for a %" PRIdPTR " milliseconds",
                   wait_time);
@@ -188,15 +188,14 @@
       }
     }
 
-    if (GRPC_TRACER_ON(grpc_timer_check_trace) &&
-        next == GRPC_MILLIS_INF_FUTURE) {
+    if (grpc_timer_check_trace.enabled() && next == GRPC_MILLIS_INF_FUTURE) {
       gpr_log(GPR_DEBUG, "sleep until kicked");
     }
 
     gpr_cv_wait(&g_cv_wait, &g_mu,
                 grpc_millis_to_timespec(next, GPR_CLOCK_REALTIME));
 
-    if (GRPC_TRACER_ON(grpc_timer_check_trace)) {
+    if (grpc_timer_check_trace.enabled()) {
       gpr_log(GPR_DEBUG, "wait ended: was_timed:%d kicked:%d",
               my_timed_waiter_generation == g_timed_waiter_generation,
               g_kicked);
@@ -226,10 +225,6 @@
     grpc_millis next = GRPC_MILLIS_INF_FUTURE;
     grpc_exec_ctx_invalidate_now(exec_ctx);
 
-    /* Calibrate g_start_time in exec_ctx.cc with a regular interval in case the
-     * system clock has changed */
-    grpc_exec_ctx_maybe_update_start_time(exec_ctx);
-
     // check timer state, updates next to the next time to run a check
     switch (grpc_timer_check(exec_ctx, &next)) {
       case GRPC_TIMERS_FIRED:
@@ -245,7 +240,7 @@
 
            Consequently, we can just sleep forever here and be happy at some
            saved wakeup cycles. */
-        if (GRPC_TRACER_ON(grpc_timer_check_trace)) {
+        if (grpc_timer_check_trace.enabled()) {
           gpr_log(GPR_DEBUG, "timers not checked: expect another thread to");
         }
         next = GRPC_MILLIS_INF_FUTURE;
@@ -271,7 +266,7 @@
   ct->next = g_completed_threads;
   g_completed_threads = ct;
   gpr_mu_unlock(&g_mu);
-  if (GRPC_TRACER_ON(grpc_timer_check_trace)) {
+  if (grpc_timer_check_trace.enabled()) {
     gpr_log(GPR_DEBUG, "End timer thread");
   }
 }
@@ -314,18 +309,18 @@
 
 static void stop_threads(void) {
   gpr_mu_lock(&g_mu);
-  if (GRPC_TRACER_ON(grpc_timer_check_trace)) {
+  if (grpc_timer_check_trace.enabled()) {
     gpr_log(GPR_DEBUG, "stop timer threads: threaded=%d", g_threaded);
   }
   if (g_threaded) {
     g_threaded = false;
     gpr_cv_broadcast(&g_cv_wait);
-    if (GRPC_TRACER_ON(grpc_timer_check_trace)) {
+    if (grpc_timer_check_trace.enabled()) {
       gpr_log(GPR_DEBUG, "num timer threads: %d", g_thread_count);
     }
     while (g_thread_count > 0) {
       gpr_cv_wait(&g_cv_shutdown, &g_mu, gpr_inf_future(GPR_CLOCK_REALTIME));
-      if (GRPC_TRACER_ON(grpc_timer_check_trace)) {
+      if (grpc_timer_check_trace.enabled()) {
         gpr_log(GPR_DEBUG, "num timer threads: %d", g_thread_count);
       }
       gc_completed_threads();
diff --git a/src/core/lib/iomgr/timer_manager.h b/src/core/lib/iomgr/timer_manager.h
index 72960d6..0ba5029 100644
--- a/src/core/lib/iomgr/timer_manager.h
+++ b/src/core/lib/iomgr/timer_manager.h
@@ -21,10 +21,6 @@
 
 #include <stdbool.h>
 
-#ifdef __cplusplus
-extern "C" {
-#endif
-
 /* Timer Manager tries to keep one thread waiting for the next timeout at all
    times */
 
@@ -38,8 +34,4 @@
  * disabled */
 void grpc_timer_manager_tick(void);
 
-#ifdef __cplusplus
-}
-#endif
-
 #endif /* GRPC_CORE_LIB_IOMGR_TIMER_MANAGER_H */
diff --git a/src/core/lib/iomgr/timer_uv.cc b/src/core/lib/iomgr/timer_uv.cc
index df40e54..fac2026 100644
--- a/src/core/lib/iomgr/timer_uv.cc
+++ b/src/core/lib/iomgr/timer_uv.cc
@@ -29,11 +29,8 @@
 
 #include <uv.h>
 
-extern "C" {
-grpc_tracer_flag grpc_timer_trace = GRPC_TRACER_INITIALIZER(false, "timer");
-grpc_tracer_flag grpc_timer_check_trace =
-    GRPC_TRACER_INITIALIZER(false, "timer_check");
-}
+grpc_core::TraceFlag grpc_timer_trace(false, "timer");
+grpc_core::TraceFlag grpc_timer_check_trace(false, "timer_check");
 
 static void timer_close_callback(uv_handle_t* handle) { gpr_free(handle); }
 
diff --git a/src/core/lib/iomgr/udp_server.h b/src/core/lib/iomgr/udp_server.h
index bca0f04..8cc08d3 100644
--- a/src/core/lib/iomgr/udp_server.h
+++ b/src/core/lib/iomgr/udp_server.h
@@ -23,10 +23,6 @@
 #include "src/core/lib/iomgr/ev_posix.h"
 #include "src/core/lib/iomgr/resolve_address.h"
 
-#ifdef __cplusplus
-extern "C" {
-#endif
-
 /* Forward decl of struct grpc_server */
 /* This is not typedef'ed to avoid a typedef-redefinition error */
 struct grpc_server;
@@ -77,8 +73,4 @@
 void grpc_udp_server_destroy(grpc_exec_ctx* exec_ctx, grpc_udp_server* server,
                              grpc_closure* on_done);
 
-#ifdef __cplusplus
-}
-#endif
-
 #endif /* GRPC_CORE_LIB_IOMGR_UDP_SERVER_H */
diff --git a/src/core/lib/iomgr/unix_sockets_posix.h b/src/core/lib/iomgr/unix_sockets_posix.h
index be3c33d..1c079e6 100644
--- a/src/core/lib/iomgr/unix_sockets_posix.h
+++ b/src/core/lib/iomgr/unix_sockets_posix.h
@@ -25,10 +25,6 @@
 
 #include "src/core/lib/iomgr/resolve_address.h"
 
-#ifdef __cplusplus
-extern "C" {
-#endif
-
 void grpc_create_socketpair_if_unix(int sv[2]);
 
 grpc_error* grpc_resolve_unix_domain_address(
@@ -42,8 +38,4 @@
 char* grpc_sockaddr_to_uri_unix_if_possible(
     const grpc_resolved_address* resolved_addr);
 
-#ifdef __cplusplus
-}
-#endif
-
 #endif /* GRPC_CORE_LIB_IOMGR_UNIX_SOCKETS_POSIX_H */
diff --git a/src/core/lib/iomgr/wakeup_fd_cv.h b/src/core/lib/iomgr/wakeup_fd_cv.h
index dcd7bdb..017e41b 100644
--- a/src/core/lib/iomgr/wakeup_fd_cv.h
+++ b/src/core/lib/iomgr/wakeup_fd_cv.h
@@ -40,10 +40,6 @@
 #define GRPC_FD_TO_IDX(fd) (-(fd)-1)
 #define GRPC_IDX_TO_FD(idx) (-(idx)-1)
 
-#ifdef __cplusplus
-extern "C" {
-#endif
-
 typedef struct cv_node {
   gpr_cv* cv;
   struct cv_node* next;
@@ -68,8 +64,4 @@
 
 extern const grpc_wakeup_fd_vtable grpc_cv_wakeup_fd_vtable;
 
-#ifdef __cplusplus
-}
-#endif
-
 #endif /* GRPC_CORE_LIB_IOMGR_WAKEUP_FD_CV_H */
diff --git a/src/core/lib/iomgr/wakeup_fd_pipe.h b/src/core/lib/iomgr/wakeup_fd_pipe.h
index 9bbb5e2..326a0c4 100644
--- a/src/core/lib/iomgr/wakeup_fd_pipe.h
+++ b/src/core/lib/iomgr/wakeup_fd_pipe.h
@@ -21,14 +21,6 @@
 
 #include "src/core/lib/iomgr/wakeup_fd_posix.h"
 
-#ifdef __cplusplus
-extern "C" {
-#endif
-
 extern const grpc_wakeup_fd_vtable grpc_pipe_wakeup_fd_vtable;
 
-#ifdef __cplusplus
-}
-#endif
-
 #endif /* GRPC_CORE_LIB_IOMGR_WAKEUP_FD_PIPE_H */
diff --git a/src/core/lib/iomgr/wakeup_fd_posix.h b/src/core/lib/iomgr/wakeup_fd_posix.h
index ae7849f..a9584d0 100644
--- a/src/core/lib/iomgr/wakeup_fd_posix.h
+++ b/src/core/lib/iomgr/wakeup_fd_posix.h
@@ -49,10 +49,6 @@
 
 #include "src/core/lib/iomgr/error.h"
 
-#ifdef __cplusplus
-extern "C" {
-#endif
-
 void grpc_wakeup_fd_global_init(void);
 void grpc_wakeup_fd_global_destroy(void);
 
@@ -95,8 +91,4 @@
  * wakeup_fd_nospecial.c if no such implementation exists. */
 extern const grpc_wakeup_fd_vtable grpc_specialized_wakeup_fd_vtable;
 
-#ifdef __cplusplus
-}
-#endif
-
 #endif /* GRPC_CORE_LIB_IOMGR_WAKEUP_FD_POSIX_H */
diff --git a/src/core/lib/json/json.h b/src/core/lib/json/json.h
index c9fdec4..bbd4302 100644
--- a/src/core/lib/json/json.h
+++ b/src/core/lib/json/json.h
@@ -23,10 +23,6 @@
 
 #include "src/core/lib/json/json_common.h"
 
-#ifdef __cplusplus
-extern "C" {
-#endif
-
 /* A tree-like structure to hold json values. The key and value pointers
  * are not owned by it.
  */
@@ -74,8 +70,4 @@
 grpc_json* grpc_json_create(grpc_json_type type);
 void grpc_json_destroy(grpc_json* json);
 
-#ifdef __cplusplus
-}
-#endif
-
 #endif /* GRPC_CORE_LIB_JSON_JSON_H */
diff --git a/src/core/lib/json/json_reader.h b/src/core/lib/json/json_reader.h
index 2636d2b..03185cb 100644
--- a/src/core/lib/json/json_reader.h
+++ b/src/core/lib/json/json_reader.h
@@ -22,10 +22,6 @@
 #include <grpc/support/port_platform.h>
 #include "src/core/lib/json/json_common.h"
 
-#ifdef __cplusplus
-extern "C" {
-#endif
-
 typedef enum {
   GRPC_JSON_STATE_OBJECT_KEY_BEGIN,
   GRPC_JSON_STATE_OBJECT_KEY_STRING,
@@ -146,8 +142,4 @@
  */
 int grpc_json_reader_is_complete(grpc_json_reader* reader);
 
-#ifdef __cplusplus
-}
-#endif
-
 #endif /* GRPC_CORE_LIB_JSON_JSON_READER_H */
diff --git a/src/core/lib/json/json_writer.h b/src/core/lib/json/json_writer.h
index 93eeb20..a4f2d4d 100644
--- a/src/core/lib/json/json_writer.h
+++ b/src/core/lib/json/json_writer.h
@@ -35,10 +35,6 @@
 
 #include "src/core/lib/json/json_common.h"
 
-#ifdef __cplusplus
-extern "C" {
-#endif
-
 typedef struct grpc_json_writer_vtable {
   /* Adds a character to the output stream. */
   void (*output_char)(void* userdata, char);
@@ -83,8 +79,4 @@
 void grpc_json_writer_value_string(grpc_json_writer* writer,
                                    const char* string);
 
-#ifdef __cplusplus
-}
-#endif
-
 #endif /* GRPC_CORE_LIB_JSON_JSON_WRITER_H */
diff --git a/src/core/lib/profiling/timers.h b/src/core/lib/profiling/timers.h
index 8b6c254..9f11f77 100644
--- a/src/core/lib/profiling/timers.h
+++ b/src/core/lib/profiling/timers.h
@@ -19,10 +19,6 @@
 #ifndef GRPC_CORE_LIB_PROFILING_TIMERS_H
 #define GRPC_CORE_LIB_PROFILING_TIMERS_H
 
-#ifdef __cplusplus
-extern "C" {
-#endif
-
 void gpr_timers_global_init(void);
 void gpr_timers_global_destroy(void);
 
@@ -84,9 +80,6 @@
 
 #endif /* at least one profiler requested. */
 
-#ifdef __cplusplus
-}
-
 #if (defined(GRPC_STAP_PROFILER) + defined(GRPC_BASIC_PROFILER) + \
      defined(GRPC_CUSTOM_PROFILER))
 namespace grpc {
@@ -111,6 +104,5 @@
   do {                                  \
   } while (false)
 #endif
-#endif
 
 #endif /* GRPC_CORE_LIB_PROFILING_TIMERS_H */
diff --git a/src/core/lib/security/context/security_context.cc b/src/core/lib/security/context/security_context.cc
index 36362d9..19c6148 100644
--- a/src/core/lib/security/context/security_context.cc
+++ b/src/core/lib/security/context/security_context.cc
@@ -29,10 +29,8 @@
 #include <grpc/support/log.h>
 #include <grpc/support/string_util.h>
 
-#ifndef NDEBUG
-grpc_tracer_flag grpc_trace_auth_context_refcount =
-    GRPC_TRACER_INITIALIZER(false, "auth_context_refcount");
-#endif
+grpc_core::DebugOnlyTraceFlag grpc_trace_auth_context_refcount(
+    false, "auth_context_refcount");
 
 /* --- grpc_call --- */
 
@@ -135,7 +133,7 @@
                                          const char* file, int line,
                                          const char* reason) {
   if (ctx == nullptr) return nullptr;
-  if (GRPC_TRACER_ON(grpc_trace_auth_context_refcount)) {
+  if (grpc_trace_auth_context_refcount.enabled()) {
     gpr_atm val = gpr_atm_no_barrier_load(&ctx->refcount.count);
     gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG,
             "AUTH_CONTEXT:%p   ref %" PRIdPTR " -> %" PRIdPTR " %s", ctx, val,
@@ -153,7 +151,7 @@
 void grpc_auth_context_unref(grpc_auth_context* ctx, const char* file, int line,
                              const char* reason) {
   if (ctx == nullptr) return;
-  if (GRPC_TRACER_ON(grpc_trace_auth_context_refcount)) {
+  if (grpc_trace_auth_context_refcount.enabled()) {
     gpr_atm val = gpr_atm_no_barrier_load(&ctx->refcount.count);
     gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG,
             "AUTH_CONTEXT:%p unref %" PRIdPTR " -> %" PRIdPTR " %s", ctx, val,
diff --git a/src/core/lib/security/context/security_context.h b/src/core/lib/security/context/security_context.h
index 4f049c4..34f8c24 100644
--- a/src/core/lib/security/context/security_context.h
+++ b/src/core/lib/security/context/security_context.h
@@ -22,13 +22,7 @@
 #include "src/core/lib/iomgr/pollset.h"
 #include "src/core/lib/security/credentials/credentials.h"
 
-#ifndef NDEBUG
-extern grpc_tracer_flag grpc_trace_auth_context_refcount;
-#endif
-
-#ifdef __cplusplus
-extern "C" {
-#endif
+extern grpc_core::DebugOnlyTraceFlag grpc_trace_auth_context_refcount;
 
 /* --- grpc_auth_context ---
 
@@ -116,8 +110,4 @@
 grpc_auth_context* grpc_find_auth_context_in_args(
     const grpc_channel_args* args);
 
-#ifdef __cplusplus
-}
-#endif
-
 #endif /* GRPC_CORE_LIB_SECURITY_CONTEXT_SECURITY_CONTEXT_H */
diff --git a/src/core/lib/security/credentials/composite/composite_credentials.h b/src/core/lib/security/credentials/composite/composite_credentials.h
index efb5f4f..11990d3 100644
--- a/src/core/lib/security/credentials/composite/composite_credentials.h
+++ b/src/core/lib/security/credentials/composite/composite_credentials.h
@@ -21,10 +21,6 @@
 
 #include "src/core/lib/security/credentials/credentials.h"
 
-#ifdef __cplusplus
-extern "C" {
-#endif
-
 typedef struct {
   grpc_call_credentials** creds_array;
   size_t num_creds;
@@ -57,9 +53,5 @@
   grpc_call_credentials_array inner;
 } grpc_composite_call_credentials;
 
-#ifdef __cplusplus
-}
-#endif
-
 #endif /* GRPC_CORE_LIB_SECURITY_CREDENTIALS_COMPOSITE_COMPOSITE_CREDENTIALS_H \
         */
diff --git a/src/core/lib/security/credentials/credentials.h b/src/core/lib/security/credentials/credentials.h
index c65b966..bc1bd11 100644
--- a/src/core/lib/security/credentials/credentials.h
+++ b/src/core/lib/security/credentials/credentials.h
@@ -29,10 +29,6 @@
 #include "src/core/lib/iomgr/polling_entity.h"
 #include "src/core/lib/security/transport/security_connector.h"
 
-#ifdef __cplusplus
-extern "C" {
-#endif
-
 struct grpc_http_response;
 
 /* --- Constants. --- */
@@ -256,8 +252,4 @@
 void grpc_credentials_metadata_request_destroy(
     grpc_exec_ctx* exec_ctx, grpc_credentials_metadata_request* r);
 
-#ifdef __cplusplus
-}
-#endif
-
 #endif /* GRPC_CORE_LIB_SECURITY_CREDENTIALS_CREDENTIALS_H */
diff --git a/src/core/lib/security/credentials/fake/fake_credentials.h b/src/core/lib/security/credentials/fake/fake_credentials.h
index b8b58cc..0e9ff15 100644
--- a/src/core/lib/security/credentials/fake/fake_credentials.h
+++ b/src/core/lib/security/credentials/fake/fake_credentials.h
@@ -21,10 +21,6 @@
 
 #include "src/core/lib/security/credentials/credentials.h"
 
-#ifdef __cplusplus
-extern "C" {
-#endif
-
 /* -- Fake transport security credentials. -- */
 
 /* Creates a fake transport security credentials object for testing. */
@@ -60,8 +56,4 @@
   bool is_async;
 } grpc_md_only_test_credentials;
 
-#ifdef __cplusplus
-}
-#endif
-
 #endif /* GRPC_CORE_LIB_SECURITY_CREDENTIALS_FAKE_FAKE_CREDENTIALS_H */
diff --git a/src/core/lib/security/credentials/google_default/google_default_credentials.h b/src/core/lib/security/credentials/google_default/google_default_credentials.h
index a0f8dc9..b163e48 100644
--- a/src/core/lib/security/credentials/google_default/google_default_credentials.h
+++ b/src/core/lib/security/credentials/google_default/google_default_credentials.h
@@ -23,10 +23,6 @@
 
 #include "src/core/lib/security/credentials/credentials.h"
 
-#ifdef __cplusplus
-extern "C" {
-#endif
-
 #define GRPC_GOOGLE_CLOUD_SDK_CONFIG_DIRECTORY "gcloud"
 #define GRPC_GOOGLE_WELL_KNOWN_CREDENTIALS_FILE \
   "application_default_credentials.json"
@@ -45,9 +41,5 @@
 
 void grpc_flush_cached_google_default_credentials(void);
 
-#ifdef __cplusplus
-}
-#endif
-
 #endif /* GRPC_CORE_LIB_SECURITY_CREDENTIALS_GOOGLE_DEFAULT_GOOGLE_DEFAULT_CREDENTIALS_H \
         */
diff --git a/src/core/lib/security/credentials/jwt/json_token.h b/src/core/lib/security/credentials/jwt/json_token.h
index b2c3c09..9b77488 100644
--- a/src/core/lib/security/credentials/jwt/json_token.h
+++ b/src/core/lib/security/credentials/jwt/json_token.h
@@ -19,10 +19,6 @@
 #ifndef GRPC_CORE_LIB_SECURITY_CREDENTIALS_JWT_JSON_TOKEN_H
 #define GRPC_CORE_LIB_SECURITY_CREDENTIALS_JWT_JSON_TOKEN_H
 
-#ifdef __cplusplus
-extern "C" {
-#endif
-
 #include <grpc/slice.h>
 #include <openssl/rsa.h>
 
@@ -74,8 +70,4 @@
 void grpc_jwt_encode_and_sign_set_override(
     grpc_jwt_encode_and_sign_override func);
 
-#ifdef __cplusplus
-}
-#endif
-
 #endif /* GRPC_CORE_LIB_SECURITY_CREDENTIALS_JWT_JSON_TOKEN_H */
diff --git a/src/core/lib/security/credentials/jwt/jwt_credentials.cc b/src/core/lib/security/credentials/jwt/jwt_credentials.cc
index d666e6b..77163c0 100644
--- a/src/core/lib/security/credentials/jwt/jwt_credentials.cc
+++ b/src/core/lib/security/credentials/jwt/jwt_credentials.cc
@@ -172,7 +172,7 @@
 
 grpc_call_credentials* grpc_service_account_jwt_access_credentials_create(
     const char* json_key, gpr_timespec token_lifetime, void* reserved) {
-  if (GRPC_TRACER_ON(grpc_api_trace)) {
+  if (grpc_api_trace.enabled()) {
     char* clean_json = redact_private_key(json_key);
     gpr_log(GPR_INFO,
             "grpc_service_account_jwt_access_credentials_create("
diff --git a/src/core/lib/security/credentials/jwt/jwt_credentials.h b/src/core/lib/security/credentials/jwt/jwt_credentials.h
index d554613..85f068a 100644
--- a/src/core/lib/security/credentials/jwt/jwt_credentials.h
+++ b/src/core/lib/security/credentials/jwt/jwt_credentials.h
@@ -22,10 +22,6 @@
 #include "src/core/lib/security/credentials/credentials.h"
 #include "src/core/lib/security/credentials/jwt/json_token.h"
 
-#ifdef __cplusplus
-extern "C" {
-#endif
-
 typedef struct {
   grpc_call_credentials base;
 
@@ -49,8 +45,4 @@
     grpc_exec_ctx* exec_ctx, grpc_auth_json_key key,
     gpr_timespec token_lifetime);
 
-#ifdef __cplusplus
-}
-#endif
-
 #endif /* GRPC_CORE_LIB_SECURITY_CREDENTIALS_JWT_JWT_CREDENTIALS_H */
diff --git a/src/core/lib/security/credentials/jwt/jwt_verifier.h b/src/core/lib/security/credentials/jwt/jwt_verifier.h
index 8083cf9..2aacd49 100644
--- a/src/core/lib/security/credentials/jwt/jwt_verifier.h
+++ b/src/core/lib/security/credentials/jwt/jwt_verifier.h
@@ -32,10 +32,6 @@
 #define GRPC_GOOGLE_SERVICE_ACCOUNTS_KEY_URL_PREFIX \
   "www.googleapis.com/robot/v1/metadata/x509"
 
-#ifdef __cplusplus
-extern "C" {
-#endif
-
 /* --- grpc_jwt_verifier_status. --- */
 
 typedef enum {
@@ -126,8 +122,4 @@
                                                const char* audience);
 const char* grpc_jwt_issuer_email_domain(const char* issuer);
 
-#ifdef __cplusplus
-}
-#endif
-
 #endif /* GRPC_CORE_LIB_SECURITY_CREDENTIALS_JWT_JWT_VERIFIER_H */
diff --git a/src/core/lib/security/credentials/oauth2/oauth2_credentials.cc b/src/core/lib/security/credentials/oauth2/oauth2_credentials.cc
index 943d23f..ccefb4d 100644
--- a/src/core/lib/security/credentials/oauth2/oauth2_credentials.cc
+++ b/src/core/lib/security/credentials/oauth2/oauth2_credentials.cc
@@ -467,7 +467,7 @@
     const char* json_refresh_token, void* reserved) {
   grpc_auth_refresh_token token =
       grpc_auth_refresh_token_create_from_string(json_refresh_token);
-  if (GRPC_TRACER_ON(grpc_api_trace)) {
+  if (grpc_api_trace.enabled()) {
     char* loggable_token = create_loggable_refresh_token(&token);
     gpr_log(GPR_INFO,
             "grpc_refresh_token_credentials_create(json_refresh_token=%s, "
diff --git a/src/core/lib/security/credentials/oauth2/oauth2_credentials.h b/src/core/lib/security/credentials/oauth2/oauth2_credentials.h
index 32d3ff7..627783d 100644
--- a/src/core/lib/security/credentials/oauth2/oauth2_credentials.h
+++ b/src/core/lib/security/credentials/oauth2/oauth2_credentials.h
@@ -22,10 +22,6 @@
 #include "src/core/lib/json/json.h"
 #include "src/core/lib/security/credentials/credentials.h"
 
-#ifdef __cplusplus
-extern "C" {
-#endif
-
 // auth_refresh_token parsing.
 typedef struct {
   const char* type;
@@ -106,8 +102,4 @@
     grpc_exec_ctx* exec_ctx, const struct grpc_http_response* response,
     grpc_mdelem* token_md, grpc_millis* token_lifetime);
 
-#ifdef __cplusplus
-}
-#endif
-
 #endif /* GRPC_CORE_LIB_SECURITY_CREDENTIALS_OAUTH2_OAUTH2_CREDENTIALS_H */
diff --git a/src/core/lib/security/credentials/plugin/plugin_credentials.cc b/src/core/lib/security/credentials/plugin/plugin_credentials.cc
index b83a1b4..1f1efd0 100644
--- a/src/core/lib/security/credentials/plugin/plugin_credentials.cc
+++ b/src/core/lib/security/credentials/plugin/plugin_credentials.cc
@@ -31,8 +31,7 @@
 #include "src/core/lib/surface/api_trace.h"
 #include "src/core/lib/surface/validate_metadata.h"
 
-grpc_tracer_flag grpc_plugin_credentials_trace =
-    GRPC_TRACER_INITIALIZER(false, "plugin_credentials");
+grpc_core::TraceFlag grpc_plugin_credentials_trace(false, "plugin_credentials");
 
 static void plugin_destruct(grpc_exec_ctx* exec_ctx,
                             grpc_call_credentials* creds) {
@@ -123,7 +122,7 @@
       nullptr, nullptr);
   grpc_plugin_credentials_pending_request* r =
       (grpc_plugin_credentials_pending_request*)request;
-  if (GRPC_TRACER_ON(grpc_plugin_credentials_trace)) {
+  if (grpc_plugin_credentials_trace.enabled()) {
     gpr_log(GPR_INFO,
             "plugin_credentials[%p]: request %p: plugin returned "
             "asynchronously",
@@ -136,7 +135,7 @@
     grpc_error* error =
         process_plugin_result(&exec_ctx, r, md, num_md, status, error_details);
     GRPC_CLOSURE_SCHED(&exec_ctx, r->on_request_metadata, error);
-  } else if (GRPC_TRACER_ON(grpc_plugin_credentials_trace)) {
+  } else if (grpc_plugin_credentials_trace.enabled()) {
     gpr_log(GPR_INFO,
             "plugin_credentials[%p]: request %p: plugin was previously "
             "cancelled",
@@ -172,7 +171,7 @@
     c->pending_requests = pending_request;
     gpr_mu_unlock(&c->mu);
     // Invoke the plugin.  The callback holds a ref to us.
-    if (GRPC_TRACER_ON(grpc_plugin_credentials_trace)) {
+    if (grpc_plugin_credentials_trace.enabled()) {
       gpr_log(GPR_INFO, "plugin_credentials[%p]: request %p: invoking plugin",
               c, pending_request);
     }
@@ -185,7 +184,7 @@
                                 plugin_md_request_metadata_ready,
                                 pending_request, creds_md, &num_creds_md,
                                 &status, &error_details)) {
-      if (GRPC_TRACER_ON(grpc_plugin_credentials_trace)) {
+      if (grpc_plugin_credentials_trace.enabled()) {
         gpr_log(GPR_INFO,
                 "plugin_credentials[%p]: request %p: plugin will return "
                 "asynchronously",
@@ -200,7 +199,7 @@
     // asynchronously by plugin_cancel_get_request_metadata(), so return
     // false.  Otherwise, process the result.
     if (pending_request->cancelled) {
-      if (GRPC_TRACER_ON(grpc_plugin_credentials_trace)) {
+      if (grpc_plugin_credentials_trace.enabled()) {
         gpr_log(GPR_INFO,
                 "plugin_credentials[%p]: request %p was cancelled, error "
                 "will be returned asynchronously",
@@ -208,7 +207,7 @@
       }
       retval = false;
     } else {
-      if (GRPC_TRACER_ON(grpc_plugin_credentials_trace)) {
+      if (grpc_plugin_credentials_trace.enabled()) {
         gpr_log(GPR_INFO,
                 "plugin_credentials[%p]: request %p: plugin returned "
                 "synchronously",
@@ -237,7 +236,7 @@
            c->pending_requests;
        pending_request != nullptr; pending_request = pending_request->next) {
     if (pending_request->md_array == md_array) {
-      if (GRPC_TRACER_ON(grpc_plugin_credentials_trace)) {
+      if (grpc_plugin_credentials_trace.enabled()) {
         gpr_log(GPR_INFO, "plugin_credentials[%p]: cancelling request %p", c,
                 pending_request);
       }
diff --git a/src/core/lib/security/credentials/plugin/plugin_credentials.h b/src/core/lib/security/credentials/plugin/plugin_credentials.h
index fc0955c..e1467b0 100644
--- a/src/core/lib/security/credentials/plugin/plugin_credentials.h
+++ b/src/core/lib/security/credentials/plugin/plugin_credentials.h
@@ -21,7 +21,7 @@
 
 #include "src/core/lib/security/credentials/credentials.h"
 
-extern grpc_tracer_flag grpc_plugin_credentials_trace;
+extern grpc_core::TraceFlag grpc_plugin_credentials_trace;
 
 struct grpc_plugin_credentials;
 
diff --git a/src/core/lib/security/credentials/ssl/ssl_credentials.h b/src/core/lib/security/credentials/ssl/ssl_credentials.h
index 82b9ce1..0003905 100644
--- a/src/core/lib/security/credentials/ssl/ssl_credentials.h
+++ b/src/core/lib/security/credentials/ssl/ssl_credentials.h
@@ -20,10 +20,6 @@
 
 #include "src/core/lib/security/credentials/credentials.h"
 
-#ifdef __cplusplus
-extern "C" {
-#endif
-
 typedef struct {
   grpc_channel_credentials base;
   grpc_ssl_config config;
@@ -53,8 +49,4 @@
 void grpc_tsi_ssl_pem_key_cert_pairs_destroy(tsi_ssl_pem_key_cert_pair* kp,
                                              size_t num_key_cert_pairs);
 
-#ifdef __cplusplus
-}
-#endif
-
 #endif /* GRPC_CORE_LIB_SECURITY_CREDENTIALS_SSL_SSL_CREDENTIALS_H */
diff --git a/src/core/lib/security/transport/auth_filters.h b/src/core/lib/security/transport/auth_filters.h
index 6376929..e999a02 100644
--- a/src/core/lib/security/transport/auth_filters.h
+++ b/src/core/lib/security/transport/auth_filters.h
@@ -22,10 +22,6 @@
 #include <grpc/grpc_security.h>
 #include "src/core/lib/channel/channel_stack.h"
 
-#ifdef __cplusplus
-extern "C" {
-#endif
-
 extern const grpc_channel_filter grpc_client_auth_filter;
 extern const grpc_channel_filter grpc_server_auth_filter;
 
@@ -36,8 +32,4 @@
 
 void grpc_auth_metadata_context_reset(grpc_auth_metadata_context* context);
 
-#ifdef __cplusplus
-}
-#endif
-
 #endif /* GRPC_CORE_LIB_SECURITY_TRANSPORT_AUTH_FILTERS_H */
diff --git a/src/core/lib/security/transport/lb_targets_info.h b/src/core/lib/security/transport/lb_targets_info.h
index b4a0bc9..7543d3c 100644
--- a/src/core/lib/security/transport/lb_targets_info.h
+++ b/src/core/lib/security/transport/lb_targets_info.h
@@ -21,10 +21,6 @@
 
 #include "src/core/lib/slice/slice_hash_table.h"
 
-#ifdef __cplusplus
-extern "C" {
-#endif
-
 /** Return a channel argument containing \a targets_info. */
 grpc_arg grpc_lb_targets_info_create_channel_arg(
     grpc_slice_hash_table* targets_info);
@@ -33,8 +29,4 @@
 grpc_slice_hash_table* grpc_lb_targets_info_find_in_args(
     const grpc_channel_args* args);
 
-#ifdef __cplusplus
-}
-#endif
-
 #endif /* GRPC_CORE_LIB_SECURITY_TRANSPORT_LB_TARGETS_INFO_H */
diff --git a/src/core/lib/security/transport/secure_endpoint.cc b/src/core/lib/security/transport/secure_endpoint.cc
index 3ba987a..4cd317a 100644
--- a/src/core/lib/security/transport/secure_endpoint.cc
+++ b/src/core/lib/security/transport/secure_endpoint.cc
@@ -61,8 +61,7 @@
   gpr_refcount ref;
 } secure_endpoint;
 
-grpc_tracer_flag grpc_trace_secure_endpoint =
-    GRPC_TRACER_INITIALIZER(false, "secure_endpoint");
+grpc_core::TraceFlag grpc_trace_secure_endpoint(false, "secure_endpoint");
 
 static void destroy(grpc_exec_ctx* exec_ctx, secure_endpoint* secure_ep) {
   secure_endpoint* ep = secure_ep;
@@ -86,7 +85,7 @@
 static void secure_endpoint_unref(grpc_exec_ctx* exec_ctx, secure_endpoint* ep,
                                   const char* reason, const char* file,
                                   int line) {
-  if (GRPC_TRACER_ON(grpc_trace_secure_endpoint)) {
+  if (grpc_trace_secure_endpoint.enabled()) {
     gpr_atm val = gpr_atm_no_barrier_load(&ep->ref.count);
     gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG,
             "SECENDP unref %p : %s %" PRIdPTR " -> %" PRIdPTR, ep, reason, val,
@@ -99,7 +98,7 @@
 
 static void secure_endpoint_ref(secure_endpoint* ep, const char* reason,
                                 const char* file, int line) {
-  if (GRPC_TRACER_ON(grpc_trace_secure_endpoint)) {
+  if (grpc_trace_secure_endpoint.enabled()) {
     gpr_atm val = gpr_atm_no_barrier_load(&ep->ref.count);
     gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG,
             "SECENDP   ref %p : %s %" PRIdPTR " -> %" PRIdPTR, ep, reason, val,
@@ -131,7 +130,7 @@
 
 static void call_read_cb(grpc_exec_ctx* exec_ctx, secure_endpoint* ep,
                          grpc_error* error) {
-  if (GRPC_TRACER_ON(grpc_trace_secure_endpoint)) {
+  if (grpc_trace_secure_endpoint.enabled()) {
     size_t i;
     for (i = 0; i < ep->read_buffer->count; i++) {
       char* data = grpc_dump_slice(ep->read_buffer->slices[i],
@@ -271,7 +270,7 @@
 
   grpc_slice_buffer_reset_and_unref_internal(exec_ctx, &ep->output_buffer);
 
-  if (GRPC_TRACER_ON(grpc_trace_secure_endpoint)) {
+  if (grpc_trace_secure_endpoint.enabled()) {
     for (i = 0; i < slices->count; i++) {
       char* data =
           grpc_dump_slice(slices->slices[i], GPR_DUMP_HEX | GPR_DUMP_ASCII);
diff --git a/src/core/lib/security/transport/secure_endpoint.h b/src/core/lib/security/transport/secure_endpoint.h
index db8233f..b2556a0 100644
--- a/src/core/lib/security/transport/secure_endpoint.h
+++ b/src/core/lib/security/transport/secure_endpoint.h
@@ -22,14 +22,10 @@
 #include <grpc/slice.h>
 #include "src/core/lib/iomgr/endpoint.h"
 
-#ifdef __cplusplus
-extern "C" {
-#endif
-
 struct tsi_frame_protector;
 struct tsi_zero_copy_grpc_protector;
 
-extern grpc_tracer_flag grpc_trace_secure_endpoint;
+extern grpc_core::TraceFlag grpc_trace_secure_endpoint;
 
 /* Takes ownership of protector, zero_copy_protector, and to_wrap, and refs
  * leftover_slices. If zero_copy_protector is not NULL, protector will never be
@@ -40,8 +36,4 @@
     grpc_endpoint* to_wrap, grpc_slice* leftover_slices,
     size_t leftover_nslices);
 
-#ifdef __cplusplus
-}
-#endif
-
 #endif /* GRPC_CORE_LIB_SECURITY_TRANSPORT_SECURE_ENDPOINT_H */
diff --git a/src/core/lib/security/transport/security_connector.cc b/src/core/lib/security/transport/security_connector.cc
index b996cc8..c56e459 100644
--- a/src/core/lib/security/transport/security_connector.cc
+++ b/src/core/lib/security/transport/security_connector.cc
@@ -44,10 +44,8 @@
 #include "src/core/tsi/ssl_transport_security.h"
 #include "src/core/tsi/transport_security_adapter.h"
 
-#ifndef NDEBUG
-grpc_tracer_flag grpc_trace_security_connector_refcount =
-    GRPC_TRACER_INITIALIZER(false, "security_connector_refcount");
-#endif
+grpc_core::DebugOnlyTraceFlag grpc_trace_security_connector_refcount(
+    false, "security_connector_refcount");
 
 /* -- Constants. -- */
 
@@ -198,7 +196,7 @@
     grpc_security_connector* sc, const char* file, int line,
     const char* reason) {
   if (sc == nullptr) return nullptr;
-  if (GRPC_TRACER_ON(grpc_trace_security_connector_refcount)) {
+  if (grpc_trace_security_connector_refcount.enabled()) {
     gpr_atm val = gpr_atm_no_barrier_load(&sc->refcount.count);
     gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG,
             "SECURITY_CONNECTOR:%p   ref %" PRIdPTR " -> %" PRIdPTR " %s", sc,
@@ -219,7 +217,7 @@
                                    const char* file, int line,
                                    const char* reason) {
   if (sc == nullptr) return;
-  if (GRPC_TRACER_ON(grpc_trace_security_connector_refcount)) {
+  if (grpc_trace_security_connector_refcount.enabled()) {
     gpr_atm val = gpr_atm_no_barrier_load(&sc->refcount.count);
     gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG,
             "SECURITY_CONNECTOR:%p unref %" PRIdPTR " -> %" PRIdPTR " %s", sc,
diff --git a/src/core/lib/security/transport/security_connector.h b/src/core/lib/security/transport/security_connector.h
index 79fdbc1..03daba3 100644
--- a/src/core/lib/security/transport/security_connector.h
+++ b/src/core/lib/security/transport/security_connector.h
@@ -29,13 +29,7 @@
 #include "src/core/tsi/ssl_transport_security.h"
 #include "src/core/tsi/transport_security_interface.h"
 
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#ifndef NDEBUG
-extern grpc_tracer_flag grpc_trace_security_connector_refcount;
-#endif
+extern grpc_core::DebugOnlyTraceFlag grpc_trace_security_connector_refcount;
 
 /* --- status enum. --- */
 
@@ -261,8 +255,4 @@
     const grpc_auth_context* auth_context);
 void tsi_shallow_peer_destruct(tsi_peer* peer);
 
-#ifdef __cplusplus
-}
-#endif
-
 #endif /* GRPC_CORE_LIB_SECURITY_TRANSPORT_SECURITY_CONNECTOR_H */
diff --git a/src/core/lib/security/transport/security_handshaker.h b/src/core/lib/security/transport/security_handshaker.h
index 174f70f..6c3a051 100644
--- a/src/core/lib/security/transport/security_handshaker.h
+++ b/src/core/lib/security/transport/security_handshaker.h
@@ -23,10 +23,6 @@
 #include "src/core/lib/iomgr/exec_ctx.h"
 #include "src/core/lib/security/transport/security_connector.h"
 
-#ifdef __cplusplus
-extern "C" {
-#endif
-
 /// Creates a security handshaker using \a handshaker.
 grpc_handshaker* grpc_security_handshaker_create(
     grpc_exec_ctx* exec_ctx, tsi_handshaker* handshaker,
@@ -35,8 +31,4 @@
 /// Registers security handshaker factories.
 void grpc_security_register_handshaker_factories();
 
-#ifdef __cplusplus
-}
-#endif
-
 #endif /* GRPC_CORE_LIB_SECURITY_TRANSPORT_SECURITY_HANDSHAKER_H */
diff --git a/src/core/lib/security/transport/tsi_error.h b/src/core/lib/security/transport/tsi_error.h
index 4e8418f..8fa6c48 100644
--- a/src/core/lib/security/transport/tsi_error.h
+++ b/src/core/lib/security/transport/tsi_error.h
@@ -22,14 +22,6 @@
 #include "src/core/lib/iomgr/error.h"
 #include "src/core/tsi/transport_security_interface.h"
 
-#ifdef __cplusplus
-extern "C" {
-#endif
-
 grpc_error* grpc_set_tsi_error_result(grpc_error* error, tsi_result result);
 
-#ifdef __cplusplus
-}
-#endif
-
 #endif /* GRPC_CORE_LIB_SECURITY_TRANSPORT_TSI_ERROR_H */
diff --git a/src/core/lib/security/util/json_util.h b/src/core/lib/security/util/json_util.h
index 7538f76..b7e46d4 100644
--- a/src/core/lib/security/util/json_util.h
+++ b/src/core/lib/security/util/json_util.h
@@ -28,10 +28,6 @@
 #define GRPC_AUTH_JSON_TYPE_SERVICE_ACCOUNT "service_account"
 #define GRPC_AUTH_JSON_TYPE_AUTHORIZED_USER "authorized_user"
 
-#ifdef __cplusplus
-extern "C" {
-#endif
-
 // Gets a child property from a json node.
 const char* grpc_json_get_string_property(const grpc_json* json,
                                           const char* prop_name);
@@ -41,8 +37,4 @@
 bool grpc_copy_json_string_property(const grpc_json* json,
                                     const char* prop_name, char** copied_value);
 
-#ifdef __cplusplus
-}
-#endif
-
 #endif /* GRPC_CORE_LIB_SECURITY_UTIL_JSON_UTIL_H */
diff --git a/src/core/lib/slice/b64.h b/src/core/lib/slice/b64.h
index 467f5d8..f86c1d9 100644
--- a/src/core/lib/slice/b64.h
+++ b/src/core/lib/slice/b64.h
@@ -21,10 +21,6 @@
 
 #include <grpc/slice.h>
 
-#ifdef __cplusplus
-extern "C" {
-#endif
-
 /* Encodes data using base64. It is the caller's responsability to free
    the returned char * using gpr_free. Returns NULL on NULL input.
    TODO(makdharma) : change the flags to bool from int */
@@ -51,8 +47,4 @@
 grpc_slice grpc_base64_decode_with_len(grpc_exec_ctx* exec_ctx, const char* b64,
                                        size_t b64_len, int url_safe);
 
-#ifdef __cplusplus
-}
-#endif
-
 #endif /* GRPC_CORE_LIB_SLICE_B64_H */
diff --git a/src/core/lib/slice/percent_encoding.h b/src/core/lib/slice/percent_encoding.h
index 22b5e8d..a1009ff 100644
--- a/src/core/lib/slice/percent_encoding.h
+++ b/src/core/lib/slice/percent_encoding.h
@@ -30,10 +30,6 @@
 
 #include <grpc/slice.h>
 
-#ifdef __cplusplus
-extern "C" {
-#endif
-
 /* URL percent encoding spec bitfield (usabel as 'unreserved_bytes' in
    grpc_percent_encode_slice, grpc_strict_percent_decode_slice).
    Flags [A-Za-z0-9-_.~] as unreserved bytes for the percent encoding routines
@@ -64,8 +60,4 @@
    This cannot fail. */
 grpc_slice grpc_permissive_percent_decode_slice(grpc_slice slice_in);
 
-#ifdef __cplusplus
-}
-#endif
-
 #endif /* GRPC_CORE_LIB_SLICE_PERCENT_ENCODING_H */
diff --git a/src/core/lib/slice/slice_hash_table.h b/src/core/lib/slice/slice_hash_table.h
index f86f25e..85102bd 100644
--- a/src/core/lib/slice/slice_hash_table.h
+++ b/src/core/lib/slice/slice_hash_table.h
@@ -19,10 +19,6 @@
 
 #include "src/core/lib/transport/metadata.h"
 
-#ifdef __cplusplus
-extern "C" {
-#endif
-
 /** Hash table implementation.
  *
  * This implementation uses open addressing
@@ -71,8 +67,4 @@
 int grpc_slice_hash_table_cmp(const grpc_slice_hash_table* a,
                               const grpc_slice_hash_table* b);
 
-#ifdef __cplusplus
-}
-#endif
-
 #endif /* GRPC_CORE_LIB_SLICE_SLICE_HASH_TABLE_H */
diff --git a/src/core/lib/slice/slice_internal.h b/src/core/lib/slice/slice_internal.h
index 2439fc0..ed0070d 100644
--- a/src/core/lib/slice/slice_internal.h
+++ b/src/core/lib/slice/slice_internal.h
@@ -24,14 +24,13 @@
 
 #include "src/core/lib/iomgr/exec_ctx.h"
 
-#ifdef __cplusplus
-extern "C" {
-#endif
-
 grpc_slice grpc_slice_ref_internal(grpc_slice slice);
 void grpc_slice_unref_internal(grpc_exec_ctx* exec_ctx, grpc_slice slice);
 void grpc_slice_buffer_reset_and_unref_internal(grpc_exec_ctx* exec_ctx,
                                                 grpc_slice_buffer* sb);
+void grpc_slice_buffer_partial_unref_internal(grpc_exec_ctx* exec_ctx,
+                                              grpc_slice_buffer* sb,
+                                              size_t idx);
 void grpc_slice_buffer_destroy_internal(grpc_exec_ctx* exec_ctx,
                                         grpc_slice_buffer* sb);
 
@@ -50,8 +49,4 @@
 uint32_t grpc_static_slice_hash(grpc_slice s);
 int grpc_static_slice_eq(grpc_slice a, grpc_slice b);
 
-#ifdef __cplusplus
-}
-#endif
-
 #endif /* GRPC_CORE_LIB_SLICE_SLICE_INTERNAL_H */
diff --git a/src/core/lib/slice/slice_string_helpers.h b/src/core/lib/slice/slice_string_helpers.h
index acbc41e..7f51b11 100644
--- a/src/core/lib/slice/slice_string_helpers.h
+++ b/src/core/lib/slice/slice_string_helpers.h
@@ -28,10 +28,6 @@
 
 #include "src/core/lib/support/string.h"
 
-#ifdef __cplusplus
-extern "C" {
-#endif
-
 /* Calls gpr_dump on a slice. */
 char* grpc_dump_slice(grpc_slice slice, uint32_t flags);
 
@@ -41,8 +37,4 @@
 
 bool grpc_parse_slice_to_uint32(grpc_slice str, uint32_t* result);
 
-#ifdef __cplusplus
-}
-#endif
-
 #endif /* GRPC_CORE_LIB_SLICE_SLICE_STRING_HELPERS_H */
diff --git a/src/core/lib/slice/slice_traits.h b/src/core/lib/slice/slice_traits.h
index 7fdb675..4b898bd 100644
--- a/src/core/lib/slice/slice_traits.h
+++ b/src/core/lib/slice/slice_traits.h
@@ -22,16 +22,8 @@
 #include <grpc/slice.h>
 #include <stdbool.h>
 
-#ifdef __cplusplus
-extern "C" {
-#endif
-
 bool grpc_slice_is_legal_header(grpc_slice s);
 bool grpc_slice_is_legal_nonbin_header(grpc_slice s);
 bool grpc_slice_is_bin_suffixed(grpc_slice s);
 
-#ifdef __cplusplus
-}
-#endif
-
 #endif /* GRPC_CORE_LIB_SLICE_SLICE_TRAITS_H */
diff --git a/src/core/lib/support/abstract.h b/src/core/lib/support/abstract.h
new file mode 100644
index 0000000..5498769
--- /dev/null
+++ b/src/core/lib/support/abstract.h
@@ -0,0 +1,29 @@
+/*
+ *
+ * Copyright 2017 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#ifndef GRPC_CORE_LIB_SUPPORT_ABSTRACT_H
+#define GRPC_CORE_LIB_SUPPORT_ABSTRACT_H
+
+// This is needed to support abstract base classes in the c core. Since gRPC
+// doesn't have a c++ runtime, it will hit a linker error on delete unless
+// we define a virtual operator delete. See this blog for more info:
+// https://eli.thegreenplace.net/2015/c-deleting-destructors-and-virtual-operator-delete/
+#define GRPC_ABSTRACT_BASE_CLASS \
+  static void operator delete(void* p) { abort(); }
+
+#endif /* GRPC_CORE_LIB_SUPPORT_ABSTRACT_H */
diff --git a/src/core/lib/support/arena.h b/src/core/lib/support/arena.h
index 4d43c56..cfe973a 100644
--- a/src/core/lib/support/arena.h
+++ b/src/core/lib/support/arena.h
@@ -27,10 +27,6 @@
 
 #include <stddef.h>
 
-#ifdef __cplusplus
-extern "C" {
-#endif
-
 typedef struct gpr_arena gpr_arena;
 
 // Create an arena, with \a initial_size bytes in the first allocated buffer
@@ -40,8 +36,4 @@
 // Destroy an arena, returning the total number of bytes allocated
 size_t gpr_arena_destroy(gpr_arena* arena);
 
-#ifdef __cplusplus
-}
-#endif
-
 #endif /* GRPC_CORE_LIB_SUPPORT_ARENA_H */
diff --git a/src/core/lib/support/cpu_posix.cc b/src/core/lib/support/cpu_posix.cc
index 503a96b..bca14a0 100644
--- a/src/core/lib/support/cpu_posix.cc
+++ b/src/core/lib/support/cpu_posix.cc
@@ -18,21 +18,23 @@
 
 #include <grpc/support/port_platform.h>
 
-#ifdef GPR_CPU_POSIX
+#if defined(GPR_CPU_POSIX)
 
 #include <errno.h>
+#include <pthread.h>
 #include <string.h>
 #include <unistd.h>
 
+#include <grpc/support/alloc.h>
 #include <grpc/support/cpu.h>
 #include <grpc/support/log.h>
 #include <grpc/support/sync.h>
 #include <grpc/support/useful.h>
 
-static __thread char magic_thread_local;
-
 static long ncpus = 0;
 
+static pthread_key_t thread_id_key;
+
 static void init_ncpus() {
   ncpus = sysconf(_SC_NPROCESSORS_ONLN);
   if (ncpus < 1 || ncpus > INT32_MAX) {
@@ -47,12 +49,32 @@
   return (unsigned)ncpus;
 }
 
+static void delete_thread_id(void* value) {
+  if (value) {
+    gpr_free(value);
+  }
+}
+
+static void init_thread_id_key(void) {
+  pthread_key_create(&thread_id_key, delete_thread_id);
+}
+
 unsigned gpr_cpu_current_cpu(void) {
   /* NOTE: there's no way I know to return the actual cpu index portably...
      most code that's using this is using it to shard across work queues though,
      so here we use thread identity instead to achieve a similar though not
      identical effect */
-  return (unsigned)GPR_HASH_POINTER(&magic_thread_local, gpr_cpu_num_cores());
+  static gpr_once once = GPR_ONCE_INIT;
+  gpr_once_init(&once, init_thread_id_key);
+
+  unsigned int* thread_id =
+      static_cast<unsigned int*>(pthread_getspecific(thread_id_key));
+  if (thread_id == nullptr) {
+    thread_id = static_cast<unsigned int*>(gpr_malloc(sizeof(unsigned int)));
+    pthread_setspecific(thread_id_key, thread_id);
+  }
+
+  return (unsigned)GPR_HASH_POINTER(thread_id, gpr_cpu_num_cores());
 }
 
 #endif /* GPR_CPU_POSIX */
diff --git a/src/core/lib/support/debug_location.h b/src/core/lib/support/debug_location.h
new file mode 100644
index 0000000..0939da5
--- /dev/null
+++ b/src/core/lib/support/debug_location.h
@@ -0,0 +1,52 @@
+/*
+ *
+ * Copyright 2017 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#ifndef GRPC_CORE_LIB_SUPPORT_DEBUG_LOCATION_H
+#define GRPC_CORE_LIB_SUPPORT_DEBUG_LOCATION_H
+
+namespace grpc_core {
+
+// Used for tracking file and line where a call is made for debug builds.
+// No-op for non-debug builds.
+// Callers can use the DEBUG_LOCATION macro in either case.
+#ifndef NDEBUG
+class DebugLocation {
+ public:
+  DebugLocation(const char* file, int line) : file_(file), line_(line) {}
+  bool Log() const { return true; }
+  const char* file() const { return file_; }
+  int line() const { return line_; }
+
+ private:
+  const char* file_;
+  const int line_;
+};
+#define DEBUG_LOCATION DebugLocation(__FILE__, __LINE__)
+#else
+class DebugLocation {
+ public:
+  bool Log() const { return false; }
+  const char* file() const { return nullptr; }
+  int line() const { return -1; }
+};
+#define DEBUG_LOCATION DebugLocation()
+#endif
+
+}  // namespace grpc_core
+
+#endif /* GRPC_CORE_LIB_SUPPORT_DEBUG_LOCATION_H */
diff --git a/src/core/lib/support/env.h b/src/core/lib/support/env.h
index f50d7bc..2452fd3 100644
--- a/src/core/lib/support/env.h
+++ b/src/core/lib/support/env.h
@@ -21,10 +21,6 @@
 
 #include <stdio.h>
 
-#ifdef __cplusplus
-extern "C" {
-#endif
-
 /* Env utility functions */
 
 /* Gets the environment variable value with the specified name.
@@ -42,8 +38,4 @@
    level of logging. So DO NOT USE THIS. */
 const char* gpr_getenv_silent(const char* name, char** dst);
 
-#ifdef __cplusplus
-}
-#endif
-
 #endif /* GRPC_CORE_LIB_SUPPORT_ENV_H */
diff --git a/src/core/lib/support/fork.cc b/src/core/lib/support/fork.cc
new file mode 100644
index 0000000..d59ca55
--- /dev/null
+++ b/src/core/lib/support/fork.cc
@@ -0,0 +1,62 @@
+/*
+ *
+ * Copyright 2017 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include "src/core/lib/support/fork.h"
+
+#include <string.h>
+
+#include <grpc/support/alloc.h>
+#include <grpc/support/useful.h>
+
+#include "src/core/lib/support/env.h"
+
+/*
+ * NOTE: FORKING IS NOT GENERALLY SUPPORTED, THIS IS ONLY INTENDED TO WORK
+ *       AROUND VERY SPECIFIC USE CASES.
+ */
+
+static int override_fork_support_enabled = -1;
+static int fork_support_enabled;
+
+void grpc_fork_support_init() {
+#ifdef GRPC_ENABLE_FORK_SUPPORT
+  fork_support_enabled = 1;
+#else
+  fork_support_enabled = 0;
+  char* env = gpr_getenv("GRPC_ENABLE_FORK_SUPPORT");
+  if (env != NULL) {
+    static const char* truthy[] = {"yes",  "Yes",  "YES", "true",
+                                   "True", "TRUE", "1"};
+    for (size_t i = 0; i < GPR_ARRAY_SIZE(truthy); i++) {
+      if (0 == strcmp(env, truthy[i])) {
+        fork_support_enabled = 1;
+      }
+    }
+    gpr_free(env);
+  }
+#endif
+  if (override_fork_support_enabled != -1) {
+    fork_support_enabled = override_fork_support_enabled;
+  }
+}
+
+int grpc_fork_support_enabled() { return fork_support_enabled; }
+
+void grpc_enable_fork_support(int enable) {
+  override_fork_support_enabled = enable;
+}
diff --git a/src/core/lib/support/fork.h b/src/core/lib/support/fork.h
new file mode 100644
index 0000000..215d4214
--- /dev/null
+++ b/src/core/lib/support/fork.h
@@ -0,0 +1,35 @@
+/*
+ *
+ * Copyright 2017 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#ifndef GRPC_CORE_LIB_SUPPORT_FORK_H
+#define GRPC_CORE_LIB_SUPPORT_FORK_H
+
+/*
+ * NOTE: FORKING IS NOT GENERALLY SUPPORTED, THIS IS ONLY INTENDED TO WORK
+ *       AROUND VERY SPECIFIC USE CASES.
+ */
+
+void grpc_fork_support_init(void);
+
+int grpc_fork_support_enabled(void);
+
+// Test only:  Must be called before grpc_init(), and overrides
+// environment variables/compile flags
+void grpc_enable_fork_support(int enable);
+
+#endif /* GRPC_CORE_LIB_SUPPORT_FORK_H */
diff --git a/src/core/lib/support/log.cc b/src/core/lib/support/log.cc
index e9adc6c..2a40745 100644
--- a/src/core/lib/support/log.cc
+++ b/src/core/lib/support/log.cc
@@ -27,7 +27,7 @@
 #include <stdio.h>
 #include <string.h>
 
-extern "C" void gpr_default_log(gpr_log_func_args* args);
+void gpr_default_log(gpr_log_func_args* args);
 static gpr_atm g_log_func = (gpr_atm)gpr_default_log;
 static gpr_atm g_min_severity_to_print = GPR_LOG_VERBOSITY_UNSET;
 
diff --git a/src/core/lib/support/log_android.cc b/src/core/lib/support/log_android.cc
index 73d24cd..0d3ac0f 100644
--- a/src/core/lib/support/log_android.cc
+++ b/src/core/lib/support/log_android.cc
@@ -39,8 +39,8 @@
   return ANDROID_LOG_DEFAULT;
 }
 
-extern "C" void gpr_log(const char* file, int line, gpr_log_severity severity,
-                        const char* format, ...) {
+void gpr_log(const char* file, int line, gpr_log_severity severity,
+             const char* format, ...) {
   char* message = NULL;
   va_list args;
   va_start(args, format);
@@ -50,7 +50,7 @@
   free(message);
 }
 
-extern "C" void gpr_default_log(gpr_log_func_args* args) {
+void gpr_default_log(gpr_log_func_args* args) {
   const char* final_slash;
   const char* display_file;
   char* output = NULL;
diff --git a/src/core/lib/support/log_linux.cc b/src/core/lib/support/log_linux.cc
index e0e277f..6b1f1c7 100644
--- a/src/core/lib/support/log_linux.cc
+++ b/src/core/lib/support/log_linux.cc
@@ -56,7 +56,7 @@
   free(message);
 }
 
-extern "C" void gpr_default_log(gpr_log_func_args* args) {
+void gpr_default_log(gpr_log_func_args* args) {
   const char* final_slash;
   char* prefix;
   const char* display_file;
diff --git a/src/core/lib/support/log_posix.cc b/src/core/lib/support/log_posix.cc
index e765f91..9fab480 100644
--- a/src/core/lib/support/log_posix.cc
+++ b/src/core/lib/support/log_posix.cc
@@ -56,7 +56,7 @@
   gpr_free(allocated);
 }
 
-extern "C" void gpr_default_log(gpr_log_func_args* args) {
+void gpr_default_log(gpr_log_func_args* args) {
   const char* final_slash;
   const char* display_file;
   char time_buffer[64];
diff --git a/src/core/lib/support/log_windows.cc b/src/core/lib/support/log_windows.cc
index d448179..0013bf4 100644
--- a/src/core/lib/support/log_windows.cc
+++ b/src/core/lib/support/log_windows.cc
@@ -65,7 +65,7 @@
 }
 
 /* Simple starter implementation */
-extern "C" void gpr_default_log(gpr_log_func_args* args) {
+void gpr_default_log(gpr_log_func_args* args) {
   const char* final_slash;
   const char* display_file;
   char time_buffer[64];
diff --git a/src/core/lib/support/manual_constructor.h b/src/core/lib/support/manual_constructor.h
index d753cf9..fda7653 100644
--- a/src/core/lib/support/manual_constructor.h
+++ b/src/core/lib/support/manual_constructor.h
@@ -22,12 +22,147 @@
 // manually construct a region of memory with some type
 
 #include <stddef.h>
+#include <stdlib.h>
 #include <new>
 #include <type_traits>
 #include <utility>
 
+#include <grpc/support/log.h>
+
 namespace grpc_core {
 
+// this contains templated helpers needed to implement the ManualConstructors
+// in this file.
+namespace manual_ctor_impl {
+
+// is_one_of returns true it a class, Member, is present in a variadic list of
+// classes, List.
+template <class Member, class... List>
+class is_one_of;
+
+template <class Member, class... List>
+class is_one_of<Member, Member, List...> {
+ public:
+  static constexpr const bool value = true;
+};
+
+template <class Member, class A, class... List>
+class is_one_of<Member, A, List...> {
+ public:
+  static constexpr const bool value = is_one_of<Member, List...>::value;
+};
+
+template <class Member>
+class is_one_of<Member> {
+ public:
+  static constexpr const bool value = false;
+};
+
+// max_size_of returns sizeof(Type) for the largest type in the variadic list
+// of classes, Types.
+template <class... Types>
+class max_size_of;
+
+template <class A>
+class max_size_of<A> {
+ public:
+  static constexpr const size_t value = sizeof(A);
+};
+
+template <class A, class... B>
+class max_size_of<A, B...> {
+ public:
+  static constexpr const size_t value = sizeof(A) > max_size_of<B...>::value
+                                            ? sizeof(A)
+                                            : max_size_of<B...>::value;
+};
+
+// max_size_of returns alignof(Type) for the largest type in the variadic list
+// of classes, Types.
+template <class... Types>
+class max_align_of;
+
+template <class A>
+class max_align_of<A> {
+ public:
+  static constexpr const size_t value = alignof(A);
+};
+
+template <class A, class... B>
+class max_align_of<A, B...> {
+ public:
+  static constexpr const size_t value = alignof(A) > max_align_of<B...>::value
+                                            ? alignof(A)
+                                            : max_align_of<B...>::value;
+};
+
+}  // namespace manual_ctor_impl
+
+template <class BaseType, class... DerivedTypes>
+class PolymorphicManualConstructor {
+ public:
+  // No constructor or destructor because one of the most useful uses of
+  // this class is as part of a union, and members of a union could not have
+  // constructors or destructors till C++11.  And, anyway, the whole point of
+  // this class is to bypass constructor and destructor.
+
+  BaseType* get() { return reinterpret_cast<BaseType*>(&space_); }
+  const BaseType* get() const {
+    return reinterpret_cast<const BaseType*>(&space_);
+  }
+
+  BaseType* operator->() { return get(); }
+  const BaseType* operator->() const { return get(); }
+
+  BaseType& operator*() { return *get(); }
+  const BaseType& operator*() const { return *get(); }
+
+  template <class DerivedType>
+  void Init() {
+    FinishInit(new (&space_) DerivedType);
+  }
+
+  // Init() constructs the Type instance using the given arguments
+  // (which are forwarded to Type's constructor).
+  //
+  // Note that Init() with no arguments performs default-initialization,
+  // not zero-initialization (i.e it behaves the same as "new Type;", not
+  // "new Type();"), so it will leave non-class types uninitialized.
+  template <class DerivedType, typename... Ts>
+  void Init(Ts&&... args) {
+    FinishInit(new (&space_) DerivedType(std::forward<Ts>(args)...));
+  }
+
+  // Init() that is equivalent to copy and move construction.
+  // Enables usage like this:
+  //   ManualConstructor<std::vector<int>> v;
+  //   v.Init({1, 2, 3});
+  template <class DerivedType>
+  void Init(const DerivedType& x) {
+    FinishInit(new (&space_) DerivedType(x));
+  }
+  template <class DerivedType>
+  void Init(DerivedType&& x) {
+    FinishInit(new (&space_) DerivedType(std::move(x)));
+  }
+
+  void Destroy() { get()->~BaseType(); }
+
+ private:
+  template <class DerivedType>
+  void FinishInit(DerivedType* p) {
+    static_assert(
+        manual_ctor_impl::is_one_of<DerivedType, DerivedTypes...>::value,
+        "DerivedType must be one of the predeclared DerivedTypes");
+    GPR_ASSERT(reinterpret_cast<BaseType*>(static_cast<DerivedType*>(p)) == p);
+  }
+
+  typename std::aligned_storage<
+      grpc_core::manual_ctor_impl::max_size_of<DerivedTypes...>::value,
+      grpc_core::manual_ctor_impl::max_align_of<DerivedTypes...>::value>::type
+      space_;
+};
+
 template <typename Type>
 class ManualConstructor {
  public:
diff --git a/src/core/lib/support/mpscq.h b/src/core/lib/support/mpscq.h
index fb22742..648ead1 100644
--- a/src/core/lib/support/mpscq.h
+++ b/src/core/lib/support/mpscq.h
@@ -24,10 +24,6 @@
 #include <stdbool.h>
 #include <stddef.h>
 
-#ifdef __cplusplus
-extern "C" {
-#endif
-
 // 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
@@ -84,8 +80,5 @@
 // Pop a node.  Returns NULL only if the queue was empty at some point after
 // calling this function
 gpr_mpscq_node* gpr_locked_mpscq_pop(gpr_locked_mpscq* q);
-#ifdef __cplusplus
-}
-#endif
 
 #endif /* GRPC_CORE_LIB_SUPPORT_MPSCQ_H */
diff --git a/src/core/lib/support/murmur_hash.cc b/src/core/lib/support/murmur_hash.cc
index 4e08579..2f0e71a 100644
--- a/src/core/lib/support/murmur_hash.cc
+++ b/src/core/lib/support/murmur_hash.cc
@@ -30,22 +30,19 @@
   (h) ^= (h) >> 16;
 
 uint32_t gpr_murmur_hash3(const void* key, size_t len, uint32_t seed) {
-  const uint8_t* data = (const uint8_t*)key;
-  const size_t nblocks = len / 4;
-  int i;
-
   uint32_t h1 = seed;
   uint32_t k1;
 
   const uint32_t c1 = 0xcc9e2d51;
   const uint32_t c2 = 0x1b873593;
 
-  const uint32_t* blocks = ((const uint32_t*)key) + nblocks;
-  const uint8_t* tail = (const uint8_t*)(data + nblocks * 4);
+  const uint8_t* keyptr = (const uint8_t*)key;
+  const size_t bsize = sizeof(k1);
+  const size_t nblocks = len / bsize;
 
   /* body */
-  for (i = -(int)nblocks; i; i++) {
-    memcpy(&k1, blocks + i, sizeof(uint32_t));
+  for (size_t i = 0; i < nblocks; i++, keyptr += bsize) {
+    memcpy(&k1, keyptr, bsize);
 
     k1 *= c1;
     k1 = ROTL32(k1, 15);
@@ -61,13 +58,13 @@
   /* tail */
   switch (len & 3) {
     case 3:
-      k1 ^= ((uint32_t)tail[2]) << 16;
+      k1 ^= ((uint32_t)keyptr[2]) << 16;
     /* fallthrough */
     case 2:
-      k1 ^= ((uint32_t)tail[1]) << 8;
+      k1 ^= ((uint32_t)keyptr[1]) << 8;
     /* fallthrough */
     case 1:
-      k1 ^= tail[0];
+      k1 ^= keyptr[0];
       k1 *= c1;
       k1 = ROTL32(k1, 15);
       k1 *= c2;
diff --git a/src/core/lib/support/murmur_hash.h b/src/core/lib/support/murmur_hash.h
index d02bba6..422770f 100644
--- a/src/core/lib/support/murmur_hash.h
+++ b/src/core/lib/support/murmur_hash.h
@@ -23,15 +23,7 @@
 
 #include <stddef.h>
 
-#ifdef __cplusplus
-extern "C" {
-#endif
-
 /* compute the hash of key (length len) */
 uint32_t gpr_murmur_hash3(const void* key, size_t len, uint32_t seed);
 
-#ifdef __cplusplus
-}
-#endif
-
 #endif /* GRPC_CORE_LIB_SUPPORT_MURMUR_HASH_H */
diff --git a/src/core/lib/support/ref_counted.h b/src/core/lib/support/ref_counted.h
new file mode 100644
index 0000000..4c662f9
--- /dev/null
+++ b/src/core/lib/support/ref_counted.h
@@ -0,0 +1,122 @@
+/*
+ *
+ * Copyright 2017 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#ifndef GRPC_CORE_LIB_SUPPORT_REF_COUNTED_H
+#define GRPC_CORE_LIB_SUPPORT_REF_COUNTED_H
+
+#include <grpc/support/log.h>
+#include <grpc/support/sync.h>
+
+#include "src/core/lib/debug/trace.h"
+#include "src/core/lib/support/debug_location.h"
+#include "src/core/lib/support/memory.h"
+
+namespace grpc_core {
+
+// A base class for reference-counted objects.
+// New objects should be created via New() and start with a refcount of 1.
+// When the refcount reaches 0, the object will be deleted via Delete().
+class RefCounted {
+ public:
+  void Ref() { gpr_ref(&refs_); }
+
+  void Unref() {
+    if (gpr_unref(&refs_)) {
+      Delete(this);
+    }
+  }
+
+  // Not copyable nor movable.
+  RefCounted(const RefCounted&) = delete;
+  RefCounted& operator=(const RefCounted&) = delete;
+
+ protected:
+  // Allow Delete() to access destructor.
+  template <typename T>
+  friend void Delete(T*);
+
+  RefCounted() { gpr_ref_init(&refs_, 1); }
+
+  virtual ~RefCounted() {}
+
+ private:
+  gpr_refcount refs_;
+};
+
+// An alternative version of the RefCounted base class that
+// supports tracing.  This is intended to be used in cases where the
+// object will be handled both by idiomatic C++ code using smart
+// pointers and legacy code that is manually calling Ref() and Unref().
+// Once all of our code is converted to idiomatic C++, we may be able to
+// eliminate this class.
+class RefCountedWithTracing {
+ public:
+  void Ref() { gpr_ref(&refs_); }
+
+  void Ref(const DebugLocation& location, const char* reason) {
+    if (location.Log() && trace_flag_ != nullptr && trace_flag_->enabled()) {
+      gpr_atm old_refs = gpr_atm_no_barrier_load(&refs_.count);
+      gpr_log(GPR_DEBUG, "%s:%p %s:%d ref %" PRIdPTR " -> %" PRIdPTR " %s",
+              trace_flag_->name(), this, location.file(), location.line(),
+              old_refs, old_refs + 1, reason);
+    }
+    Ref();
+  }
+
+  void Unref() {
+    if (gpr_unref(&refs_)) {
+      Delete(this);
+    }
+  }
+
+  void Unref(const DebugLocation& location, const char* reason) {
+    if (location.Log() && trace_flag_ != nullptr && trace_flag_->enabled()) {
+      gpr_atm old_refs = gpr_atm_no_barrier_load(&refs_.count);
+      gpr_log(GPR_DEBUG, "%s:%p %s:%d unref %" PRIdPTR " -> %" PRIdPTR " %s",
+              trace_flag_->name(), this, location.file(), location.line(),
+              old_refs, old_refs - 1, reason);
+    }
+    Unref();
+  }
+
+  // Not copyable nor movable.
+  RefCountedWithTracing(const RefCountedWithTracing&) = delete;
+  RefCountedWithTracing& operator=(const RefCountedWithTracing&) = delete;
+
+ protected:
+  // Allow Delete() to access destructor.
+  template <typename T>
+  friend void Delete(T*);
+
+  RefCountedWithTracing() : RefCountedWithTracing(nullptr) {}
+
+  explicit RefCountedWithTracing(TraceFlag* trace_flag)
+      : trace_flag_(trace_flag) {
+    gpr_ref_init(&refs_, 1);
+  }
+
+  virtual ~RefCountedWithTracing() {}
+
+ private:
+  TraceFlag* trace_flag_ = nullptr;
+  gpr_refcount refs_;
+};
+
+}  // namespace grpc_core
+
+#endif /* GRPC_CORE_LIB_SUPPORT_REF_COUNTED_H */
diff --git a/src/core/lib/support/ref_counted_ptr.h b/src/core/lib/support/ref_counted_ptr.h
new file mode 100644
index 0000000..dc2385e
--- /dev/null
+++ b/src/core/lib/support/ref_counted_ptr.h
@@ -0,0 +1,90 @@
+/*
+ *
+ * Copyright 2017 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#ifndef GRPC_CORE_LIB_SUPPORT_REF_COUNTED_PTR_H
+#define GRPC_CORE_LIB_SUPPORT_REF_COUNTED_PTR_H
+
+#include <utility>
+
+#include "src/core/lib/support/memory.h"
+
+namespace grpc_core {
+
+// A smart pointer class for objects that provide Ref() and Unref() methods,
+// such as those provided by the RefCounted base class.
+template <typename T>
+class RefCountedPtr {
+ public:
+  RefCountedPtr() {}
+
+  // If value is non-null, we take ownership of a ref to it.
+  explicit RefCountedPtr(T* value) { value_ = value; }
+
+  // Move support.
+  RefCountedPtr(RefCountedPtr&& other) {
+    value_ = other.value_;
+    other.value_ = nullptr;
+  }
+  RefCountedPtr& operator=(RefCountedPtr&& other) {
+    if (value_ != nullptr) value_->Unref();
+    value_ = other.value_;
+    other.value_ = nullptr;
+    return *this;
+  }
+
+  // Copy support.
+  RefCountedPtr(const RefCountedPtr& other) {
+    if (other.value_ != nullptr) other.value_->Ref();
+    value_ = other.value_;
+  }
+  RefCountedPtr& operator=(const RefCountedPtr& other) {
+    // Note: Order of reffing and unreffing is important here in case value_
+    // and other.value_ are the same object.
+    if (other.value_ != nullptr) other.value_->Ref();
+    if (value_ != nullptr) value_->Unref();
+    value_ = other.value_;
+    return *this;
+  }
+
+  ~RefCountedPtr() {
+    if (value_ != nullptr) value_->Unref();
+  }
+
+  // If value is non-null, we take ownership of a ref to it.
+  void reset(T* value = nullptr) {
+    if (value_ != nullptr) value_->Unref();
+    value_ = value;
+  }
+
+  T* get() const { return value_; }
+
+  T& operator*() const { return *value_; }
+  T* operator->() const { return value_; }
+
+ private:
+  T* value_ = nullptr;
+};
+
+template <typename T, typename... Args>
+inline RefCountedPtr<T> MakeRefCounted(Args&&... args) {
+  return RefCountedPtr<T>(New<T>(std::forward<Args>(args)...));
+}
+
+}  // namespace grpc_core
+
+#endif /* GRPC_CORE_LIB_SUPPORT_REF_COUNTED_PTR_H */
diff --git a/src/core/lib/support/stack_lockfree.cc b/src/core/lib/support/stack_lockfree.cc
deleted file mode 100644
index 7a4ede3..0000000
--- a/src/core/lib/support/stack_lockfree.cc
+++ /dev/null
@@ -1,137 +0,0 @@
-/*
- *
- * Copyright 2015 gRPC authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-#include "src/core/lib/support/stack_lockfree.h"
-
-#include <stdlib.h>
-#include <string.h>
-
-#include <grpc/support/alloc.h>
-#include <grpc/support/atm.h>
-#include <grpc/support/log.h>
-#include <grpc/support/port_platform.h>
-
-/* The lockfree node structure is a single architecture-level
-   word that allows for an atomic CAS to set it up. */
-struct lockfree_node_contents {
-  /* next thing to look at. Actual index for head, next index otherwise */
-  uint16_t index;
-#ifdef GPR_ARCH_64
-  uint16_t pad;
-  uint32_t aba_ctr;
-#else
-#ifdef GPR_ARCH_32
-  uint16_t aba_ctr;
-#else
-#error Unsupported bit width architecture
-#endif
-#endif
-};
-
-/* Use a union to make sure that these are in the same bits as an atm word */
-typedef union lockfree_node {
-  gpr_atm atm;
-  struct lockfree_node_contents contents;
-} lockfree_node;
-
-/* make sure that entries aligned to 8-bytes */
-#define ENTRY_ALIGNMENT_BITS 3
-/* reserve this entry as invalid */
-#define INVALID_ENTRY_INDEX ((1 << 16) - 1)
-
-struct gpr_stack_lockfree {
-  lockfree_node* entries;
-  lockfree_node head; /* An atomic entry describing curr head */
-};
-
-gpr_stack_lockfree* gpr_stack_lockfree_create(size_t entries) {
-  gpr_stack_lockfree* stack;
-  stack = (gpr_stack_lockfree*)gpr_malloc(sizeof(*stack));
-  /* Since we only allocate 16 bits to represent an entry number,
-   * make sure that we are within the desired range */
-  /* Reserve the highest entry number as a dummy */
-  GPR_ASSERT(entries < INVALID_ENTRY_INDEX);
-  stack->entries = (lockfree_node*)gpr_malloc_aligned(
-      entries * sizeof(stack->entries[0]), ENTRY_ALIGNMENT_BITS);
-  /* Clear out all entries */
-  memset(stack->entries, 0, entries * sizeof(stack->entries[0]));
-  memset(&stack->head, 0, sizeof(stack->head));
-
-  GPR_ASSERT(sizeof(stack->entries->atm) == sizeof(stack->entries->contents));
-
-  /* Point the head at reserved dummy entry */
-  stack->head.contents.index = INVALID_ENTRY_INDEX;
-/* Fill in the pad and aba_ctr to avoid confusing memcheck tools */
-#ifdef GPR_ARCH_64
-  stack->head.contents.pad = 0;
-#endif
-  stack->head.contents.aba_ctr = 0;
-  return stack;
-}
-
-void gpr_stack_lockfree_destroy(gpr_stack_lockfree* stack) {
-  gpr_free_aligned(stack->entries);
-  gpr_free(stack);
-}
-
-int gpr_stack_lockfree_push(gpr_stack_lockfree* stack, int entry) {
-  lockfree_node head;
-  lockfree_node newhead;
-  lockfree_node curent;
-  lockfree_node newent;
-
-  /* First fill in the entry's index and aba ctr for new head */
-  newhead.contents.index = (uint16_t)entry;
-#ifdef GPR_ARCH_64
-  /* Fill in the pad to avoid confusing memcheck tools */
-  newhead.contents.pad = 0;
-#endif
-
-  /* Also post-increment the aba_ctr */
-  curent.atm = gpr_atm_no_barrier_load(&stack->entries[entry].atm);
-  newhead.contents.aba_ctr = ++curent.contents.aba_ctr;
-  gpr_atm_no_barrier_store(&stack->entries[entry].atm, curent.atm);
-
-  do {
-    /* Atomically get the existing head value for use */
-    head.atm = gpr_atm_no_barrier_load(&(stack->head.atm));
-    /* Point to it */
-    newent.atm = gpr_atm_no_barrier_load(&stack->entries[entry].atm);
-    newent.contents.index = head.contents.index;
-    gpr_atm_no_barrier_store(&stack->entries[entry].atm, newent.atm);
-  } while (!gpr_atm_rel_cas(&(stack->head.atm), head.atm, newhead.atm));
-  /* Use rel_cas above to make sure that entry index is set properly */
-  return head.contents.index == INVALID_ENTRY_INDEX;
-}
-
-int gpr_stack_lockfree_pop(gpr_stack_lockfree* stack) {
-  lockfree_node head;
-  lockfree_node newhead;
-
-  do {
-    head.atm = gpr_atm_acq_load(&(stack->head.atm));
-    if (head.contents.index == INVALID_ENTRY_INDEX) {
-      return -1;
-    }
-    newhead.atm =
-        gpr_atm_no_barrier_load(&(stack->entries[head.contents.index].atm));
-
-  } while (!gpr_atm_no_barrier_cas(&(stack->head.atm), head.atm, newhead.atm));
-
-  return head.contents.index;
-}
diff --git a/src/core/lib/support/stack_lockfree.h b/src/core/lib/support/stack_lockfree.h
deleted file mode 100644
index 337ecc2..0000000
--- a/src/core/lib/support/stack_lockfree.h
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- *
- * Copyright 2015 gRPC authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-#ifndef GRPC_CORE_LIB_SUPPORT_STACK_LOCKFREE_H
-#define GRPC_CORE_LIB_SUPPORT_STACK_LOCKFREE_H
-
-#include <stddef.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-typedef struct gpr_stack_lockfree gpr_stack_lockfree;
-
-/* This stack must specify the maximum number of entries to track.
-   The current implementation only allows up to 65534 entries */
-gpr_stack_lockfree* gpr_stack_lockfree_create(size_t entries);
-void gpr_stack_lockfree_destroy(gpr_stack_lockfree* stack);
-
-/* Pass in a valid entry number for the next stack entry */
-/* Returns 1 if this is the first element on the stack, 0 otherwise */
-int gpr_stack_lockfree_push(gpr_stack_lockfree*, int entry);
-
-/* Returns -1 on empty or the actual entry number */
-int gpr_stack_lockfree_pop(gpr_stack_lockfree* stack);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* GRPC_CORE_LIB_SUPPORT_STACK_LOCKFREE_H */
diff --git a/src/core/lib/support/string.h b/src/core/lib/support/string.h
index 0b18ffc..dd37f0b 100644
--- a/src/core/lib/support/string.h
+++ b/src/core/lib/support/string.h
@@ -24,10 +24,6 @@
 
 #include <grpc/support/port_platform.h>
 
-#ifdef __cplusplus
-extern "C" {
-#endif
-
 /* String utility functions */
 
 /* Flags for gpr_dump function. */
@@ -109,8 +105,5 @@
 
 /** Return true if lower(s) equals "true", "yes" or "1", otherwise false. */
 bool gpr_is_true(const char* s);
-#ifdef __cplusplus
-}
-#endif
 
 #endif /* GRPC_CORE_LIB_SUPPORT_STRING_H */
diff --git a/src/core/lib/support/string_windows.h b/src/core/lib/support/string_windows.h
index 6771647..7c7f31e 100644
--- a/src/core/lib/support/string_windows.h
+++ b/src/core/lib/support/string_windows.h
@@ -21,10 +21,6 @@
 
 #include <grpc/support/port_platform.h>
 
-#ifdef __cplusplus
-extern "C" {
-#endif
-
 #ifdef GPR_WINDOWS
 
 /* These allocate new strings using gpr_malloc to convert from and to utf-8. */
@@ -33,8 +29,4 @@
 
 #endif /* GPR_WINDOWS */
 
-#ifdef __cplusplus
-}
-#endif
-
 #endif /* GRPC_CORE_LIB_SUPPORT_STRING_WINDOWS_H */
diff --git a/src/core/lib/support/thd_internal.h b/src/core/lib/support/thd_internal.h
new file mode 100644
index 0000000..38bffc8
--- /dev/null
+++ b/src/core/lib/support/thd_internal.h
@@ -0,0 +1,30 @@
+/*
+ *
+ * Copyright 2015 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#ifndef GRPC_CORE_LIB_SUPPORT_THD_INTERNAL_H
+#define GRPC_CORE_LIB_SUPPORT_THD_INTERNAL_H
+
+#include <grpc/support/time.h>
+
+/* Internal interfaces between modules within the gpr support library.  */
+void gpr_thd_init();
+
+/* Wait for all outstanding threads to finish, up to deadline */
+int gpr_await_threads(gpr_timespec deadline);
+
+#endif /* GRPC_CORE_LIB_SUPPORT_THD_INTERNAL_H */
diff --git a/src/core/lib/support/thd_posix.cc b/src/core/lib/support/thd_posix.cc
index 02e3846..c2a4f41 100644
--- a/src/core/lib/support/thd_posix.cc
+++ b/src/core/lib/support/thd_posix.cc
@@ -24,22 +24,34 @@
 
 #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 <pthread.h>
 #include <stdlib.h>
 #include <string.h>
 
+#include "src/core/lib/support/fork.h"
+
+static gpr_mu g_mu;
+static gpr_cv g_cv;
+static int g_thread_count;
+static int g_awaiting_threads;
+
 struct thd_arg {
   void (*body)(void* arg); /* body of a thread */
   void* arg;               /* argument to a thread */
 };
 
+static void inc_thd_count();
+static void dec_thd_count();
+
 /* Body of every thread started via gpr_thd_new. */
 static void* thread_body(void* v) {
   struct thd_arg a = *(struct thd_arg*)v;
   free(v);
   (*a.body)(a.arg);
+  dec_thd_count();
   return nullptr;
 }
 
@@ -54,6 +66,7 @@
   GPR_ASSERT(a != nullptr);
   a->body = thd_body;
   a->arg = arg;
+  inc_thd_count();
 
   GPR_ASSERT(pthread_attr_init(&attr) == 0);
   if (gpr_thd_options_is_detached(options)) {
@@ -68,6 +81,7 @@
   if (!thread_started) {
     /* don't use gpr_free, as this was allocated using malloc (see above) */
     free(a);
+    dec_thd_count();
   }
   *t = (gpr_thd_id)p;
   return thread_started;
@@ -77,4 +91,46 @@
 
 void gpr_thd_join(gpr_thd_id t) { pthread_join((pthread_t)t, nullptr); }
 
+/*****************************************
+ * Only used when fork support is enabled
+ */
+
+static void inc_thd_count() {
+  if (grpc_fork_support_enabled()) {
+    gpr_mu_lock(&g_mu);
+    g_thread_count++;
+    gpr_mu_unlock(&g_mu);
+  }
+}
+
+static void dec_thd_count() {
+  if (grpc_fork_support_enabled()) {
+    gpr_mu_lock(&g_mu);
+    g_thread_count--;
+    if (g_awaiting_threads && g_thread_count == 0) {
+      gpr_cv_signal(&g_cv);
+    }
+    gpr_mu_unlock(&g_mu);
+  }
+}
+
+void gpr_thd_init() {
+  gpr_mu_init(&g_mu);
+  gpr_cv_init(&g_cv);
+  g_thread_count = 0;
+  g_awaiting_threads = 0;
+}
+
+int gpr_await_threads(gpr_timespec deadline) {
+  gpr_mu_lock(&g_mu);
+  g_awaiting_threads = 1;
+  int res = 0;
+  if (g_thread_count > 0) {
+    res = gpr_cv_wait(&g_cv, &g_mu, deadline);
+  }
+  g_awaiting_threads = 0;
+  gpr_mu_unlock(&g_mu);
+  return res == 0;
+}
+
 #endif /* GPR_POSIX_SYNC */
diff --git a/src/core/lib/support/thd_windows.cc b/src/core/lib/support/thd_windows.cc
index 5bda7f4..0875c2f 100644
--- a/src/core/lib/support/thd_windows.cc
+++ b/src/core/lib/support/thd_windows.cc
@@ -50,6 +50,8 @@
   gpr_free(t);
 }
 
+void gpr_thd_init(void) {}
+
 /* Body of every thread started via gpr_thd_new. */
 static DWORD WINAPI thread_body(void* v) {
   g_thd_info = (struct thd_info*)v;
diff --git a/src/core/lib/support/time_posix.cc b/src/core/lib/support/time_posix.cc
index 7f65205..47a8494 100644
--- a/src/core/lib/support/time_posix.cc
+++ b/src/core/lib/support/time_posix.cc
@@ -127,9 +127,7 @@
 }
 #endif
 
-extern "C" {
 gpr_timespec (*gpr_now_impl)(gpr_clock_type clock_type) = now_impl;
-}
 
 #ifdef GPR_LOW_LEVEL_COUNTERS
 gpr_atm gpr_now_call_count;
diff --git a/src/core/lib/support/time_precise.h b/src/core/lib/support/time_precise.h
index 3befda3..35cd154 100644
--- a/src/core/lib/support/time_precise.h
+++ b/src/core/lib/support/time_precise.h
@@ -21,15 +21,7 @@
 
 #include <grpc/support/time.h>
 
-#ifdef __cplusplus
-extern "C" {
-#endif
-
 void gpr_precise_clock_init(void);
 void gpr_precise_clock_now(gpr_timespec* clk);
 
-#ifdef __cplusplus
-}
-#endif
-
 #endif /* GRPC_CORE_LIB_SUPPORT_TIME_PRECISE_H */
diff --git a/src/core/lib/support/time_windows.cc b/src/core/lib/support/time_windows.cc
index 08c1b22..fb17e5c 100644
--- a/src/core/lib/support/time_windows.cc
+++ b/src/core/lib/support/time_windows.cc
@@ -68,9 +68,7 @@
   return now_tv;
 }
 
-extern "C" {
 gpr_timespec (*gpr_now_impl)(gpr_clock_type clock_type) = now_impl;
-}
 
 gpr_timespec gpr_now(gpr_clock_type clock_type) {
   return gpr_now_impl(clock_type);
diff --git a/src/core/lib/support/tmpfile.h b/src/core/lib/support/tmpfile.h
index 437d871..c5ceda8 100644
--- a/src/core/lib/support/tmpfile.h
+++ b/src/core/lib/support/tmpfile.h
@@ -21,18 +21,10 @@
 
 #include <stdio.h>
 
-#ifdef __cplusplus
-extern "C" {
-#endif
-
 /* Creates a temporary file from a prefix.
    If tmp_filename is not NULL, *tmp_filename is assigned the name of the
    created file and it is the responsibility of the caller to gpr_free it
    unless an error occurs in which case it will be set to NULL. */
 FILE* gpr_tmpfile(const char* prefix, char** tmp_filename);
 
-#ifdef __cplusplus
-}
-#endif
-
 #endif /* GRPC_CORE_LIB_SUPPORT_TMPFILE_H */
diff --git a/src/core/lib/surface/alarm.cc b/src/core/lib/surface/alarm.cc
index d8b1f18..b1c9f7b 100644
--- a/src/core/lib/surface/alarm.cc
+++ b/src/core/lib/surface/alarm.cc
@@ -27,10 +27,8 @@
 #include "src/core/lib/iomgr/timer.h"
 #include "src/core/lib/surface/completion_queue.h"
 
-#ifndef NDEBUG
-grpc_tracer_flag grpc_trace_alarm_refcount =
-    GRPC_TRACER_INITIALIZER(false, "alarm_refcount");
-#endif
+grpc_core::DebugOnlyTraceFlag grpc_trace_alarm_refcount(false,
+                                                        "alarm_refcount");
 
 struct grpc_alarm {
   gpr_refcount refs;
@@ -59,7 +57,7 @@
 #ifndef NDEBUG
 static void alarm_ref_dbg(grpc_alarm* alarm, const char* reason,
                           const char* file, int line) {
-  if (GRPC_TRACER_ON(grpc_trace_alarm_refcount)) {
+  if (grpc_trace_alarm_refcount.enabled()) {
     gpr_atm val = gpr_atm_no_barrier_load(&alarm->refs.count);
     gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG,
             "Alarm:%p  ref %" PRIdPTR " -> %" PRIdPTR " %s", alarm, val,
@@ -71,7 +69,7 @@
 
 static void alarm_unref_dbg(grpc_alarm* alarm, const char* reason,
                             const char* file, int line) {
-  if (GRPC_TRACER_ON(grpc_trace_alarm_refcount)) {
+  if (grpc_trace_alarm_refcount.enabled()) {
     gpr_atm val = gpr_atm_no_barrier_load(&alarm->refs.count);
     gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG,
             "Alarm:%p  Unref %" PRIdPTR " -> %" PRIdPTR " %s", alarm, val,
@@ -103,7 +101,7 @@
   grpc_alarm* alarm = (grpc_alarm*)gpr_malloc(sizeof(grpc_alarm));
 
 #ifndef NDEBUG
-  if (GRPC_TRACER_ON(grpc_trace_alarm_refcount)) {
+  if (grpc_trace_alarm_refcount.enabled()) {
     gpr_log(GPR_DEBUG, "Alarm:%p created (ref: 1)", alarm);
   }
 #endif
diff --git a/src/core/lib/surface/alarm_internal.h b/src/core/lib/surface/alarm_internal.h
index 136b605..99e9812 100644
--- a/src/core/lib/surface/alarm_internal.h
+++ b/src/core/lib/surface/alarm_internal.h
@@ -22,14 +22,10 @@
 #include <grpc/support/log.h>
 #include "src/core/lib/debug/trace.h"
 
-#ifdef __cplusplus
-extern "C" {
-#endif
+extern grpc_core::DebugOnlyTraceFlag grpc_trace_alarm_refcount;
 
 #ifndef NDEBUG
 
-extern grpc_tracer_flag grpc_trace_alarm_refcount;
-
 #define GRPC_ALARM_REF(a, reason) alarm_ref_dbg(a, reason, __FILE__, __LINE__)
 #define GRPC_ALARM_UNREF(a, reason) \
   alarm_unref_dbg(a, reason, __FILE__, __LINE__)
@@ -41,8 +37,4 @@
 
 #endif /* defined(NDEBUG) */
 
-#ifdef __cplusplus
-}
-#endif
-
 #endif /* GRPC_CORE_LIB_SURFACE_ALARM_INTERNAL_H */
diff --git a/src/core/lib/surface/api_trace.cc b/src/core/lib/surface/api_trace.cc
index 5697330..7ab836a 100644
--- a/src/core/lib/surface/api_trace.cc
+++ b/src/core/lib/surface/api_trace.cc
@@ -19,4 +19,4 @@
 #include "src/core/lib/surface/api_trace.h"
 #include "src/core/lib/debug/trace.h"
 
-grpc_tracer_flag grpc_api_trace = GRPC_TRACER_INITIALIZER(false, "api");
+grpc_core::TraceFlag grpc_api_trace(false, "api");
diff --git a/src/core/lib/surface/api_trace.h b/src/core/lib/surface/api_trace.h
index 105abdf..a4e11ce 100644
--- a/src/core/lib/surface/api_trace.h
+++ b/src/core/lib/surface/api_trace.h
@@ -22,11 +22,7 @@
 #include <grpc/support/log.h>
 #include "src/core/lib/debug/trace.h"
 
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-extern grpc_tracer_flag grpc_api_trace;
+extern grpc_core::TraceFlag grpc_api_trace;
 
 /* Provide unwrapping macros because we're in C89 and variadic macros weren't
    introduced until C99... */
@@ -47,12 +43,8 @@
 /* Due to the limitations of C89's preprocessor, the arity of the var-arg list
    'nargs' must be specified. */
 #define GRPC_API_TRACE(fmt, nargs, args)                      \
-  if (GRPC_TRACER_ON(grpc_api_trace)) {                       \
+  if (grpc_api_trace.enabled()) {                             \
     gpr_log(GPR_INFO, fmt GRPC_API_TRACE_UNWRAP##nargs args); \
   }
 
-#ifdef __cplusplus
-}
-#endif
-
 #endif /* GRPC_CORE_LIB_SURFACE_API_TRACE_H */
diff --git a/src/core/lib/surface/call.cc b/src/core/lib/surface/call.cc
index 3a06b0c..a2eb02b 100644
--- a/src/core/lib/surface/call.cc
+++ b/src/core/lib/surface/call.cc
@@ -234,6 +234,7 @@
     struct {
       grpc_status_code* status;
       grpc_slice* status_details;
+      const char** error_string;
     } client;
     struct {
       int* cancelled;
@@ -259,10 +260,8 @@
   gpr_atm recv_state;
 };
 
-grpc_tracer_flag grpc_call_error_trace =
-    GRPC_TRACER_INITIALIZER(false, "call_error");
-grpc_tracer_flag grpc_compression_trace =
-    GRPC_TRACER_INITIALIZER(false, "compression");
+grpc_core::TraceFlag grpc_call_error_trace(false, "call_error");
+grpc_core::TraceFlag grpc_compression_trace(false, "compression");
 
 #define CALL_STACK_FROM_CALL(call) ((grpc_call_stack*)((call) + 1))
 #define CALL_FROM_CALL_STACK(call_stack) (((grpc_call*)(call_stack)) - 1)
@@ -286,7 +285,8 @@
 static void get_final_status(grpc_exec_ctx* exec_ctx, grpc_call* call,
                              void (*set_value)(grpc_status_code code,
                                                void* user_data),
-                             void* set_value_user_data, grpc_slice* details);
+                             void* set_value_user_data, grpc_slice* details,
+                             const char** error_string);
 static void set_status_value_directly(grpc_status_code status, void* dest);
 static void set_status_from_error(grpc_exec_ctx* exec_ctx, grpc_call* call,
                                   status_source source, grpc_error* error);
@@ -548,7 +548,8 @@
   }
 
   get_final_status(exec_ctx, c, set_status_value_directly,
-                   &c->final_info.final_status, nullptr);
+                   &c->final_info.final_status, nullptr,
+                   c->final_info.error_string);
   c->final_info.stats.latency =
       gpr_time_sub(gpr_now(GPR_CLOCK_MONOTONIC), c->start_time);
 
@@ -735,16 +736,15 @@
  * FINAL STATUS CODE MANIPULATION
  */
 
-static bool get_final_status_from(grpc_exec_ctx* exec_ctx, grpc_call* call,
-                                  grpc_error* error, bool allow_ok_status,
-                                  void (*set_value)(grpc_status_code code,
-                                                    void* user_data),
-                                  void* set_value_user_data,
-                                  grpc_slice* details) {
+static bool get_final_status_from(
+    grpc_exec_ctx* exec_ctx, grpc_call* call, grpc_error* error,
+    bool allow_ok_status,
+    void (*set_value)(grpc_status_code code, void* user_data),
+    void* set_value_user_data, grpc_slice* details, const char** error_string) {
   grpc_status_code code;
   grpc_slice slice = grpc_empty_slice();
   grpc_error_get_status(exec_ctx, error, call->send_deadline, &code, &slice,
-                        nullptr);
+                        nullptr, error_string);
   if (code == GRPC_STATUS_OK && !allow_ok_status) {
     return false;
   }
@@ -759,13 +759,14 @@
 static void get_final_status(grpc_exec_ctx* exec_ctx, grpc_call* call,
                              void (*set_value)(grpc_status_code code,
                                                void* user_data),
-                             void* set_value_user_data, grpc_slice* details) {
+                             void* set_value_user_data, grpc_slice* details,
+                             const char** error_string) {
   int i;
   received_status status[STATUS_SOURCE_COUNT];
   for (i = 0; i < STATUS_SOURCE_COUNT; i++) {
     status[i] = unpack_received_status(gpr_atm_acq_load(&call->status[i]));
   }
-  if (GRPC_TRACER_ON(grpc_call_error_trace)) {
+  if (grpc_call_error_trace.enabled()) {
     gpr_log(GPR_DEBUG, "get_final_status %s", call->is_client ? "CLI" : "SVR");
     for (i = 0; i < STATUS_SOURCE_COUNT; i++) {
       if (status[i].is_set) {
@@ -783,7 +784,7 @@
           grpc_error_has_clear_grpc_status(status[i].error)) {
         if (get_final_status_from(exec_ctx, call, status[i].error,
                                   allow_ok_status != 0, set_value,
-                                  set_value_user_data, details)) {
+                                  set_value_user_data, details, error_string)) {
           return;
         }
       }
@@ -793,7 +794,7 @@
       if (status[i].is_set) {
         if (get_final_status_from(exec_ctx, call, status[i].error,
                                   allow_ok_status != 0, set_value,
-                                  set_value_user_data, details)) {
+                                  set_value_user_data, details, error_string)) {
           return;
         }
       }
@@ -1334,10 +1335,11 @@
     if (call->is_client) {
       get_final_status(exec_ctx, call, set_status_value_directly,
                        call->final_op.client.status,
-                       call->final_op.client.status_details);
+                       call->final_op.client.status_details,
+                       call->final_op.client.error_string);
     } else {
       get_final_status(exec_ctx, call, set_cancelled_value,
-                       call->final_op.server.cancelled, nullptr);
+                       call->final_op.server.cancelled, nullptr, nullptr);
     }
 
     GRPC_ERROR_UNREF(error);
@@ -1427,7 +1429,7 @@
   }
 
   if (error != GRPC_ERROR_NONE) {
-    if (GRPC_TRACER_ON(grpc_trace_operation_failures)) {
+    if (grpc_trace_operation_failures.enabled()) {
       GRPC_LOG_IF_ERROR("receiving_slice_ready", GRPC_ERROR_REF(error));
     }
     grpc_byte_stream_destroy(exec_ctx, call->receiving_stream);
@@ -1531,7 +1533,7 @@
     GPR_ASSERT(call->stream_encodings_accepted_by_peer != 0);
     if (!GPR_BITGET(call->stream_encodings_accepted_by_peer,
                     call->incoming_stream_compression_algorithm)) {
-      if (GRPC_TRACER_ON(grpc_compression_trace)) {
+      if (grpc_compression_trace.enabled()) {
         const char* algo_name = nullptr;
         grpc_stream_compression_algorithm_name(
             call->incoming_stream_compression_algorithm, &algo_name);
@@ -1574,7 +1576,7 @@
     GPR_ASSERT(call->encodings_accepted_by_peer != 0);
     if (!GPR_BITGET(call->encodings_accepted_by_peer,
                     call->incoming_compression_algorithm)) {
-      if (GRPC_TRACER_ON(grpc_compression_trace)) {
+      if (grpc_compression_trace.enabled()) {
         const char* algo_name = nullptr;
         grpc_compression_algorithm_name(call->incoming_compression_algorithm,
                                         &algo_name);
@@ -1994,6 +1996,8 @@
         call->final_op.client.status = op->data.recv_status_on_client.status;
         call->final_op.client.status_details =
             op->data.recv_status_on_client.status_details;
+        call->final_op.client.error_string =
+            op->data.recv_status_on_client.error_string;
         stream_op->recv_trailing_metadata = true;
         stream_op->collect_stats = true;
         stream_op_payload->recv_trailing_metadata.recv_trailing_metadata =
diff --git a/src/core/lib/surface/call.h b/src/core/lib/surface/call.h
index d4e596f..1d2e266 100644
--- a/src/core/lib/surface/call.h
+++ b/src/core/lib/surface/call.h
@@ -19,10 +19,6 @@
 #ifndef GRPC_CORE_LIB_SURFACE_CALL_H
 #define GRPC_CORE_LIB_SURFACE_CALL_H
 
-#ifdef __cplusplus
-extern "C" {
-#endif
-
 #include "src/core/lib/channel/channel_stack.h"
 #include "src/core/lib/channel/context.h"
 #include "src/core/lib/surface/api_trace.h"
@@ -102,8 +98,7 @@
 void* grpc_call_context_get(grpc_call* call, grpc_context_index elem);
 
 #define GRPC_CALL_LOG_BATCH(sev, call, ops, nops, tag) \
-  if (GRPC_TRACER_ON(grpc_api_trace))                  \
-  grpc_call_log_batch(sev, call, ops, nops, tag)
+  if (grpc_api_trace.enabled()) grpc_call_log_batch(sev, call, ops, nops, tag)
 
 uint8_t grpc_call_is_client(grpc_call* call);
 
@@ -112,11 +107,7 @@
 grpc_compression_algorithm grpc_call_compression_for_level(
     grpc_call* call, grpc_compression_level level);
 
-extern grpc_tracer_flag grpc_call_error_trace;
-extern grpc_tracer_flag grpc_compression_trace;
-
-#ifdef __cplusplus
-}
-#endif
+extern grpc_core::TraceFlag grpc_call_error_trace;
+extern grpc_core::TraceFlag grpc_compression_trace;
 
 #endif /* GRPC_CORE_LIB_SURFACE_CALL_H */
diff --git a/src/core/lib/surface/call_test_only.h b/src/core/lib/surface/call_test_only.h
index 2ff4a48..90444f8 100644
--- a/src/core/lib/surface/call_test_only.h
+++ b/src/core/lib/surface/call_test_only.h
@@ -21,10 +21,6 @@
 
 #include <grpc/grpc.h>
 
-#ifdef __cplusplus
-extern "C" {
-#endif
-
 /** Return the compression algorithm from \a call.
  *
  * \warning This function should \b only be used in test code. */
@@ -54,8 +50,4 @@
 grpc_stream_compression_algorithm
 grpc_call_test_only_get_incoming_stream_encodings(grpc_call* call);
 
-#ifdef __cplusplus
-}
-#endif
-
 #endif /* GRPC_CORE_LIB_SURFACE_CALL_TEST_ONLY_H */
diff --git a/src/core/lib/surface/channel.h b/src/core/lib/surface/channel.h
index 063e685..a2e53c7 100644
--- a/src/core/lib/surface/channel.h
+++ b/src/core/lib/surface/channel.h
@@ -23,10 +23,6 @@
 #include "src/core/lib/channel/channel_stack_builder.h"
 #include "src/core/lib/surface/channel_stack_type.h"
 
-#ifdef __cplusplus
-extern "C" {
-#endif
-
 grpc_channel* grpc_channel_create(grpc_exec_ctx* exec_ctx, const char* target,
                                   const grpc_channel_args* args,
                                   grpc_channel_stack_type channel_stack_type,
@@ -85,8 +81,4 @@
 grpc_compression_options grpc_channel_compression_options(
     const grpc_channel* channel);
 
-#ifdef __cplusplus
-}
-#endif
-
 #endif /* GRPC_CORE_LIB_SURFACE_CHANNEL_H */
diff --git a/src/core/lib/surface/channel_init.h b/src/core/lib/surface/channel_init.h
index 9932781..556ecc4 100644
--- a/src/core/lib/surface/channel_init.h
+++ b/src/core/lib/surface/channel_init.h
@@ -25,10 +25,6 @@
 
 #define GRPC_CHANNEL_INIT_BUILTIN_PRIORITY 10000
 
-#ifdef __cplusplus
-extern "C" {
-#endif
-
 /// This module provides a way for plugins (and the grpc core library itself)
 /// to register mutators for channel stacks.
 /// It also provides a universal entry path to run those mutators to build
@@ -74,8 +70,4 @@
                                     grpc_channel_stack_builder* builder,
                                     grpc_channel_stack_type type);
 
-#ifdef __cplusplus
-}
-#endif
-
 #endif /* GRPC_CORE_LIB_SURFACE_CHANNEL_INIT_H */
diff --git a/src/core/lib/surface/channel_stack_type.h b/src/core/lib/surface/channel_stack_type.h
index feecd3a..52f85a6 100644
--- a/src/core/lib/surface/channel_stack_type.h
+++ b/src/core/lib/surface/channel_stack_type.h
@@ -21,10 +21,6 @@
 
 #include <stdbool.h>
 
-#ifdef __cplusplus
-extern "C" {
-#endif
-
 typedef enum {
   // normal top-half client channel with load-balancing, connection management
   GRPC_CLIENT_CHANNEL,
@@ -46,8 +42,4 @@
 
 const char* grpc_channel_stack_type_string(grpc_channel_stack_type type);
 
-#ifdef __cplusplus
-}
-#endif
-
 #endif /* GRPC_CORE_LIB_SURFACE_CHANNEL_STACK_TYPE_H */
diff --git a/src/core/lib/surface/completion_queue.cc b/src/core/lib/surface/completion_queue.cc
index a171f90..98d7e35 100644
--- a/src/core/lib/surface/completion_queue.cc
+++ b/src/core/lib/surface/completion_queue.cc
@@ -40,14 +40,9 @@
 #include "src/core/lib/surface/call.h"
 #include "src/core/lib/surface/event_string.h"
 
-grpc_tracer_flag grpc_trace_operation_failures =
-    GRPC_TRACER_INITIALIZER(false, "op_failure");
-#ifndef NDEBUG
-grpc_tracer_flag grpc_trace_pending_tags =
-    GRPC_TRACER_INITIALIZER(false, "pending_tags");
-grpc_tracer_flag grpc_trace_cq_refcount =
-    GRPC_TRACER_INITIALIZER(false, "cq_refcount");
-#endif
+grpc_core::TraceFlag grpc_trace_operation_failures(false, "op_failure");
+grpc_core::DebugOnlyTraceFlag grpc_trace_pending_tags(false, "pending_tags");
+grpc_core::DebugOnlyTraceFlag grpc_trace_cq_refcount(false, "cq_refcount");
 
 // Specifies a cq thread local cache.
 // The first event that occurs on a thread
@@ -340,18 +335,15 @@
 #define POLLSET_FROM_CQ(cq) \
   ((grpc_pollset*)(cq->vtable->data_size + (char*)DATA_FROM_CQ(cq)))
 
-grpc_tracer_flag grpc_cq_pluck_trace =
-    GRPC_TRACER_INITIALIZER(true, "queue_pluck");
-grpc_tracer_flag grpc_cq_event_timeout_trace =
-    GRPC_TRACER_INITIALIZER(true, "queue_timeout");
+grpc_core::TraceFlag grpc_cq_pluck_trace(true, "queue_pluck");
+grpc_core::TraceFlag grpc_cq_event_timeout_trace(true, "queue_timeout");
 
-#define GRPC_SURFACE_TRACE_RETURNED_EVENT(cq, event)    \
-  if (GRPC_TRACER_ON(grpc_api_trace) &&                 \
-      (GRPC_TRACER_ON(grpc_cq_pluck_trace) ||           \
-       (event)->type != GRPC_QUEUE_TIMEOUT)) {          \
-    char* _ev = grpc_event_string(event);               \
-    gpr_log(GPR_INFO, "RETURN_EVENT[%p]: %s", cq, _ev); \
-    gpr_free(_ev);                                      \
+#define GRPC_SURFACE_TRACE_RETURNED_EVENT(cq, event)                       \
+  if (grpc_api_trace.enabled() && (grpc_cq_pluck_trace.enabled() ||        \
+                                   (event)->type != GRPC_QUEUE_TIMEOUT)) { \
+    char* _ev = grpc_event_string(event);                                  \
+    gpr_log(GPR_INFO, "RETURN_EVENT[%p]: %s", cq, _ev);                    \
+    gpr_free(_ev);                                                         \
   }
 
 static void on_pollset_shutdown_done(grpc_exec_ctx* exec_ctx, void* cq,
@@ -533,7 +525,7 @@
 #ifndef NDEBUG
 void grpc_cq_internal_ref(grpc_completion_queue* cq, const char* reason,
                           const char* file, int line) {
-  if (GRPC_TRACER_ON(grpc_trace_cq_refcount)) {
+  if (grpc_trace_cq_refcount.enabled()) {
     gpr_atm val = gpr_atm_no_barrier_load(&cq->owning_refs.count);
     gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG,
             "CQ:%p   ref %" PRIdPTR " -> %" PRIdPTR " %s", cq, val, val + 1,
@@ -554,7 +546,7 @@
 #ifndef NDEBUG
 void grpc_cq_internal_unref(grpc_exec_ctx* exec_ctx, grpc_completion_queue* cq,
                             const char* reason, const char* file, int line) {
-  if (GRPC_TRACER_ON(grpc_trace_cq_refcount)) {
+  if (grpc_trace_cq_refcount.enabled()) {
     gpr_atm val = gpr_atm_no_barrier_load(&cq->owning_refs.count);
     gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG,
             "CQ:%p unref %" PRIdPTR " -> %" PRIdPTR " %s", cq, val, val - 1,
@@ -656,16 +648,14 @@
                                void* done_arg, grpc_cq_completion* storage) {
   GPR_TIMER_BEGIN("cq_end_op_for_next", 0);
 
-  if (GRPC_TRACER_ON(grpc_api_trace) ||
-      (GRPC_TRACER_ON(grpc_trace_operation_failures) &&
-       error != GRPC_ERROR_NONE)) {
+  if (grpc_api_trace.enabled() ||
+      (grpc_trace_operation_failures.enabled() && error != GRPC_ERROR_NONE)) {
     const char* errmsg = grpc_error_string(error);
     GRPC_API_TRACE(
         "cq_end_op_for_next(exec_ctx=%p, cq=%p, tag=%p, error=%s, "
         "done=%p, done_arg=%p, storage=%p)",
         7, (exec_ctx, cq, tag, errmsg, done, done_arg, storage));
-    if (GRPC_TRACER_ON(grpc_trace_operation_failures) &&
-        error != GRPC_ERROR_NONE) {
+    if (grpc_trace_operation_failures.enabled() && error != GRPC_ERROR_NONE) {
       gpr_log(GPR_ERROR, "Operation failed: tag=%p, error=%s", tag, errmsg);
     }
   }
@@ -745,16 +735,14 @@
 
   GPR_TIMER_BEGIN("cq_end_op_for_pluck", 0);
 
-  if (GRPC_TRACER_ON(grpc_api_trace) ||
-      (GRPC_TRACER_ON(grpc_trace_operation_failures) &&
-       error != GRPC_ERROR_NONE)) {
+  if (grpc_api_trace.enabled() ||
+      (grpc_trace_operation_failures.enabled() && error != GRPC_ERROR_NONE)) {
     const char* errmsg = grpc_error_string(error);
     GRPC_API_TRACE(
         "cq_end_op_for_pluck(exec_ctx=%p, cq=%p, tag=%p, error=%s, "
         "done=%p, done_arg=%p, storage=%p)",
         7, (exec_ctx, cq, tag, errmsg, done, done_arg, storage));
-    if (GRPC_TRACER_ON(grpc_trace_operation_failures) &&
-        error != GRPC_ERROR_NONE) {
+    if (grpc_trace_operation_failures.enabled() && error != GRPC_ERROR_NONE) {
       gpr_log(GPR_ERROR, "Operation failed: tag=%p, error=%s", tag, errmsg);
     }
   }
@@ -848,7 +836,7 @@
 
 #ifndef NDEBUG
 static void dump_pending_tags(grpc_completion_queue* cq) {
-  if (!GRPC_TRACER_ON(grpc_trace_pending_tags)) return;
+  if (!grpc_trace_pending_tags.enabled()) return;
 
   gpr_strvec v;
   gpr_strvec_init(&v);
@@ -1112,7 +1100,7 @@
 
   GPR_TIMER_BEGIN("grpc_completion_queue_pluck", 0);
 
-  if (GRPC_TRACER_ON(grpc_cq_pluck_trace)) {
+  if (grpc_cq_pluck_trace.enabled()) {
     GRPC_API_TRACE(
         "grpc_completion_queue_pluck("
         "cq=%p, tag=%p, "
diff --git a/src/core/lib/surface/completion_queue.h b/src/core/lib/surface/completion_queue.h
index 0ed9875..13d3e58 100644
--- a/src/core/lib/surface/completion_queue.h
+++ b/src/core/lib/surface/completion_queue.h
@@ -27,18 +27,11 @@
 
 /* These trace flags default to 1. The corresponding lines are only traced
    if grpc_api_trace is also truthy */
-extern grpc_tracer_flag grpc_cq_pluck_trace;
-extern grpc_tracer_flag grpc_cq_event_timeout_trace;
-extern grpc_tracer_flag grpc_trace_operation_failures;
-
-#ifndef NDEBUG
-extern grpc_tracer_flag grpc_trace_pending_tags;
-extern grpc_tracer_flag grpc_trace_cq_refcount;
-#endif
-
-#ifdef __cplusplus
-extern "C" {
-#endif
+extern grpc_core::TraceFlag grpc_cq_pluck_trace;
+extern grpc_core::TraceFlag grpc_cq_event_timeout_trace;
+extern grpc_core::TraceFlag grpc_trace_operation_failures;
+extern grpc_core::DebugOnlyTraceFlag grpc_trace_pending_tags;
+extern grpc_core::DebugOnlyTraceFlag grpc_trace_cq_refcount;
 
 typedef struct grpc_cq_completion {
   gpr_mpscq_node node;
@@ -98,8 +91,4 @@
 grpc_completion_queue* grpc_completion_queue_create_internal(
     grpc_cq_completion_type completion_type, grpc_cq_polling_type polling_type);
 
-#ifdef __cplusplus
-}
-#endif
-
 #endif /* GRPC_CORE_LIB_SURFACE_COMPLETION_QUEUE_H */
diff --git a/src/core/lib/surface/completion_queue_factory.h b/src/core/lib/surface/completion_queue_factory.h
index af8f3d6..89be8f8 100644
--- a/src/core/lib/surface/completion_queue_factory.h
+++ b/src/core/lib/surface/completion_queue_factory.h
@@ -22,10 +22,6 @@
 #include <grpc/grpc.h>
 #include "src/core/lib/surface/completion_queue.h"
 
-#ifdef __cplusplus
-extern "C" {
-#endif
-
 typedef struct grpc_completion_queue_factory_vtable {
   grpc_completion_queue* (*create)(const grpc_completion_queue_factory*,
                                    const grpc_completion_queue_attributes*);
@@ -37,8 +33,4 @@
   grpc_completion_queue_factory_vtable* vtable;
 };
 
-#ifdef __cplusplus
-}
-#endif
-
 #endif /* GRPC_CORE_LIB_SURFACE_COMPLETION_QUEUE_FACTORY_H */
diff --git a/src/core/lib/surface/event_string.h b/src/core/lib/surface/event_string.h
index 4bdb11f..cbf96da 100644
--- a/src/core/lib/surface/event_string.h
+++ b/src/core/lib/surface/event_string.h
@@ -21,15 +21,7 @@
 
 #include <grpc/grpc.h>
 
-#ifdef __cplusplus
-extern "C" {
-#endif
-
 /* Returns a string describing an event. Must be later freed with gpr_free() */
 char* grpc_event_string(grpc_event* ev);
 
-#ifdef __cplusplus
-}
-#endif
-
 #endif /* GRPC_CORE_LIB_SURFACE_EVENT_STRING_H */
diff --git a/src/core/lib/surface/init.cc b/src/core/lib/surface/init.cc
index 673e13c..8ee1383 100644
--- a/src/core/lib/surface/init.cc
+++ b/src/core/lib/surface/init.cc
@@ -21,6 +21,7 @@
 #include <limits.h>
 #include <memory.h>
 
+#include <grpc/fork.h>
 #include <grpc/grpc.h>
 #include <grpc/support/alloc.h>
 #include <grpc/support/log.h>
@@ -39,6 +40,8 @@
 #include "src/core/lib/iomgr/timer_manager.h"
 #include "src/core/lib/profiling/timers.h"
 #include "src/core/lib/slice/slice_internal.h"
+#include "src/core/lib/support/fork.h"
+#include "src/core/lib/support/thd_internal.h"
 #include "src/core/lib/surface/alarm_internal.h"
 #include "src/core/lib/surface/api_trace.h"
 #include "src/core/lib/surface/call.h"
@@ -62,10 +65,12 @@
 
 static void do_basic_init(void) {
   gpr_log_verbosity_init();
+  grpc_fork_support_init();
   gpr_mu_init(&g_init_mu);
   grpc_register_built_in_plugins();
   grpc_cq_global_init();
   g_initializations = 0;
+  grpc_fork_handlers_auto_register();
 }
 
 static bool append_filter(grpc_exec_ctx* exec_ctx,
@@ -122,34 +127,11 @@
   gpr_mu_lock(&g_init_mu);
   if (++g_initializations == 1) {
     gpr_time_init();
+    gpr_thd_init();
     grpc_stats_init();
     grpc_slice_intern_init();
     grpc_mdctx_global_init();
     grpc_channel_init_init();
-    grpc_register_tracer(&grpc_api_trace);
-    grpc_register_tracer(&grpc_trace_channel);
-    grpc_register_tracer(&grpc_connectivity_state_trace);
-    grpc_register_tracer(&grpc_trace_channel_stack_builder);
-    grpc_register_tracer(&grpc_http1_trace);
-    grpc_register_tracer(&grpc_cq_pluck_trace);  // default on
-    grpc_register_tracer(&grpc_call_combiner_trace);
-    grpc_register_tracer(&grpc_combiner_trace);
-    grpc_register_tracer(&grpc_server_channel_trace);
-    grpc_register_tracer(&grpc_bdp_estimator_trace);
-    grpc_register_tracer(&grpc_cq_event_timeout_trace);  // default on
-    grpc_register_tracer(&grpc_trace_operation_failures);
-    grpc_register_tracer(&grpc_resource_quota_trace);
-    grpc_register_tracer(&grpc_call_error_trace);
-#ifndef NDEBUG
-    grpc_register_tracer(&grpc_trace_pending_tags);
-    grpc_register_tracer(&grpc_trace_alarm_refcount);
-    grpc_register_tracer(&grpc_trace_cq_refcount);
-    grpc_register_tracer(&grpc_trace_closure);
-    grpc_register_tracer(&grpc_trace_error_refcount);
-    grpc_register_tracer(&grpc_trace_stream_refcount);
-    grpc_register_tracer(&grpc_trace_fd_refcount);
-    grpc_register_tracer(&grpc_trace_metadata);
-#endif
     grpc_security_pre_init();
     grpc_iomgr_init(&exec_ctx);
     gpr_timers_global_init();
diff --git a/src/core/lib/surface/init.h b/src/core/lib/surface/init.h
index d429026..9353208 100644
--- a/src/core/lib/surface/init.h
+++ b/src/core/lib/surface/init.h
@@ -19,17 +19,9 @@
 #ifndef GRPC_CORE_LIB_SURFACE_INIT_H
 #define GRPC_CORE_LIB_SURFACE_INIT_H
 
-#ifdef __cplusplus
-extern "C" {
-#endif
-
 void grpc_register_security_filters(void);
 void grpc_security_pre_init(void);
 void grpc_security_init(void);
 int grpc_is_initialized(void);
 
-#ifdef __cplusplus
-}
-#endif
-
 #endif /* GRPC_CORE_LIB_SURFACE_INIT_H */
diff --git a/src/core/lib/surface/init_secure.cc b/src/core/lib/surface/init_secure.cc
index deb9a8e..3eee570 100644
--- a/src/core/lib/surface/init_secure.cc
+++ b/src/core/lib/surface/init_secure.cc
@@ -24,6 +24,7 @@
 #include <string.h>
 
 #include "src/core/lib/debug/trace.h"
+#include "src/core/lib/security/context/security_context.h"
 #include "src/core/lib/security/credentials/credentials.h"
 #include "src/core/lib/security/credentials/plugin/plugin_credentials.h"
 #include "src/core/lib/security/transport/auth_filters.h"
@@ -33,18 +34,7 @@
 #include "src/core/lib/surface/channel_init.h"
 #include "src/core/tsi/transport_security_interface.h"
 
-#ifndef NDEBUG
-#include "src/core/lib/security/context/security_context.h"
-#endif
-
-void grpc_security_pre_init(void) {
-  grpc_register_tracer(&grpc_trace_secure_endpoint);
-  grpc_register_tracer(&tsi_tracing_enabled);
-#ifndef NDEBUG
-  grpc_register_tracer(&grpc_trace_auth_context_refcount);
-  grpc_register_tracer(&grpc_trace_security_connector_refcount);
-#endif
-}
+void grpc_security_pre_init(void) {}
 
 static bool maybe_prepend_client_auth_filter(
     grpc_exec_ctx* exec_ctx, grpc_channel_stack_builder* builder, void* arg) {
@@ -85,7 +75,4 @@
                                    maybe_prepend_server_auth_filter, nullptr);
 }
 
-void grpc_security_init() {
-  grpc_security_register_handshaker_factories();
-  grpc_register_tracer(&grpc_plugin_credentials_trace);
-}
+void grpc_security_init() { grpc_security_register_handshaker_factories(); }
diff --git a/src/core/lib/surface/lame_client.cc b/src/core/lib/surface/lame_client.cc
index 7114a9f..c32c9af 100644
--- a/src/core/lib/surface/lame_client.cc
+++ b/src/core/lib/surface/lame_client.cc
@@ -25,7 +25,6 @@
 
 #include "src/core/lib/support/atomic.h"
 
-extern "C" {
 #include "src/core/lib/channel/channel_stack.h"
 #include "src/core/lib/support/string.h"
 #include "src/core/lib/surface/api_trace.h"
@@ -33,7 +32,6 @@
 #include "src/core/lib/surface/channel.h"
 #include "src/core/lib/surface/lame_client.h"
 #include "src/core/lib/transport/static_metadata.h"
-}
 
 namespace grpc_core {
 
@@ -146,7 +144,7 @@
 
 }  // namespace grpc_core
 
-extern "C" const grpc_channel_filter grpc_lame_filter = {
+const grpc_channel_filter grpc_lame_filter = {
     grpc_core::lame_start_transport_stream_op_batch,
     grpc_core::lame_start_transport_op,
     sizeof(grpc_core::CallData),
diff --git a/src/core/lib/surface/lame_client.h b/src/core/lib/surface/lame_client.h
index 2f6f9cd..3ce353f 100644
--- a/src/core/lib/surface/lame_client.h
+++ b/src/core/lib/surface/lame_client.h
@@ -21,14 +21,6 @@
 
 #include "src/core/lib/channel/channel_stack.h"
 
-#ifdef __cplusplus
-extern "C" {
-#endif
-
 extern const grpc_channel_filter grpc_lame_filter;
 
-#ifdef __cplusplus
-}
-#endif
-
 #endif /* GRPC_CORE_LIB_SURFACE_LAME_CLIENT_H */
diff --git a/src/core/lib/surface/server.cc b/src/core/lib/surface/server.cc
index b816439..0f8a057 100644
--- a/src/core/lib/surface/server.cc
+++ b/src/core/lib/surface/server.cc
@@ -60,8 +60,7 @@
 
 typedef enum { BATCH_CALL, REGISTERED_CALL } requested_call_type;
 
-grpc_tracer_flag grpc_server_channel_trace =
-    GRPC_TRACER_INITIALIZER(false, "server_channel");
+grpc_core::TraceFlag grpc_server_channel_trace(false, "server_channel");
 
 typedef struct requested_call {
   gpr_mpscq_node request_link; /* must be first */
@@ -350,14 +349,8 @@
                                           grpc_error* error) {
   requested_call* rc;
   for (size_t i = 0; i < server->cq_count; i++) {
-    /* Here we know:
-       1. no requests are being added (since the server is shut down)
-       2. no other threads are pulling (since the shut down process is single
-          threaded)
-       So, we can ignore the queue lock and just pop, with the guarantee that a
-       NULL returned here truly means that the queue is empty */
-    while ((rc = (requested_call*)gpr_mpscq_pop(
-                &rm->requests_per_cq[i].queue)) != nullptr) {
+    while ((rc = (requested_call*)gpr_locked_mpscq_pop(
+                &rm->requests_per_cq[i])) != nullptr) {
       fail_call(exec_ctx, server, i, rc, GRPC_ERROR_REF(error));
     }
   }
@@ -434,7 +427,7 @@
   GRPC_CLOSURE_INIT(&chand->finish_destroy_channel_closure,
                     finish_destroy_channel, chand, grpc_schedule_on_exec_ctx);
 
-  if (GRPC_TRACER_ON(grpc_server_channel_trace) && error != GRPC_ERROR_NONE) {
+  if (grpc_server_channel_trace.enabled() && error != GRPC_ERROR_NONE) {
     const char* msg = grpc_error_string(error);
     gpr_log(GPR_INFO, "Disconnected client: %s", msg);
   }
@@ -839,7 +832,7 @@
   grpc_server* server = chand->server;
   if (chand->connectivity_state != GRPC_CHANNEL_SHUTDOWN) {
     grpc_transport_op* op = grpc_make_transport_op(nullptr);
-    op->on_connectivity_state_change = &chand->channel_connectivity_changed,
+    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(
diff --git a/src/core/lib/surface/server.h b/src/core/lib/surface/server.h
index e3c43f9..d7ec025 100644
--- a/src/core/lib/surface/server.h
+++ b/src/core/lib/surface/server.h
@@ -24,14 +24,10 @@
 #include "src/core/lib/debug/trace.h"
 #include "src/core/lib/transport/transport.h"
 
-#ifdef __cplusplus
-extern "C" {
-#endif
-
 extern const grpc_channel_filter grpc_server_top_filter;
 
 /** Lightweight tracing of server channel state */
-extern grpc_tracer_flag grpc_server_channel_trace;
+extern grpc_core::TraceFlag grpc_server_channel_trace;
 
 /* Add a listener to the server: when the server starts, it will call start,
    and when it shuts down, it will call destroy */
@@ -58,8 +54,4 @@
 void grpc_server_get_pollsets(grpc_server* server, grpc_pollset*** pollsets,
                               size_t* pollset_count);
 
-#ifdef __cplusplus
-}
-#endif
-
 #endif /* GRPC_CORE_LIB_SURFACE_SERVER_H */
diff --git a/src/core/lib/surface/validate_metadata.h b/src/core/lib/surface/validate_metadata.h
index 9ca2069..ff074b0 100644
--- a/src/core/lib/surface/validate_metadata.h
+++ b/src/core/lib/surface/validate_metadata.h
@@ -22,15 +22,7 @@
 #include <grpc/slice.h>
 #include "src/core/lib/iomgr/error.h"
 
-#ifdef __cplusplus
-extern "C" {
-#endif
-
 grpc_error* grpc_validate_header_key_is_legal(grpc_slice slice);
 grpc_error* grpc_validate_header_nonbin_value_is_legal(grpc_slice slice);
 
-#ifdef __cplusplus
-}
-#endif
-
 #endif /* GRPC_CORE_LIB_SURFACE_VALIDATE_METADATA_H */
diff --git a/src/core/lib/surface/version.cc b/src/core/lib/surface/version.cc
index f4feadc..7d36c6c 100644
--- a/src/core/lib/surface/version.cc
+++ b/src/core/lib/surface/version.cc
@@ -23,4 +23,4 @@
 
 const char* grpc_version_string(void) { return "5.0.0-dev"; }
 
-const char* grpc_g_stands_for(void) { return "generous"; }
+const char* grpc_g_stands_for(void) { return "glossy"; }
diff --git a/src/core/lib/transport/bdp_estimator.cc b/src/core/lib/transport/bdp_estimator.cc
index e09ae8e..bb0e583 100644
--- a/src/core/lib/transport/bdp_estimator.cc
+++ b/src/core/lib/transport/bdp_estimator.cc
@@ -23,8 +23,7 @@
 
 #include <grpc/support/useful.h>
 
-grpc_tracer_flag grpc_bdp_estimator_trace =
-    GRPC_TRACER_INITIALIZER(false, "bdp_estimator");
+grpc_core::TraceFlag grpc_bdp_estimator_trace(false, "bdp_estimator");
 
 namespace grpc_core {
 
@@ -44,7 +43,7 @@
   double dt = (double)dt_ts.tv_sec + 1e-9 * (double)dt_ts.tv_nsec;
   double bw = dt > 0 ? ((double)accumulator_ / dt) : 0;
   int start_inter_ping_delay = inter_ping_delay_;
-  if (GRPC_TRACER_ON(grpc_bdp_estimator_trace)) {
+  if (grpc_bdp_estimator_trace.enabled()) {
     gpr_log(GPR_DEBUG,
             "bdp[%s]:complete acc=%" PRId64 " est=%" PRId64
             " dt=%lf bw=%lfMbs bw_est=%lfMbs",
@@ -55,7 +54,7 @@
   if (accumulator_ > 2 * estimate_ / 3 && bw > bw_est_) {
     estimate_ = GPR_MAX(accumulator_, estimate_ * 2);
     bw_est_ = bw;
-    if (GRPC_TRACER_ON(grpc_bdp_estimator_trace)) {
+    if (grpc_bdp_estimator_trace.enabled()) {
       gpr_log(GPR_DEBUG, "bdp[%s]: estimate increased to %" PRId64, name_,
               estimate_);
     }
@@ -72,7 +71,7 @@
   }
   if (start_inter_ping_delay != inter_ping_delay_) {
     stable_estimate_count_ = 0;
-    if (GRPC_TRACER_ON(grpc_bdp_estimator_trace)) {
+    if (grpc_bdp_estimator_trace.enabled()) {
       gpr_log(GPR_DEBUG, "bdp[%s]:update_inter_time to %dms", name_,
               inter_ping_delay_);
     }
diff --git a/src/core/lib/transport/bdp_estimator.h b/src/core/lib/transport/bdp_estimator.h
index f7b94a8..df3a86c 100644
--- a/src/core/lib/transport/bdp_estimator.h
+++ b/src/core/lib/transport/bdp_estimator.h
@@ -31,7 +31,7 @@
 #include "src/core/lib/debug/trace.h"
 #include "src/core/lib/iomgr/exec_ctx.h"
 
-extern grpc_tracer_flag grpc_bdp_estimator_trace;
+extern grpc_core::TraceFlag grpc_bdp_estimator_trace;
 
 namespace grpc_core {
 
@@ -49,7 +49,7 @@
   // grpc_bdp_estimator_add_incoming_bytes once a ping has been scheduled by a
   // transport (but not necessarily started)
   void SchedulePing() {
-    if (GRPC_TRACER_ON(grpc_bdp_estimator_trace)) {
+    if (grpc_bdp_estimator_trace.enabled()) {
       gpr_log(GPR_DEBUG, "bdp[%s]:sched acc=%" PRId64 " est=%" PRId64, name_,
               accumulator_, estimate_);
     }
@@ -62,7 +62,7 @@
   // once
   // the ping is on the wire
   void StartPing() {
-    if (GRPC_TRACER_ON(grpc_bdp_estimator_trace)) {
+    if (grpc_bdp_estimator_trace.enabled()) {
       gpr_log(GPR_DEBUG, "bdp[%s]:start acc=%" PRId64 " est=%" PRId64, name_,
               accumulator_, estimate_);
     }
diff --git a/src/core/lib/transport/byte_stream.h b/src/core/lib/transport/byte_stream.h
index 54ad4b9..6bca154 100644
--- a/src/core/lib/transport/byte_stream.h
+++ b/src/core/lib/transport/byte_stream.h
@@ -28,10 +28,6 @@
 /** Mask of all valid internal flags. */
 #define GRPC_WRITE_INTERNAL_USED_MASK (GRPC_WRITE_INTERNAL_COMPRESS)
 
-#ifdef __cplusplus
-extern "C" {
-#endif
-
 typedef struct grpc_byte_stream grpc_byte_stream;
 
 typedef struct {
@@ -139,8 +135,4 @@
 // Resets the byte stream to the start of the underlying stream.
 void grpc_caching_byte_stream_reset(grpc_caching_byte_stream* stream);
 
-#ifdef __cplusplus
-}
-#endif
-
 #endif /* GRPC_CORE_LIB_TRANSPORT_BYTE_STREAM_H */
diff --git a/src/core/lib/transport/connectivity_state.cc b/src/core/lib/transport/connectivity_state.cc
index 55f4236..e7e5dbd 100644
--- a/src/core/lib/transport/connectivity_state.cc
+++ b/src/core/lib/transport/connectivity_state.cc
@@ -24,8 +24,7 @@
 #include <grpc/support/log.h>
 #include <grpc/support/string_util.h>
 
-grpc_tracer_flag grpc_connectivity_state_trace =
-    GRPC_TRACER_INITIALIZER(false, "connectivity_state");
+grpc_core::TraceFlag grpc_connectivity_state_trace(false, "connectivity_state");
 
 const char* grpc_connectivity_state_name(grpc_connectivity_state state) {
   switch (state) {
@@ -78,7 +77,7 @@
   grpc_connectivity_state cur =
       (grpc_connectivity_state)gpr_atm_no_barrier_load(
           &tracker->current_state_atm);
-  if (GRPC_TRACER_ON(grpc_connectivity_state_trace)) {
+  if (grpc_connectivity_state_trace.enabled()) {
     gpr_log(GPR_DEBUG, "CONWATCH: %p %s: get %s", tracker, tracker->name,
             grpc_connectivity_state_name(cur));
   }
@@ -90,7 +89,7 @@
   grpc_connectivity_state cur =
       (grpc_connectivity_state)gpr_atm_no_barrier_load(
           &tracker->current_state_atm);
-  if (GRPC_TRACER_ON(grpc_connectivity_state_trace)) {
+  if (grpc_connectivity_state_trace.enabled()) {
     gpr_log(GPR_DEBUG, "CONWATCH: %p %s: get %s", tracker, tracker->name,
             grpc_connectivity_state_name(cur));
   }
@@ -111,7 +110,7 @@
   grpc_connectivity_state cur =
       (grpc_connectivity_state)gpr_atm_no_barrier_load(
           &tracker->current_state_atm);
-  if (GRPC_TRACER_ON(grpc_connectivity_state_trace)) {
+  if (grpc_connectivity_state_trace.enabled()) {
     if (current == nullptr) {
       gpr_log(GPR_DEBUG, "CONWATCH: %p %s: unsubscribe notify=%p", tracker,
               tracker->name, notify);
@@ -165,7 +164,7 @@
       (grpc_connectivity_state)gpr_atm_no_barrier_load(
           &tracker->current_state_atm);
   grpc_connectivity_state_watcher* w;
-  if (GRPC_TRACER_ON(grpc_connectivity_state_trace)) {
+  if (grpc_connectivity_state_trace.enabled()) {
     const char* error_string = grpc_error_string(error);
     gpr_log(GPR_DEBUG, "SET: %p %s: %s --> %s [%s] error=%p %s", tracker,
             tracker->name, grpc_connectivity_state_name(cur),
@@ -192,7 +191,7 @@
   while ((w = tracker->watchers) != nullptr) {
     *w->current = state;
     tracker->watchers = w->next;
-    if (GRPC_TRACER_ON(grpc_connectivity_state_trace)) {
+    if (grpc_connectivity_state_trace.enabled()) {
       gpr_log(GPR_DEBUG, "NOTIFY: %p %s: %p", tracker, tracker->name,
               w->notify);
     }
diff --git a/src/core/lib/transport/connectivity_state.h b/src/core/lib/transport/connectivity_state.h
index 792e27c..653637e 100644
--- a/src/core/lib/transport/connectivity_state.h
+++ b/src/core/lib/transport/connectivity_state.h
@@ -23,10 +23,6 @@
 #include "src/core/lib/debug/trace.h"
 #include "src/core/lib/iomgr/exec_ctx.h"
 
-#ifdef __cplusplus
-extern "C" {
-#endif
-
 typedef struct grpc_connectivity_state_watcher {
   /** we keep watchers in a linked list */
   struct grpc_connectivity_state_watcher* next;
@@ -47,7 +43,7 @@
   char* name;
 } grpc_connectivity_state_tracker;
 
-extern grpc_tracer_flag grpc_connectivity_state_trace;
+extern grpc_core::TraceFlag grpc_connectivity_state_trace;
 
 /** enum --> string conversion */
 const char* grpc_connectivity_state_name(grpc_connectivity_state state);
@@ -88,8 +84,4 @@
     grpc_exec_ctx* exec_ctx, grpc_connectivity_state_tracker* tracker,
     grpc_connectivity_state* current, grpc_closure* notify);
 
-#ifdef __cplusplus
-}
-#endif
-
 #endif /* GRPC_CORE_LIB_TRANSPORT_CONNECTIVITY_STATE_H */
diff --git a/src/core/lib/transport/error_utils.cc b/src/core/lib/transport/error_utils.cc
index 19510b4..69c8ae6 100644
--- a/src/core/lib/transport/error_utils.cc
+++ b/src/core/lib/transport/error_utils.cc
@@ -18,6 +18,7 @@
 
 #include "src/core/lib/transport/error_utils.h"
 
+#include <grpc/support/string_util.h>
 #include "src/core/lib/iomgr/error_internal.h"
 #include "src/core/lib/transport/status_conversion.h"
 
@@ -41,8 +42,8 @@
 
 void grpc_error_get_status(grpc_exec_ctx* exec_ctx, grpc_error* error,
                            grpc_millis deadline, grpc_status_code* code,
-                           grpc_slice* slice,
-                           grpc_http2_error_code* http_error) {
+                           grpc_slice* slice, grpc_http2_error_code* http_error,
+                           const char** error_string) {
   // Start with the parent error and recurse through the tree of children
   // until we find the first one that has a status code.
   grpc_error* found_error =
@@ -69,6 +70,10 @@
   }
   if (code != nullptr) *code = status;
 
+  if (error_string != NULL && status != GRPC_STATUS_OK) {
+    *error_string = gpr_strdup(grpc_error_string(error));
+  }
+
   if (http_error != nullptr) {
     if (grpc_error_get_int(found_error, GRPC_ERROR_INT_HTTP2_ERROR, &integer)) {
       *http_error = (grpc_http2_error_code)integer;
diff --git a/src/core/lib/transport/error_utils.h b/src/core/lib/transport/error_utils.h
index 690e420..8b006ae 100644
--- a/src/core/lib/transport/error_utils.h
+++ b/src/core/lib/transport/error_utils.h
@@ -23,20 +23,18 @@
 #include "src/core/lib/iomgr/exec_ctx.h"
 #include "src/core/lib/transport/http2_errors.h"
 
-#ifdef __cplusplus
-extern "C" {
-#endif
-
 /// A utility function to get the status code and message to be returned
 /// to the application.  If not set in the top-level message, looks
 /// through child errors until it finds the first one with these attributes.
-/// All attributes are pulled from the same child error. If any of the
-/// attributes (code, msg, http_status) are unneeded, they can be passed as
+/// All attributes are pulled from the same child error. error_string will
+/// be populated with the entire error string. If any of the attributes (code,
+/// msg, http_status, error_string) are unneeded, they can be passed as
 /// NULL.
 void grpc_error_get_status(grpc_exec_ctx* exec_ctx, grpc_error* error,
                            grpc_millis deadline, grpc_status_code* code,
                            grpc_slice* slice,
-                           grpc_http2_error_code* http_status);
+                           grpc_http2_error_code* http_status,
+                           const char** error_string);
 
 /// A utility function to check whether there is a clear status code that
 /// doesn't need to be guessed in \a error. This means that \a error or some
@@ -44,8 +42,4 @@
 /// GRPC_ERROR_CANCELLED
 bool grpc_error_has_clear_grpc_status(grpc_error* error);
 
-#ifdef __cplusplus
-}
-#endif
-
 #endif /* GRPC_CORE_LIB_TRANSPORT_ERROR_UTILS_H */
diff --git a/src/core/lib/transport/metadata.cc b/src/core/lib/transport/metadata.cc
index a16f050..0f30c75 100644
--- a/src/core/lib/transport/metadata.cc
+++ b/src/core/lib/transport/metadata.cc
@@ -48,9 +48,9 @@
  * used to determine which kind of element a pointer refers to.
  */
 
+grpc_core::DebugOnlyTraceFlag grpc_trace_metadata(false, "metadata");
+
 #ifndef NDEBUG
-grpc_tracer_flag grpc_trace_metadata =
-    GRPC_TRACER_INITIALIZER(false, "metadata");
 #define DEBUG_ARGS , const char *file, int line
 #define FWD_DEBUG_ARGS , file, line
 #define REF_MD_LOCKED(shard, s) ref_md_locked((shard), (s), __FILE__, __LINE__)
@@ -149,7 +149,7 @@
 static void ref_md_locked(mdtab_shard* shard,
                           interned_metadata* md DEBUG_ARGS) {
 #ifndef NDEBUG
-  if (GRPC_TRACER_ON(grpc_trace_metadata)) {
+  if (grpc_trace_metadata.enabled()) {
     char* key_str = grpc_slice_to_c_string(md->key);
     char* value_str = grpc_slice_to_c_string(md->value);
     gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG,
@@ -252,7 +252,7 @@
     allocated->value = grpc_slice_ref_internal(value);
     gpr_atm_rel_store(&allocated->refcnt, 1);
 #ifndef NDEBUG
-    if (GRPC_TRACER_ON(grpc_trace_metadata)) {
+    if (grpc_trace_metadata.enabled()) {
       char* key_str = grpc_slice_to_c_string(allocated->key);
       char* value_str = grpc_slice_to_c_string(allocated->value);
       gpr_log(GPR_DEBUG, "ELM ALLOC:%p:%" PRIdPTR ": '%s' = '%s'",
@@ -306,7 +306,7 @@
   shard->elems[idx] = md;
   gpr_mu_init(&md->mu_user_data);
 #ifndef NDEBUG
-  if (GRPC_TRACER_ON(grpc_trace_metadata)) {
+  if (grpc_trace_metadata.enabled()) {
     char* key_str = grpc_slice_to_c_string(md->key);
     char* value_str = grpc_slice_to_c_string(md->value);
     gpr_log(GPR_DEBUG, "ELM   NEW:%p:%" PRIdPTR ": '%s' = '%s'", (void*)md,
@@ -373,7 +373,7 @@
     case GRPC_MDELEM_STORAGE_INTERNED: {
       interned_metadata* md = (interned_metadata*)GRPC_MDELEM_DATA(gmd);
 #ifndef NDEBUG
-      if (GRPC_TRACER_ON(grpc_trace_metadata)) {
+      if (grpc_trace_metadata.enabled()) {
         char* key_str = grpc_slice_to_c_string(md->key);
         char* value_str = grpc_slice_to_c_string(md->value);
         gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG,
@@ -395,7 +395,7 @@
     case GRPC_MDELEM_STORAGE_ALLOCATED: {
       allocated_metadata* md = (allocated_metadata*)GRPC_MDELEM_DATA(gmd);
 #ifndef NDEBUG
-      if (GRPC_TRACER_ON(grpc_trace_metadata)) {
+      if (grpc_trace_metadata.enabled()) {
         char* key_str = grpc_slice_to_c_string(md->key);
         char* value_str = grpc_slice_to_c_string(md->value);
         gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG,
@@ -425,7 +425,7 @@
     case GRPC_MDELEM_STORAGE_INTERNED: {
       interned_metadata* md = (interned_metadata*)GRPC_MDELEM_DATA(gmd);
 #ifndef NDEBUG
-      if (GRPC_TRACER_ON(grpc_trace_metadata)) {
+      if (grpc_trace_metadata.enabled()) {
         char* key_str = grpc_slice_to_c_string(md->key);
         char* value_str = grpc_slice_to_c_string(md->value);
         gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG,
@@ -451,7 +451,7 @@
     case GRPC_MDELEM_STORAGE_ALLOCATED: {
       allocated_metadata* md = (allocated_metadata*)GRPC_MDELEM_DATA(gmd);
 #ifndef NDEBUG
-      if (GRPC_TRACER_ON(grpc_trace_metadata)) {
+      if (grpc_trace_metadata.enabled()) {
         char* key_str = grpc_slice_to_c_string(md->key);
         char* value_str = grpc_slice_to_c_string(md->value);
         gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG,
diff --git a/src/core/lib/transport/metadata.h b/src/core/lib/transport/metadata.h
index 7e7e7b4..8d4868d 100644
--- a/src/core/lib/transport/metadata.h
+++ b/src/core/lib/transport/metadata.h
@@ -25,13 +25,7 @@
 
 #include "src/core/lib/iomgr/exec_ctx.h"
 
-#ifndef NDEBUG
-extern grpc_tracer_flag grpc_trace_metadata;
-#endif
-
-#ifdef __cplusplus
-extern "C" {
-#endif
+extern grpc_core::DebugOnlyTraceFlag grpc_trace_metadata;
 
 /* This file provides a mechanism for tracking metadata through the grpc stack.
    It's not intended for consumption outside of the library.
@@ -170,8 +164,4 @@
 void grpc_mdctx_global_init(void);
 void grpc_mdctx_global_shutdown(grpc_exec_ctx* exec_ctx);
 
-#ifdef __cplusplus
-}
-#endif
-
 #endif /* GRPC_CORE_LIB_TRANSPORT_METADATA_H */
diff --git a/src/core/lib/transport/metadata_batch.h b/src/core/lib/transport/metadata_batch.h
index 7d17393..adfb2d8 100644
--- a/src/core/lib/transport/metadata_batch.h
+++ b/src/core/lib/transport/metadata_batch.h
@@ -28,10 +28,6 @@
 #include "src/core/lib/transport/metadata.h"
 #include "src/core/lib/transport/static_metadata.h"
 
-#ifdef __cplusplus
-extern "C" {
-#endif
-
 typedef struct grpc_linked_mdelem {
   grpc_mdelem md;
   struct grpc_linked_mdelem* next;
@@ -146,8 +142,4 @@
   } while (0)
 #endif
 
-#ifdef __cplusplus
-}
-#endif
-
 #endif /* GRPC_CORE_LIB_TRANSPORT_METADATA_BATCH_H */
diff --git a/src/core/lib/transport/service_config.h b/src/core/lib/transport/service_config.h
index 405d0f5..75a290b 100644
--- a/src/core/lib/transport/service_config.h
+++ b/src/core/lib/transport/service_config.h
@@ -22,10 +22,6 @@
 #include "src/core/lib/json/json.h"
 #include "src/core/lib/slice/slice_hash_table.h"
 
-#ifdef __cplusplus
-extern "C" {
-#endif
-
 typedef struct grpc_service_config grpc_service_config;
 
 grpc_service_config* grpc_service_config_create(const char* json_string);
@@ -64,8 +60,4 @@
                                    const grpc_slice_hash_table* table,
                                    grpc_slice path);
 
-#ifdef __cplusplus
-}
-#endif
-
 #endif /* GRPC_CORE_LIB_TRANSPORT_SERVICE_CONFIG_H */
diff --git a/src/core/lib/transport/static_metadata.h b/src/core/lib/transport/static_metadata.h
index 8e73d5f..ce3a11b 100644
--- a/src/core/lib/transport/static_metadata.h
+++ b/src/core/lib/transport/static_metadata.h
@@ -27,10 +27,6 @@
 #ifndef GRPC_CORE_LIB_TRANSPORT_STATIC_METADATA_H
 #define GRPC_CORE_LIB_TRANSPORT_STATIC_METADATA_H
 
-#ifdef __cplusplus
-extern "C" {
-#endif
-
 #include "src/core/lib/transport/metadata.h"
 
 #define GRPC_STATIC_MDSTR_COUNT 100
@@ -588,7 +584,5 @@
   (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table                                  \
                         [grpc_static_accept_stream_encoding_metadata[(algs)]], \
                     GRPC_MDELEM_STORAGE_STATIC))
-#ifdef __cplusplus
-}
-#endif
+
 #endif /* GRPC_CORE_LIB_TRANSPORT_STATIC_METADATA_H */
diff --git a/src/core/lib/transport/status_conversion.h b/src/core/lib/transport/status_conversion.h
index b6fcebd..3637b82 100644
--- a/src/core/lib/transport/status_conversion.h
+++ b/src/core/lib/transport/status_conversion.h
@@ -23,10 +23,6 @@
 #include "src/core/lib/iomgr/exec_ctx.h"
 #include "src/core/lib/transport/http2_errors.h"
 
-#ifdef __cplusplus
-extern "C" {
-#endif
-
 /* Conversion of grpc status codes to http2 error codes (for RST_STREAM) */
 grpc_http2_error_code grpc_status_to_http2_error(grpc_status_code status);
 grpc_status_code grpc_http2_error_to_grpc_status(grpc_exec_ctx* exec_ctx,
@@ -37,8 +33,4 @@
 grpc_status_code grpc_http2_status_to_grpc_status(int status);
 int grpc_status_to_http2_status(grpc_status_code status);
 
-#ifdef __cplusplus
-}
-#endif
-
 #endif /* GRPC_CORE_LIB_TRANSPORT_STATUS_CONVERSION_H */
diff --git a/src/core/lib/transport/timeout_encoding.h b/src/core/lib/transport/timeout_encoding.h
index 9c3c459..8611f49 100644
--- a/src/core/lib/transport/timeout_encoding.h
+++ b/src/core/lib/transport/timeout_encoding.h
@@ -27,17 +27,9 @@
 
 #define GRPC_HTTP2_TIMEOUT_ENCODE_MIN_BUFSIZE (GPR_LTOA_MIN_BUFSIZE + 1)
 
-#ifdef __cplusplus
-extern "C" {
-#endif
-
 /* Encode/decode timeouts to the GRPC over HTTP/2 format;
    encoding may round up arbitrarily */
 void grpc_http2_encode_timeout(grpc_millis timeout, char* buffer);
 int grpc_http2_decode_timeout(grpc_slice text, grpc_millis* timeout);
 
-#ifdef __cplusplus
-}
-#endif
-
 #endif /* GRPC_CORE_LIB_TRANSPORT_TIMEOUT_ENCODING_H */
diff --git a/src/core/lib/transport/transport.cc b/src/core/lib/transport/transport.cc
index b39e6eb..5bda154 100644
--- a/src/core/lib/transport/transport.cc
+++ b/src/core/lib/transport/transport.cc
@@ -31,14 +31,12 @@
 #include "src/core/lib/support/string.h"
 #include "src/core/lib/transport/transport_impl.h"
 
-#ifndef NDEBUG
-grpc_tracer_flag grpc_trace_stream_refcount =
-    GRPC_TRACER_INITIALIZER(false, "stream_refcount");
-#endif
+grpc_core::DebugOnlyTraceFlag grpc_trace_stream_refcount(false,
+                                                         "stream_refcount");
 
 #ifndef NDEBUG
 void grpc_stream_ref(grpc_stream_refcount* refcount, const char* reason) {
-  if (GRPC_TRACER_ON(grpc_trace_stream_refcount)) {
+  if (grpc_trace_stream_refcount.enabled()) {
     gpr_atm val = gpr_atm_no_barrier_load(&refcount->refs.count);
     gpr_log(GPR_DEBUG, "%s %p:%p   REF %" PRIdPTR "->%" PRIdPTR " %s",
             refcount->object_type, refcount, refcount->destroy.cb_arg, val,
@@ -53,7 +51,7 @@
 #ifndef NDEBUG
 void grpc_stream_unref(grpc_exec_ctx* exec_ctx, grpc_stream_refcount* refcount,
                        const char* reason) {
-  if (GRPC_TRACER_ON(grpc_trace_stream_refcount)) {
+  if (grpc_trace_stream_refcount.enabled()) {
     gpr_atm val = gpr_atm_no_barrier_load(&refcount->refs.count);
     gpr_log(GPR_DEBUG, "%s %p:%p UNREF %" PRIdPTR "->%" PRIdPTR " %s",
             refcount->object_type, refcount, refcount->destroy.cb_arg, val,
@@ -103,7 +101,7 @@
                                                void* buffer, size_t length) {
   slice_stream_ref(&refcount->slice_refcount);
   grpc_slice res;
-  res.refcount = &refcount->slice_refcount,
+  res.refcount = &refcount->slice_refcount;
   res.data.refcounted.bytes = (uint8_t*)buffer;
   res.data.refcounted.length = length;
   return res;
diff --git a/src/core/lib/transport/transport.h b/src/core/lib/transport/transport.h
index 973018e..af48f13 100644
--- a/src/core/lib/transport/transport.h
+++ b/src/core/lib/transport/transport.h
@@ -31,10 +31,6 @@
 #include "src/core/lib/transport/byte_stream.h"
 #include "src/core/lib/transport/metadata_batch.h"
 
-#ifdef __cplusplus
-extern "C" {
-#endif
-
 /* forward declarations */
 typedef struct grpc_transport grpc_transport;
 
@@ -43,9 +39,7 @@
    for a stream. */
 typedef struct grpc_stream grpc_stream;
 
-#ifndef NDEBUG
-extern grpc_tracer_flag grpc_trace_stream_refcount;
-#endif
+extern grpc_core::DebugOnlyTraceFlag grpc_trace_stream_refcount;
 
 typedef struct grpc_stream_refcount {
   gpr_refcount refs;
@@ -352,8 +346,4 @@
 grpc_transport_stream_op_batch* grpc_make_transport_stream_op(
     grpc_closure* on_consumed);
 
-#ifdef __cplusplus
-}
-#endif
-
 #endif /* GRPC_CORE_LIB_TRANSPORT_TRANSPORT_H */
diff --git a/src/core/lib/transport/transport_impl.h b/src/core/lib/transport/transport_impl.h
index 22ad599..46be614 100644
--- a/src/core/lib/transport/transport_impl.h
+++ b/src/core/lib/transport/transport_impl.h
@@ -21,10 +21,6 @@
 
 #include "src/core/lib/transport/transport.h"
 
-#ifdef __cplusplus
-extern "C" {
-#endif
-
 typedef struct grpc_transport_vtable {
   /* Memory required for a single stream element - this is allocated by upper
      layers and initialized by the transport */
@@ -73,8 +69,4 @@
   const grpc_transport_vtable* vtable;
 };
 
-#ifdef __cplusplus
-}
-#endif
-
 #endif /* GRPC_CORE_LIB_TRANSPORT_TRANSPORT_IMPL_H */
diff --git a/src/core/plugin_registry/grpc_cronet_plugin_registry.cc b/src/core/plugin_registry/grpc_cronet_plugin_registry.cc
index e0422f6..101e29c 100644
--- a/src/core/plugin_registry/grpc_cronet_plugin_registry.cc
+++ b/src/core/plugin_registry/grpc_cronet_plugin_registry.cc
@@ -18,18 +18,18 @@
 
 #include <grpc/grpc.h>
 
-extern "C" void grpc_http_filters_init(void);
-extern "C" void grpc_http_filters_shutdown(void);
-extern "C" void grpc_chttp2_plugin_init(void);
-extern "C" void grpc_chttp2_plugin_shutdown(void);
-extern "C" void grpc_deadline_filter_init(void);
-extern "C" void grpc_deadline_filter_shutdown(void);
-extern "C" void grpc_client_channel_init(void);
-extern "C" void grpc_client_channel_shutdown(void);
-extern "C" void grpc_tsi_gts_init(void);
-extern "C" void grpc_tsi_gts_shutdown(void);
-extern "C" void grpc_server_load_reporting_plugin_init(void);
-extern "C" void grpc_server_load_reporting_plugin_shutdown(void);
+void grpc_http_filters_init(void);
+void grpc_http_filters_shutdown(void);
+void grpc_chttp2_plugin_init(void);
+void grpc_chttp2_plugin_shutdown(void);
+void grpc_deadline_filter_init(void);
+void grpc_deadline_filter_shutdown(void);
+void grpc_client_channel_init(void);
+void grpc_client_channel_shutdown(void);
+void grpc_tsi_gts_init(void);
+void grpc_tsi_gts_shutdown(void);
+void grpc_server_load_reporting_plugin_init(void);
+void grpc_server_load_reporting_plugin_shutdown(void);
 
 void grpc_register_built_in_plugins(void) {
   grpc_register_plugin(grpc_http_filters_init,
diff --git a/src/core/plugin_registry/grpc_plugin_registry.cc b/src/core/plugin_registry/grpc_plugin_registry.cc
index 339c9bb..89be351 100644
--- a/src/core/plugin_registry/grpc_plugin_registry.cc
+++ b/src/core/plugin_registry/grpc_plugin_registry.cc
@@ -18,40 +18,40 @@
 
 #include <grpc/grpc.h>
 
-extern "C" void grpc_http_filters_init(void);
-extern "C" void grpc_http_filters_shutdown(void);
-extern "C" void grpc_chttp2_plugin_init(void);
-extern "C" void grpc_chttp2_plugin_shutdown(void);
-extern "C" void grpc_tsi_gts_init(void);
-extern "C" void grpc_tsi_gts_shutdown(void);
-extern "C" void grpc_deadline_filter_init(void);
-extern "C" void grpc_deadline_filter_shutdown(void);
-extern "C" void grpc_client_channel_init(void);
-extern "C" void grpc_client_channel_shutdown(void);
-extern "C" void grpc_inproc_plugin_init(void);
-extern "C" void grpc_inproc_plugin_shutdown(void);
-extern "C" void grpc_resolver_fake_init(void);
-extern "C" void grpc_resolver_fake_shutdown(void);
-extern "C" void grpc_lb_policy_grpclb_init(void);
-extern "C" void grpc_lb_policy_grpclb_shutdown(void);
-extern "C" void grpc_lb_policy_pick_first_init(void);
-extern "C" void grpc_lb_policy_pick_first_shutdown(void);
-extern "C" void grpc_lb_policy_round_robin_init(void);
-extern "C" void grpc_lb_policy_round_robin_shutdown(void);
-extern "C" void grpc_resolver_dns_ares_init(void);
-extern "C" void grpc_resolver_dns_ares_shutdown(void);
-extern "C" void grpc_resolver_dns_native_init(void);
-extern "C" void grpc_resolver_dns_native_shutdown(void);
-extern "C" void grpc_resolver_sockaddr_init(void);
-extern "C" void grpc_resolver_sockaddr_shutdown(void);
-extern "C" void grpc_server_load_reporting_plugin_init(void);
-extern "C" void grpc_server_load_reporting_plugin_shutdown(void);
-extern "C" void grpc_max_age_filter_init(void);
-extern "C" void grpc_max_age_filter_shutdown(void);
-extern "C" void grpc_message_size_filter_init(void);
-extern "C" void grpc_message_size_filter_shutdown(void);
-extern "C" void grpc_workaround_cronet_compression_filter_init(void);
-extern "C" void grpc_workaround_cronet_compression_filter_shutdown(void);
+void grpc_http_filters_init(void);
+void grpc_http_filters_shutdown(void);
+void grpc_chttp2_plugin_init(void);
+void grpc_chttp2_plugin_shutdown(void);
+void grpc_tsi_gts_init(void);
+void grpc_tsi_gts_shutdown(void);
+void grpc_deadline_filter_init(void);
+void grpc_deadline_filter_shutdown(void);
+void grpc_client_channel_init(void);
+void grpc_client_channel_shutdown(void);
+void grpc_inproc_plugin_init(void);
+void grpc_inproc_plugin_shutdown(void);
+void grpc_resolver_fake_init(void);
+void grpc_resolver_fake_shutdown(void);
+void grpc_lb_policy_grpclb_init(void);
+void grpc_lb_policy_grpclb_shutdown(void);
+void grpc_lb_policy_pick_first_init(void);
+void grpc_lb_policy_pick_first_shutdown(void);
+void grpc_lb_policy_round_robin_init(void);
+void grpc_lb_policy_round_robin_shutdown(void);
+void grpc_resolver_dns_ares_init(void);
+void grpc_resolver_dns_ares_shutdown(void);
+void grpc_resolver_dns_native_init(void);
+void grpc_resolver_dns_native_shutdown(void);
+void grpc_resolver_sockaddr_init(void);
+void grpc_resolver_sockaddr_shutdown(void);
+void grpc_server_load_reporting_plugin_init(void);
+void grpc_server_load_reporting_plugin_shutdown(void);
+void grpc_max_age_filter_init(void);
+void grpc_max_age_filter_shutdown(void);
+void grpc_message_size_filter_init(void);
+void grpc_message_size_filter_shutdown(void);
+void grpc_workaround_cronet_compression_filter_init(void);
+void grpc_workaround_cronet_compression_filter_shutdown(void);
 
 void grpc_register_built_in_plugins(void) {
   grpc_register_plugin(grpc_http_filters_init,
diff --git a/src/core/plugin_registry/grpc_unsecure_plugin_registry.cc b/src/core/plugin_registry/grpc_unsecure_plugin_registry.cc
index c9fc17d..d73f946 100644
--- a/src/core/plugin_registry/grpc_unsecure_plugin_registry.cc
+++ b/src/core/plugin_registry/grpc_unsecure_plugin_registry.cc
@@ -18,38 +18,38 @@
 
 #include <grpc/grpc.h>
 
-extern "C" void grpc_http_filters_init(void);
-extern "C" void grpc_http_filters_shutdown(void);
-extern "C" void grpc_chttp2_plugin_init(void);
-extern "C" void grpc_chttp2_plugin_shutdown(void);
-extern "C" void grpc_deadline_filter_init(void);
-extern "C" void grpc_deadline_filter_shutdown(void);
-extern "C" void grpc_client_channel_init(void);
-extern "C" void grpc_client_channel_shutdown(void);
-extern "C" void grpc_inproc_plugin_init(void);
-extern "C" void grpc_inproc_plugin_shutdown(void);
-extern "C" void grpc_resolver_dns_ares_init(void);
-extern "C" void grpc_resolver_dns_ares_shutdown(void);
-extern "C" void grpc_resolver_dns_native_init(void);
-extern "C" void grpc_resolver_dns_native_shutdown(void);
-extern "C" void grpc_resolver_sockaddr_init(void);
-extern "C" void grpc_resolver_sockaddr_shutdown(void);
-extern "C" void grpc_resolver_fake_init(void);
-extern "C" void grpc_resolver_fake_shutdown(void);
-extern "C" void grpc_server_load_reporting_plugin_init(void);
-extern "C" void grpc_server_load_reporting_plugin_shutdown(void);
-extern "C" void grpc_lb_policy_grpclb_init(void);
-extern "C" void grpc_lb_policy_grpclb_shutdown(void);
-extern "C" void grpc_lb_policy_pick_first_init(void);
-extern "C" void grpc_lb_policy_pick_first_shutdown(void);
-extern "C" void grpc_lb_policy_round_robin_init(void);
-extern "C" void grpc_lb_policy_round_robin_shutdown(void);
-extern "C" void grpc_max_age_filter_init(void);
-extern "C" void grpc_max_age_filter_shutdown(void);
-extern "C" void grpc_message_size_filter_init(void);
-extern "C" void grpc_message_size_filter_shutdown(void);
-extern "C" void grpc_workaround_cronet_compression_filter_init(void);
-extern "C" void grpc_workaround_cronet_compression_filter_shutdown(void);
+void grpc_http_filters_init(void);
+void grpc_http_filters_shutdown(void);
+void grpc_chttp2_plugin_init(void);
+void grpc_chttp2_plugin_shutdown(void);
+void grpc_deadline_filter_init(void);
+void grpc_deadline_filter_shutdown(void);
+void grpc_client_channel_init(void);
+void grpc_client_channel_shutdown(void);
+void grpc_inproc_plugin_init(void);
+void grpc_inproc_plugin_shutdown(void);
+void grpc_resolver_dns_ares_init(void);
+void grpc_resolver_dns_ares_shutdown(void);
+void grpc_resolver_dns_native_init(void);
+void grpc_resolver_dns_native_shutdown(void);
+void grpc_resolver_sockaddr_init(void);
+void grpc_resolver_sockaddr_shutdown(void);
+void grpc_resolver_fake_init(void);
+void grpc_resolver_fake_shutdown(void);
+void grpc_server_load_reporting_plugin_init(void);
+void grpc_server_load_reporting_plugin_shutdown(void);
+void grpc_lb_policy_grpclb_init(void);
+void grpc_lb_policy_grpclb_shutdown(void);
+void grpc_lb_policy_pick_first_init(void);
+void grpc_lb_policy_pick_first_shutdown(void);
+void grpc_lb_policy_round_robin_init(void);
+void grpc_lb_policy_round_robin_shutdown(void);
+void grpc_max_age_filter_init(void);
+void grpc_max_age_filter_shutdown(void);
+void grpc_message_size_filter_init(void);
+void grpc_message_size_filter_shutdown(void);
+void grpc_workaround_cronet_compression_filter_init(void);
+void grpc_workaround_cronet_compression_filter_shutdown(void);
 
 void grpc_register_built_in_plugins(void) {
   grpc_register_plugin(grpc_http_filters_init,
diff --git a/src/core/tsi/fake_transport_security.cc b/src/core/tsi/fake_transport_security.cc
index e508d9b..f2f365f 100644
--- a/src/core/tsi/fake_transport_security.cc
+++ b/src/core/tsi/fake_transport_security.cc
@@ -575,7 +575,7 @@
     if (next_message_to_send > TSI_FAKE_HANDSHAKE_MESSAGE_MAX) {
       next_message_to_send = TSI_FAKE_HANDSHAKE_MESSAGE_MAX;
     }
-    if (GRPC_TRACER_ON(tsi_tracing_enabled)) {
+    if (tsi_tracing_enabled.enabled()) {
       gpr_log(GPR_INFO, "%s prepared %s.",
               impl->is_client ? "Client" : "Server",
               tsi_fake_handshake_message_to_string(impl->next_message_to_send));
@@ -587,7 +587,7 @@
   if (!impl->is_client &&
       impl->next_message_to_send == TSI_FAKE_HANDSHAKE_MESSAGE_MAX) {
     /* We're done. */
-    if (GRPC_TRACER_ON(tsi_tracing_enabled)) {
+    if (tsi_tracing_enabled.enabled()) {
       gpr_log(GPR_INFO, "Server is done.");
     }
     impl->result = TSI_OK;
@@ -625,7 +625,7 @@
             tsi_fake_handshake_message_to_string(received_msg),
             tsi_fake_handshake_message_to_string(expected_msg));
   }
-  if (GRPC_TRACER_ON(tsi_tracing_enabled)) {
+  if (tsi_tracing_enabled.enabled()) {
     gpr_log(GPR_INFO, "%s received %s.", impl->is_client ? "Client" : "Server",
             tsi_fake_handshake_message_to_string(received_msg));
   }
@@ -633,7 +633,7 @@
   impl->needs_incoming_message = 0;
   if (impl->next_message_to_send == TSI_FAKE_HANDSHAKE_MESSAGE_MAX) {
     /* We're done. */
-    if (GRPC_TRACER_ON(tsi_tracing_enabled)) {
+    if (tsi_tracing_enabled.enabled()) {
       gpr_log(GPR_INFO, "%s is done.", impl->is_client ? "Client" : "Server");
     }
     impl->result = TSI_OK;
diff --git a/src/core/tsi/fake_transport_security.h b/src/core/tsi/fake_transport_security.h
index b90b996..3848e7c 100644
--- a/src/core/tsi/fake_transport_security.h
+++ b/src/core/tsi/fake_transport_security.h
@@ -21,10 +21,6 @@
 
 #include "src/core/tsi/transport_security_interface.h"
 
-#ifdef __cplusplus
-extern "C" {
-#endif
-
 /* Value for the TSI_CERTIFICATE_TYPE_PEER_PROPERTY property for FAKE certs. */
 #define TSI_FAKE_CERTIFICATE_TYPE "FAKE"
 
@@ -44,8 +40,4 @@
 tsi_zero_copy_grpc_protector* tsi_create_fake_zero_copy_grpc_protector(
     size_t* max_protected_frame_size);
 
-#ifdef __cplusplus
-}
-#endif
-
 #endif /* GRPC_CORE_TSI_FAKE_TRANSPORT_SECURITY_H */
diff --git a/src/core/tsi/gts_transport_security.cc b/src/core/tsi/gts_transport_security.cc
index d5948c9..2b09977 100644
--- a/src/core/tsi/gts_transport_security.cc
+++ b/src/core/tsi/gts_transport_security.cc
@@ -24,12 +24,12 @@
 
 gts_shared_resource* gts_get_shared_resource(void) { return &g_gts_resource; }
 
-extern "C" void grpc_tsi_gts_init() {
+void grpc_tsi_gts_init() {
   memset(&g_gts_resource, 0, sizeof(gts_shared_resource));
   gpr_mu_init(&g_gts_resource.mu);
 }
 
-extern "C" void grpc_tsi_gts_shutdown() {
+void grpc_tsi_gts_shutdown() {
   gpr_mu_destroy(&g_gts_resource.mu);
   if (g_gts_resource.cq == nullptr) {
     return;
diff --git a/src/core/tsi/gts_transport_security.h b/src/core/tsi/gts_transport_security.h
index 8bc2107..23b2b66 100644
--- a/src/core/tsi/gts_transport_security.h
+++ b/src/core/tsi/gts_transport_security.h
@@ -23,10 +23,6 @@
 #include <grpc/support/sync.h>
 #include <grpc/support/thd.h>
 
-#ifdef __cplusplus
-extern "C" {
-#endif
-
 typedef struct gts_shared_resource {
   gpr_thd_id thread_id;
   grpc_channel* channel;
@@ -38,8 +34,4 @@
  *    TSI handshakes. */
 gts_shared_resource* gts_get_shared_resource(void);
 
-#ifdef __cplusplus
-}
-#endif
-
 #endif /* GRPC_CORE_TSI_GTS_TRANSPORT_SECURITY_H */
diff --git a/src/core/tsi/ssl_transport_security.cc b/src/core/tsi/ssl_transport_security.cc
index f1fff04..f35caef 100644
--- a/src/core/tsi/ssl_transport_security.cc
+++ b/src/core/tsi/ssl_transport_security.cc
@@ -175,7 +175,7 @@
 /* TODO(jboeuf): Remove when we are past the debugging phase with this code. */
 static void ssl_log_where_info(const SSL* ssl, int where, int flag,
                                const char* msg) {
-  if ((where & flag) && GRPC_TRACER_ON(tsi_tracing_enabled)) {
+  if ((where & flag) && tsi_tracing_enabled.enabled()) {
     gpr_log(GPR_INFO, "%20.20s - %30.30s  - %5.10s", msg,
             SSL_state_string_long(ssl), SSL_state_string(ssl));
   }
diff --git a/src/core/tsi/ssl_transport_security.h b/src/core/tsi/ssl_transport_security.h
index 595c4cc..bf211e1 100644
--- a/src/core/tsi/ssl_transport_security.h
+++ b/src/core/tsi/ssl_transport_security.h
@@ -21,10 +21,6 @@
 
 #include "src/core/tsi/transport_security_interface.h"
 
-#ifdef __cplusplus
-extern "C" {
-#endif
-
 /* Value for the TSI_CERTIFICATE_TYPE_PEER_PROPERTY property for X509 certs. */
 #define TSI_X509_CERTIFICATE_TYPE "X509"
 
@@ -193,8 +189,4 @@
     tsi_ssl_handshaker_factory* factory,
     tsi_ssl_handshaker_factory_vtable* new_vtable);
 
-#ifdef __cplusplus
-}
-#endif
-
 #endif /* GRPC_CORE_TSI_SSL_TRANSPORT_SECURITY_H */
diff --git a/src/core/tsi/ssl_types.h b/src/core/tsi/ssl_types.h
index e0e9670..3788643 100644
--- a/src/core/tsi/ssl_types.h
+++ b/src/core/tsi/ssl_types.h
@@ -19,10 +19,6 @@
 #ifndef GRPC_CORE_TSI_SSL_TYPES_H
 #define GRPC_CORE_TSI_SSL_TYPES_H
 
-#ifdef __cplusplus
-extern "C" {
-#endif
-
 /* A collection of macros to cast between various integer types that are
  * used differently between BoringSSL and OpenSSL:
  * TSI_INT_AS_SIZE(x):  convert 'int x' to a length parameter for an OpenSSL
@@ -41,8 +37,4 @@
 #define TSI_SIZE_AS_SIZE(x) ((int)(x))
 #endif
 
-#ifdef __cplusplus
-}
-#endif
-
 #endif /* GRPC_CORE_TSI_SSL_TYPES_H */
diff --git a/src/core/tsi/transport_security.cc b/src/core/tsi/transport_security.cc
index a2232bf..5abd2f0 100644
--- a/src/core/tsi/transport_security.cc
+++ b/src/core/tsi/transport_security.cc
@@ -26,7 +26,7 @@
 
 /* --- Tracing. --- */
 
-grpc_tracer_flag tsi_tracing_enabled = GRPC_TRACER_INITIALIZER(false, "tsi");
+grpc_core::TraceFlag tsi_tracing_enabled(false, "tsi");
 
 /* --- tsi_result common implementation. --- */
 
diff --git a/src/core/tsi/transport_security.h b/src/core/tsi/transport_security.h
index d639f85..bf3a776 100644
--- a/src/core/tsi/transport_security.h
+++ b/src/core/tsi/transport_security.h
@@ -24,11 +24,7 @@
 #include "src/core/lib/debug/trace.h"
 #include "src/core/tsi/transport_security_interface.h"
 
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-extern grpc_tracer_flag tsi_tracing_enabled;
+extern grpc_core::TraceFlag tsi_tracing_enabled;
 
 /* Base for tsi_frame_protector implementations.
    See transport_security_interface.h for documentation. */
@@ -126,8 +122,4 @@
 /* Utils. */
 char* tsi_strdup(const char* src); /* Sadly, no strdup in C89. */
 
-#ifdef __cplusplus
-}
-#endif
-
 #endif /* GRPC_CORE_TSI_TRANSPORT_SECURITY_H */
diff --git a/src/core/tsi/transport_security_adapter.h b/src/core/tsi/transport_security_adapter.h
index 232705f..9818fce 100644
--- a/src/core/tsi/transport_security_adapter.h
+++ b/src/core/tsi/transport_security_adapter.h
@@ -21,10 +21,6 @@
 
 #include "src/core/tsi/transport_security_interface.h"
 
-#ifdef __cplusplus
-extern "C" {
-#endif
-
 /* Create a tsi handshaker that takes an implementation of old interface and
    converts into an implementation of new interface. In the old interface,
    there are get_bytes_to_send_to_peer, process_bytes_from_peer, get_result,
@@ -40,8 +36,4 @@
    the caller. */
 tsi_handshaker* tsi_adapter_handshaker_get_wrapped(tsi_handshaker* adapter);
 
-#ifdef __cplusplus
-}
-#endif
-
 #endif /* GRPC_CORE_TSI_TRANSPORT_SECURITY_ADAPTER_H */
diff --git a/src/core/tsi/transport_security_grpc.h b/src/core/tsi/transport_security_grpc.h
index 1c54693..9fccfd7 100644
--- a/src/core/tsi/transport_security_grpc.h
+++ b/src/core/tsi/transport_security_grpc.h
@@ -22,10 +22,6 @@
 #include <grpc/slice_buffer.h>
 #include "src/core/tsi/transport_security.h"
 
-#ifdef __cplusplus
-extern "C" {
-#endif
-
 /* This method creates a tsi_zero_copy_grpc_protector object. It return TSI_OK
    assuming there is no fatal error.
    The caller is responsible for destroying the protector.  */
@@ -77,8 +73,4 @@
   const tsi_zero_copy_grpc_protector_vtable* vtable;
 };
 
-#ifdef __cplusplus
-}
-#endif
-
 #endif /* GRPC_CORE_TSI_TRANSPORT_SECURITY_GRPC_H */
diff --git a/src/core/tsi/transport_security_interface.h b/src/core/tsi/transport_security_interface.h
index 54942a6..e925598 100644
--- a/src/core/tsi/transport_security_interface.h
+++ b/src/core/tsi/transport_security_interface.h
@@ -24,10 +24,6 @@
 
 #include "src/core/lib/debug/trace.h"
 
-#ifdef __cplusplus
-extern "C" {
-#endif
-
 /* --- tsi result ---  */
 
 typedef enum {
@@ -60,7 +56,7 @@
 
 /* --- tsi tracing --- */
 
-extern grpc_tracer_flag tsi_tracing_enabled;
+extern grpc_core::TraceFlag tsi_tracing_enabled;
 
 /* -- tsi_zero_copy_grpc_protector object --
 
@@ -453,8 +449,4 @@
 /* This method destroys the shared objects created by tsi_init.  */
 void tsi_destroy();
 
-#ifdef __cplusplus
-}
-#endif
-
 #endif /* GRPC_CORE_TSI_TRANSPORT_SECURITY_INTERFACE_H */
diff --git a/src/cpp/common/channel_arguments.cc b/src/cpp/common/channel_arguments.cc
index f89f5f1..cae9ef9 100644
--- a/src/cpp/common/channel_arguments.cc
+++ b/src/cpp/common/channel_arguments.cc
@@ -23,11 +23,10 @@
 #include <grpc++/resource_quota.h>
 #include <grpc/impl/codegen/grpc_types.h>
 #include <grpc/support/log.h>
-extern "C" {
 #include "src/core/lib/channel/channel_args.h"
 #include "src/core/lib/iomgr/exec_ctx.h"
 #include "src/core/lib/iomgr/socket_mutator.h"
-}
+
 namespace grpc {
 
 ChannelArguments::ChannelArguments() {
diff --git a/src/cpp/common/channel_filter.cc b/src/cpp/common/channel_filter.cc
index d1cfd2b..274079f 100644
--- a/src/cpp/common/channel_filter.cc
+++ b/src/cpp/common/channel_filter.cc
@@ -18,9 +18,7 @@
 
 #include <string.h>
 
-extern "C" {
 #include "src/core/lib/channel/channel_stack.h"
-}
 #include "src/cpp/common/channel_filter.h"
 
 #include <grpc++/impl/codegen/slice.h>
diff --git a/src/cpp/common/channel_filter.h b/src/cpp/common/channel_filter.h
index 4fb81ec..9fe9cf0 100644
--- a/src/cpp/common/channel_filter.h
+++ b/src/cpp/common/channel_filter.h
@@ -26,11 +26,9 @@
 #include <functional>
 #include <vector>
 
-extern "C" {
 #include "src/core/lib/channel/channel_stack.h"
 #include "src/core/lib/surface/channel_init.h"
 #include "src/core/lib/transport/metadata_batch.h"
-}
 
 /// An interface to define filters.
 ///
diff --git a/src/cpp/common/core_codegen.cc b/src/cpp/common/core_codegen.cc
index 3cbf08a..936d699 100644
--- a/src/cpp/common/core_codegen.cc
+++ b/src/cpp/common/core_codegen.cc
@@ -33,9 +33,7 @@
 
 #include "src/core/lib/profiling/timers.h"
 
-extern "C" {
 struct grpc_byte_buffer;
-}
 
 namespace grpc {
 
diff --git a/src/cpp/common/version_cc.cc b/src/cpp/common/version_cc.cc
index e1e5e89..7f01a66 100644
--- a/src/cpp/common/version_cc.cc
+++ b/src/cpp/common/version_cc.cc
@@ -22,5 +22,5 @@
 #include <grpc++/grpc++.h>
 
 namespace grpc {
-grpc::string Version() { return "1.8.0-dev"; }
+grpc::string Version() { return "1.9.0-dev"; }
 }  // namespace grpc
diff --git a/src/cpp/util/core_stats.h b/src/cpp/util/core_stats.h
index 00e38bf..6366d7d 100644
--- a/src/cpp/util/core_stats.h
+++ b/src/cpp/util/core_stats.h
@@ -21,9 +21,7 @@
 
 #include "src/proto/grpc/core/stats.pb.h"
 
-extern "C" {
 #include "src/core/lib/debug/stats.h"
-}
 
 namespace grpc {
 
diff --git a/src/csharp/Grpc.Core.Tests/CallCancellationTest.cs b/src/csharp/Grpc.Core.Tests/CallCancellationTest.cs
new file mode 100644
index 0000000..e040f52
--- /dev/null
+++ b/src/csharp/Grpc.Core.Tests/CallCancellationTest.cs
@@ -0,0 +1,182 @@
+#region Copyright notice and license
+
+// Copyright 2015 gRPC authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#endregion
+
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.Linq;
+using System.Threading;
+using System.Threading.Tasks;
+using Grpc.Core;
+using Grpc.Core.Internal;
+using Grpc.Core.Profiling;
+using Grpc.Core.Utils;
+using NUnit.Framework;
+
+namespace Grpc.Core.Tests
+{
+    public class CallCancellationTest
+    {
+        const string Host = "127.0.0.1";
+
+        MockServiceHelper helper;
+        Server server;
+        Channel channel;
+
+        [SetUp]
+        public void Init()
+        {
+            helper = new MockServiceHelper(Host);
+            server = helper.GetServer();
+            server.Start();
+            channel = helper.GetChannel();
+        }
+
+        [TearDown]
+        public void Cleanup()
+        {
+            channel.ShutdownAsync().Wait();
+            server.ShutdownAsync().Wait();
+        }
+
+        [Test]
+        public async Task ClientStreamingCall_CancelAfterBegin()
+        {
+            var barrier = new TaskCompletionSource<object>();
+
+            helper.ClientStreamingHandler = new ClientStreamingServerMethod<string, string>(async (requestStream, context) =>
+            {
+                barrier.SetResult(null);
+                await requestStream.ToListAsync();
+                return "";
+            });
+
+            var cts = new CancellationTokenSource();
+            var call = Calls.AsyncClientStreamingCall(helper.CreateClientStreamingCall(new CallOptions(cancellationToken: cts.Token)));
+
+            await barrier.Task;  // make sure the handler has started.
+            cts.Cancel();
+
+            try
+            {
+                // cannot use Assert.ThrowsAsync because it uses Task.Wait and would deadlock.
+                await call.ResponseAsync;
+                Assert.Fail();
+            }
+            catch (RpcException ex)
+            {
+                Assert.AreEqual(StatusCode.Cancelled, ex.Status.StatusCode);
+            }
+        }
+
+        [Test]
+        public async Task ClientStreamingCall_ServerSideReadAfterCancelNotificationReturnsNull()
+        {
+            var handlerStartedBarrier = new TaskCompletionSource<object>();
+            var cancelNotificationReceivedBarrier = new TaskCompletionSource<object>();
+            var successTcs = new TaskCompletionSource<string>();
+
+            helper.ClientStreamingHandler = new ClientStreamingServerMethod<string, string>(async (requestStream, context) =>
+            {
+                handlerStartedBarrier.SetResult(null);
+
+                // wait for cancellation to be delivered.
+                context.CancellationToken.Register(() => cancelNotificationReceivedBarrier.SetResult(null));
+                await cancelNotificationReceivedBarrier.Task;
+
+                var moveNextResult = await requestStream.MoveNext();
+                successTcs.SetResult(!moveNextResult ? "SUCCESS" : "FAIL");
+                return "";
+            });
+
+            var cts = new CancellationTokenSource();
+            var call = Calls.AsyncClientStreamingCall(helper.CreateClientStreamingCall(new CallOptions(cancellationToken: cts.Token)));
+
+            await handlerStartedBarrier.Task;
+            cts.Cancel();
+
+            try
+            {
+                await call.ResponseAsync;
+                Assert.Fail();
+            }
+            catch (RpcException ex)
+            {
+                Assert.AreEqual(StatusCode.Cancelled, ex.Status.StatusCode);
+            }
+            Assert.AreEqual("SUCCESS", await successTcs.Task);
+        }
+
+        [Test]
+        public async Task ClientStreamingCall_CancelServerSideRead()
+        {
+            helper.ClientStreamingHandler = new ClientStreamingServerMethod<string, string>(async (requestStream, context) =>
+            {
+                var cts = new CancellationTokenSource();
+                var moveNextTask = requestStream.MoveNext(cts.Token);
+                cts.Cancel();
+                await moveNextTask;
+                return "";
+            });
+
+            var call = Calls.AsyncClientStreamingCall(helper.CreateClientStreamingCall());
+            try
+            {
+                // cannot use Assert.ThrowsAsync because it uses Task.Wait and would deadlock.
+                await call.ResponseAsync;
+                Assert.Fail();
+            }
+            catch (RpcException ex)
+            {
+                Assert.AreEqual(StatusCode.Cancelled, ex.Status.StatusCode);
+            }
+        }
+
+        [Test]
+        public async Task ServerStreamingCall_CancelClientSideRead()
+        {
+            helper.ServerStreamingHandler = new ServerStreamingServerMethod<string, string>(async (request, responseStream, context) =>
+            {
+                await responseStream.WriteAsync("abc");
+                while (!context.CancellationToken.IsCancellationRequested)
+                {
+                    await Task.Delay(10);
+                }
+            });
+
+            var call = Calls.AsyncServerStreamingCall(helper.CreateServerStreamingCall(), "");
+            await call.ResponseStream.MoveNext();
+            Assert.AreEqual("abc", call.ResponseStream.Current);
+
+            var cts = new CancellationTokenSource();
+            var moveNextTask = call.ResponseStream.MoveNext(cts.Token);
+            cts.Cancel();
+
+            try
+            {
+                // cannot use Assert.ThrowsAsync because it uses Task.Wait and would deadlock.
+                await moveNextTask;
+                Assert.Fail();
+            }
+            catch (RpcException ex)
+            {
+                Assert.AreEqual(StatusCode.Cancelled, ex.Status.StatusCode);
+            }
+        }
+    }
+}
diff --git a/src/csharp/Grpc.Core.Tests/ClientServerTest.cs b/src/csharp/Grpc.Core.Tests/ClientServerTest.cs
index 72d9035..90dd365 100644
--- a/src/csharp/Grpc.Core.Tests/ClientServerTest.cs
+++ b/src/csharp/Grpc.Core.Tests/ClientServerTest.cs
@@ -273,74 +273,6 @@
         }
 
         [Test]
-        public async Task ClientStreamingCall_CancelAfterBegin()
-        {
-            var barrier = new TaskCompletionSource<object>();
-
-            helper.ClientStreamingHandler = new ClientStreamingServerMethod<string, string>(async (requestStream, context) =>
-            {
-                barrier.SetResult(null);
-                await requestStream.ToListAsync();
-                return "";
-            });
-
-            var cts = new CancellationTokenSource();
-            var call = Calls.AsyncClientStreamingCall(helper.CreateClientStreamingCall(new CallOptions(cancellationToken: cts.Token)));
-
-            await barrier.Task;  // make sure the handler has started.
-            cts.Cancel();
-
-            try
-            {
-                // cannot use Assert.ThrowsAsync because it uses Task.Wait and would deadlock.
-                await call.ResponseAsync;
-                Assert.Fail();
-            }
-            catch (RpcException ex)
-            {
-                Assert.AreEqual(StatusCode.Cancelled, ex.Status.StatusCode);
-            }
-        }
-
-        [Test]
-        public async Task ClientStreamingCall_ServerSideReadAfterCancelNotificationReturnsNull()
-        {
-            var handlerStartedBarrier = new TaskCompletionSource<object>();
-            var cancelNotificationReceivedBarrier = new TaskCompletionSource<object>();
-            var successTcs = new TaskCompletionSource<string>();
-
-            helper.ClientStreamingHandler = new ClientStreamingServerMethod<string, string>(async (requestStream, context) =>
-            {
-                handlerStartedBarrier.SetResult(null);
-
-                // wait for cancellation to be delivered.
-                context.CancellationToken.Register(() => cancelNotificationReceivedBarrier.SetResult(null));
-                await cancelNotificationReceivedBarrier.Task;
-
-                var moveNextResult = await requestStream.MoveNext();
-                successTcs.SetResult(!moveNextResult ? "SUCCESS" : "FAIL");
-                return "";
-            });
-
-            var cts = new CancellationTokenSource();
-            var call = Calls.AsyncClientStreamingCall(helper.CreateClientStreamingCall(new CallOptions(cancellationToken: cts.Token)));
-
-            await handlerStartedBarrier.Task;
-            cts.Cancel();
-
-            try
-            {
-                await call.ResponseAsync;
-                Assert.Fail();
-            }
-            catch (RpcException ex)
-            {
-                Assert.AreEqual(StatusCode.Cancelled, ex.Status.StatusCode);
-            }
-            Assert.AreEqual("SUCCESS", await successTcs.Task);
-        }
-
-        [Test]
         public async Task AsyncUnaryCall_EchoMetadata()
         {
             helper.UnaryHandler = new UnaryServerMethod<string, string>((request, context) =>
diff --git a/src/csharp/Grpc.Core.Tests/Internal/AsyncCallServerTest.cs b/src/csharp/Grpc.Core.Tests/Internal/AsyncCallServerTest.cs
index 9488ce2..e7d8939 100644
--- a/src/csharp/Grpc.Core.Tests/Internal/AsyncCallServerTest.cs
+++ b/src/csharp/Grpc.Core.Tests/Internal/AsyncCallServerTest.cs
@@ -64,7 +64,7 @@
         public void CancelNotificationAfterStartDisposes()
         {
             var finishedTask = asyncCallServer.ServerSideCallAsync();
-            fakeCall.ReceivedCloseOnServerHandler(true, cancelled: true);
+            fakeCall.ReceivedCloseOnServerCallback.OnReceivedCloseOnServer(true, cancelled: true);
             AssertFinished(asyncCallServer, fakeCall, finishedTask);
         }
 
@@ -76,8 +76,8 @@
 
             var moveNextTask = requestStream.MoveNext();
 
-            fakeCall.ReceivedCloseOnServerHandler(true, cancelled: true);
-            fakeCall.ReceivedMessageHandler(true, null);
+            fakeCall.ReceivedCloseOnServerCallback.OnReceivedCloseOnServer(true, cancelled: true);
+            fakeCall.ReceivedMessageCallback.OnReceivedMessage(true, null);
             Assert.IsFalse(moveNextTask.Result);
 
             AssertFinished(asyncCallServer, fakeCall, finishedTask);
@@ -89,7 +89,7 @@
             var finishedTask = asyncCallServer.ServerSideCallAsync();
             var requestStream = new ServerRequestStream<string, string>(asyncCallServer);
 
-            fakeCall.ReceivedCloseOnServerHandler(true, cancelled: true);
+            fakeCall.ReceivedCloseOnServerCallback.OnReceivedCloseOnServer(true, cancelled: true);
 
             // Check that starting a read after cancel notification has been processed is legal.
             var moveNextTask = requestStream.MoveNext();
@@ -107,10 +107,10 @@
             // if a read completion's success==false, the request stream will silently finish
             // and we rely on C core cancelling the call.
             var moveNextTask = requestStream.MoveNext();
-            fakeCall.ReceivedMessageHandler(false, null);
+            fakeCall.ReceivedMessageCallback.OnReceivedMessage(false, null);
             Assert.IsFalse(moveNextTask.Result);
 
-            fakeCall.ReceivedCloseOnServerHandler(true, cancelled: true);
+            fakeCall.ReceivedCloseOnServerCallback.OnReceivedCloseOnServer(true, cancelled: true);
             AssertFinished(asyncCallServer, fakeCall, finishedTask);
         }
 
@@ -120,7 +120,7 @@
             var finishedTask = asyncCallServer.ServerSideCallAsync();
             var responseStream = new ServerResponseStream<string, string>(asyncCallServer);
 
-            fakeCall.ReceivedCloseOnServerHandler(true, cancelled: true);
+            fakeCall.ReceivedCloseOnServerCallback.OnReceivedCloseOnServer(true, cancelled: true);
 
             // TODO(jtattermusch): should we throw a different exception type instead?
             Assert.Throws(typeof(InvalidOperationException), () => responseStream.WriteAsync("request1"));
@@ -134,10 +134,10 @@
             var responseStream = new ServerResponseStream<string, string>(asyncCallServer);
 
             var writeTask = responseStream.WriteAsync("request1");
-            fakeCall.SendCompletionHandler(false);
+            fakeCall.SendCompletionCallback.OnSendCompletion(false);
             Assert.ThrowsAsync(typeof(IOException), async () => await writeTask);
 
-            fakeCall.ReceivedCloseOnServerHandler(true, cancelled: true);
+            fakeCall.ReceivedCloseOnServerCallback.OnReceivedCloseOnServer(true, cancelled: true);
             AssertFinished(asyncCallServer, fakeCall, finishedTask);
         }
 
@@ -150,13 +150,13 @@
             var writeTask = responseStream.WriteAsync("request1");
             var writeStatusTask = asyncCallServer.SendStatusFromServerAsync(Status.DefaultSuccess, new Metadata(), null);
 
-            fakeCall.SendCompletionHandler(true);
-            fakeCall.SendStatusFromServerHandler(true);
+            fakeCall.SendCompletionCallback.OnSendCompletion(true);
+            fakeCall.SendStatusFromServerCallback.OnSendStatusFromServerCompletion(true);
 
             Assert.DoesNotThrowAsync(async () => await writeTask);
             Assert.DoesNotThrowAsync(async () => await writeStatusTask);
 
-            fakeCall.ReceivedCloseOnServerHandler(true, cancelled: true);
+            fakeCall.ReceivedCloseOnServerCallback.OnReceivedCloseOnServer(true, cancelled: true);
 
             AssertFinished(asyncCallServer, fakeCall, finishedTask);
         }
@@ -170,8 +170,8 @@
             asyncCallServer.SendStatusFromServerAsync(Status.DefaultSuccess, new Metadata(), null);
             Assert.ThrowsAsync(typeof(InvalidOperationException), async () => await responseStream.WriteAsync("request1"));
 
-            fakeCall.SendStatusFromServerHandler(true);
-            fakeCall.ReceivedCloseOnServerHandler(true, cancelled: true);
+            fakeCall.SendStatusFromServerCallback.OnSendStatusFromServerCompletion(true);
+            fakeCall.ReceivedCloseOnServerCallback.OnReceivedCloseOnServer(true, cancelled: true);
 
             AssertFinished(asyncCallServer, fakeCall, finishedTask);
         }
diff --git a/src/csharp/Grpc.Core.Tests/Internal/AsyncCallTest.cs b/src/csharp/Grpc.Core.Tests/Internal/AsyncCallTest.cs
index b2b49f3..9aab54d 100644
--- a/src/csharp/Grpc.Core.Tests/Internal/AsyncCallTest.cs
+++ b/src/csharp/Grpc.Core.Tests/Internal/AsyncCallTest.cs
@@ -73,7 +73,7 @@
         public void AsyncUnary_Success()
         {
             var resultTask = asyncCall.UnaryCallAsync("request1");
-            fakeCall.UnaryResponseClientHandler(true,
+            fakeCall.UnaryResponseClientCallback.OnUnaryResponseClient(true,
                 new ClientSideStatus(Status.DefaultSuccess, new Metadata()),
                 CreateResponsePayload(),
                 new Metadata());
@@ -85,7 +85,7 @@
         public void AsyncUnary_NonSuccessStatusCode()
         {
             var resultTask = asyncCall.UnaryCallAsync("request1");
-            fakeCall.UnaryResponseClientHandler(true,
+            fakeCall.UnaryResponseClientCallback.OnUnaryResponseClient(true,
                 CreateClientSideStatus(StatusCode.InvalidArgument),
                 null,
                 new Metadata());
@@ -97,7 +97,7 @@
         public void AsyncUnary_NullResponsePayload()
         {
             var resultTask = asyncCall.UnaryCallAsync("request1");
-            fakeCall.UnaryResponseClientHandler(true,
+            fakeCall.UnaryResponseClientCallback.OnUnaryResponseClient(true,
                 new ClientSideStatus(Status.DefaultSuccess, new Metadata()),
                 null,
                 new Metadata());
@@ -118,7 +118,7 @@
         public void ClientStreaming_NoRequest_Success()
         {
             var resultTask = asyncCall.ClientStreamingCallAsync();
-            fakeCall.UnaryResponseClientHandler(true,
+            fakeCall.UnaryResponseClientCallback.OnUnaryResponseClient(true,
                 new ClientSideStatus(Status.DefaultSuccess, new Metadata()),
                 CreateResponsePayload(),
                 new Metadata());
@@ -130,7 +130,7 @@
         public void ClientStreaming_NoRequest_NonSuccessStatusCode()
         {
             var resultTask = asyncCall.ClientStreamingCallAsync();
-            fakeCall.UnaryResponseClientHandler(true,
+            fakeCall.UnaryResponseClientCallback.OnUnaryResponseClient(true,
                 CreateClientSideStatus(StatusCode.InvalidArgument),
                 null,
                 new Metadata());
@@ -145,18 +145,18 @@
             var requestStream = new ClientRequestStream<string, string>(asyncCall);
 
             var writeTask = requestStream.WriteAsync("request1");
-            fakeCall.SendCompletionHandler(true);
+            fakeCall.SendCompletionCallback.OnSendCompletion(true);
             writeTask.Wait();
 
             var writeTask2 = requestStream.WriteAsync("request2");
-            fakeCall.SendCompletionHandler(true);
+            fakeCall.SendCompletionCallback.OnSendCompletion(true);
             writeTask2.Wait();
 
             var completeTask = requestStream.CompleteAsync();
-            fakeCall.SendCompletionHandler(true);
+            fakeCall.SendCompletionCallback.OnSendCompletion(true);
             completeTask.Wait();
 
-            fakeCall.UnaryResponseClientHandler(true,
+            fakeCall.UnaryResponseClientCallback.OnUnaryResponseClient(true,
                 new ClientSideStatus(Status.DefaultSuccess, new Metadata()),
                 CreateResponsePayload(),
                 new Metadata());
@@ -171,12 +171,12 @@
             var requestStream = new ClientRequestStream<string, string>(asyncCall);
 
             var writeTask = requestStream.WriteAsync("request1");
-            fakeCall.SendCompletionHandler(false);
+            fakeCall.SendCompletionCallback.OnSendCompletion(false);
 
             // The write will wait for call to finish to receive the status code.
             Assert.IsFalse(writeTask.IsCompleted);
 
-            fakeCall.UnaryResponseClientHandler(true,
+            fakeCall.UnaryResponseClientCallback.OnUnaryResponseClient(true,
                 CreateClientSideStatus(StatusCode.Internal),
                 null,
                 new Metadata());
@@ -195,12 +195,12 @@
 
             var writeTask = requestStream.WriteAsync("request1");
 
-            fakeCall.UnaryResponseClientHandler(true,
+            fakeCall.UnaryResponseClientCallback.OnUnaryResponseClient(true,
                 CreateClientSideStatus(StatusCode.Internal),
                 null,
                 new Metadata());
 
-            fakeCall.SendCompletionHandler(false);
+            fakeCall.SendCompletionCallback.OnSendCompletion(false);
 
             var ex = Assert.ThrowsAsync<RpcException>(async () => await writeTask);
             Assert.AreEqual(StatusCode.Internal, ex.Status.StatusCode);
@@ -215,13 +215,13 @@
             var requestStream = new ClientRequestStream<string, string>(asyncCall);
 
             var writeTask = requestStream.WriteAsync("request1");
-            fakeCall.SendCompletionHandler(false);
+            fakeCall.SendCompletionCallback.OnSendCompletion(false);
 
             // Until the delayed write completion has been triggered,
             // we still act as if there was an active write.
             Assert.Throws(typeof(InvalidOperationException), () => requestStream.WriteAsync("request2"));
 
-            fakeCall.UnaryResponseClientHandler(true,
+            fakeCall.UnaryResponseClientCallback.OnUnaryResponseClient(true,
                 CreateClientSideStatus(StatusCode.Internal),
                 null,
                 new Metadata());
@@ -242,7 +242,7 @@
             var resultTask = asyncCall.ClientStreamingCallAsync();
             var requestStream = new ClientRequestStream<string, string>(asyncCall);
 
-            fakeCall.UnaryResponseClientHandler(true,
+            fakeCall.UnaryResponseClientCallback.OnUnaryResponseClient(true,
                 new ClientSideStatus(Status.DefaultSuccess, new Metadata()),
                 CreateResponsePayload(),
                 new Metadata());
@@ -260,7 +260,7 @@
             var resultTask = asyncCall.ClientStreamingCallAsync();
             var requestStream = new ClientRequestStream<string, string>(asyncCall);
 
-            fakeCall.UnaryResponseClientHandler(true,
+            fakeCall.UnaryResponseClientCallback.OnUnaryResponseClient(true,
                 new ClientSideStatus(new Status(StatusCode.OutOfRange, ""), new Metadata()),
                 CreateResponsePayload(),
                 new Metadata());
@@ -282,9 +282,9 @@
 
             Assert.Throws(typeof(InvalidOperationException), () => requestStream.WriteAsync("request1"));
 
-            fakeCall.SendCompletionHandler(true);
+            fakeCall.SendCompletionCallback.OnSendCompletion(true);
 
-            fakeCall.UnaryResponseClientHandler(true,
+            fakeCall.UnaryResponseClientCallback.OnUnaryResponseClient(true,
                 new ClientSideStatus(Status.DefaultSuccess, new Metadata()),
                 CreateResponsePayload(),
                 new Metadata());
@@ -298,7 +298,7 @@
             var resultTask = asyncCall.ClientStreamingCallAsync();
             var requestStream = new ClientRequestStream<string, string>(asyncCall);
 
-            fakeCall.UnaryResponseClientHandler(true,
+            fakeCall.UnaryResponseClientCallback.OnUnaryResponseClient(true,
                 new ClientSideStatus(Status.DefaultSuccess, new Metadata()),
                 CreateResponsePayload(),
                 new Metadata());
@@ -319,7 +319,7 @@
             var writeTask = requestStream.WriteAsync("request1");
             Assert.ThrowsAsync(typeof(TaskCanceledException), async () => await writeTask);
 
-            fakeCall.UnaryResponseClientHandler(true,
+            fakeCall.UnaryResponseClientCallback.OnUnaryResponseClient(true,
                 CreateClientSideStatus(StatusCode.Cancelled),
                 null,
                 new Metadata());
@@ -342,11 +342,11 @@
             var responseStream = new ClientResponseStream<string, string>(asyncCall);
             var readTask = responseStream.MoveNext();
 
-            fakeCall.ReceivedResponseHeadersHandler(true, new Metadata());
+            fakeCall.ReceivedResponseHeadersCallback.OnReceivedResponseHeaders(true, new Metadata());
             Assert.AreEqual(0, asyncCall.ResponseHeadersAsync.Result.Count);
 
-            fakeCall.ReceivedMessageHandler(true, null);
-            fakeCall.ReceivedStatusOnClientHandler(true, new ClientSideStatus(Status.DefaultSuccess, new Metadata()));
+            fakeCall.ReceivedMessageCallback.OnReceivedMessage(true, null);
+            fakeCall.ReceivedStatusOnClientCallback.OnReceivedStatusOnClient(true, new ClientSideStatus(Status.DefaultSuccess, new Metadata()));
 
             AssertStreamingResponseSuccess(asyncCall, fakeCall, readTask);
         }
@@ -359,8 +359,8 @@
             var readTask = responseStream.MoveNext();
 
             // try alternative order of completions
-            fakeCall.ReceivedStatusOnClientHandler(true, new ClientSideStatus(Status.DefaultSuccess, new Metadata()));
-            fakeCall.ReceivedMessageHandler(true, null);
+            fakeCall.ReceivedStatusOnClientCallback.OnReceivedStatusOnClient(true, new ClientSideStatus(Status.DefaultSuccess, new Metadata()));
+            fakeCall.ReceivedMessageCallback.OnReceivedMessage(true, null);
 
             AssertStreamingResponseSuccess(asyncCall, fakeCall, readTask);
         }
@@ -372,8 +372,8 @@
             var responseStream = new ClientResponseStream<string, string>(asyncCall);
             var readTask = responseStream.MoveNext();
 
-            fakeCall.ReceivedMessageHandler(false, null);  // after a failed read, we rely on C core to deliver appropriate status code.
-            fakeCall.ReceivedStatusOnClientHandler(true, CreateClientSideStatus(StatusCode.Internal));
+            fakeCall.ReceivedMessageCallback.OnReceivedMessage(false, null);  // after a failed read, we rely on C core to deliver appropriate status code.
+            fakeCall.ReceivedStatusOnClientCallback.OnReceivedStatusOnClient(true, CreateClientSideStatus(StatusCode.Internal));
 
             AssertStreamingResponseError(asyncCall, fakeCall, readTask, StatusCode.Internal);
         }
@@ -385,18 +385,18 @@
             var responseStream = new ClientResponseStream<string, string>(asyncCall);
 
             var readTask1 = responseStream.MoveNext();
-            fakeCall.ReceivedMessageHandler(true, CreateResponsePayload());
+            fakeCall.ReceivedMessageCallback.OnReceivedMessage(true, CreateResponsePayload());
             Assert.IsTrue(readTask1.Result);
             Assert.AreEqual("response1", responseStream.Current);
 
             var readTask2 = responseStream.MoveNext();
-            fakeCall.ReceivedMessageHandler(true, CreateResponsePayload());
+            fakeCall.ReceivedMessageCallback.OnReceivedMessage(true, CreateResponsePayload());
             Assert.IsTrue(readTask2.Result);
             Assert.AreEqual("response1", responseStream.Current);
 
             var readTask3 = responseStream.MoveNext();
-            fakeCall.ReceivedStatusOnClientHandler(true, new ClientSideStatus(Status.DefaultSuccess, new Metadata()));
-            fakeCall.ReceivedMessageHandler(true, null);
+            fakeCall.ReceivedStatusOnClientCallback.OnReceivedStatusOnClient(true, new ClientSideStatus(Status.DefaultSuccess, new Metadata()));
+            fakeCall.ReceivedMessageCallback.OnReceivedMessage(true, null);
 
             AssertStreamingResponseSuccess(asyncCall, fakeCall, readTask3);
         }
@@ -409,12 +409,12 @@
             var responseStream = new ClientResponseStream<string, string>(asyncCall);
 
             var writeTask1 = requestStream.CompleteAsync();
-            fakeCall.SendCompletionHandler(true);
+            fakeCall.SendCompletionCallback.OnSendCompletion(true);
             Assert.DoesNotThrowAsync(async () => await writeTask1);
 
             var readTask = responseStream.MoveNext();
-            fakeCall.ReceivedMessageHandler(true, null);
-            fakeCall.ReceivedStatusOnClientHandler(true, new ClientSideStatus(Status.DefaultSuccess, new Metadata()));
+            fakeCall.ReceivedMessageCallback.OnReceivedMessage(true, null);
+            fakeCall.ReceivedStatusOnClientCallback.OnReceivedStatusOnClient(true, new ClientSideStatus(Status.DefaultSuccess, new Metadata()));
 
             AssertStreamingResponseSuccess(asyncCall, fakeCall, readTask);
         }
@@ -427,8 +427,8 @@
             var responseStream = new ClientResponseStream<string, string>(asyncCall);
 
             var readTask = responseStream.MoveNext();
-            fakeCall.ReceivedMessageHandler(true, null);
-            fakeCall.ReceivedStatusOnClientHandler(true, new ClientSideStatus(Status.DefaultSuccess, new Metadata()));
+            fakeCall.ReceivedMessageCallback.OnReceivedMessage(true, null);
+            fakeCall.ReceivedStatusOnClientCallback.OnReceivedStatusOnClient(true, new ClientSideStatus(Status.DefaultSuccess, new Metadata()));
 
             AssertStreamingResponseSuccess(asyncCall, fakeCall, readTask);
 
@@ -445,8 +445,8 @@
             var responseStream = new ClientResponseStream<string, string>(asyncCall);
 
             var readTask = responseStream.MoveNext();
-            fakeCall.ReceivedMessageHandler(true, null);
-            fakeCall.ReceivedStatusOnClientHandler(true, new ClientSideStatus(Status.DefaultSuccess, new Metadata()));
+            fakeCall.ReceivedMessageCallback.OnReceivedMessage(true, null);
+            fakeCall.ReceivedStatusOnClientCallback.OnReceivedStatusOnClient(true, new ClientSideStatus(Status.DefaultSuccess, new Metadata()));
 
             AssertStreamingResponseSuccess(asyncCall, fakeCall, readTask);
 
@@ -461,14 +461,14 @@
             var responseStream = new ClientResponseStream<string, string>(asyncCall);
 
             var writeTask = requestStream.WriteAsync("request1");
-            fakeCall.SendCompletionHandler(false);
+            fakeCall.SendCompletionCallback.OnSendCompletion(false);
 
             // The write will wait for call to finish to receive the status code.
             Assert.IsFalse(writeTask.IsCompleted);
 
             var readTask = responseStream.MoveNext();
-            fakeCall.ReceivedMessageHandler(true, null);
-            fakeCall.ReceivedStatusOnClientHandler(true, CreateClientSideStatus(StatusCode.PermissionDenied));
+            fakeCall.ReceivedMessageCallback.OnReceivedMessage(true, null);
+            fakeCall.ReceivedStatusOnClientCallback.OnReceivedStatusOnClient(true, CreateClientSideStatus(StatusCode.PermissionDenied));
 
             var ex = Assert.ThrowsAsync<RpcException>(async () => await writeTask);
             Assert.AreEqual(StatusCode.PermissionDenied, ex.Status.StatusCode);
@@ -486,9 +486,9 @@
             var writeTask = requestStream.WriteAsync("request1");
 
             var readTask = responseStream.MoveNext();
-            fakeCall.ReceivedMessageHandler(true, null);
-            fakeCall.ReceivedStatusOnClientHandler(true, CreateClientSideStatus(StatusCode.PermissionDenied));
-            fakeCall.SendCompletionHandler(false);
+            fakeCall.ReceivedMessageCallback.OnReceivedMessage(true, null);
+            fakeCall.ReceivedStatusOnClientCallback.OnReceivedStatusOnClient(true, CreateClientSideStatus(StatusCode.PermissionDenied));
+            fakeCall.SendCompletionCallback.OnSendCompletion(false);
 
             var ex = Assert.ThrowsAsync<RpcException>(async () => await writeTask);
             Assert.AreEqual(StatusCode.PermissionDenied, ex.Status.StatusCode);
@@ -510,8 +510,8 @@
             Assert.ThrowsAsync(typeof(TaskCanceledException), async () => await writeTask);
 
             var readTask = responseStream.MoveNext();
-            fakeCall.ReceivedMessageHandler(true, null);
-            fakeCall.ReceivedStatusOnClientHandler(true, CreateClientSideStatus(StatusCode.Cancelled));
+            fakeCall.ReceivedMessageCallback.OnReceivedMessage(true, null);
+            fakeCall.ReceivedStatusOnClientCallback.OnReceivedStatusOnClient(true, CreateClientSideStatus(StatusCode.Cancelled));
 
             AssertStreamingResponseError(asyncCall, fakeCall, readTask, StatusCode.Cancelled);
         }
@@ -526,13 +526,13 @@
             Assert.IsTrue(fakeCall.IsCancelled);
 
             var readTask1 = responseStream.MoveNext();
-            fakeCall.ReceivedMessageHandler(true, CreateResponsePayload());
+            fakeCall.ReceivedMessageCallback.OnReceivedMessage(true, CreateResponsePayload());
             Assert.IsTrue(readTask1.Result);
             Assert.AreEqual("response1", responseStream.Current);
 
             var readTask2 = responseStream.MoveNext();
-            fakeCall.ReceivedMessageHandler(true, null);
-            fakeCall.ReceivedStatusOnClientHandler(true, CreateClientSideStatus(StatusCode.Cancelled));
+            fakeCall.ReceivedMessageCallback.OnReceivedMessage(true, null);
+            fakeCall.ReceivedStatusOnClientCallback.OnReceivedStatusOnClient(true, CreateClientSideStatus(StatusCode.Cancelled));
 
             AssertStreamingResponseError(asyncCall, fakeCall, readTask2, StatusCode.Cancelled);
         }
@@ -547,13 +547,13 @@
             asyncCall.Cancel();
             Assert.IsTrue(fakeCall.IsCancelled);
 
-            fakeCall.ReceivedMessageHandler(true, CreateResponsePayload());
+            fakeCall.ReceivedMessageCallback.OnReceivedMessage(true, CreateResponsePayload());
             Assert.IsTrue(readTask1.Result);
             Assert.AreEqual("response1", responseStream.Current);
 
             var readTask2 = responseStream.MoveNext();
-            fakeCall.ReceivedMessageHandler(true, null);
-            fakeCall.ReceivedStatusOnClientHandler(true, CreateClientSideStatus(StatusCode.Cancelled));
+            fakeCall.ReceivedMessageCallback.OnReceivedMessage(true, null);
+            fakeCall.ReceivedStatusOnClientCallback.OnReceivedStatusOnClient(true, CreateClientSideStatus(StatusCode.Cancelled));
 
             AssertStreamingResponseError(asyncCall, fakeCall, readTask2, StatusCode.Cancelled);
         }
diff --git a/src/csharp/Grpc.Core.Tests/Internal/CompletionQueueSafeHandleTest.cs b/src/csharp/Grpc.Core.Tests/Internal/CompletionQueueSafeHandleTest.cs
index 1d9475a..775c950 100644
--- a/src/csharp/Grpc.Core.Tests/Internal/CompletionQueueSafeHandleTest.cs
+++ b/src/csharp/Grpc.Core.Tests/Internal/CompletionQueueSafeHandleTest.cs
@@ -40,7 +40,7 @@
         public void CreateAsyncAndShutdown()
         {
             var env = GrpcEnvironment.AddRef();
-            var cq = CompletionQueueSafeHandle.CreateAsync(new CompletionRegistry(env));
+            var cq = CompletionQueueSafeHandle.CreateAsync(new CompletionRegistry(env, () => BatchContextSafeHandle.Create()));
             cq.Shutdown();
             var ev = cq.Next();
             cq.Dispose();
diff --git a/src/csharp/Grpc.Core.Tests/Internal/DefaultObjectPoolTest.cs b/src/csharp/Grpc.Core.Tests/Internal/DefaultObjectPoolTest.cs
new file mode 100644
index 0000000..b6bb0a9
--- /dev/null
+++ b/src/csharp/Grpc.Core.Tests/Internal/DefaultObjectPoolTest.cs
@@ -0,0 +1,79 @@
+#region Copyright notice and license
+
+// Copyright 2017 gRPC authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#endregion
+
+using System;
+using Grpc.Core;
+using Grpc.Core.Internal;
+using Grpc.Core.Utils;
+using NUnit.Framework;
+
+namespace Grpc.Core.Internal.Tests
+{
+    public class DefaultObjectPoolTest
+    {
+        [Test]
+        [TestCase(10, 2)]
+        [TestCase(10, 1)]
+        [TestCase(0, 2)]
+        [TestCase(2, 0)]
+        public void ObjectIsReused(int sharedCapacity, int threadLocalCapacity)
+        {
+            var pool = new DefaultObjectPool<TestPooledObject>(() => new TestPooledObject(), sharedCapacity, threadLocalCapacity);
+            var origLeased = pool.Lease();
+            pool.Return(origLeased);
+            Assert.AreSame(origLeased, pool.Lease());
+            Assert.AreNotSame(origLeased, pool.Lease());
+        }
+
+        [Test]
+        public void ZeroCapacities()
+        {
+            var pool = new DefaultObjectPool<TestPooledObject>(() => new TestPooledObject(), 0, 0);
+            var origLeased = pool.Lease();
+            pool.Return(origLeased);
+            Assert.AreNotSame(origLeased, pool.Lease());
+        }
+
+        [Test]
+        public void DisposeCleansSharedPool()
+        {
+            var pool = new DefaultObjectPool<TestPooledObject>(() => new TestPooledObject(), 10, 0);
+            var origLeased = pool.Lease();
+            pool.Return(origLeased);
+            pool.Dispose();
+            Assert.AreNotSame(origLeased, pool.Lease());
+        }
+
+        [Test]
+        public void Constructor()
+        {
+            Assert.Throws<ArgumentNullException>(() => new DefaultObjectPool<TestPooledObject>(null, 10, 2));
+            Assert.Throws<ArgumentException>(() => new DefaultObjectPool<TestPooledObject>(() => new TestPooledObject(), -1, 10));
+            Assert.Throws<ArgumentException>(() => new DefaultObjectPool<TestPooledObject>(() => new TestPooledObject(), 10, -1));
+        }
+
+        class TestPooledObject : IDisposable
+        {
+
+            public void Dispose()
+            {
+
+            }
+        }
+    }
+}
diff --git a/src/csharp/Grpc.Core.Tests/Internal/FakeNativeCall.cs b/src/csharp/Grpc.Core.Tests/Internal/FakeNativeCall.cs
index c3a2716..581ac33 100644
--- a/src/csharp/Grpc.Core.Tests/Internal/FakeNativeCall.cs
+++ b/src/csharp/Grpc.Core.Tests/Internal/FakeNativeCall.cs
@@ -31,43 +31,43 @@
     /// </summary>
     internal class FakeNativeCall : INativeCall
     {
-        public UnaryResponseClientHandler UnaryResponseClientHandler
+        public IUnaryResponseClientCallback UnaryResponseClientCallback
         {
             get;
             set;
         }
 
-        public ReceivedStatusOnClientHandler ReceivedStatusOnClientHandler
+        public IReceivedStatusOnClientCallback ReceivedStatusOnClientCallback
         {
             get;
             set;
         }
 
-        public ReceivedMessageHandler ReceivedMessageHandler
+        public IReceivedMessageCallback ReceivedMessageCallback
         {
             get;
             set;
         }
 
-        public ReceivedResponseHeadersHandler ReceivedResponseHeadersHandler
+        public IReceivedResponseHeadersCallback ReceivedResponseHeadersCallback
         {
             get;
             set;
         }
 
-        public SendCompletionHandler SendCompletionHandler
+        public ISendCompletionCallback SendCompletionCallback
         {
             get;
             set;
         }
 
-        public SendCompletionHandler SendStatusFromServerHandler
+        public ISendStatusFromServerCompletionCallback SendStatusFromServerCallback
         {
             get;
             set;
         }
 
-        public ReceivedCloseOnServerHandler ReceivedCloseOnServerHandler
+        public IReceivedCloseOnServerCallback ReceivedCloseOnServerCallback
         {
             get;
             set;
@@ -100,9 +100,9 @@
             return "PEER";
         }
 
-        public void StartUnary(UnaryResponseClientHandler callback, byte[] payload, WriteFlags writeFlags, MetadataArraySafeHandle metadataArray, CallFlags callFlags)
+        public void StartUnary(IUnaryResponseClientCallback callback, byte[] payload, WriteFlags writeFlags, MetadataArraySafeHandle metadataArray, CallFlags callFlags)
         {
-            UnaryResponseClientHandler = callback;
+            UnaryResponseClientCallback = callback;
         }
 
         public void StartUnary(BatchContextSafeHandle ctx, byte[] payload, WriteFlags writeFlags, MetadataArraySafeHandle metadataArray, CallFlags callFlags)
@@ -110,55 +110,55 @@
             throw new NotImplementedException();
         }
 
-        public void StartClientStreaming(UnaryResponseClientHandler callback, MetadataArraySafeHandle metadataArray, CallFlags callFlags)
+        public void StartClientStreaming(IUnaryResponseClientCallback callback, MetadataArraySafeHandle metadataArray, CallFlags callFlags)
         {
-            UnaryResponseClientHandler = callback;
+            UnaryResponseClientCallback = callback;
         }
 
-        public void StartServerStreaming(ReceivedStatusOnClientHandler callback, byte[] payload, WriteFlags writeFlags, MetadataArraySafeHandle metadataArray, CallFlags callFlags)
+        public void StartServerStreaming(IReceivedStatusOnClientCallback callback, byte[] payload, WriteFlags writeFlags, MetadataArraySafeHandle metadataArray, CallFlags callFlags)
         {
-            ReceivedStatusOnClientHandler = callback;
+            ReceivedStatusOnClientCallback = callback;
         }
 
-        public void StartDuplexStreaming(ReceivedStatusOnClientHandler callback, MetadataArraySafeHandle metadataArray, CallFlags callFlags)
+        public void StartDuplexStreaming(IReceivedStatusOnClientCallback callback, MetadataArraySafeHandle metadataArray, CallFlags callFlags)
         {
-            ReceivedStatusOnClientHandler = callback;
+            ReceivedStatusOnClientCallback = callback;
         }
 
-        public void StartReceiveMessage(ReceivedMessageHandler callback)
+        public void StartReceiveMessage(IReceivedMessageCallback callback)
         {
-            ReceivedMessageHandler = callback;
+            ReceivedMessageCallback = callback;
         }
 
-        public void StartReceiveInitialMetadata(ReceivedResponseHeadersHandler callback)
+        public void StartReceiveInitialMetadata(IReceivedResponseHeadersCallback callback)
         {
-            ReceivedResponseHeadersHandler = callback;
+            ReceivedResponseHeadersCallback = callback;
         }
 
-        public void StartSendInitialMetadata(SendCompletionHandler callback, MetadataArraySafeHandle metadataArray)
+        public void StartSendInitialMetadata(ISendCompletionCallback callback, MetadataArraySafeHandle metadataArray)
         {
-            SendCompletionHandler = callback;
+            SendCompletionCallback = callback;
         }
 
-        public void StartSendMessage(SendCompletionHandler callback, byte[] payload, WriteFlags writeFlags, bool sendEmptyInitialMetadata)
+        public void StartSendMessage(ISendCompletionCallback callback, byte[] payload, WriteFlags writeFlags, bool sendEmptyInitialMetadata)
         {
-            SendCompletionHandler = callback;
+            SendCompletionCallback = callback;
         }
 
-        public void StartSendCloseFromClient(SendCompletionHandler callback)
+        public void StartSendCloseFromClient(ISendCompletionCallback callback)
         {
-            SendCompletionHandler = callback;
+            SendCompletionCallback = callback;
         }
 
-        public void StartSendStatusFromServer(SendCompletionHandler callback, Status status, MetadataArraySafeHandle metadataArray, bool sendEmptyInitialMetadata,
+        public void StartSendStatusFromServer(ISendStatusFromServerCompletionCallback callback, Status status, MetadataArraySafeHandle metadataArray, bool sendEmptyInitialMetadata,
             byte[] optionalPayload, WriteFlags writeFlags)
         {
-            SendStatusFromServerHandler = callback;
+            SendStatusFromServerCallback = callback;
         }
 
-        public void StartServerSide(ReceivedCloseOnServerHandler callback)
+        public void StartServerSide(IReceivedCloseOnServerCallback callback)
         {
-            ReceivedCloseOnServerHandler = callback;
+            ReceivedCloseOnServerCallback = callback;
         }
 
         public void Dispose()
diff --git a/src/csharp/Grpc.Core.Tests/PInvokeTest.cs b/src/csharp/Grpc.Core.Tests/PInvokeTest.cs
index 7529c44..43f816b 100644
--- a/src/csharp/Grpc.Core.Tests/PInvokeTest.cs
+++ b/src/csharp/Grpc.Core.Tests/PInvokeTest.cs
@@ -63,7 +63,7 @@
         [Ignore("Prevent running on Jenkins")]
         public void NativeCallbackBenchmark()
         {
-            OpCompletionDelegate handler = Handler;
+            NativeCallbackTestDelegate handler = Handler;
 
             counter = 0;
             BenchmarkUtil.RunBenchmark(
@@ -91,7 +91,7 @@
                 10000, 10000,
                 () =>
                 {
-                    Native.grpcsharp_test_callback(new OpCompletionDelegate(Handler));
+                    Native.grpcsharp_test_callback(new NativeCallbackTestDelegate(Handler));
                 });
             Assert.AreNotEqual(0, counter);
         }
diff --git a/src/csharp/Grpc.Core/Channel.cs b/src/csharp/Grpc.Core/Channel.cs
index 1803920..f9925a8 100644
--- a/src/csharp/Grpc.Core/Channel.cs
+++ b/src/csharp/Grpc.Core/Channel.cs
@@ -127,6 +127,20 @@
             }
         }
 
+        // cached handler for watch connectivity state
+        static readonly BatchCompletionDelegate WatchConnectivityStateHandler = (success, ctx, state) =>
+        {
+            var tcs = (TaskCompletionSource<object>) state;
+            if (success)
+            {
+                tcs.SetResult(null);
+            }
+            else
+            {
+                tcs.SetCanceled();
+            }
+        };
+
         /// <summary>
         /// Returned tasks completes once channel state has become different from 
         /// given lastObservedState. 
@@ -138,18 +152,8 @@
                 "Shutdown is a terminal state. No further state changes can occur.");
             var tcs = new TaskCompletionSource<object>();
             var deadlineTimespec = deadline.HasValue ? Timespec.FromDateTime(deadline.Value) : Timespec.InfFuture;
-            var handler = new BatchCompletionDelegate((success, ctx) =>
-            {
-                if (success)
-                {
-                    tcs.SetResult(null);
-                }
-                else
-                {
-                    tcs.SetCanceled();
-                }
-            });
-            handle.WatchConnectivityState(lastObservedState, deadlineTimespec, completionQueue, handler);
+            // pass "tcs" as "state" for WatchConnectivityStateHandler.
+            handle.WatchConnectivityState(lastObservedState, deadlineTimespec, completionQueue, WatchConnectivityStateHandler, tcs);
             return tcs.Task;
         }
 
diff --git a/src/csharp/Grpc.Core/GrpcEnvironment.cs b/src/csharp/Grpc.Core/GrpcEnvironment.cs
index 80031cb..2b1b5e3 100644
--- a/src/csharp/Grpc.Core/GrpcEnvironment.cs
+++ b/src/csharp/Grpc.Core/GrpcEnvironment.cs
@@ -33,6 +33,8 @@
     public class GrpcEnvironment
     {
         const int MinDefaultThreadPoolSize = 4;
+        const int DefaultBatchContextPoolSharedCapacity = 10000;
+        const int DefaultBatchContextPoolThreadLocalCapacity = 64;
 
         static object staticLock = new object();
         static GrpcEnvironment instance;
@@ -40,11 +42,14 @@
         static int? customThreadPoolSize;
         static int? customCompletionQueueCount;
         static bool inlineHandlers;
+        static int batchContextPoolSharedCapacity = DefaultBatchContextPoolSharedCapacity;
+        static int batchContextPoolThreadLocalCapacity = DefaultBatchContextPoolThreadLocalCapacity;
         static readonly HashSet<Channel> registeredChannels = new HashSet<Channel>();
         static readonly HashSet<Server> registeredServers = new HashSet<Server>();
 
         static ILogger logger = new LogLevelFilterLogger(new ConsoleLogger(), LogLevel.Off, true);
 
+        readonly IObjectPool<BatchContextSafeHandle> batchContextPool;
         readonly GrpcThreadPool threadPool;
         readonly DebugStats debugStats = new DebugStats();
         readonly AtomicCounter cqPickerCounter = new AtomicCounter();
@@ -186,7 +191,7 @@
 
         /// <summary>
         /// Sets the number of threads in the gRPC thread pool that polls for internal RPC events.
-        /// Can be only invoke before the <c>GrpcEnviroment</c> is started and cannot be changed afterwards.
+        /// Can be only invoked before the <c>GrpcEnviroment</c> is started and cannot be changed afterwards.
         /// Setting thread pool size is an advanced setting and you should only use it if you know what you are doing.
         /// Most users should rely on the default value provided by gRPC library.
         /// Note: this method is part of an experimental API that can change or be removed without any prior notice.
@@ -203,7 +208,7 @@
 
         /// <summary>
         /// Sets the number of completion queues in the  gRPC thread pool that polls for internal RPC events.
-        /// Can be only invoke before the <c>GrpcEnviroment</c> is started and cannot be changed afterwards.
+        /// Can be only invoked before the <c>GrpcEnviroment</c> is started and cannot be changed afterwards.
         /// Setting the number of completions queues is an advanced setting and you should only use it if you know what you are doing.
         /// Most users should rely on the default value provided by gRPC library.
         /// Note: this method is part of an experimental API that can change or be removed without any prior notice.
@@ -238,6 +243,26 @@
         }
 
         /// <summary>
+        /// Sets the parameters for a pool that caches batch context instances. Reusing batch context instances
+        /// instead of creating a new one for every C core operation helps reducing the GC pressure.
+        /// Can be only invoked before the <c>GrpcEnviroment</c> is started and cannot be changed afterwards.
+        /// This is an advanced setting and you should only use it if you know what you are doing.
+        /// Most users should rely on the default value provided by gRPC library.
+        /// Note: this method is part of an experimental API that can change or be removed without any prior notice.
+        /// </summary>
+        public static void SetBatchContextPoolParams(int sharedCapacity, int threadLocalCapacity)
+        {
+            lock (staticLock)
+            {
+                GrpcPreconditions.CheckState(instance == null, "Can only be set before GrpcEnvironment is initialized");
+                GrpcPreconditions.CheckArgument(sharedCapacity >= 0, "Shared capacity needs to be a non-negative number");
+                GrpcPreconditions.CheckArgument(threadLocalCapacity >= 0, "Thread local capacity needs to be a non-negative number");
+                batchContextPoolSharedCapacity = sharedCapacity;
+                batchContextPoolThreadLocalCapacity = threadLocalCapacity;
+            }
+        }
+
+        /// <summary>
         /// Occurs when <c>GrpcEnvironment</c> is about the start the shutdown logic.
         /// If <c>GrpcEnvironment</c> is later initialized and shutdown, the event will be fired again (unless unregistered first).
         /// </summary>
@@ -249,6 +274,7 @@
         private GrpcEnvironment()
         {
             GrpcNativeInit();
+            batchContextPool = new DefaultObjectPool<BatchContextSafeHandle>(() => BatchContextSafeHandle.Create(this.batchContextPool), batchContextPoolSharedCapacity, batchContextPoolThreadLocalCapacity);
             threadPool = new GrpcThreadPool(this, GetThreadPoolSizeOrDefault(), GetCompletionQueueCountOrDefault(), inlineHandlers);
             threadPool.Start();
         }
@@ -264,6 +290,8 @@
             }
         }
 
+        internal IObjectPool<BatchContextSafeHandle> BatchContextPool => batchContextPool;
+
         internal bool IsAlive
         {
             get
@@ -325,6 +353,7 @@
             await Task.Run(() => ShuttingDown?.Invoke(this, null)).ConfigureAwait(false);
 
             await threadPool.StopAsync().ConfigureAwait(false);
+            batchContextPool.Dispose();
             GrpcNativeShutdown();
             isShutdown = true;
 
diff --git a/src/csharp/Grpc.Core/IAsyncStreamReader.cs b/src/csharp/Grpc.Core/IAsyncStreamReader.cs
index 42bfbb8..3751d54 100644
--- a/src/csharp/Grpc.Core/IAsyncStreamReader.cs
+++ b/src/csharp/Grpc.Core/IAsyncStreamReader.cs
@@ -41,6 +41,13 @@
     /// (<c>MoveNext</c> will return <c>false</c>) and the <c>CancellationToken</c>
     /// associated with the call will be cancelled to signal the failure.
     /// </para>
+    /// <para>
+    /// <c>MoveNext()</c> operations can be cancelled via a cancellation token. Cancelling
+    /// an individual read operation has the same effect as cancelling the entire call
+    /// (which will also result in the read operation returning prematurely), but the per-read cancellation
+    /// tokens passed to MoveNext() only result in cancelling the call if the read operation haven't finished
+    /// yet.
+    /// </para>
     /// </summary>
     /// <typeparam name="T">The message type.</typeparam>
     public interface IAsyncStreamReader<T> : IAsyncEnumerator<T>
diff --git a/src/csharp/Grpc.Core/Internal/AsyncCall.cs b/src/csharp/Grpc.Core/Internal/AsyncCall.cs
index 09fb722..9946d1a 100644
--- a/src/csharp/Grpc.Core/Internal/AsyncCall.cs
+++ b/src/csharp/Grpc.Core/Internal/AsyncCall.cs
@@ -27,7 +27,7 @@
     /// <summary>
     /// Manages client side native call lifecycle.
     /// </summary>
-    internal class AsyncCall<TRequest, TResponse> : AsyncCallBase<TRequest, TResponse>
+    internal class AsyncCall<TRequest, TResponse> : AsyncCallBase<TRequest, TResponse>, IUnaryResponseClientCallback, IReceivedStatusOnClientCallback, IReceivedResponseHeadersCallback
     {
         static readonly ILogger Logger = GrpcEnvironment.Logger.ForType<AsyncCall<TRequest, TResponse>>();
 
@@ -92,23 +92,28 @@
                 }
 
                 using (var metadataArray = MetadataArraySafeHandle.Create(details.Options.Headers))
-                using (var ctx = BatchContextSafeHandle.Create())
                 {
-                    call.StartUnary(ctx, payload, GetWriteFlagsForCall(), metadataArray, details.Options.Flags);
-
-                    var ev = cq.Pluck(ctx.Handle);
-
-                    bool success = (ev.success != 0);
+                    var ctx = details.Channel.Environment.BatchContextPool.Lease();
                     try
                     {
-                        using (profiler.NewScope("AsyncCall.UnaryCall.HandleBatch"))
+                        call.StartUnary(ctx, payload, GetWriteFlagsForCall(), metadataArray, details.Options.Flags);
+                        var ev = cq.Pluck(ctx.Handle);
+                        bool success = (ev.success != 0);
+                        try
                         {
-                            HandleUnaryResponse(success, ctx.GetReceivedStatusOnClient(), ctx.GetReceivedMessage(), ctx.GetReceivedInitialMetadata());
+                            using (profiler.NewScope("AsyncCall.UnaryCall.HandleBatch"))
+                            {
+                                HandleUnaryResponse(success, ctx.GetReceivedStatusOnClient(), ctx.GetReceivedMessage(), ctx.GetReceivedInitialMetadata());
+                            }
+                        }
+                        catch (Exception e)
+                        {
+                            Logger.Error(e, "Exception occured while invoking completion delegate.");
                         }
                     }
-                    catch (Exception e)
+                    finally
                     {
-                        Logger.Error(e, "Exception occured while invoking completion delegate.");
+                        ctx.Recycle();
                     }
                 }
                     
@@ -138,7 +143,7 @@
                 unaryResponseTcs = new TaskCompletionSource<TResponse>();
                 using (var metadataArray = MetadataArraySafeHandle.Create(details.Options.Headers))
                 {
-                    call.StartUnary(HandleUnaryResponse, payload, GetWriteFlagsForCall(), metadataArray, details.Options.Flags);
+                    call.StartUnary(UnaryResponseClientCallback, payload, GetWriteFlagsForCall(), metadataArray, details.Options.Flags);
                 }
                 return unaryResponseTcs.Task;
             }
@@ -162,7 +167,7 @@
                 unaryResponseTcs = new TaskCompletionSource<TResponse>();
                 using (var metadataArray = MetadataArraySafeHandle.Create(details.Options.Headers))
                 {
-                    call.StartClientStreaming(HandleUnaryResponse, metadataArray, details.Options.Flags);
+                    call.StartClientStreaming(UnaryResponseClientCallback, metadataArray, details.Options.Flags);
                 }
 
                 return unaryResponseTcs.Task;
@@ -188,9 +193,9 @@
                 streamingResponseCallFinishedTcs = new TaskCompletionSource<object>();
                 using (var metadataArray = MetadataArraySafeHandle.Create(details.Options.Headers))
                 {
-                    call.StartServerStreaming(HandleFinished, payload, GetWriteFlagsForCall(), metadataArray, details.Options.Flags);
+                    call.StartServerStreaming(ReceivedStatusOnClientCallback, payload, GetWriteFlagsForCall(), metadataArray, details.Options.Flags);
                 }
-                call.StartReceiveInitialMetadata(HandleReceivedResponseHeaders);
+                call.StartReceiveInitialMetadata(ReceivedResponseHeadersCallback);
             }
         }
 
@@ -210,9 +215,9 @@
                 streamingResponseCallFinishedTcs = new TaskCompletionSource<object>();
                 using (var metadataArray = MetadataArraySafeHandle.Create(details.Options.Headers))
                 {
-                    call.StartDuplexStreaming(HandleFinished, metadataArray, details.Options.Flags);
+                    call.StartDuplexStreaming(ReceivedStatusOnClientCallback, metadataArray, details.Options.Flags);
                 }
-                call.StartReceiveInitialMetadata(HandleReceivedResponseHeaders);
+                call.StartReceiveInitialMetadata(ReceivedResponseHeadersCallback);
             }
         }
 
@@ -256,7 +261,7 @@
                     halfcloseRequested = true;
                     return TaskUtils.CompletedTask;
                 }
-                call.StartSendCloseFromClient(HandleSendFinished);
+                call.StartSendCloseFromClient(SendCompletionCallback);
 
                 halfcloseRequested = true;
                 streamingWriteTcs = new TaskCompletionSource<object>();
@@ -516,5 +521,26 @@
 
             streamingResponseCallFinishedTcs.SetResult(null);
         }
+
+        IUnaryResponseClientCallback UnaryResponseClientCallback => this;
+
+        void IUnaryResponseClientCallback.OnUnaryResponseClient(bool success, ClientSideStatus receivedStatus, byte[] receivedMessage, Metadata responseHeaders)
+        {
+            HandleUnaryResponse(success, receivedStatus, receivedMessage, responseHeaders);
+        }
+
+        IReceivedStatusOnClientCallback ReceivedStatusOnClientCallback => this;
+
+        void IReceivedStatusOnClientCallback.OnReceivedStatusOnClient(bool success, ClientSideStatus receivedStatus)
+        {
+            HandleFinished(success, receivedStatus);
+        }
+
+        IReceivedResponseHeadersCallback ReceivedResponseHeadersCallback => this;
+
+        void IReceivedResponseHeadersCallback.OnReceivedResponseHeaders(bool success, Metadata responseHeaders)
+        {
+            HandleReceivedResponseHeaders(success, responseHeaders);
+        }
     }
 }
diff --git a/src/csharp/Grpc.Core/Internal/AsyncCallBase.cs b/src/csharp/Grpc.Core/Internal/AsyncCallBase.cs
index f379c85..3273c26 100644
--- a/src/csharp/Grpc.Core/Internal/AsyncCallBase.cs
+++ b/src/csharp/Grpc.Core/Internal/AsyncCallBase.cs
@@ -35,7 +35,7 @@
     /// Base for handling both client side and server side calls.
     /// Manages native call lifecycle and provides convenience methods.
     /// </summary>
-    internal abstract class AsyncCallBase<TWrite, TRead>
+    internal abstract class AsyncCallBase<TWrite, TRead> : IReceivedMessageCallback, ISendCompletionCallback
     {
         static readonly ILogger Logger = GrpcEnvironment.Logger.ForType<AsyncCallBase<TWrite, TRead>>();
         protected static readonly Status DeserializeResponseFailureStatus = new Status(StatusCode.Internal, "Failed to deserialize response message.");
@@ -126,7 +126,7 @@
                     return earlyResult;
                 }
 
-                call.StartSendMessage(HandleSendFinished, payload, writeFlags, !initialMetadataSent);
+                call.StartSendMessage(SendCompletionCallback, payload, writeFlags, !initialMetadataSent);
 
                 initialMetadataSent = true;
                 streamingWritesCounter++;
@@ -154,7 +154,7 @@
                 GrpcPreconditions.CheckState(streamingReadTcs == null, "Only one read can be pending at a time");
                 GrpcPreconditions.CheckState(!disposed);
 
-                call.StartReceiveMessage(HandleReadFinished);
+                call.StartReceiveMessage(ReceivedMessageCallback);
                 streamingReadTcs = new TaskCompletionSource<TRead>();
                 return streamingReadTcs.Task;
             }
@@ -342,5 +342,19 @@
             }
             origTcs.SetResult(msg);
         }
+
+        protected ISendCompletionCallback SendCompletionCallback => this;
+
+        void ISendCompletionCallback.OnSendCompletion(bool success)
+        {
+            HandleSendFinished(success);
+        }
+
+        IReceivedMessageCallback ReceivedMessageCallback => this;
+
+        void IReceivedMessageCallback.OnReceivedMessage(bool success, byte[] receivedMessage)
+        {
+            HandleReadFinished(success, receivedMessage);
+        }
     }
 }
diff --git a/src/csharp/Grpc.Core/Internal/AsyncCallServer.cs b/src/csharp/Grpc.Core/Internal/AsyncCallServer.cs
index 271a6ff..11acb27 100644
--- a/src/csharp/Grpc.Core/Internal/AsyncCallServer.cs
+++ b/src/csharp/Grpc.Core/Internal/AsyncCallServer.cs
@@ -31,7 +31,7 @@
     /// <summary>
     /// Manages server side native call lifecycle.
     /// </summary>
-    internal class AsyncCallServer<TRequest, TResponse> : AsyncCallBase<TResponse, TRequest>
+    internal class AsyncCallServer<TRequest, TResponse> : AsyncCallBase<TResponse, TRequest>, IReceivedCloseOnServerCallback, ISendStatusFromServerCompletionCallback
     {
         readonly TaskCompletionSource<object> finishedServersideTcs = new TaskCompletionSource<object>();
         readonly CancellationTokenSource cancellationTokenSource = new CancellationTokenSource();
@@ -70,7 +70,7 @@
 
                 started = true;
 
-                call.StartServerSide(HandleFinishedServerside);
+                call.StartServerSide(ReceiveCloseOnServerCallback);
                 return finishedServersideTcs.Task;
             }
         }
@@ -114,7 +114,7 @@
 
                 using (var metadataArray = MetadataArraySafeHandle.Create(headers))
                 {
-                    call.StartSendInitialMetadata(HandleSendFinished, metadataArray);
+                    call.StartSendInitialMetadata(SendCompletionCallback, metadataArray);
                 }
 
                 this.initialMetadataSent = true;
@@ -127,10 +127,10 @@
         /// Sends call result status, indicating we are done with writes.
         /// Sending a status different from StatusCode.OK will also implicitly cancel the call.
         /// </summary>
-        public Task SendStatusFromServerAsync(Status status, Metadata trailers, Tuple<TResponse, WriteFlags> optionalWrite)
+        public Task SendStatusFromServerAsync(Status status, Metadata trailers, ResponseWithFlags? optionalWrite)
         {
-            byte[] payload = optionalWrite != null ? UnsafeSerialize(optionalWrite.Item1) : null;
-            var writeFlags = optionalWrite != null ? optionalWrite.Item2 : default(WriteFlags);
+            byte[] payload = optionalWrite.HasValue ? UnsafeSerialize(optionalWrite.Value.Response) : null;
+            var writeFlags = optionalWrite.HasValue ? optionalWrite.Value.WriteFlags : default(WriteFlags);
 
             lock (myLock)
             {
@@ -140,13 +140,13 @@
 
                 using (var metadataArray = MetadataArraySafeHandle.Create(trailers))
                 {
-                    call.StartSendStatusFromServer(HandleSendStatusFromServerFinished, status, metadataArray, !initialMetadataSent,
+                    call.StartSendStatusFromServer(SendStatusFromServerCompletionCallback, status, metadataArray, !initialMetadataSent,
                         payload, writeFlags);
                 }
                 halfcloseRequested = true;
                 initialMetadataSent = true;
                 sendStatusFromServerTcs = new TaskCompletionSource<object>();
-                if (optionalWrite != null)
+                if (optionalWrite.HasValue)
                 {
                     streamingWritesCounter++;
                 }
@@ -227,5 +227,31 @@
 
             finishedServersideTcs.SetResult(null);
         }
+
+        IReceivedCloseOnServerCallback ReceiveCloseOnServerCallback => this;
+
+        void IReceivedCloseOnServerCallback.OnReceivedCloseOnServer(bool success, bool cancelled)
+        {
+            HandleFinishedServerside(success, cancelled);
+        }
+
+        ISendStatusFromServerCompletionCallback SendStatusFromServerCompletionCallback => this;
+
+        void ISendStatusFromServerCompletionCallback.OnSendStatusFromServerCompletion(bool success)
+        {
+            HandleSendStatusFromServerFinished(success);
+        }
+
+        public struct ResponseWithFlags
+        {
+            public ResponseWithFlags(TResponse response, WriteFlags writeFlags)
+            {
+                this.Response = response;
+                this.WriteFlags = writeFlags;
+            }
+
+            public TResponse Response { get; }
+            public WriteFlags WriteFlags { get; }
+        }
     }
 }
diff --git a/src/csharp/Grpc.Core/Internal/BatchContextSafeHandle.cs b/src/csharp/Grpc.Core/Internal/BatchContextSafeHandle.cs
index cd5e3d8..83385ad 100644
--- a/src/csharp/Grpc.Core/Internal/BatchContextSafeHandle.cs
+++ b/src/csharp/Grpc.Core/Internal/BatchContextSafeHandle.cs
@@ -20,23 +20,36 @@
 using System.Runtime.InteropServices;
 using System.Text;
 using Grpc.Core;
+using Grpc.Core.Logging;
+using Grpc.Core.Utils;
 
 namespace Grpc.Core.Internal
 {
+    internal interface IOpCompletionCallback
+    {
+        void OnComplete(bool success);
+    }
+
     /// <summary>
     /// grpcsharp_batch_context
     /// </summary>
-    internal class BatchContextSafeHandle : SafeHandleZeroIsInvalid
+    internal class BatchContextSafeHandle : SafeHandleZeroIsInvalid, IOpCompletionCallback
     {
         static readonly NativeMethods Native = NativeMethods.Get();
+        static readonly ILogger Logger = GrpcEnvironment.Logger.ForType<BatchContextSafeHandle>();
+
+        IObjectPool<BatchContextSafeHandle> ownedByPool;
+        CompletionCallbackData completionCallbackData;
 
         private BatchContextSafeHandle()
         {
         }
 
-        public static BatchContextSafeHandle Create()
+        public static BatchContextSafeHandle Create(IObjectPool<BatchContextSafeHandle> ownedByPool = null)
         {
-            return Native.grpcsharp_batch_context_create();
+            var ctx = Native.grpcsharp_batch_context_create();
+            ctx.ownedByPool = ownedByPool;
+            return ctx;
         }
 
         public IntPtr Handle
@@ -47,19 +60,26 @@
             }
         }
 
+        public void SetCompletionCallback(BatchCompletionDelegate callback, object state)
+        {
+            GrpcPreconditions.CheckState(completionCallbackData.Callback == null);
+            GrpcPreconditions.CheckNotNull(callback, nameof(callback));
+            completionCallbackData = new CompletionCallbackData(callback, state);
+        }
+
         // Gets data of recv_initial_metadata completion.
         public Metadata GetReceivedInitialMetadata()
         {
             IntPtr metadataArrayPtr = Native.grpcsharp_batch_context_recv_initial_metadata(this);
             return MetadataArraySafeHandle.ReadMetadataFromPtrUnsafe(metadataArrayPtr);
         }
-            
+
         // Gets data of recv_status_on_client completion.
         public ClientSideStatus GetReceivedStatusOnClient()
         {
             UIntPtr detailsLength;
             IntPtr detailsPtr = Native.grpcsharp_batch_context_recv_status_on_client_details(this, out detailsLength);
-            string details = MarshalUtils.PtrToStringUTF8(detailsPtr, (int) detailsLength.ToUInt32());
+            string details = MarshalUtils.PtrToStringUTF8(detailsPtr, (int)detailsLength.ToUInt32());
             var status = new Status(Native.grpcsharp_batch_context_recv_status_on_client_status(this), details);
 
             IntPtr metadataArrayPtr = Native.grpcsharp_batch_context_recv_status_on_client_trailing_metadata(this);
@@ -86,11 +106,53 @@
         {
             return Native.grpcsharp_batch_context_recv_close_on_server_cancelled(this) != 0;
         }
-            
+
+        public void Recycle()
+        {
+            if (ownedByPool != null)
+            {
+                Native.grpcsharp_batch_context_reset(this);
+                ownedByPool.Return(this);
+            }
+            else
+            {
+                Dispose();
+            }
+        }
+
         protected override bool ReleaseHandle()
         {
             Native.grpcsharp_batch_context_destroy(handle);
             return true;
         }
+
+        void IOpCompletionCallback.OnComplete(bool success)
+        {
+            try
+            {
+                completionCallbackData.Callback(success, this, completionCallbackData.State);
+            }
+            catch (Exception e)
+            {
+                Logger.Error(e, "Exception occured while invoking batch completion delegate.");
+            }
+            finally
+            {
+                completionCallbackData = default(CompletionCallbackData);
+                Recycle();
+            }
+        }
+
+        struct CompletionCallbackData
+        {
+            public CompletionCallbackData(BatchCompletionDelegate callback, object state)
+            {
+                this.Callback = callback;
+                this.State = state;
+            }
+
+            public BatchCompletionDelegate Callback { get; }
+            public object State { get; }
+        }
     }
 }
diff --git a/src/csharp/Grpc.Core/Internal/CallSafeHandle.cs b/src/csharp/Grpc.Core/Internal/CallSafeHandle.cs
index 3a7f977..a3ef3e6 100644
--- a/src/csharp/Grpc.Core/Internal/CallSafeHandle.cs
+++ b/src/csharp/Grpc.Core/Internal/CallSafeHandle.cs
@@ -32,6 +32,23 @@
         public static readonly CallSafeHandle NullInstance = new CallSafeHandle();
         static readonly NativeMethods Native = NativeMethods.Get();
 
+        // Completion handlers are pre-allocated to avoid unneccessary delegate allocations.
+        // The "state" field is used to store the actual callback to invoke.
+        static readonly BatchCompletionDelegate CompletionHandler_IUnaryResponseClientCallback =
+            (success, context, state) => ((IUnaryResponseClientCallback)state).OnUnaryResponseClient(success, context.GetReceivedStatusOnClient(), context.GetReceivedMessage(), context.GetReceivedInitialMetadata());
+        static readonly BatchCompletionDelegate CompletionHandler_IReceivedStatusOnClientCallback =
+            (success, context, state) => ((IReceivedStatusOnClientCallback)state).OnReceivedStatusOnClient(success, context.GetReceivedStatusOnClient());
+        static readonly BatchCompletionDelegate CompletionHandler_IReceivedMessageCallback =
+            (success, context, state) => ((IReceivedMessageCallback)state).OnReceivedMessage(success, context.GetReceivedMessage());
+        static readonly BatchCompletionDelegate CompletionHandler_IReceivedResponseHeadersCallback =
+            (success, context, state) => ((IReceivedResponseHeadersCallback)state).OnReceivedResponseHeaders(success, context.GetReceivedInitialMetadata());
+        static readonly BatchCompletionDelegate CompletionHandler_ISendCompletionCallback =
+            (success, context, state) => ((ISendCompletionCallback)state).OnSendCompletion(success);
+        static readonly BatchCompletionDelegate CompletionHandler_ISendStatusFromServerCompletionCallback =
+            (success, context, state) => ((ISendStatusFromServerCompletionCallback)state).OnSendStatusFromServerCompletion(success);
+        static readonly BatchCompletionDelegate CompletionHandler_IReceivedCloseOnServerCallback =
+            (success, context, state) => ((IReceivedCloseOnServerCallback)state).OnReceivedCloseOnServer(success, context.GetReceivedCloseOnServerCancelled());
+
         const uint GRPC_WRITE_BUFFER_HINT = 1;
         CompletionQueueSafeHandle completionQueue;
 
@@ -49,12 +66,11 @@
             Native.grpcsharp_call_set_credentials(this, credentials).CheckOk();
         }
 
-        public void StartUnary(UnaryResponseClientHandler callback, byte[] payload, WriteFlags writeFlags, MetadataArraySafeHandle metadataArray, CallFlags callFlags)
+        public void StartUnary(IUnaryResponseClientCallback callback, byte[] payload, WriteFlags writeFlags, MetadataArraySafeHandle metadataArray, CallFlags callFlags)
         {
             using (completionQueue.NewScope())
             {
-                var ctx = BatchContextSafeHandle.Create();
-                completionQueue.CompletionRegistry.RegisterBatchCompletion(ctx, (success, context) => callback(success, context.GetReceivedStatusOnClient(), context.GetReceivedMessage(), context.GetReceivedInitialMetadata()));
+                var ctx = completionQueue.CompletionRegistry.RegisterBatchCompletion(CompletionHandler_IUnaryResponseClientCallback, callback);
                 Native.grpcsharp_call_start_unary(this, ctx, payload, new UIntPtr((ulong)payload.Length), writeFlags, metadataArray, callFlags)
                     .CheckOk();
             }
@@ -66,106 +82,96 @@
                 .CheckOk();
         }
 
-        public void StartClientStreaming(UnaryResponseClientHandler callback, MetadataArraySafeHandle metadataArray, CallFlags callFlags)
+        public void StartClientStreaming(IUnaryResponseClientCallback callback, MetadataArraySafeHandle metadataArray, CallFlags callFlags)
         {
             using (completionQueue.NewScope())
             {
-                var ctx = BatchContextSafeHandle.Create();
-                completionQueue.CompletionRegistry.RegisterBatchCompletion(ctx, (success, context) => callback(success, context.GetReceivedStatusOnClient(), context.GetReceivedMessage(), context.GetReceivedInitialMetadata()));
+                var ctx = completionQueue.CompletionRegistry.RegisterBatchCompletion(CompletionHandler_IUnaryResponseClientCallback, callback);
                 Native.grpcsharp_call_start_client_streaming(this, ctx, metadataArray, callFlags).CheckOk();
             }
         }
 
-        public void StartServerStreaming(ReceivedStatusOnClientHandler callback, byte[] payload, WriteFlags writeFlags, MetadataArraySafeHandle metadataArray, CallFlags callFlags)
+        public void StartServerStreaming(IReceivedStatusOnClientCallback callback, byte[] payload, WriteFlags writeFlags, MetadataArraySafeHandle metadataArray, CallFlags callFlags)
         {
             using (completionQueue.NewScope())
             {
-                var ctx = BatchContextSafeHandle.Create();
-                completionQueue.CompletionRegistry.RegisterBatchCompletion(ctx, (success, context) => callback(success, context.GetReceivedStatusOnClient()));
+                var ctx = completionQueue.CompletionRegistry.RegisterBatchCompletion(CompletionHandler_IReceivedStatusOnClientCallback, callback);
                 Native.grpcsharp_call_start_server_streaming(this, ctx, payload, new UIntPtr((ulong)payload.Length), writeFlags, metadataArray, callFlags).CheckOk();
             }
         }
 
-        public void StartDuplexStreaming(ReceivedStatusOnClientHandler callback, MetadataArraySafeHandle metadataArray, CallFlags callFlags)
+        public void StartDuplexStreaming(IReceivedStatusOnClientCallback callback, MetadataArraySafeHandle metadataArray, CallFlags callFlags)
         {
             using (completionQueue.NewScope())
             {
-                var ctx = BatchContextSafeHandle.Create();
-                completionQueue.CompletionRegistry.RegisterBatchCompletion(ctx, (success, context) => callback(success, context.GetReceivedStatusOnClient()));
+                var ctx = completionQueue.CompletionRegistry.RegisterBatchCompletion(CompletionHandler_IReceivedStatusOnClientCallback, callback);
                 Native.grpcsharp_call_start_duplex_streaming(this, ctx, metadataArray, callFlags).CheckOk();
             }
         }
 
-        public void StartSendMessage(SendCompletionHandler callback, byte[] payload, WriteFlags writeFlags, bool sendEmptyInitialMetadata)
+        public void StartSendMessage(ISendCompletionCallback callback, byte[] payload, WriteFlags writeFlags, bool sendEmptyInitialMetadata)
         {
             using (completionQueue.NewScope())
             {
-                var ctx = BatchContextSafeHandle.Create();
-                completionQueue.CompletionRegistry.RegisterBatchCompletion(ctx, (success, context) => callback(success));
+                var ctx = completionQueue.CompletionRegistry.RegisterBatchCompletion(CompletionHandler_ISendCompletionCallback, callback);
                 Native.grpcsharp_call_send_message(this, ctx, payload, new UIntPtr((ulong)payload.Length), writeFlags, sendEmptyInitialMetadata ? 1 : 0).CheckOk();
             }
         }
 
-        public void StartSendCloseFromClient(SendCompletionHandler callback)
+        public void StartSendCloseFromClient(ISendCompletionCallback callback)
         {
             using (completionQueue.NewScope())
             {
-                var ctx = BatchContextSafeHandle.Create();
-                completionQueue.CompletionRegistry.RegisterBatchCompletion(ctx, (success, context) => callback(success));
+                var ctx = completionQueue.CompletionRegistry.RegisterBatchCompletion(CompletionHandler_ISendCompletionCallback, callback);
                 Native.grpcsharp_call_send_close_from_client(this, ctx).CheckOk();
             }
         }
 
-        public void StartSendStatusFromServer(SendCompletionHandler callback, Status status, MetadataArraySafeHandle metadataArray, bool sendEmptyInitialMetadata,
+        public void StartSendStatusFromServer(ISendStatusFromServerCompletionCallback callback, Status status, MetadataArraySafeHandle metadataArray, bool sendEmptyInitialMetadata,
             byte[] optionalPayload, WriteFlags writeFlags)
         {
             using (completionQueue.NewScope())
             {
-                var ctx = BatchContextSafeHandle.Create();
+                var ctx = completionQueue.CompletionRegistry.RegisterBatchCompletion(CompletionHandler_ISendStatusFromServerCompletionCallback, callback);
                 var optionalPayloadLength = optionalPayload != null ? new UIntPtr((ulong)optionalPayload.Length) : UIntPtr.Zero;
-                completionQueue.CompletionRegistry.RegisterBatchCompletion(ctx, (success, context) => callback(success));
                 var statusDetailBytes = MarshalUtils.GetBytesUTF8(status.Detail);
                 Native.grpcsharp_call_send_status_from_server(this, ctx, status.StatusCode, statusDetailBytes, new UIntPtr((ulong)statusDetailBytes.Length), metadataArray, sendEmptyInitialMetadata ? 1 : 0,
                     optionalPayload, optionalPayloadLength, writeFlags).CheckOk();
             }
         }
 
-        public void StartReceiveMessage(ReceivedMessageHandler callback)
+        public void StartReceiveMessage(IReceivedMessageCallback callback)
         {
             using (completionQueue.NewScope())
             {
-                var ctx = BatchContextSafeHandle.Create();
-                completionQueue.CompletionRegistry.RegisterBatchCompletion(ctx, (success, context) => callback(success, context.GetReceivedMessage()));
+                var ctx = completionQueue.CompletionRegistry.RegisterBatchCompletion(CompletionHandler_IReceivedMessageCallback, callback);
                 Native.grpcsharp_call_recv_message(this, ctx).CheckOk();
             }
         }
 
-        public void StartReceiveInitialMetadata(ReceivedResponseHeadersHandler callback)
+        public void StartReceiveInitialMetadata(IReceivedResponseHeadersCallback callback)
         {
             using (completionQueue.NewScope())
             {
-                var ctx = BatchContextSafeHandle.Create();
-                completionQueue.CompletionRegistry.RegisterBatchCompletion(ctx, (success, context) => callback(success, context.GetReceivedInitialMetadata()));
+                var ctx = completionQueue.CompletionRegistry.RegisterBatchCompletion(CompletionHandler_IReceivedResponseHeadersCallback, callback);
                 Native.grpcsharp_call_recv_initial_metadata(this, ctx).CheckOk();
             }
         }
 
-        public void StartServerSide(ReceivedCloseOnServerHandler callback)
+        public void StartServerSide(IReceivedCloseOnServerCallback callback)
         {
             using (completionQueue.NewScope())
             {
-                var ctx = BatchContextSafeHandle.Create();
-                completionQueue.CompletionRegistry.RegisterBatchCompletion(ctx, (success, context) => callback(success, context.GetReceivedCloseOnServerCancelled()));
+                var ctx = completionQueue.CompletionRegistry.RegisterBatchCompletion(CompletionHandler_IReceivedCloseOnServerCallback, callback);
                 Native.grpcsharp_call_start_serverside(this, ctx).CheckOk();
             }
         }
 
-        public void StartSendInitialMetadata(SendCompletionHandler callback, MetadataArraySafeHandle metadataArray)
+        public void StartSendInitialMetadata(ISendCompletionCallback callback, MetadataArraySafeHandle metadataArray)
         {
             using (completionQueue.NewScope())
             {
-                var ctx = BatchContextSafeHandle.Create();
-                completionQueue.CompletionRegistry.RegisterBatchCompletion(ctx, (success, context) => callback(success));
+                var ctx = completionQueue.CompletionRegistry.RegisterBatchCompletion(CompletionHandler_ISendCompletionCallback, callback);
                 Native.grpcsharp_call_send_initial_metadata(this, ctx, metadataArray).CheckOk();
             }
         }
diff --git a/src/csharp/Grpc.Core/Internal/ChannelSafeHandle.cs b/src/csharp/Grpc.Core/Internal/ChannelSafeHandle.cs
index f826a17..cd5f8ed 100644
--- a/src/csharp/Grpc.Core/Internal/ChannelSafeHandle.cs
+++ b/src/csharp/Grpc.Core/Internal/ChannelSafeHandle.cs
@@ -64,10 +64,9 @@
             return Native.grpcsharp_channel_check_connectivity_state(this, tryToConnect ? 1 : 0);
         }
 
-        public void WatchConnectivityState(ChannelState lastObservedState, Timespec deadline, CompletionQueueSafeHandle cq, BatchCompletionDelegate callback)
+        public void WatchConnectivityState(ChannelState lastObservedState, Timespec deadline, CompletionQueueSafeHandle cq, BatchCompletionDelegate callback, object callbackState)
         {
-            var ctx = BatchContextSafeHandle.Create();
-            cq.CompletionRegistry.RegisterBatchCompletion(ctx, callback);
+            var ctx = cq.CompletionRegistry.RegisterBatchCompletion(callback, callbackState);
             Native.grpcsharp_channel_watch_connectivity_state(this, lastObservedState, deadline, cq, ctx);
         }
 
diff --git a/src/csharp/Grpc.Core/Internal/ClientResponseStream.cs b/src/csharp/Grpc.Core/Internal/ClientResponseStream.cs
index 851b6ca..ab649ee 100644
--- a/src/csharp/Grpc.Core/Internal/ClientResponseStream.cs
+++ b/src/csharp/Grpc.Core/Internal/ClientResponseStream.cs
@@ -49,19 +49,19 @@
 
         public async Task<bool> MoveNext(CancellationToken token)
         {
-            if (token != CancellationToken.None)
+            var cancellationTokenRegistration = token.CanBeCanceled ? token.Register(() => call.Cancel()) : (IDisposable) null;
+            using (cancellationTokenRegistration)
             {
-                throw new InvalidOperationException("Cancellation of individual reads is not supported.");
-            }
-            var result = await call.ReadMessageAsync().ConfigureAwait(false);
-            this.current = result;
+                var result = await call.ReadMessageAsync().ConfigureAwait(false);
+                this.current = result;
 
-            if (result == null)
-            {
-                await call.StreamingResponseCallFinishedTask.ConfigureAwait(false);
-                return false;
+                if (result == null)
+                {
+                    await call.StreamingResponseCallFinishedTask.ConfigureAwait(false);
+                    return false;
+                }
+                return true;
             }
-            return true;
         }
 
         public void Dispose()
diff --git a/src/csharp/Grpc.Core/Internal/CompletionRegistry.cs b/src/csharp/Grpc.Core/Internal/CompletionRegistry.cs
index 3ce08e9..cf3f3c0 100644
--- a/src/csharp/Grpc.Core/Internal/CompletionRegistry.cs
+++ b/src/csharp/Grpc.Core/Internal/CompletionRegistry.cs
@@ -19,15 +19,15 @@
 using System;
 using System.Collections.Concurrent;
 using System.Collections.Generic;
+using System.Diagnostics;
 using System.Runtime.InteropServices;
+using System.Threading;
 using Grpc.Core.Logging;
 using Grpc.Core.Utils;
 
 namespace Grpc.Core.Internal
 {
-    internal delegate void OpCompletionDelegate(bool success);
-
-    internal delegate void BatchCompletionDelegate(bool success, BatchContextSafeHandle ctx);
+    internal delegate void BatchCompletionDelegate(bool success, BatchContextSafeHandle ctx, object state);
 
     internal delegate void RequestCallCompletionDelegate(bool success, RequestCallContextSafeHandle ctx);
 
@@ -36,87 +36,76 @@
         static readonly ILogger Logger = GrpcEnvironment.Logger.ForType<CompletionRegistry>();
 
         readonly GrpcEnvironment environment;
-        readonly ConcurrentDictionary<IntPtr, OpCompletionDelegate> dict = new ConcurrentDictionary<IntPtr, OpCompletionDelegate>(new IntPtrComparer());
+        readonly Func<BatchContextSafeHandle> batchContextFactory;
+        readonly Dictionary<IntPtr, IOpCompletionCallback> dict = new Dictionary<IntPtr, IOpCompletionCallback>(new IntPtrComparer());
+        SpinLock spinLock = new SpinLock(Debugger.IsAttached);
         IntPtr lastRegisteredKey;  // only for testing
 
-        public CompletionRegistry(GrpcEnvironment environment)
+        public CompletionRegistry(GrpcEnvironment environment, Func<BatchContextSafeHandle> batchContextFactory)
         {
-            this.environment = environment;
+            this.environment = GrpcPreconditions.CheckNotNull(environment);
+            this.batchContextFactory = GrpcPreconditions.CheckNotNull(batchContextFactory);
         }
 
-        public void Register(IntPtr key, OpCompletionDelegate callback)
+        public void Register(IntPtr key, IOpCompletionCallback callback)
         {
             environment.DebugStats.PendingBatchCompletions.Increment();
-            GrpcPreconditions.CheckState(dict.TryAdd(key, callback));
-            this.lastRegisteredKey = key;
+
+            bool lockTaken = false;
+            try
+            {
+                spinLock.Enter(ref lockTaken);
+
+                dict.Add(key, callback);
+                this.lastRegisteredKey = key;
+            }
+            finally
+            {
+                if (lockTaken) spinLock.Exit();
+            }
         }
 
-        public void RegisterBatchCompletion(BatchContextSafeHandle ctx, BatchCompletionDelegate callback)
+        public BatchContextSafeHandle RegisterBatchCompletion(BatchCompletionDelegate callback, object state)
         {
-            OpCompletionDelegate opCallback = ((success) => HandleBatchCompletion(success, ctx, callback));
-            Register(ctx.Handle, opCallback);
+            var ctx = batchContextFactory();
+            ctx.SetCompletionCallback(callback, state);
+            Register(ctx.Handle, ctx);
+            return ctx;
         }
 
         public void RegisterRequestCallCompletion(RequestCallContextSafeHandle ctx, RequestCallCompletionDelegate callback)
         {
-            OpCompletionDelegate opCallback = ((success) => HandleRequestCallCompletion(success, ctx, callback));
-            Register(ctx.Handle, opCallback);
+            ctx.CompletionCallback = callback;
+            Register(ctx.Handle, ctx);
         }
 
-        public OpCompletionDelegate Extract(IntPtr key)
+        public IOpCompletionCallback Extract(IntPtr key)
         {
-            OpCompletionDelegate value;
-            GrpcPreconditions.CheckState(dict.TryRemove(key, out value));
+            IOpCompletionCallback value = null;
+            bool lockTaken = false;
+            try
+            {
+                spinLock.Enter(ref lockTaken);
+
+                value = dict[key];
+                dict.Remove(key);
+            }
+            finally
+            {
+                if (lockTaken) spinLock.Exit();
+            }
             environment.DebugStats.PendingBatchCompletions.Decrement();
             return value;
         }
 
         /// <summary>
-        /// For testing purposes only.
+        /// For testing purposes only. NOT threadsafe.
         /// </summary>
         public IntPtr LastRegisteredKey
         {
             get { return this.lastRegisteredKey; }
         }
 
-        private static void HandleBatchCompletion(bool success, BatchContextSafeHandle ctx, BatchCompletionDelegate callback)
-        {
-            try
-            {
-                callback(success, ctx);
-            }
-            catch (Exception e)
-            {
-                Logger.Error(e, "Exception occured while invoking batch completion delegate.");
-            }
-            finally
-            {
-                if (ctx != null)
-                {
-                    ctx.Dispose();
-                }
-            }
-        }
-
-        private static void HandleRequestCallCompletion(bool success, RequestCallContextSafeHandle ctx, RequestCallCompletionDelegate callback)
-        {
-            try
-            {
-                callback(success, ctx);
-            }
-            catch (Exception e)
-            {
-                Logger.Error(e, "Exception occured while invoking request call completion delegate.");
-            }
-            finally
-            {
-                if (ctx != null)
-                {
-                    ctx.Dispose();
-                }
-            }
-        }
-
         /// <summary>
         /// IntPtr doesn't implement <c>IEquatable{IntPtr}</c> so we need to use custom comparer to avoid boxing.
         /// </summary>
diff --git a/src/csharp/Grpc.Core/Internal/DefaultObjectPool.cs b/src/csharp/Grpc.Core/Internal/DefaultObjectPool.cs
new file mode 100644
index 0000000..2f030f3
--- /dev/null
+++ b/src/csharp/Grpc.Core/Internal/DefaultObjectPool.cs
@@ -0,0 +1,196 @@
+#region Copyright notice and license
+
+// Copyright 2017 gRPC authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#endregion
+
+using System;
+using System.Threading;
+using System.Collections.Generic;
+using Grpc.Core.Utils;
+
+namespace Grpc.Core.Internal
+{
+    /// <summary>
+    /// Pool of objects that combines a shared pool and a thread local pool.
+    /// </summary>
+    internal class DefaultObjectPool<T> : IObjectPool<T>
+        where T : class, IDisposable
+    {
+        readonly object myLock = new object();
+        readonly Func<T> itemFactory;
+
+        // Queue shared between threads, access needs to be synchronized.
+        readonly Queue<T> sharedQueue;
+        readonly int sharedCapacity;
+
+        readonly ThreadLocal<ThreadLocalData> threadLocalData;
+        readonly int threadLocalCapacity;
+        readonly int rentLimit;
+
+        bool disposed;
+
+        /// <summary>
+        /// Initializes a new instance of <c>DefaultObjectPool</c> with given shared capacity and thread local capacity.
+        /// Thread local capacity should be significantly smaller than the shared capacity as we don't guarantee immediately
+        /// disposing the objects in the thread local pool after this pool is disposed (they will eventually be garbage collected
+        /// after the thread that owns them has finished).
+        /// On average, the shared pool will only be accessed approx. once for every <c>threadLocalCapacity / 2</c> rent or lease
+        /// operations.
+        /// </summary>
+        public DefaultObjectPool(Func<T> itemFactory, int sharedCapacity, int threadLocalCapacity)
+        {
+            GrpcPreconditions.CheckArgument(sharedCapacity >= 0);
+            GrpcPreconditions.CheckArgument(threadLocalCapacity >= 0);
+            this.itemFactory = GrpcPreconditions.CheckNotNull(itemFactory, nameof(itemFactory));
+            this.sharedQueue = new Queue<T>(sharedCapacity);
+            this.sharedCapacity = sharedCapacity;
+            this.threadLocalData = new ThreadLocal<ThreadLocalData>(() => new ThreadLocalData(threadLocalCapacity), false);
+            this.threadLocalCapacity = threadLocalCapacity;
+            this.rentLimit = threadLocalCapacity != 1 ? threadLocalCapacity / 2 : 1;
+        }
+
+        /// <summary>
+        /// Leases an item from the pool or creates a new instance if the pool is empty.
+        /// Attempts to retrieve the item from the thread local pool first.
+        /// If the thread local pool is empty, the item is taken from the shared pool
+        /// along with more items that are moved to the thread local pool to avoid
+        /// prevent acquiring the lock for shared pool too often.
+        /// The methods should not be called after the pool is disposed, but it won't
+        /// results in an error to do so (after depleting the items potentially left
+        /// in the thread local pool, it will continue returning new objects created by the factory).
+        /// </summary>
+        public T Lease()
+        {
+            var localData = threadLocalData.Value;
+            if (localData.Queue.Count > 0)
+            {
+                return localData.Queue.Dequeue();
+            }
+            if (localData.CreateBudget > 0)
+            {
+                localData.CreateBudget --;
+                return itemFactory();
+            }
+
+            int itemsMoved = 0;
+            T leasedItem = null;
+            lock(myLock)
+            {
+                if (sharedQueue.Count > 0)
+                {
+                    leasedItem = sharedQueue.Dequeue();
+                }
+                while (sharedQueue.Count > 0 && itemsMoved < rentLimit)
+                {
+                    localData.Queue.Enqueue(sharedQueue.Dequeue());
+                    itemsMoved ++;
+                }
+            }
+
+            // If the shared pool didn't contain all rentLimit items,
+            // next time we try to lease we will just create those
+            // instead of trying to grab them from the shared queue.
+            // This is to guarantee we won't be accessing the shared queue too often.
+            localData.CreateBudget = rentLimit - itemsMoved;
+
+            return leasedItem ?? itemFactory();
+        }
+
+        /// <summary>
+        /// Returns an item to the pool.
+        /// Attempts to add the item to the thread local pool first.
+        /// If the thread local pool is full, item is added to a shared pool,
+        /// along with half of the items for the thread local pool, which
+        /// should prevent acquiring the lock for shared pool too often.
+        /// If called after the pool is disposed, we make best effort not to
+        /// add anything to the thread local pool and we guarantee not to add
+        /// anything to the shared pool (items will be disposed instead).
+        /// </summary>
+        public void Return(T item)
+        {
+            GrpcPreconditions.CheckNotNull(item);
+
+            var localData = threadLocalData.Value;
+            if (localData.Queue.Count < threadLocalCapacity && !disposed)
+            {
+                localData.Queue.Enqueue(item);
+                return;
+            }
+            if (localData.DisposeBudget > 0)
+            {
+                localData.DisposeBudget --;
+                item.Dispose();
+                return;
+            }
+
+            int itemsReturned = 0;
+            int returnLimit = rentLimit + 1;
+            lock (myLock)
+            {
+                if (sharedQueue.Count < sharedCapacity && !disposed)
+                {
+                    sharedQueue.Enqueue(item);
+                    itemsReturned ++;
+                }
+                while (sharedQueue.Count < sharedCapacity && itemsReturned < returnLimit && !disposed)
+                {
+                    sharedQueue.Enqueue(localData.Queue.Dequeue());
+                    itemsReturned ++;
+                }
+            }
+
+            // If the shared pool could not accomodate all returnLimit items,
+            // next time we try to return we will just dispose the item
+            // instead of trying to return them to the shared queue.
+            // This is to guarantee we won't be accessing the shared queue too often.
+            localData.DisposeBudget = returnLimit - itemsReturned;
+
+            if (itemsReturned == 0)
+            {
+                localData.DisposeBudget --;
+                item.Dispose();
+            }
+        }
+
+        public void Dispose()
+        {
+            lock (myLock)
+            {
+                if (!disposed)
+                {
+                    disposed = true;
+
+                    while (sharedQueue.Count > 0)
+                    {
+                        sharedQueue.Dequeue().Dispose();
+                    }
+                }
+            }
+        }
+
+        class ThreadLocalData
+        {
+            public ThreadLocalData(int capacity)
+            {
+                this.Queue = new Queue<T>(capacity);
+            }
+
+            public Queue<T> Queue { get; }
+            public int CreateBudget { get; set; }
+            public int DisposeBudget { get; set; }
+        }
+    }
+}
diff --git a/src/csharp/Grpc.Core/Internal/GrpcThreadPool.cs b/src/csharp/Grpc.Core/Internal/GrpcThreadPool.cs
index 3c94b60..f1b5a4f 100644
--- a/src/csharp/Grpc.Core/Internal/GrpcThreadPool.cs
+++ b/src/csharp/Grpc.Core/Internal/GrpcThreadPool.cs
@@ -68,8 +68,8 @@
             GrpcPreconditions.CheckArgument(poolSize >= completionQueueCount,
                 "Thread pool size cannot be smaller than the number of completion queues used.");
 
-            this.runCompletionQueueEventCallbackSuccess = new WaitCallback((callback) => RunCompletionQueueEventCallback((OpCompletionDelegate) callback, true));
-            this.runCompletionQueueEventCallbackFailure = new WaitCallback((callback) => RunCompletionQueueEventCallback((OpCompletionDelegate) callback, false));
+            this.runCompletionQueueEventCallbackSuccess = new WaitCallback((callback) => RunCompletionQueueEventCallback((IOpCompletionCallback) callback, true));
+            this.runCompletionQueueEventCallbackFailure = new WaitCallback((callback) => RunCompletionQueueEventCallback((IOpCompletionCallback) callback, false));
         }
 
         public void Start()
@@ -176,10 +176,10 @@
                     try
                     {
                         var callback = cq.CompletionRegistry.Extract(tag);
-                        // Use cached delegates to avoid unnecessary allocations
+                        queuedContinuationCounter.Increment();
                         if (!inlineHandlers)
                         {
-                            queuedContinuationCounter.Increment();
+                            // Use cached delegates to avoid unnecessary allocations
                             ThreadPool.QueueUserWorkItem(success ? runCompletionQueueEventCallbackSuccess : runCompletionQueueEventCallbackFailure, callback);
                         }
                         else
@@ -219,17 +219,17 @@
             var list = new List<CompletionQueueSafeHandle>();
             for (int i = 0; i < completionQueueCount; i++)
             {
-                var completionRegistry = new CompletionRegistry(environment);
+                var completionRegistry = new CompletionRegistry(environment, () => environment.BatchContextPool.Lease());
                 list.Add(CompletionQueueSafeHandle.CreateAsync(completionRegistry));
             }
             return list.AsReadOnly();
         }
 
-        private void RunCompletionQueueEventCallback(OpCompletionDelegate callback, bool success)
+        private void RunCompletionQueueEventCallback(IOpCompletionCallback callback, bool success)
         {
             try
             {
-                callback(success);
+                callback.OnComplete(success);
             }
             catch (Exception e)
             {
diff --git a/src/csharp/Grpc.Core/Internal/INativeCall.cs b/src/csharp/Grpc.Core/Internal/INativeCall.cs
index f9c0658..5c35b2b 100644
--- a/src/csharp/Grpc.Core/Internal/INativeCall.cs
+++ b/src/csharp/Grpc.Core/Internal/INativeCall.cs
@@ -20,18 +20,41 @@
 
 namespace Grpc.Core.Internal
 {
-    internal delegate void UnaryResponseClientHandler(bool success, ClientSideStatus receivedStatus, byte[] receivedMessage, Metadata responseHeaders);
+    internal interface IUnaryResponseClientCallback
+    {
+        void OnUnaryResponseClient(bool success, ClientSideStatus receivedStatus, byte[] receivedMessage, Metadata responseHeaders);
+    }
 
     // Received status for streaming response calls.
-    internal delegate void ReceivedStatusOnClientHandler(bool success, ClientSideStatus receivedStatus);
+    internal interface IReceivedStatusOnClientCallback
+    {
+        void OnReceivedStatusOnClient(bool success, ClientSideStatus receivedStatus);
+    }
 
-    internal delegate void ReceivedMessageHandler(bool success, byte[] receivedMessage);
+    internal interface IReceivedMessageCallback
+    {
+        void OnReceivedMessage(bool success, byte[] receivedMessage);
+    }
 
-    internal delegate void ReceivedResponseHeadersHandler(bool success, Metadata responseHeaders);
+    internal interface IReceivedResponseHeadersCallback
+    {
+        void OnReceivedResponseHeaders(bool success, Metadata responseHeaders);
+    }
 
-    internal delegate void SendCompletionHandler(bool success);
+    internal interface ISendCompletionCallback
+    {
+        void OnSendCompletion(bool success);
+    }
 
-    internal delegate void ReceivedCloseOnServerHandler(bool success, bool cancelled);
+    internal interface ISendStatusFromServerCompletionCallback
+    {
+        void OnSendStatusFromServerCompletion(bool success);
+    }
+
+    internal interface IReceivedCloseOnServerCallback
+    {
+        void OnReceivedCloseOnServer(bool success, bool cancelled);
+    }
 
     /// <summary>
     /// Abstraction of a native call object.
@@ -44,28 +67,28 @@
 
         string GetPeer();
 
-        void StartUnary(UnaryResponseClientHandler callback, byte[] payload, WriteFlags writeFlags, MetadataArraySafeHandle metadataArray, CallFlags callFlags);
+        void StartUnary(IUnaryResponseClientCallback callback, byte[] payload, WriteFlags writeFlags, MetadataArraySafeHandle metadataArray, CallFlags callFlags);
 
         void StartUnary(BatchContextSafeHandle ctx, byte[] payload, WriteFlags writeFlags, MetadataArraySafeHandle metadataArray, CallFlags callFlags);
 
-        void StartClientStreaming(UnaryResponseClientHandler callback, MetadataArraySafeHandle metadataArray, CallFlags callFlags);
+        void StartClientStreaming(IUnaryResponseClientCallback callback, MetadataArraySafeHandle metadataArray, CallFlags callFlags);
 
-        void StartServerStreaming(ReceivedStatusOnClientHandler callback, byte[] payload, WriteFlags writeFlags, MetadataArraySafeHandle metadataArray, CallFlags callFlags);
+        void StartServerStreaming(IReceivedStatusOnClientCallback callback, byte[] payload, WriteFlags writeFlags, MetadataArraySafeHandle metadataArray, CallFlags callFlags);
 
-        void StartDuplexStreaming(ReceivedStatusOnClientHandler callback, MetadataArraySafeHandle metadataArray, CallFlags callFlags);
+        void StartDuplexStreaming(IReceivedStatusOnClientCallback callback, MetadataArraySafeHandle metadataArray, CallFlags callFlags);
 
-        void StartReceiveMessage(ReceivedMessageHandler callback);
+        void StartReceiveMessage(IReceivedMessageCallback callback);
 
-        void StartReceiveInitialMetadata(ReceivedResponseHeadersHandler callback);
+        void StartReceiveInitialMetadata(IReceivedResponseHeadersCallback callback);
 
-        void StartSendInitialMetadata(SendCompletionHandler callback, MetadataArraySafeHandle metadataArray);
+        void StartSendInitialMetadata(ISendCompletionCallback callback, MetadataArraySafeHandle metadataArray);
 
-        void StartSendMessage(SendCompletionHandler callback, byte[] payload, WriteFlags writeFlags, bool sendEmptyInitialMetadata);
+        void StartSendMessage(ISendCompletionCallback callback, byte[] payload, WriteFlags writeFlags, bool sendEmptyInitialMetadata);
 
-        void StartSendCloseFromClient(SendCompletionHandler callback);
+        void StartSendCloseFromClient(ISendCompletionCallback callback);
 
-        void StartSendStatusFromServer(SendCompletionHandler callback, Status status, MetadataArraySafeHandle metadataArray, bool sendEmptyInitialMetadata, byte[] optionalPayload, WriteFlags writeFlags);
+        void StartSendStatusFromServer(ISendStatusFromServerCompletionCallback callback, Status status, MetadataArraySafeHandle metadataArray, bool sendEmptyInitialMetadata, byte[] optionalPayload, WriteFlags writeFlags);
 
-        void StartServerSide(ReceivedCloseOnServerHandler callback);
+        void StartServerSide(IReceivedCloseOnServerCallback callback);
     }
 }
diff --git a/src/csharp/Grpc.Core/Internal/IObjectPool.cs b/src/csharp/Grpc.Core/Internal/IObjectPool.cs
new file mode 100644
index 0000000..f7d6e30
--- /dev/null
+++ b/src/csharp/Grpc.Core/Internal/IObjectPool.cs
@@ -0,0 +1,35 @@
+#region Copyright notice and license
+
+// Copyright 2017 gRPC authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#endregion
+
+using System;
+using System.Threading;
+using System.Collections.Generic;
+using Grpc.Core.Utils;
+
+namespace Grpc.Core.Internal
+{
+    /// <summary>
+    /// Pool of objects.
+    /// </summary>
+    internal interface IObjectPool<T> : IDisposable
+        where T : class
+    {
+        T Lease();
+        void Return(T item);
+    }
+}
diff --git a/src/csharp/Grpc.Core/Internal/NativeMethods.cs b/src/csharp/Grpc.Core/Internal/NativeMethods.cs
index 22faa19..43acb8f 100644
--- a/src/csharp/Grpc.Core/Internal/NativeMethods.cs
+++ b/src/csharp/Grpc.Core/Internal/NativeMethods.cs
@@ -29,6 +29,8 @@
 
 namespace Grpc.Core.Internal
 {
+    internal delegate void NativeCallbackTestDelegate(bool success);
+
     /// <summary>
     /// Provides access to all native methods provided by <c>NativeExtension</c>.
     /// An extra level of indirection is added to P/Invoke calls to allow intelligent loading
@@ -50,6 +52,7 @@
         public readonly Delegates.grpcsharp_batch_context_recv_status_on_client_details_delegate grpcsharp_batch_context_recv_status_on_client_details;
         public readonly Delegates.grpcsharp_batch_context_recv_status_on_client_trailing_metadata_delegate grpcsharp_batch_context_recv_status_on_client_trailing_metadata;
         public readonly Delegates.grpcsharp_batch_context_recv_close_on_server_cancelled_delegate grpcsharp_batch_context_recv_close_on_server_cancelled;
+        public readonly Delegates.grpcsharp_batch_context_reset_delegate grpcsharp_batch_context_reset;
         public readonly Delegates.grpcsharp_batch_context_destroy_delegate grpcsharp_batch_context_destroy;
 
         public readonly Delegates.grpcsharp_request_call_context_create_delegate grpcsharp_request_call_context_create;
@@ -167,6 +170,7 @@
             this.grpcsharp_batch_context_recv_status_on_client_details = GetMethodDelegate<Delegates.grpcsharp_batch_context_recv_status_on_client_details_delegate>(library);
             this.grpcsharp_batch_context_recv_status_on_client_trailing_metadata = GetMethodDelegate<Delegates.grpcsharp_batch_context_recv_status_on_client_trailing_metadata_delegate>(library);
             this.grpcsharp_batch_context_recv_close_on_server_cancelled = GetMethodDelegate<Delegates.grpcsharp_batch_context_recv_close_on_server_cancelled_delegate>(library);
+            this.grpcsharp_batch_context_reset = GetMethodDelegate<Delegates.grpcsharp_batch_context_reset_delegate>(library);
             this.grpcsharp_batch_context_destroy = GetMethodDelegate<Delegates.grpcsharp_batch_context_destroy_delegate>(library);
 
             this.grpcsharp_request_call_context_create = GetMethodDelegate<Delegates.grpcsharp_request_call_context_create_delegate>(library);
@@ -309,6 +313,7 @@
             public delegate IntPtr grpcsharp_batch_context_recv_status_on_client_details_delegate(BatchContextSafeHandle ctx, out UIntPtr detailsLength);
             public delegate IntPtr grpcsharp_batch_context_recv_status_on_client_trailing_metadata_delegate(BatchContextSafeHandle ctx);
             public delegate int grpcsharp_batch_context_recv_close_on_server_cancelled_delegate(BatchContextSafeHandle ctx);
+            public delegate void grpcsharp_batch_context_reset_delegate(BatchContextSafeHandle ctx);
             public delegate void grpcsharp_batch_context_destroy_delegate(IntPtr ctx);
 
             public delegate RequestCallContextSafeHandle grpcsharp_request_call_context_create_delegate();
@@ -420,7 +425,7 @@
             public delegate Timespec gprsharp_convert_clock_type_delegate(Timespec t, ClockType targetClock);
             public delegate int gprsharp_sizeof_timespec_delegate();
 
-            public delegate CallError grpcsharp_test_callback_delegate([MarshalAs(UnmanagedType.FunctionPtr)] OpCompletionDelegate callback);
+            public delegate CallError grpcsharp_test_callback_delegate([MarshalAs(UnmanagedType.FunctionPtr)] NativeCallbackTestDelegate callback);
             public delegate IntPtr grpcsharp_test_nop_delegate(IntPtr ptr);
             public delegate void grpcsharp_test_override_method_delegate(string methodName, string variant);
         }
diff --git a/src/csharp/Grpc.Core/Internal/RequestCallContextSafeHandle.cs b/src/csharp/Grpc.Core/Internal/RequestCallContextSafeHandle.cs
index b7af0c1..09f5c3e 100644
--- a/src/csharp/Grpc.Core/Internal/RequestCallContextSafeHandle.cs
+++ b/src/csharp/Grpc.Core/Internal/RequestCallContextSafeHandle.cs
@@ -19,15 +19,17 @@
 using System;
 using System.Runtime.InteropServices;
 using Grpc.Core;
+using Grpc.Core.Logging;
 
 namespace Grpc.Core.Internal
 {
     /// <summary>
     /// grpcsharp_request_call_context
     /// </summary>
-    internal class RequestCallContextSafeHandle : SafeHandleZeroIsInvalid
+    internal class RequestCallContextSafeHandle : SafeHandleZeroIsInvalid, IOpCompletionCallback
     {
         static readonly NativeMethods Native = NativeMethods.Get();
+        static readonly ILogger Logger = GrpcEnvironment.Logger.ForType<RequestCallContextSafeHandle>();
 
         private RequestCallContextSafeHandle()
         {
@@ -46,6 +48,8 @@
             }
         }
 
+        public RequestCallCompletionDelegate CompletionCallback { get; set; }
+
         // Gets data of server_rpc_new completion.
         public ServerRpcNew GetServerRpcNew(Server server)
         {
@@ -72,5 +76,22 @@
             Native.grpcsharp_request_call_context_destroy(handle);
             return true;
         }
+
+        void IOpCompletionCallback.OnComplete(bool success)
+        {
+            try
+            {
+                CompletionCallback(success, this);
+            }
+            catch (Exception e)
+            {
+                Logger.Error(e, "Exception occured while invoking request call completion delegate.");
+            }
+            finally
+            {
+                CompletionCallback = null;
+                Dispose();
+            }
+        }
     }
 }
diff --git a/src/csharp/Grpc.Core/Internal/ServerCallHandler.cs b/src/csharp/Grpc.Core/Internal/ServerCallHandler.cs
index 6019f8e..98995a0 100644
--- a/src/csharp/Grpc.Core/Internal/ServerCallHandler.cs
+++ b/src/csharp/Grpc.Core/Internal/ServerCallHandler.cs
@@ -60,7 +60,7 @@
             var responseStream = new ServerResponseStream<TRequest, TResponse>(asyncCall);
 
             Status status;
-            Tuple<TResponse,WriteFlags> responseTuple = null;
+            AsyncCallServer<TRequest,TResponse>.ResponseWithFlags? responseWithFlags = null;
             var context = HandlerUtils.NewContext(newRpc, responseStream, asyncCall.CancellationToken);
             try
             {
@@ -68,7 +68,7 @@
                 var request = requestStream.Current;
                 var response = await handler(request, context).ConfigureAwait(false);
                 status = context.Status;
-                responseTuple = Tuple.Create(response, HandlerUtils.GetWriteFlags(context.WriteOptions));
+                responseWithFlags = new AsyncCallServer<TRequest, TResponse>.ResponseWithFlags(response, HandlerUtils.GetWriteFlags(context.WriteOptions));
             } 
             catch (Exception e)
             {
@@ -80,7 +80,7 @@
             }
             try
             {
-                await asyncCall.SendStatusFromServerAsync(status, context.ResponseTrailers, responseTuple).ConfigureAwait(false);
+                await asyncCall.SendStatusFromServerAsync(status, context.ResponseTrailers, responseWithFlags).ConfigureAwait(false);
             }
             catch (Exception)
             {
@@ -177,13 +177,13 @@
             var responseStream = new ServerResponseStream<TRequest, TResponse>(asyncCall);
 
             Status status;
-            Tuple<TResponse,WriteFlags> responseTuple = null;
+            AsyncCallServer<TRequest, TResponse>.ResponseWithFlags? responseWithFlags = null;
             var context = HandlerUtils.NewContext(newRpc, responseStream, asyncCall.CancellationToken);
             try
             {
                 var response = await handler(requestStream, context).ConfigureAwait(false);
                 status = context.Status;
-                responseTuple = Tuple.Create(response, HandlerUtils.GetWriteFlags(context.WriteOptions));
+                responseWithFlags = new AsyncCallServer<TRequest, TResponse>.ResponseWithFlags(response, HandlerUtils.GetWriteFlags(context.WriteOptions));
             }
             catch (Exception e)
             {
@@ -196,7 +196,7 @@
 
             try
             {
-                await asyncCall.SendStatusFromServerAsync(status, context.ResponseTrailers, responseTuple).ConfigureAwait(false);
+                await asyncCall.SendStatusFromServerAsync(status, context.ResponseTrailers, responseWithFlags).ConfigureAwait(false);
             }
             catch (Exception)
             {
diff --git a/src/csharp/Grpc.Core/Internal/ServerRequestStream.cs b/src/csharp/Grpc.Core/Internal/ServerRequestStream.cs
index c65b960..058dddb 100644
--- a/src/csharp/Grpc.Core/Internal/ServerRequestStream.cs
+++ b/src/csharp/Grpc.Core/Internal/ServerRequestStream.cs
@@ -49,13 +49,14 @@
 
         public async Task<bool> MoveNext(CancellationToken token)
         {
-            if (token != CancellationToken.None)
+            
+            var cancellationTokenRegistration = token.CanBeCanceled ? token.Register(() => call.Cancel()) : (IDisposable) null;
+            using (cancellationTokenRegistration)
             {
-                throw new InvalidOperationException("Cancellation of individual reads is not supported.");
+                var result = await call.ReadMessageAsync().ConfigureAwait(false);
+                this.current = result;
+                return result != null;
             }
-            var result = await call.ReadMessageAsync().ConfigureAwait(false);
-            this.current = result;
-            return result != null;
         }
 
         public void Dispose()
diff --git a/src/csharp/Grpc.Core/Internal/ServerSafeHandle.cs b/src/csharp/Grpc.Core/Internal/ServerSafeHandle.cs
index 63000e9..9b7ea88 100644
--- a/src/csharp/Grpc.Core/Internal/ServerSafeHandle.cs
+++ b/src/csharp/Grpc.Core/Internal/ServerSafeHandle.cs
@@ -59,13 +59,14 @@
         {
             Native.grpcsharp_server_start(this);
         }
-    
+
         public void ShutdownAndNotify(BatchCompletionDelegate callback, CompletionQueueSafeHandle completionQueue)
         {
             using (completionQueue.NewScope())
             {
-                var ctx = BatchContextSafeHandle.Create();
-                completionQueue.CompletionRegistry.RegisterBatchCompletion(ctx, callback);
+                // TODO(jtattermusch): delegate allocation by caller can be avoided by utilizing the "state" object,
+                // but server shutdown isn't worth optimizing right now.
+                var ctx = completionQueue.CompletionRegistry.RegisterBatchCompletion(callback, null);
                 Native.grpcsharp_server_shutdown_and_notify_callback(this, completionQueue, ctx);
             }
         }
diff --git a/src/csharp/Grpc.Core/Server.cs b/src/csharp/Grpc.Core/Server.cs
index 77ad876..71c7f10 100644
--- a/src/csharp/Grpc.Core/Server.cs
+++ b/src/csharp/Grpc.Core/Server.cs
@@ -387,7 +387,7 @@
         /// <summary>
         /// Handles native callback.
         /// </summary>
-        private void HandleServerShutdown(bool success, BatchContextSafeHandle ctx)
+        private void HandleServerShutdown(bool success, BatchContextSafeHandle ctx, object state)
         {
             shutdownTcs.SetResult(null);
         }
diff --git a/src/csharp/Grpc.Core/Version.csproj.include b/src/csharp/Grpc.Core/Version.csproj.include
index b9ceaf8..2d9e4ba 100755
--- a/src/csharp/Grpc.Core/Version.csproj.include
+++ b/src/csharp/Grpc.Core/Version.csproj.include
@@ -1,7 +1,7 @@
 <!-- This file is generated -->
 <Project>
   <PropertyGroup>
-    <GrpcCsharpVersion>1.8.0-dev</GrpcCsharpVersion>
+    <GrpcCsharpVersion>1.9.0-dev</GrpcCsharpVersion>
     <GoogleProtobufVersion>3.3.0</GoogleProtobufVersion>
   </PropertyGroup>
 </Project>
diff --git a/src/csharp/Grpc.Core/VersionInfo.cs b/src/csharp/Grpc.Core/VersionInfo.cs
index dab9388..9b5da1c 100644
--- a/src/csharp/Grpc.Core/VersionInfo.cs
+++ b/src/csharp/Grpc.Core/VersionInfo.cs
@@ -33,11 +33,11 @@
         /// <summary>
         /// Current <c>AssemblyFileVersion</c> of gRPC C# assemblies
         /// </summary>
-        public const string CurrentAssemblyFileVersion = "1.8.0.0";
+        public const string CurrentAssemblyFileVersion = "1.9.0.0";
 
         /// <summary>
         /// Current version of gRPC C#
         /// </summary>
-        public const string CurrentVersion = "1.8.0-dev";
+        public const string CurrentVersion = "1.9.0-dev";
     }
 }
diff --git a/src/csharp/Grpc.IntegrationTesting/ClientRunners.cs b/src/csharp/Grpc.IntegrationTesting/ClientRunners.cs
index 60696b6..9d41d34 100644
--- a/src/csharp/Grpc.IntegrationTesting/ClientRunners.cs
+++ b/src/csharp/Grpc.IntegrationTesting/ClientRunners.cs
@@ -72,7 +72,7 @@
                 Logger.Warning("ClientConfig.CoreList is not supported for C#. Ignoring the value");
             }
 
-            var channels = CreateChannels(config.ClientChannels, config.ServerTargets, config.SecurityParams);
+            var channels = CreateChannels(config.ClientChannels, config.ServerTargets, config.SecurityParams, config.ChannelArgs);
 
             return new ClientRunnerImpl(channels,
                 config.ClientType,
@@ -84,19 +84,20 @@
                 () => GetNextProfiler());
         }
 
-        private static List<Channel> CreateChannels(int clientChannels, IEnumerable<string> serverTargets, SecurityParams securityParams)
+        private static List<Channel> CreateChannels(int clientChannels, IEnumerable<string> serverTargets, SecurityParams securityParams, IEnumerable<ChannelArg> channelArguments)
         {
             GrpcPreconditions.CheckArgument(clientChannels > 0, "clientChannels needs to be at least 1.");
             GrpcPreconditions.CheckArgument(serverTargets.Count() > 0, "at least one serverTarget needs to be specified.");
 
             var credentials = securityParams != null ? TestCredentials.CreateSslCredentials() : ChannelCredentials.Insecure;
-            List<ChannelOption> channelOptions = null;
+            var channelOptions = new List<ChannelOption>();
             if (securityParams != null && securityParams.ServerHostOverride != "")
             {
-                channelOptions = new List<ChannelOption>
-                {
-                    new ChannelOption(ChannelOptions.SslTargetNameOverride, securityParams.ServerHostOverride)
-                };
+                channelOptions.Add(new ChannelOption(ChannelOptions.SslTargetNameOverride, securityParams.ServerHostOverride));
+            }
+            foreach (var channelArgument in channelArguments)
+            {
+                channelOptions.Add(channelArgument.ToChannelOption());
             }
 
             var result = new List<Channel>();
@@ -130,7 +131,7 @@
 
         readonly List<Task> runnerTasks;
         readonly CancellationTokenSource stoppedCts = new CancellationTokenSource();
-        readonly WallClockStopwatch wallClockStopwatch = new WallClockStopwatch();
+        readonly TimeStats timeStats = new TimeStats();
         readonly AtomicCounter statsResetCount = new AtomicCounter();
         
         public ClientRunnerImpl(List<Channel> channels, ClientType clientType, RpcType rpcType, int outstandingRpcsPerChannel, LoadParams loadParams, PayloadConfig payloadConfig, HistogramParams histogramParams, Func<BasicProfiler> profilerFactory)
@@ -164,7 +165,7 @@
                 hist.GetSnapshot(histogramData, reset);
             }
 
-            var secondsElapsed = wallClockStopwatch.GetElapsedSnapshot(reset).TotalSeconds;
+            var timeSnapshot = timeStats.GetSnapshot(reset);
 
             if (reset)
             {
@@ -172,15 +173,14 @@
             }
 
             GrpcEnvironment.Logger.Info("[ClientRunnerImpl.GetStats] GC collection counts: gen0 {0}, gen1 {1}, gen2 {2}, (histogram reset count:{3}, seconds since reset: {4})",
-                GC.CollectionCount(0), GC.CollectionCount(1), GC.CollectionCount(2), statsResetCount.Count, secondsElapsed);
+                GC.CollectionCount(0), GC.CollectionCount(1), GC.CollectionCount(2), statsResetCount.Count, timeSnapshot.WallClockTime.TotalSeconds);
 
-            // TODO: populate user time and system time
             return new ClientStats
             {
                 Latencies = histogramData,
-                TimeElapsed = secondsElapsed,
-                TimeUser = 0,
-                TimeSystem = 0
+                TimeElapsed = timeSnapshot.WallClockTime.TotalSeconds,
+                TimeUser = timeSnapshot.UserProcessorTime.TotalSeconds,
+                TimeSystem = timeSnapshot.PrivilegedProcessorTime.TotalSeconds
             };
         }
 
diff --git a/src/csharp/Grpc.IntegrationTesting/ControlExtensions.cs b/src/csharp/Grpc.IntegrationTesting/ControlExtensions.cs
new file mode 100644
index 0000000..67f5fae
--- /dev/null
+++ b/src/csharp/Grpc.IntegrationTesting/ControlExtensions.cs
@@ -0,0 +1,43 @@
+#region Copyright notice and license
+
+// Copyright 2016 gRPC authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#endregion
+
+using System;
+using Grpc.Core;
+using Grpc.Testing;
+
+namespace Grpc.IntegrationTesting
+{
+    /// <summary>
+    /// Helpers for Control.cs
+    /// </summary>
+    public static class ControlExtensions
+    {
+        public static ChannelOption ToChannelOption(this ChannelArg channelArgument)
+        {
+            switch (channelArgument.ValueCase)
+            {
+                case ChannelArg.ValueOneofCase.StrValue:
+                  return new ChannelOption(channelArgument.Name, channelArgument.StrValue);
+                case ChannelArg.ValueOneofCase.IntValue:
+                  return new ChannelOption(channelArgument.Name, channelArgument.IntValue);
+                default:
+                  throw new ArgumentException("Unsupported channel argument value.");
+            }
+        }
+    }
+}
diff --git a/src/csharp/Grpc.IntegrationTesting/ServerRunners.cs b/src/csharp/Grpc.IntegrationTesting/ServerRunners.cs
index 45bff3a..ea29bd7 100644
--- a/src/csharp/Grpc.IntegrationTesting/ServerRunners.cs
+++ b/src/csharp/Grpc.IntegrationTesting/ServerRunners.cs
@@ -78,7 +78,8 @@
                 throw new ArgumentException("Unsupported ServerType");
             }
 
-            var server = new Server
+            var channelOptions = new List<ChannelOption>(config.ChannelArgs.Select((arg) => arg.ToChannelOption()));
+            var server = new Server(channelOptions)
             {
                 Services = { service },
                 Ports = { new ServerPort("[::]", config.Port, credentials) }
@@ -116,7 +117,7 @@
     public class ServerRunnerImpl : IServerRunner
     {
         readonly Server server;
-        readonly WallClockStopwatch wallClockStopwatch = new WallClockStopwatch();
+        readonly TimeStats timeStats = new TimeStats();
 
         public ServerRunnerImpl(Server server)
         {
@@ -137,17 +138,16 @@
         /// <returns>The stats.</returns>
         public ServerStats GetStats(bool reset)
         {
-            var secondsElapsed = wallClockStopwatch.GetElapsedSnapshot(reset).TotalSeconds;
+            var timeSnapshot = timeStats.GetSnapshot(reset);
 
             GrpcEnvironment.Logger.Info("[ServerRunner.GetStats] GC collection counts: gen0 {0}, gen1 {1}, gen2 {2}, (seconds since last reset {3})",
-                GC.CollectionCount(0), GC.CollectionCount(1), GC.CollectionCount(2), secondsElapsed);
+                GC.CollectionCount(0), GC.CollectionCount(1), GC.CollectionCount(2), timeSnapshot.WallClockTime.TotalSeconds);
 
-            // TODO: populate user time and system time
             return new ServerStats
             {
-                TimeElapsed = secondsElapsed,
-                TimeUser = 0,
-                TimeSystem = 0
+                TimeElapsed = timeSnapshot.WallClockTime.TotalSeconds,
+                TimeUser = timeSnapshot.UserProcessorTime.TotalSeconds,
+                TimeSystem = timeSnapshot.PrivilegedProcessorTime.TotalSeconds
             };
         }
 
diff --git a/src/csharp/Grpc.IntegrationTesting/StressTestClient.cs b/src/csharp/Grpc.IntegrationTesting/StressTestClient.cs
index 11956e4..0c62380 100644
--- a/src/csharp/Grpc.IntegrationTesting/StressTestClient.cs
+++ b/src/csharp/Grpc.IntegrationTesting/StressTestClient.cs
@@ -243,7 +243,7 @@
             const string GaugeName = "csharp_overall_qps";
 
             readonly Histogram histogram;
-            readonly WallClockStopwatch wallClockStopwatch = new WallClockStopwatch();
+            readonly TimeStats timeStats = new TimeStats();
 
             public MetricsServiceImpl(Histogram histogram)
             {
@@ -280,9 +280,9 @@
             long GetQpsAndReset()
             {
                 var snapshot = histogram.GetSnapshot(true);
-                var elapsedSnapshot = wallClockStopwatch.GetElapsedSnapshot(true);
+                var timeSnapshot = timeStats.GetSnapshot(true);
 
-                return (long) (snapshot.Count / elapsedSnapshot.TotalSeconds);
+                return (long) (snapshot.Count / timeSnapshot.WallClockTime.TotalSeconds);
             }
         }
     }
diff --git a/src/csharp/Grpc.IntegrationTesting/TimeStats.cs b/src/csharp/Grpc.IntegrationTesting/TimeStats.cs
new file mode 100644
index 0000000..6aba04c
--- /dev/null
+++ b/src/csharp/Grpc.IntegrationTesting/TimeStats.cs
@@ -0,0 +1,90 @@
+#region Copyright notice and license
+
+// Copyright 2015 gRPC authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#endregion
+
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.IO;
+using System.Linq;
+using System.Text.RegularExpressions;
+using System.Threading;
+using System.Threading.Tasks;
+using Google.Protobuf;
+using Grpc.Core;
+using Grpc.Core.Utils;
+using NUnit.Framework;
+using Grpc.Testing;
+
+namespace Grpc.IntegrationTesting
+{
+    /// <summary>
+    /// Snapshottable time statistics.
+    /// </summary>
+    public class TimeStats
+    {
+        readonly object myLock = new object();
+        DateTime lastWallClock;
+        TimeSpan lastUserTime;
+        TimeSpan lastPrivilegedTime;
+
+        public TimeStats()
+        {
+            lastWallClock = DateTime.UtcNow;
+            lastUserTime = Process.GetCurrentProcess().UserProcessorTime;
+            lastPrivilegedTime = Process.GetCurrentProcess().PrivilegedProcessorTime;
+        }
+
+        public Snapshot GetSnapshot(bool reset)
+        {
+            lock (myLock)
+            {
+                var wallClock = DateTime.UtcNow;
+                var userTime = Process.GetCurrentProcess().UserProcessorTime;
+                var privilegedTime = Process.GetCurrentProcess().PrivilegedProcessorTime;
+                var snapshot = new Snapshot(wallClock - lastWallClock, userTime - lastUserTime, privilegedTime - lastPrivilegedTime);
+
+                if (reset)
+                {
+                    lastWallClock = wallClock;
+                    lastUserTime = userTime;
+                    lastPrivilegedTime = privilegedTime;
+                }
+                return snapshot;
+            }
+        }
+
+        public class Snapshot
+        {
+            public TimeSpan WallClockTime { get; }
+            public TimeSpan UserProcessorTime { get; }
+            public TimeSpan PrivilegedProcessorTime { get; }
+
+            public Snapshot(TimeSpan wallClockTime, TimeSpan userProcessorTime, TimeSpan privilegedProcessorTime)
+            {
+                this.WallClockTime = wallClockTime;
+                this.UserProcessorTime = userProcessorTime;
+                this.PrivilegedProcessorTime = privilegedProcessorTime;
+            }
+
+            public override string ToString()
+            {
+                return string.Format("[TimeStats.Snapshot: wallClock {0}, userProcessor {1}, privilegedProcessor {2}]", WallClockTime, UserProcessorTime, PrivilegedProcessorTime);
+            }
+        }
+    }
+}
diff --git a/src/csharp/Grpc.IntegrationTesting/WallClockStopwatch.cs b/src/csharp/Grpc.IntegrationTesting/WallClockStopwatch.cs
deleted file mode 100644
index 38b58f2..0000000
--- a/src/csharp/Grpc.IntegrationTesting/WallClockStopwatch.cs
+++ /dev/null
@@ -1,63 +0,0 @@
-#region Copyright notice and license
-
-// Copyright 2015 gRPC authors.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#endregion
-
-using System;
-using System.Collections.Generic;
-using System.Diagnostics;
-using System.IO;
-using System.Linq;
-using System.Text.RegularExpressions;
-using System.Threading;
-using System.Threading.Tasks;
-using Google.Protobuf;
-using Grpc.Core;
-using Grpc.Core.Utils;
-using NUnit.Framework;
-using Grpc.Testing;
-
-namespace Grpc.IntegrationTesting
-{
-    /// <summary>
-    /// Snapshottable wall clock stopwatch.
-    /// </summary>
-    public class WallClockStopwatch
-    {
-        long startTicks;
-
-        public WallClockStopwatch()
-        {
-            this.startTicks = DateTime.UtcNow.Ticks;
-        }
-
-        public TimeSpan GetElapsedSnapshot(bool reset)
-        {
-            var utcNow = DateTime.UtcNow;
-
-            long oldStartTicks;
-            if (reset)
-            {
-                oldStartTicks = Interlocked.Exchange(ref this.startTicks, utcNow.Ticks);
-            }
-            else
-            {
-                oldStartTicks = this.startTicks;
-            }
-            return utcNow - new DateTime(oldStartTicks, DateTimeKind.Utc);
-        }
-    }
-}
diff --git a/src/csharp/Grpc.Microbenchmarks/CompletionRegistryBenchmark.cs b/src/csharp/Grpc.Microbenchmarks/CompletionRegistryBenchmark.cs
new file mode 100644
index 0000000..eefdb50
--- /dev/null
+++ b/src/csharp/Grpc.Microbenchmarks/CompletionRegistryBenchmark.cs
@@ -0,0 +1,78 @@
+#region Copyright notice and license
+
+// Copyright 2015 gRPC authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#endregion
+
+using System;
+using System.Runtime.InteropServices;
+using System.Threading;
+using Grpc.Core;
+using Grpc.Core.Internal;
+using System.Collections.Generic;
+using System.Diagnostics;
+
+namespace Grpc.Microbenchmarks
+{
+    public class CompletionRegistryBenchmark
+    {
+        GrpcEnvironment environment;
+
+        public void Init()
+        {
+            environment = GrpcEnvironment.AddRef();
+        }
+
+        public void Cleanup()
+        {
+            GrpcEnvironment.ReleaseAsync().Wait();
+        }
+
+        public void Run(int threadCount, int iterations, bool useSharedRegistry)
+        {
+            Console.WriteLine(string.Format("CompletionRegistryBenchmark: threads={0}, iterations={1}, useSharedRegistry={2}", threadCount, iterations, useSharedRegistry));
+            CompletionRegistry sharedRegistry = useSharedRegistry ? new CompletionRegistry(environment, () => BatchContextSafeHandle.Create()) : null;
+            var threadedBenchmark = new ThreadedBenchmark(threadCount, () => ThreadBody(iterations, sharedRegistry));
+            threadedBenchmark.Run();
+            // TODO: parametrize by number of pending completions
+        }
+
+        private void ThreadBody(int iterations, CompletionRegistry optionalSharedRegistry)
+        {
+            var completionRegistry = optionalSharedRegistry ?? new CompletionRegistry(environment, () => BatchContextSafeHandle.Create());
+            var ctx = BatchContextSafeHandle.Create();
+  
+            var stopwatch = Stopwatch.StartNew();
+            for (int i = 0; i < iterations; i++)
+            {
+                completionRegistry.Register(ctx.Handle, ctx);
+                var callback = completionRegistry.Extract(ctx.Handle);
+                // NOTE: we are not calling the callback to avoid disposing ctx.
+            }
+            stopwatch.Stop();
+            Console.WriteLine("Elapsed millis: " + stopwatch.ElapsedMilliseconds);          
+
+            ctx.Recycle();
+        }
+
+        private class NopCompletionCallback : IOpCompletionCallback
+        {
+            public void OnComplete(bool success)
+            {
+
+            }
+        }
+    }
+}
diff --git a/src/csharp/Grpc.Microbenchmarks/GCStats.cs b/src/csharp/Grpc.Microbenchmarks/GCStats.cs
new file mode 100644
index 0000000..ca7051e
--- /dev/null
+++ b/src/csharp/Grpc.Microbenchmarks/GCStats.cs
@@ -0,0 +1,69 @@
+#region Copyright notice and license
+
+// Copyright 2015 gRPC authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#endregion
+
+using System;
+using Grpc.Core;
+using Grpc.Core.Internal;
+
+namespace Grpc.Microbenchmarks
+{
+    internal class GCStats
+    {
+        readonly object myLock = new object();
+        GCStatsSnapshot lastSnapshot;
+
+        public GCStats()
+        {
+            lastSnapshot = new GCStatsSnapshot(GC.CollectionCount(0), GC.CollectionCount(1), GC.CollectionCount(2));
+        }
+
+        public GCStatsSnapshot GetSnapshot(bool reset = false)
+        {
+            lock (myLock)
+            {
+                var newSnapshot = new GCStatsSnapshot(GC.CollectionCount(0) - lastSnapshot.Gen0,
+                    GC.CollectionCount(1) - lastSnapshot.Gen1,
+                    GC.CollectionCount(2) - lastSnapshot.Gen2);
+                if (reset)
+                {
+                    lastSnapshot = newSnapshot;
+                }
+                return newSnapshot;
+            }
+        }
+    }
+
+    public class GCStatsSnapshot
+    {
+        public GCStatsSnapshot(int gen0, int gen1, int gen2)
+        {
+            this.Gen0 = gen0;
+            this.Gen1 = gen1;
+            this.Gen2 = gen2;
+        }
+
+        public int Gen0 { get; }
+        public int Gen1 { get; }
+        public int Gen2 { get; }
+
+        public override string ToString()
+        {
+            return string.Format("[GCCollectionCount: gen0 {0}, gen1 {1}, gen2 {2}]", Gen0, Gen1, Gen2);
+        }
+    }
+}
diff --git a/src/csharp/Grpc.Microbenchmarks/Grpc.Microbenchmarks.csproj b/src/csharp/Grpc.Microbenchmarks/Grpc.Microbenchmarks.csproj
index 108357e..8a629f9 100644
--- a/src/csharp/Grpc.Microbenchmarks/Grpc.Microbenchmarks.csproj
+++ b/src/csharp/Grpc.Microbenchmarks/Grpc.Microbenchmarks.csproj
@@ -15,6 +15,10 @@
     <ProjectReference Include="../Grpc.Core/Grpc.Core.csproj" />
   </ItemGroup>
 
+  <ItemGroup>
+    <PackageReference Include="CommandLineParser" Version="2.1.1-beta" />
+  </ItemGroup>
+
   <ItemGroup Condition=" '$(TargetFramework)' == 'net45' ">
     <Reference Include="System" />
     <Reference Include="Microsoft.CSharp" />
diff --git a/src/csharp/Grpc.Microbenchmarks/PInvokeByteArrayBenchmark.cs b/src/csharp/Grpc.Microbenchmarks/PInvokeByteArrayBenchmark.cs
new file mode 100644
index 0000000..787b550
--- /dev/null
+++ b/src/csharp/Grpc.Microbenchmarks/PInvokeByteArrayBenchmark.cs
@@ -0,0 +1,64 @@
+#region Copyright notice and license
+
+// Copyright 2015 gRPC authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#endregion
+
+using System;
+using System.Runtime.InteropServices;
+using System.Threading;
+using Grpc.Core;
+using Grpc.Core.Internal;
+using System.Collections.Generic;
+using System.Diagnostics;
+
+namespace Grpc.Microbenchmarks
+{
+    public class PInvokeByteArrayBenchmark
+    {
+        static readonly NativeMethods Native = NativeMethods.Get();
+
+        public void Init()
+        {
+        }
+
+        public void Cleanup()
+        {
+        }
+
+        public void Run(int threadCount, int iterations, int payloadSize)
+        {
+            Console.WriteLine(string.Format("PInvokeByteArrayBenchmark: threads={0}, iterations={1}, payloadSize={2}", threadCount, iterations, payloadSize));
+            var threadedBenchmark = new ThreadedBenchmark(threadCount, () => ThreadBody(iterations, payloadSize));
+            threadedBenchmark.Run();
+        }
+
+        private void ThreadBody(int iterations, int payloadSize)
+        {
+            var payload = new byte[payloadSize];
+         
+            var stopwatch = Stopwatch.StartNew();
+            for (int i = 0; i < iterations; i++)
+            {
+                var gcHandle = GCHandle.Alloc(payload, GCHandleType.Pinned);
+                var payloadPtr = gcHandle.AddrOfPinnedObject();
+                Native.grpcsharp_test_nop(payloadPtr);
+                gcHandle.Free();
+            }
+            stopwatch.Stop();
+            Console.WriteLine("Elapsed millis: " + stopwatch.ElapsedMilliseconds);
+        }
+    }
+}
diff --git a/src/csharp/Grpc.Microbenchmarks/Program.cs b/src/csharp/Grpc.Microbenchmarks/Program.cs
index d07d418..a64c297 100644
--- a/src/csharp/Grpc.Microbenchmarks/Program.cs
+++ b/src/csharp/Grpc.Microbenchmarks/Program.cs
@@ -20,14 +20,84 @@
 using Grpc.Core;
 using Grpc.Core.Internal;
 using Grpc.Core.Logging;
+using CommandLine;
+using CommandLine.Text;
 
 namespace Grpc.Microbenchmarks
 {
     class Program
     {
+        public enum MicrobenchmarkType
+        {
+            CompletionRegistry,
+            PInvokeByteArray,
+            SendMessage
+        }
+
+        private class BenchmarkOptions
+        {
+            [Option("benchmark", Required = true, HelpText = "Benchmark to run")]
+            public MicrobenchmarkType Benchmark { get; set; }
+        }
+
         public static void Main(string[] args)
         {
             GrpcEnvironment.SetLogger(new ConsoleLogger());
+            var parserResult = Parser.Default.ParseArguments<BenchmarkOptions>(args)
+                .WithNotParsed(errors => {
+                    Console.WriteLine("Supported benchmarks:");
+                    foreach (var enumValue in Enum.GetValues(typeof(MicrobenchmarkType)))
+                    {
+                        Console.WriteLine("  " + enumValue);
+                    }
+                    Environment.Exit(1);
+                })
+                .WithParsed(options =>
+                {
+                    switch (options.Benchmark)
+                    {
+                        case MicrobenchmarkType.CompletionRegistry:
+                          RunCompletionRegistryBenchmark();
+                          break;
+                        case MicrobenchmarkType.PInvokeByteArray:
+                          RunPInvokeByteArrayBenchmark();
+                          break;
+                        case MicrobenchmarkType.SendMessage:
+                          RunSendMessageBenchmark();
+                          break;
+                        default:
+                          throw new ArgumentException("Unsupported benchmark.");
+                    }
+                });
+        }
+
+        static void RunCompletionRegistryBenchmark()
+        {
+            var benchmark = new CompletionRegistryBenchmark();
+            benchmark.Init();
+            foreach (int threadCount in new int[] {1, 1, 2, 4, 8, 12})
+            {
+                foreach (bool useSharedRegistry in new bool[] {false, true})
+                {
+                    benchmark.Run(threadCount, 4 * 1000 * 1000, useSharedRegistry);
+                }
+            }
+            benchmark.Cleanup();
+        }
+
+        static void RunPInvokeByteArrayBenchmark()
+        {
+            var benchmark = new PInvokeByteArrayBenchmark();
+            benchmark.Init();
+            foreach (int threadCount in new int[] {1, 1, 2, 4, 8, 12})
+            {
+                benchmark.Run(threadCount, 4 * 1000 * 1000, 0);
+            }
+            benchmark.Cleanup();
+        }
+
+        static void RunSendMessageBenchmark()
+        {
             var benchmark = new SendMessageBenchmark();
             benchmark.Init();
             foreach (int threadCount in new int[] {1, 1, 2, 4, 8, 12})
diff --git a/src/csharp/Grpc.Microbenchmarks/SendMessageBenchmark.cs b/src/csharp/Grpc.Microbenchmarks/SendMessageBenchmark.cs
index de67874..da4f35f 100644
--- a/src/csharp/Grpc.Microbenchmarks/SendMessageBenchmark.cs
+++ b/src/csharp/Grpc.Microbenchmarks/SendMessageBenchmark.cs
@@ -52,23 +52,20 @@
 
         private void ThreadBody(int iterations, int payloadSize)
         {
-            // TODO(jtattermusch): parametrize by number of pending completions.
-            // TODO(jtattermusch): parametrize by cached/non-cached BatchContextSafeHandle
-
-            var completionRegistry = new CompletionRegistry(environment);
+            var completionRegistry = new CompletionRegistry(environment, () => environment.BatchContextPool.Lease());
             var cq = CompletionQueueSafeHandle.CreateAsync(completionRegistry);
             var call = CreateFakeCall(cq);
 
-            var sendCompletionHandler = new SendCompletionHandler((success) => { });
+            var sendCompletionCallback = new NopSendCompletionCallback();
             var payload = new byte[payloadSize];
             var writeFlags = default(WriteFlags);
 
             var stopwatch = Stopwatch.StartNew();
             for (int i = 0; i < iterations; i++)
             {
-                call.StartSendMessage(sendCompletionHandler, payload, writeFlags, false);
+                call.StartSendMessage(sendCompletionCallback, payload, writeFlags, false);
                 var callback = completionRegistry.Extract(completionRegistry.LastRegisteredKey);
-                callback(true);
+                callback.OnComplete(true);
             }
             stopwatch.Stop();
             Console.WriteLine("Elapsed millis: " + stopwatch.ElapsedMilliseconds);
@@ -87,5 +84,13 @@
             }
             return call;
         }
+
+        private class NopSendCompletionCallback : ISendCompletionCallback
+        {
+            public void OnSendCompletion(bool success)
+            {
+                // NOP
+            }
+        }
     }
 }
diff --git a/src/csharp/Grpc.Microbenchmarks/ThreadedBenchmark.cs b/src/csharp/Grpc.Microbenchmarks/ThreadedBenchmark.cs
index feac8d1..95b9aaa 100644
--- a/src/csharp/Grpc.Microbenchmarks/ThreadedBenchmark.cs
+++ b/src/csharp/Grpc.Microbenchmarks/ThreadedBenchmark.cs
@@ -46,6 +46,7 @@
         public void Run()
         {
             Console.WriteLine("Running threads.");
+            var gcStats = new GCStats();
             var threads = new List<Thread>();
             for (int i = 0; i < runners.Count; i++)
             {
@@ -58,7 +59,7 @@
             {
                 thread.Join();
             }
-            Console.WriteLine("All threads finished.");
+            Console.WriteLine("All threads finished (GC Stats Delta: " + gcStats.GetSnapshot() + ")");
         }
     }
 }
diff --git a/src/csharp/build_packages_dotnetcli.bat b/src/csharp/build_packages_dotnetcli.bat
index ff013d5..8f89e28 100755
--- a/src/csharp/build_packages_dotnetcli.bat
+++ b/src/csharp/build_packages_dotnetcli.bat
@@ -13,7 +13,7 @@
 @rem limitations under the License.
 
 @rem Current package versions
-set VERSION=1.8.0-dev
+set VERSION=1.9.0-dev
 
 @rem Adjust the location of nuget.exe
 set NUGET=C:\nuget\nuget.exe
diff --git a/src/csharp/build_packages_dotnetcli.sh b/src/csharp/build_packages_dotnetcli.sh
index 44a4791..6a6cafe 100755
--- a/src/csharp/build_packages_dotnetcli.sh
+++ b/src/csharp/build_packages_dotnetcli.sh
@@ -39,7 +39,7 @@
 dotnet pack --configuration Release Grpc.HealthCheck --output ../../../artifacts
 dotnet pack --configuration Release Grpc.Reflection --output ../../../artifacts
 
-nuget pack Grpc.nuspec -Version "1.8.0-dev" -OutputDirectory ../../artifacts
-nuget pack Grpc.Tools.nuspec -Version "1.8.0-dev" -OutputDirectory ../../artifacts
+nuget pack Grpc.nuspec -Version "1.9.0-dev" -OutputDirectory ../../artifacts
+nuget pack Grpc.Tools.nuspec -Version "1.9.0-dev" -OutputDirectory ../../artifacts
 
 (cd ../../artifacts && zip csharp_nugets_dotnetcli.zip *.nupkg)
diff --git a/src/csharp/ext/grpc_csharp_ext.c b/src/csharp/ext/grpc_csharp_ext.c
index bcb3bfa..24d779e 100644
--- a/src/csharp/ext/grpc_csharp_ext.c
+++ b/src/csharp/ext/grpc_csharp_ext.c
@@ -197,10 +197,7 @@
 }
 
 GPR_EXPORT void GPR_CALLTYPE
-grpcsharp_batch_context_destroy(grpcsharp_batch_context* ctx) {
-  if (!ctx) {
-    return;
-  }
+grpcsharp_batch_context_reset(grpcsharp_batch_context* ctx) {
   grpcsharp_metadata_array_destroy_metadata_including_entries(
       &(ctx->send_initial_metadata));
 
@@ -216,7 +213,15 @@
   grpcsharp_metadata_array_destroy_metadata_only(
       &(ctx->recv_status_on_client.trailing_metadata));
   grpc_slice_unref(ctx->recv_status_on_client.status_details);
+  memset(ctx, 0, sizeof(grpcsharp_batch_context));
+}
 
+GPR_EXPORT void GPR_CALLTYPE
+grpcsharp_batch_context_destroy(grpcsharp_batch_context* ctx) {
+  if (!ctx) {
+    return;
+  }
+  grpcsharp_batch_context_reset(ctx);
   gpr_free(ctx);
 }
 
diff --git a/src/csharp/tests.json b/src/csharp/tests.json
index 7841051..82573ed 100644
--- a/src/csharp/tests.json
+++ b/src/csharp/tests.json
@@ -5,11 +5,13 @@
     "Grpc.Core.Internal.Tests.ChannelArgsSafeHandleTest",
     "Grpc.Core.Internal.Tests.CompletionQueueEventTest",
     "Grpc.Core.Internal.Tests.CompletionQueueSafeHandleTest",
+    "Grpc.Core.Internal.Tests.DefaultObjectPoolTest",
     "Grpc.Core.Internal.Tests.MetadataArraySafeHandleTest",
     "Grpc.Core.Internal.Tests.TimespecTest",
     "Grpc.Core.Tests.AppDomainUnloadTest",
     "Grpc.Core.Tests.AuthContextTest",
     "Grpc.Core.Tests.AuthPropertyTest",
+    "Grpc.Core.Tests.CallCancellationTest",
     "Grpc.Core.Tests.CallCredentialsTest",
     "Grpc.Core.Tests.CallOptionsTest",
     "Grpc.Core.Tests.ChannelCredentialsTest",
diff --git a/src/node/health_check/package.json b/src/node/health_check/package.json
new file mode 100644
index 0000000..fca3a2a
--- /dev/null
+++ b/src/node/health_check/package.json
@@ -0,0 +1,29 @@
+{
+  "name": "grpc-health-check",
+  "version": "1.7.2",
+  "author": "Google Inc.",
+  "description": "Health check service for use with gRPC",
+  "repository": {
+    "type": "git",
+    "url": "https://github.com/grpc/grpc.git"
+  },
+  "bugs": "https://github.com/grpc/grpc/issues",
+  "contributors": [
+    {
+      "name": "Michael Lumish",
+      "email": "mlumish@google.com"
+    }
+  ],
+  "dependencies": {
+    "grpc": "^1.7.2",
+    "lodash": "^3.9.3",
+    "google-protobuf": "^3.0.0"
+  },
+  "files": [
+    "LICENSE",
+    "health.js",
+    "v1"
+  ],
+  "main": "src/node/index.js",
+  "license": "Apache-2.0"
+}
diff --git a/src/node/tools/package.json b/src/node/tools/package.json
new file mode 100644
index 0000000..99fd854
--- /dev/null
+++ b/src/node/tools/package.json
@@ -0,0 +1,41 @@
+{
+  "name": "grpc-tools",
+  "version": "1.7.2",
+  "author": "Google Inc.",
+  "description": "Tools for developing with gRPC on Node.js",
+  "homepage": "https://grpc.io/",
+  "repository": {
+    "type": "git",
+    "url": "https://github.com/grpc/grpc.git"
+  },
+  "bugs": "https://github.com/grpc/grpc/issues",
+  "contributors": [
+    {
+      "name": "Michael Lumish",
+      "email": "mlumish@google.com"
+    }
+  ],
+  "bin": {
+    "grpc_tools_node_protoc": "./bin/protoc.js",
+    "grpc_tools_node_protoc_plugin": "./bin/protoc_plugin.js"
+  },
+  "scripts": {
+    "install": "./node_modules/.bin/node-pre-gyp install"
+  },
+  "bundledDependencies": ["node-pre-gyp"],
+  "binary": {
+    "module_name": "grpc_tools",
+    "host": "https://storage.googleapis.com/",
+    "remote_path": "grpc-precompiled-binaries/node/{name}/v{version}",
+    "package_name": "{platform}-{arch}.tar.gz",
+    "module_path": "bin"
+  },
+  "files": [
+    "index.js",
+    "bin/protoc.js",
+    "bin/protoc_plugin.js",
+    "bin/google/protobuf",
+    "LICENSE"
+  ],
+  "main": "index.js"
+}
diff --git "a/src/objective-c/\041ProtoCompiler-gRPCPlugin.podspec" "b/src/objective-c/\041ProtoCompiler-gRPCPlugin.podspec"
index 9065ab9..2250176 100644
--- "a/src/objective-c/\041ProtoCompiler-gRPCPlugin.podspec"
+++ "b/src/objective-c/\041ProtoCompiler-gRPCPlugin.podspec"
@@ -42,7 +42,7 @@
   # 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.8.0-dev'
+  v = '1.9.0-dev'
   s.version  = v
   s.summary  = 'The gRPC ProtoC plugin generates Objective-C files from .proto services.'
   s.description = <<-DESC
@@ -101,7 +101,7 @@
   s.preserve_paths = plugin
 
   # Restrict the protoc version to the one supported by this plugin.
-  s.dependency '!ProtoCompiler', '3.4.0'
+  s.dependency '!ProtoCompiler', '3.5.0'
   # For the Protobuf dependency not to complain:
   s.ios.deployment_target = '7.0'
   s.osx.deployment_target = '10.9'
diff --git "a/src/objective-c/\041ProtoCompiler.podspec" "b/src/objective-c/\041ProtoCompiler.podspec"
index 25c4379..12598e6 100644
--- "a/src/objective-c/\041ProtoCompiler.podspec"
+++ "b/src/objective-c/\041ProtoCompiler.podspec"
@@ -36,7 +36,7 @@
   # exclamation mark ensures that other "regular" pods will be able to find it as it'll be installed
   # before them.
   s.name     = '!ProtoCompiler'
-  v = '3.4.0'
+  v = '3.5.0'
   s.version  = v
   s.summary  = 'The Protobuf Compiler (protoc) generates Objective-C files from .proto files'
   s.description = <<-DESC
diff --git a/src/objective-c/GRPCClient/GRPCCall.m b/src/objective-c/GRPCClient/GRPCCall.m
index b5ab611..ac4596d 100644
--- a/src/objective-c/GRPCClient/GRPCCall.m
+++ b/src/objective-c/GRPCClient/GRPCCall.m
@@ -299,7 +299,7 @@
 // network queue if the write didn't succeed.
 // If the call is a unary call, parameter \a errorHandler will be ignored and
 // the error handler of GRPCOpSendClose will be executed in case of error.
-- (void)writeMessage:(NSData *)message withErrorHandler:(void (^)())errorHandler {
+- (void)writeMessage:(NSData *)message withErrorHandler:(void (^)(void))errorHandler {
 
   __weak GRPCCall *weakSelf = self;
   void(^resumingHandler)(void) = ^{
@@ -345,7 +345,7 @@
 
 // Only called from the call queue. The error handler will be called from the
 // network queue if the requests stream couldn't be closed successfully.
-- (void)finishRequestWithErrorHandler:(void (^)())errorHandler {
+- (void)finishRequestWithErrorHandler:(void (^)(void))errorHandler {
   if (!_unaryCall) {
     [_wrappedCall startBatchWithOperations:@[[[GRPCOpSendClose alloc] init]]
                               errorHandler:errorHandler];
@@ -441,7 +441,7 @@
   }
   _connectivityMonitor = [GRPCConnectivityMonitor monitorWithHost:host];
   __weak typeof(self) weakSelf = self;
-  void (^handler)() = ^{
+  void (^handler)(void) = ^{
     typeof(self) strongSelf = weakSelf;
     [strongSelf finishWithError:[NSError errorWithDomain:kGRPCErrorDomain
                                                     code:GRPCErrorCodeUnavailable
diff --git a/src/objective-c/GRPCClient/private/GRPCConnectivityMonitor.h b/src/objective-c/GRPCClient/private/GRPCConnectivityMonitor.h
index 8d3c45e..cb55e46 100644
--- a/src/objective-c/GRPCClient/private/GRPCConnectivityMonitor.h
+++ b/src/objective-c/GRPCClient/private/GRPCConnectivityMonitor.h
@@ -57,6 +57,6 @@
  * Only one handler is active at a time, so if this method is called again before the previous
  * handler has been called, it might never be called at all (or yes, if it has already been queued).
  */
-- (void)handleLossWithHandler:(nullable void (^)())lossHandler
-      wifiStatusChangeHandler:(nullable void (^)())wifiStatusChangeHandler;
+- (void)handleLossWithHandler:(nullable void (^)(void))lossHandler
+      wifiStatusChangeHandler:(nullable void (^)(void))wifiStatusChangeHandler;
 @end
diff --git a/src/objective-c/GRPCClient/private/GRPCConnectivityMonitor.m b/src/objective-c/GRPCClient/private/GRPCConnectivityMonitor.m
index b322638..c8e10dd 100644
--- a/src/objective-c/GRPCClient/private/GRPCConnectivityMonitor.m
+++ b/src/objective-c/GRPCClient/private/GRPCConnectivityMonitor.m
@@ -136,8 +136,8 @@
   return returnValue;
 }
 
-- (void)handleLossWithHandler:(nullable void (^)())lossHandler
-      wifiStatusChangeHandler:(nullable void (^)())wifiStatusChangeHandler {
+- (void)handleLossWithHandler:(nullable void (^)(void))lossHandler
+      wifiStatusChangeHandler:(nullable void (^)(void))wifiStatusChangeHandler {
   __weak typeof(self) weakSelf = self;
   [self startListeningWithHandler:^(GRPCReachabilityFlags *flags) {
     typeof(self) strongSelf = weakSelf;
diff --git a/src/objective-c/GRPCClient/private/GRPCHost.m b/src/objective-c/GRPCClient/private/GRPCHost.m
index f73e9cb..a0f4118 100644
--- a/src/objective-c/GRPCClient/private/GRPCHost.m
+++ b/src/objective-c/GRPCClient/private/GRPCHost.m
@@ -93,7 +93,7 @@
     if (!connectivityMonitor) {
       connectivityMonitor =
       [GRPCConnectivityMonitor monitorWithHost:hostURL.host];
-      void (^handler)() = ^{
+      void (^handler)(void) = ^{
         [GRPCHost flushChannelCache];
       };
       [connectivityMonitor handleLossWithHandler:handler
diff --git a/src/objective-c/GRPCClient/private/GRPCWrappedCall.h b/src/objective-c/GRPCClient/private/GRPCWrappedCall.h
index 1cd9da8..f569895 100644
--- a/src/objective-c/GRPCClient/private/GRPCWrappedCall.h
+++ b/src/objective-c/GRPCClient/private/GRPCWrappedCall.h
@@ -30,24 +30,24 @@
 @interface GRPCOpSendMetadata : GRPCOperation
 
 - (instancetype)initWithMetadata:(NSDictionary *)metadata
-                         handler:(void(^)())handler;
+                         handler:(void(^)(void))handler;
 
 - (instancetype)initWithMetadata:(NSDictionary *)metadata
                            flags:(uint32_t)flags
-                         handler:(void(^)())handler NS_DESIGNATED_INITIALIZER;
+                         handler:(void(^)(void))handler NS_DESIGNATED_INITIALIZER;
 
 @end
 
 @interface GRPCOpSendMessage : GRPCOperation
 
 - (instancetype)initWithMessage:(NSData *)message
-                        handler:(void(^)())handler NS_DESIGNATED_INITIALIZER;
+                        handler:(void(^)(void))handler NS_DESIGNATED_INITIALIZER;
 
 @end
 
 @interface GRPCOpSendClose : GRPCOperation
 
-- (instancetype)initWithHandler:(void(^)())handler NS_DESIGNATED_INITIALIZER;
+- (instancetype)initWithHandler:(void(^)(void))handler NS_DESIGNATED_INITIALIZER;
 
 @end
 
@@ -79,7 +79,7 @@
                         path:(NSString *)path
                      timeout:(NSTimeInterval)timeout NS_DESIGNATED_INITIALIZER;
 
-- (void)startBatchWithOperations:(NSArray *)ops errorHandler:(void(^)())errorHandler;
+- (void)startBatchWithOperations:(NSArray *)ops errorHandler:(void(^)(void))errorHandler;
 
 - (void)startBatchWithOperations:(NSArray *)ops;
 
diff --git a/src/objective-c/GRPCClient/private/GRPCWrappedCall.m b/src/objective-c/GRPCClient/private/GRPCWrappedCall.m
index b0b1223..d26d134 100644
--- a/src/objective-c/GRPCClient/private/GRPCWrappedCall.m
+++ b/src/objective-c/GRPCClient/private/GRPCWrappedCall.m
@@ -36,12 +36,12 @@
   // Most operation subclasses don't set any flags in the grpc_op, and rely on the flag member being
   // initialized to zero.
   grpc_op _op;
-  void(^_handler)();
+  void(^_handler)(void);
 }
 
 - (void)finish {
   if (_handler) {
-    void(^handler)() = _handler;
+    void(^handler)(void) = _handler;
     _handler = nil;
     handler();
   }
@@ -55,13 +55,13 @@
 }
 
 - (instancetype)initWithMetadata:(NSDictionary *)metadata
-                         handler:(void (^)())handler {
+                         handler:(void (^)(void))handler {
   return [self initWithMetadata:metadata flags:0 handler:handler];
 }
 
 - (instancetype)initWithMetadata:(NSDictionary *)metadata
                            flags:(uint32_t)flags
-                         handler:(void (^)())handler {
+                         handler:(void (^)(void))handler {
   if (self = [super init]) {
     _op.op = GRPC_OP_SEND_INITIAL_METADATA;
     _op.data.send_initial_metadata.count = metadata.count;
@@ -92,7 +92,7 @@
   return [self initWithMessage:nil handler:nil];
 }
 
-- (instancetype)initWithMessage:(NSData *)message handler:(void (^)())handler {
+- (instancetype)initWithMessage:(NSData *)message handler:(void (^)(void))handler {
   if (!message) {
     [NSException raise:NSInvalidArgumentException format:@"message cannot be nil"];
   }
@@ -116,7 +116,7 @@
   return [self initWithHandler:nil];
 }
 
-- (instancetype)initWithHandler:(void (^)())handler {
+- (instancetype)initWithHandler:(void (^)(void))handler {
   if (self = [super init]) {
     _op.op = GRPC_OP_SEND_CLOSE_FROM_CLIENT;
     _handler = handler;
@@ -271,7 +271,7 @@
   [self startBatchWithOperations:operations errorHandler:nil];
 }
 
-- (void)startBatchWithOperations:(NSArray *)operations errorHandler:(void (^)())errorHandler {
+- (void)startBatchWithOperations:(NSArray *)operations errorHandler:(void (^)(void))errorHandler {
   // Keep logs of op batches when we are running tests. Disabled when in production for improved
   // performance.
 #ifdef GRPC_TEST_OBJC
diff --git a/src/objective-c/GRPCClient/private/version.h b/src/objective-c/GRPCClient/private/version.h
index db589d1..69dd626 100644
--- a/src/objective-c/GRPCClient/private/version.h
+++ b/src/objective-c/GRPCClient/private/version.h
@@ -23,4 +23,4 @@
 // `tools/buildgen/generate_projects.sh`.
 
 
-#define GRPC_OBJC_VERSION_STRING @"1.8.0-dev"
+#define GRPC_OBJC_VERSION_STRING @"1.9.0-dev"
diff --git a/src/objective-c/RxLibrary/GRXConcurrentWriteable.h b/src/objective-c/RxLibrary/GRXConcurrentWriteable.h
index cec45fa..f16a3d0 100644
--- a/src/objective-c/RxLibrary/GRXConcurrentWriteable.h
+++ b/src/objective-c/RxLibrary/GRXConcurrentWriteable.h
@@ -46,7 +46,7 @@
  * Enqueues writeValue: to be sent to the writeable in the main thread.
  * The passed handler is invoked from the main thread after writeValue: returns.
  */
-- (void)enqueueValue:(id)value completionHandler:(void (^)())handler;
+- (void)enqueueValue:(id)value completionHandler:(void (^)(void))handler;
 
 /**
  * Enqueues writesFinishedWithError:nil to be sent to the writeable in the main thread. After that
diff --git a/src/objective-c/RxLibrary/GRXConcurrentWriteable.m b/src/objective-c/RxLibrary/GRXConcurrentWriteable.m
index bbfe491..37bc975 100644
--- a/src/objective-c/RxLibrary/GRXConcurrentWriteable.m
+++ b/src/objective-c/RxLibrary/GRXConcurrentWriteable.m
@@ -50,7 +50,7 @@
                    dispatchQueue:dispatch_get_main_queue()];
 }
 
-- (void)enqueueValue:(id)value completionHandler:(void (^)())handler {
+- (void)enqueueValue:(id)value completionHandler:(void (^)(void))handler {
   dispatch_async(_writeableQueue, ^{
     // We're racing a possible cancellation performed by another thread. To turn all already-
     // enqueued messages into noops, cancellation nillifies the writeable property. If we get it
diff --git a/src/objective-c/RxLibrary/GRXImmediateWriter.h b/src/objective-c/RxLibrary/GRXImmediateWriter.h
index bdcf5d5..f88e46b 100644
--- a/src/objective-c/RxLibrary/GRXImmediateWriter.h
+++ b/src/objective-c/RxLibrary/GRXImmediateWriter.h
@@ -46,7 +46,7 @@
  * Returns a writer that pushes to its writeable the successive values returned by the passed
  * block. When the block first returns nil, it is released.
  */
-+ (GRXWriter *)writerWithValueSupplier:(id (^)())block;
++ (GRXWriter *)writerWithValueSupplier:(id (^)(void))block;
 
 /**
  * Returns a writer that iterates over the values of the passed container and pushes them to
diff --git a/src/objective-c/RxLibrary/GRXImmediateWriter.m b/src/objective-c/RxLibrary/GRXImmediateWriter.m
index d8c6975..c5d6d13 100644
--- a/src/objective-c/RxLibrary/GRXImmediateWriter.m
+++ b/src/objective-c/RxLibrary/GRXImmediateWriter.m
@@ -52,7 +52,7 @@
   return [self writerWithEnumerator:enumerator error:nil];
 }
 
-+ (GRXWriter *)writerWithValueSupplier:(id (^)())block {
++ (GRXWriter *)writerWithValueSupplier:(id (^)(void))block {
   return [self writerWithEnumerator:[NSEnumerator grx_enumeratorWithValueSupplier:block]];
 }
 
diff --git a/src/objective-c/RxLibrary/GRXWriter+Immediate.h b/src/objective-c/RxLibrary/GRXWriter+Immediate.h
index 292a35f..d7935de 100644
--- a/src/objective-c/RxLibrary/GRXWriter+Immediate.h
+++ b/src/objective-c/RxLibrary/GRXWriter+Immediate.h
@@ -30,7 +30,7 @@
  * Returns a writer that pushes to its writeable the successive values returned by the passed
  * block. When the block first returns nil, it is released.
  */
-+ (instancetype)writerWithValueSupplier:(id (^)())block;
++ (instancetype)writerWithValueSupplier:(id (^)(void))block;
 
 /**
  * Returns a writer that iterates over the values of the passed container and pushes them to
diff --git a/src/objective-c/RxLibrary/GRXWriter+Immediate.m b/src/objective-c/RxLibrary/GRXWriter+Immediate.m
index 43aa9c5..a36a567 100644
--- a/src/objective-c/RxLibrary/GRXWriter+Immediate.m
+++ b/src/objective-c/RxLibrary/GRXWriter+Immediate.m
@@ -27,7 +27,7 @@
   return [GRXImmediateWriter writerWithEnumerator:enumerator];
 }
 
-+ (instancetype)writerWithValueSupplier:(id (^)())block {
++ (instancetype)writerWithValueSupplier:(id (^)(void))block {
   return [GRXImmediateWriter writerWithValueSupplier:block];
 }
 
diff --git a/src/objective-c/RxLibrary/NSEnumerator+GRXUtil.h b/src/objective-c/RxLibrary/NSEnumerator+GRXUtil.h
index 8c72f78..38dbaaf 100644
--- a/src/objective-c/RxLibrary/NSEnumerator+GRXUtil.h
+++ b/src/objective-c/RxLibrary/NSEnumerator+GRXUtil.h
@@ -38,5 +38,5 @@
  * Returns a NSEnumerator instance that delegates the invocations of nextObject to the passed block.
  * When the block first returns nil, it is released.
  */
-+ (NSEnumerator *)grx_enumeratorWithValueSupplier:(id (^)())block;
++ (NSEnumerator *)grx_enumeratorWithValueSupplier:(id (^)(void))block;
 @end
diff --git a/src/objective-c/RxLibrary/NSEnumerator+GRXUtil.m b/src/objective-c/RxLibrary/NSEnumerator+GRXUtil.m
index 309e25e..7d8191d 100644
--- a/src/objective-c/RxLibrary/NSEnumerator+GRXUtil.m
+++ b/src/objective-c/RxLibrary/NSEnumerator+GRXUtil.m
@@ -33,7 +33,7 @@
   return [[GRXNSScalarEnumerator alloc] initWithValue:value];
 }
 
-+ (NSEnumerator *)grx_enumeratorWithValueSupplier:(id (^)())block {
++ (NSEnumerator *)grx_enumeratorWithValueSupplier:(id (^)(void))block {
   return [[GRXNSBlockEnumerator alloc] initWithValueSupplier:block];
 }
 @end
diff --git a/src/objective-c/RxLibrary/private/GRXNSBlockEnumerator.h b/src/objective-c/RxLibrary/private/GRXNSBlockEnumerator.h
index c45338a..c3317b2 100644
--- a/src/objective-c/RxLibrary/private/GRXNSBlockEnumerator.h
+++ b/src/objective-c/RxLibrary/private/GRXNSBlockEnumerator.h
@@ -27,5 +27,5 @@
  * The first time the passed block returns nil, the enumeration will end and the block will be
  * released.
  */
-- (instancetype)initWithValueSupplier:(id (^)())block;
+- (instancetype)initWithValueSupplier:(id (^)(void))block;
 @end
diff --git a/src/objective-c/RxLibrary/private/GRXNSBlockEnumerator.m b/src/objective-c/RxLibrary/private/GRXNSBlockEnumerator.m
index 7e7cc57..eddfd26 100644
--- a/src/objective-c/RxLibrary/private/GRXNSBlockEnumerator.m
+++ b/src/objective-c/RxLibrary/private/GRXNSBlockEnumerator.m
@@ -19,14 +19,14 @@
 #import "GRXNSBlockEnumerator.h"
 
 @implementation GRXNSBlockEnumerator {
-  id (^_block)();
+  id (^_block)(void);
 }
 
 - (instancetype)init {
   return [self initWithValueSupplier:nil];
 }
 
-- (instancetype)initWithValueSupplier:(id (^)())block {
+- (instancetype)initWithValueSupplier:(id (^)(void))block {
   if ((self = [super init])) {
     _block = block;
   }
diff --git a/src/objective-c/tests/CoreCronetEnd2EndTests/CoreCronetEnd2EndTests.m b/src/objective-c/tests/CoreCronetEnd2EndTests/CoreCronetEnd2EndTests.mm
similarity index 74%
rename from src/objective-c/tests/CoreCronetEnd2EndTests/CoreCronetEnd2EndTests.m
rename to src/objective-c/tests/CoreCronetEnd2EndTests/CoreCronetEnd2EndTests.mm
index 453b075..d5e668a 100644
--- a/src/objective-c/tests/CoreCronetEnd2EndTests/CoreCronetEnd2EndTests.m
+++ b/src/objective-c/tests/CoreCronetEnd2EndTests/CoreCronetEnd2EndTests.mm
@@ -58,7 +58,7 @@
   grpc_end2end_test_fixture f;
   int port = grpc_pick_unused_port_or_die();
   fullstack_secure_fixture_data *ffd =
-      gpr_malloc(sizeof(fullstack_secure_fixture_data));
+      (fullstack_secure_fixture_data*)gpr_malloc(sizeof(fullstack_secure_fixture_data));
   memset(&f, 0, sizeof(f));
 
   gpr_join_host_port(&ffd->localaddr, "127.0.0.1", port);
@@ -81,7 +81,7 @@
 static void cronet_init_client_secure_fullstack(grpc_end2end_test_fixture *f,
                                                 grpc_channel_args *client_args,
                                                 stream_engine *cronetEngine) {
-  fullstack_secure_fixture_data *ffd = f->fixture_data;
+  fullstack_secure_fixture_data *ffd = (fullstack_secure_fixture_data *)f->fixture_data;
   f->client = grpc_cronet_secure_channel_create(cronetEngine, ffd->localaddr,
                                                 client_args, NULL);
   GPR_ASSERT(f->client != NULL);
@@ -90,7 +90,7 @@
 static void chttp2_init_server_secure_fullstack(
     grpc_end2end_test_fixture *f, grpc_channel_args *server_args,
     grpc_server_credentials *server_creds) {
-  fullstack_secure_fixture_data *ffd = f->fixture_data;
+  fullstack_secure_fixture_data *ffd = (fullstack_secure_fixture_data *)f->fixture_data;
   if (f->server) {
     grpc_server_destroy(f->server);
   }
@@ -103,7 +103,7 @@
 }
 
 static void chttp2_tear_down_secure_fullstack(grpc_end2end_test_fixture *f) {
-  fullstack_secure_fixture_data *ffd = f->fixture_data;
+  fullstack_secure_fixture_data *ffd = (fullstack_secure_fixture_data *)f->fixture_data;
   gpr_free(ffd->localaddr);
   gpr_free(ffd);
 }
@@ -171,7 +171,7 @@
   FILE *roots_file;
   size_t roots_size = strlen(test_root_cert);
 
-  char *argv[] = {"CoreCronetEnd2EndTests"};
+  char *argv[] = {(char *)"CoreCronetEnd2EndTests"};
   grpc_test_init(1, argv);
   grpc_end2end_tests_pre_init();
 
@@ -207,7 +207,7 @@
 }
 
 - (void)testIndividualCase:(char *)test_case {
-  char *argv[] = {"h2_ssl", test_case};
+  char *argv[] = {(char *)"h2_ssl", test_case};
 
   for (int i = 0; i < sizeof(configs) / sizeof(*configs); i++) {
     grpc_end2end_tests(sizeof(argv) / sizeof(argv[0]), argv, configs[i]);
@@ -217,182 +217,182 @@
 // TODO(mxyan): Use NSStringFromSelector(_cmd) to acquire test name from the
 // test case method name, so that bodies of test cases can stay identical
 - (void)testAuthorityNotSupported {
-  [self testIndividualCase:"authority_not_supported"];
+  [self testIndividualCase:(char *)"authority_not_supported"];
 }
 
 - (void)testBadHostname {
-  [self testIndividualCase:"bad_hostname"];
+  [self testIndividualCase:(char *)"bad_hostname"];
 }
 
 - (void)testBinaryMetadata {
   // NOT SUPPORTED
-  //[self testIndividualCase:"binary_metadata"];
+  //[self testIndividualCase:(char *)"binary_metadata"];
 }
 
 - (void)testCallCreds {
   // NOT SUPPORTED
-  // [self testIndividualCase:"call_creds"];
+  // [self testIndividualCase:(char *)"call_creds"];
 }
 
 - (void)testCancelAfterAccept {
-  [self testIndividualCase:"cancel_after_accept"];
+  [self testIndividualCase:(char *)"cancel_after_accept"];
 }
 
 - (void)testCancelAfterClientDone {
-  [self testIndividualCase:"cancel_after_client_done"];
+  [self testIndividualCase:(char *)"cancel_after_client_done"];
 }
 
 - (void)testCancelAfterInvoke {
-  [self testIndividualCase:"cancel_after_invoke"];
+  [self testIndividualCase:(char *)"cancel_after_invoke"];
 }
 
 - (void)testCancelAfterRoundTrip {
-  [self testIndividualCase:"cancel_after_round_trip"];
+  [self testIndividualCase:(char *)"cancel_after_round_trip"];
 }
 
 - (void)testCancelBeforeInvoke {
-  [self testIndividualCase:"cancel_before_invoke"];
+  [self testIndividualCase:(char *)"cancel_before_invoke"];
 }
 
 - (void)testCancelInAVacuum {
-  [self testIndividualCase:"cancel_in_a_vacuum"];
+  [self testIndividualCase:(char *)"cancel_in_a_vacuum"];
 }
 
 - (void)testCancelWithStatus {
-  [self testIndividualCase:"cancel_with_status"];
+  [self testIndividualCase:(char *)"cancel_with_status"];
 }
 
 - (void)testCompressedPayload {
-  [self testIndividualCase:"compressed_payload"];
+  [self testIndividualCase:(char *)"compressed_payload"];
 }
 
 - (void)testConnectivity {
   // NOT SUPPORTED
-  // [self testIndividualCase:"connectivity"];
+  // [self testIndividualCase:(char *)"connectivity"];
 }
 
 - (void)testDefaultHost {
-  [self testIndividualCase:"default_host"];
+  [self testIndividualCase:(char *)"default_host"];
 }
 
 - (void)testDisappearingServer {
-  [self testIndividualCase:"disappearing_server"];
+  [self testIndividualCase:(char *)"disappearing_server"];
 }
 
 - (void)testEmptyBatch {
-  [self testIndividualCase:"empty_batch"];
+  [self testIndividualCase:(char *)"empty_batch"];
 }
 
 - (void)testFilterCausesClose {
   // NOT SUPPORTED
-  // [self testIndividualCase:"filter_causes_close"];
+  // [self testIndividualCase:(char *)"filter_causes_close"];
 }
 
 - (void)testGracefulServerShutdown {
-  [self testIndividualCase:"graceful_server_shutdown"];
+  [self testIndividualCase:(char *)"graceful_server_shutdown"];
 }
 
 - (void)testHighInitialSeqno {
-  [self testIndividualCase:"high_initial_seqno"];
+  [self testIndividualCase:(char *)"high_initial_seqno"];
 }
 
 - (void)testHpackSize {
   // NOT SUPPORTED
-  // [self testIndividualCase:"hpack_size"];
+  // [self testIndividualCase:(char *)"hpack_size"];
 }
 
 - (void)testIdempotentRequest {
   // NOT SUPPORTED
-  // [self testIndividualCase:"idempotent_request"];
+  // [self testIndividualCase:(char *)"idempotent_request"];
 }
 
 - (void)testInvokeLargeRequest {
   // NOT SUPPORTED (frame size)
-  // [self testIndividualCase:"invoke_large_request"];
+  // [self testIndividualCase:(char *)"invoke_large_request"];
 }
 
 - (void)testLargeMetadata {
   // NOT SUPPORTED
-  // [self testIndividualCase:"large_metadata"];
+  // [self testIndividualCase:(char *)"large_metadata"];
 }
 
 - (void)testMaxConcurrentStreams {
-  [self testIndividualCase:"max_concurrent_streams"];
+  [self testIndividualCase:(char *)"max_concurrent_streams"];
 }
 
 - (void)testMaxMessageLength {
   // NOT SUPPORTED (close_error)
-  // [self testIndividualCase:"max_message_length"];
+  // [self testIndividualCase:(char *)"max_message_length"];
 }
 
 - (void)testNegativeDeadline {
-  [self testIndividualCase:"negative_deadline"];
+  [self testIndividualCase:(char *)"negative_deadline"];
 }
 
 - (void)testNetworkStatusChange {
-  [self testIndividualCase:"network_status_change"];
+  [self testIndividualCase:(char *)"network_status_change"];
 }
 
 - (void)testNoOp {
-  [self testIndividualCase:"no_op"];
+  [self testIndividualCase:(char *)"no_op"];
 }
 
 - (void)testPayload {
-  [self testIndividualCase:"payload"];
+  [self testIndividualCase:(char *)"payload"];
 }
 
 - (void)testPing {
   // NOT SUPPORTED
-  // [self testIndividualCase:"ping"];
+  // [self testIndividualCase:(char *)"ping"];
 }
 
 - (void)testPingPongStreaming {
-  [self testIndividualCase:"ping_pong_streaming"];
+  [self testIndividualCase:(char *)"ping_pong_streaming"];
 }
 
 - (void)testRegisteredCall {
-  [self testIndividualCase:"registered_call"];
+  [self testIndividualCase:(char *)"registered_call"];
 }
 
 - (void)testRequestWithFlags {
   // NOT SUPPORTED
-  // [self testIndividualCase:"request_with_flags"];
+  // [self testIndividualCase:(char *)"request_with_flags"];
 }
 
 - (void)testRequestWithPayload {
-  [self testIndividualCase:"request_with_payload"];
+  [self testIndividualCase:(char *)"request_with_payload"];
 }
 
 - (void)testServerFinishesRequest {
-  [self testIndividualCase:"server_finishes_request"];
+  [self testIndividualCase:(char *)"server_finishes_request"];
 }
 
 - (void)testShutdownFinishesCalls {
-  [self testIndividualCase:"shutdown_finishes_calls"];
+  [self testIndividualCase:(char *)"shutdown_finishes_calls"];
 }
 
 - (void)testShutdownFinishesTags {
-  [self testIndividualCase:"shutdown_finishes_tags"];
+  [self testIndividualCase:(char *)"shutdown_finishes_tags"];
 }
 
 - (void)testSimpleDelayedRequest {
-  [self testIndividualCase:"simple_delayed_request"];
+  [self testIndividualCase:(char *)"simple_delayed_request"];
 }
 
 - (void)testSimpleMetadata {
-  [self testIndividualCase:"simple_metadata"];
+  [self testIndividualCase:(char *)"simple_metadata"];
 }
 
 - (void)testSimpleRequest {
-  [self testIndividualCase:"simple_request"];
+  [self testIndividualCase:(char *)"simple_request"];
 }
 
 - (void)testStreamingErrorResponse {
-  [self testIndividualCase:"streaming_error_response"];
+  [self testIndividualCase:(char *)"streaming_error_response"];
 }
 
 - (void)testTrailingMetadata {
-  [self testIndividualCase:"trailing_metadata"];
+  [self testIndividualCase:(char *)"trailing_metadata"];
 }
 
 @end
diff --git a/src/objective-c/tests/CronetUnitTests/CronetUnitTests.m b/src/objective-c/tests/CronetUnitTests/CronetUnitTests.m
index 0d295fb..92bc20e 100644
--- a/src/objective-c/tests/CronetUnitTests/CronetUnitTests.m
+++ b/src/objective-c/tests/CronetUnitTests/CronetUnitTests.m
@@ -56,7 +56,7 @@
 + (void)setUp {
   [super setUp];
 
-  char *argv[] = {"CoreCronetEnd2EndTests"};
+  char *argv[] = {(char *)"CoreCronetEnd2EndTests"};
   grpc_test_init(1, argv);
 
   grpc_init();
@@ -100,7 +100,7 @@
   // Install server certificate
   BIO *pem = BIO_new_mem_buf((void *)test_server1_cert,
                              (int)strlen(test_server1_cert));
-  X509 *cert = PEM_read_bio_X509_AUX(pem, NULL, NULL, "");
+  X509 *cert = PEM_read_bio_X509_AUX(pem, NULL, NULL, (char *)"");
   SSL_CTX_use_certificate(ctx, cert);
   X509_free(cert);
   BIO_free(pem);
@@ -108,7 +108,7 @@
   // Install server private key
   pem =
       BIO_new_mem_buf((void *)test_server1_key, (int)strlen(test_server1_key));
-  EVP_PKEY *key = PEM_read_bio_PrivateKey(pem, NULL, NULL, "");
+  EVP_PKEY *key = PEM_read_bio_PrivateKey(pem, NULL, NULL, (char *)"");
   SSL_CTX_use_PrivateKey(ctx, key);
   EVP_PKEY_free(key);
   BIO_free(pem);
@@ -258,7 +258,7 @@
 
 - (void)packetCoalescing:(BOOL)useCoalescing {
   grpc_arg arg;
-  arg.key = GRPC_ARG_USE_CRONET_PACKET_COALESCING;
+  arg.key = (char *)GRPC_ARG_USE_CRONET_PACKET_COALESCING;
   arg.type = GRPC_ARG_INTEGER;
   arg.value.integer = useCoalescing ? 1 : 0;
   grpc_channel_args *args = grpc_channel_args_copy_and_add(NULL, &arg, 1);
diff --git a/src/objective-c/tests/GRPCClientTests.m b/src/objective-c/tests/GRPCClientTests.m
index 5672bda..3bab7f6 100644
--- a/src/objective-c/tests/GRPCClientTests.m
+++ b/src/objective-c/tests/GRPCClientTests.m
@@ -95,6 +95,10 @@
 
 @implementation GRPCClientTests
 
++ (void)setUp {
+  NSLog(@"GRPCClientTests Started");
+}
+
 - (void)setUp {
   // Add a custom user agent prefix that will be used in test
   [GRPCCall setUserAgentPrefix:@"Foo" forHost:kHostAddress];
diff --git a/src/objective-c/tests/InteropTests.m b/src/objective-c/tests/InteropTests.m
index e5fcab2..0be8669 100644
--- a/src/objective-c/tests/InteropTests.m
+++ b/src/objective-c/tests/InteropTests.m
@@ -86,6 +86,7 @@
 }
 
 + (void)setUp {
+  NSLog(@"InteropTest Started, class: %@", [[self class] description]);
 #ifdef GRPC_COMPILE_WITH_CRONET
   // Cronet setup
   [Cronet setHttp2Enabled:YES];
diff --git a/src/objective-c/tests/RxLibraryUnitTests.m b/src/objective-c/tests/RxLibraryUnitTests.m
index 3a5adbb..aa178f8 100644
--- a/src/objective-c/tests/RxLibraryUnitTests.m
+++ b/src/objective-c/tests/RxLibraryUnitTests.m
@@ -58,6 +58,10 @@
 
 @implementation RxLibraryUnitTests
 
++ (void)setUp {
+  NSLog(@"GRPCClientTests Started");
+}
+
 #pragma mark Writeable
 
 - (void)testWriteableSingleHandlerIsCalledForValue {
diff --git a/src/objective-c/tests/Tests.xcodeproj/project.pbxproj b/src/objective-c/tests/Tests.xcodeproj/project.pbxproj
index 2f0c8cf..9a6cb0e 100644
--- a/src/objective-c/tests/Tests.xcodeproj/project.pbxproj
+++ b/src/objective-c/tests/Tests.xcodeproj/project.pbxproj
@@ -14,7 +14,7 @@
 		20DFDF829DD993A4A00D5662 /* libPods-RxLibraryUnitTests.a in Frameworks */ = {isa = PBXBuildFile; fileRef = A58BE6DF1C62D1739EBB2C78 /* libPods-RxLibraryUnitTests.a */; };
 		333E8FC01C8285B7C547D799 /* libPods-InteropTestsLocalCleartext.a in Frameworks */ = {isa = PBXBuildFile; fileRef = FD346DB2C23F676C4842F3FF /* libPods-InteropTestsLocalCleartext.a */; };
 		3D7C85F6AA68C4A205E3BA16 /* libPods-Tests.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 20DFF2F3C97EF098FE5A3171 /* libPods-Tests.a */; };
-		5E8A5DA71D3840B4000F8BC4 /* CoreCronetEnd2EndTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 5E8A5DA61D3840B4000F8BC4 /* CoreCronetEnd2EndTests.m */; };
+		5E8A5DA71D3840B4000F8BC4 /* CoreCronetEnd2EndTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5E8A5DA61D3840B4000F8BC4 /* CoreCronetEnd2EndTests.mm */; };
 		5E8A5DA91D3840B4000F8BC4 /* libTests.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 635697C71B14FC11007A7283 /* libTests.a */; };
 		5EAD6D271E27047400002378 /* CronetUnitTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 5EAD6D261E27047400002378 /* CronetUnitTests.m */; };
 		5EAD6D291E27047400002378 /* libTests.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 635697C71B14FC11007A7283 /* libTests.a */; };
@@ -140,7 +140,7 @@
 		573450F334B331D0BED8B961 /* Pods-CoreCronetEnd2EndTests.cronet.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-CoreCronetEnd2EndTests.cronet.xcconfig"; path = "Pods/Target Support Files/Pods-CoreCronetEnd2EndTests/Pods-CoreCronetEnd2EndTests.cronet.xcconfig"; sourceTree = "<group>"; };
 		5761E98978DDDF136A58CB7E /* Pods-AllTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-AllTests.release.xcconfig"; path = "Pods/Target Support Files/Pods-AllTests/Pods-AllTests.release.xcconfig"; sourceTree = "<group>"; };
 		5E8A5DA41D3840B4000F8BC4 /* CoreCronetEnd2EndTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = CoreCronetEnd2EndTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
-		5E8A5DA61D3840B4000F8BC4 /* CoreCronetEnd2EndTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = CoreCronetEnd2EndTests.m; sourceTree = "<group>"; };
+		5E8A5DA61D3840B4000F8BC4 /* CoreCronetEnd2EndTests.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = CoreCronetEnd2EndTests.mm; sourceTree = "<group>"; };
 		5EAD6D241E27047400002378 /* CronetUnitTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = CronetUnitTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
 		5EAD6D261E27047400002378 /* CronetUnitTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = CronetUnitTests.m; sourceTree = "<group>"; };
 		5EAD6D281E27047400002378 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
@@ -343,7 +343,7 @@
 		5E8A5DA51D3840B4000F8BC4 /* CoreCronetEnd2EndTests */ = {
 			isa = PBXGroup;
 			children = (
-				5E8A5DA61D3840B4000F8BC4 /* CoreCronetEnd2EndTests.m */,
+				5E8A5DA61D3840B4000F8BC4 /* CoreCronetEnd2EndTests.mm */,
 			);
 			path = CoreCronetEnd2EndTests;
 			sourceTree = "<group>";
@@ -1196,7 +1196,7 @@
 			isa = PBXSourcesBuildPhase;
 			buildActionMask = 2147483647;
 			files = (
-				5E8A5DA71D3840B4000F8BC4 /* CoreCronetEnd2EndTests.m in Sources */,
+				5E8A5DA71D3840B4000F8BC4 /* CoreCronetEnd2EndTests.mm in Sources */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};
@@ -1518,6 +1518,7 @@
 				"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
 				DEBUG_INFORMATION_FORMAT = dwarf;
 				ENABLE_TESTABILITY = YES;
+				GCC_INPUT_FILETYPE = sourcecode.cpp.objcpp;
 				INFOPLIST_FILE = CronetUnitTests/Info.plist;
 				IPHONEOS_DEPLOYMENT_TARGET = 9.3;
 				LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
@@ -1567,6 +1568,7 @@
 				"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
 				DEBUG_INFORMATION_FORMAT = dwarf;
 				ENABLE_TESTABILITY = YES;
+				GCC_INPUT_FILETYPE = sourcecode.cpp.objcpp;
 				INFOPLIST_FILE = CronetUnitTests/Info.plist;
 				IPHONEOS_DEPLOYMENT_TARGET = 9.3;
 				LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
@@ -1582,6 +1584,7 @@
 			buildSettings = {
 				CLANG_ANALYZER_NONNULL = YES;
 				"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
+				GCC_INPUT_FILETYPE = sourcecode.cpp.objcpp;
 				INFOPLIST_FILE = CronetUnitTests/Info.plist;
 				IPHONEOS_DEPLOYMENT_TARGET = 9.3;
 				LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
@@ -1597,6 +1600,7 @@
 			buildSettings = {
 				CLANG_ANALYZER_NONNULL = YES;
 				"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
+				GCC_INPUT_FILETYPE = sourcecode.cpp.objcpp;
 				INFOPLIST_FILE = CronetUnitTests/Info.plist;
 				IPHONEOS_DEPLOYMENT_TARGET = 9.3;
 				LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
diff --git a/src/objective-c/tests/run_tests.sh b/src/objective-c/tests/run_tests.sh
index 608ae68..62c4e10 100755
--- a/src/objective-c/tests/run_tests.sh
+++ b/src/objective-c/tests/run_tests.sh
@@ -38,7 +38,7 @@
 # element of the pipe fails.
 # TODO(jcanizales): Use xctool instead? Issue #2540.
 set -o pipefail
-XCODEBUILD_FILTER='(^CompileC |^Ld |^.*clang |^ *cd |^ *export |^Libtool |^.*libtool |^CpHeader |^ *builtin-copy )'
+XCODEBUILD_FILTER='(^CompileC |^Ld |^ *[^ ]*clang |^ *cd |^ *export |^Libtool |^ *[^ ]*libtool |^CpHeader |^ *builtin-copy )'
 echo "TIME:  $(date)"
 xcodebuild \
     -workspace Tests.xcworkspace \
diff --git a/src/objective-c/tests/version.h b/src/objective-c/tests/version.h
index 0251506..6e3a073 100644
--- a/src/objective-c/tests/version.h
+++ b/src/objective-c/tests/version.h
@@ -23,5 +23,5 @@
 // `tools/buildgen/generate_projects.sh`.
 
 
-#define GRPC_OBJC_VERSION_STRING @"1.8.0-dev"
+#define GRPC_OBJC_VERSION_STRING @"1.9.0-dev"
 #define GRPC_C_VERSION_STRING @"5.0.0-dev"
diff --git a/src/php/composer.json b/src/php/composer.json
index 09471d2..4383398 100644
--- a/src/php/composer.json
+++ b/src/php/composer.json
@@ -2,7 +2,7 @@
   "name": "grpc/grpc-dev",
   "description": "gRPC library for PHP - for Developement use only",
   "license": "Apache-2.0",
-  "version": "1.8.0",
+  "version": "1.9.0",
   "require": {
     "php": ">=5.5.0",
     "google/protobuf": "^v3.3.0"
diff --git a/src/php/ext/grpc/version.h b/src/php/ext/grpc/version.h
index 93dd563..48131d7 100644
--- a/src/php/ext/grpc/version.h
+++ b/src/php/ext/grpc/version.h
@@ -20,6 +20,6 @@
 #ifndef VERSION_H
 #define VERSION_H
 
-#define PHP_GRPC_VERSION "1.8.0dev"
+#define PHP_GRPC_VERSION "1.9.0dev"
 
 #endif /* VERSION_H */
diff --git a/src/python/grpcio/grpc/__init__.py b/src/python/grpcio/grpc/__init__.py
index c9f9ac2..558ce42 100644
--- a/src/python/grpcio/grpc/__init__.py
+++ b/src/python/grpcio/grpc/__init__.py
@@ -424,6 +424,21 @@
         self._credentials = credentials
 
 
+class ServerCertificateConfiguration(object):
+    """A certificate configuration for use with an SSL-enabled Server.
+
+    Instances of this class can be returned in the certificate configuration
+    fetching callback.
+
+    This class has no supported interface -- it exists to define the
+    type of its instances and its instances exist to be passed to
+    other functions.
+    """
+
+    def __init__(self, certificate_configuration):
+        self._certificate_configuration = certificate_configuration
+
+
 ########################  Multi-Callable Interfaces  ###########################
 
 
@@ -1252,6 +1267,61 @@
             ], require_client_auth))
 
 
+def ssl_server_certificate_configuration(private_key_certificate_chain_pairs,
+                                         root_certificates=None):
+    """Creates a ServerCertificateConfiguration for use with a Server.
+
+    Args:
+      private_key_certificate_chain_pairs: A collection of pairs of
+        the form [PEM-encoded private key, PEM-encoded certificate
+        chain].
+      root_certificates: An optional byte string of PEM-encoded client root
+        certificates that the server will use to verify client authentication.
+
+    Returns:
+      A ServerCertificateConfiguration that can be returned in the certificate
+        configuration fetching callback.
+    """
+    if len(private_key_certificate_chain_pairs) == 0:
+        raise ValueError(
+            'At least one private key-certificate chain pair is required!')
+    else:
+        return ServerCertificateConfiguration(
+            _cygrpc.server_certificate_config_ssl(root_certificates, [
+                _cygrpc.SslPemKeyCertPair(key, pem)
+                for key, pem in private_key_certificate_chain_pairs
+            ]))
+
+
+def dynamic_ssl_server_credentials(initial_certificate_configuration,
+                                   certificate_configuration_fetcher,
+                                   require_client_authentication=False):
+    """Creates a ServerCredentials for use with an SSL-enabled Server.
+
+    Args:
+      initial_certificate_configuration (ServerCertificateConfiguration): The
+        certificate configuration with which the server will be initialized.
+      certificate_configuration_fetcher (callable): A callable that takes no
+        arguments and should return a ServerCertificateConfiguration to
+        replace the server's current certificate, or None for no change
+        (i.e., the server will continue its current certificate
+        config). The library will call this callback on *every* new
+        client connection before starting the TLS handshake with the
+        client, thus allowing the user application to optionally
+        return a new ServerCertificateConfiguration that the server will then
+        use for the handshake.
+      require_client_authentication: A boolean indicating whether or not to
+        require clients to be authenticated.
+
+    Returns:
+      A ServerCredentials.
+    """
+    return ServerCredentials(
+        _cygrpc.server_credentials_ssl_dynamic_cert_config(
+            initial_certificate_configuration,
+            certificate_configuration_fetcher, require_client_authentication))
+
+
 def channel_ready_future(channel):
     """Creates a Future that tracks when a Channel is ready.
 
@@ -1334,7 +1404,8 @@
            'ChannelConnectivity', 'StatusCode', 'RpcError', 'RpcContext',
            'Call', 'ChannelCredentials', 'CallCredentials',
            'AuthMetadataContext', 'AuthMetadataPluginCallback',
-           'AuthMetadataPlugin', 'ServerCredentials', 'UnaryUnaryMultiCallable',
+           'AuthMetadataPlugin', 'ServerCertificateConfiguration',
+           'ServerCredentials', 'UnaryUnaryMultiCallable',
            'UnaryStreamMultiCallable', 'StreamUnaryMultiCallable',
            'StreamStreamMultiCallable', 'Channel', 'ServicerContext',
            'RpcMethodHandler', 'HandlerCallDetails', 'GenericRpcHandler',
@@ -1344,8 +1415,9 @@
            'method_handlers_generic_handler', 'ssl_channel_credentials',
            'metadata_call_credentials', 'access_token_call_credentials',
            'composite_call_credentials', 'composite_channel_credentials',
-           'ssl_server_credentials', 'channel_ready_future', 'insecure_channel',
-           'secure_channel', 'server',)
+           'ssl_server_credentials', 'ssl_server_certificate_configuration',
+           'dynamic_ssl_server_credentials', 'channel_ready_future',
+           'insecure_channel', 'secure_channel', 'server',)
 
 ############################### Extension Shims ################################
 
diff --git a/src/python/grpcio/grpc/_cython/_cygrpc/credentials.pxd.pxi b/src/python/grpcio/grpc/_cython/_cygrpc/credentials.pxd.pxi
index 41975cb..bc0f185 100644
--- a/src/python/grpcio/grpc/_cython/_cygrpc/credentials.pxd.pxi
+++ b/src/python/grpcio/grpc/_cython/_cygrpc/credentials.pxd.pxi
@@ -28,12 +28,27 @@
   cdef list references
 
 
+cdef class ServerCertificateConfig:
+
+  cdef grpc_ssl_server_certificate_config *c_cert_config
+  cdef const char *c_pem_root_certs
+  cdef grpc_ssl_pem_key_cert_pair *c_ssl_pem_key_cert_pairs
+  cdef size_t c_ssl_pem_key_cert_pairs_count
+  cdef list references
+
+
 cdef class ServerCredentials:
 
   cdef grpc_server_credentials *c_credentials
   cdef grpc_ssl_pem_key_cert_pair *c_ssl_pem_key_cert_pairs
   cdef size_t c_ssl_pem_key_cert_pairs_count
   cdef list references
+  # the cert config related state is used only if this credentials is
+  # created with cert config/fetcher
+  cdef object initial_cert_config
+  cdef object cert_config_fetcher
+  # whether C-core has asked for the initial_cert_config
+  cdef bint initial_cert_config_fetched
 
 
 cdef class CredentialsMetadataPlugin:
diff --git a/src/python/grpcio/grpc/_cython/_cygrpc/credentials.pyx.pxi b/src/python/grpcio/grpc/_cython/_cygrpc/credentials.pyx.pxi
index 0fabda1..ee1328d 100644
--- a/src/python/grpcio/grpc/_cython/_cygrpc/credentials.pyx.pxi
+++ b/src/python/grpcio/grpc/_cython/_cygrpc/credentials.pyx.pxi
@@ -14,6 +14,7 @@
 
 cimport cpython
 
+import grpc
 import threading
 import traceback
 
@@ -58,12 +59,30 @@
     grpc_shutdown()
 
 
+cdef class ServerCertificateConfig:
+
+  def __cinit__(self):
+    grpc_init()
+    self.c_cert_config = NULL
+    self.c_pem_root_certs = NULL
+    self.c_ssl_pem_key_cert_pairs = NULL
+    self.references = []
+
+  def __dealloc__(self):
+    grpc_ssl_server_certificate_config_destroy(self.c_cert_config)
+    gpr_free(self.c_ssl_pem_key_cert_pairs)
+    grpc_shutdown()
+
+
 cdef class ServerCredentials:
 
   def __cinit__(self):
     grpc_init()
     self.c_credentials = NULL
     self.references = []
+    self.initial_cert_config = None
+    self.cert_config_fetcher = None
+    self.initial_cert_config_fetched = False
 
   def __dealloc__(self):
     if self.c_credentials != NULL:
@@ -254,34 +273,86 @@
   credentials.references.append(plugin)
   return credentials
 
-def server_credentials_ssl(pem_root_certs, pem_key_cert_pairs,
-                           bint force_client_auth):
-  pem_root_certs = str_to_bytes(pem_root_certs)
-  cdef char *c_pem_root_certs = NULL
-  if pem_root_certs is not None: 
-    c_pem_root_certs = pem_root_certs
-  pem_key_cert_pairs = list(pem_key_cert_pairs)
+cdef const char* _get_c_pem_root_certs(pem_root_certs):
+  if pem_root_certs is None:
+    return NULL
+  else:
+    return pem_root_certs
+
+cdef grpc_ssl_pem_key_cert_pair* _create_c_ssl_pem_key_cert_pairs(pem_key_cert_pairs):
+  # return a malloc'ed grpc_ssl_pem_key_cert_pair from a _list_ of SslPemKeyCertPair
   for pair in pem_key_cert_pairs:
     if not isinstance(pair, SslPemKeyCertPair):
       raise TypeError("expected pem_key_cert_pairs to be sequence of "
                       "SslPemKeyCertPair")
-  cdef ServerCredentials credentials = ServerCredentials()
-  credentials.references.append(pem_key_cert_pairs)
-  credentials.references.append(pem_root_certs)
-  credentials.c_ssl_pem_key_cert_pairs_count = len(pem_key_cert_pairs)
+  cdef size_t c_ssl_pem_key_cert_pairs_count = len(pem_key_cert_pairs)
+  cdef grpc_ssl_pem_key_cert_pair* c_ssl_pem_key_cert_pairs = NULL
   with nogil:
-    credentials.c_ssl_pem_key_cert_pairs = (
-        <grpc_ssl_pem_key_cert_pair *>gpr_malloc(
-            sizeof(grpc_ssl_pem_key_cert_pair) *
-                credentials.c_ssl_pem_key_cert_pairs_count
-        ))
-  for i in range(credentials.c_ssl_pem_key_cert_pairs_count):
-    credentials.c_ssl_pem_key_cert_pairs[i] = (
-        (<SslPemKeyCertPair>pem_key_cert_pairs[i]).c_pair)
-  credentials.c_credentials = grpc_ssl_server_credentials_create(
-      c_pem_root_certs, credentials.c_ssl_pem_key_cert_pairs,
-      credentials.c_ssl_pem_key_cert_pairs_count,
-      GRPC_SSL_REQUEST_AND_REQUIRE_CLIENT_CERTIFICATE_AND_VERIFY if force_client_auth else GRPC_SSL_DONT_REQUEST_CLIENT_CERTIFICATE,
-      NULL)
+    c_ssl_pem_key_cert_pairs = (
+      <grpc_ssl_pem_key_cert_pair *>gpr_malloc(
+        sizeof(grpc_ssl_pem_key_cert_pair) * c_ssl_pem_key_cert_pairs_count))
+  for i in range(c_ssl_pem_key_cert_pairs_count):
+    c_ssl_pem_key_cert_pairs[i] = (
+      (<SslPemKeyCertPair>pem_key_cert_pairs[i]).c_pair)
+  return c_ssl_pem_key_cert_pairs
+
+def server_credentials_ssl(pem_root_certs, pem_key_cert_pairs,
+                           bint force_client_auth):
+  pem_root_certs = str_to_bytes(pem_root_certs)
+  pem_key_cert_pairs = list(pem_key_cert_pairs)
+  cdef ServerCredentials credentials = ServerCredentials()
+  credentials.references.append(pem_root_certs)
+  credentials.references.append(pem_key_cert_pairs)
+  cdef const char * c_pem_root_certs = _get_c_pem_root_certs(pem_root_certs)
+  credentials.c_ssl_pem_key_cert_pairs_count = len(pem_key_cert_pairs)
+  credentials.c_ssl_pem_key_cert_pairs = _create_c_ssl_pem_key_cert_pairs(pem_key_cert_pairs)
+  cdef grpc_ssl_server_certificate_config *c_cert_config = NULL
+  c_cert_config = grpc_ssl_server_certificate_config_create(
+    c_pem_root_certs, credentials.c_ssl_pem_key_cert_pairs,
+    credentials.c_ssl_pem_key_cert_pairs_count)
+  cdef grpc_ssl_server_credentials_options* c_options = NULL
+  # C-core assumes ownership of c_cert_config
+  c_options = grpc_ssl_server_credentials_create_options_using_config(
+    GRPC_SSL_REQUEST_AND_REQUIRE_CLIENT_CERTIFICATE_AND_VERIFY
+    if force_client_auth else
+    GRPC_SSL_DONT_REQUEST_CLIENT_CERTIFICATE,
+    c_cert_config)
+  # C-core assumes ownership of c_options
+  credentials.c_credentials = grpc_ssl_server_credentials_create_with_options(c_options)
   return credentials
 
+def server_certificate_config_ssl(pem_root_certs, pem_key_cert_pairs):
+  pem_root_certs = str_to_bytes(pem_root_certs)
+  pem_key_cert_pairs = list(pem_key_cert_pairs)
+  cdef ServerCertificateConfig cert_config = ServerCertificateConfig()
+  cert_config.references.append(pem_root_certs)
+  cert_config.references.append(pem_key_cert_pairs)
+  cert_config.c_pem_root_certs = _get_c_pem_root_certs(pem_root_certs)
+  cert_config.c_ssl_pem_key_cert_pairs_count = len(pem_key_cert_pairs)
+  cert_config.c_ssl_pem_key_cert_pairs = _create_c_ssl_pem_key_cert_pairs(pem_key_cert_pairs)
+  cert_config.c_cert_config = grpc_ssl_server_certificate_config_create(
+    cert_config.c_pem_root_certs, cert_config.c_ssl_pem_key_cert_pairs,
+    cert_config.c_ssl_pem_key_cert_pairs_count)
+  return cert_config
+
+def server_credentials_ssl_dynamic_cert_config(initial_cert_config,
+                                               cert_config_fetcher,
+                                               bint force_client_auth):
+  if not isinstance(initial_cert_config, grpc.ServerCertificateConfiguration):
+    raise TypeError(
+        'initial_cert_config must be a grpc.ServerCertificateConfiguration')
+  if not callable(cert_config_fetcher):
+    raise TypeError('cert_config_fetcher must be callable')
+  cdef ServerCredentials credentials = ServerCredentials()
+  credentials.initial_cert_config = initial_cert_config
+  credentials.cert_config_fetcher = cert_config_fetcher
+  cdef grpc_ssl_server_credentials_options* c_options = NULL
+  c_options = grpc_ssl_server_credentials_create_options_using_config_fetcher(
+    GRPC_SSL_REQUEST_AND_REQUIRE_CLIENT_CERTIFICATE_AND_VERIFY
+    if force_client_auth else
+    GRPC_SSL_DONT_REQUEST_CLIENT_CERTIFICATE,
+    _server_cert_config_fetcher_wrapper,
+    <void*>credentials)
+  # C-core assumes ownership of c_options
+  credentials.c_credentials = grpc_ssl_server_credentials_create_with_options(c_options)
+  return credentials
diff --git a/src/python/grpcio/grpc/_cython/_cygrpc/grpc.pxi b/src/python/grpcio/grpc/_cython/_cygrpc/grpc.pxi
index f115106..660263f 100644
--- a/src/python/grpcio/grpc/_cython/_cygrpc/grpc.pxi
+++ b/src/python/grpcio/grpc/_cython/_cygrpc/grpc.pxi
@@ -391,6 +391,42 @@
     GRPC_SSL_REQUEST_AND_REQUIRE_CLIENT_CERTIFICATE_BUT_DONT_VERIFY
     GRPC_SSL_REQUEST_AND_REQUIRE_CLIENT_CERTIFICATE_AND_VERIFY
 
+  ctypedef enum grpc_ssl_certificate_config_reload_status:
+    GRPC_SSL_CERTIFICATE_CONFIG_RELOAD_UNCHANGED
+    GRPC_SSL_CERTIFICATE_CONFIG_RELOAD_NEW
+    GRPC_SSL_CERTIFICATE_CONFIG_RELOAD_FAIL
+
+  ctypedef struct grpc_ssl_server_certificate_config:
+    # We don't care about the internals
+    pass
+
+  ctypedef struct grpc_ssl_server_credentials_options:
+    # We don't care about the internals
+    pass
+
+  grpc_ssl_server_certificate_config * grpc_ssl_server_certificate_config_create(
+    const char *pem_root_certs,
+    const grpc_ssl_pem_key_cert_pair *pem_key_cert_pairs,
+    size_t num_key_cert_pairs)
+
+  void grpc_ssl_server_certificate_config_destroy(grpc_ssl_server_certificate_config *config)
+
+  ctypedef grpc_ssl_certificate_config_reload_status (*grpc_ssl_server_certificate_config_callback)(
+    void *user_data,
+    grpc_ssl_server_certificate_config **config)
+
+  grpc_ssl_server_credentials_options *grpc_ssl_server_credentials_create_options_using_config(
+    grpc_ssl_client_certificate_request_type client_certificate_request,
+    grpc_ssl_server_certificate_config *certificate_config)
+
+  grpc_ssl_server_credentials_options* grpc_ssl_server_credentials_create_options_using_config_fetcher(
+    grpc_ssl_client_certificate_request_type client_certificate_request,
+    grpc_ssl_server_certificate_config_callback cb,
+    void *user_data)
+
+  grpc_server_credentials *grpc_ssl_server_credentials_create_with_options(
+      grpc_ssl_server_credentials_options *options)
+
   ctypedef struct grpc_ssl_pem_key_cert_pair:
     const char *private_key
     const char *certificate_chain "cert_chain"
@@ -440,10 +476,6 @@
     # We don't care about the internals (and in fact don't know them)
     pass
 
-  grpc_server_credentials *grpc_ssl_server_credentials_create(
-      const char *pem_root_certs,
-      grpc_ssl_pem_key_cert_pair *pem_key_cert_pairs,
-      size_t num_key_cert_pairs, int force_client_auth, void *reserved)
   void grpc_server_credentials_release(grpc_server_credentials *creds) nogil
 
   int grpc_server_add_secure_http2_port(grpc_server *server, const char *addr,
diff --git a/src/python/grpcio/grpc/_cython/_cygrpc/server.pyx.pxi b/src/python/grpcio/grpc/_cython/_cygrpc/server.pyx.pxi
index b8db274..5f34059 100644
--- a/src/python/grpcio/grpc/_cython/_cygrpc/server.pyx.pxi
+++ b/src/python/grpcio/grpc/_cython/_cygrpc/server.pyx.pxi
@@ -14,8 +14,46 @@
 
 cimport cpython
 
+import logging
 import time
+import grpc
 
+cdef grpc_ssl_certificate_config_reload_status _server_cert_config_fetcher_wrapper(
+        void* user_data, grpc_ssl_server_certificate_config **config) with gil:
+  # This is a credentials.ServerCertificateConfig
+  cdef ServerCertificateConfig cert_config = None
+  if not user_data:
+    raise ValueError('internal error: user_data must be specified')
+  credentials = <ServerCredentials>user_data
+  if not credentials.initial_cert_config_fetched:
+    # C-core is asking for the initial cert config
+    credentials.initial_cert_config_fetched = True
+    cert_config = credentials.initial_cert_config._certificate_configuration
+  else:
+    user_cb = credentials.cert_config_fetcher
+    try:
+      cert_config_wrapper = user_cb()
+    except Exception:
+      logging.exception('Error fetching certificate config')
+      return GRPC_SSL_CERTIFICATE_CONFIG_RELOAD_FAIL
+    if cert_config_wrapper is None:
+      return GRPC_SSL_CERTIFICATE_CONFIG_RELOAD_UNCHANGED
+    elif not isinstance(
+        cert_config_wrapper, grpc.ServerCertificateConfiguration):
+      logging.error(
+          'Error fetching certificate configuration: certificate '
+          'configuration must be of type grpc.ServerCertificateConfiguration, '
+          'not %s' % type(cert_config_wrapper).__name__)
+      return GRPC_SSL_CERTIFICATE_CONFIG_RELOAD_FAIL
+    else:
+      cert_config = cert_config_wrapper._certificate_configuration
+  config[0] = <grpc_ssl_server_certificate_config*>cert_config.c_cert_config
+  # our caller will assume ownership of memory, so we have to recreate
+  # a copy of c_cert_config here
+  cert_config.c_cert_config = grpc_ssl_server_certificate_config_create(
+      cert_config.c_pem_root_certs, cert_config.c_ssl_pem_key_cert_pairs,
+      cert_config.c_ssl_pem_key_cert_pairs_count)
+  return GRPC_SSL_CERTIFICATE_CONFIG_RELOAD_NEW
 
 cdef class Server:
 
diff --git a/src/python/grpcio/grpc/_grpcio_metadata.py b/src/python/grpcio/grpc/_grpcio_metadata.py
index 0887ac1..993c49d 100644
--- a/src/python/grpcio/grpc/_grpcio_metadata.py
+++ b/src/python/grpcio/grpc/_grpcio_metadata.py
@@ -14,4 +14,4 @@
 
 # AUTO-GENERATED FROM `$REPO_ROOT/templates/src/python/grpcio/grpc/_grpcio_metadata.py.template`!!!
 
-__version__ = """1.8.0.dev0"""
+__version__ = """1.9.0.dev0"""
diff --git a/src/python/grpcio/grpc_core_dependencies.py b/src/python/grpcio/grpc_core_dependencies.py
index 330c418..d2a68f0 100644
--- a/src/python/grpcio/grpc_core_dependencies.py
+++ b/src/python/grpcio/grpc_core_dependencies.py
@@ -29,7 +29,7 @@
   'src/core/lib/support/env_linux.cc',
   'src/core/lib/support/env_posix.cc',
   'src/core/lib/support/env_windows.cc',
-  'src/core/lib/support/histogram.cc',
+  'src/core/lib/support/fork.cc',
   'src/core/lib/support/host_port.cc',
   'src/core/lib/support/log.cc',
   'src/core/lib/support/log_android.cc',
@@ -38,7 +38,6 @@
   'src/core/lib/support/log_windows.cc',
   'src/core/lib/support/mpscq.cc',
   'src/core/lib/support/murmur_hash.cc',
-  'src/core/lib/support/stack_lockfree.cc',
   'src/core/lib/support/string.cc',
   'src/core/lib/support/string_posix.cc',
   'src/core/lib/support/string_util_windows.cc',
@@ -94,6 +93,8 @@
   'src/core/lib/iomgr/ev_windows.cc',
   'src/core/lib/iomgr/exec_ctx.cc',
   'src/core/lib/iomgr/executor.cc',
+  'src/core/lib/iomgr/fork_posix.cc',
+  'src/core/lib/iomgr/fork_windows.cc',
   'src/core/lib/iomgr/gethostname_fallback.cc',
   'src/core/lib/iomgr/gethostname_host_name_max.cc',
   'src/core/lib/iomgr/gethostname_sysconf.cc',
diff --git a/src/python/grpcio/grpc_version.py b/src/python/grpcio/grpc_version.py
index 61c4157..8f07f3b 100644
--- a/src/python/grpcio/grpc_version.py
+++ b/src/python/grpcio/grpc_version.py
@@ -14,4 +14,4 @@
 
 # AUTO-GENERATED FROM `$REPO_ROOT/templates/src/python/grpcio/grpc_version.py.template`!!!
 
-VERSION='1.8.0.dev0'
+VERSION='1.9.0.dev0'
diff --git a/src/python/grpcio_health_checking/grpc_version.py b/src/python/grpcio_health_checking/grpc_version.py
index 889297f..0987d57 100644
--- a/src/python/grpcio_health_checking/grpc_version.py
+++ b/src/python/grpcio_health_checking/grpc_version.py
@@ -14,4 +14,4 @@
 
 # AUTO-GENERATED FROM `$REPO_ROOT/templates/src/python/grpcio_health_checking/grpc_version.py.template`!!!
 
-VERSION='1.8.0.dev0'
+VERSION='1.9.0.dev0'
diff --git a/src/python/grpcio_health_checking/setup.py b/src/python/grpcio_health_checking/setup.py
index 01d796f..c105f57 100644
--- a/src/python/grpcio_health_checking/setup.py
+++ b/src/python/grpcio_health_checking/setup.py
@@ -56,21 +56,12 @@
     '': '.',
 }
 
-INSTALL_REQUIRES = ('protobuf>=3.3.0',
+INSTALL_REQUIRES = ('protobuf>=3.5.0.post1',
                     'grpcio>={version}'.format(version=grpc_version.VERSION),)
 
 try:
-    # ensure we can load the _pb2_grpc module:
-    from grpc_health.v1 import health_pb2_grpc as _pb2_grpc
-    # if we can find the _pb2_grpc module, the package has already been built.
-    SETUP_REQUIRES = ()
-    COMMAND_CLASS = {
-        # wire up commands to no-op not to break the external dependencies
-        'preprocess': _NoOpCommand,
-        'build_package_protos': _NoOpCommand,
-    }
-except ImportError:  # we are in the build environment
     import health_commands as _health_commands
+    # we are in the build environment, otherwise the above import fails
     SETUP_REQUIRES = (
         'grpcio-tools=={version}'.format(version=grpc_version.VERSION),)
     COMMAND_CLASS = {
@@ -78,6 +69,13 @@
         'preprocess': _health_commands.CopyProtoModules,
         'build_package_protos': _health_commands.BuildPackageProtos,
     }
+except ImportError:
+    SETUP_REQUIRES = ()
+    COMMAND_CLASS = {
+        # wire up commands to no-op not to break the external dependencies
+        'preprocess': _NoOpCommand,
+        'build_package_protos': _NoOpCommand,
+    }
 
 setuptools.setup(
     name='grpcio-health-checking',
diff --git a/src/python/grpcio_reflection/grpc_version.py b/src/python/grpcio_reflection/grpc_version.py
index 192f4cc..95d2ff1 100644
--- a/src/python/grpcio_reflection/grpc_version.py
+++ b/src/python/grpcio_reflection/grpc_version.py
@@ -14,4 +14,4 @@
 
 # AUTO-GENERATED FROM `$REPO_ROOT/templates/src/python/grpcio_reflection/grpc_version.py.template`!!!
 
-VERSION='1.8.0.dev0'
+VERSION='1.9.0.dev0'
diff --git a/src/python/grpcio_reflection/setup.py b/src/python/grpcio_reflection/setup.py
index ad9e869..760b893 100644
--- a/src/python/grpcio_reflection/setup.py
+++ b/src/python/grpcio_reflection/setup.py
@@ -57,21 +57,12 @@
     '': '.',
 }
 
-INSTALL_REQUIRES = ('protobuf>=3.3.0',
+INSTALL_REQUIRES = ('protobuf>=3.5.0.post1',
                     'grpcio>={version}'.format(version=grpc_version.VERSION),)
 
 try:
-    # ensure we can load the _pb2_grpc module:
-    from grpc_reflection.v1alpha import reflection_pb2_grpc as _pb2_grpc
-    # if we can find the _pb2_grpc module, the package has already been built.
-    SETUP_REQUIRES = ()
-    COMMAND_CLASS = {
-        # wire up commands to no-op not to break the external dependencies
-        'preprocess': _NoOpCommand,
-        'build_package_protos': _NoOpCommand,
-    }
-except ImportError:  # we are in the build environment
     import reflection_commands as _reflection_commands
+    # we are in the build environment, otherwise the above import fails
     SETUP_REQUIRES = (
         'grpcio-tools=={version}'.format(version=grpc_version.VERSION),)
     COMMAND_CLASS = {
@@ -79,6 +70,13 @@
         'preprocess': _reflection_commands.CopyProtoModules,
         'build_package_protos': _reflection_commands.BuildPackageProtos,
     }
+except ImportError:
+    SETUP_REQUIRES = ()
+    COMMAND_CLASS = {
+        # wire up commands to no-op not to break the external dependencies
+        'preprocess': _NoOpCommand,
+        'build_package_protos': _NoOpCommand,
+    }
 
 setuptools.setup(
     name='grpcio-reflection',
diff --git a/src/python/grpcio_testing/grpc_version.py b/src/python/grpcio_testing/grpc_version.py
index 83470c2..afc6dd8 100644
--- a/src/python/grpcio_testing/grpc_version.py
+++ b/src/python/grpcio_testing/grpc_version.py
@@ -14,4 +14,4 @@
 
 # AUTO-GENERATED FROM `$REPO_ROOT/templates/src/python/grpcio_testing/grpc_version.py.template`!!!
 
-VERSION='1.8.0.dev0'
+VERSION='1.9.0.dev0'
diff --git a/src/python/grpcio_testing/setup.py b/src/python/grpcio_testing/setup.py
index 0cc336a..fa40424 100644
--- a/src/python/grpcio_testing/setup.py
+++ b/src/python/grpcio_testing/setup.py
@@ -28,7 +28,7 @@
     '': '.',
 }
 
-INSTALL_REQUIRES = ('protobuf>=3.3.0',
+INSTALL_REQUIRES = ('protobuf>=3.5.0.post1',
                     'grpcio>={version}'.format(version=grpc_version.VERSION),)
 
 setuptools.setup(
diff --git a/src/python/grpcio_tests/grpc_version.py b/src/python/grpcio_tests/grpc_version.py
index 7065edd..99ca3fd 100644
--- a/src/python/grpcio_tests/grpc_version.py
+++ b/src/python/grpcio_tests/grpc_version.py
@@ -14,4 +14,4 @@
 
 # AUTO-GENERATED FROM `$REPO_ROOT/templates/src/python/grpcio_tests/grpc_version.py.template`!!!
 
-VERSION='1.8.0.dev0'
+VERSION='1.9.0.dev0'
diff --git a/src/python/grpcio_tests/setup.py b/src/python/grpcio_tests/setup.py
index debe14c..aeb4ea9 100644
--- a/src/python/grpcio_tests/setup.py
+++ b/src/python/grpcio_tests/setup.py
@@ -41,8 +41,8 @@
     '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.3.0', 'six>=1.10', 'google-auth>=1.0.0',
-    'requests>=2.14.2')
+    'oauth2client>=1.4.7', 'protobuf>=3.5.0.post1', 'six>=1.10',
+    'google-auth>=1.0.0', 'requests>=2.14.2')
 
 COMMAND_CLASS = {
     # Run `preprocess` *before* doing any packaging!
diff --git a/src/python/grpcio_tests/tests/interop/client.py b/src/python/grpcio_tests/tests/interop/client.py
index e520c08..383b5f0 100644
--- a/src/python/grpcio_tests/tests/interop/client.py
+++ b/src/python/grpcio_tests/tests/interop/client.py
@@ -29,37 +29,40 @@
     parser = argparse.ArgumentParser()
     parser.add_argument(
         '--server_host',
-        help='the host to which to connect',
+        default="localhost",
         type=str,
-        default="localhost")
+        help='the host to which to connect')
     parser.add_argument(
-        '--server_port', help='the port to which to connect', type=int)
+        '--server_port',
+        type=int,
+        required=True,
+        help='the port to which to connect')
     parser.add_argument(
         '--test_case',
-        help='the test case to execute',
+        default='large_unary',
         type=str,
-        default="large_unary")
+        help='the test case to execute')
     parser.add_argument(
         '--use_tls',
-        help='require a secure connection',
         default=False,
-        type=resources.parse_bool)
+        type=resources.parse_bool,
+        help='require a secure connection')
     parser.add_argument(
         '--use_test_ca',
-        help='replace platform root CAs with ca.pem',
         default=False,
-        type=resources.parse_bool)
+        type=resources.parse_bool,
+        help='replace platform root CAs with ca.pem')
     parser.add_argument(
         '--server_host_override',
         default="foo.test.google.fr",
-        help='the server host to which to claim to connect',
-        type=str)
+        type=str,
+        help='the server host to which to claim to connect')
     parser.add_argument(
-        '--oauth_scope', help='scope for OAuth tokens', type=str)
+        '--oauth_scope', type=str, help='scope for OAuth tokens')
     parser.add_argument(
         '--default_service_account',
-        help='email address of the default service account',
-        type=str)
+        type=str,
+        help='email address of the default service account')
     return parser.parse_args()
 
 
diff --git a/src/python/grpcio_tests/tests/interop/server.py b/src/python/grpcio_tests/tests/interop/server.py
index 8ad1f5f..eeb41a2 100644
--- a/src/python/grpcio_tests/tests/interop/server.py
+++ b/src/python/grpcio_tests/tests/interop/server.py
@@ -29,12 +29,13 @@
 
 def serve():
     parser = argparse.ArgumentParser()
-    parser.add_argument('--port', help='the port on which to serve', type=int)
+    parser.add_argument(
+        '--port', type=int, required=True, help='the port on which to serve')
     parser.add_argument(
         '--use_tls',
-        help='require a secure connection',
         default=False,
-        type=resources.parse_bool)
+        type=resources.parse_bool,
+        help='require a secure connection')
     args = parser.parse_args()
 
     server = grpc.server(futures.ThreadPoolExecutor(max_workers=10))
diff --git a/src/python/grpcio_tests/tests/tests.json b/src/python/grpcio_tests/tests/tests.json
index 8512d5b..e277a3e 100644
--- a/src/python/grpcio_tests/tests/tests.json
+++ b/src/python/grpcio_tests/tests/tests.json
@@ -46,6 +46,10 @@
   "unit._reconnect_test.ReconnectTest",
   "unit._resource_exhausted_test.ResourceExhaustedTest",
   "unit._rpc_test.RPCTest",
+  "unit._server_ssl_cert_config_test.ServerSSLCertConfigFetcherParamsChecks",
+  "unit._server_ssl_cert_config_test.ServerSSLCertReloadTestCertConfigReuse",
+  "unit._server_ssl_cert_config_test.ServerSSLCertReloadTestWithClientAuth",
+  "unit._server_ssl_cert_config_test.ServerSSLCertReloadTestWithoutClientAuth",
   "unit._thread_cleanup_test.CleanupThreadTest",
   "unit.beta._beta_features_test.BetaFeaturesTest",
   "unit.beta._beta_features_test.ContextManagementAndLifecycleTest",
diff --git a/src/python/grpcio_tests/tests/unit/_api_test.py b/src/python/grpcio_tests/tests/unit/_api_test.py
index a3351aa..b14e8d5 100644
--- a/src/python/grpcio_tests/tests/unit/_api_test.py
+++ b/src/python/grpcio_tests/tests/unit/_api_test.py
@@ -30,18 +30,20 @@
             'ChannelConnectivity', 'StatusCode', 'RpcError', 'RpcContext',
             'Call', 'ChannelCredentials', 'CallCredentials',
             'AuthMetadataContext', 'AuthMetadataPluginCallback',
-            'AuthMetadataPlugin', 'ServerCredentials',
-            'UnaryUnaryMultiCallable', 'UnaryStreamMultiCallable',
-            'StreamUnaryMultiCallable', 'StreamStreamMultiCallable', 'Channel',
-            'ServicerContext', 'RpcMethodHandler', 'HandlerCallDetails',
-            'GenericRpcHandler', 'ServiceRpcHandler', 'Server',
-            'unary_unary_rpc_method_handler', 'unary_stream_rpc_method_handler',
+            'AuthMetadataPlugin', 'ServerCertificateConfiguration',
+            'ServerCredentials', 'UnaryUnaryMultiCallable',
+            'UnaryStreamMultiCallable', 'StreamUnaryMultiCallable',
+            'StreamStreamMultiCallable', 'Channel', 'ServicerContext',
+            'RpcMethodHandler', 'HandlerCallDetails', 'GenericRpcHandler',
+            'ServiceRpcHandler', 'Server', 'unary_unary_rpc_method_handler',
+            'unary_stream_rpc_method_handler',
             'stream_unary_rpc_method_handler',
             'stream_stream_rpc_method_handler',
             'method_handlers_generic_handler', 'ssl_channel_credentials',
             'metadata_call_credentials', 'access_token_call_credentials',
             'composite_call_credentials', 'composite_channel_credentials',
-            'ssl_server_credentials', 'channel_ready_future',
+            'ssl_server_credentials', 'ssl_server_certificate_configuration',
+            'dynamic_ssl_server_credentials', 'channel_ready_future',
             'insecure_channel', 'secure_channel', 'server',)
 
         six.assertCountEqual(self, expected_grpc_code_elements,
diff --git a/src/python/grpcio_tests/tests/unit/_server_ssl_cert_config_test.py b/src/python/grpcio_tests/tests/unit/_server_ssl_cert_config_test.py
new file mode 100644
index 0000000..005d16e
--- /dev/null
+++ b/src/python/grpcio_tests/tests/unit/_server_ssl_cert_config_test.py
@@ -0,0 +1,519 @@
+# Copyright 2017 gRPC authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+"""Tests server certificate rotation.
+
+Here we test various aspects of gRPC Python, and in some cases gRPC
+Core by extension, support for server certificate rotation.
+
+* ServerSSLCertReloadTestWithClientAuth: test ability to rotate
+  server's SSL cert for use in future channels with clients while not
+  affecting any existing channel. The server requires client
+  authentication.
+
+* ServerSSLCertReloadTestWithoutClientAuth: like
+  ServerSSLCertReloadTestWithClientAuth except that the server does
+  not authenticate the client.
+
+* ServerSSLCertReloadTestCertConfigReuse: tests gRPC Python's ability
+  to deal with user's reuse of ServerCertificateConfiguration instances.
+"""
+
+import abc
+import collections
+import os
+import six
+import threading
+import unittest
+
+from concurrent import futures
+
+import grpc
+from tests.unit import resources
+from tests.testing import _application_common
+from tests.testing import _server_application
+from tests.testing.proto import services_pb2_grpc
+
+CA_1_PEM = resources.cert_hier_1_root_ca_cert()
+CA_2_PEM = resources.cert_hier_2_root_ca_cert()
+
+CLIENT_KEY_1_PEM = resources.cert_hier_1_client_1_key()
+CLIENT_CERT_CHAIN_1_PEM = (resources.cert_hier_1_client_1_cert() +
+                           resources.cert_hier_1_intermediate_ca_cert())
+
+CLIENT_KEY_2_PEM = resources.cert_hier_2_client_1_key()
+CLIENT_CERT_CHAIN_2_PEM = (resources.cert_hier_2_client_1_cert() +
+                           resources.cert_hier_2_intermediate_ca_cert())
+
+SERVER_KEY_1_PEM = resources.cert_hier_1_server_1_key()
+SERVER_CERT_CHAIN_1_PEM = (resources.cert_hier_1_server_1_cert() +
+                           resources.cert_hier_1_intermediate_ca_cert())
+
+SERVER_KEY_2_PEM = resources.cert_hier_2_server_1_key()
+SERVER_CERT_CHAIN_2_PEM = (resources.cert_hier_2_server_1_cert() +
+                           resources.cert_hier_2_intermediate_ca_cert())
+
+# for use with the CertConfigFetcher. Roughly a simple custom mock
+# implementation
+Call = collections.namedtuple('Call', ['did_raise', 'returned_cert_config'])
+
+
+def _create_client_stub(
+        port,
+        expect_success,
+        root_certificates=None,
+        private_key=None,
+        certificate_chain=None,):
+    channel = grpc.secure_channel('localhost:{}'.format(port),
+                                  grpc.ssl_channel_credentials(
+                                      root_certificates=root_certificates,
+                                      private_key=private_key,
+                                      certificate_chain=certificate_chain))
+    if expect_success:
+        # per Nathaniel: there's some robustness issue if we start
+        # using a channel without waiting for it to be actually ready
+        grpc.channel_ready_future(channel).result(timeout=10)
+    return services_pb2_grpc.FirstServiceStub(channel)
+
+
+class CertConfigFetcher(object):
+
+    def __init__(self):
+        self._lock = threading.Lock()
+        self._calls = []
+        self._should_raise = False
+        self._cert_config = None
+
+    def reset(self):
+        with self._lock:
+            self._calls = []
+            self._should_raise = False
+            self._cert_config = None
+
+    def configure(self, should_raise, cert_config):
+        assert not (should_raise and cert_config), (
+            "should not specify both should_raise and a cert_config at the same time"
+        )
+        with self._lock:
+            self._should_raise = should_raise
+            self._cert_config = cert_config
+
+    def getCalls(self):
+        with self._lock:
+            return self._calls
+
+    def __call__(self):
+        with self._lock:
+            if self._should_raise:
+                self._calls.append(Call(True, None))
+                raise ValueError('just for fun, should not affect the test')
+            else:
+                self._calls.append(Call(False, self._cert_config))
+                return self._cert_config
+
+
+class _ServerSSLCertReloadTest(
+        six.with_metaclass(abc.ABCMeta, unittest.TestCase)):
+
+    def __init__(self, *args, **kwargs):
+        super(_ServerSSLCertReloadTest, self).__init__(*args, **kwargs)
+        self.server = None
+        self.port = None
+
+    @abc.abstractmethod
+    def require_client_auth(self):
+        raise NotImplementedError()
+
+    def setUp(self):
+        self.server = grpc.server(futures.ThreadPoolExecutor(max_workers=10))
+        services_pb2_grpc.add_FirstServiceServicer_to_server(
+            _server_application.FirstServiceServicer(), self.server)
+        switch_cert_on_client_num = 10
+        initial_cert_config = grpc.ssl_server_certificate_configuration(
+            [(SERVER_KEY_1_PEM, SERVER_CERT_CHAIN_1_PEM)],
+            root_certificates=CA_2_PEM)
+        self.cert_config_fetcher = CertConfigFetcher()
+        server_credentials = grpc.dynamic_ssl_server_credentials(
+            initial_cert_config,
+            self.cert_config_fetcher,
+            require_client_authentication=self.require_client_auth())
+        self.port = self.server.add_secure_port('[::]:0', server_credentials)
+        self.server.start()
+
+    def tearDown(self):
+        if self.server:
+            self.server.stop(None)
+
+    def _perform_rpc(self, client_stub, expect_success):
+        # we don't care about the actual response of the rpc; only
+        # whether we can perform it or not, and if not, the status
+        # code must be UNAVAILABLE
+        request = _application_common.UNARY_UNARY_REQUEST
+        if expect_success:
+            response = client_stub.UnUn(request)
+            self.assertEqual(response, _application_common.UNARY_UNARY_RESPONSE)
+        else:
+            with self.assertRaises(grpc.RpcError) as exception_context:
+                client_stub.UnUn(request)
+            self.assertEqual(exception_context.exception.code(),
+                             grpc.StatusCode.UNAVAILABLE)
+
+    def _do_one_shot_client_rpc(self,
+                                expect_success,
+                                root_certificates=None,
+                                private_key=None,
+                                certificate_chain=None):
+        client_stub = _create_client_stub(
+            self.port,
+            expect_success,
+            root_certificates=root_certificates,
+            private_key=private_key,
+            certificate_chain=certificate_chain)
+        self._perform_rpc(client_stub, expect_success)
+        del client_stub
+
+    def _test(self):
+        # things should work...
+        self.cert_config_fetcher.configure(False, None)
+        self._do_one_shot_client_rpc(
+            True,
+            root_certificates=CA_1_PEM,
+            private_key=CLIENT_KEY_2_PEM,
+            certificate_chain=CLIENT_CERT_CHAIN_2_PEM)
+        actual_calls = self.cert_config_fetcher.getCalls()
+        self.assertEqual(len(actual_calls), 1)
+        self.assertFalse(actual_calls[0].did_raise)
+        self.assertIsNone(actual_calls[0].returned_cert_config)
+
+        # client should reject server...
+        # fails because client trusts ca2 and so will reject server
+        self.cert_config_fetcher.reset()
+        self.cert_config_fetcher.configure(False, None)
+        self._do_one_shot_client_rpc(
+            False,
+            root_certificates=CA_2_PEM,
+            private_key=CLIENT_KEY_2_PEM,
+            certificate_chain=CLIENT_CERT_CHAIN_2_PEM)
+        actual_calls = self.cert_config_fetcher.getCalls()
+        self.assertGreaterEqual(len(actual_calls), 1)
+        self.assertFalse(actual_calls[0].did_raise)
+        for i, call in enumerate(actual_calls):
+            self.assertFalse(call.did_raise, 'i= {}'.format(i))
+            self.assertIsNone(call.returned_cert_config, 'i= {}'.format(i))
+
+        # should work again...
+        self.cert_config_fetcher.reset()
+        self.cert_config_fetcher.configure(True, None)
+        self._do_one_shot_client_rpc(
+            True,
+            root_certificates=CA_1_PEM,
+            private_key=CLIENT_KEY_2_PEM,
+            certificate_chain=CLIENT_CERT_CHAIN_2_PEM)
+        actual_calls = self.cert_config_fetcher.getCalls()
+        self.assertEqual(len(actual_calls), 1)
+        self.assertTrue(actual_calls[0].did_raise)
+        self.assertIsNone(actual_calls[0].returned_cert_config)
+
+        # if with_client_auth, then client should be rejected by
+        # server because client uses key/cert1, but server trusts ca2,
+        # so server will reject
+        self.cert_config_fetcher.reset()
+        self.cert_config_fetcher.configure(False, None)
+        self._do_one_shot_client_rpc(
+            not self.require_client_auth(),
+            root_certificates=CA_1_PEM,
+            private_key=CLIENT_KEY_1_PEM,
+            certificate_chain=CLIENT_CERT_CHAIN_1_PEM)
+        actual_calls = self.cert_config_fetcher.getCalls()
+        self.assertGreaterEqual(len(actual_calls), 1)
+        for i, call in enumerate(actual_calls):
+            self.assertFalse(call.did_raise, 'i= {}'.format(i))
+            self.assertIsNone(call.returned_cert_config, 'i= {}'.format(i))
+
+        # should work again...
+        self.cert_config_fetcher.reset()
+        self.cert_config_fetcher.configure(False, None)
+        self._do_one_shot_client_rpc(
+            True,
+            root_certificates=CA_1_PEM,
+            private_key=CLIENT_KEY_2_PEM,
+            certificate_chain=CLIENT_CERT_CHAIN_2_PEM)
+        actual_calls = self.cert_config_fetcher.getCalls()
+        self.assertEqual(len(actual_calls), 1)
+        self.assertFalse(actual_calls[0].did_raise)
+        self.assertIsNone(actual_calls[0].returned_cert_config)
+
+        # now create the "persistent" clients
+        self.cert_config_fetcher.reset()
+        self.cert_config_fetcher.configure(False, None)
+        persistent_client_stub_A = _create_client_stub(
+            self.port,
+            True,
+            root_certificates=CA_1_PEM,
+            private_key=CLIENT_KEY_2_PEM,
+            certificate_chain=CLIENT_CERT_CHAIN_2_PEM)
+        self._perform_rpc(persistent_client_stub_A, True)
+        actual_calls = self.cert_config_fetcher.getCalls()
+        self.assertEqual(len(actual_calls), 1)
+        self.assertFalse(actual_calls[0].did_raise)
+        self.assertIsNone(actual_calls[0].returned_cert_config)
+
+        self.cert_config_fetcher.reset()
+        self.cert_config_fetcher.configure(False, None)
+        persistent_client_stub_B = _create_client_stub(
+            self.port,
+            True,
+            root_certificates=CA_1_PEM,
+            private_key=CLIENT_KEY_2_PEM,
+            certificate_chain=CLIENT_CERT_CHAIN_2_PEM)
+        self._perform_rpc(persistent_client_stub_B, True)
+        actual_calls = self.cert_config_fetcher.getCalls()
+        self.assertEqual(len(actual_calls), 1)
+        self.assertFalse(actual_calls[0].did_raise)
+        self.assertIsNone(actual_calls[0].returned_cert_config)
+
+        # moment of truth!! client should reject server because the
+        # server switch cert...
+        cert_config = grpc.ssl_server_certificate_configuration(
+            [(SERVER_KEY_2_PEM, SERVER_CERT_CHAIN_2_PEM)],
+            root_certificates=CA_1_PEM)
+        self.cert_config_fetcher.reset()
+        self.cert_config_fetcher.configure(False, cert_config)
+        self._do_one_shot_client_rpc(
+            False,
+            root_certificates=CA_1_PEM,
+            private_key=CLIENT_KEY_2_PEM,
+            certificate_chain=CLIENT_CERT_CHAIN_2_PEM)
+        actual_calls = self.cert_config_fetcher.getCalls()
+        self.assertGreaterEqual(len(actual_calls), 1)
+        self.assertFalse(actual_calls[0].did_raise)
+        for i, call in enumerate(actual_calls):
+            self.assertFalse(call.did_raise, 'i= {}'.format(i))
+            self.assertEqual(call.returned_cert_config, cert_config,
+                             'i= {}'.format(i))
+
+        # now should work again...
+        self.cert_config_fetcher.reset()
+        self.cert_config_fetcher.configure(False, None)
+        self._do_one_shot_client_rpc(
+            True,
+            root_certificates=CA_2_PEM,
+            private_key=CLIENT_KEY_1_PEM,
+            certificate_chain=CLIENT_CERT_CHAIN_1_PEM)
+        actual_calls = self.cert_config_fetcher.getCalls()
+        self.assertEqual(len(actual_calls), 1)
+        self.assertFalse(actual_calls[0].did_raise)
+        self.assertIsNone(actual_calls[0].returned_cert_config)
+
+        # client should be rejected by server if with_client_auth
+        self.cert_config_fetcher.reset()
+        self.cert_config_fetcher.configure(False, None)
+        self._do_one_shot_client_rpc(
+            not self.require_client_auth(),
+            root_certificates=CA_2_PEM,
+            private_key=CLIENT_KEY_2_PEM,
+            certificate_chain=CLIENT_CERT_CHAIN_2_PEM)
+        actual_calls = self.cert_config_fetcher.getCalls()
+        self.assertGreaterEqual(len(actual_calls), 1)
+        for i, call in enumerate(actual_calls):
+            self.assertFalse(call.did_raise, 'i= {}'.format(i))
+            self.assertIsNone(call.returned_cert_config, 'i= {}'.format(i))
+
+        # here client should reject server...
+        self.cert_config_fetcher.reset()
+        self.cert_config_fetcher.configure(False, None)
+        self._do_one_shot_client_rpc(
+            False,
+            root_certificates=CA_1_PEM,
+            private_key=CLIENT_KEY_2_PEM,
+            certificate_chain=CLIENT_CERT_CHAIN_2_PEM)
+        actual_calls = self.cert_config_fetcher.getCalls()
+        self.assertGreaterEqual(len(actual_calls), 1)
+        for i, call in enumerate(actual_calls):
+            self.assertFalse(call.did_raise, 'i= {}'.format(i))
+            self.assertIsNone(call.returned_cert_config, 'i= {}'.format(i))
+
+        # persistent clients should continue to work
+        self.cert_config_fetcher.reset()
+        self.cert_config_fetcher.configure(False, None)
+        self._perform_rpc(persistent_client_stub_A, True)
+        actual_calls = self.cert_config_fetcher.getCalls()
+        self.assertEqual(len(actual_calls), 0)
+
+        self.cert_config_fetcher.reset()
+        self.cert_config_fetcher.configure(False, None)
+        self._perform_rpc(persistent_client_stub_B, True)
+        actual_calls = self.cert_config_fetcher.getCalls()
+        self.assertEqual(len(actual_calls), 0)
+
+
+class ServerSSLCertConfigFetcherParamsChecks(unittest.TestCase):
+
+    def test_check_on_initial_config(self):
+        with self.assertRaises(TypeError):
+            grpc.dynamic_ssl_server_credentials(None, str)
+        with self.assertRaises(TypeError):
+            grpc.dynamic_ssl_server_credentials(1, str)
+
+    def test_check_on_config_fetcher(self):
+        cert_config = grpc.ssl_server_certificate_configuration(
+            [(SERVER_KEY_2_PEM, SERVER_CERT_CHAIN_2_PEM)],
+            root_certificates=CA_1_PEM)
+        with self.assertRaises(TypeError):
+            grpc.dynamic_ssl_server_credentials(cert_config, None)
+        with self.assertRaises(TypeError):
+            grpc.dynamic_ssl_server_credentials(cert_config, 1)
+
+
+class ServerSSLCertReloadTestWithClientAuth(_ServerSSLCertReloadTest):
+
+    def require_client_auth(self):
+        return True
+
+    test = _ServerSSLCertReloadTest._test
+
+
+class ServerSSLCertReloadTestWithoutClientAuth(_ServerSSLCertReloadTest):
+
+    def require_client_auth(self):
+        return False
+
+    test = _ServerSSLCertReloadTest._test
+
+
+class ServerSSLCertReloadTestCertConfigReuse(_ServerSSLCertReloadTest):
+    """Ensures that `ServerCertificateConfiguration` instances can be reused.
+
+    Because gRPC Core takes ownership of the
+    `grpc_ssl_server_certificate_config` encapsulated by
+    `ServerCertificateConfiguration`, this test reuses the same
+    `ServerCertificateConfiguration` instances multiple times to make sure
+    gRPC Python takes care of maintaining the validity of
+    `ServerCertificateConfiguration` instances, so that such instances can be
+    re-used by user application.
+    """
+
+    def require_client_auth(self):
+        return True
+
+    def setUp(self):
+        self.server = grpc.server(futures.ThreadPoolExecutor(max_workers=10))
+        services_pb2_grpc.add_FirstServiceServicer_to_server(
+            _server_application.FirstServiceServicer(), self.server)
+        self.cert_config_A = grpc.ssl_server_certificate_configuration(
+            [(SERVER_KEY_1_PEM, SERVER_CERT_CHAIN_1_PEM)],
+            root_certificates=CA_2_PEM)
+        self.cert_config_B = grpc.ssl_server_certificate_configuration(
+            [(SERVER_KEY_2_PEM, SERVER_CERT_CHAIN_2_PEM)],
+            root_certificates=CA_1_PEM)
+        self.cert_config_fetcher = CertConfigFetcher()
+        server_credentials = grpc.dynamic_ssl_server_credentials(
+            self.cert_config_A,
+            self.cert_config_fetcher,
+            require_client_authentication=True)
+        self.port = self.server.add_secure_port('[::]:0', server_credentials)
+        self.server.start()
+
+    def test_cert_config_reuse(self):
+
+        # succeed with A
+        self.cert_config_fetcher.reset()
+        self.cert_config_fetcher.configure(False, self.cert_config_A)
+        self._do_one_shot_client_rpc(
+            True,
+            root_certificates=CA_1_PEM,
+            private_key=CLIENT_KEY_2_PEM,
+            certificate_chain=CLIENT_CERT_CHAIN_2_PEM)
+        actual_calls = self.cert_config_fetcher.getCalls()
+        self.assertEqual(len(actual_calls), 1)
+        self.assertFalse(actual_calls[0].did_raise)
+        self.assertEqual(actual_calls[0].returned_cert_config,
+                         self.cert_config_A)
+
+        # fail with A
+        self.cert_config_fetcher.reset()
+        self.cert_config_fetcher.configure(False, self.cert_config_A)
+        self._do_one_shot_client_rpc(
+            False,
+            root_certificates=CA_2_PEM,
+            private_key=CLIENT_KEY_1_PEM,
+            certificate_chain=CLIENT_CERT_CHAIN_1_PEM)
+        actual_calls = self.cert_config_fetcher.getCalls()
+        self.assertGreaterEqual(len(actual_calls), 1)
+        self.assertFalse(actual_calls[0].did_raise)
+        for i, call in enumerate(actual_calls):
+            self.assertFalse(call.did_raise, 'i= {}'.format(i))
+            self.assertEqual(call.returned_cert_config, self.cert_config_A,
+                             'i= {}'.format(i))
+
+        # succeed again with A
+        self.cert_config_fetcher.reset()
+        self.cert_config_fetcher.configure(False, self.cert_config_A)
+        self._do_one_shot_client_rpc(
+            True,
+            root_certificates=CA_1_PEM,
+            private_key=CLIENT_KEY_2_PEM,
+            certificate_chain=CLIENT_CERT_CHAIN_2_PEM)
+        actual_calls = self.cert_config_fetcher.getCalls()
+        self.assertEqual(len(actual_calls), 1)
+        self.assertFalse(actual_calls[0].did_raise)
+        self.assertEqual(actual_calls[0].returned_cert_config,
+                         self.cert_config_A)
+
+        # succeed with B
+        self.cert_config_fetcher.reset()
+        self.cert_config_fetcher.configure(False, self.cert_config_B)
+        self._do_one_shot_client_rpc(
+            True,
+            root_certificates=CA_2_PEM,
+            private_key=CLIENT_KEY_1_PEM,
+            certificate_chain=CLIENT_CERT_CHAIN_1_PEM)
+        actual_calls = self.cert_config_fetcher.getCalls()
+        self.assertEqual(len(actual_calls), 1)
+        self.assertFalse(actual_calls[0].did_raise)
+        self.assertEqual(actual_calls[0].returned_cert_config,
+                         self.cert_config_B)
+
+        # fail with B
+        self.cert_config_fetcher.reset()
+        self.cert_config_fetcher.configure(False, self.cert_config_B)
+        self._do_one_shot_client_rpc(
+            False,
+            root_certificates=CA_1_PEM,
+            private_key=CLIENT_KEY_2_PEM,
+            certificate_chain=CLIENT_CERT_CHAIN_2_PEM)
+        actual_calls = self.cert_config_fetcher.getCalls()
+        self.assertGreaterEqual(len(actual_calls), 1)
+        self.assertFalse(actual_calls[0].did_raise)
+        for i, call in enumerate(actual_calls):
+            self.assertFalse(call.did_raise, 'i= {}'.format(i))
+            self.assertEqual(call.returned_cert_config, self.cert_config_B,
+                             'i= {}'.format(i))
+
+        # succeed again with B
+        self.cert_config_fetcher.reset()
+        self.cert_config_fetcher.configure(False, self.cert_config_B)
+        self._do_one_shot_client_rpc(
+            True,
+            root_certificates=CA_2_PEM,
+            private_key=CLIENT_KEY_1_PEM,
+            certificate_chain=CLIENT_CERT_CHAIN_1_PEM)
+        actual_calls = self.cert_config_fetcher.getCalls()
+        self.assertEqual(len(actual_calls), 1)
+        self.assertFalse(actual_calls[0].did_raise)
+        self.assertEqual(actual_calls[0].returned_cert_config,
+                         self.cert_config_B)
+
+
+if __name__ == '__main__':
+    unittest.main(verbosity=2)
diff --git a/src/python/grpcio_tests/tests/unit/credentials/README b/src/python/grpcio_tests/tests/unit/credentials/README
deleted file mode 100644
index cb20dcb..0000000
--- a/src/python/grpcio_tests/tests/unit/credentials/README
+++ /dev/null
@@ -1 +0,0 @@
-These are test keys *NOT* to be used in production.
diff --git a/src/python/grpcio_tests/tests/unit/credentials/README.md b/src/python/grpcio_tests/tests/unit/credentials/README.md
new file mode 100644
index 0000000..100b43c
--- /dev/null
+++ b/src/python/grpcio_tests/tests/unit/credentials/README.md
@@ -0,0 +1,15 @@
+These are test keys *NOT* to be used in production.
+
+The `certificate_hierarchy_1` and `certificate_hierarchy_2` contain
+two disjoint but similarly organized certificate hierarchies. Each
+contains:
+
+* The respective root CA cert in `certs/ca.cert.pem`
+
+* The intermediate CA cert in
+  `intermediate/certs/intermediate.cert.pem`, signed by the root CA
+
+* A client cert and a server cert--both signed by the intermediate
+  CA--in `intermediate/certs/client.cert.pem` and
+  `intermediate/certs/localhost-1.cert.pem`; the corresponding keys
+  are in `intermediate/private`
diff --git a/src/python/grpcio_tests/tests/unit/credentials/certificate_hierarchy_1/certs/ca.cert.pem b/src/python/grpcio_tests/tests/unit/credentials/certificate_hierarchy_1/certs/ca.cert.pem
new file mode 100644
index 0000000..604b86f
--- /dev/null
+++ b/src/python/grpcio_tests/tests/unit/credentials/certificate_hierarchy_1/certs/ca.cert.pem
@@ -0,0 +1,31 @@
+-----BEGIN CERTIFICATE-----
+MIIFZDCCA0ygAwIBAgIJAKfkDFZ6+Ly/MA0GCSqGSIb3DQEBCwUAMD8xCzAJBgNV
+BAYTAnVzMQ4wDAYDVQQIDAVkdW1teTEOMAwGA1UECgwFZHVtbXkxEDAOBgNVBAMM
+B3Jvb3QgY2EwHhcNMTcxMTAyMDAzNzA1WhcNMzcxMDI4MDAzNzA1WjA/MQswCQYD
+VQQGEwJ1czEOMAwGA1UECAwFZHVtbXkxDjAMBgNVBAoMBWR1bW15MRAwDgYDVQQD
+DAdyb290IGNhMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAxlSUuSbi
+o66tT2ZCqu9wNqSX8VhAJkmrAT5y6m2V0VlQ8Gz7ddynW5UVSmtvDNTebZ15FrvO
+6Ng7QnwXXNs/dEzl6oMe6AKDZpuWScVkiqH1UYWBkMLRygWCTEYpSTWTpZWk1zxj
+DJ2LlIoO1X/ufLyLOfy2a2XEz8ICzJePmqVca6fmfEtCTj1/8FcwCBF6YlUWVzlR
+wewjanQo/lorTYbub+Q6LGxPXZ8W0qoKZzLDSD9cnj4pcJzGGFeu9KkNaW4rldZG
+t7mTGQqIRc98dDRc9Jb7PqL8tMPLidw1KErUi05ofxggc5vqNnj4xBl6aX6b/EYN
+rBLzO2e0FazX6TwNKwwg68vbOanpDq5LVmIUH8bY1zNZ+JPBGO9pXlAA0YwLx86r
+R7YhQ431ZpJ2KGnYjVhYnZ2L3NjV3UYX3x5Z3OrDj9hybhucJB48DMQ1+loEabwK
+fSUJtcSPc8dCIibxVKidBFgaTPXtHy2MPXuhMhR7PCtMpE7RPUoYmdZLr9FNN1ty
+/RAbwBfuhGLbRI2qqJgbOzHJHaOY/FtShfooLz7lt4LIjPTARaNsulG2rbv+m3z9
+mhNjL+peV8gni/xyOYYTbdzZagLrtSHeTWsITvmVt0flMHkjHyv35rw23+hBlSjp
+6+S+0MmwuwxqBBccBSlZ9t3Xh1N+vFkb2UkCAwEAAaNjMGEwHQYDVR0OBBYEFJWE
+tQwTbTCgZWNN08VSxjdNA0oaMB8GA1UdIwQYMBaAFJWEtQwTbTCgZWNN08VSxjdN
+A0oaMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgGGMA0GCSqGSIb3DQEB
+CwUAA4ICAQCNjPv/e3ozX1PuN5Tluf0yOmKCxKVCK3Pp98WkDzH4Rp1urEeYrGJL
+vBNcl17avOJ0e+zTVYPXFviFbsBsU/zaf+TqEujXabsdL+nvvCJ2mMqYn4wyDFjS
+zDNbGH6O0ENZz5NSY0/UGSOHYrYnYB94QRFLbbf0Y3PmBS2eRNjIUnv7ytPZNMi/
+piM+QhPb0Ebyk0rHQZ0RAJaC/wsEtqP8TGV/fx+AzG7zW/zxgPTrgIThy138tLQ+
+xCVDP9H2c17nVP6vjYzKnMZ94uGrGqUzV9vU7EqYl0uZflIf98pLfdKHnQ3heqds
+8KQPNKRxVvcc92qv2pQY951wb1fkhLutjHn7TUvrenyAngz+Vs19NxbqLPys1CTw
+iaL7vZ8VE/aEDm1tjt5SLM474tpATjk1+qMRaWnii8J5rTodYHP+Zu2GxyIrMiGq
+tfNZMYI0tETK1XmEo75E/3s9pmIeQNGKLFp+qL7xrVyN/2ffNv0at8kkqXluunK9
+/Ki0gKYlGFm4Eu8t/nHMqhBx/njYg6pLDuarLW6ftUV7aHd7qKcCWOWqK6gnH/vX
+3Apv31eltZBBVN69p3CFy2oMnjrom2Yn/DUXFwrJLBiNJ1dd1JyDxpqpJ74ZQy+/
+pSRWMTRM5SuC7lYARx5rYPmp6cZJWyWRH/3r7bwS699/W965pa5nug==
+-----END CERTIFICATE-----
diff --git a/src/python/grpcio_tests/tests/unit/credentials/certificate_hierarchy_1/intermediate/certs/client.cert.pem b/src/python/grpcio_tests/tests/unit/credentials/certificate_hierarchy_1/intermediate/certs/client.cert.pem
new file mode 100644
index 0000000..44bc562
--- /dev/null
+++ b/src/python/grpcio_tests/tests/unit/credentials/certificate_hierarchy_1/intermediate/certs/client.cert.pem
@@ -0,0 +1,28 @@
+-----BEGIN CERTIFICATE-----
+MIIExzCCAq+gAwIBAgICEAMwDQYJKoZIhvcNAQELBQAwRzELMAkGA1UEBhMCdXMx
+DjAMBgNVBAgMBWR1bW15MQ4wDAYDVQQKDAVkdW1teTEYMBYGA1UEAwwPaW50ZXJt
+ZWRpYXRlIGNhMB4XDTE3MTEwMjAwMzcwNloXDTI3MTAzMTAwMzcwNlowPjELMAkG
+A1UEBhMCdXMxDjAMBgNVBAgMBWR1bW15MQ4wDAYDVQQKDAVkdW1teTEPMA0GA1UE
+AwwGY2xpZW50MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAwquL6gtP
+R7P9xJK76FTj8fI5TSJa3cAMt1p6CmessjHQq7nQ6DWLGVi4XIt9Sc/1C3rXupOe
+90Ok4L0tsuVZH78Wn0EBmBH7S4IbhU9P+aJ9mcigepj1lnxWqoVblgeJYKMOOwAf
+pAKUNMWDSm+nCfwE+R5d8d8cfA41Awq1jTRjOVpiJq6aoKfs791a1ZkZde3kFrNV
+AVjC06GgA1lZd3sHf94hmLeC+xJztRXVE9e+7dcc7nFDH0t5DIKYBAklsHg77mZa
+3IK4aOZew7Lm6diPoMnAzXh2rWpJU6RrEE29gIkJBsF8CL1Ndg9MzssCg6KBjoai
+Vt5dJ+4TSEGCOwIDAQABo4HFMIHCMAkGA1UdEwQCMAAwEQYJYIZIAYb4QgEBBAQD
+AgWgMDMGCWCGSAGG+EIBDQQmFiRPcGVuU1NMIEdlbmVyYXRlZCBDbGllbnQgQ2Vy
+dGlmaWNhdGUwHQYDVR0OBBYEFPeuKDCswk8jaH9tl6X+uXjo+WM1MB8GA1UdIwQY
+MBaAFCoqYgmKh3CUafVp+paXxfz+He+FMA4GA1UdDwEB/wQEAwIF4DAdBgNVHSUE
+FjAUBggrBgEFBQcDAgYIKwYBBQUHAwQwDQYJKoZIhvcNAQELBQADggIBADYAp8XS
+UjMEpX/zVjRWpAAT4HNEJylCV1QNyhBIAyx38A6xJYuFIx966Htd6W9/Rw4sUY6y
+F4pOmnLCRxIPqFzzMYcBHSpynlcu5G7zqIod3wYIk7BNlB0AzkZn6yD8bM1y5Plf
+myzQVDEGggrDtaW2EehhNIB+wOmbRGITjIcZUEr8V4BlLXkCqOuxauxl82d5/k2w
+LAhjOb9d1VW6RT8+Lcn6drhHZdvtSCe8Z27BcXhaQLL8366mhbigKYJt5adD0KOx
+pl0MQcoL1Rth5cJEj+1/lgUaxcnvh7TaIIGEx0h3olQXsTxSTypU/nww2Ic41xdG
+xl3xvHsxe20IvOOAMRfS/LPW7MCtQ3k0BqB/rAQvmB0r5YITLlMJuBqg+zjYrG/j
+s5szSGAz9r0leFuPraeuZA41d9UBTAJMoVrrQZ4xVHMXQi1oz9E9KlIdbO9+spvC
+ulfO+D+Z4a9trYSWhnQL2dSHT0+kHqJ/8GipiUNP/yAC76dRpDVR3xtYNr73iw0j
+hyDsVjihTD8JBebs3axnt+Bc+FwoCCd6CVcsggfGUNhu/N5LS78b13PcaRzrUNjU
+Eh+8cJvMLst+UQzePlyazzpn7jjN3KsBzWUkbnXCtUs2qRMn8f2gZqliDo7JSFvy
+WtBSCYpikOivuJSQUlrHQ8NaXeddyWQzLY79
+-----END CERTIFICATE-----
diff --git a/src/python/grpcio_tests/tests/unit/credentials/certificate_hierarchy_1/intermediate/certs/intermediate.cert.pem b/src/python/grpcio_tests/tests/unit/credentials/certificate_hierarchy_1/intermediate/certs/intermediate.cert.pem
new file mode 100644
index 0000000..98e1366
--- /dev/null
+++ b/src/python/grpcio_tests/tests/unit/credentials/certificate_hierarchy_1/intermediate/certs/intermediate.cert.pem
@@ -0,0 +1,31 @@
+-----BEGIN CERTIFICATE-----
+MIIFaDCCA1CgAwIBAgICEAAwDQYJKoZIhvcNAQELBQAwPzELMAkGA1UEBhMCdXMx
+DjAMBgNVBAgMBWR1bW15MQ4wDAYDVQQKDAVkdW1teTEQMA4GA1UEAwwHcm9vdCBj
+YTAeFw0xNzExMDIwMDM3MDZaFw0yNzEwMzEwMDM3MDZaMEcxCzAJBgNVBAYTAnVz
+MQ4wDAYDVQQIDAVkdW1teTEOMAwGA1UECgwFZHVtbXkxGDAWBgNVBAMMD2ludGVy
+bWVkaWF0ZSBjYTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAOOxzve7
+CG2P9SvKfXkJVTXkj4y79JSZ77Kud/TiPfDbHTqZWKuLTXkOCkCCxfpuJvWXnnj5
+1AeLCdKx9hEwJQeU23EXDt1K+RsRyl09SXtPNnJnqHD1mUHRQR28vGX5ctrQzK8J
+Sa6/mHW4bX8ol100npbgVMDnM4IDfLYcsv4BXMICGkSHOW6Gn0zJaeHzRVPpmnK/
+0k/GQAcIrU2sZ39kVlVQkWq3HJC28cNL/P04hjh4gAf0evo/k9VrEtxPWYMfiPDt
+kOAKueoPv/VTA/zL5t8lyzfhrhxvsJxFg/klapPXK0gLLbhsHyOhnkbrzvmSR4Rw
+xubYJ2dDK0DKx+BIZqlFznjP9BvOtvtuVVMyqg9cfgc7J/OjvAguO0f93MLSfIWP
+uISqv7Llt/Blvy/xI5owvOKVc/hm3d+5pqjWBC1HkVwo4qugpWmM49dFWl4kc4c7
+ayYUjTmcgoj1ZR89w4Off/bPd1A6gXqSkw2VQfgFF+uOos84fP1V+zPWhp3UDY3P
+bFeJtuTdv1gR5w1jCIq6xVJ+UsyDZBaYP7yBBRiNzS1/yXJpnXrvHmDfUeQHLBPR
+N0nbMjqXJ1dVpZwydiI0Qx9DnJtOaq/spUreXr8+PU2jeQdCCAN21MB1umr2gZBJ
+8MZBStTgE7SDByfGmGfp7B5/s/r4O/rNc4WzAgMBAAGjZjBkMB0GA1UdDgQWBBQq
+KmIJiodwlGn1afqWl8X8/h3vhTAfBgNVHSMEGDAWgBSVhLUME20woGVjTdPFUsY3
+TQNKGjASBgNVHRMBAf8ECDAGAQH/AgEAMA4GA1UdDwEB/wQEAwIBhjANBgkqhkiG
+9w0BAQsFAAOCAgEAvzLu/Jc8DlfCltVufC54UZ8DVwUfxdGapNBGv4icrs1wMV3S
+xqdaLO+vSp9NeEufi724+/hj4URapW9kSt2TMD7BNJ61QSATZFJajxTFgGa0Zz95
+RBDw8/b5Arz/2pOF4VX+FJ+wqHvoH/2A0T+fwz8hLORhxZHv/cUN6kif4FKCwryQ
+s89e694kXkEiJfquvu7DR9hYCLOJwzMOOJiTnjz3hlQg4WGu7Z8ZvqzCM+how1hr
+nYbUx6a+HfoUf79AHJB0N1EsEEetJ+omvTdrrayCvy1bHA3QgHlJ28QZIJ7MzX9E
+n11/xQ95iTuSp8iWurzjTjbrm7eHnGUh+5QubYLXOzbqKzNZu72w0uvWv6ptIudU
+usttltiwW8H9kP0ArWTcZDPhhPfS9impFlhiPDk1wUv2/7g+Zz1OaOb7IiSH0s8y
+FG72AB8ucJ5dNa/2q5dJiM8Gm5CbiVw5RXTBjlfTTkNeM6LBI3dRghpPdU7Kbfhn
+xYs9vnRZeRMJHrcodLuwVcpY/gyeJ0k5LD6eIPCJmatkYZ122isYyMX8lL2P5aR+
+7d2hhqcOCproOrtThjp6nW2jWTB+R/O2+s6mhKSPgfbY2cdky1Y9FSJxSNayb9B8
+eQ+A29iOHrGVAA0R/rvw119rLAYxjXzToM28owx7IyXKrBaU4RMv5yokgag=
+-----END CERTIFICATE-----
diff --git a/src/python/grpcio_tests/tests/unit/credentials/certificate_hierarchy_1/intermediate/certs/localhost-1.cert.pem b/src/python/grpcio_tests/tests/unit/credentials/certificate_hierarchy_1/intermediate/certs/localhost-1.cert.pem
new file mode 100644
index 0000000..f15f1cf
--- /dev/null
+++ b/src/python/grpcio_tests/tests/unit/credentials/certificate_hierarchy_1/intermediate/certs/localhost-1.cert.pem
@@ -0,0 +1,30 @@
+-----BEGIN CERTIFICATE-----
+MIIFFzCCAv+gAwIBAgICEAAwDQYJKoZIhvcNAQELBQAwRzELMAkGA1UEBhMCdXMx
+DjAMBgNVBAgMBWR1bW15MQ4wDAYDVQQKDAVkdW1teTEYMBYGA1UEAwwPaW50ZXJt
+ZWRpYXRlIGNhMB4XDTE3MTEwMjAwMzcwNloXDTI3MTAzMTAwMzcwNlowTTELMAkG
+A1UEBhMCdXMxDjAMBgNVBAgMBWR1bW15MQ4wDAYDVQQKDAVkdW1teTEKMAgGA1UE
+CwwBMTESMBAGA1UEAwwJbG9jYWxob3N0MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A
+MIIBCgKCAQEArRAy0Nim9P883BAisXdFoKmgHGTtcLH/SzwkkPWTFHz0rHU1Klwz
+w8u3OkRyvgoQp7DqkohboNMDwg5VrOOcfKwtM2GZ5jixo+YKvJ25oj8Jfr+40baz
+nyWTmOcfoviKrb7u2T9BPEEz5og+lXRDAsTFATGaQDX2LN3Dd9KIw+7sWY+gc3Zi
+13HHaWYhtmfJjzFbH1vDxHKCdSdgtPyEhqcJ4OC6wbgp/mQ01VlPAr08kRfkC8mT
+TS7atqc410irKViF3sWi4YNPf7LuBrjo75FIIOp+sQgZE6xwOuZ/9bT2Zx/IUtCC
+TqzVgZI0s5NVlINtWR6eyyxQ1uDKTs4xrQIDAQABo4IBBTCCAQEwCQYDVR0TBAIw
+ADARBglghkgBhvhCAQEEBAMCBkAwMwYJYIZIAYb4QgENBCYWJE9wZW5TU0wgR2Vu
+ZXJhdGVkIFNlcnZlciBDZXJ0aWZpY2F0ZTAdBgNVHQ4EFgQUDE8pwi7aELJjvyNT
+ed81/KIgGfowaAYDVR0jBGEwX4AUKipiCYqHcJRp9Wn6lpfF/P4d74WhQ6RBMD8x
+CzAJBgNVBAYTAnVzMQ4wDAYDVQQIDAVkdW1teTEOMAwGA1UECgwFZHVtbXkxEDAO
+BgNVBAMMB3Jvb3QgY2GCAhAAMA4GA1UdDwEB/wQEAwIFoDATBgNVHSUEDDAKBggr
+BgEFBQcDATANBgkqhkiG9w0BAQsFAAOCAgEA2cvXxJw120Z9oWXyGwR6CH7TcXoy
+1i77B1M5j0Krvkjh2/MkEU+JxpZcrhAgZODK9wMPeIUIpJNw2t6Hg+vigpInu7pY
+MXR4IA5XLnhGV/hueXa0JLia5FG1TISxr4piW6Jd9P2pOt3ECm3Url/F0OeFF/74
+jGaAlWkbhqWJ9M7Gd4QP2wUNm0P4CwAqS9DC6dnMz+JXTakEUirOpmq7U8UKT+5N
+QS1K4WuH671n4MiYye3+UoRYt4zPjOzN+QxzvAMtkUBspPmWD6txmD5tKUYDECqn
+0sSbY6ytD30OTHIbICFp40arOffmEEJSriL+uQNPPmvqMxX1G2kUFGm15NLPs8Xa
+J7ChrAaJzssN5J3myZUbDfCuxmTkWg+hGvGmxLraVNWc3fzKFmdszSkXrGIdf2HR
+gZeFI3w6M4Ktx3KctXlsjwqQTYZI/WwLOEpsrHQBPBLQhISyNw4xjZ4MxK8SFZuQ
+IiGps/do0eEgeQ+o3gD1dIXt8YxFIxrgk0pzJONpXGgv/cZrukbLNTBdkTSkIwtx
+TXKdiJbO17H24MvW+UxFdsIoJXmfQZWdQC3p+Dl0iP+K80aI6WbaysmToHuOi216
+e49nmiM72Izul2zmBi7Cq2nRQbHAETsFfqC34FzJlx0aP8WS953IBD0jNi1BB+AX
+BxwiZ1rPjeMvekI=
+-----END CERTIFICATE-----
diff --git a/src/python/grpcio_tests/tests/unit/credentials/certificate_hierarchy_1/intermediate/private/client.key.pem b/src/python/grpcio_tests/tests/unit/credentials/certificate_hierarchy_1/intermediate/private/client.key.pem
new file mode 100644
index 0000000..d8a2163
--- /dev/null
+++ b/src/python/grpcio_tests/tests/unit/credentials/certificate_hierarchy_1/intermediate/private/client.key.pem
@@ -0,0 +1,27 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIIEogIBAAKCAQEAwquL6gtPR7P9xJK76FTj8fI5TSJa3cAMt1p6CmessjHQq7nQ
+6DWLGVi4XIt9Sc/1C3rXupOe90Ok4L0tsuVZH78Wn0EBmBH7S4IbhU9P+aJ9mcig
+epj1lnxWqoVblgeJYKMOOwAfpAKUNMWDSm+nCfwE+R5d8d8cfA41Awq1jTRjOVpi
+Jq6aoKfs791a1ZkZde3kFrNVAVjC06GgA1lZd3sHf94hmLeC+xJztRXVE9e+7dcc
+7nFDH0t5DIKYBAklsHg77mZa3IK4aOZew7Lm6diPoMnAzXh2rWpJU6RrEE29gIkJ
+BsF8CL1Ndg9MzssCg6KBjoaiVt5dJ+4TSEGCOwIDAQABAoIBABECKAFU56JeKYfp
+Qh20fQ4Amd0RaVsCkpnaf9s037PaAl9eptADDZozVDhRv6qZTtGn8/1LNJJqCJfS
+L5H30+egLHvRlDATMh+QyJLHMTegaNTs4IiVoK97QZ84c54SHoCg/ndNNXaA+y35
+K9VvF+sZZ93UN2UQl06Hdz5Cy0YA7L5HIIH3Ezk0ArAw4AarLil5mv4yEz2ApZhm
+Tw4I4yNfxB7tZeP+ekNg0XXRL1quA0tGblp+A5fAFfVMDplqqB2d3/KxPR9FSEOi
+4PzBZ5Mq2wQBPIaNog5um9qkw6VKxjl5sQGhP1GGTA8iZqR9iM2+xh57xdCZm3g3
+jcr+aPECgYEA42mXTsF/4oBQtU6hh/sOCMWHhxAPstKpQHFMKGYLHKEJ/V1qq0Sd
+d0kswAYCmH5G9ookzu5p7pNf0hUUHO5EwelpSZ3FEmtIM+oBwSnDk3vGuadYXN5X
+fPuVUla65B1F9SSwapYNBUAiRgrY69Knca2rkTSdcZQaBuWmo684UQcCgYEA2yRE
+P23I/9N6AVhKB/zTRtil1AxnTW8o+j7AE4q1o+xly7DS7DT34INaLKLiuG6ylV1F
+UoTiqmWqH3A7m3o3Id2AnVf/oDoKV78LCXRF3dJJWvzrPdob2fLlwyjgqXYvmD3O
+UH/OFY2blYcAHOYib1Y1AAhHPlXiHA52BYZtnC0CgYAVjjitWmII0ijURrPA8+cM
+pcyG3NrgFF++n/6cBbAf8pPD1Er8GPDkEaeQPAGa+r03OTjr9GVOG+IFQ8I4S81w
+o/M66x129XxOj2vDJ3ZGUIExr88MXnbkfeRVfasRXET5S5T9RWPOj5mwEe8lyz3b
+5J5SkS4rSeJ9rN7yvPUVmQKBgAvrrB67LRzldxSNpfFLSn7nGBYx2oi2zEbYlQA7
+ImhZWqw64S5iLz2yR3x4G9cmhmZjnXrAqcfVIez14PgzLL6V2wI0ID6qCZf+V25b
+OdW4M69UZMOHks5HTUJRfe8Z87rXWdq9KQu5GUaIAnSP/D2MNfPbf2yfpV4bV0Yz
+qtC9AoGAD3/XXaeGCdV5DPomEmehp84JXU2q/YECRvph46tr4jArG67PCvx2m84B
++W6my4Yi7QJcW4gC0gsdAuxbJl4Y7MCZBnTtNIRCRnHEIciKITJ/+brFln5QUgyn
+WnXEPN8q7VjSVXGrljFuLWkzi2Vh8iZDgourNfW+iYDGCJjx1H0=
+-----END RSA PRIVATE KEY-----
diff --git a/src/python/grpcio_tests/tests/unit/credentials/certificate_hierarchy_1/intermediate/private/localhost-1.key.pem b/src/python/grpcio_tests/tests/unit/credentials/certificate_hierarchy_1/intermediate/private/localhost-1.key.pem
new file mode 100644
index 0000000..aa83f1a
--- /dev/null
+++ b/src/python/grpcio_tests/tests/unit/credentials/certificate_hierarchy_1/intermediate/private/localhost-1.key.pem
@@ -0,0 +1,27 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIIEogIBAAKCAQEArRAy0Nim9P883BAisXdFoKmgHGTtcLH/SzwkkPWTFHz0rHU1
+Klwzw8u3OkRyvgoQp7DqkohboNMDwg5VrOOcfKwtM2GZ5jixo+YKvJ25oj8Jfr+4
+0baznyWTmOcfoviKrb7u2T9BPEEz5og+lXRDAsTFATGaQDX2LN3Dd9KIw+7sWY+g
+c3Zi13HHaWYhtmfJjzFbH1vDxHKCdSdgtPyEhqcJ4OC6wbgp/mQ01VlPAr08kRfk
+C8mTTS7atqc410irKViF3sWi4YNPf7LuBrjo75FIIOp+sQgZE6xwOuZ/9bT2Zx/I
+UtCCTqzVgZI0s5NVlINtWR6eyyxQ1uDKTs4xrQIDAQABAoIBAC56mDswxH4uAmlT
+yA2Da+a/R6n4jTBkDZ1mFKf93Dd3a7rZa6Lpylk+YAI9GdfiGiD/SbB7AKjLo0m9
+0dKx+ngdQbJ39v42obbT9HQ9o/poFaO91+QyvkDytZYuFHgPaidJjRo5e8qz9D1o
+v+4hoFGhCQvOB5BRLcFU+cc3etWr5t61sNL/kKCWEDd+MWWsOCHpdhEoWC+o25pC
+bhD3FG5xoz+8zL7WdNfke/4twfKoBJ/kq89bfIkl8eKpg387WBQY44RJF7/zVr7a
+9dsUuW2y/wVXslCHChjSrxhRlOyy5ssv3EgKh8gPkZ+oeKuONqAGw27nyKyvpjxS
+i62K+WECgYEA4oKpIS2D77RCC6rpYIK6KYfbUcNSOtHFvcbf0RH9Oi8vSRYum2ZA
+/ITdWSFgWkhT6iOSPuvZlu/EvueWDgNgW1ZVsTMFeapz1+Jwk7JRoBKF1dUEwELh
+jdAswdh0MLbgBYs6NXtVVkeK2ocgZtosmt1PUktl566NlyIyhOjH6vkCgYEAw5g0
+cteTpz+noKsfWcbnjyesuQy0caICfZIE01nKv9rKTF8BtCO6Qxj10iM2o00jW7Vl
+tZa/igjuqvozXAHBI3xegtrWV05urkjj3FB/Pyuqsx3wxhAdSNchQjdTjwUBQEzp
+3ztGSlDTRPpijnpW28lg8Kkr3weryaHvl0xM1VUCgYBqnTN8QU8rgT3g/gYw/fcf
+2ylY98V5mAkqBTSN1JjLTTBFh2JSlLOb5/HDpRkUBZ0xxKJuaVaWW67QaHLRj7dH
+5oAZErnOBXPXNmbkrfcLkAxclJJS6Gf/9u9KIla2Iy2YjmrMh4uoO65Yo2eV4bVD
+A031nzWM8jUE4PzEYEjRCQKBgHDdTj6KiQg0Yg0DUabjcNEZasCpRSJhAyDkdmZi
+5OzKWnuxQvFowF1hdM/aQ/f9Vg7gYJ1lLIeBWf9NOv+3f3RzmrHVh2N/vbxSETIb
+PSH9l5WeDEauG8fhY66q8EuR7sPk3ftTX98YPqEJ/n8Ktz5COO8GH2umKInEKNXc
+UGW1AoGAfENy7vInNv0tzFWPSYdFgesvzo7e8mXyVO8hCyWvY3rxW2on7qfLF3Z9
+fHjd7P9gULja0n1kvmxwUC3u20RrvpY59F4hfi+ji2EiubS9Yhszd2e1CLeRMkln
+ojDjnflN32ZbWVHX/i6g3Dabq9JOD0FsOaOlriLMuofdA6jTUFE=
+-----END RSA PRIVATE KEY-----
diff --git a/src/python/grpcio_tests/tests/unit/credentials/certificate_hierarchy_2/certs/ca.cert.pem b/src/python/grpcio_tests/tests/unit/credentials/certificate_hierarchy_2/certs/ca.cert.pem
new file mode 100644
index 0000000..212b586
--- /dev/null
+++ b/src/python/grpcio_tests/tests/unit/credentials/certificate_hierarchy_2/certs/ca.cert.pem
@@ -0,0 +1,31 @@
+-----BEGIN CERTIFICATE-----
+MIIFZDCCA0ygAwIBAgIJALhSfZ8i0rWTMA0GCSqGSIb3DQEBCwUAMD8xCzAJBgNV
+BAYTAnVzMQ4wDAYDVQQIDAVkdW1teTEOMAwGA1UECgwFZHVtbXkxEDAOBgNVBAMM
+B3Jvb3QgY2EwHhcNMTcxMTAyMDAzNzU4WhcNMzcxMDI4MDAzNzU4WjA/MQswCQYD
+VQQGEwJ1czEOMAwGA1UECAwFZHVtbXkxDjAMBgNVBAoMBWR1bW15MRAwDgYDVQQD
+DAdyb290IGNhMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEArHaQ3uyp
+wVaVPZDYvy/EJbnP7KbZNPBvKpQCDEqg9B2TPaC8WVjiqT6I88c+KcGuB8nADJdk
+o10iZC5AwbrXK4ELSCOvBpxYI5sjoFcv3lZ/oe4e650QO2L/ADmtwLaLYK6rZkwW
+Sd90yCGF7ZOTZTJZDwmWEl+ohi+2ow6sRMHKcSKUNfx9G5BB7TOzoqUxqH+moEds
+YpjVMEcKzQi2FmbRd+8Dlg2eGqA2V4faprGQwoYz8NqJZGa/KPpRvXE2VjSTDN6b
+rJ7mmui6eYN53mZEBRYogyoQHdFXhK02FgyoPEgR/wQlLLbQ+xxOcv02YsOljtza
+hl5LjeNUYPMjyhef0QpONp+5NcFhZf38DsSq5EWZLLxPScxwl0lBQkJTjo5ARuFl
+Mrv50RYrLwv4ImsiO2ftE7gAX4vNsgcixnCHd6rNzoGimf1+DSvDVJ9ujWo7HPN3
+7ONuoyjsU4mUJJpYXs8zHx5WSxaYiPJRcmG3LjcU5/A+Fs7bkqSrlEjJsG29xDrO
+vKR7hH+m6MwcIcXSh9wjjAIvHxAALdU9xaYE3hmVkoxew1mRBsYq34h2vpwGOY5r
+0njRQyGGZnVa8qkQd6P3U5fcvLOM8v9QImZqRDS2jAGZXYruo/RIgJpklVX7ZY0+
+CnGdz4YxgLyOBJCDu3aEgL1oON3mg2SsrVMCAwEAAaNjMGEwHQYDVR0OBBYEFOBO
+9R6yEY6KOE+aSClwD2BQtWXKMB8GA1UdIwQYMBaAFOBO9R6yEY6KOE+aSClwD2BQ
+tWXKMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgGGMA0GCSqGSIb3DQEB
+CwUAA4ICAQBElio7lLZ2eNt0tDPVSkChksc0IJ2/DpjYjqJzqxF/jZ2oToaAn2Er
+9iHl8ggTLB5WrTQxO1ev7qOwQsk9hrgvZ+EQCBTbyDyfNwVjgftH5jdQGdbyrnuJ
+yaks1mnd8is5ZZQmmQSd7GVOMTYi/7yH0xI4DHQ386dwnf5eKdoOI7yrVufEMxRx
+tB3Wv8KrX4z47zsIO28H/O0T26oUkrd4PEqFwDa5HQr6iG7QQgoGD/DPLgbBudlO
+kEos9fmXxiX60RLziKCE/DAxI3YWPvG3WhIWnVj22Oz6apz2pYWpOKwlaihNYrhq
+8xc02vIFwKh+t7D+wF4KHfduyMJ/wKVc5dzpNbTgkZePPKSB7QgbsMeRqbdPoXQF
+pMuzfj8VCWzpqBeHqE/adSCZhzeTrnyiYavF4T2vkSC5KJu+MHmbZ3nU9bcnnEy+
+24oEv9cEAiYNkvftbD+5ByEtkcBB2uT47sbiGrAeco+GxFGUVqi1IjObqrkIrPzV
+OjQhTZV6qgYCOuniJiGfoiMeHqdaDybpqo1bIrxSlvGRNcVoOsKt2/KP1DzW4ARZ
+hoRvayU2apHz/T5TAailqAW2MsrjGRaVHQTmeZKag8CKtAcjWzui0J2DnfXxUMn8
+R3ruFu3xJduOT1VghT9L9udvX9YhPCIKVL9+B5eFX9eMV6N7hUnVug==
+-----END CERTIFICATE-----
diff --git a/src/python/grpcio_tests/tests/unit/credentials/certificate_hierarchy_2/intermediate/certs/client.cert.pem b/src/python/grpcio_tests/tests/unit/credentials/certificate_hierarchy_2/intermediate/certs/client.cert.pem
new file mode 100644
index 0000000..b6f4280
--- /dev/null
+++ b/src/python/grpcio_tests/tests/unit/credentials/certificate_hierarchy_2/intermediate/certs/client.cert.pem
@@ -0,0 +1,28 @@
+-----BEGIN CERTIFICATE-----
+MIIExzCCAq+gAwIBAgICEAMwDQYJKoZIhvcNAQELBQAwRzELMAkGA1UEBhMCdXMx
+DjAMBgNVBAgMBWR1bW15MQ4wDAYDVQQKDAVkdW1teTEYMBYGA1UEAwwPaW50ZXJt
+ZWRpYXRlIGNhMB4XDTE3MTEwMjAwMzgwMFoXDTI3MTAzMTAwMzgwMFowPjELMAkG
+A1UEBhMCdXMxDjAMBgNVBAgMBWR1bW15MQ4wDAYDVQQKDAVkdW1teTEPMA0GA1UE
+AwwGY2xpZW50MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAyxZFTLqv
+Gd9SpFAykyRyLQgHcR5hgD55mz+9fl1OfnMoAc7yTdPVLksDLmeFUlxcvCtLHysJ
+klIBX62c6LzbsVcfLg/DPJlQxFnkhJCRKen4fp7x9h62qqJkDFVXsiEFza9L1lsN
+4OwqU8i4RRgZ/xggM/s/wVBtynioeW9QADNmKZ1n6HVKkYwdOynbFSggYfFrL3HL
+54bC9roZUETin0G5wZ9QU+srgivT0a/KC3ourBYHXAI40iHuuOBf3syDVJ6xId/r
+3UO3qkiQ5q7pwglg+8Nx7Q3CFtGZY3ewxSSSDo6BOyweGYMsBaxMO3EyTqecyfXn
+3n4XPqwmDalWYQIDAQABo4HFMIHCMAkGA1UdEwQCMAAwEQYJYIZIAYb4QgEBBAQD
+AgWgMDMGCWCGSAGG+EIBDQQmFiRPcGVuU1NMIEdlbmVyYXRlZCBDbGllbnQgQ2Vy
+dGlmaWNhdGUwHQYDVR0OBBYEFP2bodoNQ1tCNEOALPnygGMUfNI+MB8GA1UdIwQY
+MBaAFOWzLd7eBJwSNbzRqNsD7MQDCHg/MA4GA1UdDwEB/wQEAwIF4DAdBgNVHSUE
+FjAUBggrBgEFBQcDAgYIKwYBBQUHAwQwDQYJKoZIhvcNAQELBQADggIBAHqUuCLt
+olOdR9p/g+KgGPnKuVgMn15Wc2VLCrbbl2P0fuCcNWmnBKqHHgQ1EJEpgnQ2N8m6
+tOGucX7IAzlZj36RP4lN3gZqFRSO/OiTOUYpE6Uv1hYRxeMzAYo5sBdCiiypjV9z
+H0Ew5NuWRf2/0nFWoywB9ktHcfD8lRFI3o8zUFXmE2JSUPQtKhW3tBkPPjYBlgzD
+RD8cq8dVK9P7i3tUENP+MNHJToNLFBqfA9De6bKnhCWHhZkfB0VeeSm4Ja9HkCg/
+DB+PAKMfbLCH5T8gCpEWxNlvj09r9mn37fNjtJPO/goAcNZNO2AURmb/ZQ4ggdry
+xb6lm832qplMUMWx//Ore0faEodlEc5d2kEtmcjj79gAypcLmm74q7CPt7xmniyd
+XvNT33S2tkh4dSirpCVwq0xyqOP3ZqTsTjudTveTBaTZNhTbCjDbaV7ga47TcH9/
++OZ3fQKjt2LAC6162wgEFZf10nUgaAXvSlI74gru93vEwWd8Pd3sWfGwuAFX3oKI
+JuwL2kxEuoZQmeRiVJu6KQb+Im7d5CIoWViDmfxcSDJfdtSePTqmDURIx87fw14Z
+XBWJP4PiK5PRmG/L0cGiDckmDKm/MuD13Z2I/NMl81GNY/q3WY2O7BmddPpAG5dr
+sc5hOqA9+jX08XbxKnfBPYllK5skYMkFH5tN
+-----END CERTIFICATE-----
diff --git a/src/python/grpcio_tests/tests/unit/credentials/certificate_hierarchy_2/intermediate/certs/intermediate.cert.pem b/src/python/grpcio_tests/tests/unit/credentials/certificate_hierarchy_2/intermediate/certs/intermediate.cert.pem
new file mode 100644
index 0000000..4305e53
--- /dev/null
+++ b/src/python/grpcio_tests/tests/unit/credentials/certificate_hierarchy_2/intermediate/certs/intermediate.cert.pem
@@ -0,0 +1,31 @@
+-----BEGIN CERTIFICATE-----
+MIIFaDCCA1CgAwIBAgICEAAwDQYJKoZIhvcNAQELBQAwPzELMAkGA1UEBhMCdXMx
+DjAMBgNVBAgMBWR1bW15MQ4wDAYDVQQKDAVkdW1teTEQMA4GA1UEAwwHcm9vdCBj
+YTAeFw0xNzExMDIwMDM3NTlaFw0yNzEwMzEwMDM3NTlaMEcxCzAJBgNVBAYTAnVz
+MQ4wDAYDVQQIDAVkdW1teTEOMAwGA1UECgwFZHVtbXkxGDAWBgNVBAMMD2ludGVy
+bWVkaWF0ZSBjYTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAKuM2iFz
+CCKmbs4uLj/8wjtxf+jFmkwzN4Pps4hqJ3NJqWB326LhzWyqM4WiTAJWE02wSJbS
+16RPfbjkVC77OI4+PUdwqxU9vNAP/95w0h6hBSFtkysuT5VVUt5jiY7wnUKgqTCi
+MYhYOl+HEP32O4cnxAazkUKKvtyrd4/PvejJ9zz+iYexRnaaGfOFR3co7jQ5QKar
+oK4UgJC3mVDZQEMBV0oljkpgVQMAVb4XQU7e+o25JOUkOoK6LdK/b/95khR0jTyD
+OBLqd4mCEzxNi+jZ0jLTLPk0c+DnGmRfoNUxnFb40R8QnEIEKwf+JKyl6p89oqOl
+pvIZFLZlUWIS4qL+993l1SCqPkWJOAdTg+s/Zh6DeAOhrUn9/wk0aQwZrK7wQQLJ
+4GGhxC/FfuUGsLqZszAVkP8jDEWnzhN2rw3V+C7v6lj4qHhUwqGHuYzCx2Hxl+B8
+UyBmZb9gXKVUtAvaZjaL2PDj1ZAxT0KVMlw1ZVrZu45OsHNQuBx/4uIAt6Rga8yt
+av1lsq+hFqwI4bU/oZC/oPMacOsB4qEkAA1101WjMc5bg6JOPWobwIqmUXQR1WJE
+j30e99HCpk1Cc2+9sUCzNu8KvU5kUY2K90zwqProvj5IfMuDetAVXsEjgW+ZqSho
+UMIpJ2M/hzAFl8Z5IRlG+YNfZNXl0FqJ5LzLAgMBAAGjZjBkMB0GA1UdDgQWBBTl
+sy3e3gScEjW80ajbA+zEAwh4PzAfBgNVHSMEGDAWgBTgTvUeshGOijhPmkgpcA9g
+ULVlyjASBgNVHRMBAf8ECDAGAQH/AgEAMA4GA1UdDwEB/wQEAwIBhjANBgkqhkiG
+9w0BAQsFAAOCAgEAOS7DtliOUPcVosRfyx9dHcSUc3O+uY8uKjSHhdIrxDJm4lwP
+Q6lKg5j8CdMVb+sDQmyBkqQIA/6E13corP6R283jO6W8D4A8kjOiQWpXfjW6OcP3
+4rrDEWhCdeLFSNJIYOFkr2qWJpI/k0VpyDnmY0YluS5WbNjg6zTzGelzhFbV7/S1
+cteNAZD0vHD8NmbLVDJjjIY3E/iwzoUzBncLYbDwqyVS1g6utWdSy8LEJxzzqqWJ
+pBKlNYILAdh8efBgvotafaxsn2nfjmVmekPn3KcQZuE4Kzv1EQ2PrHpGeJKwh6up
+YBL2tav5cAki8bWoGPr2oGmWUf9L2tB57SdWdaY60ifzmQaeGiWPZBSmAz7PRSrz
+sR9SMIkBfYVRxXgWwlvr8JYnd2h/Ef5K9fI32nGfje+7/0kPEjNyjehri7sV4Sjt
+zzkDiFO+JklrRuLBPMFYOokq6Pcko32FKlE82pe8QkMDS8Sk//9PqCTK9ceB7y6E
+NYLNBW/X9SAw/TR5kdRinHHgHyEug7N4+DCU3lU1wl72ZjoiGE7V6c2AssFC2VcE
+E+WYxJT1ROJ1/5+U6BKdaIpTwMtRIFRomOEI66iOwOSEwqLIztkqxwpQ7THraWKm
+2W5e54u/efapIDcQFnP3E8r7TD0PdIeU6mD28o0+WiK3uL/OZpvyKaHPeFU=
+-----END CERTIFICATE-----
diff --git a/src/python/grpcio_tests/tests/unit/credentials/certificate_hierarchy_2/intermediate/certs/localhost-1.cert.pem b/src/python/grpcio_tests/tests/unit/credentials/certificate_hierarchy_2/intermediate/certs/localhost-1.cert.pem
new file mode 100644
index 0000000..2850e42
--- /dev/null
+++ b/src/python/grpcio_tests/tests/unit/credentials/certificate_hierarchy_2/intermediate/certs/localhost-1.cert.pem
@@ -0,0 +1,30 @@
+-----BEGIN CERTIFICATE-----
+MIIFFzCCAv+gAwIBAgICEAAwDQYJKoZIhvcNAQELBQAwRzELMAkGA1UEBhMCdXMx
+DjAMBgNVBAgMBWR1bW15MQ4wDAYDVQQKDAVkdW1teTEYMBYGA1UEAwwPaW50ZXJt
+ZWRpYXRlIGNhMB4XDTE3MTEwMjAwMzc1OVoXDTI3MTAzMTAwMzc1OVowTTELMAkG
+A1UEBhMCdXMxDjAMBgNVBAgMBWR1bW15MQ4wDAYDVQQKDAVkdW1teTEKMAgGA1UE
+CwwBMTESMBAGA1UEAwwJbG9jYWxob3N0MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A
+MIIBCgKCAQEAycY/7H1xk3/XHZRopULV7YsOzPIrMG25zoACbpDZxjS0I+2r1c7V
+wnvE8TszAkloLi+Skku5CYC7IvVEEEuKuIuV+8M48FJEwlCPge8LPiy18C+npCEd
+fgDzCV/O9DfJj6UaiCUayVE7UujXoke7AlKQEJcqvnD/CoTv2Y8jV1A6mPf6CTEI
+Sl1BMeFSmeFyvZll+xJ8Up1KfQZxKhtpP1s/rp6ZNlqSs1LM5+vcDHHZ6COTbq7t
+2vvcmGDTqeCLsqicBg1kJyMPRtqa0bNPj2bcVtcK0Ndfn6eL2hi+EoBy2nIXi6aG
+PpXf85b9bCLd5pZI80nHzFlhdvV+SxqrfwIDAQABo4IBBTCCAQEwCQYDVR0TBAIw
+ADARBglghkgBhvhCAQEEBAMCBkAwMwYJYIZIAYb4QgENBCYWJE9wZW5TU0wgR2Vu
+ZXJhdGVkIFNlcnZlciBDZXJ0aWZpY2F0ZTAdBgNVHQ4EFgQUoYjECaDz/ZELru/r
+jfTB1ShlVrAwaAYDVR0jBGEwX4AU5bMt3t4EnBI1vNGo2wPsxAMIeD+hQ6RBMD8x
+CzAJBgNVBAYTAnVzMQ4wDAYDVQQIDAVkdW1teTEOMAwGA1UECgwFZHVtbXkxEDAO
+BgNVBAMMB3Jvb3QgY2GCAhAAMA4GA1UdDwEB/wQEAwIFoDATBgNVHSUEDDAKBggr
+BgEFBQcDATANBgkqhkiG9w0BAQsFAAOCAgEAiiR2knMMym4O+3fD1KlYSnc2UR3v
+0FlRVAsr8wvTlVjJhx7DbRusBNJHWX66mUgK9x5OLnhyvyqlFVhR9AwlnxgfLWz9
+nnACeXzcjQZnKWFQWu8bJSC6Ene6rd1g2acK6SOjxavVbj7JVFnmlHF/naZUzvMl
+mJivYta4k7ob8UcX0I5TlJpzglU3UHyyJd5d9zhbF8wqbBq63zR2ovWci4pYCg+F
+jYcTGYVZJti3SHO+9/EqTC9x2KDNs3o0+rreJ3GuoonkInKZMQQZJQ6qILvkxlhT
+jyU5xlcaJ+0tSaiFK3eF0nXIpFYdZbIHYPCdLjh9AZ2dkFcAgSa/L8+tsVt60k8D
+HTO0Hz6dW5D2ckeebZvz5LACMN89gVzrc/rVkeg7QmpSbjkTSLC2KJS53hJzWcEI
+3KB73B9iY+ZYytcYBTYLizsAxd5g7j9z8UXrmVQ4mWbh2+xKiG+9aVOzCZ09AYi6
+WVK2aRcMQshgkkqPOloN9OeQNCE8Exf7N/zHsBhygorJXoD/PFgnV1VZm8xkOdiJ
+zTb3bpGdmL5+bzzS6wP8Q7pGZGYdlnB7JNO8oMYPPtzX8OOx92BTkPnqJnnRWTpR
+SjMEEdQe8K7iXxejQkjaAq5BlwaAOjCjPTqYomECcYjC0WaXsmrPcnZwSqpnHZZ2
+OiINYJub5cvBLNo=
+-----END CERTIFICATE-----
diff --git a/src/python/grpcio_tests/tests/unit/credentials/certificate_hierarchy_2/intermediate/private/client.key.pem b/src/python/grpcio_tests/tests/unit/credentials/certificate_hierarchy_2/intermediate/private/client.key.pem
new file mode 100644
index 0000000..a4c5fd4
--- /dev/null
+++ b/src/python/grpcio_tests/tests/unit/credentials/certificate_hierarchy_2/intermediate/private/client.key.pem
@@ -0,0 +1,27 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIIEowIBAAKCAQEAyxZFTLqvGd9SpFAykyRyLQgHcR5hgD55mz+9fl1OfnMoAc7y
+TdPVLksDLmeFUlxcvCtLHysJklIBX62c6LzbsVcfLg/DPJlQxFnkhJCRKen4fp7x
+9h62qqJkDFVXsiEFza9L1lsN4OwqU8i4RRgZ/xggM/s/wVBtynioeW9QADNmKZ1n
+6HVKkYwdOynbFSggYfFrL3HL54bC9roZUETin0G5wZ9QU+srgivT0a/KC3ourBYH
+XAI40iHuuOBf3syDVJ6xId/r3UO3qkiQ5q7pwglg+8Nx7Q3CFtGZY3ewxSSSDo6B
+OyweGYMsBaxMO3EyTqecyfXn3n4XPqwmDalWYQIDAQABAoIBAFhIOR3OtVlw3BLz
+jdiq6jsrF1kUFNxTzDcxsSUiWIHde1G17Vzpre0uzJY6iBkyb1mZFFHbOpDxtwkp
+hmEh3/qqXbJ/RaatGxAP56e81G28+LnKTHJqDYwFhapa2wFjG4u7HSN0d4cEAq5j
+Pb9DZ+GdUjpmiON3HBL8+ne3bLZ42uI+DSVe8d3irbqg2rqsiANf0gdimMW4nuI4
+rVxf8HrY43PdQn/Vby+7qLRE3tmIlpbTqJGRtWRjdeBBI91APCrRljjXrKqT6Zpa
+E6Daz3YIQvXkIT0q+WkeN1VmQbtRnk7kRsPNp15kSwpHfmv6o/vkO9OUb1n71P2F
+wnB0WDECgYEA8iltnKxXnjqwZ/vzIWzcd94j+mdZg/K2/JCOqjwMvpSGCvx2zUmq
+Y2nxO2K85AVeOm/Yt87SMODB6AQ9CsrVGEUAzzacvCJDb8oUhaOL5gypnyvZiGCy
+snzXfgB+v/xuGekIjs2y7E8h3GG40j0aNQnUY1Fuc6iaeJG4BtjkuQUCgYEA1rE4
+DrTSsUh3hLYQusIHZR8Lecrrd4QUZSMKLkWjobiSTw3m4mglx1s2G4eZ3WuzOyFq
+Dp3/b3yfT8prdPBGA6shHNFf+1TO1q1/pIt15dc3sFwxMkuunai8N4QZJRqZLbYq
+FkNFkZ20hFHcH/NHDsAsRL/0tJdEmJ2ruP+Qdq0CgYBsdPGKwgVb8J0hdU4nIkJ7
+zRoABFmrJwGdjIDY7Zwnnw2JzhjHSL7vV3ubRVWkKmNReNZvPEoXahJuf7d3JfDa
+tczvAV6hRBc/8hnO4Li/h9xQVatP0T83gYJiBIbAJaaKJDyY+Lex7p8TvRCx2Hvs
+VUKyWL5HPrQwW9M3/dwyoQKBgQCNQoPA4Wcz8Jt7PZQaXaoh9eBGHab6t3P366s6
+MOXudZQG4f3FgINC/ZfHW1x43PFL+btfrMOyJkxoYqZ7hdB7f3DFFlpR80Y46GVw
+7bYAKbBhoPdZwYQ+BhT5bjhhOnQJKK/egBrZKevpmDb+6sIZSYaXIbovzMv8otmn
+WrhB7QKBgAdl+KYBQULCUBp8qCQH5sAQoWErpyuD2FNN6LGknpPqn4DdujvwEP0Z
+OSvbauLkI0Qc9/MezKPTeYXlFqdbpItwyySJsUkiI3HhVYlBgDkZ7xb6uHIH5E6I
+bKgIW5JEf5I7Eu1iurORkXxCCGMkiQmEs4X5kSXXRYgXfNgAD0FX
+-----END RSA PRIVATE KEY-----
diff --git a/src/python/grpcio_tests/tests/unit/credentials/certificate_hierarchy_2/intermediate/private/localhost-1.key.pem b/src/python/grpcio_tests/tests/unit/credentials/certificate_hierarchy_2/intermediate/private/localhost-1.key.pem
new file mode 100644
index 0000000..8cba174
--- /dev/null
+++ b/src/python/grpcio_tests/tests/unit/credentials/certificate_hierarchy_2/intermediate/private/localhost-1.key.pem
@@ -0,0 +1,27 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIIEpAIBAAKCAQEAycY/7H1xk3/XHZRopULV7YsOzPIrMG25zoACbpDZxjS0I+2r
+1c7VwnvE8TszAkloLi+Skku5CYC7IvVEEEuKuIuV+8M48FJEwlCPge8LPiy18C+n
+pCEdfgDzCV/O9DfJj6UaiCUayVE7UujXoke7AlKQEJcqvnD/CoTv2Y8jV1A6mPf6
+CTEISl1BMeFSmeFyvZll+xJ8Up1KfQZxKhtpP1s/rp6ZNlqSs1LM5+vcDHHZ6COT
+bq7t2vvcmGDTqeCLsqicBg1kJyMPRtqa0bNPj2bcVtcK0Ndfn6eL2hi+EoBy2nIX
+i6aGPpXf85b9bCLd5pZI80nHzFlhdvV+SxqrfwIDAQABAoIBAQC022161aoTEtjH
+m7n8v56vUCCRFVQfEYsljFohrtZ0sdLyDVwjxkSWEYiizXRYTWIDXALd/N+7o9aZ
+bAx5Kq0J45wpUYBc8PDO15T6W0DRlxPxWVXDaSddRQ6TTXxcLREPH2dbtx5+asBo
+/Woi/Haki0q0hDr8/p2sWSH/+SwtWpOezGVlrWrkMeIhlBwHZfdHVoZvSx65Uv7x
+WU07vsjrbXNDwf+2fmklAQrzhedCeh8loGyjtN3cfrTjrE1zqpEsHnlZcJxe6sRB
+1nOqpoUnpZXklDDIYC8EmeubmDJ0jnXOQCDDep3MzVcnZGyF5E/+szaa1NL70Ayj
+rbKk1Y3ZAoGBAPy/1ym7Cjl4OGHN2fdkR6iL68ebJozpr+eTSxDNLuBSi5IJxJyG
+1+B4+v1u0RwZ3DjrSQsO5DCbZ+DHU6O/DAJK2CxUED+M+G2kRyffailRQmNzjpRG
+75dIhSkSRYH8vdvEOnGpeQBZwBcCRH/2YUMlZeSfx9fHJhk1nyUxJeHjAoGBAMxe
+k+cBb0zYok+Ww1xTwOdq0PwKj0oDsEg8hOdWc8pH0SlOAB4BI5kmfd1JDMHfRc49
+7tpNqjsPrnlb9xd8l0281Lj2NoVSE5KX1JtsOsKecQsvHH5zRk4eJ3h/mNixpjfe
+79Zc/O40T4rWpQRqhat+WHveJC0/ON4AH4uT0BK1AoGBAPcTioCu6YXYsjVaCJPB
+IhPwBGOylfL2lxDoel9IVWTRDMOMbPkfEHXNjn6lECJKXW//Af6fZg7mPJwN/wN5
+xYGQLNbYrrGRW2HDUBP4YU1WtHGIC3+EAL+BEztdMzmpGuh1YTSvmSvwkMltXA1D
+iz0amArw72lOsz29n3+6FfBFAoGAIpRqMC8k9vq80/yth6TAQifnvo3G2v4uyLo8
+vqv5IaPvNy70hB8rN9G0gEnI99Dgjdoa3SNBB4dKvUwbTgUN0OB/meBHL13I5Af+
+uGGiu6V1eS/6gUbeAX/Gq/PjF99PQareKAZJ4cBGKTbSayHfBjp1nFflBSbqZ13b
++JEFJvUCgYBOs2J2XXamPbI7gu7B2TE9j/62v0SJyoHq2LHMmYUDRuPdPk3eKCt3
+283w+E8XUIFbctaxsbo8msNjjvV22D/Nci3d87aPe8bn1SVto3GnTuwnOpRq3E+3
+wAarqrhiZbGZSCcAkEOk7FlxAwYnCM6paqMxDEMCJ4qChMM42E9ZyQ==
+-----END RSA PRIVATE KEY-----
diff --git a/src/python/grpcio_tests/tests/unit/resources.py b/src/python/grpcio_tests/tests/unit/resources.py
index 823d230..11ef9e8 100644
--- a/src/python/grpcio_tests/tests/unit/resources.py
+++ b/src/python/grpcio_tests/tests/unit/resources.py
@@ -11,7 +11,7 @@
 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 # See the License for the specific language governing permissions and
 # limitations under the License.
-"""Constants and functions for data used in interoperability testing."""
+"""Constants and functions for data used in testing."""
 
 import os
 
@@ -34,3 +34,81 @@
 def certificate_chain():
     return pkg_resources.resource_string(__name__,
                                          _CERTIFICATE_CHAIN_RESOURCE_PATH)
+
+
+def cert_hier_1_root_ca_cert():
+    return pkg_resources.resource_string(
+        __name__, 'credentials/certificate_hierarchy_1/certs/ca.cert.pem')
+
+
+def cert_hier_1_intermediate_ca_cert():
+    return pkg_resources.resource_string(
+        __name__,
+        'credentials/certificate_hierarchy_1/intermediate/certs/intermediate.cert.pem'
+    )
+
+
+def cert_hier_1_client_1_key():
+    return pkg_resources.resource_string(
+        __name__,
+        'credentials/certificate_hierarchy_1/intermediate/private/client.key.pem'
+    )
+
+
+def cert_hier_1_client_1_cert():
+    return pkg_resources.resource_string(
+        __name__,
+        'credentials/certificate_hierarchy_1/intermediate/certs/client.cert.pem')
+
+
+def cert_hier_1_server_1_key():
+    return pkg_resources.resource_string(
+        __name__,
+        'credentials/certificate_hierarchy_1/intermediate/private/localhost-1.key.pem'
+    )
+
+
+def cert_hier_1_server_1_cert():
+    return pkg_resources.resource_string(
+        __name__,
+        'credentials/certificate_hierarchy_1/intermediate/certs/localhost-1.cert.pem'
+    )
+
+
+def cert_hier_2_root_ca_cert():
+    return pkg_resources.resource_string(
+        __name__, 'credentials/certificate_hierarchy_2/certs/ca.cert.pem')
+
+
+def cert_hier_2_intermediate_ca_cert():
+    return pkg_resources.resource_string(
+        __name__,
+        'credentials/certificate_hierarchy_2/intermediate/certs/intermediate.cert.pem'
+    )
+
+
+def cert_hier_2_client_1_key():
+    return pkg_resources.resource_string(
+        __name__,
+        'credentials/certificate_hierarchy_2/intermediate/private/client.key.pem'
+    )
+
+
+def cert_hier_2_client_1_cert():
+    return pkg_resources.resource_string(
+        __name__,
+        'credentials/certificate_hierarchy_2/intermediate/certs/client.cert.pem')
+
+
+def cert_hier_2_server_1_key():
+    return pkg_resources.resource_string(
+        __name__,
+        'credentials/certificate_hierarchy_2/intermediate/private/localhost-1.key.pem'
+    )
+
+
+def cert_hier_2_server_1_cert():
+    return pkg_resources.resource_string(
+        __name__,
+        'credentials/certificate_hierarchy_2/intermediate/certs/localhost-1.cert.pem'
+    )
diff --git a/src/ruby/end2end/channel_closing_driver.rb b/src/ruby/end2end/channel_closing_driver.rb
index 0ceb366..57544b0 100755
--- a/src/ruby/end2end/channel_closing_driver.rb
+++ b/src/ruby/end2end/channel_closing_driver.rb
@@ -23,13 +23,11 @@
   STDERR.puts 'start server'
   server_runner = ServerRunner.new(EchoServerImpl)
   server_port = server_runner.run
-
-  sleep 1
-
   STDERR.puts 'start client'
   control_stub, client_pid = start_client('channel_closing_client.rb',
                                           server_port)
-
+  # sleep to allow time for the client to get into
+  # the middle of a "watch connectivity state" call
   sleep 3
 
   begin
diff --git a/src/ruby/end2end/channel_state_driver.rb b/src/ruby/end2end/channel_state_driver.rb
index 98339ba..f4b1cd2 100755
--- a/src/ruby/end2end/channel_state_driver.rb
+++ b/src/ruby/end2end/channel_state_driver.rb
@@ -22,14 +22,11 @@
   STDERR.puts 'start server'
   server_runner = ServerRunner.new(EchoServerImpl)
   server_port = server_runner.run
-
-  sleep 1
-
   STDERR.puts 'start client'
   _, client_pid = start_client('channel_state_client.rb', server_port)
-
+  # sleep to allow time for the client to get into
+  # the middle of a "watch connectivity state" call
   sleep 3
-
   Process.kill('SIGTERM', client_pid)
 
   begin
diff --git a/src/ruby/end2end/end2end_common.rb b/src/ruby/end2end/end2end_common.rb
index a1b824f..790fc23 100755
--- a/src/ruby/end2end/end2end_common.rb
+++ b/src/ruby/end2end/end2end_common.rb
@@ -40,12 +40,13 @@
 
 # ServerRunner starts an "echo server" that test clients can make calls to
 class ServerRunner
-  def initialize(service_impl)
+  def initialize(service_impl, rpc_server_args: {})
     @service_impl = service_impl
+    @rpc_server_args = rpc_server_args
   end
 
   def run
-    @srv = GRPC::RpcServer.new
+    @srv = GRPC::RpcServer.new(@rpc_server_args)
     port = @srv.add_http2_port('0.0.0.0:0', :this_port_is_insecure)
     @srv.handle(@service_impl)
 
@@ -75,7 +76,6 @@
                              client_path,
                              "--client_control_port=#{client_control_port}",
                              "--server_port=#{server_port}")
-  sleep 1
   control_stub = ClientControl::ClientController::Stub.new(
     "localhost:#{client_control_port}", :this_channel_is_insecure)
   [control_stub, client_pid]
diff --git a/src/ruby/end2end/forking_client_driver.rb b/src/ruby/end2end/forking_client_driver.rb
index 6356539..5cf1d73 100755
--- a/src/ruby/end2end/forking_client_driver.rb
+++ b/src/ruby/end2end/forking_client_driver.rb
@@ -20,12 +20,6 @@
   STDERR.puts 'start server'
   server_runner = ServerRunner.new(EchoServerImpl)
   server_port = server_runner.run
-
-  # TODO(apolcyn) Can we get rid of this sleep?
-  # Without it, an immediate call to the just started EchoServer
-  # fails with UNAVAILABLE
-  sleep 1
-
   STDERR.puts 'start client'
   _, client_pid = start_client('forking_client_client.rb',
                                server_port)
diff --git a/src/ruby/end2end/grpc_class_init_client.rb b/src/ruby/end2end/grpc_class_init_client.rb
index c35719a..ff40350 100755
--- a/src/ruby/end2end/grpc_class_init_client.rb
+++ b/src/ruby/end2end/grpc_class_init_client.rb
@@ -54,7 +54,7 @@
 
   test_proc.call
 
-  fail 'exception thrown while child thread initing class'
+  fail '(expected) exception thrown while child thread initing class'
 end
 
 # default (no gc_stress and no concurrency_stress)
diff --git a/src/ruby/end2end/killed_client_thread_driver.rb b/src/ruby/end2end/killed_client_thread_driver.rb
index fce5d13..370f7e6 100755
--- a/src/ruby/end2end/killed_client_thread_driver.rb
+++ b/src/ruby/end2end/killed_client_thread_driver.rb
@@ -17,56 +17,46 @@
 require_relative './end2end_common'
 
 # Service that sleeps for a long time upon receiving an 'echo request'
-# Also, this notifies @call_started_cv once it has received a request.
+# Also, this calls it's callback upon receiving an RPC as a method
+# of synchronization/waiting for the child to start.
 class SleepingEchoServerImpl < Echo::EchoServer::Service
-  def initialize(call_started, call_started_mu, call_started_cv)
-    @call_started = call_started
-    @call_started_mu = call_started_mu
-    @call_started_cv = call_started_cv
+  def initialize(received_rpc_callback)
+    @received_rpc_callback = received_rpc_callback
   end
 
   def echo(echo_req, _)
-    @call_started_mu.synchronize do
-      @call_started.set_true
-      @call_started_cv.signal
-    end
-    sleep 1000
+    @received_rpc_callback.call
+    # sleep forever to get the client stuck waiting
+    sleep
     Echo::EchoReply.new(response: echo_req.request)
   end
 end
 
-# Mutable boolean
-class BoolHolder
-  attr_reader :val
-
-  def init
-    @val = false
-  end
-
-  def set_true
-    @val = true
-  end
-end
-
 def main
   STDERR.puts 'start server'
 
-  call_started = BoolHolder.new
-  call_started_mu = Mutex.new
-  call_started_cv = ConditionVariable.new
+  client_started = false
+  client_started_mu = Mutex.new
+  client_started_cv = ConditionVariable.new
+  received_rpc_callback = proc do
+    client_started_mu.synchronize do
+      client_started = true
+      client_started_cv.signal
+    end
+  end
 
-  service_impl = SleepingEchoServerImpl.new(call_started,
-                                            call_started_mu,
-                                            call_started_cv)
-  server_runner = ServerRunner.new(service_impl)
+  service_impl = SleepingEchoServerImpl.new(received_rpc_callback)
+  # RPCs against the server will all be hanging, so kill thread
+  # pool workers immediately rather than after waiting for a second.
+  rpc_server_args = { poll_period: 0, pool_keep_alive: 0 }
+  server_runner = ServerRunner.new(service_impl, rpc_server_args: rpc_server_args)
   server_port = server_runner.run
-
   STDERR.puts 'start client'
   _, client_pid = start_client('killed_client_thread_client.rb',
                                server_port)
 
-  call_started_mu.synchronize do
-    call_started_cv.wait(call_started_mu) until call_started.val
+  client_started_mu.synchronize do
+    client_started_cv.wait(client_started_mu) until client_started
   end
 
   # SIGTERM the child process now that it's
diff --git a/src/ruby/end2end/multiple_killed_watching_threads_driver.rb b/src/ruby/end2end/multiple_killed_watching_threads_driver.rb
index 94d5e9d..59f6f27 100755
--- a/src/ruby/end2end/multiple_killed_watching_threads_driver.rb
+++ b/src/ruby/end2end/multiple_killed_watching_threads_driver.rb
@@ -26,6 +26,8 @@
     fail "non-idle state: #{state}" unless state == IDLE
     ch.watch_connectivity_state(IDLE, Time.now + 360)
   end
+  # sleep to get the thread into the middle of a
+  # "watch connectivity state" call
   sleep 0.1
   thd.kill
 end
diff --git a/src/ruby/end2end/sig_handling_client.rb b/src/ruby/end2end/sig_handling_client.rb
index 41b5f33..129ad7c 100755
--- a/src/ruby/end2end/sig_handling_client.rb
+++ b/src/ruby/end2end/sig_handling_client.rb
@@ -30,16 +30,18 @@
   end
 
   def shutdown(_, _)
-    Thread.new do
-      # TODO(apolcyn) There is a race between stopping the
-      # server and the "shutdown" rpc completing,
-      # See if stop method on server can end active RPC cleanly, to
-      # avoid this sleep.
-      sleep 3
+    # Spawn a new thread because RpcServer#stop is
+    # synchronous and blocks until either this RPC has finished,
+    # or the server's "poll_period" seconds have passed.
+    @shutdown_thread = Thread.new do
       @srv.stop
     end
     ClientControl::Void.new
   end
+
+  def join_shutdown_thread
+    @shutdown_thread.join
+  end
 end
 
 def main
@@ -62,13 +64,23 @@
     STDERR.puts 'SIGINT received'
   end
 
-  srv = GRPC::RpcServer.new
+  # The "shutdown" RPC should end very quickly.
+  # Allow a few seconds to be safe.
+  srv = GRPC::RpcServer.new(poll_period: 3)
   srv.add_http2_port("0.0.0.0:#{client_control_port}",
                      :this_port_is_insecure)
   stub = Echo::EchoServer::Stub.new("localhost:#{server_port}",
                                     :this_channel_is_insecure)
-  srv.handle(SigHandlingClientController.new(srv, stub))
-  srv.run
+  control_service = SigHandlingClientController.new(srv, stub)
+  srv.handle(control_service)
+  server_thread = Thread.new do
+    srv.run
+  end
+  srv.wait_till_running
+  # send a first RPC to notify the parent process that we've started
+  stub.echo(Echo::EchoRequest.new(request: 'client/child started'))
+  server_thread.join
+  control_service.join_shutdown_thread
 end
 
 main
diff --git a/src/ruby/end2end/sig_handling_driver.rb b/src/ruby/end2end/sig_handling_driver.rb
index 291bf29..0ad1cbd 100755
--- a/src/ruby/end2end/sig_handling_driver.rb
+++ b/src/ruby/end2end/sig_handling_driver.rb
@@ -19,17 +19,42 @@
 
 require_relative './end2end_common'
 
+# A service that calls back it's received_rpc_callback
+# upon receiving an RPC. Used for synchronization/waiting
+# for child process to start.
+class ClientStartedService < Echo::EchoServer::Service
+  def initialize(received_rpc_callback)
+    @received_rpc_callback = received_rpc_callback
+  end
+
+  def echo(echo_req, _)
+    @received_rpc_callback.call unless @received_rpc_callback.nil?
+    @received_rpc_callback = nil
+    Echo::EchoReply.new(response: echo_req.request)
+  end
+end
+
 def main
   STDERR.puts 'start server'
-  server_runner = ServerRunner.new(EchoServerImpl)
+  client_started = false
+  client_started_mu = Mutex.new
+  client_started_cv = ConditionVariable.new
+  received_rpc_callback = proc do
+    client_started_mu.synchronize do
+      client_started = true
+      client_started_cv.signal
+    end
+  end
+
+  client_started_service = ClientStartedService.new(received_rpc_callback)
+  server_runner = ServerRunner.new(client_started_service)
   server_port = server_runner.run
-
-  sleep 1
-
   STDERR.puts 'start client'
   control_stub, client_pid = start_client('sig_handling_client.rb', server_port)
 
-  sleep 1
+  client_started_mu.synchronize do
+    client_started_cv.wait(client_started_mu) until client_started
+  end
 
   count = 0
   while count < 5
diff --git a/src/ruby/end2end/sig_int_during_channel_watch_driver.rb b/src/ruby/end2end/sig_int_during_channel_watch_driver.rb
index b054f0f..2df22f4 100755
--- a/src/ruby/end2end/sig_int_during_channel_watch_driver.rb
+++ b/src/ruby/end2end/sig_int_during_channel_watch_driver.rb
@@ -23,13 +23,9 @@
   STDERR.puts 'start server'
   server_runner = ServerRunner.new(EchoServerImpl)
   server_port = server_runner.run
-
-  sleep 1
-
   STDERR.puts 'start client'
   _, client_pid = start_client('sig_int_during_channel_watch_client.rb',
                                server_port)
-
   # give time for the client to get into the middle
   # of a channel state watch call
   sleep 1
diff --git a/src/ruby/ext/grpc/rb_grpc_imports.generated.c b/src/ruby/ext/grpc/rb_grpc_imports.generated.c
index 648d515..56f1d4c 100644
--- a/src/ruby/ext/grpc/rb_grpc_imports.generated.c
+++ b/src/ruby/ext/grpc/rb_grpc_imports.generated.c
@@ -223,21 +223,6 @@
 gpr_cmdline_usage_string_type gpr_cmdline_usage_string_import;
 gpr_cpu_num_cores_type gpr_cpu_num_cores_import;
 gpr_cpu_current_cpu_type gpr_cpu_current_cpu_import;
-gpr_histogram_create_type gpr_histogram_create_import;
-gpr_histogram_destroy_type gpr_histogram_destroy_import;
-gpr_histogram_add_type gpr_histogram_add_import;
-gpr_histogram_merge_type gpr_histogram_merge_import;
-gpr_histogram_percentile_type gpr_histogram_percentile_import;
-gpr_histogram_mean_type gpr_histogram_mean_import;
-gpr_histogram_stddev_type gpr_histogram_stddev_import;
-gpr_histogram_variance_type gpr_histogram_variance_import;
-gpr_histogram_maximum_type gpr_histogram_maximum_import;
-gpr_histogram_minimum_type gpr_histogram_minimum_import;
-gpr_histogram_count_type gpr_histogram_count_import;
-gpr_histogram_sum_type gpr_histogram_sum_import;
-gpr_histogram_sum_of_squares_type gpr_histogram_sum_of_squares_import;
-gpr_histogram_get_contents_type gpr_histogram_get_contents_import;
-gpr_histogram_merge_contents_type gpr_histogram_merge_contents_import;
 gpr_join_host_port_type gpr_join_host_port_import;
 gpr_split_host_port_type gpr_split_host_port_import;
 gpr_log_severity_string_type gpr_log_severity_string_import;
@@ -510,21 +495,6 @@
   gpr_cmdline_usage_string_import = (gpr_cmdline_usage_string_type) GetProcAddress(library, "gpr_cmdline_usage_string");
   gpr_cpu_num_cores_import = (gpr_cpu_num_cores_type) GetProcAddress(library, "gpr_cpu_num_cores");
   gpr_cpu_current_cpu_import = (gpr_cpu_current_cpu_type) GetProcAddress(library, "gpr_cpu_current_cpu");
-  gpr_histogram_create_import = (gpr_histogram_create_type) GetProcAddress(library, "gpr_histogram_create");
-  gpr_histogram_destroy_import = (gpr_histogram_destroy_type) GetProcAddress(library, "gpr_histogram_destroy");
-  gpr_histogram_add_import = (gpr_histogram_add_type) GetProcAddress(library, "gpr_histogram_add");
-  gpr_histogram_merge_import = (gpr_histogram_merge_type) GetProcAddress(library, "gpr_histogram_merge");
-  gpr_histogram_percentile_import = (gpr_histogram_percentile_type) GetProcAddress(library, "gpr_histogram_percentile");
-  gpr_histogram_mean_import = (gpr_histogram_mean_type) GetProcAddress(library, "gpr_histogram_mean");
-  gpr_histogram_stddev_import = (gpr_histogram_stddev_type) GetProcAddress(library, "gpr_histogram_stddev");
-  gpr_histogram_variance_import = (gpr_histogram_variance_type) GetProcAddress(library, "gpr_histogram_variance");
-  gpr_histogram_maximum_import = (gpr_histogram_maximum_type) GetProcAddress(library, "gpr_histogram_maximum");
-  gpr_histogram_minimum_import = (gpr_histogram_minimum_type) GetProcAddress(library, "gpr_histogram_minimum");
-  gpr_histogram_count_import = (gpr_histogram_count_type) GetProcAddress(library, "gpr_histogram_count");
-  gpr_histogram_sum_import = (gpr_histogram_sum_type) GetProcAddress(library, "gpr_histogram_sum");
-  gpr_histogram_sum_of_squares_import = (gpr_histogram_sum_of_squares_type) GetProcAddress(library, "gpr_histogram_sum_of_squares");
-  gpr_histogram_get_contents_import = (gpr_histogram_get_contents_type) GetProcAddress(library, "gpr_histogram_get_contents");
-  gpr_histogram_merge_contents_import = (gpr_histogram_merge_contents_type) GetProcAddress(library, "gpr_histogram_merge_contents");
   gpr_join_host_port_import = (gpr_join_host_port_type) GetProcAddress(library, "gpr_join_host_port");
   gpr_split_host_port_import = (gpr_split_host_port_type) GetProcAddress(library, "gpr_split_host_port");
   gpr_log_severity_string_import = (gpr_log_severity_string_type) GetProcAddress(library, "gpr_log_severity_string");
diff --git a/src/ruby/ext/grpc/rb_grpc_imports.generated.h b/src/ruby/ext/grpc/rb_grpc_imports.generated.h
index ae1e1a0..62223fd 100644
--- a/src/ruby/ext/grpc/rb_grpc_imports.generated.h
+++ b/src/ruby/ext/grpc/rb_grpc_imports.generated.h
@@ -36,7 +36,6 @@
 #include <grpc/support/avl.h>
 #include <grpc/support/cmdline.h>
 #include <grpc/support/cpu.h>
-#include <grpc/support/histogram.h>
 #include <grpc/support/host_port.h>
 #include <grpc/support/log.h>
 #include <grpc/support/log_windows.h>
@@ -337,7 +336,7 @@
 typedef grpc_call_credentials*(*grpc_google_compute_engine_credentials_create_type)(void* reserved);
 extern grpc_google_compute_engine_credentials_create_type grpc_google_compute_engine_credentials_create_import;
 #define grpc_google_compute_engine_credentials_create grpc_google_compute_engine_credentials_create_import
-typedef gpr_timespec(*grpc_max_auth_token_lifetime_type)();
+typedef gpr_timespec(*grpc_max_auth_token_lifetime_type)(void);
 extern grpc_max_auth_token_lifetime_type grpc_max_auth_token_lifetime_import;
 #define grpc_max_auth_token_lifetime grpc_max_auth_token_lifetime_import
 typedef grpc_call_credentials*(*grpc_service_account_jwt_access_credentials_create_type)(const char* json_key, gpr_timespec token_lifetime, void* reserved);
@@ -589,7 +588,7 @@
 typedef void(*gpr_set_allocation_functions_type)(gpr_allocation_functions functions);
 extern gpr_set_allocation_functions_type gpr_set_allocation_functions_import;
 #define gpr_set_allocation_functions gpr_set_allocation_functions_import
-typedef gpr_allocation_functions(*gpr_get_allocation_functions_type)();
+typedef gpr_allocation_functions(*gpr_get_allocation_functions_type)(void);
 extern gpr_get_allocation_functions_type gpr_get_allocation_functions_import;
 #define gpr_get_allocation_functions gpr_get_allocation_functions_import
 typedef gpr_avl(*gpr_avl_create_type)(const gpr_avl_vtable* vtable);
@@ -649,51 +648,6 @@
 typedef unsigned(*gpr_cpu_current_cpu_type)(void);
 extern gpr_cpu_current_cpu_type gpr_cpu_current_cpu_import;
 #define gpr_cpu_current_cpu gpr_cpu_current_cpu_import
-typedef gpr_histogram*(*gpr_histogram_create_type)(double resolution, double max_bucket_start);
-extern gpr_histogram_create_type gpr_histogram_create_import;
-#define gpr_histogram_create gpr_histogram_create_import
-typedef void(*gpr_histogram_destroy_type)(gpr_histogram* h);
-extern gpr_histogram_destroy_type gpr_histogram_destroy_import;
-#define gpr_histogram_destroy gpr_histogram_destroy_import
-typedef void(*gpr_histogram_add_type)(gpr_histogram* h, double x);
-extern gpr_histogram_add_type gpr_histogram_add_import;
-#define gpr_histogram_add gpr_histogram_add_import
-typedef int(*gpr_histogram_merge_type)(gpr_histogram* dst, const gpr_histogram* src);
-extern gpr_histogram_merge_type gpr_histogram_merge_import;
-#define gpr_histogram_merge gpr_histogram_merge_import
-typedef double(*gpr_histogram_percentile_type)(gpr_histogram* histogram, double percentile);
-extern gpr_histogram_percentile_type gpr_histogram_percentile_import;
-#define gpr_histogram_percentile gpr_histogram_percentile_import
-typedef double(*gpr_histogram_mean_type)(gpr_histogram* histogram);
-extern gpr_histogram_mean_type gpr_histogram_mean_import;
-#define gpr_histogram_mean gpr_histogram_mean_import
-typedef double(*gpr_histogram_stddev_type)(gpr_histogram* histogram);
-extern gpr_histogram_stddev_type gpr_histogram_stddev_import;
-#define gpr_histogram_stddev gpr_histogram_stddev_import
-typedef double(*gpr_histogram_variance_type)(gpr_histogram* histogram);
-extern gpr_histogram_variance_type gpr_histogram_variance_import;
-#define gpr_histogram_variance gpr_histogram_variance_import
-typedef double(*gpr_histogram_maximum_type)(gpr_histogram* histogram);
-extern gpr_histogram_maximum_type gpr_histogram_maximum_import;
-#define gpr_histogram_maximum gpr_histogram_maximum_import
-typedef double(*gpr_histogram_minimum_type)(gpr_histogram* histogram);
-extern gpr_histogram_minimum_type gpr_histogram_minimum_import;
-#define gpr_histogram_minimum gpr_histogram_minimum_import
-typedef double(*gpr_histogram_count_type)(gpr_histogram* histogram);
-extern gpr_histogram_count_type gpr_histogram_count_import;
-#define gpr_histogram_count gpr_histogram_count_import
-typedef double(*gpr_histogram_sum_type)(gpr_histogram* histogram);
-extern gpr_histogram_sum_type gpr_histogram_sum_import;
-#define gpr_histogram_sum gpr_histogram_sum_import
-typedef double(*gpr_histogram_sum_of_squares_type)(gpr_histogram* histogram);
-extern gpr_histogram_sum_of_squares_type gpr_histogram_sum_of_squares_import;
-#define gpr_histogram_sum_of_squares gpr_histogram_sum_of_squares_import
-typedef const uint32_t*(*gpr_histogram_get_contents_type)(gpr_histogram* histogram, size_t* count);
-extern gpr_histogram_get_contents_type gpr_histogram_get_contents_import;
-#define gpr_histogram_get_contents gpr_histogram_get_contents_import
-typedef void(*gpr_histogram_merge_contents_type)(gpr_histogram* histogram, const uint32_t* data, size_t data_count, double min_seen, double max_seen, double sum, double sum_of_squares, double count);
-extern gpr_histogram_merge_contents_type gpr_histogram_merge_contents_import;
-#define gpr_histogram_merge_contents gpr_histogram_merge_contents_import
 typedef int(*gpr_join_host_port_type)(char** out, const char* host, int port);
 extern gpr_join_host_port_type gpr_join_host_port_import;
 #define gpr_join_host_port gpr_join_host_port_import
@@ -712,7 +666,7 @@
 typedef void(*gpr_set_log_verbosity_type)(gpr_log_severity min_severity_to_print);
 extern gpr_set_log_verbosity_type gpr_set_log_verbosity_import;
 #define gpr_set_log_verbosity gpr_set_log_verbosity_import
-typedef void(*gpr_log_verbosity_init_type)();
+typedef void(*gpr_log_verbosity_init_type)(void);
 extern gpr_log_verbosity_init_type gpr_log_verbosity_init_import;
 #define gpr_log_verbosity_init gpr_log_verbosity_init_import
 typedef void(*gpr_set_log_function_type)(gpr_log_func func);
diff --git a/src/ruby/lib/grpc/generic/rpc_server.rb b/src/ruby/lib/grpc/generic/rpc_server.rb
index d5fc11d..c80c7fc 100644
--- a/src/ruby/lib/grpc/generic/rpc_server.rb
+++ b/src/ruby/lib/grpc/generic/rpc_server.rb
@@ -92,9 +92,13 @@
     # Stops the jobs in the pool
     def stop
       GRPC.logger.info('stopping, will wait for all the workers to exit')
-      schedule { throw :exit } while ready_for_work?
-      @stop_mutex.synchronize do  # wait @keep_alive for works to stop
+      @stop_mutex.synchronize do  # wait @keep_alive seconds for workers to stop
         @stopped = true
+        loop do
+          break unless ready_for_work?
+          worker_queue = @ready_workers.pop
+          worker_queue << [proc { throw :exit }, []]
+        end
         @stop_cond.wait(@stop_mutex, @keep_alive) if @workers.size > 0
       end
       forcibly_stop_workers
@@ -138,7 +142,10 @@
         end
         # there shouldn't be any work given to this thread while its busy
         fail('received a task while busy') unless worker_queue.empty?
-        @ready_workers << worker_queue
+        @stop_mutex.synchronize do
+          return if @stopped
+          @ready_workers << worker_queue
+        end
       end
     end
   end
@@ -186,8 +193,13 @@
     # * max_waiting_requests: Deprecated due to internal changes to the thread
     # pool. This is still an argument for compatibility but is ignored.
     #
-    # * poll_period: when present, the server polls for new events with this
-    # period
+    # * poll_period: The amount of time in seconds to wait for
+    # currently-serviced RPC's to finish before cancelling them when shutting
+    # down the server.
+    #
+    # * pool_keep_alive: The amount of time in seconds to wait
+    # for currently busy thread-pool threads to finish before
+    # forcing an abrupt exit to each thread.
     #
     # * connect_md_proc:
     # when non-nil is a proc for determining metadata to to send back the client
@@ -202,17 +214,18 @@
     # intercepting server handlers to provide extra functionality.
     # Interceptors are an EXPERIMENTAL API.
     #
-    def initialize(pool_size:DEFAULT_POOL_SIZE,
-                   max_waiting_requests:DEFAULT_MAX_WAITING_REQUESTS,
-                   poll_period:DEFAULT_POLL_PERIOD,
-                   connect_md_proc:nil,
-                   server_args:{},
-                   interceptors:[])
+    def initialize(pool_size: DEFAULT_POOL_SIZE,
+                   max_waiting_requests: DEFAULT_MAX_WAITING_REQUESTS,
+                   poll_period: DEFAULT_POLL_PERIOD,
+                   pool_keep_alive: GRPC::RpcServer::DEFAULT_POOL_SIZE,
+                   connect_md_proc: nil,
+                   server_args: {},
+                   interceptors: [])
       @connect_md_proc = RpcServer.setup_connect_md_proc(connect_md_proc)
       @max_waiting_requests = max_waiting_requests
       @poll_period = poll_period
       @pool_size = pool_size
-      @pool = Pool.new(@pool_size)
+      @pool = Pool.new(@pool_size, keep_alive: pool_keep_alive)
       @run_cond = ConditionVariable.new
       @run_mutex = Mutex.new
       # running_state can take 4 values: :not_started, :running, :stopping, and
diff --git a/src/ruby/lib/grpc/version.rb b/src/ruby/lib/grpc/version.rb
index 3001579..be14125 100644
--- a/src/ruby/lib/grpc/version.rb
+++ b/src/ruby/lib/grpc/version.rb
@@ -14,5 +14,5 @@
 
 # GRPC contains the General RPC module.
 module GRPC
-  VERSION = '1.8.0.dev'
+  VERSION = '1.9.0.dev'
 end
diff --git a/src/ruby/pb/grpc/health/checker.rb b/src/ruby/pb/grpc/health/checker.rb
index f23db39..c492455 100644
--- a/src/ruby/pb/grpc/health/checker.rb
+++ b/src/ruby/pb/grpc/health/checker.rb
@@ -48,6 +48,20 @@
         @status_mutex.synchronize { @statuses["#{service}"] = status }
       end
 
+      # Adds given health status for all given services
+      def set_status_for_services(status, *services)
+        @status_mutex.synchronize do
+          services.each { |service| @statuses["#{service}"] = status }
+        end
+      end
+
+      # Adds health status for each service given within hash
+      def add_statuses(service_statuses = {})
+        @status_mutex.synchronize do
+          service_statuses.each_pair { |service, status| @statuses["#{service}"] = status }
+        end
+      end
+
       # Clears the status for the given service.
       def clear_status(service)
         @status_mutex.synchronize { @statuses.delete("#{service}") }
diff --git a/src/ruby/qps/worker.rb b/src/ruby/qps/worker.rb
index 21e8815..8258487 100755
--- a/src/ruby/qps/worker.rb
+++ b/src/ruby/qps/worker.rb
@@ -77,8 +77,7 @@
     Grpc::Testing::CoreResponse.new(cores: cpu_cores)
   end
   def quit_worker(_args, _call)
-    Thread.new {
-      sleep 3
+    @shutdown_thread = Thread.new {
       @server.stop
     }
     Grpc::Testing::Void.new
@@ -87,6 +86,9 @@
     @server = s
     @server_port = sp
   end
+  def join_shutdown_thread
+    @shutdown_thread.join
+  end
 end
 
 def main
@@ -107,11 +109,13 @@
   # Configure any errors with client or server child threads to surface
   Thread.abort_on_exception = true
   
-  s = GRPC::RpcServer.new
+  s = GRPC::RpcServer.new(poll_period: 3)
   s.add_http2_port("0.0.0.0:" + options['driver_port'].to_s,
                    :this_port_is_insecure)
-  s.handle(WorkerServiceImpl.new(s, options['server_port'].to_i))
+  worker_service = WorkerServiceImpl.new(s, options['server_port'].to_i)
+  s.handle(worker_service)
   s.run
+  worker_service.join_shutdown_thread
 end
 
 main
diff --git a/src/ruby/spec/pb/health/checker_spec.rb b/src/ruby/spec/pb/health/checker_spec.rb
index 6c9e206..c79ccfd 100644
--- a/src/ruby/spec/pb/health/checker_spec.rb
+++ b/src/ruby/spec/pb/health/checker_spec.rb
@@ -99,6 +99,35 @@
     end
   end
 
+  context 'method `add_statuses`' do
+    it 'should add status to each service' do
+      checker = Grpc::Health::Checker.new
+      checker.add_statuses(
+        'service1' => ServingStatus::SERVING,
+        'service2' => ServingStatus::NOT_SERVING
+      )
+      service1_health = checker.check(HCReq.new(service: 'service1'), nil)
+      service2_health = checker.check(HCReq.new(service: 'service2'), nil)
+      expect(service1_health).to eq(HCResp.new(status: ServingStatus::SERVING))
+      expect(service2_health).to eq(HCResp.new(status: ServingStatus::NOT_SERVING))
+    end
+  end
+
+  context 'method `set_status_for_services`' do
+    it 'should add given status to all given services' do
+      checker = Grpc::Health::Checker.new
+      checker.set_status_for_services(
+        ServingStatus::SERVING,
+        'service1',
+        'service2'
+      )
+      service1_health = checker.check(HCReq.new(service: 'service1'), nil)
+      service2_health = checker.check(HCReq.new(service: 'service2'), nil)
+      expect(service1_health).to eq(HCResp.new(status: ServingStatus::SERVING))
+      expect(service2_health).to eq(HCResp.new(status: ServingStatus::SERVING))
+    end
+  end
+
   context 'method `check`' do
     success_tests.each do |t|
       it "should fail with NOT_FOUND when #{t[:desc]}" do
diff --git a/src/ruby/tools/version.rb b/src/ruby/tools/version.rb
index c584a7c..48aad39 100644
--- a/src/ruby/tools/version.rb
+++ b/src/ruby/tools/version.rb
@@ -14,6 +14,6 @@
 
 module GRPC
   module Tools
-    VERSION = '1.8.0.dev'
+    VERSION = '1.9.0.dev'
   end
 end
diff --git a/templates/CMakeLists.txt.template b/templates/CMakeLists.txt.template
index 2ed7c90..f893710 100644
--- a/templates/CMakeLists.txt.template
+++ b/templates/CMakeLists.txt.template
@@ -280,6 +280,7 @@
   elseif("<%text>${gRPC_SSL_PROVIDER}</%text>" STREQUAL "package")
     find_package(OpenSSL REQUIRED)
     set(_gRPC_SSL_LIBRARIES <%text>${OPENSSL_LIBRARIES}</%text>)
+    include_directories(<%text>${OPENSSL_INCLUDE_DIR}</%text>)
     set(_gRPC_FIND_SSL "if(NOT OPENSSL_FOUND)\n  find_package(OpenSSL)\nendif()")
   endif()
 
@@ -522,7 +523,6 @@
     PRIVATE <%text>${CARES_INCLUDE_DIR}</%text>
     PRIVATE <%text>${CMAKE_CURRENT_BINARY_DIR}</%text>/third_party/cares/cares
     PRIVATE <%text>${CMAKE_CURRENT_BINARY_DIR}</%text>/third_party/gflags/include
-    PRIVATE <%text>${CMAKE_CURRENT_SOURCE_DIR}</%text>/third_party/abseil-cpp
   % if lib.build in ['test', 'private'] and lib.language == 'c++':
     PRIVATE third_party/googletest/googletest/include
     PRIVATE third_party/googletest/googletest
@@ -594,7 +594,6 @@
     PRIVATE <%text>${CARES_INCLUDE_DIR}</%text>
     PRIVATE <%text>${CMAKE_CURRENT_BINARY_DIR}</%text>/third_party/cares/cares
     PRIVATE <%text>${CMAKE_CURRENT_BINARY_DIR}</%text>/third_party/gflags/include
-    PRIVATE <%text>${CMAKE_CURRENT_SOURCE_DIR}</%text>/third_party/abseil-cpp
   % if tgt.build in ['test', 'private'] and tgt.language == 'c++':
     PRIVATE third_party/googletest/googletest/include
     PRIVATE third_party/googletest/googletest
diff --git a/templates/Makefile.template b/templates/Makefile.template
index 0588787..3eb8388 100644
--- a/templates/Makefile.template
+++ b/templates/Makefile.template
@@ -215,7 +215,7 @@
   ifeq ($(SYSTEM),Darwin)
   CXXFLAGS += -stdlib=libc++
   endif
-  % for arg in ['CFLAGS', 'CXXFLAGS', 'CPPFLAGS', 'LDFLAGS', 'DEFINES']:
+  % for arg in ['CFLAGS', 'CXXFLAGS', 'CPPFLAGS', 'COREFLAGS', 'LDFLAGS', 'DEFINES']:
   %  if defaults.get('global', []).get(arg, None) is not None:
   ${arg} += ${defaults.get('global').get(arg)}
   %  endif
@@ -1268,6 +1268,16 @@
   	$(Q) mkdir -p `dirname $@`
   	$(Q) $(HOST_CXX) $(HOST_CXXFLAGS) $(HOST_CPPFLAGS) -MMD -MF $(addsuffix .dep, $(basename $@)) -c -o $@ $<
 
+  $(OBJDIR)/$(CONFIG)/src/core/%.o : src/core/%.cc
+  	$(E) "[CXX]     Compiling $<"
+  	$(Q) mkdir -p `dirname $@`
+  	$(Q) $(CXX) $(CPPFLAGS) $(CXXFLAGS) $(COREFLAGS) -MMD -MF $(addsuffix .dep, $(basename $@)) -c -o $@ $<
+
+  $(OBJDIR)/$(CONFIG)/test/core/%.o : test/core/%.cc
+  	$(E) "[CXX]     Compiling $<"
+  	$(Q) mkdir -p `dirname $@`
+  	$(Q) $(CXX) $(CPPFLAGS) $(CXXFLAGS) $(COREFLAGS) -MMD -MF $(addsuffix .dep, $(basename $@)) -c -o $@ $<
+
   $(OBJDIR)/$(CONFIG)/%.o : %.cc
   	$(E) "[CXX]     Compiling $<"
   	$(Q) mkdir -p `dirname $@`
diff --git a/templates/gRPC-Core.podspec.template b/templates/gRPC-Core.podspec.template
index 3b935e9..04b8940 100644
--- a/templates/gRPC-Core.podspec.template
+++ b/templates/gRPC-Core.podspec.template
@@ -112,6 +112,7 @@
       'USE_HEADERMAP' => 'NO',
       'ALWAYS_SEARCH_USER_PATHS' => 'NO',
       'GCC_PREPROCESSOR_DEFINITIONS' => '"$(inherited)" "COCOAPODS=1" "PB_NO_PACKED_STRUCTS=1"',
+      'CLANG_WARN_STRICT_PROTOTYPES' => 'NO',
     }
 
     s.default_subspecs = 'Interface', 'Implementation'
diff --git a/templates/gRPC-ProtoRPC.podspec.template b/templates/gRPC-ProtoRPC.podspec.template
index 4d99f6e..d2dcc42 100644
--- a/templates/gRPC-ProtoRPC.podspec.template
+++ b/templates/gRPC-ProtoRPC.podspec.template
@@ -54,5 +54,6 @@
       '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',
+      'CLANG_WARN_STRICT_PROTOTYPES' => 'NO',
     }
   end
diff --git a/templates/gRPC-RxLibrary.podspec.template b/templates/gRPC-RxLibrary.podspec.template
index de4ee1e..14147d7 100644
--- a/templates/gRPC-RxLibrary.podspec.template
+++ b/templates/gRPC-RxLibrary.podspec.template
@@ -46,4 +46,8 @@
     s.source_files = "#{src_dir}/*.{h,m}", "#{src_dir}/**/*.{h,m}"
     s.private_header_files = "#{src_dir}/private/*.h"
     s.header_mappings_dir = "#{src_dir}"
+
+    s.pod_target_xcconfig = {
+      'CLANG_WARN_STRICT_PROTOTYPES' => 'NO',
+    }
   end
diff --git a/templates/gRPC.podspec.template b/templates/gRPC.podspec.template
index 4b360cf..6616e74 100644
--- a/templates/gRPC.podspec.template
+++ b/templates/gRPC.podspec.template
@@ -52,6 +52,7 @@
     s.pod_target_xcconfig = {
       # This is needed by all pods that depend on gRPC-RxLibrary:
       'CLANG_ALLOW_NON_MODULAR_INCLUDES_IN_FRAMEWORK_MODULES' => 'YES',
+      'CLANG_WARN_STRICT_PROTOTYPES' => 'NO',
     }
 
     s.subspec 'Main' do |ss|
diff --git a/templates/src/core/plugin_registry.template b/templates/src/core/plugin_registry.template
index 8d76171..805ae90 100644
--- a/templates/src/core/plugin_registry.template
+++ b/templates/src/core/plugin_registry.template
@@ -25,8 +25,8 @@
   #include <grpc/grpc.h>
 
   %for plugin in selected.plugins:
-  extern "C" void ${plugin}_init(void);
-  extern "C" void ${plugin}_shutdown(void);
+  void ${plugin}_init(void);
+  void ${plugin}_shutdown(void);
   %endfor
 
   void grpc_register_built_in_plugins(void) {
diff --git "a/templates/src/objective-c/\041ProtoCompiler-gRPCPlugin.podspec.template" "b/templates/src/objective-c/\041ProtoCompiler-gRPCPlugin.podspec.template"
index 196c405..5c1358f 100644
--- "a/templates/src/objective-c/\041ProtoCompiler-gRPCPlugin.podspec.template"
+++ "b/templates/src/objective-c/\041ProtoCompiler-gRPCPlugin.podspec.template"
@@ -103,7 +103,7 @@
     s.preserve_paths = plugin
 
     # Restrict the protoc version to the one supported by this plugin.
-    s.dependency '!ProtoCompiler', '3.4.0'
+    s.dependency '!ProtoCompiler', '3.5.0'
     # For the Protobuf dependency not to complain:
     s.ios.deployment_target = '7.0'
     s.osx.deployment_target = '10.9'
diff --git a/templates/test/core/surface/public_headers_must_be_c89.c.template b/templates/test/core/surface/public_headers_must_be_c89.c.template
index e2d3b18..6e4a836 100644
--- a/templates/test/core/surface/public_headers_must_be_c89.c.template
+++ b/templates/test/core/surface/public_headers_must_be_c89.c.template
@@ -48,10 +48,8 @@
   #include <stdio.h>
 
   int main(int argc, char **argv) {
-    if(argc == 12345678) {
-      % for fn in fns:
-      printf("%lx", (unsigned long) ${fn});
-      % endfor
-    }
+    % for fn in fns:
+    printf("%lx", (unsigned long) ${fn});
+    % endfor
     return 0;
   }
diff --git a/templates/tools/dockerfile/python_deps.include b/templates/tools/dockerfile/python_deps.include
index bf1f57f..cd1af22 100644
--- a/templates/tools/dockerfile/python_deps.include
+++ b/templates/tools/dockerfile/python_deps.include
@@ -11,4 +11,4 @@
 # Install Python packages from PyPI
 RUN pip install --upgrade pip==9.0.1
 RUN pip install virtualenv
-RUN pip install futures==2.2.0 enum34==1.0.4 protobuf==3.2.0 six==1.10.0 twisted==17.5.0
+RUN pip install futures==2.2.0 enum34==1.0.4 protobuf==3.5.0.post1 six==1.10.0 twisted==17.5.0
diff --git a/test/core/end2end/cq_verifier.h b/test/core/end2end/cq_verifier.h
index 0b3b3fb..959f849 100644
--- a/test/core/end2end/cq_verifier.h
+++ b/test/core/end2end/cq_verifier.h
@@ -24,10 +24,6 @@
 #include <grpc/grpc.h>
 #include "test/core/util/test_config.h"
 
-#ifdef __cplusplus
-extern "C" {
-#endif
-
 /* A cq_verifier can verify that expected events arrive in a timely fashion
    on a single completion queue */
 
@@ -63,8 +59,4 @@
 int contains_metadata_slices(grpc_metadata_array* array, grpc_slice key,
                              grpc_slice value);
 
-#ifdef __cplusplus
-}
-#endif
-
 #endif /* GRPC_TEST_CORE_END2END_CQ_VERIFIER_H */
diff --git a/test/core/end2end/data/client_certs.cc b/test/core/end2end/data/client_certs.cc
index 7e0b10d..46fc139 100644
--- a/test/core/end2end/data/client_certs.cc
+++ b/test/core/end2end/data/client_certs.cc
@@ -16,7 +16,7 @@
  *
  */
 
-extern "C" const char test_self_signed_client_cert[] = {
+extern const char test_self_signed_client_cert[] = {
     0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x42, 0x45, 0x47, 0x49, 0x4e, 0x20, 0x43,
     0x45, 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d,
     0x2d, 0x2d, 0x2d, 0x0a, 0x4d, 0x49, 0x49, 0x43, 0x6f, 0x44, 0x43, 0x43,
@@ -100,7 +100,7 @@
     0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d,
     0x0a, 0x00};
 
-extern "C" const char test_self_signed_client_key[] = {
+extern const char test_self_signed_client_key[] = {
     0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x42, 0x45, 0x47, 0x49, 0x4e, 0x20, 0x50,
     0x52, 0x49, 0x56, 0x41, 0x54, 0x45, 0x20, 0x4b, 0x45, 0x59, 0x2d, 0x2d,
     0x2d, 0x2d, 0x2d, 0x0a, 0x4d, 0x49, 0x49, 0x43, 0x64, 0x77, 0x49, 0x42,
@@ -179,7 +179,7 @@
     0x52, 0x49, 0x56, 0x41, 0x54, 0x45, 0x20, 0x4b, 0x45, 0x59, 0x2d, 0x2d,
     0x2d, 0x2d, 0x2d, 0x0a, 0x00};
 
-extern "C" const char test_signed_client_cert[] = {
+extern const char test_signed_client_cert[] = {
     0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x42, 0x45, 0x47, 0x49, 0x4e, 0x20, 0x43,
     0x45, 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d,
     0x2d, 0x2d, 0x2d, 0x0a, 0x4d, 0x49, 0x49, 0x43, 0x48, 0x7a, 0x43, 0x43,
@@ -248,7 +248,7 @@
     0x20, 0x43, 0x45, 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x45,
     0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x00};
 
-extern "C" const char test_signed_client_key[] = {
+extern const char test_signed_client_key[] = {
     0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x42, 0x45, 0x47, 0x49, 0x4e, 0x20, 0x50,
     0x52, 0x49, 0x56, 0x41, 0x54, 0x45, 0x20, 0x4b, 0x45, 0x59, 0x2d, 0x2d,
     0x2d, 0x2d, 0x2d, 0x0a, 0x4d, 0x49, 0x49, 0x43, 0x65, 0x51, 0x49, 0x42,
diff --git a/test/core/end2end/data/server1_cert.cc b/test/core/end2end/data/server1_cert.cc
index dd09810..0943244 100644
--- a/test/core/end2end/data/server1_cert.cc
+++ b/test/core/end2end/data/server1_cert.cc
@@ -16,7 +16,7 @@
  *
  */
 
-extern "C" const char test_server1_cert[] = {
+extern const char test_server1_cert[] = {
     0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x42, 0x45, 0x47, 0x49, 0x4e, 0x20, 0x43,
     0x45, 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d,
     0x2d, 0x2d, 0x2d, 0x0a, 0x4d, 0x49, 0x49, 0x43, 0x6e, 0x44, 0x43, 0x43,
diff --git a/test/core/end2end/data/server1_key.cc b/test/core/end2end/data/server1_key.cc
index 59dcaf6..8f3ad15 100644
--- a/test/core/end2end/data/server1_key.cc
+++ b/test/core/end2end/data/server1_key.cc
@@ -16,7 +16,7 @@
  *
  */
 
-extern "C" const char test_server1_key[] = {
+extern const char test_server1_key[] = {
     0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x42, 0x45, 0x47, 0x49, 0x4e, 0x20, 0x52,
     0x53, 0x41, 0x20, 0x50, 0x52, 0x49, 0x56, 0x41, 0x54, 0x45, 0x20, 0x4b,
     0x45, 0x59, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x4d, 0x49, 0x49, 0x43,
diff --git a/test/core/end2end/data/ssl_test_data.h b/test/core/end2end/data/ssl_test_data.h
index e9c7dbc..303f3a6 100644
--- a/test/core/end2end/data/ssl_test_data.h
+++ b/test/core/end2end/data/ssl_test_data.h
@@ -19,10 +19,6 @@
 #ifndef GRPC_TEST_CORE_END2END_DATA_SSL_TEST_DATA_H
 #define GRPC_TEST_CORE_END2END_DATA_SSL_TEST_DATA_H
 
-#ifdef __cplusplus
-extern "C" {
-#endif
-
 extern const char test_root_cert[];
 extern const char test_server1_cert[];
 extern const char test_server1_key[];
@@ -31,8 +27,4 @@
 extern const char test_signed_client_cert[];
 extern const char test_signed_client_key[];
 
-#ifdef __cplusplus
-}
-#endif
-
 #endif /* GRPC_TEST_CORE_END2END_DATA_SSL_TEST_DATA_H */
diff --git a/test/core/end2end/data/test_root_cert.cc b/test/core/end2end/data/test_root_cert.cc
index 36fca2e..b4771b2 100644
--- a/test/core/end2end/data/test_root_cert.cc
+++ b/test/core/end2end/data/test_root_cert.cc
@@ -16,7 +16,7 @@
  *
  */
 
-extern "C" const char test_root_cert[] = {
+extern const char test_root_cert[] = {
     0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x42, 0x45, 0x47, 0x49, 0x4e, 0x20, 0x43,
     0x45, 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d,
     0x2d, 0x2d, 0x2d, 0x0a, 0x4d, 0x49, 0x49, 0x43, 0x49, 0x7a, 0x43, 0x43,
diff --git a/test/core/end2end/end2end_tests.h b/test/core/end2end/end2end_tests.h
index 33943a7..b42d90b 100644
--- a/test/core/end2end/end2end_tests.h
+++ b/test/core/end2end/end2end_tests.h
@@ -21,10 +21,6 @@
 
 #include <grpc/grpc.h>
 
-#ifdef __cplusplus
-extern "C" {
-#endif
-
 typedef struct grpc_end2end_test_fixture grpc_end2end_test_fixture;
 typedef struct grpc_end2end_test_config grpc_end2end_test_config;
 
@@ -78,8 +74,4 @@
 void validate_host_override_string(const char* pattern, grpc_slice str,
                                    grpc_end2end_test_config config);
 
-#ifdef __cplusplus
-}
-#endif
-
 #endif /* GRPC_TEST_CORE_END2END_END2END_TESTS_H */
diff --git a/test/core/end2end/fixtures/http_proxy_fixture.cc b/test/core/end2end/fixtures/http_proxy_fixture.cc
index 0bdd15c..ac0c953 100644
--- a/test/core/end2end/fixtures/http_proxy_fixture.cc
+++ b/test/core/end2end/fixtures/http_proxy_fixture.cc
@@ -88,9 +88,11 @@
 
   grpc_slice_buffer client_read_buffer;
   grpc_slice_buffer client_deferred_write_buffer;
+  bool client_is_writing;
   grpc_slice_buffer client_write_buffer;
   grpc_slice_buffer server_read_buffer;
   grpc_slice_buffer server_deferred_write_buffer;
+  bool server_is_writing;
   grpc_slice_buffer server_write_buffer;
 
   grpc_http_parser http_parser;
@@ -148,6 +150,7 @@
 static void on_client_write_done(grpc_exec_ctx* exec_ctx, void* arg,
                                  grpc_error* error) {
   proxy_connection* conn = (proxy_connection*)arg;
+  conn->client_is_writing = false;
   if (error != GRPC_ERROR_NONE) {
     proxy_connection_failed(exec_ctx, conn, true /* is_client */,
                             "HTTP proxy client write", error);
@@ -160,6 +163,7 @@
   if (conn->client_deferred_write_buffer.length > 0) {
     grpc_slice_buffer_move_into(&conn->client_deferred_write_buffer,
                                 &conn->client_write_buffer);
+    conn->client_is_writing = true;
     grpc_endpoint_write(exec_ctx, conn->client_endpoint,
                         &conn->client_write_buffer,
                         &conn->on_client_write_done);
@@ -173,6 +177,7 @@
 static void on_server_write_done(grpc_exec_ctx* exec_ctx, void* arg,
                                  grpc_error* error) {
   proxy_connection* conn = (proxy_connection*)arg;
+  conn->server_is_writing = false;
   if (error != GRPC_ERROR_NONE) {
     proxy_connection_failed(exec_ctx, conn, false /* is_client */,
                             "HTTP proxy server write", error);
@@ -185,6 +190,7 @@
   if (conn->server_deferred_write_buffer.length > 0) {
     grpc_slice_buffer_move_into(&conn->server_deferred_write_buffer,
                                 &conn->server_write_buffer);
+    conn->server_is_writing = true;
     grpc_endpoint_write(exec_ctx, conn->server_endpoint,
                         &conn->server_write_buffer,
                         &conn->on_server_write_done);
@@ -210,13 +216,14 @@
   // the current write is finished.
   //
   // Otherwise, move the read data into the write buffer and write it.
-  if (conn->server_write_buffer.length > 0) {
+  if (conn->server_is_writing) {
     grpc_slice_buffer_move_into(&conn->client_read_buffer,
                                 &conn->server_deferred_write_buffer);
   } else {
     grpc_slice_buffer_move_into(&conn->client_read_buffer,
                                 &conn->server_write_buffer);
     proxy_connection_ref(conn, "client_read");
+    conn->server_is_writing = true;
     grpc_endpoint_write(exec_ctx, conn->server_endpoint,
                         &conn->server_write_buffer,
                         &conn->on_server_write_done);
@@ -242,13 +249,14 @@
   // the current write is finished.
   //
   // Otherwise, move the read data into the write buffer and write it.
-  if (conn->client_write_buffer.length > 0) {
+  if (conn->client_is_writing) {
     grpc_slice_buffer_move_into(&conn->server_read_buffer,
                                 &conn->client_deferred_write_buffer);
   } else {
     grpc_slice_buffer_move_into(&conn->server_read_buffer,
                                 &conn->client_write_buffer);
     proxy_connection_ref(conn, "server_read");
+    conn->client_is_writing = true;
     grpc_endpoint_write(exec_ctx, conn->client_endpoint,
                         &conn->client_write_buffer,
                         &conn->on_client_write_done);
@@ -262,6 +270,7 @@
 static void on_write_response_done(grpc_exec_ctx* exec_ctx, void* arg,
                                    grpc_error* error) {
   proxy_connection* conn = (proxy_connection*)arg;
+  conn->client_is_writing = false;
   if (error != GRPC_ERROR_NONE) {
     proxy_connection_failed(exec_ctx, conn, true /* is_client */,
                             "HTTP proxy write response", error);
@@ -302,6 +311,7 @@
   grpc_slice slice =
       grpc_slice_from_copied_string("HTTP/1.0 200 connected\r\n\r\n");
   grpc_slice_buffer_add(&conn->client_write_buffer, slice);
+  conn->client_is_writing = true;
   grpc_endpoint_write(exec_ctx, conn->client_endpoint,
                       &conn->client_write_buffer,
                       &conn->on_write_response_done);
@@ -450,9 +460,11 @@
                     grpc_combiner_scheduler(conn->proxy->combiner));
   grpc_slice_buffer_init(&conn->client_read_buffer);
   grpc_slice_buffer_init(&conn->client_deferred_write_buffer);
+  conn->client_is_writing = false;
   grpc_slice_buffer_init(&conn->client_write_buffer);
   grpc_slice_buffer_init(&conn->server_read_buffer);
   grpc_slice_buffer_init(&conn->server_deferred_write_buffer);
+  conn->server_is_writing = false;
   grpc_slice_buffer_init(&conn->server_write_buffer);
   grpc_http_parser_init(&conn->http_parser, GRPC_HTTP_REQUEST,
                         &conn->http_request);
diff --git a/test/core/end2end/fuzzers/api_fuzzer.cc b/test/core/end2end/fuzzers/api_fuzzer.cc
index b8ec125..0b49b89 100644
--- a/test/core/end2end/fuzzers/api_fuzzer.cc
+++ b/test/core/end2end/fuzzers/api_fuzzer.cc
@@ -56,7 +56,7 @@
 static grpc_channel* g_channel;
 static grpc_resource_quota* g_resource_quota;
 
-extern "C" gpr_timespec (*gpr_now_impl)(gpr_clock_type clock_type);
+extern gpr_timespec (*gpr_now_impl)(gpr_clock_type clock_type);
 
 static gpr_timespec now_impl(gpr_clock_type clock_type) {
   GPR_ASSERT(clock_type != GPR_TIMESPAN);
@@ -441,7 +441,7 @@
 // client connection
 
 // defined in tcp_client_posix.c
-extern "C" void (*grpc_tcp_client_connect_impl)(
+extern void (*grpc_tcp_client_connect_impl)(
     grpc_exec_ctx* exec_ctx, grpc_closure* closure, grpc_endpoint** ep,
     grpc_pollset_set* interested_parties, const grpc_channel_args* channel_args,
     const grpc_resolved_address* addr, grpc_millis deadline);
diff --git a/test/core/end2end/tests/no_logging.cc b/test/core/end2end/tests/no_logging.cc
index 55d211c..bf86512 100644
--- a/test/core/end2end/tests/no_logging.cc
+++ b/test/core/end2end/tests/no_logging.cc
@@ -36,7 +36,7 @@
 
 static void* tag(intptr_t t) { return (void*)t; }
 
-extern "C" void gpr_default_log(gpr_log_func_args* args);
+void gpr_default_log(gpr_log_func_args* args);
 
 static void test_no_log(gpr_log_func_args* args) {
   char* message = nullptr;
diff --git a/test/core/end2end/tests/simple_request.cc b/test/core/end2end/tests/simple_request.cc
index ec7425a..7eb7467 100644
--- a/test/core/end2end/tests/simple_request.cc
+++ b/test/core/end2end/tests/simple_request.cc
@@ -99,6 +99,7 @@
   grpc_metadata_array request_metadata_recv;
   grpc_call_details call_details;
   grpc_status_code status;
+  const char* error_string;
   grpc_call_error error;
   grpc_slice details;
   int was_cancelled = 2;
@@ -148,6 +149,7 @@
   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.error_string = &error_string;
   op->flags = 0;
   op->reserved = nullptr;
   op++;
@@ -199,6 +201,15 @@
 
   GPR_ASSERT(status == GRPC_STATUS_UNIMPLEMENTED);
   GPR_ASSERT(0 == grpc_slice_str_cmp(details, "xyz"));
+  // the following sanity check makes sure that the requested error string is
+  // correctly populated by the core. It looks for certain substrings that are
+  // not likely to change much. Some parts of the error, like time created,
+  // obviously are not checked.
+  GPR_ASSERT(nullptr != strstr(error_string, "xyz"));
+  GPR_ASSERT(nullptr != strstr(error_string, "description"));
+  GPR_ASSERT(nullptr != strstr(error_string, "Error received from peer"));
+  GPR_ASSERT(nullptr != strstr(error_string, "grpc_message"));
+  GPR_ASSERT(nullptr != strstr(error_string, "grpc_status"));
   GPR_ASSERT(0 == grpc_slice_str_cmp(call_details.method, "/foo"));
   validate_host_override_string("foo.test.google.fr:1234", call_details.host,
                                 config);
@@ -206,6 +217,7 @@
   GPR_ASSERT(was_cancelled == 1);
 
   grpc_slice_unref(details);
+  gpr_free((void*)error_string);
   grpc_metadata_array_destroy(&initial_metadata_recv);
   grpc_metadata_array_destroy(&trailing_metadata_recv);
   grpc_metadata_array_destroy(&request_metadata_recv);
diff --git a/test/core/fling/client.cc b/test/core/fling/client.cc
index 544b66d..69fb6dc 100644
--- a/test/core/fling/client.cc
+++ b/test/core/fling/client.cc
@@ -22,15 +22,15 @@
 #include <string.h>
 
 #include <grpc/support/cmdline.h>
-#include <grpc/support/histogram.h>
 #include <grpc/support/log.h>
 #include <grpc/support/time.h>
 #include <grpc/support/useful.h>
 #include "src/core/lib/profiling/timers.h"
 #include "test/core/util/grpc_profiler.h"
+#include "test/core/util/histogram.h"
 #include "test/core/util/test_config.h"
 
-static gpr_histogram* histogram;
+static grpc_histogram* histogram;
 static grpc_byte_buffer* the_buffer;
 static grpc_channel* channel;
 static grpc_completion_queue* cq;
@@ -195,7 +195,7 @@
   channel = grpc_insecure_channel_create(target, nullptr, nullptr);
   cq = grpc_completion_queue_create_for_next(nullptr);
   the_buffer = grpc_raw_byte_buffer_create(&slice, (size_t)payload_size);
-  histogram = gpr_histogram_create(0.01, 60e9);
+  histogram = grpc_histogram_create(0.01, 60e9);
 
   sc.init();
 
@@ -213,7 +213,7 @@
     start = now();
     sc.do_one_step();
     stop = now();
-    gpr_histogram_add(histogram, stop - start);
+    grpc_histogram_add(histogram, stop - start);
   }
   grpc_profiler_stop();
 
@@ -232,11 +232,11 @@
   grpc_slice_unref(slice);
 
   gpr_log(GPR_INFO, "latency (50/95/99/99.9): %f/%f/%f/%f",
-          gpr_histogram_percentile(histogram, 50),
-          gpr_histogram_percentile(histogram, 95),
-          gpr_histogram_percentile(histogram, 99),
-          gpr_histogram_percentile(histogram, 99.9));
-  gpr_histogram_destroy(histogram);
+          grpc_histogram_percentile(histogram, 50),
+          grpc_histogram_percentile(histogram, 95),
+          grpc_histogram_percentile(histogram, 99),
+          grpc_histogram_percentile(histogram, 99.9));
+  grpc_histogram_destroy(histogram);
 
   grpc_shutdown();
 
diff --git a/test/core/iomgr/timer_list_test.cc b/test/core/iomgr/timer_list_test.cc
index dc965ef..d74ea4f 100644
--- a/test/core/iomgr/timer_list_test.cc
+++ b/test/core/iomgr/timer_list_test.cc
@@ -28,11 +28,12 @@
 #include <grpc/support/log.h>
 #include "src/core/lib/debug/trace.h"
 #include "test/core/util/test_config.h"
+#include "test/core/util/tracer_util.h"
 
 #define MAX_CB 30
 
-extern "C" grpc_tracer_flag grpc_timer_trace;
-extern "C" grpc_tracer_flag grpc_timer_check_trace;
+extern grpc_core::TraceFlag grpc_timer_trace;
+extern grpc_core::TraceFlag grpc_timer_check_trace;
 
 static int cb_called[MAX_CB][2];
 
@@ -48,8 +49,8 @@
   gpr_log(GPR_INFO, "add_test");
 
   grpc_timer_list_init(&exec_ctx);
-  grpc_timer_trace.value = 1;
-  grpc_timer_check_trace.value = 1;
+  grpc_core::testing::grpc_tracer_enable_flag(&grpc_timer_trace);
+  grpc_core::testing::grpc_tracer_enable_flag(&grpc_timer_check_trace);
   memset(cb_called, 0, sizeof(cb_called));
 
   grpc_millis start = grpc_exec_ctx_now(&exec_ctx);
@@ -117,8 +118,8 @@
   exec_ctx.now_is_valid = true;
   exec_ctx.now = 0;
   grpc_timer_list_init(&exec_ctx);
-  grpc_timer_trace.value = 1;
-  grpc_timer_check_trace.value = 1;
+  grpc_core::testing::grpc_tracer_enable_flag(&grpc_timer_trace);
+  grpc_core::testing::grpc_tracer_enable_flag(&grpc_timer_check_trace);
   memset(cb_called, 0, sizeof(cb_called));
 
   grpc_timer_init(
diff --git a/test/core/network_benchmarks/low_level_ping_pong.cc b/test/core/network_benchmarks/low_level_ping_pong.cc
index 687395d..2ae9a45 100644
--- a/test/core/network_benchmarks/low_level_ping_pong.cc
+++ b/test/core/network_benchmarks/low_level_ping_pong.cc
@@ -36,13 +36,13 @@
 
 #include <grpc/support/alloc.h>
 #include <grpc/support/cmdline.h>
-#include <grpc/support/histogram.h>
 #include <grpc/support/log.h>
 #include <grpc/support/thd.h>
 #include <grpc/support/time.h>
 #include <grpc/support/useful.h>
 #include "src/core/lib/iomgr/error.h"
 #include "src/core/lib/iomgr/socket_utils_posix.h"
+#include "test/core/util/histogram.h"
 
 typedef struct fd_pair {
   int read_fd;
@@ -275,14 +275,14 @@
   server_thread(args);
 }
 
-static void print_histogram(gpr_histogram* histogram) {
+static void print_histogram(grpc_histogram* histogram) {
   /* TODO(klempner): Print more detailed information, such as detailed histogram
      buckets */
   gpr_log(GPR_INFO, "latency (50/95/99/99.9): %f/%f/%f/%f",
-          gpr_histogram_percentile(histogram, 50),
-          gpr_histogram_percentile(histogram, 95),
-          gpr_histogram_percentile(histogram, 99),
-          gpr_histogram_percentile(histogram, 99.9));
+          grpc_histogram_percentile(histogram, 50),
+          grpc_histogram_percentile(histogram, 95),
+          grpc_histogram_percentile(histogram, 99),
+          grpc_histogram_percentile(histogram, 99.9));
 }
 
 static double now(void) {
@@ -293,7 +293,7 @@
 static void client_thread(thread_args* args) {
   char* buf = static_cast<char*>(gpr_malloc(args->msg_size * sizeof(char)));
   memset(buf, 0, args->msg_size * sizeof(char));
-  gpr_histogram* histogram = gpr_histogram_create(0.01, 60e9);
+  grpc_histogram* histogram = grpc_histogram_create(0.01, 60e9);
   double start_time;
   double end_time;
   double interval;
@@ -316,13 +316,13 @@
     end_time = now();
     if (i > kNumIters / 2) {
       interval = end_time - start_time;
-      gpr_histogram_add(histogram, interval);
+      grpc_histogram_add(histogram, interval);
     }
   }
   print_histogram(histogram);
 error:
   gpr_free(buf);
-  gpr_histogram_destroy(histogram);
+  grpc_histogram_destroy(histogram);
 }
 
 /* This roughly matches tcp_server's create_listening_socket */
diff --git a/test/core/support/BUILD b/test/core/support/BUILD
index 9d042fd..4372b49 100644
--- a/test/core/support/BUILD
+++ b/test/core/support/BUILD
@@ -69,16 +69,6 @@
 )
 
 grpc_cc_test(
-    name = "histogram_test",
-    srcs = ["histogram_test.cc"],
-    language = "C++",
-    deps = [
-        "//:gpr",
-        "//test/core/util:gpr_test_util",
-    ],
-)
-
-grpc_cc_test(
     name = "host_port_test",
     srcs = ["host_port_test.cc"],
     language = "C++",
@@ -119,8 +109,8 @@
 )
 
 grpc_cc_test(
-    name = "stack_lockfree_test",
-    srcs = ["stack_lockfree_test.cc"],
+    name = "string_test",
+    srcs = ["string_test.cc"],
     language = "C++",
     deps = [
         "//:gpr",
@@ -129,8 +119,8 @@
 )
 
 grpc_cc_test(
-    name = "string_test",
-    srcs = ["string_test.cc"],
+    name = "manual_constructor_test",
+    srcs = ["manual_constructor_test.cc"],
     language = "C++",
     deps = [
         "//:gpr",
@@ -201,22 +191,49 @@
 grpc_cc_test(
     name = "memory_test",
     srcs = ["memory_test.cc"],
+    external_deps = [
+        "gtest",
+    ],
     language = "C++",
     deps = [
         "//:grpc",
         "//test/core/util:gpr_test_util",
     ],
+)
+
+grpc_cc_test(
+    name = "vector_test",
+    srcs = ["vector_test.cc"],
+    external_deps = [
+        "gtest",
+    ],
+    language = "C++",
+    deps = [
+        "//:grpc",
+        "//test/core/util:gpr_test_util",
+    ],
+)
+
+grpc_cc_test(
+    name = "ref_counted_test",
+    srcs = ["ref_counted_test.cc"],
+    language = "C++",
+    deps = [
+        "//:ref_counted",
+        "//test/core/util:gpr_test_util",
+    ],
     external_deps = [
         "gtest",
     ],
 )
 
 grpc_cc_test(
-    name = "vector_test",
-    srcs = ["vector_test.cc"],
+    name = "ref_counted_ptr_test",
+    srcs = ["ref_counted_ptr_test.cc"],
     language = "C++",
     deps = [
-        "//:grpc",
+        "//:ref_counted",
+        "//:ref_counted_ptr",
         "//test/core/util:gpr_test_util",
     ],
     external_deps = [
diff --git a/test/core/support/histogram_test.cc b/test/core/support/histogram_test.cc
deleted file mode 100644
index 86b7d59..0000000
--- a/test/core/support/histogram_test.cc
+++ /dev/null
@@ -1,163 +0,0 @@
-/*
- *
- * Copyright 2015 gRPC authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-#include <grpc/support/histogram.h>
-#include <grpc/support/log.h>
-
-#define LOG_TEST(x) gpr_log(GPR_INFO, "%s", x);
-
-static void test_no_op(void) {
-  gpr_histogram_destroy(gpr_histogram_create(0.01, 60e9));
-}
-
-static void expect_percentile(gpr_histogram* h, double percentile,
-                              double min_expect, double max_expect) {
-  double got = gpr_histogram_percentile(h, percentile);
-  gpr_log(GPR_INFO, "@%f%%, expect %f <= %f <= %f", percentile, min_expect, got,
-          max_expect);
-  GPR_ASSERT(min_expect <= got);
-  GPR_ASSERT(got <= max_expect);
-}
-
-static void test_simple(void) {
-  gpr_histogram* h;
-
-  LOG_TEST("test_simple");
-
-  h = gpr_histogram_create(0.01, 60e9);
-  gpr_histogram_add(h, 10000);
-  gpr_histogram_add(h, 10000);
-  gpr_histogram_add(h, 11000);
-  gpr_histogram_add(h, 11000);
-
-  expect_percentile(h, 50, 10001, 10999);
-  GPR_ASSERT(gpr_histogram_mean(h) == 10500);
-
-  gpr_histogram_destroy(h);
-}
-
-static void test_percentile(void) {
-  gpr_histogram* h;
-  double last;
-  double i;
-  double cur;
-
-  LOG_TEST("test_percentile");
-
-  h = gpr_histogram_create(0.05, 1e9);
-  gpr_histogram_add(h, 2.5);
-  gpr_histogram_add(h, 2.5);
-  gpr_histogram_add(h, 8);
-  gpr_histogram_add(h, 4);
-
-  GPR_ASSERT(gpr_histogram_count(h) == 4);
-  GPR_ASSERT(gpr_histogram_minimum(h) == 2.5);
-  GPR_ASSERT(gpr_histogram_maximum(h) == 8);
-  GPR_ASSERT(gpr_histogram_sum(h) == 17);
-  GPR_ASSERT(gpr_histogram_sum_of_squares(h) == 92.5);
-  GPR_ASSERT(gpr_histogram_mean(h) == 4.25);
-  GPR_ASSERT(gpr_histogram_variance(h) == 5.0625);
-  GPR_ASSERT(gpr_histogram_stddev(h) == 2.25);
-
-  expect_percentile(h, -10, 2.5, 2.5);
-  expect_percentile(h, 0, 2.5, 2.5);
-  expect_percentile(h, 12.5, 2.5, 2.5);
-  expect_percentile(h, 25, 2.5, 2.5);
-  expect_percentile(h, 37.5, 2.5, 2.8);
-  expect_percentile(h, 50, 3.0, 3.5);
-  expect_percentile(h, 62.5, 3.5, 4.5);
-  expect_percentile(h, 75, 5, 7.9);
-  expect_percentile(h, 100, 8, 8);
-  expect_percentile(h, 110, 8, 8);
-
-  /* test monotonicity */
-  last = 0.0;
-  for (i = 0; i < 100.0; i += 0.01) {
-    cur = gpr_histogram_percentile(h, i);
-    GPR_ASSERT(cur >= last);
-    last = cur;
-  }
-
-  gpr_histogram_destroy(h);
-}
-
-static void test_merge(void) {
-  gpr_histogram *h1, *h2;
-  double last;
-  double i;
-  double cur;
-
-  LOG_TEST("test_merge");
-
-  h1 = gpr_histogram_create(0.05, 1e9);
-  gpr_histogram_add(h1, 2.5);
-  gpr_histogram_add(h1, 2.5);
-  gpr_histogram_add(h1, 8);
-  gpr_histogram_add(h1, 4);
-
-  h2 = gpr_histogram_create(0.01, 1e9);
-  GPR_ASSERT(gpr_histogram_merge(h1, h2) == 0);
-  gpr_histogram_destroy(h2);
-
-  h2 = gpr_histogram_create(0.05, 1e10);
-  GPR_ASSERT(gpr_histogram_merge(h1, h2) == 0);
-  gpr_histogram_destroy(h2);
-
-  h2 = gpr_histogram_create(0.05, 1e9);
-  GPR_ASSERT(gpr_histogram_merge(h1, h2) == 1);
-  GPR_ASSERT(gpr_histogram_count(h1) == 4);
-  GPR_ASSERT(gpr_histogram_minimum(h1) == 2.5);
-  GPR_ASSERT(gpr_histogram_maximum(h1) == 8);
-  GPR_ASSERT(gpr_histogram_sum(h1) == 17);
-  GPR_ASSERT(gpr_histogram_sum_of_squares(h1) == 92.5);
-  GPR_ASSERT(gpr_histogram_mean(h1) == 4.25);
-  GPR_ASSERT(gpr_histogram_variance(h1) == 5.0625);
-  GPR_ASSERT(gpr_histogram_stddev(h1) == 2.25);
-  gpr_histogram_destroy(h2);
-
-  h2 = gpr_histogram_create(0.05, 1e9);
-  gpr_histogram_add(h2, 7.0);
-  gpr_histogram_add(h2, 17.0);
-  gpr_histogram_add(h2, 1.0);
-  GPR_ASSERT(gpr_histogram_merge(h1, h2) == 1);
-  GPR_ASSERT(gpr_histogram_count(h1) == 7);
-  GPR_ASSERT(gpr_histogram_minimum(h1) == 1.0);
-  GPR_ASSERT(gpr_histogram_maximum(h1) == 17.0);
-  GPR_ASSERT(gpr_histogram_sum(h1) == 42.0);
-  GPR_ASSERT(gpr_histogram_sum_of_squares(h1) == 431.5);
-  GPR_ASSERT(gpr_histogram_mean(h1) == 6.0);
-
-  /* test monotonicity */
-  last = 0.0;
-  for (i = 0; i < 100.0; i += 0.01) {
-    cur = gpr_histogram_percentile(h1, i);
-    GPR_ASSERT(cur >= last);
-    last = cur;
-  }
-
-  gpr_histogram_destroy(h1);
-  gpr_histogram_destroy(h2);
-}
-
-int main(void) {
-  test_no_op();
-  test_simple();
-  test_percentile();
-  test_merge();
-  return 0;
-}
diff --git a/test/core/support/manual_constructor_test.cc b/test/core/support/manual_constructor_test.cc
new file mode 100644
index 0000000..714f8b2
--- /dev/null
+++ b/test/core/support/manual_constructor_test.cc
@@ -0,0 +1,99 @@
+/*
+ *
+ * Copyright 2017 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+/* Test of gpr synchronization support. */
+
+#include "src/core/lib/support/manual_constructor.h"
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+#include <grpc/support/sync.h>
+#include <grpc/support/thd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <cstring>
+#include "src/core/lib/support/abstract.h"
+#include "test/core/util/test_config.h"
+
+class A {
+ public:
+  A() {}
+  virtual ~A() {}
+  virtual const char* foo() { return "A_foo"; }
+  virtual const char* bar() { return "A_bar"; }
+  GRPC_ABSTRACT_BASE_CLASS
+};
+
+class B : public A {
+ public:
+  B() {}
+  ~B() {}
+  const char* foo() override { return "B_foo"; }
+  char get_junk() { return junk[0]; }
+
+ private:
+  char junk[1000];
+};
+
+class C : public B {
+ public:
+  C() {}
+  ~C() {}
+  virtual const char* bar() { return "C_bar"; }
+  char get_more_junk() { return more_junk[0]; }
+
+ private:
+  char more_junk[1000];
+};
+
+class D : public A {
+ public:
+  virtual const char* bar() { return "D_bar"; }
+};
+
+static void basic_test() {
+  grpc_core::PolymorphicManualConstructor<A, B> poly;
+  poly.Init<B>();
+  GPR_ASSERT(!strcmp(poly->foo(), "B_foo"));
+  GPR_ASSERT(!strcmp(poly->bar(), "A_bar"));
+}
+
+static void complex_test() {
+  grpc_core::PolymorphicManualConstructor<A, B, C, D> polyB;
+  polyB.Init<B>();
+  GPR_ASSERT(!strcmp(polyB->foo(), "B_foo"));
+  GPR_ASSERT(!strcmp(polyB->bar(), "A_bar"));
+
+  grpc_core::PolymorphicManualConstructor<A, B, C, D> polyC;
+  polyC.Init<C>();
+  GPR_ASSERT(!strcmp(polyC->foo(), "B_foo"));
+  GPR_ASSERT(!strcmp(polyC->bar(), "C_bar"));
+
+  grpc_core::PolymorphicManualConstructor<A, B, C, D> polyD;
+  polyD.Init<D>();
+  GPR_ASSERT(!strcmp(polyD->foo(), "A_foo"));
+  GPR_ASSERT(!strcmp(polyD->bar(), "D_bar"));
+}
+
+/* ------------------------------------------------- */
+
+int main(int argc, char* argv[]) {
+  grpc_test_init(argc, argv);
+  basic_test();
+  complex_test();
+  return 0;
+}
diff --git a/test/core/support/ref_counted_ptr_test.cc b/test/core/support/ref_counted_ptr_test.cc
new file mode 100644
index 0000000..1830edc
--- /dev/null
+++ b/test/core/support/ref_counted_ptr_test.cc
@@ -0,0 +1,172 @@
+/*
+ *
+ * Copyright 2017 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include "src/core/lib/support/ref_counted_ptr.h"
+
+#include <gtest/gtest.h>
+
+#include <grpc/support/log.h>
+
+#include "src/core/lib/support/memory.h"
+#include "src/core/lib/support/ref_counted.h"
+#include "test/core/util/test_config.h"
+
+namespace grpc_core {
+namespace testing {
+namespace {
+
+class Foo : public RefCounted {
+ public:
+  Foo() : value_(0) {}
+
+  explicit Foo(int value) : value_(value) {}
+
+  int value() const { return value_; }
+
+ private:
+  int value_;
+};
+
+TEST(RefCountedPtr, DefaultConstructor) { RefCountedPtr<Foo> foo; }
+
+TEST(RefCountedPtr, ExplicitConstructorEmpty) {
+  RefCountedPtr<Foo> foo(nullptr);
+}
+
+TEST(RefCountedPtr, ExplicitConstructor) { RefCountedPtr<Foo> foo(New<Foo>()); }
+
+TEST(RefCountedPtr, MoveConstructor) {
+  RefCountedPtr<Foo> foo(New<Foo>());
+  RefCountedPtr<Foo> foo2(std::move(foo));
+  EXPECT_EQ(nullptr, foo.get());
+  EXPECT_NE(nullptr, foo2.get());
+}
+
+TEST(RefCountedPtr, MoveAssignment) {
+  RefCountedPtr<Foo> foo(New<Foo>());
+  RefCountedPtr<Foo> foo2 = std::move(foo);
+  EXPECT_EQ(nullptr, foo.get());
+  EXPECT_NE(nullptr, foo2.get());
+}
+
+TEST(RefCountedPtr, CopyConstructor) {
+  RefCountedPtr<Foo> foo(New<Foo>());
+  RefCountedPtr<Foo> foo2(foo);
+  EXPECT_NE(nullptr, foo.get());
+  EXPECT_EQ(foo.get(), foo2.get());
+}
+
+TEST(RefCountedPtr, CopyAssignment) {
+  RefCountedPtr<Foo> foo(New<Foo>());
+  RefCountedPtr<Foo> foo2 = foo;
+  EXPECT_NE(nullptr, foo.get());
+  EXPECT_EQ(foo.get(), foo2.get());
+}
+
+TEST(RefCountedPtr, CopyAssignmentWhenEmpty) {
+  RefCountedPtr<Foo> foo;
+  RefCountedPtr<Foo> foo2;
+  foo2 = foo;
+  EXPECT_EQ(nullptr, foo.get());
+  EXPECT_EQ(nullptr, foo2.get());
+}
+
+TEST(RefCountedPtr, CopyAssignmentToSelf) {
+  RefCountedPtr<Foo> foo(New<Foo>());
+  foo = foo;
+}
+
+TEST(RefCountedPtr, EnclosedScope) {
+  RefCountedPtr<Foo> foo(New<Foo>());
+  {
+    RefCountedPtr<Foo> foo2(std::move(foo));
+    EXPECT_EQ(nullptr, foo.get());
+    EXPECT_NE(nullptr, foo2.get());
+  }
+  EXPECT_EQ(nullptr, foo.get());
+}
+
+TEST(RefCountedPtr, ResetFromNullToNonNull) {
+  RefCountedPtr<Foo> foo;
+  EXPECT_EQ(nullptr, foo.get());
+  foo.reset(New<Foo>());
+  EXPECT_NE(nullptr, foo.get());
+}
+
+TEST(RefCountedPtr, ResetFromNonNullToNonNull) {
+  RefCountedPtr<Foo> foo(New<Foo>());
+  EXPECT_NE(nullptr, foo.get());
+  Foo* original = foo.get();
+  foo.reset(New<Foo>());
+  EXPECT_NE(nullptr, foo.get());
+  EXPECT_NE(original, foo.get());
+}
+
+TEST(RefCountedPtr, ResetFromNonNullToNull) {
+  RefCountedPtr<Foo> foo(New<Foo>());
+  EXPECT_NE(nullptr, foo.get());
+  foo.reset();
+  EXPECT_EQ(nullptr, foo.get());
+}
+
+TEST(RefCountedPtr, ResetFromNullToNull) {
+  RefCountedPtr<Foo> foo;
+  EXPECT_EQ(nullptr, foo.get());
+  foo.reset(nullptr);
+  EXPECT_EQ(nullptr, foo.get());
+}
+
+TEST(RefCountedPtr, DerefernceOperators) {
+  RefCountedPtr<Foo> foo(New<Foo>());
+  foo->value();
+  Foo& foo_ref = *foo;
+  foo_ref.value();
+}
+
+TEST(MakeRefCounted, NoArgs) {
+  RefCountedPtr<Foo> foo = MakeRefCounted<Foo>();
+  EXPECT_EQ(0, foo->value());
+}
+
+TEST(MakeRefCounted, Args) {
+  RefCountedPtr<Foo> foo = MakeRefCounted<Foo>(3);
+  EXPECT_EQ(3, foo->value());
+}
+
+TraceFlag foo_tracer(true, "foo");
+
+class FooWithTracing : public RefCountedWithTracing {
+ public:
+  FooWithTracing() : RefCountedWithTracing(&foo_tracer) {}
+};
+
+TEST(RefCountedPtr, RefCountedWithTracing) {
+  RefCountedPtr<FooWithTracing> foo(New<FooWithTracing>());
+  foo->Ref(DEBUG_LOCATION, "foo");
+  foo->Unref(DEBUG_LOCATION, "foo");
+}
+
+}  // namespace
+}  // namespace testing
+}  // namespace grpc_core
+
+int main(int argc, char** argv) {
+  grpc_test_init(argc, argv);
+  ::testing::InitGoogleTest(&argc, argv);
+  return RUN_ALL_TESTS();
+}
diff --git a/test/core/support/ref_counted_test.cc b/test/core/support/ref_counted_test.cc
new file mode 100644
index 0000000..be9b6ff
--- /dev/null
+++ b/test/core/support/ref_counted_test.cc
@@ -0,0 +1,72 @@
+/*
+ *
+ * Copyright 2017 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include "src/core/lib/support/ref_counted.h"
+
+#include <gtest/gtest.h>
+
+#include "src/core/lib/support/memory.h"
+#include "test/core/util/test_config.h"
+
+namespace grpc_core {
+namespace testing {
+namespace {
+
+class Foo : public RefCounted {
+ public:
+  Foo() {}
+};
+
+TEST(RefCounted, Basic) {
+  Foo* foo = New<Foo>();
+  foo->Unref();
+}
+
+TEST(RefCounted, ExtraRef) {
+  Foo* foo = New<Foo>();
+  foo->Ref();
+  foo->Unref();
+  foo->Unref();
+}
+
+TraceFlag foo_tracer(true, "foo");
+
+class FooWithTracing : public RefCountedWithTracing {
+ public:
+  FooWithTracing() : RefCountedWithTracing(&foo_tracer) {}
+};
+
+TEST(RefCountedWithTracing, Basic) {
+  FooWithTracing* foo = New<FooWithTracing>();
+  foo->Ref(DEBUG_LOCATION, "extra_ref");
+  foo->Unref(DEBUG_LOCATION, "extra_ref");
+  // Can use the no-argument methods, too.
+  foo->Ref();
+  foo->Unref();
+  foo->Unref(DEBUG_LOCATION, "original_ref");
+}
+
+}  // namespace
+}  // namespace testing
+}  // namespace grpc_core
+
+int main(int argc, char** argv) {
+  grpc_test_init(argc, argv);
+  ::testing::InitGoogleTest(&argc, argv);
+  return RUN_ALL_TESTS();
+}
diff --git a/test/core/support/stack_lockfree_test.cc b/test/core/support/stack_lockfree_test.cc
deleted file mode 100644
index e6d0c9b..0000000
--- a/test/core/support/stack_lockfree_test.cc
+++ /dev/null
@@ -1,140 +0,0 @@
-/*
- *
- * Copyright 2015 gRPC authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-#include "src/core/lib/support/stack_lockfree.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 "test/core/util/test_config.h"
-
-/* max stack size supported */
-#define MAX_STACK_SIZE 65534
-
-#define MAX_THREADS 32
-
-static void test_serial_sized(size_t size) {
-  gpr_stack_lockfree* stack = gpr_stack_lockfree_create(size);
-  size_t i;
-  size_t j;
-
-  /* First try popping empty */
-  GPR_ASSERT(gpr_stack_lockfree_pop(stack) == -1);
-
-  /* Now add one item and check it */
-  gpr_stack_lockfree_push(stack, 3);
-  GPR_ASSERT(gpr_stack_lockfree_pop(stack) == 3);
-  GPR_ASSERT(gpr_stack_lockfree_pop(stack) == -1);
-
-  /* Now add repeatedly more items and check them */
-  for (i = 1; i < size; i *= 2) {
-    for (j = 0; j <= i; j++) {
-      GPR_ASSERT(gpr_stack_lockfree_push(stack, (int)j) == (j == 0));
-    }
-    for (j = 0; j <= i; j++) {
-      GPR_ASSERT(gpr_stack_lockfree_pop(stack) == (int)(i - j));
-    }
-    GPR_ASSERT(gpr_stack_lockfree_pop(stack) == -1);
-  }
-
-  gpr_stack_lockfree_destroy(stack);
-}
-
-static void test_serial() {
-  size_t i;
-  for (i = 128; i < MAX_STACK_SIZE; i *= 2) {
-    test_serial_sized(i);
-  }
-  test_serial_sized(MAX_STACK_SIZE);
-}
-
-struct test_arg {
-  gpr_stack_lockfree* stack;
-  int stack_size;
-  int nthreads;
-  int rank;
-  int sum;
-};
-
-static void test_mt_body(void* v) {
-  struct test_arg* arg = (struct test_arg*)v;
-  int lo, hi;
-  int i;
-  int res;
-  lo = arg->rank * arg->stack_size / arg->nthreads;
-  hi = (arg->rank + 1) * arg->stack_size / arg->nthreads;
-  for (i = lo; i < hi; i++) {
-    gpr_stack_lockfree_push(arg->stack, i);
-    if ((res = gpr_stack_lockfree_pop(arg->stack)) != -1) {
-      arg->sum += res;
-    }
-  }
-  while ((res = gpr_stack_lockfree_pop(arg->stack)) != -1) {
-    arg->sum += res;
-  }
-}
-
-static void test_mt_sized(size_t size, int nth) {
-  gpr_stack_lockfree* stack;
-  struct test_arg args[MAX_THREADS];
-  gpr_thd_id thds[MAX_THREADS];
-  int sum;
-  int i;
-  gpr_thd_options options = gpr_thd_options_default();
-
-  stack = gpr_stack_lockfree_create(size);
-  for (i = 0; i < nth; i++) {
-    args[i].stack = stack;
-    args[i].stack_size = (int)size;
-    args[i].nthreads = nth;
-    args[i].rank = i;
-    args[i].sum = 0;
-  }
-  gpr_thd_options_set_joinable(&options);
-  for (i = 0; i < nth; i++) {
-    GPR_ASSERT(gpr_thd_new(&thds[i], test_mt_body, &args[i], &options));
-  }
-  sum = 0;
-  for (i = 0; i < nth; i++) {
-    gpr_thd_join(thds[i]);
-    sum = sum + args[i].sum;
-  }
-  GPR_ASSERT((unsigned)sum == ((unsigned)size * (size - 1)) / 2);
-  gpr_stack_lockfree_destroy(stack);
-}
-
-static void test_mt() {
-  size_t size;
-  int nth;
-  for (nth = 1; nth < MAX_THREADS; nth++) {
-    for (size = 128; size < MAX_STACK_SIZE; size *= 2) {
-      test_mt_sized(size, nth);
-    }
-    test_mt_sized(MAX_STACK_SIZE, nth);
-  }
-}
-
-int main(int argc, char** argv) {
-  grpc_test_init(argc, argv);
-  test_serial();
-  test_mt();
-  return 0;
-}
diff --git a/test/core/surface/concurrent_connectivity_test.cc b/test/core/surface/concurrent_connectivity_test.cc
index 8fa15ab..c7611b0 100644
--- a/test/core/surface/concurrent_connectivity_test.cc
+++ b/test/core/surface/concurrent_connectivity_test.cc
@@ -49,10 +49,11 @@
 #define NUM_OUTER_LOOPS_SHORT_TIMEOUTS 10
 #define NUM_INNER_LOOPS_SHORT_TIMEOUTS 100
 #define DELAY_MILLIS_SHORT_TIMEOUTS 1
-// in a successful test run, POLL_MILLIS should never be reached beause all runs
-// should
-// end after the shorter delay_millis
+// in a successful test run, POLL_MILLIS should never be reached because all
+// runs should end after the shorter delay_millis
 #define POLL_MILLIS_SHORT_TIMEOUTS 30000
+// it should never take longer that this to shutdown the server
+#define SERVER_SHUTDOWN_TIMEOUT 30000
 
 static void* tag(int n) { return (void*)(uintptr_t)n; }
 static int detag(void* p) { return (int)(uintptr_t)p; }
@@ -95,7 +96,8 @@
 void server_thread(void* vargs) {
   struct server_thread_args* args = (struct server_thread_args*)vargs;
   grpc_event ev;
-  gpr_timespec deadline = gpr_inf_future(GPR_CLOCK_MONOTONIC);
+  gpr_timespec deadline =
+      grpc_timeout_milliseconds_to_deadline(SERVER_SHUTDOWN_TIMEOUT);
   ev = grpc_completion_queue_next(args->cq, deadline, nullptr);
   GPR_ASSERT(ev.type == GRPC_OP_COMPLETE);
   GPR_ASSERT(detag(ev.tag) == 0xd1e);
diff --git a/test/core/surface/public_headers_must_be_c89.c b/test/core/surface/public_headers_must_be_c89.c
index db9f902..8d2384b 100644
--- a/test/core/surface/public_headers_must_be_c89.c
+++ b/test/core/surface/public_headers_must_be_c89.c
@@ -20,6 +20,7 @@
 #include <grpc/byte_buffer_reader.h>
 #include <grpc/census.h>
 #include <grpc/compression.h>
+#include <grpc/fork.h>
 #include <grpc/grpc.h>
 #include <grpc/grpc_security.h>
 #include <grpc/grpc_security_constants.h>
@@ -29,6 +30,7 @@
 #include <grpc/impl/codegen/compression_types.h>
 #include <grpc/impl/codegen/connectivity_state.h>
 #include <grpc/impl/codegen/exec_ctx_fwd.h>
+#include <grpc/impl/codegen/fork.h>
 #include <grpc/impl/codegen/gpr_slice.h>
 #include <grpc/impl/codegen/gpr_types.h>
 #include <grpc/impl/codegen/grpc_types.h>
@@ -48,7 +50,6 @@
 #include <grpc/support/avl.h>
 #include <grpc/support/cmdline.h>
 #include <grpc/support/cpu.h>
-#include <grpc/support/histogram.h>
 #include <grpc/support/host_port.h>
 #include <grpc/support/log.h>
 #include <grpc/support/port_platform.h>
@@ -66,288 +67,271 @@
 #include <stdio.h>
 
 int main(int argc, char **argv) {
-  if(argc == 12345678) {
-    printf("%lx", (unsigned long) grpc_compression_algorithm_parse);
-    printf("%lx", (unsigned long) grpc_compression_algorithm_name);
-    printf("%lx", (unsigned long) grpc_stream_compression_algorithm_name);
-    printf("%lx", (unsigned long) grpc_compression_algorithm_for_level);
-    printf("%lx", (unsigned long) grpc_stream_compression_algorithm_for_level);
-    printf("%lx", (unsigned long) grpc_compression_options_init);
-    printf("%lx", (unsigned long) grpc_compression_options_enable_algorithm);
-    printf("%lx", (unsigned long) grpc_compression_options_disable_algorithm);
-    printf("%lx", (unsigned long) grpc_compression_options_is_algorithm_enabled);
-    printf("%lx", (unsigned long) grpc_compression_options_is_stream_compression_algorithm_enabled);
-    printf("%lx", (unsigned long) grpc_metadata_array_init);
-    printf("%lx", (unsigned long) grpc_metadata_array_destroy);
-    printf("%lx", (unsigned long) grpc_call_details_init);
-    printf("%lx", (unsigned long) grpc_call_details_destroy);
-    printf("%lx", (unsigned long) grpc_register_plugin);
-    printf("%lx", (unsigned long) grpc_init);
-    printf("%lx", (unsigned long) grpc_shutdown);
-    printf("%lx", (unsigned long) grpc_version_string);
-    printf("%lx", (unsigned long) grpc_g_stands_for);
-    printf("%lx", (unsigned long) grpc_completion_queue_factory_lookup);
-    printf("%lx", (unsigned long) grpc_completion_queue_create_for_next);
-    printf("%lx", (unsigned long) grpc_completion_queue_create_for_pluck);
-    printf("%lx", (unsigned long) grpc_completion_queue_create);
-    printf("%lx", (unsigned long) grpc_completion_queue_next);
-    printf("%lx", (unsigned long) grpc_completion_queue_pluck);
-    printf("%lx", (unsigned long) grpc_completion_queue_shutdown);
-    printf("%lx", (unsigned long) grpc_completion_queue_destroy);
-    printf("%lx", (unsigned long) grpc_completion_queue_thread_local_cache_init);
-    printf("%lx", (unsigned long) grpc_completion_queue_thread_local_cache_flush);
-    printf("%lx", (unsigned long) grpc_alarm_create);
-    printf("%lx", (unsigned long) grpc_alarm_set);
-    printf("%lx", (unsigned long) grpc_alarm_cancel);
-    printf("%lx", (unsigned long) grpc_alarm_destroy);
-    printf("%lx", (unsigned long) grpc_channel_check_connectivity_state);
-    printf("%lx", (unsigned long) grpc_channel_num_external_connectivity_watchers);
-    printf("%lx", (unsigned long) grpc_channel_watch_connectivity_state);
-    printf("%lx", (unsigned long) grpc_channel_support_connectivity_watcher);
-    printf("%lx", (unsigned long) grpc_channel_create_call);
-    printf("%lx", (unsigned long) grpc_channel_ping);
-    printf("%lx", (unsigned long) grpc_channel_register_call);
-    printf("%lx", (unsigned long) grpc_channel_create_registered_call);
-    printf("%lx", (unsigned long) grpc_call_arena_alloc);
-    printf("%lx", (unsigned long) grpc_call_start_batch);
-    printf("%lx", (unsigned long) grpc_call_get_peer);
-    printf("%lx", (unsigned long) grpc_census_call_set_context);
-    printf("%lx", (unsigned long) grpc_census_call_get_context);
-    printf("%lx", (unsigned long) grpc_channel_get_target);
-    printf("%lx", (unsigned long) grpc_channel_get_info);
-    printf("%lx", (unsigned long) grpc_insecure_channel_create);
-    printf("%lx", (unsigned long) grpc_lame_client_channel_create);
-    printf("%lx", (unsigned long) grpc_channel_destroy);
-    printf("%lx", (unsigned long) grpc_call_cancel);
-    printf("%lx", (unsigned long) grpc_call_cancel_with_status);
-    printf("%lx", (unsigned long) grpc_call_ref);
-    printf("%lx", (unsigned long) grpc_call_unref);
-    printf("%lx", (unsigned long) grpc_server_request_call);
-    printf("%lx", (unsigned long) grpc_server_register_method);
-    printf("%lx", (unsigned long) grpc_server_request_registered_call);
-    printf("%lx", (unsigned long) grpc_server_create);
-    printf("%lx", (unsigned long) grpc_server_register_completion_queue);
-    printf("%lx", (unsigned long) grpc_server_add_insecure_http2_port);
-    printf("%lx", (unsigned long) grpc_server_start);
-    printf("%lx", (unsigned long) grpc_server_shutdown_and_notify);
-    printf("%lx", (unsigned long) grpc_server_cancel_all_calls);
-    printf("%lx", (unsigned long) grpc_server_destroy);
-    printf("%lx", (unsigned long) grpc_tracer_set_enabled);
-    printf("%lx", (unsigned long) grpc_header_key_is_legal);
-    printf("%lx", (unsigned long) grpc_header_nonbin_value_is_legal);
-    printf("%lx", (unsigned long) grpc_is_binary_header);
-    printf("%lx", (unsigned long) grpc_call_error_to_string);
-    printf("%lx", (unsigned long) grpc_resource_quota_create);
-    printf("%lx", (unsigned long) grpc_resource_quota_ref);
-    printf("%lx", (unsigned long) grpc_resource_quota_unref);
-    printf("%lx", (unsigned long) grpc_resource_quota_resize);
-    printf("%lx", (unsigned long) grpc_resource_quota_arg_vtable);
-    printf("%lx", (unsigned long) grpc_auth_property_iterator_next);
-    printf("%lx", (unsigned long) grpc_auth_context_property_iterator);
-    printf("%lx", (unsigned long) grpc_auth_context_peer_identity);
-    printf("%lx", (unsigned long) grpc_auth_context_find_properties_by_name);
-    printf("%lx", (unsigned long) grpc_auth_context_peer_identity_property_name);
-    printf("%lx", (unsigned long) grpc_auth_context_peer_is_authenticated);
-    printf("%lx", (unsigned long) grpc_call_auth_context);
-    printf("%lx", (unsigned long) grpc_auth_context_release);
-    printf("%lx", (unsigned long) grpc_auth_context_add_property);
-    printf("%lx", (unsigned long) grpc_auth_context_add_cstring_property);
-    printf("%lx", (unsigned long) grpc_auth_context_set_peer_identity_property_name);
-    printf("%lx", (unsigned long) grpc_channel_credentials_release);
-    printf("%lx", (unsigned long) grpc_google_default_credentials_create);
-    printf("%lx", (unsigned long) grpc_set_ssl_roots_override_callback);
-    printf("%lx", (unsigned long) grpc_ssl_credentials_create);
-    printf("%lx", (unsigned long) grpc_call_credentials_release);
-    printf("%lx", (unsigned long) grpc_composite_channel_credentials_create);
-    printf("%lx", (unsigned long) grpc_composite_call_credentials_create);
-    printf("%lx", (unsigned long) grpc_google_compute_engine_credentials_create);
-    printf("%lx", (unsigned long) grpc_max_auth_token_lifetime);
-    printf("%lx", (unsigned long) grpc_service_account_jwt_access_credentials_create);
-    printf("%lx", (unsigned long) grpc_google_refresh_token_credentials_create);
-    printf("%lx", (unsigned long) grpc_access_token_credentials_create);
-    printf("%lx", (unsigned long) grpc_google_iam_credentials_create);
-    printf("%lx", (unsigned long) grpc_metadata_credentials_create_from_plugin);
-    printf("%lx", (unsigned long) grpc_secure_channel_create);
-    printf("%lx", (unsigned long) grpc_server_credentials_release);
-    printf("%lx", (unsigned long) grpc_ssl_server_certificate_config_create);
-    printf("%lx", (unsigned long) grpc_ssl_server_certificate_config_destroy);
-    printf("%lx", (unsigned long) grpc_ssl_server_credentials_create);
-    printf("%lx", (unsigned long) grpc_ssl_server_credentials_create_ex);
-    printf("%lx", (unsigned long) grpc_ssl_server_credentials_create_options_using_config);
-    printf("%lx", (unsigned long) grpc_ssl_server_credentials_create_options_using_config_fetcher);
-    printf("%lx", (unsigned long) grpc_ssl_server_credentials_options_destroy);
-    printf("%lx", (unsigned long) grpc_ssl_server_credentials_create_with_options);
-    printf("%lx", (unsigned long) grpc_server_add_secure_http2_port);
-    printf("%lx", (unsigned long) grpc_call_set_credentials);
-    printf("%lx", (unsigned long) grpc_server_credentials_set_auth_metadata_processor);
-    printf("%lx", (unsigned long) grpc_raw_byte_buffer_create);
-    printf("%lx", (unsigned long) grpc_raw_compressed_byte_buffer_create);
-    printf("%lx", (unsigned long) grpc_byte_buffer_copy);
-    printf("%lx", (unsigned long) grpc_byte_buffer_length);
-    printf("%lx", (unsigned long) grpc_byte_buffer_destroy);
-    printf("%lx", (unsigned long) grpc_byte_buffer_reader_init);
-    printf("%lx", (unsigned long) grpc_byte_buffer_reader_destroy);
-    printf("%lx", (unsigned long) grpc_byte_buffer_reader_next);
-    printf("%lx", (unsigned long) grpc_byte_buffer_reader_readall);
-    printf("%lx", (unsigned long) grpc_raw_byte_buffer_from_reader);
-    printf("%lx", (unsigned long) grpc_slice_ref);
-    printf("%lx", (unsigned long) grpc_slice_unref);
-    printf("%lx", (unsigned long) grpc_slice_copy);
-    printf("%lx", (unsigned long) grpc_slice_new);
-    printf("%lx", (unsigned long) grpc_slice_new_with_user_data);
-    printf("%lx", (unsigned long) grpc_slice_new_with_len);
-    printf("%lx", (unsigned long) grpc_slice_malloc);
-    printf("%lx", (unsigned long) grpc_slice_malloc_large);
-    printf("%lx", (unsigned long) grpc_slice_intern);
-    printf("%lx", (unsigned long) grpc_slice_from_copied_string);
-    printf("%lx", (unsigned long) grpc_slice_from_copied_buffer);
-    printf("%lx", (unsigned long) grpc_slice_from_static_string);
-    printf("%lx", (unsigned long) grpc_slice_from_static_buffer);
-    printf("%lx", (unsigned long) grpc_slice_sub);
-    printf("%lx", (unsigned long) grpc_slice_sub_no_ref);
-    printf("%lx", (unsigned long) grpc_slice_split_tail);
-    printf("%lx", (unsigned long) grpc_slice_split_tail_maybe_ref);
-    printf("%lx", (unsigned long) grpc_slice_split_head);
-    printf("%lx", (unsigned long) grpc_empty_slice);
-    printf("%lx", (unsigned long) grpc_slice_default_hash_impl);
-    printf("%lx", (unsigned long) grpc_slice_default_eq_impl);
-    printf("%lx", (unsigned long) grpc_slice_eq);
-    printf("%lx", (unsigned long) grpc_slice_cmp);
-    printf("%lx", (unsigned long) grpc_slice_str_cmp);
-    printf("%lx", (unsigned long) grpc_slice_buf_start_eq);
-    printf("%lx", (unsigned long) grpc_slice_rchr);
-    printf("%lx", (unsigned long) grpc_slice_chr);
-    printf("%lx", (unsigned long) grpc_slice_slice);
-    printf("%lx", (unsigned long) grpc_slice_hash);
-    printf("%lx", (unsigned long) grpc_slice_is_equivalent);
-    printf("%lx", (unsigned long) grpc_slice_dup);
-    printf("%lx", (unsigned long) grpc_slice_to_c_string);
-    printf("%lx", (unsigned long) grpc_slice_buffer_init);
-    printf("%lx", (unsigned long) grpc_slice_buffer_destroy);
-    printf("%lx", (unsigned long) grpc_slice_buffer_add);
-    printf("%lx", (unsigned long) grpc_slice_buffer_add_indexed);
-    printf("%lx", (unsigned long) grpc_slice_buffer_addn);
-    printf("%lx", (unsigned long) grpc_slice_buffer_tiny_add);
-    printf("%lx", (unsigned long) grpc_slice_buffer_pop);
-    printf("%lx", (unsigned long) grpc_slice_buffer_reset_and_unref);
-    printf("%lx", (unsigned long) grpc_slice_buffer_swap);
-    printf("%lx", (unsigned long) grpc_slice_buffer_move_into);
-    printf("%lx", (unsigned long) grpc_slice_buffer_trim_end);
-    printf("%lx", (unsigned long) grpc_slice_buffer_move_first);
-    printf("%lx", (unsigned long) grpc_slice_buffer_move_first_no_ref);
-    printf("%lx", (unsigned long) grpc_slice_buffer_move_first_into_buffer);
-    printf("%lx", (unsigned long) grpc_slice_buffer_take_first);
-    printf("%lx", (unsigned long) grpc_slice_buffer_undo_take_first);
-    printf("%lx", (unsigned long) gpr_malloc);
-    printf("%lx", (unsigned long) gpr_zalloc);
-    printf("%lx", (unsigned long) gpr_free);
-    printf("%lx", (unsigned long) gpr_realloc);
-    printf("%lx", (unsigned long) gpr_malloc_aligned);
-    printf("%lx", (unsigned long) gpr_free_aligned);
-    printf("%lx", (unsigned long) gpr_set_allocation_functions);
-    printf("%lx", (unsigned long) gpr_get_allocation_functions);
-    printf("%lx", (unsigned long) gpr_avl_create);
-    printf("%lx", (unsigned long) gpr_avl_ref);
-    printf("%lx", (unsigned long) gpr_avl_unref);
-    printf("%lx", (unsigned long) gpr_avl_add);
-    printf("%lx", (unsigned long) gpr_avl_remove);
-    printf("%lx", (unsigned long) gpr_avl_get);
-    printf("%lx", (unsigned long) gpr_avl_maybe_get);
-    printf("%lx", (unsigned long) gpr_avl_is_empty);
-    printf("%lx", (unsigned long) gpr_cmdline_create);
-    printf("%lx", (unsigned long) gpr_cmdline_add_int);
-    printf("%lx", (unsigned long) gpr_cmdline_add_flag);
-    printf("%lx", (unsigned long) gpr_cmdline_add_string);
-    printf("%lx", (unsigned long) gpr_cmdline_on_extra_arg);
-    printf("%lx", (unsigned long) gpr_cmdline_set_survive_failure);
-    printf("%lx", (unsigned long) gpr_cmdline_parse);
-    printf("%lx", (unsigned long) gpr_cmdline_destroy);
-    printf("%lx", (unsigned long) gpr_cmdline_usage_string);
-    printf("%lx", (unsigned long) gpr_cpu_num_cores);
-    printf("%lx", (unsigned long) gpr_cpu_current_cpu);
-    printf("%lx", (unsigned long) gpr_histogram_create);
-    printf("%lx", (unsigned long) gpr_histogram_destroy);
-    printf("%lx", (unsigned long) gpr_histogram_add);
-    printf("%lx", (unsigned long) gpr_histogram_merge);
-    printf("%lx", (unsigned long) gpr_histogram_percentile);
-    printf("%lx", (unsigned long) gpr_histogram_mean);
-    printf("%lx", (unsigned long) gpr_histogram_stddev);
-    printf("%lx", (unsigned long) gpr_histogram_variance);
-    printf("%lx", (unsigned long) gpr_histogram_maximum);
-    printf("%lx", (unsigned long) gpr_histogram_minimum);
-    printf("%lx", (unsigned long) gpr_histogram_count);
-    printf("%lx", (unsigned long) gpr_histogram_sum);
-    printf("%lx", (unsigned long) gpr_histogram_sum_of_squares);
-    printf("%lx", (unsigned long) gpr_histogram_get_contents);
-    printf("%lx", (unsigned long) gpr_histogram_merge_contents);
-    printf("%lx", (unsigned long) gpr_join_host_port);
-    printf("%lx", (unsigned long) gpr_split_host_port);
-    printf("%lx", (unsigned long) gpr_log_severity_string);
-    printf("%lx", (unsigned long) gpr_log);
-    printf("%lx", (unsigned long) gpr_log_message);
-    printf("%lx", (unsigned long) gpr_set_log_verbosity);
-    printf("%lx", (unsigned long) gpr_log_verbosity_init);
-    printf("%lx", (unsigned long) gpr_set_log_function);
-    printf("%lx", (unsigned long) gpr_strdup);
-    printf("%lx", (unsigned long) gpr_asprintf);
-    printf("%lx", (unsigned long) gpr_subprocess_binary_extension);
-    printf("%lx", (unsigned long) gpr_subprocess_create);
-    printf("%lx", (unsigned long) gpr_subprocess_destroy);
-    printf("%lx", (unsigned long) gpr_subprocess_join);
-    printf("%lx", (unsigned long) gpr_subprocess_interrupt);
-    printf("%lx", (unsigned long) gpr_mu_init);
-    printf("%lx", (unsigned long) gpr_mu_destroy);
-    printf("%lx", (unsigned long) gpr_mu_lock);
-    printf("%lx", (unsigned long) gpr_mu_unlock);
-    printf("%lx", (unsigned long) gpr_mu_trylock);
-    printf("%lx", (unsigned long) gpr_cv_init);
-    printf("%lx", (unsigned long) gpr_cv_destroy);
-    printf("%lx", (unsigned long) gpr_cv_wait);
-    printf("%lx", (unsigned long) gpr_cv_signal);
-    printf("%lx", (unsigned long) gpr_cv_broadcast);
-    printf("%lx", (unsigned long) gpr_once_init);
-    printf("%lx", (unsigned long) gpr_event_init);
-    printf("%lx", (unsigned long) gpr_event_set);
-    printf("%lx", (unsigned long) gpr_event_get);
-    printf("%lx", (unsigned long) gpr_event_wait);
-    printf("%lx", (unsigned long) gpr_ref_init);
-    printf("%lx", (unsigned long) gpr_ref);
-    printf("%lx", (unsigned long) gpr_ref_non_zero);
-    printf("%lx", (unsigned long) gpr_refn);
-    printf("%lx", (unsigned long) gpr_unref);
-    printf("%lx", (unsigned long) gpr_ref_is_unique);
-    printf("%lx", (unsigned long) gpr_stats_init);
-    printf("%lx", (unsigned long) gpr_stats_inc);
-    printf("%lx", (unsigned long) gpr_stats_read);
-    printf("%lx", (unsigned long) gpr_thd_new);
-    printf("%lx", (unsigned long) gpr_thd_options_default);
-    printf("%lx", (unsigned long) gpr_thd_options_set_detached);
-    printf("%lx", (unsigned long) gpr_thd_options_set_joinable);
-    printf("%lx", (unsigned long) gpr_thd_options_is_detached);
-    printf("%lx", (unsigned long) gpr_thd_options_is_joinable);
-    printf("%lx", (unsigned long) gpr_thd_currentid);
-    printf("%lx", (unsigned long) gpr_thd_join);
-    printf("%lx", (unsigned long) gpr_time_0);
-    printf("%lx", (unsigned long) gpr_inf_future);
-    printf("%lx", (unsigned long) gpr_inf_past);
-    printf("%lx", (unsigned long) gpr_time_init);
-    printf("%lx", (unsigned long) gpr_now);
-    printf("%lx", (unsigned long) gpr_convert_clock_type);
-    printf("%lx", (unsigned long) gpr_time_cmp);
-    printf("%lx", (unsigned long) gpr_time_max);
-    printf("%lx", (unsigned long) gpr_time_min);
-    printf("%lx", (unsigned long) gpr_time_add);
-    printf("%lx", (unsigned long) gpr_time_sub);
-    printf("%lx", (unsigned long) gpr_time_from_micros);
-    printf("%lx", (unsigned long) gpr_time_from_nanos);
-    printf("%lx", (unsigned long) gpr_time_from_millis);
-    printf("%lx", (unsigned long) gpr_time_from_seconds);
-    printf("%lx", (unsigned long) gpr_time_from_minutes);
-    printf("%lx", (unsigned long) gpr_time_from_hours);
-    printf("%lx", (unsigned long) gpr_time_to_millis);
-    printf("%lx", (unsigned long) gpr_time_similar);
-    printf("%lx", (unsigned long) gpr_sleep_until);
-    printf("%lx", (unsigned long) gpr_timespec_to_micros);
-  }
+  printf("%lx", (unsigned long) grpc_compression_algorithm_parse);
+  printf("%lx", (unsigned long) grpc_compression_algorithm_name);
+  printf("%lx", (unsigned long) grpc_stream_compression_algorithm_name);
+  printf("%lx", (unsigned long) grpc_compression_algorithm_for_level);
+  printf("%lx", (unsigned long) grpc_stream_compression_algorithm_for_level);
+  printf("%lx", (unsigned long) grpc_compression_options_init);
+  printf("%lx", (unsigned long) grpc_compression_options_enable_algorithm);
+  printf("%lx", (unsigned long) grpc_compression_options_disable_algorithm);
+  printf("%lx", (unsigned long) grpc_compression_options_is_algorithm_enabled);
+  printf("%lx", (unsigned long) grpc_compression_options_is_stream_compression_algorithm_enabled);
+  printf("%lx", (unsigned long) grpc_metadata_array_init);
+  printf("%lx", (unsigned long) grpc_metadata_array_destroy);
+  printf("%lx", (unsigned long) grpc_call_details_init);
+  printf("%lx", (unsigned long) grpc_call_details_destroy);
+  printf("%lx", (unsigned long) grpc_register_plugin);
+  printf("%lx", (unsigned long) grpc_init);
+  printf("%lx", (unsigned long) grpc_shutdown);
+  printf("%lx", (unsigned long) grpc_version_string);
+  printf("%lx", (unsigned long) grpc_g_stands_for);
+  printf("%lx", (unsigned long) grpc_completion_queue_factory_lookup);
+  printf("%lx", (unsigned long) grpc_completion_queue_create_for_next);
+  printf("%lx", (unsigned long) grpc_completion_queue_create_for_pluck);
+  printf("%lx", (unsigned long) grpc_completion_queue_create);
+  printf("%lx", (unsigned long) grpc_completion_queue_next);
+  printf("%lx", (unsigned long) grpc_completion_queue_pluck);
+  printf("%lx", (unsigned long) grpc_completion_queue_shutdown);
+  printf("%lx", (unsigned long) grpc_completion_queue_destroy);
+  printf("%lx", (unsigned long) grpc_completion_queue_thread_local_cache_init);
+  printf("%lx", (unsigned long) grpc_completion_queue_thread_local_cache_flush);
+  printf("%lx", (unsigned long) grpc_alarm_create);
+  printf("%lx", (unsigned long) grpc_alarm_set);
+  printf("%lx", (unsigned long) grpc_alarm_cancel);
+  printf("%lx", (unsigned long) grpc_alarm_destroy);
+  printf("%lx", (unsigned long) grpc_channel_check_connectivity_state);
+  printf("%lx", (unsigned long) grpc_channel_num_external_connectivity_watchers);
+  printf("%lx", (unsigned long) grpc_channel_watch_connectivity_state);
+  printf("%lx", (unsigned long) grpc_channel_support_connectivity_watcher);
+  printf("%lx", (unsigned long) grpc_channel_create_call);
+  printf("%lx", (unsigned long) grpc_channel_ping);
+  printf("%lx", (unsigned long) grpc_channel_register_call);
+  printf("%lx", (unsigned long) grpc_channel_create_registered_call);
+  printf("%lx", (unsigned long) grpc_call_arena_alloc);
+  printf("%lx", (unsigned long) grpc_call_start_batch);
+  printf("%lx", (unsigned long) grpc_call_get_peer);
+  printf("%lx", (unsigned long) grpc_census_call_set_context);
+  printf("%lx", (unsigned long) grpc_census_call_get_context);
+  printf("%lx", (unsigned long) grpc_channel_get_target);
+  printf("%lx", (unsigned long) grpc_channel_get_info);
+  printf("%lx", (unsigned long) grpc_insecure_channel_create);
+  printf("%lx", (unsigned long) grpc_lame_client_channel_create);
+  printf("%lx", (unsigned long) grpc_channel_destroy);
+  printf("%lx", (unsigned long) grpc_call_cancel);
+  printf("%lx", (unsigned long) grpc_call_cancel_with_status);
+  printf("%lx", (unsigned long) grpc_call_ref);
+  printf("%lx", (unsigned long) grpc_call_unref);
+  printf("%lx", (unsigned long) grpc_server_request_call);
+  printf("%lx", (unsigned long) grpc_server_register_method);
+  printf("%lx", (unsigned long) grpc_server_request_registered_call);
+  printf("%lx", (unsigned long) grpc_server_create);
+  printf("%lx", (unsigned long) grpc_server_register_completion_queue);
+  printf("%lx", (unsigned long) grpc_server_add_insecure_http2_port);
+  printf("%lx", (unsigned long) grpc_server_start);
+  printf("%lx", (unsigned long) grpc_server_shutdown_and_notify);
+  printf("%lx", (unsigned long) grpc_server_cancel_all_calls);
+  printf("%lx", (unsigned long) grpc_server_destroy);
+  printf("%lx", (unsigned long) grpc_tracer_set_enabled);
+  printf("%lx", (unsigned long) grpc_header_key_is_legal);
+  printf("%lx", (unsigned long) grpc_header_nonbin_value_is_legal);
+  printf("%lx", (unsigned long) grpc_is_binary_header);
+  printf("%lx", (unsigned long) grpc_call_error_to_string);
+  printf("%lx", (unsigned long) grpc_resource_quota_create);
+  printf("%lx", (unsigned long) grpc_resource_quota_ref);
+  printf("%lx", (unsigned long) grpc_resource_quota_unref);
+  printf("%lx", (unsigned long) grpc_resource_quota_resize);
+  printf("%lx", (unsigned long) grpc_resource_quota_arg_vtable);
+  printf("%lx", (unsigned long) grpc_auth_property_iterator_next);
+  printf("%lx", (unsigned long) grpc_auth_context_property_iterator);
+  printf("%lx", (unsigned long) grpc_auth_context_peer_identity);
+  printf("%lx", (unsigned long) grpc_auth_context_find_properties_by_name);
+  printf("%lx", (unsigned long) grpc_auth_context_peer_identity_property_name);
+  printf("%lx", (unsigned long) grpc_auth_context_peer_is_authenticated);
+  printf("%lx", (unsigned long) grpc_call_auth_context);
+  printf("%lx", (unsigned long) grpc_auth_context_release);
+  printf("%lx", (unsigned long) grpc_auth_context_add_property);
+  printf("%lx", (unsigned long) grpc_auth_context_add_cstring_property);
+  printf("%lx", (unsigned long) grpc_auth_context_set_peer_identity_property_name);
+  printf("%lx", (unsigned long) grpc_channel_credentials_release);
+  printf("%lx", (unsigned long) grpc_google_default_credentials_create);
+  printf("%lx", (unsigned long) grpc_set_ssl_roots_override_callback);
+  printf("%lx", (unsigned long) grpc_ssl_credentials_create);
+  printf("%lx", (unsigned long) grpc_call_credentials_release);
+  printf("%lx", (unsigned long) grpc_composite_channel_credentials_create);
+  printf("%lx", (unsigned long) grpc_composite_call_credentials_create);
+  printf("%lx", (unsigned long) grpc_google_compute_engine_credentials_create);
+  printf("%lx", (unsigned long) grpc_max_auth_token_lifetime);
+  printf("%lx", (unsigned long) grpc_service_account_jwt_access_credentials_create);
+  printf("%lx", (unsigned long) grpc_google_refresh_token_credentials_create);
+  printf("%lx", (unsigned long) grpc_access_token_credentials_create);
+  printf("%lx", (unsigned long) grpc_google_iam_credentials_create);
+  printf("%lx", (unsigned long) grpc_metadata_credentials_create_from_plugin);
+  printf("%lx", (unsigned long) grpc_secure_channel_create);
+  printf("%lx", (unsigned long) grpc_server_credentials_release);
+  printf("%lx", (unsigned long) grpc_ssl_server_certificate_config_create);
+  printf("%lx", (unsigned long) grpc_ssl_server_certificate_config_destroy);
+  printf("%lx", (unsigned long) grpc_ssl_server_credentials_create);
+  printf("%lx", (unsigned long) grpc_ssl_server_credentials_create_ex);
+  printf("%lx", (unsigned long) grpc_ssl_server_credentials_create_options_using_config);
+  printf("%lx", (unsigned long) grpc_ssl_server_credentials_create_options_using_config_fetcher);
+  printf("%lx", (unsigned long) grpc_ssl_server_credentials_options_destroy);
+  printf("%lx", (unsigned long) grpc_ssl_server_credentials_create_with_options);
+  printf("%lx", (unsigned long) grpc_server_add_secure_http2_port);
+  printf("%lx", (unsigned long) grpc_call_set_credentials);
+  printf("%lx", (unsigned long) grpc_server_credentials_set_auth_metadata_processor);
+  printf("%lx", (unsigned long) grpc_raw_byte_buffer_create);
+  printf("%lx", (unsigned long) grpc_raw_compressed_byte_buffer_create);
+  printf("%lx", (unsigned long) grpc_byte_buffer_copy);
+  printf("%lx", (unsigned long) grpc_byte_buffer_length);
+  printf("%lx", (unsigned long) grpc_byte_buffer_destroy);
+  printf("%lx", (unsigned long) grpc_byte_buffer_reader_init);
+  printf("%lx", (unsigned long) grpc_byte_buffer_reader_destroy);
+  printf("%lx", (unsigned long) grpc_byte_buffer_reader_next);
+  printf("%lx", (unsigned long) grpc_byte_buffer_reader_readall);
+  printf("%lx", (unsigned long) grpc_raw_byte_buffer_from_reader);
+  printf("%lx", (unsigned long) grpc_slice_ref);
+  printf("%lx", (unsigned long) grpc_slice_unref);
+  printf("%lx", (unsigned long) grpc_slice_copy);
+  printf("%lx", (unsigned long) grpc_slice_new);
+  printf("%lx", (unsigned long) grpc_slice_new_with_user_data);
+  printf("%lx", (unsigned long) grpc_slice_new_with_len);
+  printf("%lx", (unsigned long) grpc_slice_malloc);
+  printf("%lx", (unsigned long) grpc_slice_malloc_large);
+  printf("%lx", (unsigned long) grpc_slice_intern);
+  printf("%lx", (unsigned long) grpc_slice_from_copied_string);
+  printf("%lx", (unsigned long) grpc_slice_from_copied_buffer);
+  printf("%lx", (unsigned long) grpc_slice_from_static_string);
+  printf("%lx", (unsigned long) grpc_slice_from_static_buffer);
+  printf("%lx", (unsigned long) grpc_slice_sub);
+  printf("%lx", (unsigned long) grpc_slice_sub_no_ref);
+  printf("%lx", (unsigned long) grpc_slice_split_tail);
+  printf("%lx", (unsigned long) grpc_slice_split_tail_maybe_ref);
+  printf("%lx", (unsigned long) grpc_slice_split_head);
+  printf("%lx", (unsigned long) grpc_empty_slice);
+  printf("%lx", (unsigned long) grpc_slice_default_hash_impl);
+  printf("%lx", (unsigned long) grpc_slice_default_eq_impl);
+  printf("%lx", (unsigned long) grpc_slice_eq);
+  printf("%lx", (unsigned long) grpc_slice_cmp);
+  printf("%lx", (unsigned long) grpc_slice_str_cmp);
+  printf("%lx", (unsigned long) grpc_slice_buf_start_eq);
+  printf("%lx", (unsigned long) grpc_slice_rchr);
+  printf("%lx", (unsigned long) grpc_slice_chr);
+  printf("%lx", (unsigned long) grpc_slice_slice);
+  printf("%lx", (unsigned long) grpc_slice_hash);
+  printf("%lx", (unsigned long) grpc_slice_is_equivalent);
+  printf("%lx", (unsigned long) grpc_slice_dup);
+  printf("%lx", (unsigned long) grpc_slice_to_c_string);
+  printf("%lx", (unsigned long) grpc_slice_buffer_init);
+  printf("%lx", (unsigned long) grpc_slice_buffer_destroy);
+  printf("%lx", (unsigned long) grpc_slice_buffer_add);
+  printf("%lx", (unsigned long) grpc_slice_buffer_add_indexed);
+  printf("%lx", (unsigned long) grpc_slice_buffer_addn);
+  printf("%lx", (unsigned long) grpc_slice_buffer_tiny_add);
+  printf("%lx", (unsigned long) grpc_slice_buffer_pop);
+  printf("%lx", (unsigned long) grpc_slice_buffer_reset_and_unref);
+  printf("%lx", (unsigned long) grpc_slice_buffer_swap);
+  printf("%lx", (unsigned long) grpc_slice_buffer_move_into);
+  printf("%lx", (unsigned long) grpc_slice_buffer_trim_end);
+  printf("%lx", (unsigned long) grpc_slice_buffer_move_first);
+  printf("%lx", (unsigned long) grpc_slice_buffer_move_first_no_ref);
+  printf("%lx", (unsigned long) grpc_slice_buffer_move_first_into_buffer);
+  printf("%lx", (unsigned long) grpc_slice_buffer_take_first);
+  printf("%lx", (unsigned long) grpc_slice_buffer_undo_take_first);
+  printf("%lx", (unsigned long) gpr_malloc);
+  printf("%lx", (unsigned long) gpr_zalloc);
+  printf("%lx", (unsigned long) gpr_free);
+  printf("%lx", (unsigned long) gpr_realloc);
+  printf("%lx", (unsigned long) gpr_malloc_aligned);
+  printf("%lx", (unsigned long) gpr_free_aligned);
+  printf("%lx", (unsigned long) gpr_set_allocation_functions);
+  printf("%lx", (unsigned long) gpr_get_allocation_functions);
+  printf("%lx", (unsigned long) gpr_avl_create);
+  printf("%lx", (unsigned long) gpr_avl_ref);
+  printf("%lx", (unsigned long) gpr_avl_unref);
+  printf("%lx", (unsigned long) gpr_avl_add);
+  printf("%lx", (unsigned long) gpr_avl_remove);
+  printf("%lx", (unsigned long) gpr_avl_get);
+  printf("%lx", (unsigned long) gpr_avl_maybe_get);
+  printf("%lx", (unsigned long) gpr_avl_is_empty);
+  printf("%lx", (unsigned long) gpr_cmdline_create);
+  printf("%lx", (unsigned long) gpr_cmdline_add_int);
+  printf("%lx", (unsigned long) gpr_cmdline_add_flag);
+  printf("%lx", (unsigned long) gpr_cmdline_add_string);
+  printf("%lx", (unsigned long) gpr_cmdline_on_extra_arg);
+  printf("%lx", (unsigned long) gpr_cmdline_set_survive_failure);
+  printf("%lx", (unsigned long) gpr_cmdline_parse);
+  printf("%lx", (unsigned long) gpr_cmdline_destroy);
+  printf("%lx", (unsigned long) gpr_cmdline_usage_string);
+  printf("%lx", (unsigned long) gpr_cpu_num_cores);
+  printf("%lx", (unsigned long) gpr_cpu_current_cpu);
+  printf("%lx", (unsigned long) gpr_join_host_port);
+  printf("%lx", (unsigned long) gpr_split_host_port);
+  printf("%lx", (unsigned long) gpr_log_severity_string);
+  printf("%lx", (unsigned long) gpr_log);
+  printf("%lx", (unsigned long) gpr_log_message);
+  printf("%lx", (unsigned long) gpr_set_log_verbosity);
+  printf("%lx", (unsigned long) gpr_log_verbosity_init);
+  printf("%lx", (unsigned long) gpr_set_log_function);
+  printf("%lx", (unsigned long) gpr_strdup);
+  printf("%lx", (unsigned long) gpr_asprintf);
+  printf("%lx", (unsigned long) gpr_subprocess_binary_extension);
+  printf("%lx", (unsigned long) gpr_subprocess_create);
+  printf("%lx", (unsigned long) gpr_subprocess_destroy);
+  printf("%lx", (unsigned long) gpr_subprocess_join);
+  printf("%lx", (unsigned long) gpr_subprocess_interrupt);
+  printf("%lx", (unsigned long) gpr_mu_init);
+  printf("%lx", (unsigned long) gpr_mu_destroy);
+  printf("%lx", (unsigned long) gpr_mu_lock);
+  printf("%lx", (unsigned long) gpr_mu_unlock);
+  printf("%lx", (unsigned long) gpr_mu_trylock);
+  printf("%lx", (unsigned long) gpr_cv_init);
+  printf("%lx", (unsigned long) gpr_cv_destroy);
+  printf("%lx", (unsigned long) gpr_cv_wait);
+  printf("%lx", (unsigned long) gpr_cv_signal);
+  printf("%lx", (unsigned long) gpr_cv_broadcast);
+  printf("%lx", (unsigned long) gpr_once_init);
+  printf("%lx", (unsigned long) gpr_event_init);
+  printf("%lx", (unsigned long) gpr_event_set);
+  printf("%lx", (unsigned long) gpr_event_get);
+  printf("%lx", (unsigned long) gpr_event_wait);
+  printf("%lx", (unsigned long) gpr_ref_init);
+  printf("%lx", (unsigned long) gpr_ref);
+  printf("%lx", (unsigned long) gpr_ref_non_zero);
+  printf("%lx", (unsigned long) gpr_refn);
+  printf("%lx", (unsigned long) gpr_unref);
+  printf("%lx", (unsigned long) gpr_ref_is_unique);
+  printf("%lx", (unsigned long) gpr_stats_init);
+  printf("%lx", (unsigned long) gpr_stats_inc);
+  printf("%lx", (unsigned long) gpr_stats_read);
+  printf("%lx", (unsigned long) gpr_thd_new);
+  printf("%lx", (unsigned long) gpr_thd_options_default);
+  printf("%lx", (unsigned long) gpr_thd_options_set_detached);
+  printf("%lx", (unsigned long) gpr_thd_options_set_joinable);
+  printf("%lx", (unsigned long) gpr_thd_options_is_detached);
+  printf("%lx", (unsigned long) gpr_thd_options_is_joinable);
+  printf("%lx", (unsigned long) gpr_thd_currentid);
+  printf("%lx", (unsigned long) gpr_thd_join);
+  printf("%lx", (unsigned long) gpr_time_0);
+  printf("%lx", (unsigned long) gpr_inf_future);
+  printf("%lx", (unsigned long) gpr_inf_past);
+  printf("%lx", (unsigned long) gpr_time_init);
+  printf("%lx", (unsigned long) gpr_now);
+  printf("%lx", (unsigned long) gpr_convert_clock_type);
+  printf("%lx", (unsigned long) gpr_time_cmp);
+  printf("%lx", (unsigned long) gpr_time_max);
+  printf("%lx", (unsigned long) gpr_time_min);
+  printf("%lx", (unsigned long) gpr_time_add);
+  printf("%lx", (unsigned long) gpr_time_sub);
+  printf("%lx", (unsigned long) gpr_time_from_micros);
+  printf("%lx", (unsigned long) gpr_time_from_nanos);
+  printf("%lx", (unsigned long) gpr_time_from_millis);
+  printf("%lx", (unsigned long) gpr_time_from_seconds);
+  printf("%lx", (unsigned long) gpr_time_from_minutes);
+  printf("%lx", (unsigned long) gpr_time_from_hours);
+  printf("%lx", (unsigned long) gpr_time_to_millis);
+  printf("%lx", (unsigned long) gpr_time_similar);
+  printf("%lx", (unsigned long) gpr_sleep_until);
+  printf("%lx", (unsigned long) gpr_timespec_to_micros);
   return 0;
 }
diff --git a/test/core/transport/bdp_estimator_test.cc b/test/core/transport/bdp_estimator_test.cc
index 2a6fa95..d127260 100644
--- a/test/core/transport/bdp_estimator_test.cc
+++ b/test/core/transport/bdp_estimator_test.cc
@@ -29,7 +29,7 @@
 #include "src/core/lib/support/string.h"
 #include "test/core/util/test_config.h"
 
-extern "C" gpr_timespec (*gpr_now_impl)(gpr_clock_type clock_type);
+extern gpr_timespec (*gpr_now_impl)(gpr_clock_type clock_type);
 
 namespace grpc_core {
 namespace testing {
diff --git a/test/core/transport/connectivity_state_test.cc b/test/core/transport/connectivity_state_test.cc
index 7a22ec8..11046e1 100644
--- a/test/core/transport/connectivity_state_test.cc
+++ b/test/core/transport/connectivity_state_test.cc
@@ -23,6 +23,7 @@
 #include <grpc/support/log.h>
 
 #include "test/core/util/test_config.h"
+#include "test/core/util/tracer_util.h"
 
 #define THE_ARG ((void*)(size_t)0xcafebabe)
 
@@ -136,7 +137,7 @@
 
 int main(int argc, char** argv) {
   grpc_test_init(argc, argv);
-  grpc_connectivity_state_trace.value = 1;
+  grpc_core::testing::grpc_tracer_enable_flag(&grpc_connectivity_state_trace);
   test_connectivity_state_name();
   test_check();
   test_subscribe_then_unsubscribe();
diff --git a/test/core/util/BUILD b/test/core/util/BUILD
index 2437923..2237cfc 100644
--- a/test/core/util/BUILD
+++ b/test/core/util/BUILD
@@ -16,7 +16,10 @@
 
 licenses(["notice"])  # Apache v2
 
-grpc_package(name = "test/core/util", visibility = "public")
+grpc_package(
+    name = "test/core/util",
+    visibility = "public",
+)
 
 grpc_cc_library(
     name = "gpr_test_util",
@@ -49,18 +52,22 @@
     name = "grpc_test_util_base",
     srcs = [
         "grpc_profiler.cc",
+        "histogram.cc",
         "mock_endpoint.cc",
         "parse_hexstring.cc",
         "passthru_endpoint.cc",
         "port.cc",
+        "port_isolated_runtime_environment.cc",
         "port_server_client.cc",
         "reconnect_server.cc",
         "slice_splitter.cc",
         "test_tcp_server.cc",
+        "tracer_util.cc",
         "trickle_endpoint.cc",
     ],
     hdrs = [
         "grpc_profiler.h",
+        "histogram.h",
         "mock_endpoint.h",
         "parse_hexstring.h",
         "passthru_endpoint.h",
@@ -69,13 +76,14 @@
         "reconnect_server.h",
         "slice_splitter.h",
         "test_tcp_server.h",
+        "tracer_util.h",
         "trickle_endpoint.h",
     ],
     language = "C++",
     deps = [
         ":gpr_test_util",
+        ":grpc_debugger_macros",
         "//:grpc_common",
-        ":grpc_debugger_macros"
     ],
 )
 
@@ -105,13 +113,23 @@
     name = "fuzzer_corpus_test",
     testonly = 1,
     srcs = ["fuzzer_corpus_test.cc"],
+    external_deps = [
+        "gtest",
+        "gflags",
+    ],
     deps = [
         ":gpr_test_util",
         "//:grpc",
     ],
-    external_deps = [
-        "gtest",
-        "gflags",
+)
+
+grpc_cc_test(
+    name = "histogram_test",
+    srcs = ["histogram_test.cc"],
+    language = "C++",
+    deps = [
+        ":grpc_test_util",
+        "//:gpr",
     ],
 )
 
@@ -119,3 +137,8 @@
     name = "fuzzer_one_entry_runner",
     srcs = ["fuzzer_one_entry_runner.sh"],
 )
+
+sh_library(
+    name = "run_with_poller_sh",
+    srcs = ["run_with_poller.sh"],
+)
diff --git a/test/core/util/fuzzer_corpus_test.cc b/test/core/util/fuzzer_corpus_test.cc
index d7aea54..7849321 100644
--- a/test/core/util/fuzzer_corpus_test.cc
+++ b/test/core/util/fuzzer_corpus_test.cc
@@ -29,8 +29,8 @@
 #include "test/core/util/test_config.h"
 
 extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size);
-extern "C" bool squelch;
-extern "C" bool leak_check;
+extern bool squelch;
+extern bool leak_check;
 
 // In some distros, gflags is in the namespace google, and in some others,
 // in gflags. This hack is enabling us to find both.
diff --git a/test/core/util/grpc_fuzzer.bzl b/test/core/util/grpc_fuzzer.bzl
index 55b6f1c..b8b270e 100644
--- a/test/core/util/grpc_fuzzer.bzl
+++ b/test/core/util/grpc_fuzzer.bzl
@@ -19,8 +19,7 @@
     name = name,
     srcs = srcs,
     deps = deps + ["//test/core/util:fuzzer_corpus_test"],
-    data = [corpus],
-    args = ['--directory', '$(location %s)' % corpus],
+    data = native.glob([corpus + "/**"]),
     external_deps = [
       'gtest',
     ],
diff --git a/src/core/lib/support/histogram.cc b/test/core/util/histogram.cc
similarity index 72%
rename from src/core/lib/support/histogram.cc
rename to test/core/util/histogram.cc
index 73c821a..2f916f8 100644
--- a/src/core/lib/support/histogram.cc
+++ b/test/core/util/histogram.cc
@@ -16,8 +16,6 @@
  *
  */
 
-#include <grpc/support/histogram.h>
-
 #include <math.h>
 #include <stddef.h>
 #include <string.h>
@@ -27,12 +25,14 @@
 #include <grpc/support/port_platform.h>
 #include <grpc/support/useful.h>
 
+#include "test/core/util/histogram.h"
+
 /* Histograms are stored with exponentially increasing bucket sizes.
    The first bucket is [0, m) where m = 1 + resolution
    Bucket n (n>=1) contains [m**n, m**(n+1))
    There are sufficient buckets to reach max_bucket_start */
 
-struct gpr_histogram {
+struct grpc_histogram {
   /* Sum of all values seen so far */
   double sum;
   /* Sum of squares of all values seen so far */
@@ -55,25 +55,25 @@
 };
 
 /* determine a bucket index given a value - does no bounds checking */
-static size_t bucket_for_unchecked(gpr_histogram* h, double x) {
+static size_t bucket_for_unchecked(grpc_histogram* h, double x) {
   return (size_t)(log(x) * h->one_on_log_multiplier);
 }
 
 /* bounds checked version of the above */
-static size_t bucket_for(gpr_histogram* h, double x) {
+static size_t bucket_for(grpc_histogram* h, double x) {
   size_t bucket = bucket_for_unchecked(h, GPR_CLAMP(x, 1.0, h->max_possible));
   GPR_ASSERT(bucket < h->num_buckets);
   return bucket;
 }
 
 /* at what value does a bucket start? */
-static double bucket_start(gpr_histogram* h, double x) {
+static double bucket_start(grpc_histogram* h, double x) {
   return pow(h->multiplier, x);
 }
 
-gpr_histogram* gpr_histogram_create(double resolution,
-                                    double max_bucket_start) {
-  gpr_histogram* h = (gpr_histogram*)gpr_malloc(sizeof(gpr_histogram));
+grpc_histogram* grpc_histogram_create(double resolution,
+                                      double max_bucket_start) {
+  grpc_histogram* h = (grpc_histogram*)gpr_malloc(sizeof(grpc_histogram));
   GPR_ASSERT(resolution > 0.0);
   GPR_ASSERT(max_bucket_start > resolution);
   h->sum = 0.0;
@@ -91,12 +91,12 @@
   return h;
 }
 
-void gpr_histogram_destroy(gpr_histogram* h) {
+void grpc_histogram_destroy(grpc_histogram* h) {
   gpr_free(h->buckets);
   gpr_free(h);
 }
 
-void gpr_histogram_add(gpr_histogram* h, double x) {
+void grpc_histogram_add(grpc_histogram* h, double x) {
   h->sum += x;
   h->sum_of_squares += x * x;
   h->count++;
@@ -109,22 +109,22 @@
   h->buckets[bucket_for(h, x)]++;
 }
 
-int gpr_histogram_merge(gpr_histogram* dst, const gpr_histogram* src) {
+int grpc_histogram_merge(grpc_histogram* dst, const grpc_histogram* src) {
   if ((dst->num_buckets != src->num_buckets) ||
       (dst->multiplier != src->multiplier)) {
     /* Fail because these histograms don't match */
     return 0;
   }
-  gpr_histogram_merge_contents(dst, src->buckets, src->num_buckets,
-                               src->min_seen, src->max_seen, src->sum,
-                               src->sum_of_squares, src->count);
+  grpc_histogram_merge_contents(dst, src->buckets, src->num_buckets,
+                                src->min_seen, src->max_seen, src->sum,
+                                src->sum_of_squares, src->count);
   return 1;
 }
 
-void gpr_histogram_merge_contents(gpr_histogram* dst, const uint32_t* data,
-                                  size_t data_count, double min_seen,
-                                  double max_seen, double sum,
-                                  double sum_of_squares, double count) {
+void grpc_histogram_merge_contents(grpc_histogram* dst, const uint32_t* data,
+                                   size_t data_count, double min_seen,
+                                   double max_seen, double sum,
+                                   double sum_of_squares, double count) {
   size_t i;
   GPR_ASSERT(dst->num_buckets == data_count);
   dst->sum += sum;
@@ -141,7 +141,7 @@
   }
 }
 
-static double threshold_for_count_below(gpr_histogram* h, double count_below) {
+static double threshold_for_count_below(grpc_histogram* h, double count_below) {
   double count_so_far;
   double lower_bound;
   double upper_bound;
@@ -190,38 +190,38 @@
   }
 }
 
-double gpr_histogram_percentile(gpr_histogram* h, double percentile) {
+double grpc_histogram_percentile(grpc_histogram* h, double percentile) {
   return threshold_for_count_below(h, h->count * percentile / 100.0);
 }
 
-double gpr_histogram_mean(gpr_histogram* h) {
+double grpc_histogram_mean(grpc_histogram* h) {
   GPR_ASSERT(h->count != 0);
   return h->sum / h->count;
 }
 
-double gpr_histogram_stddev(gpr_histogram* h) {
-  return sqrt(gpr_histogram_variance(h));
+double grpc_histogram_stddev(grpc_histogram* h) {
+  return sqrt(grpc_histogram_variance(h));
 }
 
-double gpr_histogram_variance(gpr_histogram* h) {
+double grpc_histogram_variance(grpc_histogram* h) {
   if (h->count == 0) return 0.0;
   return (h->sum_of_squares * h->count - h->sum * h->sum) /
          (h->count * h->count);
 }
 
-double gpr_histogram_maximum(gpr_histogram* h) { return h->max_seen; }
+double grpc_histogram_maximum(grpc_histogram* h) { return h->max_seen; }
 
-double gpr_histogram_minimum(gpr_histogram* h) { return h->min_seen; }
+double grpc_histogram_minimum(grpc_histogram* h) { return h->min_seen; }
 
-double gpr_histogram_count(gpr_histogram* h) { return h->count; }
+double grpc_histogram_count(grpc_histogram* h) { return h->count; }
 
-double gpr_histogram_sum(gpr_histogram* h) { return h->sum; }
+double grpc_histogram_sum(grpc_histogram* h) { return h->sum; }
 
-double gpr_histogram_sum_of_squares(gpr_histogram* h) {
+double grpc_histogram_sum_of_squares(grpc_histogram* h) {
   return h->sum_of_squares;
 }
 
-const uint32_t* gpr_histogram_get_contents(gpr_histogram* h, size_t* size) {
+const uint32_t* grpc_histogram_get_contents(grpc_histogram* h, size_t* size) {
   *size = h->num_buckets;
   return h->buckets;
 }
diff --git a/test/core/util/histogram.h b/test/core/util/histogram.h
new file mode 100644
index 0000000..9d4985e
--- /dev/null
+++ b/test/core/util/histogram.h
@@ -0,0 +1,62 @@
+/*
+ *
+ * Copyright 2015 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#ifndef GRPC_SUPPORT_HISTOGRAM_H
+#define GRPC_SUPPORT_HISTOGRAM_H
+
+#include <grpc/support/port_platform.h>
+#include <stddef.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct grpc_histogram grpc_histogram;
+
+grpc_histogram* grpc_histogram_create(double resolution,
+                                      double max_bucket_start);
+void grpc_histogram_destroy(grpc_histogram* h);
+void grpc_histogram_add(grpc_histogram* h, double x);
+
+/** The following merges the second histogram into the first. It only works
+   if they have the same buckets and resolution. Returns 0 on failure, 1
+   on success */
+int grpc_histogram_merge(grpc_histogram* dst, const grpc_histogram* src);
+
+double grpc_histogram_percentile(grpc_histogram* histogram, double percentile);
+double grpc_histogram_mean(grpc_histogram* histogram);
+double grpc_histogram_stddev(grpc_histogram* histogram);
+double grpc_histogram_variance(grpc_histogram* histogram);
+double grpc_histogram_maximum(grpc_histogram* histogram);
+double grpc_histogram_minimum(grpc_histogram* histogram);
+double grpc_histogram_count(grpc_histogram* histogram);
+double grpc_histogram_sum(grpc_histogram* histogram);
+double grpc_histogram_sum_of_squares(grpc_histogram* histogram);
+
+const uint32_t* grpc_histogram_get_contents(grpc_histogram* histogram,
+                                            size_t* count);
+void grpc_histogram_merge_contents(grpc_histogram* histogram,
+                                   const uint32_t* data, size_t data_count,
+                                   double min_seen, double max_seen, double sum,
+                                   double sum_of_squares, double count);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* GRPC_SUPPORT_HISTOGRAM_H */
diff --git a/test/core/util/histogram_test.cc b/test/core/util/histogram_test.cc
new file mode 100644
index 0000000..b96ac7d
--- /dev/null
+++ b/test/core/util/histogram_test.cc
@@ -0,0 +1,163 @@
+/*
+ *
+ * Copyright 2015 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include "test/core/util/histogram.h"
+#include <grpc/support/log.h>
+
+#define LOG_TEST(x) gpr_log(GPR_INFO, "%s", x);
+
+static void test_no_op(void) {
+  grpc_histogram_destroy(grpc_histogram_create(0.01, 60e9));
+}
+
+static void expect_percentile(grpc_histogram* h, double percentile,
+                              double min_expect, double max_expect) {
+  double got = grpc_histogram_percentile(h, percentile);
+  gpr_log(GPR_INFO, "@%f%%, expect %f <= %f <= %f", percentile, min_expect, got,
+          max_expect);
+  GPR_ASSERT(min_expect <= got);
+  GPR_ASSERT(got <= max_expect);
+}
+
+static void test_simple(void) {
+  grpc_histogram* h;
+
+  LOG_TEST("test_simple");
+
+  h = grpc_histogram_create(0.01, 60e9);
+  grpc_histogram_add(h, 10000);
+  grpc_histogram_add(h, 10000);
+  grpc_histogram_add(h, 11000);
+  grpc_histogram_add(h, 11000);
+
+  expect_percentile(h, 50, 10001, 10999);
+  GPR_ASSERT(grpc_histogram_mean(h) == 10500);
+
+  grpc_histogram_destroy(h);
+}
+
+static void test_percentile(void) {
+  grpc_histogram* h;
+  double last;
+  double i;
+  double cur;
+
+  LOG_TEST("test_percentile");
+
+  h = grpc_histogram_create(0.05, 1e9);
+  grpc_histogram_add(h, 2.5);
+  grpc_histogram_add(h, 2.5);
+  grpc_histogram_add(h, 8);
+  grpc_histogram_add(h, 4);
+
+  GPR_ASSERT(grpc_histogram_count(h) == 4);
+  GPR_ASSERT(grpc_histogram_minimum(h) == 2.5);
+  GPR_ASSERT(grpc_histogram_maximum(h) == 8);
+  GPR_ASSERT(grpc_histogram_sum(h) == 17);
+  GPR_ASSERT(grpc_histogram_sum_of_squares(h) == 92.5);
+  GPR_ASSERT(grpc_histogram_mean(h) == 4.25);
+  GPR_ASSERT(grpc_histogram_variance(h) == 5.0625);
+  GPR_ASSERT(grpc_histogram_stddev(h) == 2.25);
+
+  expect_percentile(h, -10, 2.5, 2.5);
+  expect_percentile(h, 0, 2.5, 2.5);
+  expect_percentile(h, 12.5, 2.5, 2.5);
+  expect_percentile(h, 25, 2.5, 2.5);
+  expect_percentile(h, 37.5, 2.5, 2.8);
+  expect_percentile(h, 50, 3.0, 3.5);
+  expect_percentile(h, 62.5, 3.5, 4.5);
+  expect_percentile(h, 75, 5, 7.9);
+  expect_percentile(h, 100, 8, 8);
+  expect_percentile(h, 110, 8, 8);
+
+  /* test monotonicity */
+  last = 0.0;
+  for (i = 0; i < 100.0; i += 0.01) {
+    cur = grpc_histogram_percentile(h, i);
+    GPR_ASSERT(cur >= last);
+    last = cur;
+  }
+
+  grpc_histogram_destroy(h);
+}
+
+static void test_merge(void) {
+  grpc_histogram *h1, *h2;
+  double last;
+  double i;
+  double cur;
+
+  LOG_TEST("test_merge");
+
+  h1 = grpc_histogram_create(0.05, 1e9);
+  grpc_histogram_add(h1, 2.5);
+  grpc_histogram_add(h1, 2.5);
+  grpc_histogram_add(h1, 8);
+  grpc_histogram_add(h1, 4);
+
+  h2 = grpc_histogram_create(0.01, 1e9);
+  GPR_ASSERT(grpc_histogram_merge(h1, h2) == 0);
+  grpc_histogram_destroy(h2);
+
+  h2 = grpc_histogram_create(0.05, 1e10);
+  GPR_ASSERT(grpc_histogram_merge(h1, h2) == 0);
+  grpc_histogram_destroy(h2);
+
+  h2 = grpc_histogram_create(0.05, 1e9);
+  GPR_ASSERT(grpc_histogram_merge(h1, h2) == 1);
+  GPR_ASSERT(grpc_histogram_count(h1) == 4);
+  GPR_ASSERT(grpc_histogram_minimum(h1) == 2.5);
+  GPR_ASSERT(grpc_histogram_maximum(h1) == 8);
+  GPR_ASSERT(grpc_histogram_sum(h1) == 17);
+  GPR_ASSERT(grpc_histogram_sum_of_squares(h1) == 92.5);
+  GPR_ASSERT(grpc_histogram_mean(h1) == 4.25);
+  GPR_ASSERT(grpc_histogram_variance(h1) == 5.0625);
+  GPR_ASSERT(grpc_histogram_stddev(h1) == 2.25);
+  grpc_histogram_destroy(h2);
+
+  h2 = grpc_histogram_create(0.05, 1e9);
+  grpc_histogram_add(h2, 7.0);
+  grpc_histogram_add(h2, 17.0);
+  grpc_histogram_add(h2, 1.0);
+  GPR_ASSERT(grpc_histogram_merge(h1, h2) == 1);
+  GPR_ASSERT(grpc_histogram_count(h1) == 7);
+  GPR_ASSERT(grpc_histogram_minimum(h1) == 1.0);
+  GPR_ASSERT(grpc_histogram_maximum(h1) == 17.0);
+  GPR_ASSERT(grpc_histogram_sum(h1) == 42.0);
+  GPR_ASSERT(grpc_histogram_sum_of_squares(h1) == 431.5);
+  GPR_ASSERT(grpc_histogram_mean(h1) == 6.0);
+
+  /* test monotonicity */
+  last = 0.0;
+  for (i = 0; i < 100.0; i += 0.01) {
+    cur = grpc_histogram_percentile(h1, i);
+    GPR_ASSERT(cur >= last);
+    last = cur;
+  }
+
+  grpc_histogram_destroy(h1);
+  grpc_histogram_destroy(h2);
+}
+
+int main(void) {
+  test_no_op();
+  test_simple();
+  test_percentile();
+  test_merge();
+  return 0;
+}
diff --git a/test/core/util/port.h b/test/core/util/port.h
index 602099d..3a4cf44 100644
--- a/test/core/util/port.h
+++ b/test/core/util/port.h
@@ -19,10 +19,6 @@
 #ifndef GRPC_TEST_CORE_UTIL_PORT_H
 #define GRPC_TEST_CORE_UTIL_PORT_H
 
-#ifdef __cplusplus
-extern "C" {
-#endif
-
 typedef struct grpc_pick_port_functions {
   int (*pick_unused_port_fn)(void);
   int (*pick_unused_port_or_die_fn)(void);
@@ -45,8 +41,4 @@
 /** Request the family of pick_port functions in \a functions be used. */
 void grpc_set_pick_port_functions(grpc_pick_port_functions functions);
 
-#ifdef __cplusplus
-}
-#endif
-
 #endif /* GRPC_TEST_CORE_UTIL_PORT_H */
diff --git a/test/core/util/port_isolated_runtime_environment.cc b/test/core/util/port_isolated_runtime_environment.cc
new file mode 100644
index 0000000..5f0585e
--- /dev/null
+++ b/test/core/util/port_isolated_runtime_environment.cc
@@ -0,0 +1,42 @@
+/*
+ *
+ * Copyright 2017 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+/* When running tests on remote machines, the framework takes a round-robin pick
+ * of a port within certain range. There is no need to recycle ports.
+ */
+#include "src/core/lib/iomgr/port.h"
+#include "test/core/util/test_config.h"
+#if defined(GRPC_PORT_ISOLATED_RUNTIME)
+
+#include "test/core/util/port.h"
+
+#define LOWER_PORT 49152
+static int s_allocated_port = LOWER_PORT;
+
+int grpc_pick_unused_port_or_die(void) {
+  int allocated_port = s_allocated_port++;
+  if (s_allocated_port == 65536) {
+    s_allocated_port = LOWER_PORT;
+  }
+
+  return allocated_port;
+}
+
+void grpc_recycle_unused_port(int port) { (void)port; }
+
+#endif /* GRPC_PORT_ISOLATED_RUNTIME */
diff --git a/test/core/util/run_with_poller.sh b/test/core/util/run_with_poller.sh
new file mode 100755
index 0000000..0579145
--- /dev/null
+++ b/test/core/util/run_with_poller.sh
@@ -0,0 +1,19 @@
+#!/bin/sh
+# Copyright 2017 gRPC authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+set -ex
+export GRPC_POLL_STRATEGY=$1
+shift
+$@
diff --git a/test/core/util/test_config.h b/test/core/util/test_config.h
index 4383fbf..5b3d347 100644
--- a/test/core/util/test_config.h
+++ b/test/core/util/test_config.h
@@ -21,10 +21,6 @@
 
 #include <grpc/support/time.h>
 
-#ifdef __cplusplus
-extern "C" {
-#endif
-
 extern int64_t g_fixture_slowdown_factor;
 extern int64_t g_poller_slowdown_factor;
 
@@ -37,14 +33,10 @@
 /* Converts a given timeout (in milliseconds) to a deadline. */
 gpr_timespec grpc_timeout_milliseconds_to_deadline(int64_t time_ms);
 
-#ifndef GRPC_TEST_CUSTOM_PICK_PORT
+#if !defined(GRPC_TEST_CUSTOM_PICK_PORT) && !defined(GRPC_PORT_ISOLATED_RUNTIME)
 #define GRPC_TEST_PICK_PORT
 #endif
 
 void grpc_test_init(int argc, char** argv);
 
-#ifdef __cplusplus
-}
-#endif
-
 #endif /* GRPC_TEST_CORE_UTIL_TEST_CONFIG_H */
diff --git a/test/core/util/tracer_util.cc b/test/core/util/tracer_util.cc
new file mode 100644
index 0000000..34a132d
--- /dev/null
+++ b/test/core/util/tracer_util.cc
@@ -0,0 +1,31 @@
+/*
+ *
+ * Copyright 2015 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include "test/core/util/test_config.h"
+
+#include "src/core/lib/debug/trace.h"
+
+namespace grpc_core {
+namespace testing {
+
+void grpc_tracer_enable_flag(grpc_core::TraceFlag* flag) {
+  flag->set_enabled(1);
+}
+
+}  // namespace testing
+}  // namespace grpc_core
diff --git a/test/core/util/tracer_util.h b/test/core/util/tracer_util.h
new file mode 100644
index 0000000..0b432ff
--- /dev/null
+++ b/test/core/util/tracer_util.h
@@ -0,0 +1,32 @@
+/*
+ *
+ * Copyright 2015 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#ifndef GRPC_TEST_CORE_UTIL_TRACER_UTIL_H
+#define GRPC_TEST_CORE_UTIL_TRACER_UTIL_H
+
+namespace grpc_core {
+class TraceFlag;
+
+namespace testing {
+// enables the TraceFlag passed to it. Used for testing purposes.
+void grpc_tracer_enable_flag(grpc_core::TraceFlag* flag);
+
+}  // namespace testing
+}  // namespace grpc_core
+
+#endif /* GRPC_TEST_CORE_UTIL_TRACER_UTIL_H */
diff --git a/test/cpp/client/client_channel_stress_test.cc b/test/cpp/client/client_channel_stress_test.cc
index 8940f6f..0954b28 100644
--- a/test/cpp/client/client_channel_stress_test.cc
+++ b/test/cpp/client/client_channel_stress_test.cc
@@ -34,10 +34,8 @@
 #include <grpc/support/thd.h>
 #include <grpc/support/time.h>
 
-extern "C" {
 #include "src/core/ext/filters/client_channel/resolver/fake/fake_resolver.h"
 #include "src/core/lib/iomgr/sockaddr.h"
-}
 
 #include "test/core/util/port.h"
 #include "test/core/util/test_config.h"
diff --git a/test/cpp/interop/interop_server.cc b/test/cpp/interop/interop_server.cc
index a24cdc7..30bd8bf 100644
--- a/test/cpp/interop/interop_server.cc
+++ b/test/cpp/interop/interop_server.cc
@@ -317,9 +317,15 @@
 
 void grpc::testing::interop::RunServer(
     std::shared_ptr<ServerCredentials> creds) {
-  GPR_ASSERT(FLAGS_port != 0);
+  RunServer(creds, FLAGS_port, nullptr);
+}
+
+void grpc::testing::interop::RunServer(
+    std::shared_ptr<ServerCredentials> creds, const int port,
+    ServerStartedCondition* server_started_condition) {
+  GPR_ASSERT(port != 0);
   std::ostringstream server_address;
-  server_address << "0.0.0.0:" << FLAGS_port;
+  server_address << "0.0.0.0:" << port;
   TestServiceImpl service;
 
   SimpleRequest request;
@@ -333,6 +339,14 @@
   }
   std::unique_ptr<Server> server(builder.BuildAndStart());
   gpr_log(GPR_INFO, "Server listening on %s", server_address.str().c_str());
+
+  // Signal that the server has started.
+  if (server_started_condition) {
+    std::unique_lock<std::mutex> lock(server_started_condition->mutex);
+    server_started_condition->server_started = true;
+    server_started_condition->condition.notify_all();
+  }
+
   while (!gpr_atm_no_barrier_load(&g_got_sigint)) {
     gpr_sleep_until(gpr_time_add(gpr_now(GPR_CLOCK_REALTIME),
                                  gpr_time_from_seconds(5, GPR_TIMESPAN)));
diff --git a/test/cpp/interop/server_helper.h b/test/cpp/interop/server_helper.h
index 6af003f..1bf7db1 100644
--- a/test/cpp/interop/server_helper.h
+++ b/test/cpp/interop/server_helper.h
@@ -19,6 +19,7 @@
 #ifndef GRPC_TEST_CPP_INTEROP_SERVER_HELPER_H
 #define GRPC_TEST_CPP_INTEROP_SERVER_HELPER_H
 
+#include <condition_variable>
 #include <memory>
 
 #include <grpc/compression.h>
@@ -50,8 +51,27 @@
 namespace interop {
 
 extern gpr_atm g_got_sigint;
+
+struct ServerStartedCondition {
+  std::mutex mutex;
+  std::condition_variable condition;
+  bool server_started = false;
+};
+
+/// Run gRPC interop server using port FLAGS_port.
+///
+/// \param creds The credentials associated with the server.
 void RunServer(std::shared_ptr<ServerCredentials> creds);
 
+/// Run gRPC interop server.
+///
+/// \param creds The credentials associated with the server.
+/// \param port Port to use for the server.
+/// \param server_started_condition (optional) Struct holding mutex, condition
+///     variable, and condition used to notify when the server has started.
+void RunServer(std::shared_ptr<ServerCredentials> creds, int port,
+               ServerStartedCondition* server_started_condition);
+
 }  // namespace interop
 }  // namespace testing
 }  // namespace grpc
diff --git a/test/cpp/interop/stress_test.cc b/test/cpp/interop/stress_test.cc
index 028ff11..4b39dc3 100644
--- a/test/cpp/interop/stress_test.cc
+++ b/test/cpp/interop/stress_test.cc
@@ -36,9 +36,7 @@
 #include "test/cpp/util/metrics_server.h"
 #include "test/cpp/util/test_config.h"
 
-extern "C" {
 extern void gpr_default_log(gpr_log_func_args* args);
-}
 
 DEFINE_int32(metrics_port, 8081, "The metrics server port.");
 
diff --git a/test/cpp/microbenchmarks/bm_error.cc b/test/cpp/microbenchmarks/bm_error.cc
index 02a93e9..bbd8b3c 100644
--- a/test/cpp/microbenchmarks/bm_error.cc
+++ b/test/cpp/microbenchmarks/bm_error.cc
@@ -251,7 +251,7 @@
     grpc_status_code status;
     grpc_slice slice;
     grpc_error_get_status(&exec_ctx, fixture.error(), fixture.deadline(),
-                          &status, &slice, nullptr);
+                          &status, &slice, nullptr, nullptr);
   }
   grpc_exec_ctx_finish(&exec_ctx);
   track_counters.Finish(state);
@@ -265,7 +265,7 @@
   while (state.KeepRunning()) {
     grpc_status_code status;
     grpc_error_get_status(&exec_ctx, fixture.error(), fixture.deadline(),
-                          &status, nullptr, nullptr);
+                          &status, nullptr, nullptr, nullptr);
   }
   grpc_exec_ctx_finish(&exec_ctx);
   track_counters.Finish(state);
@@ -279,7 +279,7 @@
   while (state.KeepRunning()) {
     grpc_http2_error_code error;
     grpc_error_get_status(&exec_ctx, fixture.error(), fixture.deadline(),
-                          nullptr, nullptr, &error);
+                          nullptr, nullptr, &error, nullptr);
   }
   grpc_exec_ctx_finish(&exec_ctx);
   track_counters.Finish(state);
diff --git a/test/cpp/microbenchmarks/bm_fullstack_trickle.cc b/test/cpp/microbenchmarks/bm_fullstack_trickle.cc
index bb974fa..5e72213 100644
--- a/test/cpp/microbenchmarks/bm_fullstack_trickle.cc
+++ b/test/cpp/microbenchmarks/bm_fullstack_trickle.cc
@@ -445,7 +445,7 @@
 }  // namespace testing
 }  // namespace grpc
 
-extern "C" gpr_timespec (*gpr_now_impl)(gpr_clock_type clock_type);
+extern gpr_timespec (*gpr_now_impl)(gpr_clock_type clock_type);
 
 int main(int argc, char** argv) {
   ::benchmark::Initialize(&argc, argv);
diff --git a/test/cpp/microbenchmarks/helpers.h b/test/cpp/microbenchmarks/helpers.h
index 07be589..afa3e0f 100644
--- a/test/cpp/microbenchmarks/helpers.h
+++ b/test/cpp/microbenchmarks/helpers.h
@@ -54,10 +54,10 @@
 };
 
 #ifdef GPR_LOW_LEVEL_COUNTERS
-extern "C" gpr_atm gpr_mu_locks;
-extern "C" gpr_atm gpr_counter_atm_cas;
-extern "C" gpr_atm gpr_counter_atm_add;
-extern "C" gpr_atm gpr_now_call_count;
+extern gpr_atm gpr_mu_locks;
+extern gpr_atm gpr_counter_atm_cas;
+extern gpr_atm gpr_counter_atm_add;
+extern gpr_atm gpr_now_call_count;
 #endif
 
 class TrackCounters {
diff --git a/test/cpp/qps/BUILD b/test/cpp/qps/BUILD
index 0d91d52..f1abb19 100644
--- a/test/cpp/qps/BUILD
+++ b/test/cpp/qps/BUILD
@@ -106,7 +106,7 @@
         "histogram.h",
         "stats.h",
     ],
-    deps = ["//:gpr"],
+    deps = ["//test/core/util:grpc_test_util"],
 )
 
 grpc_cc_test(
diff --git a/test/cpp/qps/client_async.cc b/test/cpp/qps/client_async.cc
index f7cdfc2..0788821 100644
--- a/test/cpp/qps/client_async.cc
+++ b/test/cpp/qps/client_async.cc
@@ -236,6 +236,22 @@
     this->EndThreads();  // this needed for resolution
   }
 
+  ClientRpcContext* ProcessTag(size_t thread_idx, void* tag) {
+    ClientRpcContext* ctx = ClientRpcContext::detag(tag);
+    if (shutdown_state_[thread_idx]->shutdown) {
+      ctx->TryCancel();
+      delete ctx;
+      bool ok;
+      while (cli_cqs_[cq_[thread_idx]]->Next(&tag, &ok)) {
+        ctx = ClientRpcContext::detag(tag);
+        ctx->TryCancel();
+        delete ctx;
+      }
+      return nullptr;
+    }
+    return ctx;
+  }
+
   void ThreadFunc(size_t thread_idx, Client::Thread* t) override final {
     void* got_tag;
     bool ok;
@@ -245,9 +261,13 @@
     if (!cli_cqs_[cq_[thread_idx]]->Next(&got_tag, &ok)) {
       return;
     }
-    ClientRpcContext* ctx = ClientRpcContext::detag(got_tag);
     std::mutex* shutdown_mu = &shutdown_state_[thread_idx]->mutex;
     shutdown_mu->lock();
+    ClientRpcContext* ctx = ProcessTag(thread_idx, got_tag);
+    if (ctx == nullptr) {
+      shutdown_mu->unlock();
+      return;
+    }
     while (cli_cqs_[cq_[thread_idx]]->DoThenAsyncNext(
         [&, ctx, ok, entry_ptr, shutdown_mu]() {
           if (!ctx->RunNextState(ok, entry_ptr)) {
@@ -260,19 +280,9 @@
         },
         &got_tag, &ok, gpr_inf_future(GPR_CLOCK_REALTIME))) {
       t->UpdateHistogram(entry_ptr);
-      // Got a regular event, so process it
-      ctx = ClientRpcContext::detag(got_tag);
-      // Proceed while holding a lock to make sure that
-      // this thread isn't supposed to shut down
       shutdown_mu->lock();
-      if (shutdown_state_[thread_idx]->shutdown) {
-        ctx->TryCancel();
-        delete ctx;
-        while (cli_cqs_[cq_[thread_idx]]->Next(&got_tag, &ok)) {
-          ctx = ClientRpcContext::detag(got_tag);
-          ctx->TryCancel();
-          delete ctx;
-        }
+      ctx = ProcessTag(thread_idx, got_tag);
+      if (ctx == nullptr) {
         shutdown_mu->unlock();
         return;
       }
diff --git a/test/cpp/qps/client_sync.cc b/test/cpp/qps/client_sync.cc
index 9f20b14..82a3f00 100644
--- a/test/cpp/qps/client_sync.cc
+++ b/test/cpp/qps/client_sync.cc
@@ -60,21 +60,20 @@
     SetupLoadTest(config, num_threads_);
   }
 
-  virtual ~SynchronousClient(){};
+  virtual ~SynchronousClient() {}
 
-  virtual void InitThreadFuncImpl(size_t thread_idx) = 0;
+  virtual bool InitThreadFuncImpl(size_t thread_idx) = 0;
   virtual bool ThreadFuncImpl(HistogramEntry* entry, size_t thread_idx) = 0;
 
   void ThreadFunc(size_t thread_idx, Thread* t) override {
-    InitThreadFuncImpl(thread_idx);
+    if (!InitThreadFuncImpl(thread_idx)) {
+      return;
+    }
     for (;;) {
       // run the loop body
       HistogramEntry entry;
       const bool thread_still_ok = ThreadFuncImpl(&entry, thread_idx);
       t->UpdateHistogram(&entry);
-      if (!thread_still_ok) {
-        gpr_log(GPR_ERROR, "Finishing client thread due to RPC error");
-      }
       if (!thread_still_ok || ThreadCompleted()) {
         return;
       }
@@ -109,9 +108,6 @@
 
   size_t num_threads_;
   std::vector<SimpleResponse> responses_;
-
- private:
-  void DestroyMultithreading() override final { EndThreads(); }
 };
 
 class SynchronousUnaryClient final : public SynchronousClient {
@@ -122,7 +118,7 @@
   }
   ~SynchronousUnaryClient() {}
 
-  void InitThreadFuncImpl(size_t thread_idx) override {}
+  bool InitThreadFuncImpl(size_t thread_idx) override { return true; }
 
   bool ThreadFuncImpl(HistogramEntry* entry, size_t thread_idx) override {
     if (!WaitToIssue(thread_idx)) {
@@ -140,6 +136,9 @@
     entry->set_status(s.error_code());
     return true;
   }
+
+ private:
+  void DestroyMultithreading() override final { EndThreads(); }
 };
 
 template <class StreamType>
@@ -149,31 +148,30 @@
       : SynchronousClient(config),
         context_(num_threads_),
         stream_(num_threads_),
+        stream_mu_(num_threads_),
+        shutdown_(num_threads_),
         messages_per_stream_(config.messages_per_stream()),
         messages_issued_(num_threads_) {
     StartThreads(num_threads_);
   }
   virtual ~SynchronousStreamingClient() {
-    std::vector<std::thread> cleanup_threads;
-    for (size_t i = 0; i < num_threads_; i++) {
-      cleanup_threads.emplace_back([this, i]() {
-        auto stream = &stream_[i];
-        if (*stream) {
-          // forcibly cancel the streams, then finish
-          context_[i].TryCancel();
-          (*stream)->Finish().IgnoreError();
-          // don't log any error message on !ok since this was canceled
-        }
-      });
-    }
-    for (auto& th : cleanup_threads) {
-      th.join();
-    }
+    CleanupAllStreams([this](size_t thread_idx) {
+      // Don't log any kind of error since we may have canceled this
+      stream_[thread_idx]->Finish().IgnoreError();
+    });
   }
 
  protected:
   std::vector<grpc::ClientContext> context_;
   std::vector<std::unique_ptr<StreamType>> stream_;
+  // stream_mu_ is only needed when changing an element of stream_ or context_
+  std::vector<std::mutex> stream_mu_;
+  // use struct Bool rather than bool because vector<bool> is not concurrent
+  struct Bool {
+    bool val;
+    Bool() : val(false) {}
+  };
+  std::vector<Bool> shutdown_;
   const int messages_per_stream_;
   std::vector<int> messages_issued_;
 
@@ -182,12 +180,40 @@
     // don't set the value since the stream is failed and shouldn't be timed
     entry->set_status(s.error_code());
     if (!s.ok()) {
-      gpr_log(GPR_ERROR, "Stream %" PRIuPTR " received an error %s", thread_idx,
-              s.error_message().c_str());
+      std::lock_guard<std::mutex> l(stream_mu_[thread_idx]);
+      if (!shutdown_[thread_idx].val) {
+        gpr_log(GPR_ERROR, "Stream %" PRIuPTR " received an error %s",
+                thread_idx, s.error_message().c_str());
+      }
     }
+    // Lock the stream_mu_ now because the client context could change
+    std::lock_guard<std::mutex> l(stream_mu_[thread_idx]);
     context_[thread_idx].~ClientContext();
     new (&context_[thread_idx]) ClientContext();
   }
+
+  void CleanupAllStreams(std::function<void(size_t)> cleaner) {
+    std::vector<std::thread> cleanup_threads;
+    for (size_t i = 0; i < num_threads_; i++) {
+      cleanup_threads.emplace_back([this, i, cleaner] {
+        std::lock_guard<std::mutex> l(stream_mu_[i]);
+        shutdown_[i].val = true;
+        if (stream_[i]) {
+          cleaner(i);
+        }
+      });
+    }
+    for (auto& th : cleanup_threads) {
+      th.join();
+    }
+  }
+
+ private:
+  void DestroyMultithreading() override final {
+    CleanupAllStreams(
+        [this](size_t thread_idx) { context_[thread_idx].TryCancel(); });
+    EndThreads();
+  }
 };
 
 class SynchronousStreamingPingPongClient final
@@ -197,24 +223,21 @@
   SynchronousStreamingPingPongClient(const ClientConfig& config)
       : SynchronousStreamingClient(config) {}
   ~SynchronousStreamingPingPongClient() {
-    std::vector<std::thread> cleanup_threads;
-    for (size_t i = 0; i < num_threads_; i++) {
-      cleanup_threads.emplace_back([this, i]() {
-        auto stream = &stream_[i];
-        if (*stream) {
-          (*stream)->WritesDone();
-        }
-      });
-    }
-    for (auto& th : cleanup_threads) {
-      th.join();
-    }
+    CleanupAllStreams(
+        [this](size_t thread_idx) { stream_[thread_idx]->WritesDone(); });
   }
 
-  void InitThreadFuncImpl(size_t thread_idx) override {
+ private:
+  bool InitThreadFuncImpl(size_t thread_idx) override {
     auto* stub = channels_[thread_idx % channels_.size()].get_stub();
-    stream_[thread_idx] = stub->StreamingCall(&context_[thread_idx]);
+    std::lock_guard<std::mutex> l(stream_mu_[thread_idx]);
+    if (!shutdown_[thread_idx].val) {
+      stream_[thread_idx] = stub->StreamingCall(&context_[thread_idx]);
+    } else {
+      return false;
+    }
     messages_issued_[thread_idx] = 0;
+    return true;
   }
 
   bool ThreadFuncImpl(HistogramEntry* entry, size_t thread_idx) override {
@@ -239,7 +262,13 @@
     stream_[thread_idx]->WritesDone();
     FinishStream(entry, thread_idx);
     auto* stub = channels_[thread_idx % channels_.size()].get_stub();
-    stream_[thread_idx] = stub->StreamingCall(&context_[thread_idx]);
+    std::lock_guard<std::mutex> l(stream_mu_[thread_idx]);
+    if (!shutdown_[thread_idx].val) {
+      stream_[thread_idx] = stub->StreamingCall(&context_[thread_idx]);
+    } else {
+      stream_[thread_idx].reset();
+      return false;
+    }
     messages_issued_[thread_idx] = 0;
     return true;
   }
@@ -251,25 +280,24 @@
   SynchronousStreamingFromClientClient(const ClientConfig& config)
       : SynchronousStreamingClient(config), last_issue_(num_threads_) {}
   ~SynchronousStreamingFromClientClient() {
-    std::vector<std::thread> cleanup_threads;
-    for (size_t i = 0; i < num_threads_; i++) {
-      cleanup_threads.emplace_back([this, i]() {
-        auto stream = &stream_[i];
-        if (*stream) {
-          (*stream)->WritesDone();
-        }
-      });
-    }
-    for (auto& th : cleanup_threads) {
-      th.join();
-    }
+    CleanupAllStreams(
+        [this](size_t thread_idx) { stream_[thread_idx]->WritesDone(); });
   }
 
-  void InitThreadFuncImpl(size_t thread_idx) override {
+ private:
+  std::vector<double> last_issue_;
+
+  bool InitThreadFuncImpl(size_t thread_idx) override {
     auto* stub = channels_[thread_idx % channels_.size()].get_stub();
-    stream_[thread_idx] = stub->StreamingFromClient(&context_[thread_idx],
-                                                    &responses_[thread_idx]);
+    std::lock_guard<std::mutex> l(stream_mu_[thread_idx]);
+    if (!shutdown_[thread_idx].val) {
+      stream_[thread_idx] = stub->StreamingFromClient(&context_[thread_idx],
+                                                      &responses_[thread_idx]);
+    } else {
+      return false;
+    }
     last_issue_[thread_idx] = UsageTimer::Now();
+    return true;
   }
 
   bool ThreadFuncImpl(HistogramEntry* entry, size_t thread_idx) override {
@@ -287,13 +315,16 @@
     stream_[thread_idx]->WritesDone();
     FinishStream(entry, thread_idx);
     auto* stub = channels_[thread_idx % channels_.size()].get_stub();
-    stream_[thread_idx] = stub->StreamingFromClient(&context_[thread_idx],
-                                                    &responses_[thread_idx]);
+    std::lock_guard<std::mutex> l(stream_mu_[thread_idx]);
+    if (!shutdown_[thread_idx].val) {
+      stream_[thread_idx] = stub->StreamingFromClient(&context_[thread_idx],
+                                                      &responses_[thread_idx]);
+    } else {
+      stream_[thread_idx].reset();
+      return false;
+    }
     return true;
   }
-
- private:
-  std::vector<double> last_issue_;
 };
 
 class SynchronousStreamingFromServerClient final
@@ -301,12 +332,24 @@
  public:
   SynchronousStreamingFromServerClient(const ClientConfig& config)
       : SynchronousStreamingClient(config), last_recv_(num_threads_) {}
-  void InitThreadFuncImpl(size_t thread_idx) override {
+  ~SynchronousStreamingFromServerClient() {}
+
+ private:
+  std::vector<double> last_recv_;
+
+  bool InitThreadFuncImpl(size_t thread_idx) override {
     auto* stub = channels_[thread_idx % channels_.size()].get_stub();
-    stream_[thread_idx] =
-        stub->StreamingFromServer(&context_[thread_idx], request_);
+    std::lock_guard<std::mutex> l(stream_mu_[thread_idx]);
+    if (!shutdown_[thread_idx].val) {
+      stream_[thread_idx] =
+          stub->StreamingFromServer(&context_[thread_idx], request_);
+    } else {
+      return false;
+    }
     last_recv_[thread_idx] = UsageTimer::Now();
+    return true;
   }
+
   bool ThreadFuncImpl(HistogramEntry* entry, size_t thread_idx) override {
     GPR_TIMER_SCOPE("SynchronousStreamingFromServerClient::ThreadFunc", 0);
     if (stream_[thread_idx]->Read(&responses_[thread_idx])) {
@@ -317,13 +360,16 @@
     }
     FinishStream(entry, thread_idx);
     auto* stub = channels_[thread_idx % channels_.size()].get_stub();
-    stream_[thread_idx] =
-        stub->StreamingFromServer(&context_[thread_idx], request_);
+    std::lock_guard<std::mutex> l(stream_mu_[thread_idx]);
+    if (!shutdown_[thread_idx].val) {
+      stream_[thread_idx] =
+          stub->StreamingFromServer(&context_[thread_idx], request_);
+    } else {
+      stream_[thread_idx].reset();
+      return false;
+    }
     return true;
   }
-
- private:
-  std::vector<double> last_recv_;
 };
 
 class SynchronousStreamingBothWaysClient final
@@ -333,24 +379,22 @@
   SynchronousStreamingBothWaysClient(const ClientConfig& config)
       : SynchronousStreamingClient(config) {}
   ~SynchronousStreamingBothWaysClient() {
-    std::vector<std::thread> cleanup_threads;
-    for (size_t i = 0; i < num_threads_; i++) {
-      cleanup_threads.emplace_back([this, i]() {
-        auto stream = &stream_[i];
-        if (*stream) {
-          (*stream)->WritesDone();
-        }
-      });
-    }
-    for (auto& th : cleanup_threads) {
-      th.join();
-    }
+    CleanupAllStreams(
+        [this](size_t thread_idx) { stream_[thread_idx]->WritesDone(); });
   }
 
-  void InitThreadFuncImpl(size_t thread_idx) override {
+ private:
+  bool InitThreadFuncImpl(size_t thread_idx) override {
     auto* stub = channels_[thread_idx % channels_.size()].get_stub();
-    stream_[thread_idx] = stub->StreamingBothWays(&context_[thread_idx]);
+    std::lock_guard<std::mutex> l(stream_mu_[thread_idx]);
+    if (!shutdown_[thread_idx].val) {
+      stream_[thread_idx] = stub->StreamingBothWays(&context_[thread_idx]);
+    } else {
+      return false;
+    }
+    return true;
   }
+
   bool ThreadFuncImpl(HistogramEntry* entry, size_t thread_idx) override {
     // TODO (vjpai): Do this
     return true;
diff --git a/test/cpp/qps/histogram.h b/test/cpp/qps/histogram.h
index e31d5d7..ba72b5b 100644
--- a/test/cpp/qps/histogram.h
+++ b/test/cpp/qps/histogram.h
@@ -19,8 +19,8 @@
 #ifndef TEST_QPS_HISTOGRAM_H
 #define TEST_QPS_HISTOGRAM_H
 
-#include <grpc/support/histogram.h>
 #include "src/proto/grpc/testing/stats.pb.h"
+#include "test/core/util/histogram.h"
 
 namespace grpc {
 namespace testing {
@@ -29,36 +29,36 @@
  public:
   // TODO: look into making histogram params not hardcoded for C++
   Histogram()
-      : impl_(gpr_histogram_create(default_resolution(),
-                                   default_max_possible())) {}
+      : impl_(grpc_histogram_create(default_resolution(),
+                                    default_max_possible())) {}
   ~Histogram() {
-    if (impl_) gpr_histogram_destroy(impl_);
+    if (impl_) grpc_histogram_destroy(impl_);
   }
   Histogram(Histogram&& other) : impl_(other.impl_) { other.impl_ = nullptr; }
 
-  void Merge(const Histogram& h) { gpr_histogram_merge(impl_, h.impl_); }
-  void Add(double value) { gpr_histogram_add(impl_, value); }
+  void Merge(const Histogram& h) { grpc_histogram_merge(impl_, h.impl_); }
+  void Add(double value) { grpc_histogram_add(impl_, value); }
   double Percentile(double pctile) const {
-    return gpr_histogram_percentile(impl_, pctile);
+    return grpc_histogram_percentile(impl_, pctile);
   }
-  double Count() const { return gpr_histogram_count(impl_); }
+  double Count() const { return grpc_histogram_count(impl_); }
   void Swap(Histogram* other) { std::swap(impl_, other->impl_); }
   void FillProto(HistogramData* p) {
     size_t n;
-    const auto* data = gpr_histogram_get_contents(impl_, &n);
+    const auto* data = grpc_histogram_get_contents(impl_, &n);
     for (size_t i = 0; i < n; i++) {
       p->add_bucket(data[i]);
     }
-    p->set_min_seen(gpr_histogram_minimum(impl_));
-    p->set_max_seen(gpr_histogram_maximum(impl_));
-    p->set_sum(gpr_histogram_sum(impl_));
-    p->set_sum_of_squares(gpr_histogram_sum_of_squares(impl_));
-    p->set_count(gpr_histogram_count(impl_));
+    p->set_min_seen(grpc_histogram_minimum(impl_));
+    p->set_max_seen(grpc_histogram_maximum(impl_));
+    p->set_sum(grpc_histogram_sum(impl_));
+    p->set_sum_of_squares(grpc_histogram_sum_of_squares(impl_));
+    p->set_count(grpc_histogram_count(impl_));
   }
   void MergeProto(const HistogramData& p) {
-    gpr_histogram_merge_contents(impl_, &*p.bucket().begin(), p.bucket_size(),
-                                 p.min_seen(), p.max_seen(), p.sum(),
-                                 p.sum_of_squares(), p.count());
+    grpc_histogram_merge_contents(impl_, &*p.bucket().begin(), p.bucket_size(),
+                                  p.min_seen(), p.max_seen(), p.sum(),
+                                  p.sum_of_squares(), p.count());
   }
 
   static double default_resolution() { return 0.01; }
@@ -68,7 +68,7 @@
   Histogram(const Histogram&);
   Histogram& operator=(const Histogram&);
 
-  gpr_histogram* impl_;
+  grpc_histogram* impl_;
 };
 }  // namespace testing
 }  // namespace grpc
diff --git a/test/cpp/qps/qps_interarrival_test.cc b/test/cpp/qps/qps_interarrival_test.cc
index 461bf62..625b7db 100644
--- a/test/cpp/qps/qps_interarrival_test.cc
+++ b/test/cpp/qps/qps_interarrival_test.cc
@@ -20,7 +20,7 @@
 #include <iostream>
 
 // Use the C histogram rather than C++ to avoid depending on proto
-#include <grpc/support/histogram.h>
+#include "test/core/util/histogram.h"
 
 #include "test/cpp/qps/interarrival.h"
 #include "test/cpp/util/test_config.h"
@@ -31,21 +31,21 @@
 static void RunTest(RandomDistInterface&& r, int threads, std::string title) {
   InterarrivalTimer timer;
   timer.init(r, threads);
-  gpr_histogram* h(gpr_histogram_create(0.01, 60e9));
+  grpc_histogram* h(grpc_histogram_create(0.01, 60e9));
 
   for (int i = 0; i < 10000000; i++) {
     for (int j = 0; j < threads; j++) {
-      gpr_histogram_add(h, timer.next(j));
+      grpc_histogram_add(h, timer.next(j));
     }
   }
 
   std::cout << title << " Distribution" << std::endl;
   std::cout << "Value, Percentile" << std::endl;
   for (double pct = 0.0; pct < 100.0; pct += 1.0) {
-    std::cout << gpr_histogram_percentile(h, pct) << "," << pct << std::endl;
+    std::cout << grpc_histogram_percentile(h, pct) << "," << pct << std::endl;
   }
 
-  gpr_histogram_destroy(h);
+  grpc_histogram_destroy(h);
 }
 
 using grpc::testing::ExpDist;
diff --git a/test/cpp/qps/qps_worker.cc b/test/cpp/qps/qps_worker.cc
index c288b03..4c9ab0e 100644
--- a/test/cpp/qps/qps_worker.cc
+++ b/test/cpp/qps/qps_worker.cc
@@ -32,12 +32,12 @@
 #include <grpc/grpc.h>
 #include <grpc/support/alloc.h>
 #include <grpc/support/cpu.h>
-#include <grpc/support/histogram.h>
 #include <grpc/support/host_port.h>
 #include <grpc/support/log.h>
 
 #include "src/proto/grpc/testing/services.pb.h"
 #include "test/core/util/grpc_profiler.h"
+#include "test/core/util/histogram.h"
 #include "test/cpp/qps/client.h"
 #include "test/cpp/qps/server.h"
 #include "test/cpp/util/create_test_channel.h"
diff --git a/test/cpp/util/BUILD b/test/cpp/util/BUILD
index 2559c18..19e15b1 100644
--- a/test/cpp/util/BUILD
+++ b/test/cpp/util/BUILD
@@ -43,6 +43,7 @@
         "proto_reflection_descriptor_database.h",
     ],
     deps = [
+        "//:grpc++",
         "//:grpc++_config_proto",
         "//src/proto/grpc/reflection/v1alpha:reflection_proto",
     ],
@@ -135,6 +136,105 @@
 )
 
 grpc_cc_test(
+    name = "grpc_tool_test",
+    srcs = [
+        "grpc_tool_test.cc",
+    ],
+    deps = [
+        ":grpc_cli_libs",
+	":test_util",
+	"//:grpc++_reflection",
+        "//src/proto/grpc/testing:echo_proto",
+        "//src/proto/grpc/testing:echo_messages_proto",
+	"//test/core/util:grpc_test_util",
+    ],
+    external_deps = [
+        "gtest",
+    ],
+)
+
+grpc_cc_test(
+    name = "byte_buffer_test",
+    srcs = [
+        "byte_buffer_test.cc",
+    ],
+    deps = [
+	":test_util",
+    ],
+    external_deps = [
+        "gtest",
+    ],
+)
+
+grpc_cc_test(
+    name = "slice_test",
+    srcs = [
+        "slice_test.cc",
+    ],
+    deps = [
+	":test_util",
+    ],
+    external_deps = [
+        "gtest",
+    ],
+)
+
+grpc_cc_test(
+    name = "string_ref_test",
+    srcs = [
+        "string_ref_test.cc",
+    ],
+    deps = [
+	"//:grpc++",
+    ],
+    external_deps = [
+        "gtest",
+    ],
+)
+
+grpc_cc_test(
+    name = "time_test",
+    srcs = [
+        "time_test.cc",
+    ],
+    deps = [
+	":test_util",
+    ],
+    external_deps = [
+        "gtest",
+    ],
+)
+
+grpc_cc_test(
+    name = "status_test",
+    srcs = [
+        "status_test.cc",
+    ],
+    deps = [
+	":test_util",
+    ],
+    external_deps = [
+        "gtest",
+    ],
+)
+
+grpc_cc_test(
+    name = "cli_call_test",
+    srcs = [
+        "cli_call_test.cc",
+    ],
+    deps = [
+        ":grpc_cli_libs",
+	":test_util",
+        "//src/proto/grpc/testing:echo_proto",
+	"//test/core/util:grpc_test_util",
+    ],
+    external_deps = [
+        "gtest",
+    ],
+)
+
+grpc_cc_test(
     name = "error_details_test",
     srcs = [
         "error_details_test.cc",
diff --git a/test/distrib/cpp/run_distrib_test_cmake.bat b/test/distrib/cpp/run_distrib_test_cmake.bat
new file mode 100644
index 0000000..047846b
--- /dev/null
+++ b/test/distrib/cpp/run_distrib_test_cmake.bat
@@ -0,0 +1,75 @@
+@rem Copyright 2016 gRPC authors.
+@rem
+@rem Licensed under the Apache License, Version 2.0 (the "License");
+@rem you may not use this file except in compliance with the License.
+@rem You may obtain a copy of the License at
+@rem
+@rem     http://www.apache.org/licenses/LICENSE-2.0
+@rem
+@rem Unless required by applicable law or agreed to in writing, software
+@rem distributed under the License is distributed on an "AS IS" BASIS,
+@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+@rem See the License for the specific language governing permissions and
+@rem limitations under the License.
+
+@rem enter this directory
+cd /d %~dp0\..\..\..
+
+@rem TODO(jtattermusch): Kokoro has pre-installed protoc.exe in C:\Program Files\ProtoC and that directory
+@rem is on PATH. To avoid picking up the older version protoc.exe, we change the path to something non-existent.
+set PATH=%PATH:ProtoC=DontPickupProtoC%
+
+@rem Install into ./testinstall, but use absolute path and foward slashes
+set INSTALL_DIR=%cd:\=/%/testinstall
+
+@rem Download OpenSSL-Win32 originally installed from https://slproweb.com/products/Win32OpenSSL.html
+powershell -Command "(New-Object Net.WebClient).DownloadFile('https://storage.googleapis.com/grpc-testing.appspot.com/OpenSSL-Win32-1_1_0g.zip', 'OpenSSL-Win32.zip')"
+powershell -Command "Add-Type -Assembly 'System.IO.Compression.FileSystem'; [System.IO.Compression.ZipFile]::ExtractToDirectory('OpenSSL-Win32.zip', '.');"
+
+@rem set absolute path to OpenSSL with forward slashes
+set OPENSSL_DIR=%cd:\=/%/OpenSSL-Win32
+
+cd third_party/zlib
+mkdir cmake
+cd cmake
+cmake -DCMAKE_INSTALL_PREFIX=%INSTALL_DIR% ..
+cmake --build . --config Release --target install || goto :error
+cd ../../..
+
+cd third_party/protobuf/cmake
+mkdir build
+cd build
+cmake -DCMAKE_INSTALL_PREFIX=%INSTALL_DIR% -Dprotobuf_MSVC_STATIC_RUNTIME=OFF -Dprotobuf_BUILD_TESTS=OFF ..
+cmake --build . --config Release --target install || goto :error
+cd ../../../..
+
+cd third_party/cares/cares
+mkdir cmake
+cd cmake
+cmake -DCMAKE_INSTALL_PREFIX=%INSTALL_DIR% ..
+cmake --build . --config Release --target install || goto :error
+cd ../../../..
+
+@rem OpenSSL-Win32 and OpenSSL-Win64 can be downloaded from https://slproweb.com/products/Win32OpenSSL.html
+cd cmake
+mkdir build
+cd build
+cmake -DCMAKE_INSTALL_PREFIX=%INSTALL_DIR% -DOPENSSL_ROOT_DIR=%OPENSSL_DIR% -DOPENSSL_INCLUDE_DIR=%OPENSSL_DIR%/include -DZLIB_LIBRARY=%INSTALL_DIR%/lib/zlibstatic.lib -DZLIB_INCLUDE_DIR=%INSTALL_DIR%/include -DgRPC_INSTALL=ON -DgRPC_BUILD_TESTS=OFF -DgRPC_PROTOBUF_PROVIDER=package -DgRPC_ZLIB_PROVIDER=package -DgRPC_CARES_PROVIDER=package -DgRPC_SSL_PROVIDER=package -DCMAKE_BUILD_TYPE=Release ../.. || goto :error
+cmake --build . --config Release --target install || goto :error
+cd ../..
+
+# Build helloworld example using cmake
+cd examples/cpp/helloworld
+mkdir cmake
+cd cmake
+mkdir build
+cd build
+cmake -DCMAKE_INSTALL_PREFIX=%INSTALL_DIR% ../.. || goto :error
+cmake --build . --config Release || goto :error
+cd ../../../../..
+
+goto :EOF
+
+:error
+echo Failed!
+exit /b %errorlevel%
diff --git a/test/distrib/cpp/run_distrib_test_cmake.sh b/test/distrib/cpp/run_distrib_test_cmake.sh
index ead8cc1..a9c081c 100755
--- a/test/distrib/cpp/run_distrib_test_cmake.sh
+++ b/test/distrib/cpp/run_distrib_test_cmake.sh
@@ -19,7 +19,6 @@
 
 echo "deb http://ftp.debian.org/debian jessie-backports main" | tee /etc/apt/sources.list.d/jessie-backports.list
 apt-get update
-#apt-get install -t jessie-backports -y libc-ares-dev  # we need specifically version 1.12
 apt-get install -t jessie-backports -y libssl-dev
 
 # Install c-ares
diff --git a/third_party/cares/cares.BUILD b/third_party/cares/cares.BUILD
index 8cc01b6..85ca506 100644
--- a/third_party/cares/cares.BUILD
+++ b/third_party/cares/cares.BUILD
@@ -8,7 +8,7 @@
 config_setting(
     name = "android",
     values = {
-      "crosstool_top": "//external:android/crosstool",
+        "crosstool_top": "//external:android/crosstool",
     },
 )
 
@@ -18,120 +18,128 @@
     name = "ios_x86_64",
     values = {"cpu": "ios_x86_64"},
 )
+
 config_setting(
     name = "ios_armv7",
     values = {"cpu": "ios_armv7"},
 )
+
 config_setting(
     name = "ios_armv7s",
     values = {"cpu": "ios_armv7s"},
 )
+
 config_setting(
     name = "ios_arm64",
     values = {"cpu": "ios_arm64"},
 )
 
+genrule(
+    name = "ares_build",
+    srcs = ["@cares_local_files//:ares_build_h"],
+    outs = ["ares_build.h"],
+    cmd = "cat $(location @cares_local_files//:ares_build_h) > $@",
+)
+
+# cc_library(
+#     name = "ares_build_h",
+#     hdrs = ["ares_build.h"],
+#     data = [":ares_build"],
+#     includes = ["."],
+# )
+
+genrule(
+    name = "ares_config",
+    srcs = ["@cares_local_files//:ares_config_h"],
+    outs = ["ares_config.h"],
+    cmd = "cat $(location @cares_local_files//:ares_config_h) > $@",
+)
+
+# cc_library(
+#     name = "ares_config_h",
+#     hdrs = ["ares_config.h"],
+#     data = [":ares_config"],
+#     includes = ["."],
+# )
+
 cc_library(
     name = "ares",
     srcs = [
-        "cares/ares__close_sockets.c",
-        "cares/ares__get_hostent.c",
-        "cares/ares__read_line.c",
-        "cares/ares__timeval.c",
-        "cares/ares_cancel.c",
-        "cares/ares_create_query.c",
-        "cares/ares_data.c",
-        "cares/ares_destroy.c",
-        "cares/ares_expand_name.c",
-        "cares/ares_expand_string.c",
-        "cares/ares_fds.c",
-        "cares/ares_free_hostent.c",
-        "cares/ares_free_string.c",
-        "cares/ares_getenv.c",
-        "cares/ares_gethostbyaddr.c",
-        "cares/ares_gethostbyname.c",
-        "cares/ares_getnameinfo.c",
-        "cares/ares_getopt.c",
-        "cares/ares_getsock.c",
-        "cares/ares_init.c",
-        "cares/ares_library_init.c",
-        "cares/ares_llist.c",
-        "cares/ares_mkquery.c",
-        "cares/ares_nowarn.c",
-        "cares/ares_options.c",
-        "cares/ares_parse_a_reply.c",
-        "cares/ares_parse_aaaa_reply.c",
-        "cares/ares_parse_mx_reply.c",
-        "cares/ares_parse_naptr_reply.c",
-        "cares/ares_parse_ns_reply.c",
-        "cares/ares_parse_ptr_reply.c",
-        "cares/ares_parse_soa_reply.c",
-        "cares/ares_parse_srv_reply.c",
-        "cares/ares_parse_txt_reply.c",
-        "cares/ares_platform.c",
-        "cares/ares_process.c",
-        "cares/ares_query.c",
-        "cares/ares_search.c",
-        "cares/ares_send.c",
-        "cares/ares_strcasecmp.c",
-        "cares/ares_strdup.c",
-        "cares/ares_strerror.c",
-        "cares/ares_timeout.c",
-        "cares/ares_version.c",
-        "cares/ares_writev.c",
-        "cares/bitncmp.c",
-        "cares/inet_net_pton.c",
-        "cares/inet_ntop.c",
-        "cares/windows_port.c",
+        "ares__close_sockets.c",
+        "ares__get_hostent.c",
+        "ares__read_line.c",
+        "ares__timeval.c",
+        "ares_cancel.c",
+        "ares_create_query.c",
+        "ares_data.c",
+        "ares_destroy.c",
+        "ares_expand_name.c",
+        "ares_expand_string.c",
+        "ares_fds.c",
+        "ares_free_hostent.c",
+        "ares_free_string.c",
+        "ares_getenv.c",
+        "ares_gethostbyaddr.c",
+        "ares_gethostbyname.c",
+        "ares_getnameinfo.c",
+        "ares_getopt.c",
+        "ares_getsock.c",
+        "ares_init.c",
+        "ares_library_init.c",
+        "ares_llist.c",
+        "ares_mkquery.c",
+        "ares_nowarn.c",
+        "ares_options.c",
+        "ares_parse_a_reply.c",
+        "ares_parse_aaaa_reply.c",
+        "ares_parse_mx_reply.c",
+        "ares_parse_naptr_reply.c",
+        "ares_parse_ns_reply.c",
+        "ares_parse_ptr_reply.c",
+        "ares_parse_soa_reply.c",
+        "ares_parse_srv_reply.c",
+        "ares_parse_txt_reply.c",
+        "ares_platform.c",
+        "ares_process.c",
+        "ares_query.c",
+        "ares_search.c",
+        "ares_send.c",
+        "ares_strcasecmp.c",
+        "ares_strdup.c",
+        "ares_strerror.c",
+        "ares_timeout.c",
+        "ares_version.c",
+        "ares_writev.c",
+        "bitncmp.c",
+        "inet_net_pton.c",
+        "inet_ntop.c",
+        "windows_port.c",
     ],
     hdrs = [
+        "ares.h",
         "ares_build.h",
-        "cares/ares.h",
-        "cares/ares_data.h",
-        "cares/ares_dns.h",
-        "cares/ares_getenv.h",
-        "cares/ares_getopt.h",
-        "cares/ares_inet_net_pton.h",
-        "cares/ares_iphlpapi.h",
-        "cares/ares_ipv6.h",
-        "cares/ares_library_init.h",
-        "cares/ares_llist.h",
-        "cares/ares_nowarn.h",
-        "cares/ares_platform.h",
-        "cares/ares_private.h",
-        "cares/ares_rules.h",
-        "cares/ares_setup.h",
-        "cares/ares_strcasecmp.h",
-        "cares/ares_strdup.h",
-        "cares/ares_version.h",
-        "cares/bitncmp.h",
-        "cares/config-win32.h",
-        "cares/nameser.h",
-        "cares/setup_once.h",
-    ] + select({
-        ":ios_x86_64": ["config_darwin/ares_config.h"],
-        ":ios_armv7": ["config_darwin/ares_config.h"],
-        ":ios_armv7s": ["config_darwin/ares_config.h"],
-        ":ios_arm64": ["config_darwin/ares_config.h"],
-        ":darwin": ["config_darwin/ares_config.h"],
-        ":android": ["config_android/ares_config.h"],
-        "//conditions:default": ["config_linux/ares_config.h"],
-    }),
-    includes = [
-        ".",
-        "cares"
-    ] + select({
-        ":ios_x86_64": ["config_darwin"],
-        ":ios_armv7": ["config_darwin"],
-        ":ios_armv7s": ["config_darwin"],
-        ":ios_arm64": ["config_darwin"],
-        ":darwin": ["config_darwin"],
-        ":android": ["config_android"],
-        "//conditions:default": ["config_linux"],
-    }),
-    linkstatic = 1,
-    visibility = [
-        "//visibility:public",
+        "ares_config.h",
+        "ares_data.h",
+        "ares_dns.h",
+        "ares_getenv.h",
+        "ares_getopt.h",
+        "ares_inet_net_pton.h",
+        "ares_iphlpapi.h",
+        "ares_ipv6.h",
+        "ares_library_init.h",
+        "ares_llist.h",
+        "ares_nowarn.h",
+        "ares_platform.h",
+        "ares_private.h",
+        "ares_rules.h",
+        "ares_setup.h",
+        "ares_strcasecmp.h",
+        "ares_strdup.h",
+        "ares_version.h",
+        "bitncmp.h",
+        "config-win32.h",
+        "nameser.h",
+        "setup_once.h",
     ],
     copts = [
         "-D_GNU_SOURCE",
@@ -139,4 +147,13 @@
         "-DNOMINMAX",
         "-DHAVE_CONFIG_H",
     ],
+    data = [
+        ":ares_build",
+        ":ares_config",
+    ],
+    includes = ["."],
+    linkstatic = 1,
+    visibility = [
+        "//visibility:public",
+    ],
 )
diff --git a/third_party/cares/cares_local_files.BUILD b/third_party/cares/cares_local_files.BUILD
new file mode 100644
index 0000000..fe59447
--- /dev/null
+++ b/third_party/cares/cares_local_files.BUILD
@@ -0,0 +1,57 @@
+package(
+    default_visibility = ["//visibility:public"],
+)
+
+config_setting(
+    name = "darwin",
+    values = {"cpu": "darwin"},
+)
+
+# Android is not officially supported through C++.
+# This just helps with the build for now.
+config_setting(
+    name = "android",
+    values = {
+        "crosstool_top": "//external:android/crosstool",
+    },
+)
+
+# iOS is not officially supported through C++.
+# This just helps with the build for now.
+config_setting(
+    name = "ios_x86_64",
+    values = {"cpu": "ios_x86_64"},
+)
+
+config_setting(
+    name = "ios_armv7",
+    values = {"cpu": "ios_armv7"},
+)
+
+config_setting(
+    name = "ios_armv7s",
+    values = {"cpu": "ios_armv7s"},
+)
+
+config_setting(
+    name = "ios_arm64",
+    values = {"cpu": "ios_arm64"},
+)
+
+filegroup(
+    name = "ares_build_h",
+    srcs = ["ares_build.h"],
+)
+
+filegroup(
+    name = "ares_config_h",
+    srcs = select({
+        ":ios_x86_64": ["config_darwin/ares_config.h"],
+        ":ios_armv7": ["config_darwin/ares_config.h"],
+        ":ios_armv7s": ["config_darwin/ares_config.h"],
+        ":ios_arm64": ["config_darwin/ares_config.h"],
+        ":darwin": ["config_darwin/ares_config.h"],
+        ":android": ["config_android/ares_config.h"],
+        "//conditions:default": ["config_linux/ares_config.h"],
+    }),
+)
diff --git a/third_party/protobuf b/third_party/protobuf
index 80a37e0..2761122 160000
--- a/third_party/protobuf
+++ b/third_party/protobuf
@@ -1 +1 @@
-Subproject commit 80a37e0782d2d702d52234b62dd4b9ec74fd2c95
+Subproject commit 2761122b810fe8861004ae785cc3ab39f384d342
diff --git a/third_party/zlib.BUILD b/third_party/zlib.BUILD
index 7879a81..a71c85f 100644
--- a/third_party/zlib.BUILD
+++ b/third_party/zlib.BUILD
@@ -27,7 +27,7 @@
         "zutil.h",
     ],
     includes = [
-        "include",
+        ".",
     ],
     linkstatic = 1,
     visibility = [
diff --git a/tools/bazel.rc b/tools/bazel.rc
new file mode 100644
index 0000000..c554f03
--- /dev/null
+++ b/tools/bazel.rc
@@ -0,0 +1,48 @@
+build --client_env=CC=clang
+
+build:asan --strip=never
+build:asan --copt -fsanitize-coverage=edge
+build:asan --copt -fsanitize=address
+build:asan --copt -O0
+build:asan --copt -fno-omit-frame-pointer
+build:asan --copt -DGPR_NO_DIRECT_SYSCALLS
+build:asan --linkopt -fsanitize=address
+build:asan --action_env=ASAN_OPTIONS=detect_leaks=1:color=always
+build:asan --action_env=LSAN_OPTIONS=suppressions=lsan_suppressions.txt:report_objects=1
+
+build:msan --strip=never
+build:msan --copt -fsanitize-coverage=edge
+build:msan --copt -fsanitize=memory
+build:msan --copt -O0
+build:msan --copt -fsanitize-memory-track-origins
+build:msan --copt -fsanitize-memory-use-after-dtor
+build:msan --copt -fno-omit-frame-pointer
+build:msan --copt -fPIE
+build:msan --copt -DGPR_NO_DIRECT_SYSCALLS
+build:msan --linkopt -fsanitize=memory
+build:msan --linkopt -fPIE
+build:msan --action_env=MSAN_OPTIONS=poison_in_dtor=1
+
+build:tsan --strip=never
+build:tsan --copt -fsanitize=thread
+build:tsan --copt -fno-omit-frame-pointer
+build:tsan --copt -DGPR_NO_DIRECT_SYSCALLS
+build:tsan --copt -DGRPC_TSAN
+build:tsan --linkopt -fsanitize=thread
+build:tsan --action_env=TSAN_OPTIONS=suppressions=tools/tsan_suppressions.txt:halt_on_error=1:second_deadlock_stack=1
+
+build:ubsan --strip=never
+build:ubsan --copt -fsanitize-coverage=edge
+build:ubsan --copt -fsanitize=undefined
+build:ubsan --copt -fno-omit-frame-pointer
+build:ubsan --copt -DGRPC_UBSAN
+build:ubsan --copt -DNDEBUG
+build:ubsan --copt -fno-sanitize=function,vptr
+build:ubsan --linkopt -fsanitize=undefined
+build:ubsan --action_env=UBSAN_OPTIONS=halt_on_error=1:print_stacktrace=1:suppressions=tools/ubsan_suppressions.txt
+
+build:basicprof --strip=never
+build:basicprof --copt -DNDEBUG
+build:basicprof --copt -O2
+build:basicprof --copt -DGRPC_BASIC_PROFILER
+build:basicprof --copt -DGRPC_TIMERS_RDTSC
diff --git a/tools/codegen/core/gen_nano_proto.sh b/tools/codegen/core/gen_nano_proto.sh
index db00bd9..4246840 100755
--- a/tools/codegen/core/gen_nano_proto.sh
+++ b/tools/codegen/core/gen_nano_proto.sh
@@ -68,7 +68,7 @@
 
 # this should be the same version as the submodule we compile against
 # ideally we'd update this as a template to ensure that
-pip install protobuf==3.2.0
+pip install protobuf==3.5.0.post1
 
 pushd "$(dirname $INPUT_PROTO)" > /dev/null
 
diff --git a/tools/distrib/python/check_grpcio_tools.py b/tools/distrib/python/check_grpcio_tools.py
index c5afa71..b56ccae 100755
--- a/tools/distrib/python/check_grpcio_tools.py
+++ b/tools/distrib/python/check_grpcio_tools.py
@@ -14,17 +14,21 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-import cStringIO
-
-import make_grpcio_tools as make
+import make_grpcio_tools as _make
 
 OUT_OF_DATE_MESSAGE = """file {} is out of date
 
 Have you called tools/distrib/python/make_grpcio_tools.py since upgrading protobuf?"""
 
-check_protoc_lib_deps_content = make.get_deps()
+submodule_commit_hash = _make.protobuf_submodule_commit_hash()
 
-with open(make.GRPC_PYTHON_PROTOC_LIB_DEPS, 'r') as protoc_lib_deps_file:
-  if protoc_lib_deps_file.read() != check_protoc_lib_deps_content:
-    print(OUT_OF_DATE_MESSAGE.format(make.GRPC_PYTHON_PROTOC_LIB_DEPS))
-    raise SystemExit(1)
+with open(_make.GRPC_PYTHON_PROTOC_LIB_DEPS, 'r') as _protoc_lib_deps_file:
+  content = _protoc_lib_deps_file.read().splitlines()
+
+testString = (_make.COMMIT_HASH_PREFIX +
+              submodule_commit_hash +
+              _make.COMMIT_HASH_SUFFIX)
+
+if testString not in content:
+  print(OUT_OF_DATE_MESSAGE.format(_make.GRPC_PYTHON_PROTOC_LIB_DEPS))
+  raise SystemExit(1)
diff --git a/tools/distrib/python/grpcio_tools/grpc_version.py b/tools/distrib/python/grpcio_tools/grpc_version.py
index db92b10..f613025 100644
--- a/tools/distrib/python/grpcio_tools/grpc_version.py
+++ b/tools/distrib/python/grpcio_tools/grpc_version.py
@@ -14,4 +14,4 @@
 
 # AUTO-GENERATED FROM `$REPO_ROOT/templates/tools/distrib/python/grpcio_tools/grpc_version.py.template`!!!
 
-VERSION='1.8.0.dev0'
+VERSION='1.9.0.dev0'
diff --git a/tools/distrib/python/grpcio_tools/protoc_lib_deps.py b/tools/distrib/python/grpcio_tools/protoc_lib_deps.py
index 18470d5..2c65fca 100644
--- a/tools/distrib/python/grpcio_tools/protoc_lib_deps.py
+++ b/tools/distrib/python/grpcio_tools/protoc_lib_deps.py
@@ -1,5 +1,5 @@
 
-# Copyright 2016 gRPC authors.
+# Copyright 2017 gRPC authors.
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
 # you may not use this file except in compliance with the License.
@@ -14,8 +14,10 @@
 # limitations under the License.
 
 # AUTO-GENERATED BY make_grpcio_tools.py!
-CC_FILES=['google/protobuf/compiler/zip_writer.cc', 'google/protobuf/compiler/subprocess.cc', 'google/protobuf/compiler/ruby/ruby_generator.cc', 'google/protobuf/compiler/python/python_generator.cc', 'google/protobuf/compiler/plugin.pb.cc', 'google/protobuf/compiler/plugin.cc', 'google/protobuf/compiler/php/php_generator.cc', 'google/protobuf/compiler/objectivec/objectivec_primitive_field.cc', 'google/protobuf/compiler/objectivec/objectivec_oneof.cc', 'google/protobuf/compiler/objectivec/objectivec_message_field.cc', 'google/protobuf/compiler/objectivec/objectivec_message.cc', 'google/protobuf/compiler/objectivec/objectivec_map_field.cc', 'google/protobuf/compiler/objectivec/objectivec_helpers.cc', 'google/protobuf/compiler/objectivec/objectivec_generator.cc', 'google/protobuf/compiler/objectivec/objectivec_file.cc', 'google/protobuf/compiler/objectivec/objectivec_field.cc', 'google/protobuf/compiler/objectivec/objectivec_extension.cc', 'google/protobuf/compiler/objectivec/objectivec_enum_field.cc', 'google/protobuf/compiler/objectivec/objectivec_enum.cc', 'google/protobuf/compiler/js/well_known_types_embed.cc', 'google/protobuf/compiler/js/js_generator.cc', 'google/protobuf/compiler/javanano/javanano_primitive_field.cc', 'google/protobuf/compiler/javanano/javanano_message_field.cc', 'google/protobuf/compiler/javanano/javanano_message.cc', 'google/protobuf/compiler/javanano/javanano_map_field.cc', 'google/protobuf/compiler/javanano/javanano_helpers.cc', 'google/protobuf/compiler/javanano/javanano_generator.cc', 'google/protobuf/compiler/javanano/javanano_file.cc', 'google/protobuf/compiler/javanano/javanano_field.cc', 'google/protobuf/compiler/javanano/javanano_extension.cc', 'google/protobuf/compiler/javanano/javanano_enum_field.cc', 'google/protobuf/compiler/javanano/javanano_enum.cc', 'google/protobuf/compiler/java/java_string_field_lite.cc', 'google/protobuf/compiler/java/java_string_field.cc', 'google/protobuf/compiler/java/java_shared_code_generator.cc', 'google/protobuf/compiler/java/java_service.cc', 'google/protobuf/compiler/java/java_primitive_field_lite.cc', 'google/protobuf/compiler/java/java_primitive_field.cc', 'google/protobuf/compiler/java/java_name_resolver.cc', 'google/protobuf/compiler/java/java_message_lite.cc', 'google/protobuf/compiler/java/java_message_field_lite.cc', 'google/protobuf/compiler/java/java_message_field.cc', 'google/protobuf/compiler/java/java_message_builder_lite.cc', 'google/protobuf/compiler/java/java_message_builder.cc', 'google/protobuf/compiler/java/java_message.cc', 'google/protobuf/compiler/java/java_map_field_lite.cc', 'google/protobuf/compiler/java/java_map_field.cc', 'google/protobuf/compiler/java/java_lazy_message_field_lite.cc', 'google/protobuf/compiler/java/java_lazy_message_field.cc', 'google/protobuf/compiler/java/java_helpers.cc', 'google/protobuf/compiler/java/java_generator_factory.cc', 'google/protobuf/compiler/java/java_generator.cc', 'google/protobuf/compiler/java/java_file.cc', 'google/protobuf/compiler/java/java_field.cc', 'google/protobuf/compiler/java/java_extension_lite.cc', 'google/protobuf/compiler/java/java_extension.cc', 'google/protobuf/compiler/java/java_enum_lite.cc', 'google/protobuf/compiler/java/java_enum_field_lite.cc', 'google/protobuf/compiler/java/java_enum_field.cc', 'google/protobuf/compiler/java/java_enum.cc', 'google/protobuf/compiler/java/java_doc_comment.cc', 'google/protobuf/compiler/java/java_context.cc', 'google/protobuf/compiler/csharp/csharp_wrapper_field.cc', 'google/protobuf/compiler/csharp/csharp_source_generator_base.cc', 'google/protobuf/compiler/csharp/csharp_repeated_primitive_field.cc', 'google/protobuf/compiler/csharp/csharp_repeated_message_field.cc', 'google/protobuf/compiler/csharp/csharp_repeated_enum_field.cc', 'google/protobuf/compiler/csharp/csharp_reflection_class.cc', 'google/protobuf/compiler/csharp/csharp_primitive_field.cc', 'google/protobuf/compiler/csharp/csharp_message_field.cc', 'google/protobuf/compiler/csharp/csharp_message.cc', 'google/protobuf/compiler/csharp/csharp_map_field.cc', 'google/protobuf/compiler/csharp/csharp_helpers.cc', 'google/protobuf/compiler/csharp/csharp_generator.cc', 'google/protobuf/compiler/csharp/csharp_field_base.cc', 'google/protobuf/compiler/csharp/csharp_enum_field.cc', 'google/protobuf/compiler/csharp/csharp_enum.cc', 'google/protobuf/compiler/csharp/csharp_doc_comment.cc', 'google/protobuf/compiler/cpp/cpp_string_field.cc', 'google/protobuf/compiler/cpp/cpp_service.cc', 'google/protobuf/compiler/cpp/cpp_primitive_field.cc', 'google/protobuf/compiler/cpp/cpp_message_field.cc', 'google/protobuf/compiler/cpp/cpp_message.cc', 'google/protobuf/compiler/cpp/cpp_map_field.cc', 'google/protobuf/compiler/cpp/cpp_helpers.cc', 'google/protobuf/compiler/cpp/cpp_generator.cc', 'google/protobuf/compiler/cpp/cpp_file.cc', 'google/protobuf/compiler/cpp/cpp_field.cc', 'google/protobuf/compiler/cpp/cpp_extension.cc', 'google/protobuf/compiler/cpp/cpp_enum_field.cc', 'google/protobuf/compiler/cpp/cpp_enum.cc', 'google/protobuf/compiler/command_line_interface.cc', 'google/protobuf/compiler/code_generator.cc', 'google/protobuf/wrappers.pb.cc', 'google/protobuf/wire_format.cc', 'google/protobuf/util/type_resolver_util.cc', 'google/protobuf/util/time_util.cc', 'google/protobuf/util/message_differencer.cc', 'google/protobuf/util/json_util.cc', 'google/protobuf/util/internal/utility.cc', 'google/protobuf/util/internal/type_info_test_helper.cc', 'google/protobuf/util/internal/type_info.cc', 'google/protobuf/util/internal/protostream_objectwriter.cc', 'google/protobuf/util/internal/protostream_objectsource.cc', 'google/protobuf/util/internal/proto_writer.cc', 'google/protobuf/util/internal/object_writer.cc', 'google/protobuf/util/internal/json_stream_parser.cc', 'google/protobuf/util/internal/json_objectwriter.cc', 'google/protobuf/util/internal/json_escaping.cc', 'google/protobuf/util/internal/field_mask_utility.cc', 'google/protobuf/util/internal/error_listener.cc', 'google/protobuf/util/internal/default_value_objectwriter.cc', 'google/protobuf/util/internal/datapiece.cc', 'google/protobuf/util/field_mask_util.cc', 'google/protobuf/util/field_comparator.cc', 'google/protobuf/util/delimited_message_util.cc', 'google/protobuf/unknown_field_set.cc', 'google/protobuf/type.pb.cc', 'google/protobuf/timestamp.pb.cc', 'google/protobuf/text_format.cc', 'google/protobuf/stubs/substitute.cc', 'google/protobuf/stubs/mathlimits.cc', 'google/protobuf/struct.pb.cc', 'google/protobuf/source_context.pb.cc', 'google/protobuf/service.cc', 'google/protobuf/reflection_ops.cc', 'google/protobuf/message.cc', 'google/protobuf/map_field.cc', 'google/protobuf/io/zero_copy_stream_impl.cc', 'google/protobuf/io/tokenizer.cc', 'google/protobuf/io/strtod.cc', 'google/protobuf/io/printer.cc', 'google/protobuf/io/gzip_stream.cc', 'google/protobuf/generated_message_table_driven.cc', 'google/protobuf/generated_message_reflection.cc', 'google/protobuf/field_mask.pb.cc', 'google/protobuf/extension_set_heavy.cc', 'google/protobuf/empty.pb.cc', 'google/protobuf/dynamic_message.cc', 'google/protobuf/duration.pb.cc', 'google/protobuf/descriptor_database.cc', 'google/protobuf/descriptor.pb.cc', 'google/protobuf/descriptor.cc', 'google/protobuf/compiler/parser.cc', 'google/protobuf/compiler/importer.cc', 'google/protobuf/api.pb.cc', 'google/protobuf/any.pb.cc', 'google/protobuf/any.cc', 'google/protobuf/wire_format_lite.cc', 'google/protobuf/stubs/time.cc', 'google/protobuf/stubs/strutil.cc', 'google/protobuf/stubs/structurally_valid.cc', 'google/protobuf/stubs/stringprintf.cc', 'google/protobuf/stubs/stringpiece.cc', 'google/protobuf/stubs/statusor.cc', 'google/protobuf/stubs/status.cc', 'google/protobuf/stubs/once.cc', 'google/protobuf/stubs/io_win32.cc', 'google/protobuf/stubs/int128.cc', 'google/protobuf/stubs/common.cc', 'google/protobuf/stubs/bytestream.cc', 'google/protobuf/stubs/atomicops_internals_x86_msvc.cc', 'google/protobuf/stubs/atomicops_internals_x86_gcc.cc', 'google/protobuf/repeated_field.cc', 'google/protobuf/message_lite.cc', 'google/protobuf/io/zero_copy_stream_impl_lite.cc', 'google/protobuf/io/zero_copy_stream.cc', 'google/protobuf/io/coded_stream.cc', 'google/protobuf/generated_message_util.cc', 'google/protobuf/generated_message_table_driven_lite.cc', 'google/protobuf/extension_set.cc', 'google/protobuf/arenastring.cc', 'google/protobuf/arena.cc', 'google/protobuf/compiler/js/embed.cc']
+CC_FILES=['google/protobuf/compiler/zip_writer.cc', 'google/protobuf/compiler/subprocess.cc', 'google/protobuf/compiler/ruby/ruby_generator.cc', 'google/protobuf/compiler/python/python_generator.cc', 'google/protobuf/compiler/plugin.pb.cc', 'google/protobuf/compiler/plugin.cc', 'google/protobuf/compiler/php/php_generator.cc', 'google/protobuf/compiler/objectivec/objectivec_primitive_field.cc', 'google/protobuf/compiler/objectivec/objectivec_oneof.cc', 'google/protobuf/compiler/objectivec/objectivec_message_field.cc', 'google/protobuf/compiler/objectivec/objectivec_message.cc', 'google/protobuf/compiler/objectivec/objectivec_map_field.cc', 'google/protobuf/compiler/objectivec/objectivec_helpers.cc', 'google/protobuf/compiler/objectivec/objectivec_generator.cc', 'google/protobuf/compiler/objectivec/objectivec_file.cc', 'google/protobuf/compiler/objectivec/objectivec_field.cc', 'google/protobuf/compiler/objectivec/objectivec_extension.cc', 'google/protobuf/compiler/objectivec/objectivec_enum_field.cc', 'google/protobuf/compiler/objectivec/objectivec_enum.cc', 'google/protobuf/compiler/js/well_known_types_embed.cc', 'google/protobuf/compiler/js/js_generator.cc', 'google/protobuf/compiler/javanano/javanano_primitive_field.cc', 'google/protobuf/compiler/javanano/javanano_message_field.cc', 'google/protobuf/compiler/javanano/javanano_message.cc', 'google/protobuf/compiler/javanano/javanano_map_field.cc', 'google/protobuf/compiler/javanano/javanano_helpers.cc', 'google/protobuf/compiler/javanano/javanano_generator.cc', 'google/protobuf/compiler/javanano/javanano_file.cc', 'google/protobuf/compiler/javanano/javanano_field.cc', 'google/protobuf/compiler/javanano/javanano_extension.cc', 'google/protobuf/compiler/javanano/javanano_enum_field.cc', 'google/protobuf/compiler/javanano/javanano_enum.cc', 'google/protobuf/compiler/java/java_string_field_lite.cc', 'google/protobuf/compiler/java/java_string_field.cc', 'google/protobuf/compiler/java/java_shared_code_generator.cc', 'google/protobuf/compiler/java/java_service.cc', 'google/protobuf/compiler/java/java_primitive_field_lite.cc', 'google/protobuf/compiler/java/java_primitive_field.cc', 'google/protobuf/compiler/java/java_name_resolver.cc', 'google/protobuf/compiler/java/java_message_lite.cc', 'google/protobuf/compiler/java/java_message_field_lite.cc', 'google/protobuf/compiler/java/java_message_field.cc', 'google/protobuf/compiler/java/java_message_builder_lite.cc', 'google/protobuf/compiler/java/java_message_builder.cc', 'google/protobuf/compiler/java/java_message.cc', 'google/protobuf/compiler/java/java_map_field_lite.cc', 'google/protobuf/compiler/java/java_map_field.cc', 'google/protobuf/compiler/java/java_lazy_message_field_lite.cc', 'google/protobuf/compiler/java/java_lazy_message_field.cc', 'google/protobuf/compiler/java/java_helpers.cc', 'google/protobuf/compiler/java/java_generator_factory.cc', 'google/protobuf/compiler/java/java_generator.cc', 'google/protobuf/compiler/java/java_file.cc', 'google/protobuf/compiler/java/java_field.cc', 'google/protobuf/compiler/java/java_extension_lite.cc', 'google/protobuf/compiler/java/java_extension.cc', 'google/protobuf/compiler/java/java_enum_lite.cc', 'google/protobuf/compiler/java/java_enum_field_lite.cc', 'google/protobuf/compiler/java/java_enum_field.cc', 'google/protobuf/compiler/java/java_enum.cc', 'google/protobuf/compiler/java/java_doc_comment.cc', 'google/protobuf/compiler/java/java_context.cc', 'google/protobuf/compiler/csharp/csharp_wrapper_field.cc', 'google/protobuf/compiler/csharp/csharp_source_generator_base.cc', 'google/protobuf/compiler/csharp/csharp_repeated_primitive_field.cc', 'google/protobuf/compiler/csharp/csharp_repeated_message_field.cc', 'google/protobuf/compiler/csharp/csharp_repeated_enum_field.cc', 'google/protobuf/compiler/csharp/csharp_reflection_class.cc', 'google/protobuf/compiler/csharp/csharp_primitive_field.cc', 'google/protobuf/compiler/csharp/csharp_message_field.cc', 'google/protobuf/compiler/csharp/csharp_message.cc', 'google/protobuf/compiler/csharp/csharp_map_field.cc', 'google/protobuf/compiler/csharp/csharp_helpers.cc', 'google/protobuf/compiler/csharp/csharp_generator.cc', 'google/protobuf/compiler/csharp/csharp_field_base.cc', 'google/protobuf/compiler/csharp/csharp_enum_field.cc', 'google/protobuf/compiler/csharp/csharp_enum.cc', 'google/protobuf/compiler/csharp/csharp_doc_comment.cc', 'google/protobuf/compiler/cpp/cpp_string_field.cc', 'google/protobuf/compiler/cpp/cpp_service.cc', 'google/protobuf/compiler/cpp/cpp_primitive_field.cc', 'google/protobuf/compiler/cpp/cpp_padding_optimizer.cc', 'google/protobuf/compiler/cpp/cpp_message_field.cc', 'google/protobuf/compiler/cpp/cpp_message.cc', 'google/protobuf/compiler/cpp/cpp_map_field.cc', 'google/protobuf/compiler/cpp/cpp_helpers.cc', 'google/protobuf/compiler/cpp/cpp_generator.cc', 'google/protobuf/compiler/cpp/cpp_file.cc', 'google/protobuf/compiler/cpp/cpp_field.cc', 'google/protobuf/compiler/cpp/cpp_extension.cc', 'google/protobuf/compiler/cpp/cpp_enum_field.cc', 'google/protobuf/compiler/cpp/cpp_enum.cc', 'google/protobuf/compiler/command_line_interface.cc', 'google/protobuf/compiler/code_generator.cc', 'google/protobuf/wrappers.pb.cc', 'google/protobuf/wire_format.cc', 'google/protobuf/util/type_resolver_util.cc', 'google/protobuf/util/time_util.cc', 'google/protobuf/util/message_differencer.cc', 'google/protobuf/util/json_util.cc', 'google/protobuf/util/internal/utility.cc', 'google/protobuf/util/internal/type_info_test_helper.cc', 'google/protobuf/util/internal/type_info.cc', 'google/protobuf/util/internal/protostream_objectwriter.cc', 'google/protobuf/util/internal/protostream_objectsource.cc', 'google/protobuf/util/internal/proto_writer.cc', 'google/protobuf/util/internal/object_writer.cc', 'google/protobuf/util/internal/json_stream_parser.cc', 'google/protobuf/util/internal/json_objectwriter.cc', 'google/protobuf/util/internal/json_escaping.cc', 'google/protobuf/util/internal/field_mask_utility.cc', 'google/protobuf/util/internal/error_listener.cc', 'google/protobuf/util/internal/default_value_objectwriter.cc', 'google/protobuf/util/internal/datapiece.cc', 'google/protobuf/util/field_mask_util.cc', 'google/protobuf/util/field_comparator.cc', 'google/protobuf/util/delimited_message_util.cc', 'google/protobuf/unknown_field_set.cc', 'google/protobuf/type.pb.cc', 'google/protobuf/timestamp.pb.cc', 'google/protobuf/text_format.cc', 'google/protobuf/stubs/substitute.cc', 'google/protobuf/stubs/mathlimits.cc', 'google/protobuf/struct.pb.cc', 'google/protobuf/source_context.pb.cc', 'google/protobuf/service.cc', 'google/protobuf/reflection_ops.cc', 'google/protobuf/message.cc', 'google/protobuf/map_field.cc', 'google/protobuf/io/zero_copy_stream_impl.cc', 'google/protobuf/io/tokenizer.cc', 'google/protobuf/io/strtod.cc', 'google/protobuf/io/printer.cc', 'google/protobuf/io/gzip_stream.cc', 'google/protobuf/generated_message_table_driven.cc', 'google/protobuf/generated_message_reflection.cc', 'google/protobuf/field_mask.pb.cc', 'google/protobuf/extension_set_heavy.cc', 'google/protobuf/empty.pb.cc', 'google/protobuf/dynamic_message.cc', 'google/protobuf/duration.pb.cc', 'google/protobuf/descriptor_database.cc', 'google/protobuf/descriptor.pb.cc', 'google/protobuf/descriptor.cc', 'google/protobuf/compiler/parser.cc', 'google/protobuf/compiler/importer.cc', 'google/protobuf/api.pb.cc', 'google/protobuf/any.pb.cc', 'google/protobuf/any.cc', 'google/protobuf/wire_format_lite.cc', 'google/protobuf/stubs/time.cc', 'google/protobuf/stubs/strutil.cc', 'google/protobuf/stubs/structurally_valid.cc', 'google/protobuf/stubs/stringprintf.cc', 'google/protobuf/stubs/stringpiece.cc', 'google/protobuf/stubs/statusor.cc', 'google/protobuf/stubs/status.cc', 'google/protobuf/stubs/once.cc', 'google/protobuf/stubs/io_win32.cc', 'google/protobuf/stubs/int128.cc', 'google/protobuf/stubs/common.cc', 'google/protobuf/stubs/bytestream.cc', 'google/protobuf/stubs/atomicops_internals_x86_msvc.cc', 'google/protobuf/stubs/atomicops_internals_x86_gcc.cc', 'google/protobuf/repeated_field.cc', 'google/protobuf/message_lite.cc', 'google/protobuf/io/zero_copy_stream_impl_lite.cc', 'google/protobuf/io/zero_copy_stream.cc', 'google/protobuf/io/coded_stream.cc', 'google/protobuf/generated_message_util.cc', 'google/protobuf/generated_message_table_driven_lite.cc', 'google/protobuf/extension_set.cc', 'google/protobuf/arenastring.cc', 'google/protobuf/arena.cc', 'google/protobuf/compiler/js/embed.cc']
 PROTO_FILES=['google/protobuf/wrappers.proto', 'google/protobuf/type.proto', 'google/protobuf/timestamp.proto', 'google/protobuf/struct.proto', 'google/protobuf/source_context.proto', 'google/protobuf/field_mask.proto', 'google/protobuf/empty.proto', 'google/protobuf/duration.proto', 'google/protobuf/descriptor.proto', 'google/protobuf/compiler/plugin.proto', 'google/protobuf/api.proto', 'google/protobuf/any.proto']
 
 CC_INCLUDE='third_party/protobuf/src'
 PROTO_INCLUDE='third_party/protobuf/src'
+
+PROTOBUF_SUBMODULE_VERSION="2761122b810fe8861004ae785cc3ab39f384d342"
diff --git a/tools/distrib/python/grpcio_tools/setup.py b/tools/distrib/python/grpcio_tools/setup.py
index e0e9226..8d95cb5 100644
--- a/tools/distrib/python/grpcio_tools/setup.py
+++ b/tools/distrib/python/grpcio_tools/setup.py
@@ -209,7 +209,7 @@
   ext_modules=extension_modules(),
   packages=setuptools.find_packages('.'),
   install_requires=[
-    'protobuf>=3.3.0',
+    'protobuf>=3.5.0.post1',
     '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 5bc07ff..c865f0b 100755
--- a/tools/distrib/python/make_grpcio_tools.py
+++ b/tools/distrib/python/make_grpcio_tools.py
@@ -28,7 +28,7 @@
 import uuid
 
 DEPS_FILE_CONTENT="""
-# Copyright 2016 gRPC authors.
+# Copyright 2017 gRPC authors.
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
 # you may not use this file except in compliance with the License.
@@ -48,8 +48,13 @@
 
 CC_INCLUDE={cc_include}
 PROTO_INCLUDE={proto_include}
+
+{commit_hash}
 """
 
+COMMIT_HASH_PREFIX = 'PROTOBUF_SUBMODULE_VERSION="'
+COMMIT_HASH_SUFFIX = '"'
+
 # Bazel query result prefix for expected source files in protobuf.
 PROTOBUF_CC_PREFIX = '//:src/'
 PROTOBUF_PROTO_PREFIX = '//:src/'
@@ -63,6 +68,7 @@
 
 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_PROTOBUF_SUBMODULE_ROOT = os.path.join(GRPC_ROOT, 'third_party', 'protobuf')
 GRPC_PROTOC_PLUGINS = os.path.join(GRPC_ROOT, 'src', 'compiler')
 GRPC_PYTHON_PROTOBUF = os.path.join(GRPC_PYTHON_ROOT, 'third_party', 'protobuf',
                                     'src')
@@ -78,6 +84,14 @@
 BAZEL_DEPS_PROTOC_LIB_QUERY = '//:protoc_lib'
 BAZEL_DEPS_COMMON_PROTOS_QUERY = '//:well_known_protos'
 
+def protobuf_submodule_commit_hash():
+  """Gets the commit hash for the HEAD of the protobuf submodule currently
+     checked out."""
+  cwd = os.getcwd()
+  os.chdir(GRPC_PROTOBUF_SUBMODULE_ROOT)
+  output = subprocess.check_output(['git', 'rev-parse', 'HEAD'])
+  os.chdir(cwd)
+  return output.splitlines()[0].strip()
 
 def bazel_query(query):
   output = subprocess.check_output([BAZEL_DEPS, query])
@@ -94,11 +108,13 @@
   proto_files = [
       name[len(PROTOBUF_PROTO_PREFIX):] for name in proto_files_output
       if name.endswith('.proto') and name.startswith(PROTOBUF_PROTO_PREFIX)]
+  commit_hash = protobuf_submodule_commit_hash()
   deps_file_content = DEPS_FILE_CONTENT.format(
       cc_files=cc_files,
       proto_files=proto_files,
       cc_include=repr(GRPC_PYTHON_PROTOBUF_RELATIVE_ROOT),
-      proto_include=repr(GRPC_PYTHON_PROTOBUF_RELATIVE_ROOT))
+      proto_include=repr(GRPC_PYTHON_PROTOBUF_RELATIVE_ROOT),
+      commit_hash=COMMIT_HASH_PREFIX + commit_hash + COMMIT_HASH_SUFFIX)
   return deps_file_content
 
 def long_path(path):
diff --git a/tools/dockerfile/interoptest/grpc_interop_csharp/Dockerfile b/tools/dockerfile/interoptest/grpc_interop_csharp/Dockerfile
index ea82476..af2ab90 100644
--- a/tools/dockerfile/interoptest/grpc_interop_csharp/Dockerfile
+++ b/tools/dockerfile/interoptest/grpc_interop_csharp/Dockerfile
@@ -62,7 +62,7 @@
 # Install Python packages from PyPI
 RUN pip install --upgrade pip==9.0.1
 RUN pip install virtualenv
-RUN pip install futures==2.2.0 enum34==1.0.4 protobuf==3.2.0 six==1.10.0 twisted==17.5.0
+RUN pip install futures==2.2.0 enum34==1.0.4 protobuf==3.5.0.post1 six==1.10.0 twisted==17.5.0
 
 #================
 # C# dependencies
diff --git a/tools/dockerfile/interoptest/grpc_interop_csharpcoreclr/Dockerfile b/tools/dockerfile/interoptest/grpc_interop_csharpcoreclr/Dockerfile
index ea82476..af2ab90 100644
--- a/tools/dockerfile/interoptest/grpc_interop_csharpcoreclr/Dockerfile
+++ b/tools/dockerfile/interoptest/grpc_interop_csharpcoreclr/Dockerfile
@@ -62,7 +62,7 @@
 # Install Python packages from PyPI
 RUN pip install --upgrade pip==9.0.1
 RUN pip install virtualenv
-RUN pip install futures==2.2.0 enum34==1.0.4 protobuf==3.2.0 six==1.10.0 twisted==17.5.0
+RUN pip install futures==2.2.0 enum34==1.0.4 protobuf==3.5.0.post1 six==1.10.0 twisted==17.5.0
 
 #================
 # C# dependencies
diff --git a/tools/dockerfile/interoptest/grpc_interop_cxx/Dockerfile b/tools/dockerfile/interoptest/grpc_interop_cxx/Dockerfile
index 38d377c..ec5338b 100644
--- a/tools/dockerfile/interoptest/grpc_interop_cxx/Dockerfile
+++ b/tools/dockerfile/interoptest/grpc_interop_cxx/Dockerfile
@@ -62,7 +62,7 @@
 # Install Python packages from PyPI
 RUN pip install --upgrade pip==9.0.1
 RUN pip install virtualenv
-RUN pip install futures==2.2.0 enum34==1.0.4 protobuf==3.2.0 six==1.10.0 twisted==17.5.0
+RUN pip install futures==2.2.0 enum34==1.0.4 protobuf==3.5.0.post1 six==1.10.0 twisted==17.5.0
 
 #=================
 # C++ dependencies
diff --git a/tools/dockerfile/interoptest/grpc_interop_go/Dockerfile b/tools/dockerfile/interoptest/grpc_interop_go/Dockerfile
index 73c41a4..a775961 100644
--- a/tools/dockerfile/interoptest/grpc_interop_go/Dockerfile
+++ b/tools/dockerfile/interoptest/grpc_interop_go/Dockerfile
@@ -30,7 +30,7 @@
 # Install Python packages from PyPI
 RUN pip install --upgrade pip==9.0.1
 RUN pip install virtualenv
-RUN pip install futures==2.2.0 enum34==1.0.4 protobuf==3.2.0 six==1.10.0 twisted==17.5.0
+RUN pip install futures==2.2.0 enum34==1.0.4 protobuf==3.5.0.post1 six==1.10.0 twisted==17.5.0
 
 # Define the default command.
 CMD ["bash"]
diff --git a/tools/dockerfile/interoptest/grpc_interop_go1.7/Dockerfile b/tools/dockerfile/interoptest/grpc_interop_go1.7/Dockerfile
index 7c083de..c296c8c 100644
--- a/tools/dockerfile/interoptest/grpc_interop_go1.7/Dockerfile
+++ b/tools/dockerfile/interoptest/grpc_interop_go1.7/Dockerfile
@@ -30,7 +30,7 @@
 # Install Python packages from PyPI
 RUN pip install --upgrade pip==9.0.1
 RUN pip install virtualenv
-RUN pip install futures==2.2.0 enum34==1.0.4 protobuf==3.2.0 six==1.10.0 twisted==17.5.0
+RUN pip install futures==2.2.0 enum34==1.0.4 protobuf==3.5.0.post1 six==1.10.0 twisted==17.5.0
 
 # Define the default command.
 CMD ["bash"]
diff --git a/tools/dockerfile/interoptest/grpc_interop_go1.8/Dockerfile b/tools/dockerfile/interoptest/grpc_interop_go1.8/Dockerfile
index 61efc18..9ac0b97 100644
--- a/tools/dockerfile/interoptest/grpc_interop_go1.8/Dockerfile
+++ b/tools/dockerfile/interoptest/grpc_interop_go1.8/Dockerfile
@@ -30,7 +30,7 @@
 # Install Python packages from PyPI
 RUN pip install --upgrade pip==9.0.1
 RUN pip install virtualenv
-RUN pip install futures==2.2.0 enum34==1.0.4 protobuf==3.2.0 six==1.10.0 twisted==17.5.0
+RUN pip install futures==2.2.0 enum34==1.0.4 protobuf==3.5.0.post1 six==1.10.0 twisted==17.5.0
 
 # Define the default command.
 CMD ["bash"]
diff --git a/tools/dockerfile/interoptest/grpc_interop_http2/Dockerfile b/tools/dockerfile/interoptest/grpc_interop_http2/Dockerfile
index 278b09a..92a2faa 100644
--- a/tools/dockerfile/interoptest/grpc_interop_http2/Dockerfile
+++ b/tools/dockerfile/interoptest/grpc_interop_http2/Dockerfile
@@ -30,7 +30,7 @@
 # Install Python packages from PyPI
 RUN pip install --upgrade pip==9.0.1
 RUN pip install virtualenv
-RUN pip install futures==2.2.0 enum34==1.0.4 protobuf==3.2.0 six==1.10.0 twisted==17.5.0
+RUN pip install futures==2.2.0 enum34==1.0.4 protobuf==3.5.0.post1 six==1.10.0 twisted==17.5.0
 
 RUN pip install twisted h2==2.6.1 hyper
 
diff --git a/tools/dockerfile/interoptest/grpc_interop_java/Dockerfile b/tools/dockerfile/interoptest/grpc_interop_java/Dockerfile
index d566324..34b4e39 100644
--- a/tools/dockerfile/interoptest/grpc_interop_java/Dockerfile
+++ b/tools/dockerfile/interoptest/grpc_interop_java/Dockerfile
@@ -45,7 +45,7 @@
 # Install Python packages from PyPI
 RUN pip install --upgrade pip==9.0.1
 RUN pip install virtualenv
-RUN pip install futures==2.2.0 enum34==1.0.4 protobuf==3.2.0 six==1.10.0 twisted==17.5.0
+RUN pip install futures==2.2.0 enum34==1.0.4 protobuf==3.5.0.post1 six==1.10.0 twisted==17.5.0
 
 
 # Trigger download of as many Gradle artifacts as possible.
diff --git a/tools/dockerfile/interoptest/grpc_interop_java_oracle8/Dockerfile b/tools/dockerfile/interoptest/grpc_interop_java_oracle8/Dockerfile
index d566324..34b4e39 100644
--- a/tools/dockerfile/interoptest/grpc_interop_java_oracle8/Dockerfile
+++ b/tools/dockerfile/interoptest/grpc_interop_java_oracle8/Dockerfile
@@ -45,7 +45,7 @@
 # Install Python packages from PyPI
 RUN pip install --upgrade pip==9.0.1
 RUN pip install virtualenv
-RUN pip install futures==2.2.0 enum34==1.0.4 protobuf==3.2.0 six==1.10.0 twisted==17.5.0
+RUN pip install futures==2.2.0 enum34==1.0.4 protobuf==3.5.0.post1 six==1.10.0 twisted==17.5.0
 
 
 # Trigger download of as many Gradle artifacts as possible.
diff --git a/tools/dockerfile/interoptest/grpc_interop_node/Dockerfile b/tools/dockerfile/interoptest/grpc_interop_node/Dockerfile
index f4c3e41..17671a3 100644
--- a/tools/dockerfile/interoptest/grpc_interop_node/Dockerfile
+++ b/tools/dockerfile/interoptest/grpc_interop_node/Dockerfile
@@ -62,7 +62,7 @@
 # Install Python packages from PyPI
 RUN pip install --upgrade pip==9.0.1
 RUN pip install virtualenv
-RUN pip install futures==2.2.0 enum34==1.0.4 protobuf==3.2.0 six==1.10.0 twisted==17.5.0
+RUN pip install futures==2.2.0 enum34==1.0.4 protobuf==3.5.0.post1 six==1.10.0 twisted==17.5.0
 
 #==================
 # Node dependencies
diff --git a/tools/dockerfile/interoptest/grpc_interop_python/Dockerfile b/tools/dockerfile/interoptest/grpc_interop_python/Dockerfile
index d165307..07f419f 100644
--- a/tools/dockerfile/interoptest/grpc_interop_python/Dockerfile
+++ b/tools/dockerfile/interoptest/grpc_interop_python/Dockerfile
@@ -62,7 +62,7 @@
 # Install Python packages from PyPI
 RUN pip install --upgrade pip==9.0.1
 RUN pip install virtualenv
-RUN pip install futures==2.2.0 enum34==1.0.4 protobuf==3.2.0 six==1.10.0 twisted==17.5.0
+RUN pip install futures==2.2.0 enum34==1.0.4 protobuf==3.5.0.post1 six==1.10.0 twisted==17.5.0
 
 # Prepare ccache
 RUN ln -s /usr/bin/ccache /usr/local/bin/gcc
diff --git a/tools/dockerfile/interoptest/grpc_interop_ruby/Dockerfile b/tools/dockerfile/interoptest/grpc_interop_ruby/Dockerfile
index 2217b10..543e207 100644
--- a/tools/dockerfile/interoptest/grpc_interop_ruby/Dockerfile
+++ b/tools/dockerfile/interoptest/grpc_interop_ruby/Dockerfile
@@ -62,7 +62,7 @@
 # Install Python packages from PyPI
 RUN pip install --upgrade pip==9.0.1
 RUN pip install virtualenv
-RUN pip install futures==2.2.0 enum34==1.0.4 protobuf==3.2.0 six==1.10.0 twisted==17.5.0
+RUN pip install futures==2.2.0 enum34==1.0.4 protobuf==3.5.0.post1 six==1.10.0 twisted==17.5.0
 
 #==================
 # Ruby dependencies
diff --git a/tools/dockerfile/test/csharp_jessie_x64/Dockerfile b/tools/dockerfile/test/csharp_jessie_x64/Dockerfile
index 3e31e67..0fae21d 100644
--- a/tools/dockerfile/test/csharp_jessie_x64/Dockerfile
+++ b/tools/dockerfile/test/csharp_jessie_x64/Dockerfile
@@ -66,7 +66,7 @@
 # Install Python packages from PyPI
 RUN pip install --upgrade pip==9.0.1
 RUN pip install virtualenv
-RUN pip install futures==2.2.0 enum34==1.0.4 protobuf==3.2.0 six==1.10.0 twisted==17.5.0
+RUN pip install futures==2.2.0 enum34==1.0.4 protobuf==3.5.0.post1 six==1.10.0 twisted==17.5.0
 
 #================
 # C# dependencies
diff --git a/tools/dockerfile/test/cxx_alpine_x64/Dockerfile b/tools/dockerfile/test/cxx_alpine_x64/Dockerfile
index af5e7d6..13a0ea1 100644
--- a/tools/dockerfile/test/cxx_alpine_x64/Dockerfile
+++ b/tools/dockerfile/test/cxx_alpine_x64/Dockerfile
@@ -38,7 +38,7 @@
 # Install Python packages from PyPI
 RUN pip install --upgrade pip==9.0.1
 RUN pip install virtualenv
-RUN pip install futures==2.2.0 enum34==1.0.4 protobuf==3.2.0 six==1.10.0
+RUN pip install futures==2.2.0 enum34==1.0.4 protobuf==3.5.0.post1 six==1.10.0
 
 # Google Cloud platform API libraries
 RUN pip install --upgrade google-api-python-client
diff --git a/tools/dockerfile/test/cxx_jessie_x64/Dockerfile b/tools/dockerfile/test/cxx_jessie_x64/Dockerfile
index 3492dd7..dff4c96 100644
--- a/tools/dockerfile/test/cxx_jessie_x64/Dockerfile
+++ b/tools/dockerfile/test/cxx_jessie_x64/Dockerfile
@@ -66,7 +66,7 @@
 # Install Python packages from PyPI
 RUN pip install --upgrade pip==9.0.1
 RUN pip install virtualenv
-RUN pip install futures==2.2.0 enum34==1.0.4 protobuf==3.2.0 six==1.10.0 twisted==17.5.0
+RUN pip install futures==2.2.0 enum34==1.0.4 protobuf==3.5.0.post1 six==1.10.0 twisted==17.5.0
 
 #=================
 # C++ dependencies
diff --git a/tools/dockerfile/test/cxx_jessie_x86/Dockerfile b/tools/dockerfile/test/cxx_jessie_x86/Dockerfile
index f8cbf35..ea1d645 100644
--- a/tools/dockerfile/test/cxx_jessie_x86/Dockerfile
+++ b/tools/dockerfile/test/cxx_jessie_x86/Dockerfile
@@ -66,7 +66,7 @@
 # Install Python packages from PyPI
 RUN pip install --upgrade pip==9.0.1
 RUN pip install virtualenv
-RUN pip install futures==2.2.0 enum34==1.0.4 protobuf==3.2.0 six==1.10.0 twisted==17.5.0
+RUN pip install futures==2.2.0 enum34==1.0.4 protobuf==3.5.0.post1 six==1.10.0 twisted==17.5.0
 
 #=================
 # C++ dependencies
diff --git a/tools/dockerfile/test/cxx_ubuntu1404_x64/Dockerfile b/tools/dockerfile/test/cxx_ubuntu1404_x64/Dockerfile
index 6966d6b..990dac9 100644
--- a/tools/dockerfile/test/cxx_ubuntu1404_x64/Dockerfile
+++ b/tools/dockerfile/test/cxx_ubuntu1404_x64/Dockerfile
@@ -66,7 +66,7 @@
 # Install Python packages from PyPI
 RUN pip install --upgrade pip==9.0.1
 RUN pip install virtualenv
-RUN pip install futures==2.2.0 enum34==1.0.4 protobuf==3.2.0 six==1.10.0 twisted==17.5.0
+RUN pip install futures==2.2.0 enum34==1.0.4 protobuf==3.5.0.post1 six==1.10.0 twisted==17.5.0
 
 #=================
 # C++ dependencies
diff --git a/tools/dockerfile/test/cxx_ubuntu1604_x64/Dockerfile b/tools/dockerfile/test/cxx_ubuntu1604_x64/Dockerfile
index 016034a..c8943ca 100644
--- a/tools/dockerfile/test/cxx_ubuntu1604_x64/Dockerfile
+++ b/tools/dockerfile/test/cxx_ubuntu1604_x64/Dockerfile
@@ -66,7 +66,7 @@
 # Install Python packages from PyPI
 RUN pip install --upgrade pip==9.0.1
 RUN pip install virtualenv
-RUN pip install futures==2.2.0 enum34==1.0.4 protobuf==3.2.0 six==1.10.0 twisted==17.5.0
+RUN pip install futures==2.2.0 enum34==1.0.4 protobuf==3.5.0.post1 six==1.10.0 twisted==17.5.0
 
 #=================
 # C++ dependencies
diff --git a/tools/dockerfile/test/fuzzer/Dockerfile b/tools/dockerfile/test/fuzzer/Dockerfile
index 50104ad..52666ea 100644
--- a/tools/dockerfile/test/fuzzer/Dockerfile
+++ b/tools/dockerfile/test/fuzzer/Dockerfile
@@ -66,7 +66,7 @@
 # Install Python packages from PyPI
 RUN pip install --upgrade pip==9.0.1
 RUN pip install virtualenv
-RUN pip install futures==2.2.0 enum34==1.0.4 protobuf==3.2.0 six==1.10.0 twisted==17.5.0
+RUN pip install futures==2.2.0 enum34==1.0.4 protobuf==3.5.0.post1 six==1.10.0 twisted==17.5.0
 
 #=================
 # C++ dependencies
diff --git a/tools/dockerfile/test/multilang_jessie_x64/Dockerfile b/tools/dockerfile/test/multilang_jessie_x64/Dockerfile
index 8e29fcb..362c061 100644
--- a/tools/dockerfile/test/multilang_jessie_x64/Dockerfile
+++ b/tools/dockerfile/test/multilang_jessie_x64/Dockerfile
@@ -141,7 +141,7 @@
 # Install Python packages from PyPI
 RUN pip install --upgrade pip==9.0.1
 RUN pip install virtualenv
-RUN pip install futures==2.2.0 enum34==1.0.4 protobuf==3.2.0 six==1.10.0 twisted==17.5.0
+RUN pip install futures==2.2.0 enum34==1.0.4 protobuf==3.5.0.post1 six==1.10.0 twisted==17.5.0
 
 # Install coverage for Python test coverage reporting
 RUN pip install coverage
diff --git a/tools/dockerfile/test/node_jessie_x64/Dockerfile b/tools/dockerfile/test/node_jessie_x64/Dockerfile
index d0e5af6..9f19e76 100644
--- a/tools/dockerfile/test/node_jessie_x64/Dockerfile
+++ b/tools/dockerfile/test/node_jessie_x64/Dockerfile
@@ -77,7 +77,7 @@
 # Install Python packages from PyPI
 RUN pip install --upgrade pip==9.0.1
 RUN pip install virtualenv
-RUN pip install futures==2.2.0 enum34==1.0.4 protobuf==3.2.0 six==1.10.0 twisted==17.5.0
+RUN pip install futures==2.2.0 enum34==1.0.4 protobuf==3.5.0.post1 six==1.10.0 twisted==17.5.0
 
 #==================
 # Node dependencies
diff --git a/tools/dockerfile/test/php7_jessie_x64/Dockerfile b/tools/dockerfile/test/php7_jessie_x64/Dockerfile
index 1399502..865bf69 100644
--- a/tools/dockerfile/test/php7_jessie_x64/Dockerfile
+++ b/tools/dockerfile/test/php7_jessie_x64/Dockerfile
@@ -77,7 +77,7 @@
 # Install Python packages from PyPI
 RUN pip install --upgrade pip==9.0.1
 RUN pip install virtualenv
-RUN pip install futures==2.2.0 enum34==1.0.4 protobuf==3.2.0 six==1.10.0 twisted==17.5.0
+RUN pip install futures==2.2.0 enum34==1.0.4 protobuf==3.5.0.post1 six==1.10.0 twisted==17.5.0
 
 # Prepare ccache
 RUN ln -s /usr/bin/ccache /usr/local/bin/gcc
diff --git a/tools/dockerfile/test/php_jessie_x64/Dockerfile b/tools/dockerfile/test/php_jessie_x64/Dockerfile
index 56dc604..fb653d3 100644
--- a/tools/dockerfile/test/php_jessie_x64/Dockerfile
+++ b/tools/dockerfile/test/php_jessie_x64/Dockerfile
@@ -66,7 +66,7 @@
 # Install Python packages from PyPI
 RUN pip install --upgrade pip==9.0.1
 RUN pip install virtualenv
-RUN pip install futures==2.2.0 enum34==1.0.4 protobuf==3.2.0 six==1.10.0 twisted==17.5.0
+RUN pip install futures==2.2.0 enum34==1.0.4 protobuf==3.5.0.post1 six==1.10.0 twisted==17.5.0
 
 #=================
 # PHP dependencies
diff --git a/tools/dockerfile/test/python_alpine_x64/Dockerfile b/tools/dockerfile/test/python_alpine_x64/Dockerfile
index 7584ab8..87acef9 100644
--- a/tools/dockerfile/test/python_alpine_x64/Dockerfile
+++ b/tools/dockerfile/test/python_alpine_x64/Dockerfile
@@ -38,7 +38,7 @@
 # Install Python packages from PyPI
 RUN pip install --upgrade pip==9.0.1
 RUN pip install virtualenv
-RUN pip install futures==2.2.0 enum34==1.0.4 protobuf==3.2.0 six==1.10.0
+RUN pip install futures==2.2.0 enum34==1.0.4 protobuf==3.5.0.post1 six==1.10.0
 
 # Google Cloud platform API libraries
 RUN pip install --upgrade google-api-python-client
diff --git a/tools/dockerfile/test/python_jessie_x64/Dockerfile b/tools/dockerfile/test/python_jessie_x64/Dockerfile
index 8d89f50..914e343 100644
--- a/tools/dockerfile/test/python_jessie_x64/Dockerfile
+++ b/tools/dockerfile/test/python_jessie_x64/Dockerfile
@@ -66,7 +66,7 @@
 # Install Python packages from PyPI
 RUN pip install --upgrade pip==9.0.1
 RUN pip install virtualenv
-RUN pip install futures==2.2.0 enum34==1.0.4 protobuf==3.2.0 six==1.10.0 twisted==17.5.0
+RUN pip install futures==2.2.0 enum34==1.0.4 protobuf==3.5.0.post1 six==1.10.0 twisted==17.5.0
 
 # Prepare ccache
 RUN ln -s /usr/bin/ccache /usr/local/bin/gcc
diff --git a/tools/dockerfile/test/python_pyenv_x64/Dockerfile b/tools/dockerfile/test/python_pyenv_x64/Dockerfile
index f8cbdc5..379f26a 100644
--- a/tools/dockerfile/test/python_pyenv_x64/Dockerfile
+++ b/tools/dockerfile/test/python_pyenv_x64/Dockerfile
@@ -66,7 +66,7 @@
 # Install Python packages from PyPI
 RUN pip install --upgrade pip==9.0.1
 RUN pip install virtualenv
-RUN pip install futures==2.2.0 enum34==1.0.4 protobuf==3.2.0 six==1.10.0 twisted==17.5.0
+RUN pip install futures==2.2.0 enum34==1.0.4 protobuf==3.5.0.post1 six==1.10.0 twisted==17.5.0
 
 # Install dependencies for pyenv
 RUN apt-get update && apt-get install -y \
diff --git a/tools/dockerfile/test/ruby_jessie_x64/Dockerfile b/tools/dockerfile/test/ruby_jessie_x64/Dockerfile
index 5d7f80b..63e42fd 100644
--- a/tools/dockerfile/test/ruby_jessie_x64/Dockerfile
+++ b/tools/dockerfile/test/ruby_jessie_x64/Dockerfile
@@ -66,7 +66,7 @@
 # Install Python packages from PyPI
 RUN pip install --upgrade pip==9.0.1
 RUN pip install virtualenv
-RUN pip install futures==2.2.0 enum34==1.0.4 protobuf==3.2.0 six==1.10.0 twisted==17.5.0
+RUN pip install futures==2.2.0 enum34==1.0.4 protobuf==3.5.0.post1 six==1.10.0 twisted==17.5.0
 
 #==================
 # Ruby dependencies
diff --git a/tools/dockerfile/test/sanity/Dockerfile b/tools/dockerfile/test/sanity/Dockerfile
index 967e813..e4a2972 100644
--- a/tools/dockerfile/test/sanity/Dockerfile
+++ b/tools/dockerfile/test/sanity/Dockerfile
@@ -66,7 +66,7 @@
 # Install Python packages from PyPI
 RUN pip install --upgrade pip==9.0.1
 RUN pip install virtualenv
-RUN pip install futures==2.2.0 enum34==1.0.4 protobuf==3.2.0 six==1.10.0 twisted==17.5.0
+RUN pip install futures==2.2.0 enum34==1.0.4 protobuf==3.5.0.post1 six==1.10.0 twisted==17.5.0
 
 #=================
 # C++ dependencies
diff --git a/tools/doxygen/Doxyfile.c++ b/tools/doxygen/Doxyfile.c++
index eb27eed..e62278c 100644
--- a/tools/doxygen/Doxyfile.c++
+++ b/tools/doxygen/Doxyfile.c++
@@ -40,7 +40,7 @@
 # could be handy for archiving the generated documentation or if some version
 # control system is used.
 
-PROJECT_NUMBER         = 1.8.0-dev
+PROJECT_NUMBER         = 1.9.0-dev
 
 # Using the PROJECT_BRIEF tag one can provide an optional one line description
 # for a project that appears at the top of each page and should give viewer a
@@ -875,6 +875,7 @@
 include/grpc/byte_buffer.h \
 include/grpc/byte_buffer_reader.h \
 include/grpc/compression.h \
+include/grpc/fork.h \
 include/grpc/grpc.h \
 include/grpc/grpc_posix.h \
 include/grpc/grpc_security_constants.h \
@@ -887,6 +888,7 @@
 include/grpc/impl/codegen/compression_types.h \
 include/grpc/impl/codegen/connectivity_state.h \
 include/grpc/impl/codegen/exec_ctx_fwd.h \
+include/grpc/impl/codegen/fork.h \
 include/grpc/impl/codegen/gpr_slice.h \
 include/grpc/impl/codegen/gpr_types.h \
 include/grpc/impl/codegen/grpc_types.h \
@@ -911,7 +913,6 @@
 include/grpc/support/avl.h \
 include/grpc/support/cmdline.h \
 include/grpc/support/cpu.h \
-include/grpc/support/histogram.h \
 include/grpc/support/host_port.h \
 include/grpc/support/log.h \
 include/grpc/support/log_windows.h \
diff --git a/tools/doxygen/Doxyfile.c++.internal b/tools/doxygen/Doxyfile.c++.internal
index c9c6439..d09b325 100644
--- a/tools/doxygen/Doxyfile.c++.internal
+++ b/tools/doxygen/Doxyfile.c++.internal
@@ -40,7 +40,7 @@
 # could be handy for archiving the generated documentation or if some version
 # control system is used.
 
-PROJECT_NUMBER         = 1.8.0-dev
+PROJECT_NUMBER         = 1.9.0-dev
 
 # Using the PROJECT_BRIEF tag one can provide an optional one line description
 # for a project that appears at the top of each page and should give viewer a
@@ -876,6 +876,7 @@
 include/grpc/byte_buffer.h \
 include/grpc/byte_buffer_reader.h \
 include/grpc/compression.h \
+include/grpc/fork.h \
 include/grpc/grpc.h \
 include/grpc/grpc_posix.h \
 include/grpc/grpc_security_constants.h \
@@ -888,6 +889,7 @@
 include/grpc/impl/codegen/compression_types.h \
 include/grpc/impl/codegen/connectivity_state.h \
 include/grpc/impl/codegen/exec_ctx_fwd.h \
+include/grpc/impl/codegen/fork.h \
 include/grpc/impl/codegen/gpr_slice.h \
 include/grpc/impl/codegen/gpr_types.h \
 include/grpc/impl/codegen/grpc_types.h \
@@ -912,7 +914,6 @@
 include/grpc/support/avl.h \
 include/grpc/support/cmdline.h \
 include/grpc/support/cpu.h \
-include/grpc/support/histogram.h \
 include/grpc/support/host_port.h \
 include/grpc/support/log.h \
 include/grpc/support/log_windows.h \
@@ -1026,22 +1027,26 @@
 src/core/lib/slice/slice_hash_table.h \
 src/core/lib/slice/slice_internal.h \
 src/core/lib/slice/slice_string_helpers.h \
+src/core/lib/support/abstract.h \
 src/core/lib/support/arena.h \
 src/core/lib/support/atomic.h \
 src/core/lib/support/atomic_with_atm.h \
 src/core/lib/support/atomic_with_std.h \
+src/core/lib/support/debug_location.h \
 src/core/lib/support/env.h \
+src/core/lib/support/fork.h \
 src/core/lib/support/manual_constructor.h \
 src/core/lib/support/memory.h \
 src/core/lib/support/mpscq.h \
 src/core/lib/support/murmur_hash.h \
+src/core/lib/support/ref_counted.h \
+src/core/lib/support/ref_counted_ptr.h \
 src/core/lib/support/spinlock.h \
-src/core/lib/support/stack_lockfree.h \
 src/core/lib/support/string.h \
 src/core/lib/support/string_windows.h \
+src/core/lib/support/thd_internal.h \
 src/core/lib/support/time_precise.h \
 src/core/lib/support/tmpfile.h \
-src/core/lib/support/vector.h \
 src/core/lib/surface/alarm_internal.h \
 src/core/lib/surface/api_trace.h \
 src/core/lib/surface/call.h \
diff --git a/tools/doxygen/Doxyfile.core b/tools/doxygen/Doxyfile.core
index c8fd2ee..6ce9041 100644
--- a/tools/doxygen/Doxyfile.core
+++ b/tools/doxygen/Doxyfile.core
@@ -774,6 +774,7 @@
 doc/core/grpc-error.md \
 doc/core/moving-to-c++.md \
 doc/core/pending_api_cleanups.md \
+doc/core/transport_explainer.md \
 doc/cpp-style-guide.md \
 doc/environment_variables.md \
 doc/epoll-polling-engine.md \
@@ -800,6 +801,7 @@
 include/grpc/byte_buffer_reader.h \
 include/grpc/census.h \
 include/grpc/compression.h \
+include/grpc/fork.h \
 include/grpc/grpc.h \
 include/grpc/grpc_posix.h \
 include/grpc/grpc_security.h \
@@ -817,6 +819,8 @@
 include/grpc/impl/codegen/compression_types.h \
 include/grpc/impl/codegen/connectivity_state.h \
 include/grpc/impl/codegen/exec_ctx_fwd.h \
+include/grpc/impl/codegen/fork.h \
+include/grpc/impl/codegen/fork.h \
 include/grpc/impl/codegen/gpr_slice.h \
 include/grpc/impl/codegen/gpr_slice.h \
 include/grpc/impl/codegen/gpr_types.h \
@@ -849,7 +853,6 @@
 include/grpc/support/avl.h \
 include/grpc/support/cmdline.h \
 include/grpc/support/cpu.h \
-include/grpc/support/histogram.h \
 include/grpc/support/host_port.h \
 include/grpc/support/log.h \
 include/grpc/support/log_windows.h \
diff --git a/tools/doxygen/Doxyfile.core.internal b/tools/doxygen/Doxyfile.core.internal
index b8434bb..1aff007 100644
--- a/tools/doxygen/Doxyfile.core.internal
+++ b/tools/doxygen/Doxyfile.core.internal
@@ -774,6 +774,7 @@
 doc/core/grpc-error.md \
 doc/core/moving-to-c++.md \
 doc/core/pending_api_cleanups.md \
+doc/core/transport_explainer.md \
 doc/cpp-style-guide.md \
 doc/environment_variables.md \
 doc/epoll-polling-engine.md \
@@ -800,6 +801,7 @@
 include/grpc/byte_buffer_reader.h \
 include/grpc/census.h \
 include/grpc/compression.h \
+include/grpc/fork.h \
 include/grpc/grpc.h \
 include/grpc/grpc_posix.h \
 include/grpc/grpc_security.h \
@@ -817,6 +819,8 @@
 include/grpc/impl/codegen/compression_types.h \
 include/grpc/impl/codegen/connectivity_state.h \
 include/grpc/impl/codegen/exec_ctx_fwd.h \
+include/grpc/impl/codegen/fork.h \
+include/grpc/impl/codegen/fork.h \
 include/grpc/impl/codegen/gpr_slice.h \
 include/grpc/impl/codegen/gpr_slice.h \
 include/grpc/impl/codegen/gpr_types.h \
@@ -849,7 +853,6 @@
 include/grpc/support/avl.h \
 include/grpc/support/cmdline.h \
 include/grpc/support/cpu.h \
-include/grpc/support/histogram.h \
 include/grpc/support/host_port.h \
 include/grpc/support/log.h \
 include/grpc/support/log_windows.h \
@@ -1100,6 +1103,8 @@
 src/core/lib/iomgr/exec_ctx.h \
 src/core/lib/iomgr/executor.cc \
 src/core/lib/iomgr/executor.h \
+src/core/lib/iomgr/fork_posix.cc \
+src/core/lib/iomgr/fork_windows.cc \
 src/core/lib/iomgr/gethostname.h \
 src/core/lib/iomgr/gethostname_fallback.cc \
 src/core/lib/iomgr/gethostname_host_name_max.cc \
@@ -1267,6 +1272,7 @@
 src/core/lib/slice/slice_internal.h \
 src/core/lib/slice/slice_string_helpers.cc \
 src/core/lib/slice/slice_string_helpers.h \
+src/core/lib/support/abstract.h \
 src/core/lib/support/alloc.cc \
 src/core/lib/support/arena.cc \
 src/core/lib/support/arena.h \
@@ -1280,11 +1286,13 @@
 src/core/lib/support/cpu_linux.cc \
 src/core/lib/support/cpu_posix.cc \
 src/core/lib/support/cpu_windows.cc \
+src/core/lib/support/debug_location.h \
 src/core/lib/support/env.h \
 src/core/lib/support/env_linux.cc \
 src/core/lib/support/env_posix.cc \
 src/core/lib/support/env_windows.cc \
-src/core/lib/support/histogram.cc \
+src/core/lib/support/fork.cc \
+src/core/lib/support/fork.h \
 src/core/lib/support/host_port.cc \
 src/core/lib/support/log.cc \
 src/core/lib/support/log_android.cc \
@@ -1297,9 +1305,9 @@
 src/core/lib/support/mpscq.h \
 src/core/lib/support/murmur_hash.cc \
 src/core/lib/support/murmur_hash.h \
+src/core/lib/support/ref_counted.h \
+src/core/lib/support/ref_counted_ptr.h \
 src/core/lib/support/spinlock.h \
-src/core/lib/support/stack_lockfree.cc \
-src/core/lib/support/stack_lockfree.h \
 src/core/lib/support/string.cc \
 src/core/lib/support/string.h \
 src/core/lib/support/string_posix.cc \
@@ -1312,6 +1320,7 @@
 src/core/lib/support/sync_posix.cc \
 src/core/lib/support/sync_windows.cc \
 src/core/lib/support/thd.cc \
+src/core/lib/support/thd_internal.h \
 src/core/lib/support/thd_posix.cc \
 src/core/lib/support/thd_windows.cc \
 src/core/lib/support/time.cc \
@@ -1324,7 +1333,6 @@
 src/core/lib/support/tmpfile_msys.cc \
 src/core/lib/support/tmpfile_posix.cc \
 src/core/lib/support/tmpfile_windows.cc \
-src/core/lib/support/vector.h \
 src/core/lib/support/wrap_memcpy.cc \
 src/core/lib/surface/README.md \
 src/core/lib/surface/alarm.cc \
diff --git a/tools/gce/linux_kokoro_performance_worker_init.sh b/tools/gce/linux_kokoro_performance_worker_init.sh
index ac3d393..460f639 100755
--- a/tools/gce/linux_kokoro_performance_worker_init.sh
+++ b/tools/gce/linux_kokoro_performance_worker_init.sh
@@ -114,6 +114,19 @@
 sudo apt-get install -y dotnet-dev-1.0.0-preview2.1-003155
 sudo apt-get install -y dotnet-dev-1.0.1
 
+# C# 1.0.4 SDK
+curl -O https://download.microsoft.com/download/2/4/A/24A06858-E8AC-469B-8AE6-D0CEC9BA982A/dotnet-ubuntu.16.04-x64.1.0.5.tar.gz
+sudo mkdir -p /opt/dotnet
+sudo tar zxf dotnet-ubuntu.16.04-x64.1.0.5.tar.gz -C /opt/dotnet
+sudo ln -s /opt/dotnet/dotnet /usr/local/bin
+
+# C# .NET dependencies
+wget http://security.ubuntu.com/ubuntu/pool/main/i/icu/libicu52_52.1-8ubuntu0.2_amd64.deb
+sudo dpkg -i libicu52_52.1-8ubuntu0.2_amd64.deb
+wget http://security.ubuntu.com/ubuntu/pool/main/i/icu/libicu55_55.1-7ubuntu0.3_amd64.deb
+sudo dpkg -i libicu55_55.1-7ubuntu0.3_amd64.deb
+sudo apt-get update && sudo apt-get install -y libicu55
+
 # Ruby dependencies
 gpg --keyserver hkp://keys.gnupg.net --recv-keys 409B6B1796C275462A1703113804BB82D39DC0E3
 curl -sSL https://get.rvm.io | bash -s stable --ruby
diff --git a/tools/internal_ci/helper_scripts/prepare_build_linux_perf_multilang_rc b/tools/internal_ci/helper_scripts/prepare_build_linux_perf_multilang_rc
new file mode 100644
index 0000000..f1031ae
--- /dev/null
+++ b/tools/internal_ci/helper_scripts/prepare_build_linux_perf_multilang_rc
@@ -0,0 +1,40 @@
+#!/bin/bash
+# Copyright 2017 gRPC authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Source this rc script to prepare the environment for linux perf builds
+
+# Need to increase open files limit and size for perf test
+ulimit -n 32768
+ulimit -c unlimited
+
+# Download non-core gRPC repos
+git clone --recursive https://github.com/grpc/grpc-go ./../grpc-go
+git clone --recursive https://github.com/grpc/grpc-java ./../grpc-java
+git clone --recursive https://github.com/grpc/grpc-node ./../grpc-node
+
+sudo pip install tabulate
+
+# Set up Ruby
+export PATH="$HOME/.rbenv/bin:$PATH"
+eval "$(rbenv init -)"
+gem list bundler
+gem install bundler --no-ri --no-rdoc
+
+# Allow SSH to Kokoro performance workers without explicit key verification
+gsutil cp gs://grpc-testing-secrets/grpc_kokoro_performance_ssh_keys/id_rsa ~/.ssh
+echo -e 'Host grpc-kokoro-performance*\n\tStrictHostKeyChecking no' >> ~/.ssh/config
+chmod 600 ~/.ssh/id_rsa ~/.ssh/config
+
+git submodule update --init
diff --git a/tools/internal_ci/linux/grpc_bazel_on_foundry.sh b/tools/internal_ci/linux/grpc_bazel_on_foundry.sh
new file mode 100644
index 0000000..e328be8
--- /dev/null
+++ b/tools/internal_ci/linux/grpc_bazel_on_foundry.sh
@@ -0,0 +1,55 @@
+#!/usr/bin/env bash
+# Copyright 2017 gRPC authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+set -ex
+
+# A temporary solution to give Kokoro credentials. 
+# The file name 4321_grpc-testing-service needs to match auth_credential in 
+# the build config.
+mkdir -p ${KOKORO_KEYSTORE_DIR}
+cp ${KOKORO_GFILE_DIR}/GrpcTesting-d0eeee2db331.json ${KOKORO_KEYSTORE_DIR}/4321_grpc-testing-service
+
+mkdir -p /tmpfs/tmp/bazel-canary
+ln -f "${KOKORO_GFILE_DIR}/bazel-canary" /tmpfs/tmp/bazel-canary/bazel
+chmod 755 "${KOKORO_GFILE_DIR}/bazel-canary"
+export PATH="/tmpfs/tmp/bazel-canary:${PATH}"
+# This should show /tmpfs/tmp/bazel-canary/bazel
+which bazel
+chmod +x "${KOKORO_GFILE_DIR}/bazel_wrapper.py"
+
+# change to grpc repo root
+cd $(dirname $0)/../../..
+
+source tools/internal_ci/helper_scripts/prepare_build_linux_rc
+
+"${KOKORO_GFILE_DIR}/bazel_wrapper.py" \
+  --host_jvm_args=-Dbazel.DigestFunction=SHA1 \
+  test --jobs="50" \
+  --test_timeout="300,450,1200,3600" \
+  --test_output=errors  \
+  --verbose_failures=true  \
+  --keep_going  \
+  --remote_accept_cached=true  \
+  --spawn_strategy=remote  \
+  --remote_local_fallback=false  \
+  --remote_timeout=3600  \
+  --strategy=Javac=remote  \
+  --strategy=Closure=remote  \
+  --genrule_strategy=remote  \
+  --experimental_strict_action_env=true \
+  --experimental_remote_platform_override='properties:{name:"container-image" value:"docker://gcr.io/asci-toolchain/nosla-debian8-clang-fl@sha256:aa20628a902f06a11a015caa94b0432eb60690de2d2525bd046b9eea046f5d8a" }' \
+  --crosstool_top=@bazel_toolchains//configs/debian8_clang/0.2.0/bazel_0.7.0:toolchain \
+  --define GRPC_PORT_ISOLATED_RUNTIME=1 \
+  -- //test/...
diff --git a/tools/internal_ci/linux/grpc_full_performance_master.cfg b/tools/internal_ci/linux/grpc_full_performance_master.cfg
new file mode 100644
index 0000000..8852130
--- /dev/null
+++ b/tools/internal_ci/linux/grpc_full_performance_master.cfg
@@ -0,0 +1,25 @@
+# Copyright 2017 gRPC authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Config file for the internal CI (in protobuf text format)
+
+# Location of the continuous shell script in repository.
+build_file: "grpc/tools/internal_ci/linux/grpc_full_performance_master.sh"
+timeout_mins: 600
+action {
+  define_artifacts {
+    regex: "**/*sponge_log.xml"
+    regex: "**/perf_reports/**"
+  }
+}
diff --git a/tools/internal_ci/linux/grpc_full_performance_master.sh b/tools/internal_ci/linux/grpc_full_performance_master.sh
new file mode 100755
index 0000000..1846839
--- /dev/null
+++ b/tools/internal_ci/linux/grpc_full_performance_master.sh
@@ -0,0 +1,59 @@
+#!/usr/bin/env bash
+# Copyright 2017 gRPC authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+set -ex
+
+# Enter the gRPC repo root
+cd $(dirname $0)/../../..
+
+source tools/internal_ci/helper_scripts/prepare_build_linux_perf_multilang_rc
+
+# run 8core client vs 8core server
+tools/run_tests/run_performance_tests.py \
+    -l c++ csharp ruby java python go php7 php7_protobuf_c \
+    --netperf \
+    --category scalable \
+    --remote_worker_host grpc-kokoro-performance-server-8core grpc-kokoro-performance-client-8core grpc-kokoro-performance-client2-8core \
+    -u kbuilder \
+    --bq_result_table performance_test.kokoro_performance_experiment \
+    --xml_report reports/8core/sponge_log.xml \
+    || EXIT_CODE=1
+
+# prevent pushing leftover build files to remote hosts in the next step.
+git clean -fdxq -e reports
+
+# scalability with 32cores (and upload to a different BQ table)
+tools/run_tests/run_performance_tests.py \
+    -l c++ java csharp go \
+    --netperf \
+    --category scalable \
+    --remote_worker_host grpc-kokoro-performance-server-32core grpc-kokoro-performance-client-32core grpc-kokoro-performance-client2-32core \
+    -u kbuilder \
+    --bq_result_table performance_test.kokoro_performance_experiment_32core \
+    --xml_report reports/32core/sponge_log.xml \
+    || EXIT_CODE=1
+
+# prevent pushing leftover build files to remote hosts in the next step.
+git clean -fdxq -e reports
+
+# selected scenarios on Windows
+tools/run_tests/run_performance_tests.py \
+    -l csharp \
+    --category scalable \
+    --remote_worker_host grpc-kokoro-performance-windows1 grpc-kokoro-performance-windows2 \
+    --bq_result_table performance_test.kokoro_performance_experiment_windows \
+    --xml_report reports/windows/sponge_log.xml \
+    || EXIT_CODE=1
+
+exit $EXIT_CODE
diff --git a/tools/internal_ci/linux/grpc_interop_matrix.cfg b/tools/internal_ci/linux/grpc_interop_matrix.cfg
index a7fd479..71e930e 100644
--- a/tools/internal_ci/linux/grpc_interop_matrix.cfg
+++ b/tools/internal_ci/linux/grpc_interop_matrix.cfg
@@ -17,7 +17,7 @@
 # Location of the continuous shell script in repository.
 build_file: "grpc/tools/internal_ci/linux/grpc_interop_matrix.sh"
 # grpc_interop tests can take 1 hours to complete.
-timeout_mins: 60
+timeout_mins: 120
 action {
   define_artifacts {
     regex: "**/sponge_log.xml"
diff --git a/tools/interop_matrix/README.md b/tools/interop_matrix/README.md
index 588afe4..40c02a1 100644
--- a/tools/interop_matrix/README.md
+++ b/tools/interop_matrix/README.md
@@ -8,8 +8,8 @@
 ## Step-by-step instructions for adding a GCR image for a new release for compatibility test
 We have continuous nightly test setup to test gRPC backward compatibility between old clients and latest server.  When a gRPC developer creates a new gRPC release, s/he is also responsible to add the just-released gRPC client to the nightly test.  The steps are:
 - Add (or update) an entry in `./client_matrix.py` file to reference the github tag for the release.
-- Build new client docker image(s).  For example, for java release `v1.9.9`, do
-  - `tools/interop_matrix/create_matrix_images.py --git_checkout --release=v1.9.9 --language=java`
+- Build new client docker image(s).  For example, for C and wrapper languages release `v1.9.9`, do
+  - `tools/interop_matrix/create_matrix_images.py --git_checkout --release=v1.9.9 --language cxx csharp python ruby php`
 - Verify that the new docker image was built successfully and uploaded to GCR.  For example,
   - `gcloud beta container images list --repository gcr.io/grpc-testing` shows image repos.
   - `gcloud beta container images list-tags gcr.io/grpc-testing/grpc_interop_java_oracle8` should show an image entry with tag `v1.9.9`.
diff --git a/tools/interop_matrix/client_matrix.py b/tools/interop_matrix/client_matrix.py
index c8dbb3a..c9a4996 100644
--- a/tools/interop_matrix/client_matrix.py
+++ b/tools/interop_matrix/client_matrix.py
@@ -19,6 +19,7 @@
   return {
       'go': 'git@github.com:grpc/grpc-go.git',
       'java': 'git@github.com:grpc/grpc-java.git',
+      'node': 'git@github.com:grpc/grpc-node.git',
       # all other languages use the grpc.git repo.
   }.get(lang, 'git@github.com:grpc/grpc.git')
 
@@ -44,6 +45,7 @@
         'v1.3.9',
         'v1.4.2',
         'v1.6.6',
+        'v1.7.2',
     ],
     'go': [
         'v1.0.5',
@@ -53,6 +55,10 @@
         'v1.5.2',
         'v1.6.0',
         'v1.7.0',
+        'v1.7.1',
+        'v1.7.2',
+        'v1.7.3',
+        'v1.8.0',
     ],
     'java': [
         'v1.0.3',
@@ -63,6 +69,7 @@
         'v1.5.0',
         'v1.6.1',
         'v1.7.0',
+        'v1.8.0',
     ],
     'python': [
         'v1.0.x',
@@ -71,6 +78,7 @@
         'v1.3.9',
         'v1.4.2',
         'v1.6.6',
+        'v1.7.2',    
     ],
     'node': [
         'v1.0.1',
@@ -79,6 +87,7 @@
         'v1.3.9',
         'v1.4.2',
         'v1.6.6',
+        #'v1.7.1',  Failing tests.
     ],
     'ruby': [
         # Ruby v1.0.x doesn't have the fix #8914, therefore not supported.
@@ -87,6 +96,7 @@
         'v1.3.9',
         'v1.4.2',
         'v1.6.6',
+        'v1.7.2',
     ],
     'php': [
         'v1.0.1',
@@ -95,6 +105,7 @@
         'v1.3.9',
         'v1.4.2',
         'v1.6.6',
+        'v1.7.2',
     ],
    'csharp': [
         #'v1.0.1',
@@ -103,5 +114,6 @@
         'v1.3.9',
         'v1.4.2',
         'v1.6.6',
+        'v1.7.2',
     ],
 }
diff --git a/tools/interop_matrix/create_matrix_images.py b/tools/interop_matrix/create_matrix_images.py
index 21040ea..493a7d5 100755
--- a/tools/interop_matrix/create_matrix_images.py
+++ b/tools/interop_matrix/create_matrix_images.py
@@ -77,6 +77,15 @@
                   action='store_true',
                   help='keep the created local images after uploading to GCR')
 
+argp.add_argument('--reuse_git_root',
+                  default=False,
+                  action='store_const',
+                  const=True,                  
+                  help='reuse the repo dir. If False, the existing git root '
+                  'directory will removed before a clean checkout, because '
+                  'reusing the repo can cause git checkout error if you switch '
+                  'between releases.')
+
 
 args = argp.parse_args()
 
@@ -133,7 +142,7 @@
   }
   build_env.update(env)
   build_job = jobset.JobSpec(
-          cmdline=[os.path.join(stack_base, _IMAGE_BUILDER)],
+          cmdline=[_IMAGE_BUILDER],
           environ=build_env,
           shortname='build_docker_%s' % runtime,
           timeout_seconds=30*60)
@@ -227,6 +236,11 @@
   repo_dir = os.path.splitext(os.path.basename(repo))[0]
   stack_base = os.path.join(args.git_checkout_root, repo_dir)
 
+  # Clean up leftover repo dir if necessary.
+  if not args.reuse_git_root and os.path.exists(stack_base):
+    jobset.message('START', 'Removing git checkout root.', do_newline=True)
+    shutil.rmtree(stack_base)
+
   if not os.path.exists(stack_base):
     subprocess.check_call(['git', 'clone', '--recursive', repo],
                           cwd=os.path.dirname(stack_base))
diff --git a/tools/interop_matrix/run_interop_matrix_tests.py b/tools/interop_matrix/run_interop_matrix_tests.py
index dce1033..4265bc5 100755
--- a/tools/interop_matrix/run_interop_matrix_tests.py
+++ b/tools/interop_matrix/run_interop_matrix_tests.py
@@ -100,7 +100,7 @@
       jobset.message('SKIPPED',
                      '%s for %s is not defined' % (args.release, lang),
                      do_newline=True)
-      return []
+      return {}
     releases = [args.release]
 
   # Images tuples keyed by runtime.
diff --git a/tools/interop_matrix/testcases/node__v1.0.1 b/tools/interop_matrix/testcases/node__v1.0.1
index fca9821..6faf321 100644
--- a/tools/interop_matrix/testcases/node__v1.0.1
+++ b/tools/interop_matrix/testcases/node__v1.0.1
@@ -1,21 +1,21 @@
 #!/bin/bash
 echo "Testing ${docker_image:=grpc_interop_node:a53aa5e3-b548-4566-b5a8-6d15c1315b32}"
-docker run -i --rm=true -w /var/local/git/grpc --net=host --name interop_client_node_00c688f2-57da-4023-89f3-46b1f7b5869f $docker_image bash -l -c "node src/node/interop/interop_client.js --server_host=grpc-test.sandbox.googleapis.com --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=large_unary"
-docker run -i --rm=true -w /var/local/git/grpc --net=host --name interop_client_node_d86705d8-14ea-4024-90b6-de74d6e8d19c $docker_image bash -l -c "node src/node/interop/interop_client.js --server_host=grpc-test.sandbox.googleapis.com --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=empty_unary"
-docker run -i --rm=true -w /var/local/git/grpc --net=host --name interop_client_node_ebaafacd-1d82-4a75-bea1-a5c64e01fcaf $docker_image bash -l -c "node src/node/interop/interop_client.js --server_host=grpc-test.sandbox.googleapis.com --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=ping_pong"
-docker run -i --rm=true -w /var/local/git/grpc --net=host --name interop_client_node_5125241a-fbf6-4c1c-895b-026a5a41f02f $docker_image bash -l -c "node src/node/interop/interop_client.js --server_host=grpc-test.sandbox.googleapis.com --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=empty_stream"
-docker run -i --rm=true -w /var/local/git/grpc --net=host --name interop_client_node_3d5e5b82-7205-4eba-b775-8122f05a4760 $docker_image bash -l -c "node src/node/interop/interop_client.js --server_host=grpc-test.sandbox.googleapis.com --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=client_streaming"
-docker run -i --rm=true -w /var/local/git/grpc --net=host --name interop_client_node_16fa0b49-2083-4932-8f26-79cfdffec940 $docker_image bash -l -c "node src/node/interop/interop_client.js --server_host=grpc-test.sandbox.googleapis.com --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=server_streaming"
-docker run -i --rm=true -w /var/local/git/grpc --net=host --name interop_client_node_23cee670-2d8d-4f5c-8893-c3c43da8b03a $docker_image bash -l -c "node src/node/interop/interop_client.js --server_host=grpc-test.sandbox.googleapis.com --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=cancel_after_begin"
-docker run -i --rm=true -w /var/local/git/grpc --net=host --name interop_client_node_7b6a9454-e3b6-4993-b542-468e268930aa $docker_image bash -l -c "node src/node/interop/interop_client.js --server_host=grpc-test.sandbox.googleapis.com --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=cancel_after_first_response"
-docker run -i --rm=true -w /var/local/git/grpc --net=host --name interop_client_node_5a7109ed-c065-4b62-98f4-b3ed8f385762 $docker_image bash -l -c "node src/node/interop/interop_client.js --server_host=grpc-test.sandbox.googleapis.com --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=timeout_on_sleeping_server"
-docker run -i --rm=true -w /var/local/git/grpc --net=host --name interop_client_node_1e0ba8dd-4dc1-431b-b202-529e7ace5d1d $docker_image bash -l -c "node src/node/interop/interop_client.js --server_host=grpc-test4.sandbox.googleapis.com --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=large_unary"
-docker run -i --rm=true -w /var/local/git/grpc --net=host --name interop_client_node_649de56a-e722-4a59-b265-e9c0e871f068 $docker_image bash -l -c "node src/node/interop/interop_client.js --server_host=grpc-test4.sandbox.googleapis.com --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=empty_unary"
-docker run -i --rm=true -w /var/local/git/grpc --net=host --name interop_client_node_8be512a2-5e1c-4858-8cfc-82f99b678b76 $docker_image bash -l -c "node src/node/interop/interop_client.js --server_host=grpc-test4.sandbox.googleapis.com --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=ping_pong"
-docker run -i --rm=true -w /var/local/git/grpc --net=host --name interop_client_node_d19b6333-e528-48b5-8421-2ae3f7ce9dab $docker_image bash -l -c "node src/node/interop/interop_client.js --server_host=grpc-test4.sandbox.googleapis.com --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=empty_stream"
-docker run -i --rm=true -w /var/local/git/grpc --net=host --name interop_client_node_4749c80a-21c5-4d81-9df5-3c46ba6480cd $docker_image bash -l -c "node src/node/interop/interop_client.js --server_host=grpc-test4.sandbox.googleapis.com --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=client_streaming"
-docker run -i --rm=true -w /var/local/git/grpc --net=host --name interop_client_node_b7bee545-4857-4269-a1f2-9553dfc7e4b8 $docker_image bash -l -c "node src/node/interop/interop_client.js --server_host=grpc-test4.sandbox.googleapis.com --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=server_streaming"
-docker run -i --rm=true -w /var/local/git/grpc --net=host --name interop_client_node_4e96db87-6f48-426d-a7f0-97f3a5b6b3f4 $docker_image bash -l -c "node src/node/interop/interop_client.js --server_host=grpc-test4.sandbox.googleapis.com --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=cancel_after_begin"
-docker run -i --rm=true -w /var/local/git/grpc --net=host --name interop_client_node_31a1d58c-f8bf-460a-af60-28969ecaaf80 $docker_image bash -l -c "node src/node/interop/interop_client.js --server_host=grpc-test4.sandbox.googleapis.com --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=cancel_after_first_response"
-docker run -i --rm=true -w /var/local/git/grpc --net=host --name interop_client_node_ce64b147-bcfa-44b2-a2f7-4a485380ce30 $docker_image bash -l -c "node src/node/interop/interop_client.js --server_host=grpc-test4.sandbox.googleapis.com --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=timeout_on_sleeping_server"
+docker run -i --rm=true -w /var/local/git/grpc --net=host --name interop_client_node_00c688f2-57da-4023-89f3-46b1f7b5869f $docker_image bash -l -c "node src/node/interop/interop_client.js --server_host=216.239.32.254 --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=large_unary"
+docker run -i --rm=true -w /var/local/git/grpc --net=host --name interop_client_node_d86705d8-14ea-4024-90b6-de74d6e8d19c $docker_image bash -l -c "node src/node/interop/interop_client.js --server_host=216.239.32.254 --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=empty_unary"
+docker run -i --rm=true -w /var/local/git/grpc --net=host --name interop_client_node_ebaafacd-1d82-4a75-bea1-a5c64e01fcaf $docker_image bash -l -c "node src/node/interop/interop_client.js --server_host=216.239.32.254 --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=ping_pong"
+docker run -i --rm=true -w /var/local/git/grpc --net=host --name interop_client_node_5125241a-fbf6-4c1c-895b-026a5a41f02f $docker_image bash -l -c "node src/node/interop/interop_client.js --server_host=216.239.32.254 --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=empty_stream"
+docker run -i --rm=true -w /var/local/git/grpc --net=host --name interop_client_node_3d5e5b82-7205-4eba-b775-8122f05a4760 $docker_image bash -l -c "node src/node/interop/interop_client.js --server_host=216.239.32.254 --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=client_streaming"
+docker run -i --rm=true -w /var/local/git/grpc --net=host --name interop_client_node_16fa0b49-2083-4932-8f26-79cfdffec940 $docker_image bash -l -c "node src/node/interop/interop_client.js --server_host=216.239.32.254 --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=server_streaming"
+docker run -i --rm=true -w /var/local/git/grpc --net=host --name interop_client_node_23cee670-2d8d-4f5c-8893-c3c43da8b03a $docker_image bash -l -c "node src/node/interop/interop_client.js --server_host=216.239.32.254 --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=cancel_after_begin"
+docker run -i --rm=true -w /var/local/git/grpc --net=host --name interop_client_node_7b6a9454-e3b6-4993-b542-468e268930aa $docker_image bash -l -c "node src/node/interop/interop_client.js --server_host=216.239.32.254 --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=cancel_after_first_response"
+docker run -i --rm=true -w /var/local/git/grpc --net=host --name interop_client_node_5a7109ed-c065-4b62-98f4-b3ed8f385762 $docker_image bash -l -c "node src/node/interop/interop_client.js --server_host=216.239.32.254 --server_host_override=grpc-test.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=timeout_on_sleeping_server"
+docker run -i --rm=true -w /var/local/git/grpc --net=host --name interop_client_node_1e0ba8dd-4dc1-431b-b202-529e7ace5d1d $docker_image bash -l -c "node src/node/interop/interop_client.js --server_host=216.239.32.254 --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=large_unary"
+docker run -i --rm=true -w /var/local/git/grpc --net=host --name interop_client_node_649de56a-e722-4a59-b265-e9c0e871f068 $docker_image bash -l -c "node src/node/interop/interop_client.js --server_host=216.239.32.254 --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=empty_unary"
+docker run -i --rm=true -w /var/local/git/grpc --net=host --name interop_client_node_8be512a2-5e1c-4858-8cfc-82f99b678b76 $docker_image bash -l -c "node src/node/interop/interop_client.js --server_host=216.239.32.254 --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=ping_pong"
+docker run -i --rm=true -w /var/local/git/grpc --net=host --name interop_client_node_d19b6333-e528-48b5-8421-2ae3f7ce9dab $docker_image bash -l -c "node src/node/interop/interop_client.js --server_host=216.239.32.254 --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=empty_stream"
+docker run -i --rm=true -w /var/local/git/grpc --net=host --name interop_client_node_4749c80a-21c5-4d81-9df5-3c46ba6480cd $docker_image bash -l -c "node src/node/interop/interop_client.js --server_host=216.239.32.254 --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=client_streaming"
+docker run -i --rm=true -w /var/local/git/grpc --net=host --name interop_client_node_b7bee545-4857-4269-a1f2-9553dfc7e4b8 $docker_image bash -l -c "node src/node/interop/interop_client.js --server_host=216.239.32.254 --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=server_streaming"
+docker run -i --rm=true -w /var/local/git/grpc --net=host --name interop_client_node_4e96db87-6f48-426d-a7f0-97f3a5b6b3f4 $docker_image bash -l -c "node src/node/interop/interop_client.js --server_host=216.239.32.254 --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=cancel_after_begin"
+docker run -i --rm=true -w /var/local/git/grpc --net=host --name interop_client_node_31a1d58c-f8bf-460a-af60-28969ecaaf80 $docker_image bash -l -c "node src/node/interop/interop_client.js --server_host=216.239.32.254 --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=cancel_after_first_response"
+docker run -i --rm=true -w /var/local/git/grpc --net=host --name interop_client_node_ce64b147-bcfa-44b2-a2f7-4a485380ce30 $docker_image bash -l -c "node src/node/interop/interop_client.js --server_host=216.239.32.254 --server_host_override=grpc-test4.sandbox.googleapis.com --server_port=443 --use_tls=true --test_case=timeout_on_sleeping_server"
 
diff --git a/tools/run_tests/artifacts/build_artifact_ruby.sh b/tools/run_tests/artifacts/build_artifact_ruby.sh
index 993aaae..9165a22 100755
--- a/tools/run_tests/artifacts/build_artifact_ruby.sh
+++ b/tools/run_tests/artifacts/build_artifact_ruby.sh
@@ -42,6 +42,7 @@
 
 set -ex
 
+export DOCKERHUB_ORGANIZATION=grpctesting
 rake gem:native
 
 if [ "$SYSTEM" == "Darwin" ] ; then
diff --git a/tools/run_tests/artifacts/distribtest_targets.py b/tools/run_tests/artifacts/distribtest_targets.py
index 9959651..7ba0e0e 100644
--- a/tools/run_tests/artifacts/distribtest_targets.py
+++ b/tools/run_tests/artifacts/distribtest_targets.py
@@ -49,7 +49,8 @@
 
 def create_jobspec(name, cmdline, environ=None, shell=False,
                    flake_retries=0, timeout_retries=0,
-                   use_workspace=False):
+                   use_workspace=False,
+                   timeout_seconds=10*60):
   """Creates jobspec."""
   environ = environ.copy()
   if use_workspace:
@@ -60,7 +61,7 @@
           cmdline=cmdline,
           environ=environ,
           shortname='distribtest.%s' % (name),
-          timeout_seconds=10*60,
+          timeout_seconds=timeout_seconds,
           flake_retries=flake_retries,
           timeout_retries=timeout_retries,
           shell=shell)
@@ -214,7 +215,10 @@
   """Tests Cpp make intall by building examples."""
 
   def __init__(self, platform, arch, docker_suffix=None, testcase=None):
-    self.name = 'cpp_%s_%s_%s_%s' % (platform, arch, docker_suffix, testcase)
+    if platform == 'linux':
+      self.name = 'cpp_%s_%s_%s_%s' % (platform, arch, docker_suffix, testcase)
+    else:
+      self.name = 'cpp_%s_%s_%s' % (platform, arch, testcase)
     self.platform = platform
     self.arch = arch
     self.docker_suffix = docker_suffix
@@ -231,6 +235,12 @@
                                        self.docker_suffix,
                                        self.arch),
                                    'test/distrib/cpp/run_distrib_test_%s.sh' % self.testcase)
+    elif self.platform == 'windows':
+      return create_jobspec(self.name,
+                            ['test\\distrib\\cpp\\run_distrib_test_%s.bat' % self.testcase],
+                            environ={},
+                            timeout_seconds=30*60,
+                            use_workspace=True)
     else:
       raise Exception("Not supported yet.")
 
@@ -242,6 +252,7 @@
   """Gets list of supported targets"""
   return [CppDistribTest('linux', 'x64', 'jessie', 'routeguide'),
           CppDistribTest('linux', 'x64', 'jessie', 'cmake'),
+          CppDistribTest('windows', 'x86', testcase='cmake'),
           CSharpDistribTest('linux', 'x64', 'wheezy'),
           CSharpDistribTest('linux', 'x64', 'jessie'),
           CSharpDistribTest('linux', 'x86', 'jessie'),
diff --git a/tools/run_tests/generated/configs.json b/tools/run_tests/generated/configs.json
index abbe76d..fee8290 100644
--- a/tools/run_tests/generated/configs.json
+++ b/tools/run_tests/generated/configs.json
@@ -20,7 +20,10 @@
     }
   }, 
   {
-    "config": "msan"
+    "config": "msan", 
+    "environ": {
+      "MSAN_OPTIONS": "poison_in_dtor=1"
+    }
   }, 
   {
     "config": "basicprof"
diff --git a/tools/run_tests/generated/sources_and_headers.json b/tools/run_tests/generated/sources_and_headers.json
index 7e02624..ae7ddb2 100644
--- a/tools/run_tests/generated/sources_and_headers.json
+++ b/tools/run_tests/generated/sources_and_headers.json
@@ -711,21 +711,6 @@
     "headers": [], 
     "is_filegroup": false, 
     "language": "c", 
-    "name": "gpr_histogram_test", 
-    "src": [
-      "test/core/support/histogram_test.cc"
-    ], 
-    "third_party": false, 
-    "type": "target"
-  }, 
-  {
-    "deps": [
-      "gpr", 
-      "gpr_test_util"
-    ], 
-    "headers": [], 
-    "is_filegroup": false, 
-    "language": "c", 
     "name": "gpr_host_port_test", 
     "src": [
       "test/core/support/host_port_test.cc"
@@ -756,6 +741,21 @@
     "headers": [], 
     "is_filegroup": false, 
     "language": "c", 
+    "name": "gpr_manual_constructor_test", 
+    "src": [
+      "test/core/support/manual_constructor_test.cc"
+    ], 
+    "third_party": false, 
+    "type": "target"
+  }, 
+  {
+    "deps": [
+      "gpr", 
+      "gpr_test_util"
+    ], 
+    "headers": [], 
+    "is_filegroup": false, 
+    "language": "c", 
     "name": "gpr_mpscq_test", 
     "src": [
       "test/core/support/mpscq_test.cc"
@@ -786,21 +786,6 @@
     "headers": [], 
     "is_filegroup": false, 
     "language": "c", 
-    "name": "gpr_stack_lockfree_test", 
-    "src": [
-      "test/core/support/stack_lockfree_test.cc"
-    ], 
-    "third_party": false, 
-    "type": "target"
-  }, 
-  {
-    "deps": [
-      "gpr", 
-      "gpr_test_util"
-    ], 
-    "headers": [], 
-    "is_filegroup": false, 
-    "language": "c", 
     "name": "gpr_string_test", 
     "src": [
       "test/core/support/string_test.cc"
@@ -1245,6 +1230,21 @@
   {
     "deps": [
       "gpr", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "is_filegroup": false, 
+    "language": "c", 
+    "name": "histogram_test", 
+    "src": [
+      "test/core/util/histogram_test.cc"
+    ], 
+    "third_party": false, 
+    "type": "target"
+  }, 
+  {
+    "deps": [
+      "gpr", 
       "gpr_test_util", 
       "grpc", 
       "grpc_test_util"
@@ -3908,6 +3908,44 @@
       "gpr_test_util", 
       "grpc", 
       "grpc++", 
+      "grpc++_test", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "is_filegroup": false, 
+    "language": "c++", 
+    "name": "ref_counted_ptr_test", 
+    "src": [
+      "test/core/support/ref_counted_ptr_test.cc"
+    ], 
+    "third_party": false, 
+    "type": "target"
+  }, 
+  {
+    "deps": [
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc++", 
+      "grpc++_test", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "is_filegroup": false, 
+    "language": "c++", 
+    "name": "ref_counted_test", 
+    "src": [
+      "test/core/support/ref_counted_test.cc"
+    ], 
+    "third_party": false, 
+    "type": "target"
+  }, 
+  {
+    "deps": [
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc++", 
       "grpc++_test_util", 
       "grpc_test_util"
     ], 
@@ -4252,25 +4290,6 @@
       "gpr_test_util", 
       "grpc", 
       "grpc++", 
-      "grpc++_test", 
-      "grpc_test_util"
-    ], 
-    "headers": [], 
-    "is_filegroup": false, 
-    "language": "c++", 
-    "name": "vector_test", 
-    "src": [
-      "test/core/support/vector_test.cc"
-    ], 
-    "third_party": false, 
-    "type": "target"
-  }, 
-  {
-    "deps": [
-      "gpr", 
-      "gpr_test_util", 
-      "grpc", 
-      "grpc++", 
       "grpc++_test_util", 
       "grpc_test_util"
     ], 
@@ -7746,7 +7765,7 @@
       "src/core/lib/support/env_linux.cc", 
       "src/core/lib/support/env_posix.cc", 
       "src/core/lib/support/env_windows.cc", 
-      "src/core/lib/support/histogram.cc", 
+      "src/core/lib/support/fork.cc", 
       "src/core/lib/support/host_port.cc", 
       "src/core/lib/support/log.cc", 
       "src/core/lib/support/log_android.cc", 
@@ -7755,7 +7774,6 @@
       "src/core/lib/support/log_windows.cc", 
       "src/core/lib/support/mpscq.cc", 
       "src/core/lib/support/murmur_hash.cc", 
-      "src/core/lib/support/stack_lockfree.cc", 
       "src/core/lib/support/string.cc", 
       "src/core/lib/support/string_posix.cc", 
       "src/core/lib/support/string_util_windows.cc", 
@@ -7794,7 +7812,6 @@
       "include/grpc/support/avl.h", 
       "include/grpc/support/cmdline.h", 
       "include/grpc/support/cpu.h", 
-      "include/grpc/support/histogram.h", 
       "include/grpc/support/host_port.h", 
       "include/grpc/support/log.h", 
       "include/grpc/support/log_windows.h", 
@@ -7814,19 +7831,21 @@
       "include/grpc/support/tls_pthread.h", 
       "include/grpc/support/useful.h", 
       "src/core/lib/profiling/timers.h", 
+      "src/core/lib/support/abstract.h", 
       "src/core/lib/support/arena.h", 
       "src/core/lib/support/atomic.h", 
       "src/core/lib/support/atomic_with_atm.h", 
       "src/core/lib/support/atomic_with_std.h", 
       "src/core/lib/support/env.h", 
+      "src/core/lib/support/fork.h", 
       "src/core/lib/support/manual_constructor.h", 
       "src/core/lib/support/memory.h", 
       "src/core/lib/support/mpscq.h", 
       "src/core/lib/support/murmur_hash.h", 
       "src/core/lib/support/spinlock.h", 
-      "src/core/lib/support/stack_lockfree.h", 
       "src/core/lib/support/string.h", 
       "src/core/lib/support/string_windows.h", 
+      "src/core/lib/support/thd_internal.h", 
       "src/core/lib/support/time_precise.h", 
       "src/core/lib/support/tmpfile.h"
     ], 
@@ -7842,7 +7861,6 @@
       "include/grpc/support/avl.h", 
       "include/grpc/support/cmdline.h", 
       "include/grpc/support/cpu.h", 
-      "include/grpc/support/histogram.h", 
       "include/grpc/support/host_port.h", 
       "include/grpc/support/log.h", 
       "include/grpc/support/log_windows.h", 
@@ -7862,19 +7880,21 @@
       "include/grpc/support/tls_pthread.h", 
       "include/grpc/support/useful.h", 
       "src/core/lib/profiling/timers.h", 
+      "src/core/lib/support/abstract.h", 
       "src/core/lib/support/arena.h", 
       "src/core/lib/support/atomic.h", 
       "src/core/lib/support/atomic_with_atm.h", 
       "src/core/lib/support/atomic_with_std.h", 
       "src/core/lib/support/env.h", 
+      "src/core/lib/support/fork.h", 
       "src/core/lib/support/manual_constructor.h", 
       "src/core/lib/support/memory.h", 
       "src/core/lib/support/mpscq.h", 
       "src/core/lib/support/murmur_hash.h", 
       "src/core/lib/support/spinlock.h", 
-      "src/core/lib/support/stack_lockfree.h", 
       "src/core/lib/support/string.h", 
       "src/core/lib/support/string_windows.h", 
+      "src/core/lib/support/thd_internal.h", 
       "src/core/lib/support/time_precise.h", 
       "src/core/lib/support/tmpfile.h"
     ], 
@@ -7888,6 +7908,7 @@
       "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/fork.h", 
       "include/grpc/impl/codegen/gpr_slice.h", 
       "include/grpc/impl/codegen/gpr_types.h", 
       "include/grpc/impl/codegen/port_platform.h", 
@@ -7905,6 +7926,7 @@
       "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/fork.h", 
       "include/grpc/impl/codegen/gpr_slice.h", 
       "include/grpc/impl/codegen/gpr_types.h", 
       "include/grpc/impl/codegen/port_platform.h", 
@@ -7992,6 +8014,8 @@
       "src/core/lib/iomgr/ev_windows.cc", 
       "src/core/lib/iomgr/exec_ctx.cc", 
       "src/core/lib/iomgr/executor.cc", 
+      "src/core/lib/iomgr/fork_posix.cc", 
+      "src/core/lib/iomgr/fork_windows.cc", 
       "src/core/lib/iomgr/gethostname_fallback.cc", 
       "src/core/lib/iomgr/gethostname_host_name_max.cc", 
       "src/core/lib/iomgr/gethostname_sysconf.cc", 
@@ -8104,6 +8128,7 @@
       "include/grpc/byte_buffer.h", 
       "include/grpc/byte_buffer_reader.h", 
       "include/grpc/compression.h", 
+      "include/grpc/fork.h", 
       "include/grpc/grpc.h", 
       "include/grpc/grpc_posix.h", 
       "include/grpc/grpc_security_constants.h", 
@@ -8203,7 +8228,9 @@
       "src/core/lib/slice/slice_hash_table.h", 
       "src/core/lib/slice/slice_internal.h", 
       "src/core/lib/slice/slice_string_helpers.h", 
-      "src/core/lib/support/vector.h", 
+      "src/core/lib/support/debug_location.h", 
+      "src/core/lib/support/ref_counted.h", 
+      "src/core/lib/support/ref_counted_ptr.h", 
       "src/core/lib/surface/alarm_internal.h", 
       "src/core/lib/surface/api_trace.h", 
       "src/core/lib/surface/call.h", 
@@ -8240,6 +8267,7 @@
       "include/grpc/byte_buffer.h", 
       "include/grpc/byte_buffer_reader.h", 
       "include/grpc/compression.h", 
+      "include/grpc/fork.h", 
       "include/grpc/grpc.h", 
       "include/grpc/grpc_posix.h", 
       "include/grpc/grpc_security_constants.h", 
@@ -8339,7 +8367,9 @@
       "src/core/lib/slice/slice_hash_table.h", 
       "src/core/lib/slice/slice_internal.h", 
       "src/core/lib/slice/slice_string_helpers.h", 
-      "src/core/lib/support/vector.h", 
+      "src/core/lib/support/debug_location.h", 
+      "src/core/lib/support/ref_counted.h", 
+      "src/core/lib/support/ref_counted_ptr.h", 
       "src/core/lib/surface/alarm_internal.h", 
       "src/core/lib/surface/api_trace.h", 
       "src/core/lib/surface/call.h", 
@@ -8895,6 +8925,7 @@
       "test/core/iomgr/endpoint_tests.h", 
       "test/core/util/debugger_macros.h", 
       "test/core/util/grpc_profiler.h", 
+      "test/core/util/histogram.h", 
       "test/core/util/memory_counters.h", 
       "test/core/util/mock_endpoint.h", 
       "test/core/util/parse_hexstring.h", 
@@ -8902,6 +8933,7 @@
       "test/core/util/port.h", 
       "test/core/util/port_server_client.h", 
       "test/core/util/slice_splitter.h", 
+      "test/core/util/tracer_util.h", 
       "test/core/util/trickle_endpoint.h"
     ], 
     "is_filegroup": true, 
@@ -8922,6 +8954,8 @@
       "test/core/util/debugger_macros.h", 
       "test/core/util/grpc_profiler.cc", 
       "test/core/util/grpc_profiler.h", 
+      "test/core/util/histogram.cc", 
+      "test/core/util/histogram.h", 
       "test/core/util/memory_counters.cc", 
       "test/core/util/memory_counters.h", 
       "test/core/util/mock_endpoint.cc", 
@@ -8932,10 +8966,13 @@
       "test/core/util/passthru_endpoint.h", 
       "test/core/util/port.cc", 
       "test/core/util/port.h", 
+      "test/core/util/port_isolated_runtime_environment.cc", 
       "test/core/util/port_server_client.cc", 
       "test/core/util/port_server_client.h", 
       "test/core/util/slice_splitter.cc", 
       "test/core/util/slice_splitter.h", 
+      "test/core/util/tracer_util.cc", 
+      "test/core/util/tracer_util.h", 
       "test/core/util/trickle_endpoint.cc", 
       "test/core/util/trickle_endpoint.h"
     ], 
diff --git a/tools/run_tests/generated/tests.json b/tools/run_tests/generated/tests.json
index 4a5817c..ce698cb 100644
--- a/tools/run_tests/generated/tests.json
+++ b/tools/run_tests/generated/tests.json
@@ -854,30 +854,6 @@
     "flaky": false, 
     "gtest": false, 
     "language": "c", 
-    "name": "gpr_histogram_test", 
-    "platforms": [
-      "linux", 
-      "mac", 
-      "posix", 
-      "windows"
-    ], 
-    "uses_polling": false
-  }, 
-  {
-    "args": [], 
-    "benchmark": false, 
-    "ci_platforms": [
-      "linux", 
-      "mac", 
-      "posix", 
-      "windows"
-    ], 
-    "cpu_cost": 1.0, 
-    "exclude_configs": [], 
-    "exclude_iomgrs": [], 
-    "flaky": false, 
-    "gtest": false, 
-    "language": "c", 
     "name": "gpr_host_port_test", 
     "platforms": [
       "linux", 
@@ -920,6 +896,30 @@
       "posix", 
       "windows"
     ], 
+    "cpu_cost": 3, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "gtest": false, 
+    "language": "c", 
+    "name": "gpr_manual_constructor_test", 
+    "platforms": [
+      "linux", 
+      "mac", 
+      "posix", 
+      "windows"
+    ], 
+    "uses_polling": false
+  }, 
+  {
+    "args": [], 
+    "benchmark": false, 
+    "ci_platforms": [
+      "linux", 
+      "mac", 
+      "posix", 
+      "windows"
+    ], 
     "cpu_cost": 30, 
     "exclude_configs": [], 
     "exclude_iomgrs": [], 
@@ -968,30 +968,6 @@
       "posix", 
       "windows"
     ], 
-    "cpu_cost": 7, 
-    "exclude_configs": [], 
-    "exclude_iomgrs": [], 
-    "flaky": false, 
-    "gtest": false, 
-    "language": "c", 
-    "name": "gpr_stack_lockfree_test", 
-    "platforms": [
-      "linux", 
-      "mac", 
-      "posix", 
-      "windows"
-    ], 
-    "uses_polling": false
-  }, 
-  {
-    "args": [], 
-    "benchmark": false, 
-    "ci_platforms": [
-      "linux", 
-      "mac", 
-      "posix", 
-      "windows"
-    ], 
     "cpu_cost": 1.0, 
     "exclude_configs": [], 
     "exclude_iomgrs": [], 
@@ -1538,6 +1514,30 @@
     "flaky": false, 
     "gtest": false, 
     "language": "c", 
+    "name": "histogram_test", 
+    "platforms": [
+      "linux", 
+      "mac", 
+      "posix", 
+      "windows"
+    ], 
+    "uses_polling": false
+  }, 
+  {
+    "args": [], 
+    "benchmark": false, 
+    "ci_platforms": [
+      "linux", 
+      "mac", 
+      "posix", 
+      "windows"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "gtest": false, 
+    "language": "c", 
     "name": "hpack_parser_test", 
     "platforms": [
       "linux", 
@@ -4114,6 +4114,54 @@
     "flaky": false, 
     "gtest": true, 
     "language": "c++", 
+    "name": "ref_counted_ptr_test", 
+    "platforms": [
+      "linux", 
+      "mac", 
+      "posix", 
+      "windows"
+    ], 
+    "uses_polling": true
+  }, 
+  {
+    "args": [], 
+    "benchmark": false, 
+    "ci_platforms": [
+      "linux", 
+      "mac", 
+      "posix", 
+      "windows"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "gtest": true, 
+    "language": "c++", 
+    "name": "ref_counted_test", 
+    "platforms": [
+      "linux", 
+      "mac", 
+      "posix", 
+      "windows"
+    ], 
+    "uses_polling": true
+  }, 
+  {
+    "args": [], 
+    "benchmark": false, 
+    "ci_platforms": [
+      "linux", 
+      "mac", 
+      "posix", 
+      "windows"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "gtest": true, 
+    "language": "c++", 
     "name": "secure_auth_context_test", 
     "platforms": [
       "linux", 
@@ -4438,30 +4486,6 @@
     "ci_platforms": [
       "linux", 
       "mac", 
-      "posix", 
-      "windows"
-    ], 
-    "cpu_cost": 1.0, 
-    "exclude_configs": [], 
-    "exclude_iomgrs": [], 
-    "flaky": false, 
-    "gtest": true, 
-    "language": "c++", 
-    "name": "vector_test", 
-    "platforms": [
-      "linux", 
-      "mac", 
-      "posix", 
-      "windows"
-    ], 
-    "uses_polling": true
-  }, 
-  {
-    "args": [], 
-    "benchmark": false, 
-    "ci_platforms": [
-      "linux", 
-      "mac", 
       "posix"
     ], 
     "cpu_cost": 0.5, 
diff --git a/tools/run_tests/run_performance_tests.py b/tools/run_tests/run_performance_tests.py
index 1bbab9e..aa305be 100755
--- a/tools/run_tests/run_performance_tests.py
+++ b/tools/run_tests/run_performance_tests.py
@@ -196,7 +196,7 @@
 
 def prepare_remote_hosts(hosts, prepare_local=False):
   """Prepares remote hosts (and maybe prepare localhost as well)."""
-  prepare_timeout = 5*60
+  prepare_timeout = 10*60
   prepare_jobs = []
   for host in hosts:
     user_at_host = '%s@%s' % (_REMOTE_HOST_USERNAME, host)
@@ -229,6 +229,8 @@
 def build_on_remote_hosts(hosts, languages=scenario_config.LANGUAGES.keys(), build_local=False):
   """Builds performance worker on remote hosts (and maybe also locally)."""
   build_timeout = 15*60
+  # Kokoro VMs (which are local only) do not have caching, so they need more time to build
+  local_build_timeout = 30*60
   build_jobs = []
   for host in hosts:
     user_at_host = '%s@%s' % (_REMOTE_HOST_USERNAME, host)
@@ -245,7 +247,7 @@
             cmdline=['tools/run_tests/performance/build_performance.sh'] + languages,
             shortname='local_build',
             environ = {'CONFIG': 'opt'},
-            timeout_seconds=build_timeout))
+            timeout_seconds=local_build_timeout))
   jobset.message('START', 'Building.', do_newline=True)
   num_failures, _ = jobset.run(
       build_jobs, newline_on_success=True, maxjobs=10)
@@ -483,9 +485,15 @@
                           'generating flamegraphs (e.g., "--perf_args=stat ...")'))
   argp.add_argument('-f', '--flame_graph_reports', default='perf_reports', type=str,
                     help='Name of directory to output flame graph profiles to, if any are created.')
+  argp.add_argument('-u', '--remote_host_username', default='', type=str,
+                    help='Use a username that isn\'t "Jenkins" to SSH into remote workers.')
 
   args = argp.parse_args()
 
+  global _REMOTE_HOST_USERNAME
+  if args.remote_host_username:
+    _REMOTE_HOST_USERNAME = args.remote_host_username
+
   languages = set(scenario_config.LANGUAGES[l]
                   for l in itertools.chain.from_iterable(
                         six.iterkeys(scenario_config.LANGUAGES) if x == 'all'
diff --git a/tools/run_tests/sanity/check_bazel_workspace.py b/tools/run_tests/sanity/check_bazel_workspace.py
new file mode 100755
index 0000000..776c78b
--- /dev/null
+++ b/tools/run_tests/sanity/check_bazel_workspace.py
@@ -0,0 +1,49 @@
+#!/usr/bin/env python
+
+# Copyright 2016 gRPC authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+from __future__ import print_function
+
+import ast
+import os
+import re
+import subprocess
+import sys
+
+os.chdir(os.path.join(os.path.dirname(sys.argv[0]), '../../..'))
+
+git_hash_pattern = re.compile('[0-9a-f]{40}')
+
+# Parse git hashes from submodules
+git_submodules = subprocess.check_output('git submodule', shell=True).strip().split('\n')
+git_submodule_hashes = {re.search(git_hash_pattern, s).group() for s in git_submodules}
+
+# Parse git hashes from Bazel WORKSPACE {new_}http_archive rules
+with open('WORKSPACE', 'r') as f:
+  workspace_rules = [expr.value for expr in ast.parse(f.read()).body]
+
+http_archive_rules = [rule for rule in workspace_rules if rule.func.id.endswith('http_archive')]
+archive_urls = [kw.value.s for rule in http_archive_rules for kw in rule.keywords if kw.arg == 'url']
+workspace_git_hashes = {re.search(git_hash_pattern, url).group() for url in archive_urls}
+
+# Validate the equivalence of the git submodules and Bazel git dependencies. The
+# condition we impose is that there is a git submodule for every dependency in
+# the workspace, but not necessarily conversely. E.g. Bloaty is a dependency
+# not used by any of the targets built by Bazel.
+if len(workspace_git_hashes - git_submodule_hashes) > 0:
+    print("Found discrepancies between git submodules and Bazel WORKSPACE dependencies")
+    sys.exit(1)
+
+sys.exit(0)
diff --git a/tools/run_tests/sanity/check_submodules.sh b/tools/run_tests/sanity/check_submodules.sh
index 1f7b078..b573d21 100755
--- a/tools/run_tests/sanity/check_submodules.sh
+++ b/tools/run_tests/sanity/check_submodules.sh
@@ -31,7 +31,7 @@
  886e7d75368e3f4fab3f4d0d3584e4abfc557755 third_party/boringssl-with-bazel (version_for_cocoapods_7.0-857-g886e7d7)
  30dbc81fb5ffdc98ea9b14b1918bfe4e8779b26e third_party/gflags (v2.2.0)
  ec44c6c1675c25b9827aacd08c02433cccde7780 third_party/googletest (release-1.8.0)
- 80a37e0782d2d702d52234b62dd4b9ec74fd2c95 third_party/protobuf (v3.4.0)
+ 2761122b810fe8861004ae785cc3ab39f384d342 third_party/protobuf (v3.5.0)
  cacf7f1d4e3d44d871b605da3b647f07d718623f third_party/zlib (v1.2.11)
  3be1924221e1326df520f8498d704a5c4c8d0cce third_party/cares/cares (cares-1_13_0)
  73594cde8c9a52a102c4341c244c833aa61b9c06 third_party/bloaty
diff --git a/tools/run_tests/sanity/check_unsecure.sh b/tools/run_tests/sanity/check_unsecure.sh
new file mode 100755
index 0000000..8584cbe
--- /dev/null
+++ b/tools/run_tests/sanity/check_unsecure.sh
@@ -0,0 +1,27 @@
+#!/bin/sh
+# Copyright 2017 gRPC authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+set -e
+
+# Make sure that there is no path from known unsecure libraries and targets
+# to an SSL library. Any failure among these will make the script fail.
+
+test `bazel query 'somepath("//:grpc_unsecure", "//external:libssl")' 2>/dev/null | wc -l` -eq 0 || exit 1
+test `bazel query 'somepath("//:grpc++_unsecure", "//external:libssl")' 2>/dev/null | wc -l` -eq 0 || exit 1
+test `bazel query 'somepath("//:grpc++_codegen_proto", "//external:libssl")' 2>/dev/null | wc -l` -eq 0 || exit 1
+test `bazel query 'somepath("//test/cpp/microbenchmarks:helpers", "//external:libssl")' 2>/dev/null | wc -l` -eq 0 || exit 1
+
+exit 0
+
diff --git a/tools/run_tests/sanity/sanity_tests.yaml b/tools/run_tests/sanity/sanity_tests.yaml
index 3ca5c1b..3ce864a 100644
--- a/tools/run_tests/sanity/sanity_tests.yaml
+++ b/tools/run_tests/sanity/sanity_tests.yaml
@@ -1,10 +1,12 @@
 # a set of tests that are run in parallel for sanity tests
+- script: tools/run_tests/sanity/check_bazel_workspace.py
 - script: tools/run_tests/sanity/check_cache_mk.sh
 - script: tools/run_tests/sanity/check_owners.sh
 - script: tools/run_tests/sanity/check_sources_and_headers.py
 - script: tools/run_tests/sanity/check_submodules.sh
 - script: tools/run_tests/sanity/check_test_filtering.py
 - script: tools/run_tests/sanity/check_tracer_sanity.py
+- script: tools/run_tests/sanity/check_unsecure.sh
 - script: tools/run_tests/sanity/core_banned_functions.py
 - script: tools/run_tests/sanity/core_untyped_structs.sh
 - script: tools/buildgen/generate_projects.sh -j 3