diff --git a/BUILD b/BUILD
index c164daeca1cf3b33120c598e4bdc871c65a4e874..8505f19bb3a1c7e5f7423e3f429c873d6d4365dc 100644
--- a/BUILD
+++ b/BUILD
@@ -41,7 +41,7 @@ g_stands_for = "green"
 
 core_version = "3.0.0-dev"
 
-version = "1.2.0"
+version = "1.3.0-dev"
 
 grpc_cc_library(
     name = "gpr",
@@ -67,6 +67,7 @@ grpc_cc_library(
         "grpc_lb_policy_pick_first",
         "grpc_lb_policy_round_robin",
         "grpc_load_reporting",
+        "grpc_max_age_filter",
         "grpc_resolver_dns_ares",
         "grpc_resolver_dns_native",
         "grpc_resolver_sockaddr",
@@ -75,7 +76,6 @@ grpc_cc_library(
         "grpc_transport_chttp2_client_secure",
         "grpc_transport_chttp2_server_insecure",
         "grpc_transport_chttp2_server_secure",
-        "grpc_max_age_filter",
     ],
 )
 
@@ -109,11 +109,11 @@ grpc_cc_library(
         "grpc_lb_policy_pick_first",
         "grpc_lb_policy_round_robin",
         "grpc_load_reporting",
+        "grpc_max_age_filter",
         "grpc_resolver_dns_native",
         "grpc_resolver_sockaddr",
         "grpc_transport_chttp2_client_insecure",
         "grpc_transport_chttp2_server_insecure",
-        "grpc_max_age_filter",
     ],
 )
 
@@ -177,8 +177,6 @@ grpc_cc_library(
     ],
     hdrs = [
         "src/compiler/config.h",
-        "src/compiler/schema_interface.h",
-        "src/compiler/protobuf_plugin.h",
         "src/compiler/cpp_generator.h",
         "src/compiler/cpp_generator_helpers.h",
         "src/compiler/csharp_generator.h",
@@ -190,6 +188,7 @@ grpc_cc_library(
         "src/compiler/objective_c_generator_helpers.h",
         "src/compiler/php_generator.h",
         "src/compiler/php_generator_helpers.h",
+        "src/compiler/protobuf_plugin.h",
         "src/compiler/python_generator.h",
         "src/compiler/python_generator_helpers.h",
         "src/compiler/python_private_generator.h",
@@ -197,6 +196,7 @@ grpc_cc_library(
         "src/compiler/ruby_generator_helpers-inl.h",
         "src/compiler/ruby_generator_map-inl.h",
         "src/compiler/ruby_generator_string-inl.h",
+        "src/compiler/schema_interface.h",
     ],
     external_deps = [
         "protobuf_clib",
@@ -457,6 +457,7 @@ grpc_cc_library(
         "src/core/lib/iomgr/endpoint_pair_windows.c",
         "src/core/lib/iomgr/error.c",
         "src/core/lib/iomgr/ev_epoll_linux.c",
+        "src/core/lib/iomgr/lockfree_event.c",
         "src/core/lib/iomgr/ev_poll_posix.c",
         "src/core/lib/iomgr/ev_posix.c",
         "src/core/lib/iomgr/exec_ctx.c",
@@ -583,6 +584,7 @@ grpc_cc_library(
         "src/core/lib/iomgr/error.h",
         "src/core/lib/iomgr/error_internal.h",
         "src/core/lib/iomgr/ev_epoll_linux.h",
+        "src/core/lib/iomgr/lockfree_event.h",
         "src/core/lib/iomgr/ev_poll_posix.h",
         "src/core/lib/iomgr/ev_posix.h",
         "src/core/lib/iomgr/exec_ctx.h",
@@ -884,14 +886,14 @@ grpc_cc_library(
         "src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver.h",
         "src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.h",
     ],
+    external_deps = [
+        "cares",
+    ],
     language = "c",
     deps = [
         "grpc_base",
         "grpc_client_channel",
     ],
-    external_deps = [
-        "cares",
-    ],
 )
 
 grpc_cc_library(
diff --git a/CMakeLists.txt b/CMakeLists.txt
index c713f696cc2fc2e594f96118e2d6fc439d2e4655..4f09fda1da88756cc974558293c30c4ed1b063f8 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -5,9 +5,6 @@
 # This file can be regenerated from the template by running
 # tools/buildgen/generate_projects.sh
 #
-# Additionally, this is currently very experimental, and unsupported.
-# Further work will happen on that file.
-#
 # Copyright 2015, Google Inc.
 # All rights reserved.
 #
@@ -308,7 +305,7 @@ function(protobuf_generate_grpc_cpp)
   foreach(FIL ${ARGN})
     get_filename_component(ABS_FIL ${FIL} ABSOLUTE)
     get_filename_component(FIL_WE ${FIL} NAME_WE)
-    file(RELATIVE_PATH REL_FIL ${CMAKE_SOURCE_DIR} ${ABS_FIL})
+    file(RELATIVE_PATH REL_FIL ${CMAKE_CURRENT_SOURCE_DIR} ${ABS_FIL})
     get_filename_component(REL_DIR ${REL_FIL} DIRECTORY)
     set(RELFIL_WE "${REL_DIR}/${FIL_WE}")
 
@@ -324,7 +321,7 @@ function(protobuf_generate_grpc_cpp)
            ${_protobuf_include_path}
            ${REL_FIL}
       DEPENDS ${ABS_FIL} ${_gRPC_PROTOBUF_PROTOC} grpc_cpp_plugin
-      WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
+      WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
       COMMENT "Running gRPC C++ protocol buffer compiler on ${FIL}"
       VERBATIM)
 
@@ -626,6 +623,9 @@ if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_POSIX)
 add_dependencies(buildtests_cxx bm_cq)
 endif()
 if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_POSIX)
+add_dependencies(buildtests_cxx bm_cq_multiple_threads)
+endif()
+if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_POSIX)
 add_dependencies(buildtests_cxx bm_error)
 endif()
 if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_POSIX)
@@ -943,6 +943,7 @@ add_library(grpc
   src/core/lib/iomgr/iomgr_uv.c
   src/core/lib/iomgr/iomgr_windows.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
@@ -1266,6 +1267,7 @@ add_library(grpc_cronet
   src/core/lib/iomgr/iomgr_uv.c
   src/core/lib/iomgr/iomgr_windows.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
@@ -1575,6 +1577,7 @@ add_library(grpc_test_util
   src/core/lib/iomgr/iomgr_uv.c
   src/core/lib/iomgr/iomgr_windows.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
@@ -1835,6 +1838,7 @@ add_library(grpc_unsecure
   src/core/lib/iomgr/iomgr_uv.c
   src/core/lib/iomgr/iomgr_windows.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
@@ -2252,6 +2256,7 @@ add_library(grpc++
   src/core/lib/iomgr/iomgr_uv.c
   src/core/lib/iomgr/iomgr_windows.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
@@ -2582,6 +2587,7 @@ add_library(grpc++_cronet
   src/core/lib/iomgr/iomgr_uv.c
   src/core/lib/iomgr/iomgr_windows.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
@@ -2936,8 +2942,8 @@ target_include_directories(grpc++_proto_reflection_desc_db
   PRIVATE ${CARES_PLATFORM_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE third_party/googletest/include
-  PRIVATE third_party/googletest
+  PRIVATE third_party/googletest/googletest/include
+  PRIVATE third_party/googletest/googletest
   PRIVATE ${_gRPC_PROTO_GENS_DIR}
 )
 
@@ -3055,8 +3061,8 @@ target_include_directories(grpc++_test_config
   PRIVATE ${CARES_PLATFORM_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE third_party/googletest/include
-  PRIVATE third_party/googletest
+  PRIVATE third_party/googletest/googletest/include
+  PRIVATE third_party/googletest/googletest
   PRIVATE ${_gRPC_PROTO_GENS_DIR}
 )
 
@@ -3132,8 +3138,8 @@ target_include_directories(grpc++_test_util
   PRIVATE ${CARES_PLATFORM_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE third_party/googletest/include
-  PRIVATE third_party/googletest
+  PRIVATE third_party/googletest/googletest/include
+  PRIVATE third_party/googletest/googletest
   PRIVATE ${_gRPC_PROTO_GENS_DIR}
 )
 
@@ -3281,6 +3287,7 @@ add_library(grpc++_unsecure
   src/core/lib/iomgr/iomgr_uv.c
   src/core/lib/iomgr/iomgr_windows.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
@@ -3564,8 +3571,8 @@ target_include_directories(grpc_benchmark
   PRIVATE ${CARES_PLATFORM_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE third_party/googletest/include
-  PRIVATE third_party/googletest
+  PRIVATE third_party/googletest/googletest/include
+  PRIVATE third_party/googletest/googletest
   PRIVATE ${_gRPC_PROTO_GENS_DIR}
 )
 
@@ -3623,8 +3630,8 @@ target_include_directories(grpc_cli_libs
   PRIVATE ${CARES_PLATFORM_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE third_party/googletest/include
-  PRIVATE third_party/googletest
+  PRIVATE third_party/googletest/googletest/include
+  PRIVATE third_party/googletest/googletest
   PRIVATE ${_gRPC_PROTO_GENS_DIR}
 )
 
@@ -3762,8 +3769,8 @@ target_include_directories(http2_client_main
   PRIVATE ${CARES_PLATFORM_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE third_party/googletest/include
-  PRIVATE third_party/googletest
+  PRIVATE third_party/googletest/googletest/include
+  PRIVATE third_party/googletest/googletest
   PRIVATE ${_gRPC_PROTO_GENS_DIR}
 )
 
@@ -3817,8 +3824,8 @@ target_include_directories(interop_client_helper
   PRIVATE ${CARES_PLATFORM_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE third_party/googletest/include
-  PRIVATE third_party/googletest
+  PRIVATE third_party/googletest/googletest/include
+  PRIVATE third_party/googletest/googletest
   PRIVATE ${_gRPC_PROTO_GENS_DIR}
 )
 
@@ -3887,8 +3894,8 @@ target_include_directories(interop_client_main
   PRIVATE ${CARES_PLATFORM_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE third_party/googletest/include
-  PRIVATE third_party/googletest
+  PRIVATE third_party/googletest/googletest/include
+  PRIVATE third_party/googletest/googletest
   PRIVATE ${_gRPC_PROTO_GENS_DIR}
 )
 
@@ -3938,8 +3945,8 @@ target_include_directories(interop_server_helper
   PRIVATE ${CARES_PLATFORM_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE third_party/googletest/include
-  PRIVATE third_party/googletest
+  PRIVATE third_party/googletest/googletest/include
+  PRIVATE third_party/googletest/googletest
   PRIVATE ${_gRPC_PROTO_GENS_DIR}
 )
 
@@ -4007,8 +4014,8 @@ target_include_directories(interop_server_lib
   PRIVATE ${CARES_PLATFORM_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE third_party/googletest/include
-  PRIVATE third_party/googletest
+  PRIVATE third_party/googletest/googletest/include
+  PRIVATE third_party/googletest/googletest
   PRIVATE ${_gRPC_PROTO_GENS_DIR}
 )
 
@@ -4058,8 +4065,8 @@ target_include_directories(interop_server_main
   PRIVATE ${CARES_PLATFORM_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE third_party/googletest/include
-  PRIVATE third_party/googletest
+  PRIVATE third_party/googletest/googletest/include
+  PRIVATE third_party/googletest/googletest
   PRIVATE ${_gRPC_PROTO_GENS_DIR}
 )
 
@@ -4146,8 +4153,8 @@ target_include_directories(qps
   PRIVATE ${CARES_PLATFORM_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE third_party/googletest/include
-  PRIVATE third_party/googletest
+  PRIVATE third_party/googletest/googletest/include
+  PRIVATE third_party/googletest/googletest
   PRIVATE ${_gRPC_PROTO_GENS_DIR}
 )
 
@@ -8609,7 +8616,7 @@ if (gRPC_BUILD_TESTS)
 
 add_executable(alarm_cpp_test
   test/cpp/common/alarm_cpp_test.cc
-  third_party/googletest/src/gtest-all.cc
+  third_party/googletest/googletest/src/gtest-all.cc
 )
 
 
@@ -8626,8 +8633,8 @@ target_include_directories(alarm_cpp_test
   PRIVATE ${CARES_PLATFORM_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE third_party/googletest/include
-  PRIVATE third_party/googletest
+  PRIVATE third_party/googletest/googletest/include
+  PRIVATE third_party/googletest/googletest
   PRIVATE ${_gRPC_PROTO_GENS_DIR}
 )
 
@@ -8648,7 +8655,7 @@ if (gRPC_BUILD_TESTS)
 
 add_executable(async_end2end_test
   test/cpp/end2end/async_end2end_test.cc
-  third_party/googletest/src/gtest-all.cc
+  third_party/googletest/googletest/src/gtest-all.cc
 )
 
 
@@ -8665,8 +8672,8 @@ target_include_directories(async_end2end_test
   PRIVATE ${CARES_PLATFORM_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE third_party/googletest/include
-  PRIVATE third_party/googletest
+  PRIVATE third_party/googletest/googletest/include
+  PRIVATE third_party/googletest/googletest
   PRIVATE ${_gRPC_PROTO_GENS_DIR}
 )
 
@@ -8687,7 +8694,7 @@ if (gRPC_BUILD_TESTS)
 
 add_executable(auth_property_iterator_test
   test/cpp/common/auth_property_iterator_test.cc
-  third_party/googletest/src/gtest-all.cc
+  third_party/googletest/googletest/src/gtest-all.cc
 )
 
 
@@ -8704,8 +8711,8 @@ target_include_directories(auth_property_iterator_test
   PRIVATE ${CARES_PLATFORM_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE third_party/googletest/include
-  PRIVATE third_party/googletest
+  PRIVATE third_party/googletest/googletest/include
+  PRIVATE third_party/googletest/googletest
   PRIVATE ${_gRPC_PROTO_GENS_DIR}
 )
 
@@ -8727,7 +8734,7 @@ if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_POSIX)
 
 add_executable(bm_arena
   test/cpp/microbenchmarks/bm_arena.cc
-  third_party/googletest/src/gtest-all.cc
+  third_party/googletest/googletest/src/gtest-all.cc
 )
 
 
@@ -8744,8 +8751,8 @@ target_include_directories(bm_arena
   PRIVATE ${CARES_PLATFORM_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE third_party/googletest/include
-  PRIVATE third_party/googletest
+  PRIVATE third_party/googletest/googletest/include
+  PRIVATE third_party/googletest/googletest
   PRIVATE ${_gRPC_PROTO_GENS_DIR}
 )
 
@@ -8770,7 +8777,7 @@ if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_POSIX)
 
 add_executable(bm_call_create
   test/cpp/microbenchmarks/bm_call_create.cc
-  third_party/googletest/src/gtest-all.cc
+  third_party/googletest/googletest/src/gtest-all.cc
 )
 
 
@@ -8787,8 +8794,8 @@ target_include_directories(bm_call_create
   PRIVATE ${CARES_PLATFORM_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE third_party/googletest/include
-  PRIVATE third_party/googletest
+  PRIVATE third_party/googletest/googletest/include
+  PRIVATE third_party/googletest/googletest
   PRIVATE ${_gRPC_PROTO_GENS_DIR}
 )
 
@@ -8813,7 +8820,7 @@ if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_POSIX)
 
 add_executable(bm_chttp2_hpack
   test/cpp/microbenchmarks/bm_chttp2_hpack.cc
-  third_party/googletest/src/gtest-all.cc
+  third_party/googletest/googletest/src/gtest-all.cc
 )
 
 
@@ -8830,8 +8837,8 @@ target_include_directories(bm_chttp2_hpack
   PRIVATE ${CARES_PLATFORM_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE third_party/googletest/include
-  PRIVATE third_party/googletest
+  PRIVATE third_party/googletest/googletest/include
+  PRIVATE third_party/googletest/googletest
   PRIVATE ${_gRPC_PROTO_GENS_DIR}
 )
 
@@ -8856,7 +8863,7 @@ if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_POSIX)
 
 add_executable(bm_chttp2_transport
   test/cpp/microbenchmarks/bm_chttp2_transport.cc
-  third_party/googletest/src/gtest-all.cc
+  third_party/googletest/googletest/src/gtest-all.cc
 )
 
 
@@ -8873,8 +8880,8 @@ target_include_directories(bm_chttp2_transport
   PRIVATE ${CARES_PLATFORM_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE third_party/googletest/include
-  PRIVATE third_party/googletest
+  PRIVATE third_party/googletest/googletest/include
+  PRIVATE third_party/googletest/googletest
   PRIVATE ${_gRPC_PROTO_GENS_DIR}
 )
 
@@ -8899,7 +8906,7 @@ if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_POSIX)
 
 add_executable(bm_closure
   test/cpp/microbenchmarks/bm_closure.cc
-  third_party/googletest/src/gtest-all.cc
+  third_party/googletest/googletest/src/gtest-all.cc
 )
 
 
@@ -8916,8 +8923,8 @@ target_include_directories(bm_closure
   PRIVATE ${CARES_PLATFORM_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE third_party/googletest/include
-  PRIVATE third_party/googletest
+  PRIVATE third_party/googletest/googletest/include
+  PRIVATE third_party/googletest/googletest
   PRIVATE ${_gRPC_PROTO_GENS_DIR}
 )
 
@@ -8942,7 +8949,7 @@ if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_POSIX)
 
 add_executable(bm_cq
   test/cpp/microbenchmarks/bm_cq.cc
-  third_party/googletest/src/gtest-all.cc
+  third_party/googletest/googletest/src/gtest-all.cc
 )
 
 
@@ -8959,8 +8966,8 @@ target_include_directories(bm_cq
   PRIVATE ${CARES_PLATFORM_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE third_party/googletest/include
-  PRIVATE third_party/googletest
+  PRIVATE third_party/googletest/googletest/include
+  PRIVATE third_party/googletest/googletest
   PRIVATE ${_gRPC_PROTO_GENS_DIR}
 )
 
@@ -8983,9 +8990,52 @@ endif (gRPC_BUILD_TESTS)
 if (gRPC_BUILD_TESTS)
 if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_POSIX)
 
+add_executable(bm_cq_multiple_threads
+  test/cpp/microbenchmarks/bm_cq_multiple_threads.cc
+  third_party/googletest/googletest/src/gtest-all.cc
+)
+
+
+target_include_directories(bm_cq_multiple_threads
+  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_BUILD_INCLUDE_DIR}
+  PRIVATE ${CARES_INCLUDE_DIR}
+  PRIVATE ${CARES_PLATFORM_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 ${_gRPC_PROTO_GENS_DIR}
+)
+
+target_link_libraries(bm_cq_multiple_threads
+  ${_gRPC_PROTOBUF_LIBRARIES}
+  ${_gRPC_ALLTARGETS_LIBRARIES}
+  grpc_benchmark
+  benchmark
+  grpc++_test_util
+  grpc_test_util
+  grpc++
+  grpc
+  gpr_test_util
+  gpr
+  ${_gRPC_GFLAGS_LIBRARIES}
+)
+
+endif()
+endif (gRPC_BUILD_TESTS)
+if (gRPC_BUILD_TESTS)
+if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_POSIX)
+
 add_executable(bm_error
   test/cpp/microbenchmarks/bm_error.cc
-  third_party/googletest/src/gtest-all.cc
+  third_party/googletest/googletest/src/gtest-all.cc
 )
 
 
@@ -9002,8 +9052,8 @@ target_include_directories(bm_error
   PRIVATE ${CARES_PLATFORM_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE third_party/googletest/include
-  PRIVATE third_party/googletest
+  PRIVATE third_party/googletest/googletest/include
+  PRIVATE third_party/googletest/googletest
   PRIVATE ${_gRPC_PROTO_GENS_DIR}
 )
 
@@ -9028,7 +9078,7 @@ if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_POSIX)
 
 add_executable(bm_fullstack_streaming_ping_pong
   test/cpp/microbenchmarks/bm_fullstack_streaming_ping_pong.cc
-  third_party/googletest/src/gtest-all.cc
+  third_party/googletest/googletest/src/gtest-all.cc
 )
 
 
@@ -9045,8 +9095,8 @@ target_include_directories(bm_fullstack_streaming_ping_pong
   PRIVATE ${CARES_PLATFORM_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE third_party/googletest/include
-  PRIVATE third_party/googletest
+  PRIVATE third_party/googletest/googletest/include
+  PRIVATE third_party/googletest/googletest
   PRIVATE ${_gRPC_PROTO_GENS_DIR}
 )
 
@@ -9071,7 +9121,7 @@ if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_POSIX)
 
 add_executable(bm_fullstack_streaming_pump
   test/cpp/microbenchmarks/bm_fullstack_streaming_pump.cc
-  third_party/googletest/src/gtest-all.cc
+  third_party/googletest/googletest/src/gtest-all.cc
 )
 
 
@@ -9088,8 +9138,8 @@ target_include_directories(bm_fullstack_streaming_pump
   PRIVATE ${CARES_PLATFORM_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE third_party/googletest/include
-  PRIVATE third_party/googletest
+  PRIVATE third_party/googletest/googletest/include
+  PRIVATE third_party/googletest/googletest
   PRIVATE ${_gRPC_PROTO_GENS_DIR}
 )
 
@@ -9114,7 +9164,7 @@ if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_POSIX)
 
 add_executable(bm_fullstack_trickle
   test/cpp/microbenchmarks/bm_fullstack_trickle.cc
-  third_party/googletest/src/gtest-all.cc
+  third_party/googletest/googletest/src/gtest-all.cc
 )
 
 
@@ -9131,8 +9181,8 @@ target_include_directories(bm_fullstack_trickle
   PRIVATE ${CARES_PLATFORM_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE third_party/googletest/include
-  PRIVATE third_party/googletest
+  PRIVATE third_party/googletest/googletest/include
+  PRIVATE third_party/googletest/googletest
   PRIVATE ${_gRPC_PROTO_GENS_DIR}
 )
 
@@ -9157,7 +9207,7 @@ if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_POSIX)
 
 add_executable(bm_fullstack_unary_ping_pong
   test/cpp/microbenchmarks/bm_fullstack_unary_ping_pong.cc
-  third_party/googletest/src/gtest-all.cc
+  third_party/googletest/googletest/src/gtest-all.cc
 )
 
 
@@ -9174,8 +9224,8 @@ target_include_directories(bm_fullstack_unary_ping_pong
   PRIVATE ${CARES_PLATFORM_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE third_party/googletest/include
-  PRIVATE third_party/googletest
+  PRIVATE third_party/googletest/googletest/include
+  PRIVATE third_party/googletest/googletest
   PRIVATE ${_gRPC_PROTO_GENS_DIR}
 )
 
@@ -9200,7 +9250,7 @@ if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_POSIX)
 
 add_executable(bm_metadata
   test/cpp/microbenchmarks/bm_metadata.cc
-  third_party/googletest/src/gtest-all.cc
+  third_party/googletest/googletest/src/gtest-all.cc
 )
 
 
@@ -9217,8 +9267,8 @@ target_include_directories(bm_metadata
   PRIVATE ${CARES_PLATFORM_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE third_party/googletest/include
-  PRIVATE third_party/googletest
+  PRIVATE third_party/googletest/googletest/include
+  PRIVATE third_party/googletest/googletest
   PRIVATE ${_gRPC_PROTO_GENS_DIR}
 )
 
@@ -9243,7 +9293,7 @@ if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_POSIX)
 
 add_executable(bm_pollset
   test/cpp/microbenchmarks/bm_pollset.cc
-  third_party/googletest/src/gtest-all.cc
+  third_party/googletest/googletest/src/gtest-all.cc
 )
 
 
@@ -9260,8 +9310,8 @@ target_include_directories(bm_pollset
   PRIVATE ${CARES_PLATFORM_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE third_party/googletest/include
-  PRIVATE third_party/googletest
+  PRIVATE third_party/googletest/googletest/include
+  PRIVATE third_party/googletest/googletest
   PRIVATE ${_gRPC_PROTO_GENS_DIR}
 )
 
@@ -9285,7 +9335,7 @@ if (gRPC_BUILD_TESTS)
 
 add_executable(channel_arguments_test
   test/cpp/common/channel_arguments_test.cc
-  third_party/googletest/src/gtest-all.cc
+  third_party/googletest/googletest/src/gtest-all.cc
 )
 
 
@@ -9302,8 +9352,8 @@ target_include_directories(channel_arguments_test
   PRIVATE ${CARES_PLATFORM_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE third_party/googletest/include
-  PRIVATE third_party/googletest
+  PRIVATE third_party/googletest/googletest/include
+  PRIVATE third_party/googletest/googletest
   PRIVATE ${_gRPC_PROTO_GENS_DIR}
 )
 
@@ -9321,7 +9371,7 @@ if (gRPC_BUILD_TESTS)
 
 add_executable(channel_filter_test
   test/cpp/common/channel_filter_test.cc
-  third_party/googletest/src/gtest-all.cc
+  third_party/googletest/googletest/src/gtest-all.cc
 )
 
 
@@ -9338,8 +9388,8 @@ target_include_directories(channel_filter_test
   PRIVATE ${CARES_PLATFORM_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE third_party/googletest/include
-  PRIVATE third_party/googletest
+  PRIVATE third_party/googletest/googletest/include
+  PRIVATE third_party/googletest/googletest
   PRIVATE ${_gRPC_PROTO_GENS_DIR}
 )
 
@@ -9357,7 +9407,7 @@ if (gRPC_BUILD_TESTS)
 
 add_executable(cli_call_test
   test/cpp/util/cli_call_test.cc
-  third_party/googletest/src/gtest-all.cc
+  third_party/googletest/googletest/src/gtest-all.cc
 )
 
 
@@ -9374,8 +9424,8 @@ target_include_directories(cli_call_test
   PRIVATE ${CARES_PLATFORM_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE third_party/googletest/include
-  PRIVATE third_party/googletest
+  PRIVATE third_party/googletest/googletest/include
+  PRIVATE third_party/googletest/googletest
   PRIVATE ${_gRPC_PROTO_GENS_DIR}
 )
 
@@ -9398,7 +9448,7 @@ if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_POSIX)
 
 add_executable(client_crash_test
   test/cpp/end2end/client_crash_test.cc
-  third_party/googletest/src/gtest-all.cc
+  third_party/googletest/googletest/src/gtest-all.cc
 )
 
 
@@ -9415,8 +9465,8 @@ target_include_directories(client_crash_test
   PRIVATE ${CARES_PLATFORM_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE third_party/googletest/include
-  PRIVATE third_party/googletest
+  PRIVATE third_party/googletest/googletest/include
+  PRIVATE third_party/googletest/googletest
   PRIVATE ${_gRPC_PROTO_GENS_DIR}
 )
 
@@ -9438,7 +9488,7 @@ if (gRPC_BUILD_TESTS)
 
 add_executable(client_crash_test_server
   test/cpp/end2end/client_crash_test_server.cc
-  third_party/googletest/src/gtest-all.cc
+  third_party/googletest/googletest/src/gtest-all.cc
 )
 
 
@@ -9455,8 +9505,8 @@ target_include_directories(client_crash_test_server
   PRIVATE ${CARES_PLATFORM_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE third_party/googletest/include
-  PRIVATE third_party/googletest
+  PRIVATE third_party/googletest/googletest/include
+  PRIVATE third_party/googletest/googletest
   PRIVATE ${_gRPC_PROTO_GENS_DIR}
 )
 
@@ -9497,7 +9547,7 @@ add_executable(codegen_test_full
   ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/stats.pb.h
   ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/stats.grpc.pb.h
   test/cpp/codegen/codegen_test_full.cc
-  third_party/googletest/src/gtest-all.cc
+  third_party/googletest/googletest/src/gtest-all.cc
 )
 
 protobuf_generate_grpc_cpp(
@@ -9529,8 +9579,8 @@ target_include_directories(codegen_test_full
   PRIVATE ${CARES_PLATFORM_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE third_party/googletest/include
-  PRIVATE third_party/googletest
+  PRIVATE third_party/googletest/googletest/include
+  PRIVATE third_party/googletest/googletest
   PRIVATE ${_gRPC_PROTO_GENS_DIR}
 )
 
@@ -9569,7 +9619,7 @@ add_executable(codegen_test_minimal
   ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/stats.grpc.pb.h
   test/cpp/codegen/codegen_test_minimal.cc
   src/cpp/codegen/codegen_init.cc
-  third_party/googletest/src/gtest-all.cc
+  third_party/googletest/googletest/src/gtest-all.cc
 )
 
 protobuf_generate_grpc_cpp(
@@ -9601,8 +9651,8 @@ target_include_directories(codegen_test_minimal
   PRIVATE ${CARES_PLATFORM_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE third_party/googletest/include
-  PRIVATE third_party/googletest
+  PRIVATE third_party/googletest/googletest/include
+  PRIVATE third_party/googletest/googletest
   PRIVATE ${_gRPC_PROTO_GENS_DIR}
 )
 
@@ -9617,7 +9667,7 @@ if (gRPC_BUILD_TESTS)
 
 add_executable(credentials_test
   test/cpp/client/credentials_test.cc
-  third_party/googletest/src/gtest-all.cc
+  third_party/googletest/googletest/src/gtest-all.cc
 )
 
 
@@ -9634,8 +9684,8 @@ target_include_directories(credentials_test
   PRIVATE ${CARES_PLATFORM_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE third_party/googletest/include
-  PRIVATE third_party/googletest
+  PRIVATE third_party/googletest/googletest/include
+  PRIVATE third_party/googletest/googletest
   PRIVATE ${_gRPC_PROTO_GENS_DIR}
 )
 
@@ -9653,7 +9703,7 @@ if (gRPC_BUILD_TESTS)
 
 add_executable(cxx_byte_buffer_test
   test/cpp/util/byte_buffer_test.cc
-  third_party/googletest/src/gtest-all.cc
+  third_party/googletest/googletest/src/gtest-all.cc
 )
 
 
@@ -9670,8 +9720,8 @@ target_include_directories(cxx_byte_buffer_test
   PRIVATE ${CARES_PLATFORM_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE third_party/googletest/include
-  PRIVATE third_party/googletest
+  PRIVATE third_party/googletest/googletest/include
+  PRIVATE third_party/googletest/googletest
   PRIVATE ${_gRPC_PROTO_GENS_DIR}
 )
 
@@ -9691,7 +9741,7 @@ if (gRPC_BUILD_TESTS)
 
 add_executable(cxx_slice_test
   test/cpp/util/slice_test.cc
-  third_party/googletest/src/gtest-all.cc
+  third_party/googletest/googletest/src/gtest-all.cc
 )
 
 
@@ -9708,8 +9758,8 @@ target_include_directories(cxx_slice_test
   PRIVATE ${CARES_PLATFORM_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE third_party/googletest/include
-  PRIVATE third_party/googletest
+  PRIVATE third_party/googletest/googletest/include
+  PRIVATE third_party/googletest/googletest
   PRIVATE ${_gRPC_PROTO_GENS_DIR}
 )
 
@@ -9729,7 +9779,7 @@ if (gRPC_BUILD_TESTS)
 
 add_executable(cxx_string_ref_test
   test/cpp/util/string_ref_test.cc
-  third_party/googletest/src/gtest-all.cc
+  third_party/googletest/googletest/src/gtest-all.cc
 )
 
 
@@ -9746,8 +9796,8 @@ target_include_directories(cxx_string_ref_test
   PRIVATE ${CARES_PLATFORM_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE third_party/googletest/include
-  PRIVATE third_party/googletest
+  PRIVATE third_party/googletest/googletest/include
+  PRIVATE third_party/googletest/googletest
   PRIVATE ${_gRPC_PROTO_GENS_DIR}
 )
 
@@ -9763,7 +9813,7 @@ if (gRPC_BUILD_TESTS)
 
 add_executable(cxx_time_test
   test/cpp/util/time_test.cc
-  third_party/googletest/src/gtest-all.cc
+  third_party/googletest/googletest/src/gtest-all.cc
 )
 
 
@@ -9780,8 +9830,8 @@ target_include_directories(cxx_time_test
   PRIVATE ${CARES_PLATFORM_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE third_party/googletest/include
-  PRIVATE third_party/googletest
+  PRIVATE third_party/googletest/googletest/include
+  PRIVATE third_party/googletest/googletest
   PRIVATE ${_gRPC_PROTO_GENS_DIR}
 )
 
@@ -9801,7 +9851,7 @@ if (gRPC_BUILD_TESTS)
 
 add_executable(end2end_test
   test/cpp/end2end/end2end_test.cc
-  third_party/googletest/src/gtest-all.cc
+  third_party/googletest/googletest/src/gtest-all.cc
 )
 
 
@@ -9818,8 +9868,8 @@ target_include_directories(end2end_test
   PRIVATE ${CARES_PLATFORM_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE third_party/googletest/include
-  PRIVATE third_party/googletest
+  PRIVATE third_party/googletest/googletest/include
+  PRIVATE third_party/googletest/googletest
   PRIVATE ${_gRPC_PROTO_GENS_DIR}
 )
 
@@ -9840,7 +9890,7 @@ if (gRPC_BUILD_TESTS)
 
 add_executable(filter_end2end_test
   test/cpp/end2end/filter_end2end_test.cc
-  third_party/googletest/src/gtest-all.cc
+  third_party/googletest/googletest/src/gtest-all.cc
 )
 
 
@@ -9857,8 +9907,8 @@ target_include_directories(filter_end2end_test
   PRIVATE ${CARES_PLATFORM_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE third_party/googletest/include
-  PRIVATE third_party/googletest
+  PRIVATE third_party/googletest/googletest/include
+  PRIVATE third_party/googletest/googletest
   PRIVATE ${_gRPC_PROTO_GENS_DIR}
 )
 
@@ -9879,7 +9929,7 @@ if (gRPC_BUILD_TESTS)
 
 add_executable(generic_end2end_test
   test/cpp/end2end/generic_end2end_test.cc
-  third_party/googletest/src/gtest-all.cc
+  third_party/googletest/googletest/src/gtest-all.cc
 )
 
 
@@ -9896,8 +9946,8 @@ target_include_directories(generic_end2end_test
   PRIVATE ${CARES_PLATFORM_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE third_party/googletest/include
-  PRIVATE third_party/googletest
+  PRIVATE third_party/googletest/googletest/include
+  PRIVATE third_party/googletest/googletest
   PRIVATE ${_gRPC_PROTO_GENS_DIR}
 )
 
@@ -9922,7 +9972,7 @@ add_executable(golden_file_test
   ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/compiler_test.pb.h
   ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/compiler_test.grpc.pb.h
   test/cpp/codegen/golden_file_test.cc
-  third_party/googletest/src/gtest-all.cc
+  third_party/googletest/googletest/src/gtest-all.cc
 )
 
 protobuf_generate_grpc_cpp(
@@ -9942,8 +9992,8 @@ target_include_directories(golden_file_test
   PRIVATE ${CARES_PLATFORM_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE third_party/googletest/include
-  PRIVATE third_party/googletest
+  PRIVATE third_party/googletest/googletest/include
+  PRIVATE third_party/googletest/googletest
   PRIVATE ${_gRPC_PROTO_GENS_DIR}
 )
 
@@ -9961,7 +10011,7 @@ if (gRPC_BUILD_TESTS)
 
 add_executable(grpc_cli
   test/cpp/util/grpc_cli.cc
-  third_party/googletest/src/gtest-all.cc
+  third_party/googletest/googletest/src/gtest-all.cc
 )
 
 
@@ -9978,8 +10028,8 @@ target_include_directories(grpc_cli
   PRIVATE ${CARES_PLATFORM_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE third_party/googletest/include
-  PRIVATE third_party/googletest
+  PRIVATE third_party/googletest/googletest/include
+  PRIVATE third_party/googletest/googletest
   PRIVATE ${_gRPC_PROTO_GENS_DIR}
 )
 
@@ -10274,7 +10324,7 @@ add_executable(grpc_tool_test
   ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/echo_messages.pb.h
   ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/echo_messages.grpc.pb.h
   test/cpp/util/grpc_tool_test.cc
-  third_party/googletest/src/gtest-all.cc
+  third_party/googletest/googletest/src/gtest-all.cc
 )
 
 protobuf_generate_grpc_cpp(
@@ -10297,8 +10347,8 @@ target_include_directories(grpc_tool_test
   PRIVATE ${CARES_PLATFORM_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE third_party/googletest/include
-  PRIVATE third_party/googletest
+  PRIVATE third_party/googletest/googletest/include
+  PRIVATE third_party/googletest/googletest
   PRIVATE ${_gRPC_PROTO_GENS_DIR}
 )
 
@@ -10326,7 +10376,7 @@ add_executable(grpclb_api_test
   ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/lb/v1/load_balancer.pb.h
   ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/lb/v1/load_balancer.grpc.pb.h
   test/cpp/grpclb/grpclb_api_test.cc
-  third_party/googletest/src/gtest-all.cc
+  third_party/googletest/googletest/src/gtest-all.cc
 )
 
 protobuf_generate_grpc_cpp(
@@ -10346,8 +10396,8 @@ target_include_directories(grpclb_api_test
   PRIVATE ${CARES_PLATFORM_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE third_party/googletest/include
-  PRIVATE third_party/googletest
+  PRIVATE third_party/googletest/googletest/include
+  PRIVATE third_party/googletest/googletest
   PRIVATE ${_gRPC_PROTO_GENS_DIR}
 )
 
@@ -10370,7 +10420,7 @@ add_executable(grpclb_test
   ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/lb/v1/load_balancer.pb.h
   ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/lb/v1/load_balancer.grpc.pb.h
   test/cpp/grpclb/grpclb_test.cc
-  third_party/googletest/src/gtest-all.cc
+  third_party/googletest/googletest/src/gtest-all.cc
 )
 
 protobuf_generate_grpc_cpp(
@@ -10390,8 +10440,8 @@ target_include_directories(grpclb_test
   PRIVATE ${CARES_PLATFORM_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE third_party/googletest/include
-  PRIVATE third_party/googletest
+  PRIVATE third_party/googletest/googletest/include
+  PRIVATE third_party/googletest/googletest
   PRIVATE ${_gRPC_PROTO_GENS_DIR}
 )
 
@@ -10412,7 +10462,7 @@ if (gRPC_BUILD_TESTS)
 
 add_executable(health_service_end2end_test
   test/cpp/end2end/health_service_end2end_test.cc
-  third_party/googletest/src/gtest-all.cc
+  third_party/googletest/googletest/src/gtest-all.cc
 )
 
 
@@ -10429,8 +10479,8 @@ target_include_directories(health_service_end2end_test
   PRIVATE ${CARES_PLATFORM_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE third_party/googletest/include
-  PRIVATE third_party/googletest
+  PRIVATE third_party/googletest/googletest/include
+  PRIVATE third_party/googletest/googletest
   PRIVATE ${_gRPC_PROTO_GENS_DIR}
 )
 
@@ -10451,7 +10501,7 @@ if (gRPC_BUILD_TESTS)
 if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_POSIX)
 
 add_executable(http2_client
-  third_party/googletest/src/gtest-all.cc
+  third_party/googletest/googletest/src/gtest-all.cc
 )
 
 
@@ -10468,8 +10518,8 @@ target_include_directories(http2_client
   PRIVATE ${CARES_PLATFORM_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE third_party/googletest/include
-  PRIVATE third_party/googletest
+  PRIVATE third_party/googletest/googletest/include
+  PRIVATE third_party/googletest/googletest
   PRIVATE ${_gRPC_PROTO_GENS_DIR}
 )
 
@@ -10491,7 +10541,7 @@ if (gRPC_BUILD_TESTS)
 
 add_executable(hybrid_end2end_test
   test/cpp/end2end/hybrid_end2end_test.cc
-  third_party/googletest/src/gtest-all.cc
+  third_party/googletest/googletest/src/gtest-all.cc
 )
 
 
@@ -10508,8 +10558,8 @@ target_include_directories(hybrid_end2end_test
   PRIVATE ${CARES_PLATFORM_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE third_party/googletest/include
-  PRIVATE third_party/googletest
+  PRIVATE third_party/googletest/googletest/include
+  PRIVATE third_party/googletest/googletest
   PRIVATE ${_gRPC_PROTO_GENS_DIR}
 )
 
@@ -10530,7 +10580,7 @@ if (gRPC_BUILD_TESTS)
 if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_POSIX)
 
 add_executable(interop_client
-  third_party/googletest/src/gtest-all.cc
+  third_party/googletest/googletest/src/gtest-all.cc
 )
 
 
@@ -10547,8 +10597,8 @@ target_include_directories(interop_client
   PRIVATE ${CARES_PLATFORM_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE third_party/googletest/include
-  PRIVATE third_party/googletest
+  PRIVATE third_party/googletest/googletest/include
+  PRIVATE third_party/googletest/googletest
   PRIVATE ${_gRPC_PROTO_GENS_DIR}
 )
 
@@ -10573,7 +10623,7 @@ if (gRPC_BUILD_TESTS)
 if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_POSIX)
 
 add_executable(interop_server
-  third_party/googletest/src/gtest-all.cc
+  third_party/googletest/googletest/src/gtest-all.cc
 )
 
 
@@ -10590,8 +10640,8 @@ target_include_directories(interop_server
   PRIVATE ${CARES_PLATFORM_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE third_party/googletest/include
-  PRIVATE third_party/googletest
+  PRIVATE third_party/googletest/googletest/include
+  PRIVATE third_party/googletest/googletest
   PRIVATE ${_gRPC_PROTO_GENS_DIR}
 )
 
@@ -10618,7 +10668,7 @@ if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_POSIX)
 
 add_executable(interop_test
   test/cpp/interop/interop_test.cc
-  third_party/googletest/src/gtest-all.cc
+  third_party/googletest/googletest/src/gtest-all.cc
 )
 
 
@@ -10635,8 +10685,8 @@ target_include_directories(interop_test
   PRIVATE ${CARES_PLATFORM_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE third_party/googletest/include
-  PRIVATE third_party/googletest
+  PRIVATE third_party/googletest/googletest/include
+  PRIVATE third_party/googletest/googletest
   PRIVATE ${_gRPC_PROTO_GENS_DIR}
 )
 
@@ -10658,7 +10708,7 @@ if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_POSIX)
 
 add_executable(json_run_localhost
   test/cpp/qps/json_run_localhost.cc
-  third_party/googletest/src/gtest-all.cc
+  third_party/googletest/googletest/src/gtest-all.cc
 )
 
 
@@ -10675,8 +10725,8 @@ target_include_directories(json_run_localhost
   PRIVATE ${CARES_PLATFORM_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE third_party/googletest/include
-  PRIVATE third_party/googletest
+  PRIVATE third_party/googletest/googletest/include
+  PRIVATE third_party/googletest/googletest
   PRIVATE ${_gRPC_PROTO_GENS_DIR}
 )
 
@@ -10703,7 +10753,7 @@ add_executable(metrics_client
   ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/metrics.pb.h
   ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/metrics.grpc.pb.h
   test/cpp/interop/metrics_client.cc
-  third_party/googletest/src/gtest-all.cc
+  third_party/googletest/googletest/src/gtest-all.cc
 )
 
 protobuf_generate_grpc_cpp(
@@ -10723,8 +10773,8 @@ target_include_directories(metrics_client
   PRIVATE ${CARES_PLATFORM_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE third_party/googletest/include
-  PRIVATE third_party/googletest
+  PRIVATE third_party/googletest/googletest/include
+  PRIVATE third_party/googletest/googletest
   PRIVATE ${_gRPC_PROTO_GENS_DIR}
 )
 
@@ -10743,7 +10793,7 @@ if (gRPC_BUILD_TESTS)
 
 add_executable(mock_test
   test/cpp/end2end/mock_test.cc
-  third_party/googletest/src/gtest-all.cc
+  third_party/googletest/googletest/src/gtest-all.cc
 )
 
 
@@ -10760,8 +10810,8 @@ target_include_directories(mock_test
   PRIVATE ${CARES_PLATFORM_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE third_party/googletest/include
-  PRIVATE third_party/googletest
+  PRIVATE third_party/googletest/googletest/include
+  PRIVATE third_party/googletest/googletest
   PRIVATE ${_gRPC_PROTO_GENS_DIR}
 )
 
@@ -10782,7 +10832,7 @@ if (gRPC_BUILD_TESTS)
 
 add_executable(noop-benchmark
   test/cpp/microbenchmarks/noop-benchmark.cc
-  third_party/googletest/src/gtest-all.cc
+  third_party/googletest/googletest/src/gtest-all.cc
 )
 
 
@@ -10799,8 +10849,8 @@ target_include_directories(noop-benchmark
   PRIVATE ${CARES_PLATFORM_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE third_party/googletest/include
-  PRIVATE third_party/googletest
+  PRIVATE third_party/googletest/googletest/include
+  PRIVATE third_party/googletest/googletest
   PRIVATE ${_gRPC_PROTO_GENS_DIR}
 )
 
@@ -10816,7 +10866,7 @@ if (gRPC_BUILD_TESTS)
 
 add_executable(proto_server_reflection_test
   test/cpp/end2end/proto_server_reflection_test.cc
-  third_party/googletest/src/gtest-all.cc
+  third_party/googletest/googletest/src/gtest-all.cc
 )
 
 
@@ -10833,8 +10883,8 @@ target_include_directories(proto_server_reflection_test
   PRIVATE ${CARES_PLATFORM_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE third_party/googletest/include
-  PRIVATE third_party/googletest
+  PRIVATE third_party/googletest/googletest/include
+  PRIVATE third_party/googletest/googletest
   PRIVATE ${_gRPC_PROTO_GENS_DIR}
 )
 
@@ -10857,7 +10907,7 @@ if (gRPC_BUILD_TESTS)
 
 add_executable(proto_utils_test
   test/cpp/codegen/proto_utils_test.cc
-  third_party/googletest/src/gtest-all.cc
+  third_party/googletest/googletest/src/gtest-all.cc
 )
 
 
@@ -10874,8 +10924,8 @@ target_include_directories(proto_utils_test
   PRIVATE ${CARES_PLATFORM_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE third_party/googletest/include
-  PRIVATE third_party/googletest
+  PRIVATE third_party/googletest/googletest/include
+  PRIVATE third_party/googletest/googletest
   PRIVATE ${_gRPC_PROTO_GENS_DIR}
 )
 
@@ -10893,7 +10943,7 @@ if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_POSIX)
 
 add_executable(qps_interarrival_test
   test/cpp/qps/qps_interarrival_test.cc
-  third_party/googletest/src/gtest-all.cc
+  third_party/googletest/googletest/src/gtest-all.cc
 )
 
 
@@ -10910,8 +10960,8 @@ target_include_directories(qps_interarrival_test
   PRIVATE ${CARES_PLATFORM_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE third_party/googletest/include
-  PRIVATE third_party/googletest
+  PRIVATE third_party/googletest/googletest/include
+  PRIVATE third_party/googletest/googletest
   PRIVATE ${_gRPC_PROTO_GENS_DIR}
 )
 
@@ -10934,7 +10984,7 @@ if (gRPC_BUILD_TESTS)
 
 add_executable(qps_json_driver
   test/cpp/qps/qps_json_driver.cc
-  third_party/googletest/src/gtest-all.cc
+  third_party/googletest/googletest/src/gtest-all.cc
 )
 
 
@@ -10951,8 +11001,8 @@ target_include_directories(qps_json_driver
   PRIVATE ${CARES_PLATFORM_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE third_party/googletest/include
-  PRIVATE third_party/googletest
+  PRIVATE third_party/googletest/googletest/include
+  PRIVATE third_party/googletest/googletest
   PRIVATE ${_gRPC_PROTO_GENS_DIR}
 )
 
@@ -10976,7 +11026,7 @@ if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_POSIX)
 
 add_executable(qps_openloop_test
   test/cpp/qps/qps_openloop_test.cc
-  third_party/googletest/src/gtest-all.cc
+  third_party/googletest/googletest/src/gtest-all.cc
 )
 
 
@@ -10993,8 +11043,8 @@ target_include_directories(qps_openloop_test
   PRIVATE ${CARES_PLATFORM_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE third_party/googletest/include
-  PRIVATE third_party/googletest
+  PRIVATE third_party/googletest/googletest/include
+  PRIVATE third_party/googletest/googletest
   PRIVATE ${_gRPC_PROTO_GENS_DIR}
 )
 
@@ -11018,7 +11068,7 @@ if (gRPC_BUILD_TESTS)
 
 add_executable(qps_worker
   test/cpp/qps/worker.cc
-  third_party/googletest/src/gtest-all.cc
+  third_party/googletest/googletest/src/gtest-all.cc
 )
 
 
@@ -11035,8 +11085,8 @@ target_include_directories(qps_worker
   PRIVATE ${CARES_PLATFORM_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE third_party/googletest/include
-  PRIVATE third_party/googletest
+  PRIVATE third_party/googletest/googletest/include
+  PRIVATE third_party/googletest/googletest
   PRIVATE ${_gRPC_PROTO_GENS_DIR}
 )
 
@@ -11071,7 +11121,7 @@ add_executable(reconnect_interop_client
   ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/test.pb.h
   ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/test.grpc.pb.h
   test/cpp/interop/reconnect_interop_client.cc
-  third_party/googletest/src/gtest-all.cc
+  third_party/googletest/googletest/src/gtest-all.cc
 )
 
 protobuf_generate_grpc_cpp(
@@ -11097,8 +11147,8 @@ target_include_directories(reconnect_interop_client
   PRIVATE ${CARES_PLATFORM_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE third_party/googletest/include
-  PRIVATE third_party/googletest
+  PRIVATE third_party/googletest/googletest/include
+  PRIVATE third_party/googletest/googletest
   PRIVATE ${_gRPC_PROTO_GENS_DIR}
 )
 
@@ -11132,7 +11182,7 @@ add_executable(reconnect_interop_server
   ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/test.pb.h
   ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/test.grpc.pb.h
   test/cpp/interop/reconnect_interop_server.cc
-  third_party/googletest/src/gtest-all.cc
+  third_party/googletest/googletest/src/gtest-all.cc
 )
 
 protobuf_generate_grpc_cpp(
@@ -11158,8 +11208,8 @@ target_include_directories(reconnect_interop_server
   PRIVATE ${CARES_PLATFORM_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE third_party/googletest/include
-  PRIVATE third_party/googletest
+  PRIVATE third_party/googletest/googletest/include
+  PRIVATE third_party/googletest/googletest
   PRIVATE ${_gRPC_PROTO_GENS_DIR}
 )
 
@@ -11183,7 +11233,7 @@ if (gRPC_BUILD_TESTS)
 
 add_executable(round_robin_end2end_test
   test/cpp/end2end/round_robin_end2end_test.cc
-  third_party/googletest/src/gtest-all.cc
+  third_party/googletest/googletest/src/gtest-all.cc
 )
 
 
@@ -11200,8 +11250,8 @@ target_include_directories(round_robin_end2end_test
   PRIVATE ${CARES_PLATFORM_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE third_party/googletest/include
-  PRIVATE third_party/googletest
+  PRIVATE third_party/googletest/googletest/include
+  PRIVATE third_party/googletest/googletest
   PRIVATE ${_gRPC_PROTO_GENS_DIR}
 )
 
@@ -11222,7 +11272,7 @@ if (gRPC_BUILD_TESTS)
 
 add_executable(secure_auth_context_test
   test/cpp/common/secure_auth_context_test.cc
-  third_party/googletest/src/gtest-all.cc
+  third_party/googletest/googletest/src/gtest-all.cc
 )
 
 
@@ -11239,8 +11289,8 @@ target_include_directories(secure_auth_context_test
   PRIVATE ${CARES_PLATFORM_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE third_party/googletest/include
-  PRIVATE third_party/googletest
+  PRIVATE third_party/googletest/googletest/include
+  PRIVATE third_party/googletest/googletest
   PRIVATE ${_gRPC_PROTO_GENS_DIR}
 )
 
@@ -11262,7 +11312,7 @@ if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_POSIX)
 
 add_executable(secure_sync_unary_ping_pong_test
   test/cpp/qps/secure_sync_unary_ping_pong_test.cc
-  third_party/googletest/src/gtest-all.cc
+  third_party/googletest/googletest/src/gtest-all.cc
 )
 
 
@@ -11279,8 +11329,8 @@ target_include_directories(secure_sync_unary_ping_pong_test
   PRIVATE ${CARES_PLATFORM_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE third_party/googletest/include
-  PRIVATE third_party/googletest
+  PRIVATE third_party/googletest/googletest/include
+  PRIVATE third_party/googletest/googletest
   PRIVATE ${_gRPC_PROTO_GENS_DIR}
 )
 
@@ -11303,7 +11353,7 @@ if (gRPC_BUILD_TESTS)
 
 add_executable(server_builder_plugin_test
   test/cpp/end2end/server_builder_plugin_test.cc
-  third_party/googletest/src/gtest-all.cc
+  third_party/googletest/googletest/src/gtest-all.cc
 )
 
 
@@ -11320,8 +11370,8 @@ target_include_directories(server_builder_plugin_test
   PRIVATE ${CARES_PLATFORM_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE third_party/googletest/include
-  PRIVATE third_party/googletest
+  PRIVATE third_party/googletest/googletest/include
+  PRIVATE third_party/googletest/googletest
   PRIVATE ${_gRPC_PROTO_GENS_DIR}
 )
 
@@ -11350,7 +11400,7 @@ add_executable(server_builder_test
   ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/echo.pb.h
   ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/echo.grpc.pb.h
   test/cpp/server/server_builder_test.cc
-  third_party/googletest/src/gtest-all.cc
+  third_party/googletest/googletest/src/gtest-all.cc
 )
 
 protobuf_generate_grpc_cpp(
@@ -11373,8 +11423,8 @@ target_include_directories(server_builder_test
   PRIVATE ${CARES_PLATFORM_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE third_party/googletest/include
-  PRIVATE third_party/googletest
+  PRIVATE third_party/googletest/googletest/include
+  PRIVATE third_party/googletest/googletest
   PRIVATE ${_gRPC_PROTO_GENS_DIR}
 )
 
@@ -11395,7 +11445,7 @@ if (gRPC_BUILD_TESTS)
 
 add_executable(server_context_test_spouse_test
   test/cpp/test/server_context_test_spouse_test.cc
-  third_party/googletest/src/gtest-all.cc
+  third_party/googletest/googletest/src/gtest-all.cc
 )
 
 
@@ -11412,8 +11462,8 @@ target_include_directories(server_context_test_spouse_test
   PRIVATE ${CARES_PLATFORM_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE third_party/googletest/include
-  PRIVATE third_party/googletest
+  PRIVATE third_party/googletest/googletest/include
+  PRIVATE third_party/googletest/googletest
   PRIVATE ${_gRPC_PROTO_GENS_DIR}
 )
 
@@ -11434,7 +11484,7 @@ if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_POSIX)
 
 add_executable(server_crash_test
   test/cpp/end2end/server_crash_test.cc
-  third_party/googletest/src/gtest-all.cc
+  third_party/googletest/googletest/src/gtest-all.cc
 )
 
 
@@ -11451,8 +11501,8 @@ target_include_directories(server_crash_test
   PRIVATE ${CARES_PLATFORM_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE third_party/googletest/include
-  PRIVATE third_party/googletest
+  PRIVATE third_party/googletest/googletest/include
+  PRIVATE third_party/googletest/googletest
   PRIVATE ${_gRPC_PROTO_GENS_DIR}
 )
 
@@ -11474,7 +11524,7 @@ if (gRPC_BUILD_TESTS)
 
 add_executable(server_crash_test_client
   test/cpp/end2end/server_crash_test_client.cc
-  third_party/googletest/src/gtest-all.cc
+  third_party/googletest/googletest/src/gtest-all.cc
 )
 
 
@@ -11491,8 +11541,8 @@ target_include_directories(server_crash_test_client
   PRIVATE ${CARES_PLATFORM_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE third_party/googletest/include
-  PRIVATE third_party/googletest
+  PRIVATE third_party/googletest/googletest/include
+  PRIVATE third_party/googletest/googletest
   PRIVATE ${_gRPC_PROTO_GENS_DIR}
 )
 
@@ -11513,7 +11563,7 @@ if (gRPC_BUILD_TESTS)
 
 add_executable(shutdown_test
   test/cpp/end2end/shutdown_test.cc
-  third_party/googletest/src/gtest-all.cc
+  third_party/googletest/googletest/src/gtest-all.cc
 )
 
 
@@ -11530,8 +11580,8 @@ target_include_directories(shutdown_test
   PRIVATE ${CARES_PLATFORM_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE third_party/googletest/include
-  PRIVATE third_party/googletest
+  PRIVATE third_party/googletest/googletest/include
+  PRIVATE third_party/googletest/googletest
   PRIVATE ${_gRPC_PROTO_GENS_DIR}
 )
 
@@ -11552,7 +11602,7 @@ if (gRPC_BUILD_TESTS)
 
 add_executable(status_test
   test/cpp/util/status_test.cc
-  third_party/googletest/src/gtest-all.cc
+  third_party/googletest/googletest/src/gtest-all.cc
 )
 
 
@@ -11569,8 +11619,8 @@ target_include_directories(status_test
   PRIVATE ${CARES_PLATFORM_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE third_party/googletest/include
-  PRIVATE third_party/googletest
+  PRIVATE third_party/googletest/googletest/include
+  PRIVATE third_party/googletest/googletest
   PRIVATE ${_gRPC_PROTO_GENS_DIR}
 )
 
@@ -11591,7 +11641,7 @@ if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_POSIX)
 
 add_executable(streaming_throughput_test
   test/cpp/end2end/streaming_throughput_test.cc
-  third_party/googletest/src/gtest-all.cc
+  third_party/googletest/googletest/src/gtest-all.cc
 )
 
 
@@ -11608,8 +11658,8 @@ target_include_directories(streaming_throughput_test
   PRIVATE ${CARES_PLATFORM_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE third_party/googletest/include
-  PRIVATE third_party/googletest
+  PRIVATE third_party/googletest/googletest/include
+  PRIVATE third_party/googletest/googletest
   PRIVATE ${_gRPC_PROTO_GENS_DIR}
 )
 
@@ -11650,7 +11700,7 @@ add_executable(stress_test
   test/cpp/interop/stress_interop_client.cc
   test/cpp/interop/stress_test.cc
   test/cpp/util/metrics_server.cc
-  third_party/googletest/src/gtest-all.cc
+  third_party/googletest/googletest/src/gtest-all.cc
 )
 
 protobuf_generate_grpc_cpp(
@@ -11679,8 +11729,8 @@ target_include_directories(stress_test
   PRIVATE ${CARES_PLATFORM_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE third_party/googletest/include
-  PRIVATE third_party/googletest
+  PRIVATE third_party/googletest/googletest/include
+  PRIVATE third_party/googletest/googletest
   PRIVATE ${_gRPC_PROTO_GENS_DIR}
 )
 
@@ -11702,7 +11752,7 @@ if (gRPC_BUILD_TESTS)
 
 add_executable(thread_manager_test
   test/cpp/thread_manager/thread_manager_test.cc
-  third_party/googletest/src/gtest-all.cc
+  third_party/googletest/googletest/src/gtest-all.cc
 )
 
 
@@ -11719,8 +11769,8 @@ target_include_directories(thread_manager_test
   PRIVATE ${CARES_PLATFORM_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE third_party/googletest/include
-  PRIVATE third_party/googletest
+  PRIVATE third_party/googletest/googletest/include
+  PRIVATE third_party/googletest/googletest
   PRIVATE ${_gRPC_PROTO_GENS_DIR}
 )
 
@@ -11739,7 +11789,7 @@ if (gRPC_BUILD_TESTS)
 
 add_executable(thread_stress_test
   test/cpp/end2end/thread_stress_test.cc
-  third_party/googletest/src/gtest-all.cc
+  third_party/googletest/googletest/src/gtest-all.cc
 )
 
 
@@ -11756,8 +11806,8 @@ target_include_directories(thread_stress_test
   PRIVATE ${CARES_PLATFORM_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE third_party/googletest/include
-  PRIVATE third_party/googletest
+  PRIVATE third_party/googletest/googletest/include
+  PRIVATE third_party/googletest/googletest
   PRIVATE ${_gRPC_PROTO_GENS_DIR}
 )
 
@@ -11779,7 +11829,7 @@ if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_POSIX)
 
 add_executable(writes_per_rpc_test
   test/cpp/performance/writes_per_rpc_test.cc
-  third_party/googletest/src/gtest-all.cc
+  third_party/googletest/googletest/src/gtest-all.cc
 )
 
 
@@ -11796,8 +11846,8 @@ target_include_directories(writes_per_rpc_test
   PRIVATE ${CARES_PLATFORM_INCLUDE_DIR}
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares
   PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include
-  PRIVATE third_party/googletest/include
-  PRIVATE third_party/googletest
+  PRIVATE third_party/googletest/googletest/include
+  PRIVATE third_party/googletest/googletest
   PRIVATE ${_gRPC_PROTO_GENS_DIR}
 )
 
diff --git a/Makefile b/Makefile
index b0dcfc21c5977bce2fda3d3a16148f9c18fe0002..02840b3c26ce6b769f670b8445f924ee449a2573 100644
--- a/Makefile
+++ b/Makefile
@@ -409,7 +409,7 @@ AROPTS = $(GRPC_CROSS_AROPTS) # e.g., rc --target=elf32-little
 USE_BUILT_PROTOC = false
 endif
 
-GTEST_LIB = -Ithird_party/googletest/include -Ithird_party/googletest third_party/googletest/src/gtest-all.cc
+GTEST_LIB = -Ithird_party/googletest/googletest/include -Ithird_party/googletest/googletest third_party/googletest/googletest/src/gtest-all.cc
 GTEST_LIB += -lgflags
 ifeq ($(V),1)
 E = @:
@@ -784,7 +784,7 @@ PROTOBUF_PKG_CONFIG = false
 PC_REQUIRES_GRPCXX =
 PC_LIBS_GRPCXX =
 
-CPPFLAGS := -Ithird_party/googletest/include $(CPPFLAGS)
+CPPFLAGS := -Ithird_party/googletest/googletest/include $(CPPFLAGS)
 
 PROTOC_PLUGINS_ALL = $(BINDIR)/$(CONFIG)/grpc_cpp_plugin $(BINDIR)/$(CONFIG)/grpc_csharp_plugin $(BINDIR)/$(CONFIG)/grpc_node_plugin $(BINDIR)/$(CONFIG)/grpc_objective_c_plugin $(BINDIR)/$(CONFIG)/grpc_php_plugin $(BINDIR)/$(CONFIG)/grpc_python_plugin $(BINDIR)/$(CONFIG)/grpc_ruby_plugin
 PROTOC_PLUGINS_DIR = $(BINDIR)/$(CONFIG)
@@ -1105,6 +1105,7 @@ bm_chttp2_hpack: $(BINDIR)/$(CONFIG)/bm_chttp2_hpack
 bm_chttp2_transport: $(BINDIR)/$(CONFIG)/bm_chttp2_transport
 bm_closure: $(BINDIR)/$(CONFIG)/bm_closure
 bm_cq: $(BINDIR)/$(CONFIG)/bm_cq
+bm_cq_multiple_threads: $(BINDIR)/$(CONFIG)/bm_cq_multiple_threads
 bm_error: $(BINDIR)/$(CONFIG)/bm_error
 bm_fullstack_streaming_ping_pong: $(BINDIR)/$(CONFIG)/bm_fullstack_streaming_ping_pong
 bm_fullstack_streaming_pump: $(BINDIR)/$(CONFIG)/bm_fullstack_streaming_pump
@@ -1530,6 +1531,7 @@ buildtests_cxx: privatelibs_cxx \
   $(BINDIR)/$(CONFIG)/bm_chttp2_transport \
   $(BINDIR)/$(CONFIG)/bm_closure \
   $(BINDIR)/$(CONFIG)/bm_cq \
+  $(BINDIR)/$(CONFIG)/bm_cq_multiple_threads \
   $(BINDIR)/$(CONFIG)/bm_error \
   $(BINDIR)/$(CONFIG)/bm_fullstack_streaming_ping_pong \
   $(BINDIR)/$(CONFIG)/bm_fullstack_streaming_pump \
@@ -1648,6 +1650,7 @@ buildtests_cxx: privatelibs_cxx \
   $(BINDIR)/$(CONFIG)/bm_chttp2_transport \
   $(BINDIR)/$(CONFIG)/bm_closure \
   $(BINDIR)/$(CONFIG)/bm_cq \
+  $(BINDIR)/$(CONFIG)/bm_cq_multiple_threads \
   $(BINDIR)/$(CONFIG)/bm_error \
   $(BINDIR)/$(CONFIG)/bm_fullstack_streaming_ping_pong \
   $(BINDIR)/$(CONFIG)/bm_fullstack_streaming_pump \
@@ -1997,6 +2000,8 @@ test_cxx: buildtests_cxx
 	$(Q) $(BINDIR)/$(CONFIG)/bm_closure || ( echo test bm_closure failed ; exit 1 )
 	$(E) "[RUN]     Testing bm_cq"
 	$(Q) $(BINDIR)/$(CONFIG)/bm_cq || ( echo test bm_cq failed ; exit 1 )
+	$(E) "[RUN]     Testing bm_cq_multiple_threads"
+	$(Q) $(BINDIR)/$(CONFIG)/bm_cq_multiple_threads || ( echo test bm_cq_multiple_threads failed ; exit 1 )
 	$(E) "[RUN]     Testing bm_error"
 	$(Q) $(BINDIR)/$(CONFIG)/bm_error || ( echo test bm_error failed ; exit 1 )
 	$(E) "[RUN]     Testing bm_fullstack_streaming_ping_pong"
@@ -2383,12 +2388,12 @@ ifeq ($(NO_PROTOC),true)
 $(GENDIR)/src/proto/grpc/testing/services.pb.cc: protoc_dep_error
 $(GENDIR)/src/proto/grpc/testing/services.grpc.pb.cc: protoc_dep_error
 else
-$(GENDIR)/src/proto/grpc/testing/services.pb.cc: src/proto/grpc/testing/services.proto $(PROTOBUF_DEP) $(PROTOC_PLUGINS) $(GENDIR)/src/proto/grpc/testing/messages.pb.cc $(GENDIR)/src/proto/grpc/testing/control.pb.cc
+$(GENDIR)/src/proto/grpc/testing/services.pb.cc: src/proto/grpc/testing/services.proto $(PROTOBUF_DEP) $(PROTOC_PLUGINS) $(GENDIR)/src/proto/grpc/testing/messages.pb.cc $(GENDIR)/src/proto/grpc/testing/control.pb.cc $(GENDIR)/src/proto/grpc/testing/stats.pb.cc
 	$(E) "[PROTOC]  Generating protobuf CC file from $<"
 	$(Q) mkdir -p `dirname $@`
 	$(Q) $(PROTOC) -Ithird_party/protobuf/src -I. --cpp_out=$(GENDIR) $<
 
-$(GENDIR)/src/proto/grpc/testing/services.grpc.pb.cc: src/proto/grpc/testing/services.proto $(PROTOBUF_DEP) $(PROTOC_PLUGINS) $(GENDIR)/src/proto/grpc/testing/messages.pb.cc $(GENDIR)/src/proto/grpc/testing/messages.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/control.pb.cc $(GENDIR)/src/proto/grpc/testing/control.grpc.pb.cc
+$(GENDIR)/src/proto/grpc/testing/services.grpc.pb.cc: src/proto/grpc/testing/services.proto $(PROTOBUF_DEP) $(PROTOC_PLUGINS) $(GENDIR)/src/proto/grpc/testing/messages.pb.cc $(GENDIR)/src/proto/grpc/testing/messages.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/control.pb.cc $(GENDIR)/src/proto/grpc/testing/control.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/stats.pb.cc $(GENDIR)/src/proto/grpc/testing/stats.grpc.pb.cc
 	$(E) "[GRPC]    Generating gRPC's protobuf service CC file from $<"
 	$(Q) mkdir -p `dirname $@`
 	$(Q) $(PROTOC) -Ithird_party/protobuf/src -I. --grpc_out=$(GENDIR) --plugin=protoc-gen-grpc=$(PROTOC_PLUGINS_DIR)/grpc_cpp_plugin$(EXECUTABLE_SUFFIX) $<
@@ -2845,6 +2850,7 @@ LIBGRPC_SRC = \
     src/core/lib/iomgr/iomgr_uv.c \
     src/core/lib/iomgr/iomgr_windows.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 \
@@ -3166,6 +3172,7 @@ LIBGRPC_CRONET_SRC = \
     src/core/lib/iomgr/iomgr_uv.c \
     src/core/lib/iomgr/iomgr_windows.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 \
@@ -3474,6 +3481,7 @@ LIBGRPC_TEST_UTIL_SRC = \
     src/core/lib/iomgr/iomgr_uv.c \
     src/core/lib/iomgr/iomgr_windows.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 \
@@ -3706,6 +3714,7 @@ LIBGRPC_UNSECURE_SRC = \
     src/core/lib/iomgr/iomgr_uv.c \
     src/core/lib/iomgr/iomgr_windows.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 \
@@ -4100,6 +4109,7 @@ LIBGRPC++_SRC = \
     src/core/lib/iomgr/iomgr_uv.c \
     src/core/lib/iomgr/iomgr_windows.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 \
@@ -4438,6 +4448,7 @@ LIBGRPC++_CRONET_SRC = \
     src/core/lib/iomgr/iomgr_uv.c \
     src/core/lib/iomgr/iomgr_windows.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 \
@@ -5129,6 +5140,7 @@ LIBGRPC++_UNSECURE_SRC = \
     src/core/lib/iomgr/iomgr_uv.c \
     src/core/lib/iomgr/iomgr_windows.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 \
@@ -13364,6 +13376,50 @@ endif
 endif
 
 
+BM_CQ_MULTIPLE_THREADS_SRC = \
+    test/cpp/microbenchmarks/bm_cq_multiple_threads.cc \
+
+BM_CQ_MULTIPLE_THREADS_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(BM_CQ_MULTIPLE_THREADS_SRC))))
+ifeq ($(NO_SECURE),true)
+
+# You can't build secure targets if you don't have OpenSSL.
+
+$(BINDIR)/$(CONFIG)/bm_cq_multiple_threads: 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)/bm_cq_multiple_threads: protobuf_dep_error
+
+else
+
+$(BINDIR)/$(CONFIG)/bm_cq_multiple_threads: $(PROTOBUF_DEP) $(BM_CQ_MULTIPLE_THREADS_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc_benchmark.a $(LIBDIR)/$(CONFIG)/libbenchmark.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(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) $(BM_CQ_MULTIPLE_THREADS_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc_benchmark.a $(LIBDIR)/$(CONFIG)/libbenchmark.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(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)/bm_cq_multiple_threads
+
+endif
+
+endif
+
+$(BM_CQ_MULTIPLE_THREADS_OBJS): CPPFLAGS += -Ithird_party/benchmark/include -DHAVE_POSIX_REGEX
+$(OBJDIR)/$(CONFIG)/test/cpp/microbenchmarks/bm_cq_multiple_threads.o:  $(LIBDIR)/$(CONFIG)/libgrpc_benchmark.a $(LIBDIR)/$(CONFIG)/libbenchmark.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(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_bm_cq_multiple_threads: $(BM_CQ_MULTIPLE_THREADS_OBJS:.o=.dep)
+
+ifneq ($(NO_SECURE),true)
+ifneq ($(NO_DEPS),true)
+-include $(BM_CQ_MULTIPLE_THREADS_OBJS:.o=.dep)
+endif
+endif
+
+
 BM_ERROR_SRC = \
     test/cpp/microbenchmarks/bm_error.cc \
 
diff --git a/binding.gyp b/binding.gyp
index 61668115af81b482085ba35173e9ec7d532428f7..b33cef5a4ec168822cbacaa2ca3230255e80b7e7 100644
--- a/binding.gyp
+++ b/binding.gyp
@@ -519,9 +519,10 @@
           # the OpenSSL headers, from the downloaded Node development package,
           # which is typically located in `.node-gyp` in your home directory.
           'target_name': 'WINDOWS_BUILD_WARNING',
-          'actions': [
+          'rules': [
             {
-              'action_name': 'WINDOWS_BUILD_WARNING',
+              'rule_name': 'WINDOWS_BUILD_WARNING',
+              'extension': 'S',
               'inputs': [
                 'package.json'
               ],
@@ -685,6 +686,7 @@
         'src/core/lib/iomgr/iomgr_uv.c',
         'src/core/lib/iomgr/iomgr_windows.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',
diff --git a/build.yaml b/build.yaml
index def5ebf3a353adf5113681e3b8c391bcdda9642a..414950cd6fc4b5fd87820acd1724eaf0a0570a70 100644
--- a/build.yaml
+++ b/build.yaml
@@ -208,6 +208,7 @@ filegroups:
   - src/core/lib/iomgr/iomgr_internal.h
   - src/core/lib/iomgr/iomgr_posix.h
   - src/core/lib/iomgr/load_file.h
+  - src/core/lib/iomgr/lockfree_event.h
   - src/core/lib/iomgr/network_status_tracker.h
   - src/core/lib/iomgr/polling_entity.h
   - src/core/lib/iomgr/pollset.h
@@ -320,6 +321,7 @@ filegroups:
   - src/core/lib/iomgr/iomgr_uv.c
   - src/core/lib/iomgr/iomgr_windows.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
@@ -3219,6 +3221,27 @@ targets:
   - mac
   - linux
   - posix
+- name: bm_cq_multiple_threads
+  build: test
+  language: c++
+  src:
+  - test/cpp/microbenchmarks/bm_cq_multiple_threads.cc
+  deps:
+  - grpc_benchmark
+  - benchmark
+  - grpc++_test_util
+  - grpc_test_util
+  - grpc++
+  - grpc
+  - gpr_test_util
+  - gpr
+  args:
+  - --benchmark_min_time=0
+  defaults: benchmark
+  platforms:
+  - mac
+  - linux
+  - posix
 - name: bm_error
   build: test
   language: c++
diff --git a/cmake/msvc_static_runtime.cmake b/cmake/msvc_static_runtime.cmake
index 5a31ab3d2429e7c257dd892bc63beb546a08e491..fc6d1d62d32925e3f59bd30fe14c4e513116cae6 100644
--- a/cmake/msvc_static_runtime.cmake
+++ b/cmake/msvc_static_runtime.cmake
@@ -3,6 +3,8 @@ option(gRPC_MSVC_STATIC_RUNTIME "Link with static msvc runtime libraries" OFF)
 if(gRPC_MSVC_STATIC_RUNTIME)
   # switch from dynamic to static linking of msvcrt
   foreach(flag_var
+    CMAKE_C_FLAGS CMAKE_C_FLAGS_DEBUG CMAKE_C_FLAGS_RELEASE
+    CMAKE_C_FLAGS_MINSIZEREL CMAKE_C_FLAGS_RELWITHDEBINFO
     CMAKE_CXX_FLAGS CMAKE_CXX_FLAGS_DEBUG CMAKE_CXX_FLAGS_RELEASE
     CMAKE_CXX_FLAGS_MINSIZEREL CMAKE_CXX_FLAGS_RELWITHDEBINFO)
 
diff --git a/config.m4 b/config.m4
index c3a45540bc04fa744b3cf0d85f5253a2d19d7043..c414fc3620fb7cd077b1108e4b2df0dabd9e302d 100644
--- a/config.m4
+++ b/config.m4
@@ -119,6 +119,7 @@ if test "$PHP_GRPC" != "no"; then
     src/core/lib/iomgr/iomgr_uv.c \
     src/core/lib/iomgr/iomgr_windows.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 \
diff --git a/doc/PROTOCOL-WEB.md b/doc/PROTOCOL-WEB.md
index 5f01af362734d0e319d96362a097a66eb295860a..6bb280894ab9e8a8b8c87560c68afaeed0ca1d03 100644
--- a/doc/PROTOCOL-WEB.md
+++ b/doc/PROTOCOL-WEB.md
@@ -83,7 +83,8 @@ in the body.
 
 User Agent
 
-* U-A: grpc-web-javascript
+* Do NOT use User-Agent header (which is to be set by browsers, by default)
+* Use X-User-Agent: grpc-web-javascript/0.1 (follow the same format as specified in [gRPC over HTTP2](http://www.grpc.io/docs/guides/wire.html))
 
 ---
 
diff --git a/etc/roots.pem b/etc/roots.pem
index 66605675ef0377015f3161ca21d6e464a3157129..b2096fbc4d3c89eb0eebbbf11743c6c76238488f 100644
--- a/etc/roots.pem
+++ b/etc/roots.pem
@@ -1617,42 +1617,6 @@ wKeI8lN3s2Berq4o2jUsbzRF0ybh3uxbTydrFny9RAQYgrOJeRcQcT16ohZO9QHN
 pGxlaKFJdlxDydi8NmdspZS11My5vWo1ViHe2MPr+8ukYEywVaCge1ey
 -----END CERTIFICATE-----
 
-# Issuer: CN=WellsSecure Public Root Certificate Authority O=Wells Fargo WellsSecure OU=Wells Fargo Bank NA
-# Subject: CN=WellsSecure Public Root Certificate Authority O=Wells Fargo WellsSecure OU=Wells Fargo Bank NA
-# Label: "WellsSecure Public Root Certificate Authority"
-# Serial: 1
-# MD5 Fingerprint: 15:ac:a5:c2:92:2d:79:bc:e8:7f:cb:67:ed:02:cf:36
-# SHA1 Fingerprint: e7:b4:f6:9d:61:ec:90:69:db:7e:90:a7:40:1a:3c:f4:7d:4f:e8:ee
-# SHA256 Fingerprint: a7:12:72:ae:aa:a3:cf:e8:72:7f:7f:b3:9f:0f:b3:d1:e5:42:6e:90:60:b0:6e:e6:f1:3e:9a:3c:58:33:cd:43
------BEGIN CERTIFICATE-----
-MIIEvTCCA6WgAwIBAgIBATANBgkqhkiG9w0BAQUFADCBhTELMAkGA1UEBhMCVVMx
-IDAeBgNVBAoMF1dlbGxzIEZhcmdvIFdlbGxzU2VjdXJlMRwwGgYDVQQLDBNXZWxs
-cyBGYXJnbyBCYW5rIE5BMTYwNAYDVQQDDC1XZWxsc1NlY3VyZSBQdWJsaWMgUm9v
-dCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkwHhcNMDcxMjEzMTcwNzU0WhcNMjIxMjE0
-MDAwNzU0WjCBhTELMAkGA1UEBhMCVVMxIDAeBgNVBAoMF1dlbGxzIEZhcmdvIFdl
-bGxzU2VjdXJlMRwwGgYDVQQLDBNXZWxscyBGYXJnbyBCYW5rIE5BMTYwNAYDVQQD
-DC1XZWxsc1NlY3VyZSBQdWJsaWMgUm9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkw
-ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDub7S9eeKPCCGeOARBJe+r
-WxxTkqxtnt3CxC5FlAM1iGd0V+PfjLindo8796jE2yljDpFoNoqXjopxaAkH5OjU
-Dk/41itMpBb570OYj7OeUt9tkTmPOL13i0Nj67eT/DBMHAGTthP796EfvyXhdDcs
-HqRePGj4S78NuR4uNuip5Kf4D8uCdXw1LSLWwr8L87T8bJVhHlfXBIEyg1J55oNj
-z7fLY4sR4r1e6/aN7ZVyKLSsEmLpSjPmgzKuBXWVvYSV2ypcm44uDLiBK0HmOFaf
-SZtsdvqKXfcBeYF8wYNABf5x/Qw/zE5gCQ5lRxAvAcAFP4/4s0HvWkJ+We/Slwxl
-AgMBAAGjggE0MIIBMDAPBgNVHRMBAf8EBTADAQH/MDkGA1UdHwQyMDAwLqAsoCqG
-KGh0dHA6Ly9jcmwucGtpLndlbGxzZmFyZ28uY29tL3dzcHJjYS5jcmwwDgYDVR0P
-AQH/BAQDAgHGMB0GA1UdDgQWBBQmlRkQ2eihl5H/3BnZtQQ+0nMKajCBsgYDVR0j
-BIGqMIGngBQmlRkQ2eihl5H/3BnZtQQ+0nMKaqGBi6SBiDCBhTELMAkGA1UEBhMC
-VVMxIDAeBgNVBAoMF1dlbGxzIEZhcmdvIFdlbGxzU2VjdXJlMRwwGgYDVQQLDBNX
-ZWxscyBGYXJnbyBCYW5rIE5BMTYwNAYDVQQDDC1XZWxsc1NlY3VyZSBQdWJsaWMg
-Um9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHmCAQEwDQYJKoZIhvcNAQEFBQADggEB
-ALkVsUSRzCPIK0134/iaeycNzXK7mQDKfGYZUMbVmO2rvwNa5U3lHshPcZeG1eMd
-/ZDJPHV3V3p9+N701NX3leZ0bh08rnyd2wIDBSxxSyU+B+NemvVmFymIGjifz6pB
-A4SXa5M4esowRBskRDPQ5NHcKDj0E0M1NSljqHyita04pO2t/caaH/+Xc/77szWn
-k4bGdpEA5qxRFsQnMlzbc9qlk1eOPm01JghZ1edE13YgY+esE2fDbbFwRnzVlhE9
-iW9dqKHrjQrawx0zbKPqZxmamX9LPYNRKh3KL4YMon4QLSvUFpULB6ouFJJJtylv
-2G0xffX8oRAHh84vWdw+WNs=
------END CERTIFICATE-----
-
 # Issuer: CN=COMODO ECC Certification Authority O=COMODO CA Limited
 # Subject: CN=COMODO ECC Certification Authority O=COMODO CA Limited
 # Label: "COMODO ECC Certification Authority"
@@ -1738,57 +1702,6 @@ Fj4A4xylNoEYokxSdsARo27mHbrjWr42U8U+dY+GaSlYU7Wcu2+fXMUY7N0v4ZjJ
 /L7fCg0=
 -----END CERTIFICATE-----
 
-# Issuer: CN=Microsec e-Szigno Root CA O=Microsec Ltd. OU=e-Szigno CA
-# Subject: CN=Microsec e-Szigno Root CA O=Microsec Ltd. OU=e-Szigno CA
-# Label: "Microsec e-Szigno Root CA"
-# Serial: 272122594155480254301341951808045322001
-# MD5 Fingerprint: f0:96:b6:2f:c5:10:d5:67:8e:83:25:32:e8:5e:2e:e5
-# SHA1 Fingerprint: 23:88:c9:d3:71:cc:9e:96:3d:ff:7d:3c:a7:ce:fc:d6:25:ec:19:0d
-# SHA256 Fingerprint: 32:7a:3d:76:1a:ba:de:a0:34:eb:99:84:06:27:5c:b1:a4:77:6e:fd:ae:2f:df:6d:01:68:ea:1c:4f:55:67:d0
------BEGIN CERTIFICATE-----
-MIIHqDCCBpCgAwIBAgIRAMy4579OKRr9otxmpRwsDxEwDQYJKoZIhvcNAQEFBQAw
-cjELMAkGA1UEBhMCSFUxETAPBgNVBAcTCEJ1ZGFwZXN0MRYwFAYDVQQKEw1NaWNy
-b3NlYyBMdGQuMRQwEgYDVQQLEwtlLVN6aWdubyBDQTEiMCAGA1UEAxMZTWljcm9z
-ZWMgZS1Temlnbm8gUm9vdCBDQTAeFw0wNTA0MDYxMjI4NDRaFw0xNzA0MDYxMjI4
-NDRaMHIxCzAJBgNVBAYTAkhVMREwDwYDVQQHEwhCdWRhcGVzdDEWMBQGA1UEChMN
-TWljcm9zZWMgTHRkLjEUMBIGA1UECxMLZS1Temlnbm8gQ0ExIjAgBgNVBAMTGU1p
-Y3Jvc2VjIGUtU3ppZ25vIFJvb3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw
-ggEKAoIBAQDtyADVgXvNOABHzNuEwSFpLHSQDCHZU4ftPkNEU6+r+ICbPHiN1I2u
-uO/TEdyB5s87lozWbxXGd36hL+BfkrYn13aaHUM86tnsL+4582pnS4uCzyL4ZVX+
-LMsvfUh6PXX5qqAnu3jCBspRwn5mS6/NoqdNAoI/gqyFxuEPkEeZlApxcpMqyabA
-vjxWTHOSJ/FrtfX9/DAFYJLG65Z+AZHCabEeHXtTRbjcQR/Ji3HWVBTji1R4P770
-Yjtb9aPs1ZJ04nQw7wHb4dSrmZsqa/i9phyGI0Jf7Enemotb9HI6QMVJPqW+jqpx
-62z69Rrkav17fVVA71hu5tnVvCSrwe+3AgMBAAGjggQ3MIIEMzBnBggrBgEFBQcB
-AQRbMFkwKAYIKwYBBQUHMAGGHGh0dHBzOi8vcmNhLmUtc3ppZ25vLmh1L29jc3Aw
-LQYIKwYBBQUHMAKGIWh0dHA6Ly93d3cuZS1zemlnbm8uaHUvUm9vdENBLmNydDAP
-BgNVHRMBAf8EBTADAQH/MIIBcwYDVR0gBIIBajCCAWYwggFiBgwrBgEEAYGoGAIB
-AQEwggFQMCgGCCsGAQUFBwIBFhxodHRwOi8vd3d3LmUtc3ppZ25vLmh1L1NaU1ov
-MIIBIgYIKwYBBQUHAgIwggEUHoIBEABBACAAdABhAG4A+gBzAO0AdAB2AOEAbgB5
-ACAA6QByAHQAZQBsAG0AZQB6AOkAcwDpAGgAZQB6ACAA6QBzACAAZQBsAGYAbwBn
-AGEAZADhAHMA4QBoAG8AegAgAGEAIABTAHoAbwBsAGcA4QBsAHQAYQB0APMAIABT
-AHoAbwBsAGcA4QBsAHQAYQB0AOEAcwBpACAAUwB6AGEAYgDhAGwAeQB6AGEAdABh
-ACAAcwB6AGUAcgBpAG4AdAAgAGsAZQBsAGwAIABlAGwAagDhAHIAbgBpADoAIABo
-AHQAdABwADoALwAvAHcAdwB3AC4AZQAtAHMAegBpAGcAbgBvAC4AaAB1AC8AUwBa
-AFMAWgAvMIHIBgNVHR8EgcAwgb0wgbqggbeggbSGIWh0dHA6Ly93d3cuZS1zemln
-bm8uaHUvUm9vdENBLmNybIaBjmxkYXA6Ly9sZGFwLmUtc3ppZ25vLmh1L0NOPU1p
-Y3Jvc2VjJTIwZS1Temlnbm8lMjBSb290JTIwQ0EsT1U9ZS1Temlnbm8lMjBDQSxP
-PU1pY3Jvc2VjJTIwTHRkLixMPUJ1ZGFwZXN0LEM9SFU/Y2VydGlmaWNhdGVSZXZv
-Y2F0aW9uTGlzdDtiaW5hcnkwDgYDVR0PAQH/BAQDAgEGMIGWBgNVHREEgY4wgYuB
-EGluZm9AZS1zemlnbm8uaHWkdzB1MSMwIQYDVQQDDBpNaWNyb3NlYyBlLVN6aWdu
-w7MgUm9vdCBDQTEWMBQGA1UECwwNZS1TemlnbsOzIEhTWjEWMBQGA1UEChMNTWlj
-cm9zZWMgS2Z0LjERMA8GA1UEBxMIQnVkYXBlc3QxCzAJBgNVBAYTAkhVMIGsBgNV
-HSMEgaQwgaGAFMegSXUWYYTbMUuE0vE3QJDvTtz3oXakdDByMQswCQYDVQQGEwJI
-VTERMA8GA1UEBxMIQnVkYXBlc3QxFjAUBgNVBAoTDU1pY3Jvc2VjIEx0ZC4xFDAS
-BgNVBAsTC2UtU3ppZ25vIENBMSIwIAYDVQQDExlNaWNyb3NlYyBlLVN6aWdubyBS
-b290IENBghEAzLjnv04pGv2i3GalHCwPETAdBgNVHQ4EFgQUx6BJdRZhhNsxS4TS
-8TdAkO9O3PcwDQYJKoZIhvcNAQEFBQADggEBANMTnGZjWS7KXHAM/IO8VbH0jgds
-ZifOwTsgqRy7RlRw7lrMoHfqaEQn6/Ip3Xep1fvj1KcExJW4C+FEaGAHQzAxQmHl
-7tnlJNUb3+FKG6qfx1/4ehHqE5MAyopYse7tDk2016g2JnzgOsHVV4Lxdbb9iV/a
-86g4nzUGCM4ilb7N1fy+W955a9x6qWVmvrElWl/tftOsRm1M9DKHtCAE4Gx4sHfR
-hUZLphK3dehKyVZs15KrnfVJONJPU+NVkBHbmJbGSfI+9J8b4PeI3CVimUTYc78/
-MPMMNz7UwiiAc7EBt51alhQBS6kRnSlqLtBdgcDPsiBDxwPgN05dCtxZICU=
------END CERTIFICATE-----
-
 # Issuer: CN=Certigna O=Dhimyotis
 # Subject: CN=Certigna O=Dhimyotis
 # Label: "Certigna"
@@ -2014,36 +1927,6 @@ buXf6iFViZx9fX+Y9QCJ7uOEwFyWtcVG6kbghVW2G8kS1sHNzYDzAgE8yGnLRUhj
 2JTQ7IUOO04RZfSCjKY9ri4ilAnIXOo8gV0WKgOXFlUJ24pBgp5mmxE=
 -----END CERTIFICATE-----
 
-# Issuer: O=Japanese Government OU=ApplicationCA
-# Subject: O=Japanese Government OU=ApplicationCA
-# Label: "ApplicationCA - Japanese Government"
-# Serial: 49
-# MD5 Fingerprint: 7e:23:4e:5b:a7:a5:b4:25:e9:00:07:74:11:62:ae:d6
-# SHA1 Fingerprint: 7f:8a:b0:cf:d0:51:87:6a:66:f3:36:0f:47:c8:8d:8c:d3:35:fc:74
-# SHA256 Fingerprint: 2d:47:43:7d:e1:79:51:21:5a:12:f3:c5:8e:51:c7:29:a5:80:26:ef:1f:cc:0a:5f:b3:d9:dc:01:2f:60:0d:19
------BEGIN CERTIFICATE-----
-MIIDoDCCAoigAwIBAgIBMTANBgkqhkiG9w0BAQUFADBDMQswCQYDVQQGEwJKUDEc
-MBoGA1UEChMTSmFwYW5lc2UgR292ZXJubWVudDEWMBQGA1UECxMNQXBwbGljYXRp
-b25DQTAeFw0wNzEyMTIxNTAwMDBaFw0xNzEyMTIxNTAwMDBaMEMxCzAJBgNVBAYT
-AkpQMRwwGgYDVQQKExNKYXBhbmVzZSBHb3Zlcm5tZW50MRYwFAYDVQQLEw1BcHBs
-aWNhdGlvbkNBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAp23gdE6H
-j6UG3mii24aZS2QNcfAKBZuOquHMLtJqO8F6tJdhjYq+xpqcBrSGUeQ3DnR4fl+K
-f5Sk10cI/VBaVuRorChzoHvpfxiSQE8tnfWuREhzNgaeZCw7NCPbXCbkcXmP1G55
-IrmTwcrNwVbtiGrXoDkhBFcsovW8R0FPXjQilbUfKW1eSvNNcr5BViCH/OlQR9cw
-FO5cjFW6WY2H/CPek9AEjP3vbb3QesmlOmpyM8ZKDQUXKi17safY1vC+9D/qDiht
-QWEjdnjDuGWk81quzMKq2edY3rZ+nYVunyoKb58DKTCXKB28t89UKU5RMfkntigm
-/qJj5kEW8DOYRwIDAQABo4GeMIGbMB0GA1UdDgQWBBRUWssmP3HMlEYNllPqa0jQ
-k/5CdTAOBgNVHQ8BAf8EBAMCAQYwWQYDVR0RBFIwUKROMEwxCzAJBgNVBAYTAkpQ
-MRgwFgYDVQQKDA/ml6XmnKzlm73mlL/lupwxIzAhBgNVBAsMGuOCouODl+ODquOC
-seODvOOCt+ODp+ODs0NBMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEFBQAD
-ggEBADlqRHZ3ODrso2dGD/mLBqj7apAxzn7s2tGJfHrrLgy9mTLnsCTWw//1sogJ
-hyzjVOGjprIIC8CFqMjSnHH2HZ9g/DgzE+Ge3Atf2hZQKXsvcJEPmbo0NI2VdMV+
-eKlmXb3KIXdCEKxmJj3ekav9FfBv7WxfEPjzFvYDio+nEhEMy/0/ecGc/WLuo89U
-DNErXxc+4z6/wCs+CZv+iKZ+tJIX/COUgb1up8WMwusRRdv4QcmWdupwX3kSa+Sj
-B1oF7ydJzyGfikwJcGapJsErEU4z0g781mzSDjJkaP+tBXhfAx2o45CsJOAPQKdL
-rosot4LKGAfmt1t06SAZf7IbiVQ=
------END CERTIFICATE-----
-
 # Issuer: CN=GeoTrust Primary Certification Authority - G3 O=GeoTrust Inc. OU=(c) 2008 GeoTrust Inc. - For authorized use only
 # Subject: CN=GeoTrust Primary Certification Authority - G3 O=GeoTrust Inc. OU=(c) 2008 GeoTrust Inc. - For authorized use only
 # Label: "GeoTrust Primary Certification Authority - G3"
@@ -4720,39 +4603,6 @@ Yv4HAqGEVka+lgqaE9chTLd8B59OTj+RdPsnnRHM3eaxynFNExc5JsUpISuTKWqW
 +qtB4Uu2NQvAmxU=
 -----END CERTIFICATE-----
 
-# Issuer: CN=TÜRKTRUST Elektronik Sertifika Hizmet Sağlayıcısı H6 O=TÜRKTRUST Bilgi İletişim ve Bilişim Güvenliği Hizmetleri A.Ş.
-# Subject: CN=TÜRKTRUST Elektronik Sertifika Hizmet Sağlayıcısı H6 O=TÜRKTRUST Bilgi İletişim ve Bilişim Güvenliği Hizmetleri A.Ş.
-# Label: "TÜRKTRUST Elektronik Sertifika Hizmet Sağlayıcısı H6"
-# Serial: 138134509972618
-# MD5 Fingerprint: f8:c5:ee:2a:6b:be:95:8d:08:f7:25:4a:ea:71:3e:46
-# SHA1 Fingerprint: 8a:5c:8c:ee:a5:03:e6:05:56:ba:d8:1b:d4:f6:c9:b0:ed:e5:2f:e0
-# SHA256 Fingerprint: 8d:e7:86:55:e1:be:7f:78:47:80:0b:93:f6:94:d2:1d:36:8c:c0:6e:03:3e:7f:ab:04:bb:5e:b9:9d:a6:b7:00
------BEGIN CERTIFICATE-----
-MIIEJjCCAw6gAwIBAgIGfaHyZeyKMA0GCSqGSIb3DQEBCwUAMIGxMQswCQYDVQQG
-EwJUUjEPMA0GA1UEBwwGQW5rYXJhMU0wSwYDVQQKDERUw5xSS1RSVVNUIEJpbGdp
-IMSwbGV0acWfaW0gdmUgQmlsacWfaW0gR8O8dmVubGnEn2kgSGl6bWV0bGVyaSBB
-LsWeLjFCMEAGA1UEAww5VMOcUktUUlVTVCBFbGVrdHJvbmlrIFNlcnRpZmlrYSBI
-aXptZXQgU2HEn2xhecSxY8Sxc8SxIEg2MB4XDTEzMTIxODA5MDQxMFoXDTIzMTIx
-NjA5MDQxMFowgbExCzAJBgNVBAYTAlRSMQ8wDQYDVQQHDAZBbmthcmExTTBLBgNV
-BAoMRFTDnFJLVFJVU1QgQmlsZ2kgxLBsZXRpxZ9pbSB2ZSBCaWxpxZ9pbSBHw7x2
-ZW5sacSfaSBIaXptZXRsZXJpIEEuxZ4uMUIwQAYDVQQDDDlUw5xSS1RSVVNUIEVs
-ZWt0cm9uaWsgU2VydGlmaWthIEhpem1ldCBTYcSfbGF5xLFjxLFzxLEgSDYwggEi
-MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCdsGjW6L0UlqMACprx9MfMkU1x
-eHe59yEmFXNRFpQJRwXiM/VomjX/3EsvMsew7eKC5W/a2uqsxgbPJQ1BgfbBOCK9
-+bGlprMBvD9QFyv26WZV1DOzXPhDIHiTVRZwGTLmiddk671IUP320EEDwnS3/faA
-z1vFq6TWlRKb55cTMgPp1KtDWxbtMyJkKbbSk60vbNg9tvYdDjTu0n2pVQ8g9P0p
-u5FbHH3GQjhtQiht1AH7zYiXSX6484P4tZgvsycLSF5W506jM7NE1qXyGJTtHB6p
-lVxiSvgNZ1GpryHV+DKdeboaX+UEVU0TRv/yz3THGmNtwx8XEsMeED5gCLMxAgMB
-AAGjQjBAMB0GA1UdDgQWBBTdVRcT9qzoSCHK77Wv0QAy7Z6MtTAOBgNVHQ8BAf8E
-BAMCAQYwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAb1gNl0Oq
-FlQ+v6nfkkU/hQu7VtMMUszIv3ZnXuaqs6fvuay0EBQNdH49ba3RfdCaqaXKGDsC
-QC4qnFAUi/5XfldcEQlLNkVS9z2sFP1E34uXI9TDwe7UU5X+LEr+DXCqu4svLcsy
-o4LyVN/Y8t3XSHLuSqMplsNEzm61kod2pLv0kmzOLBQJZo6NrRa1xxsJYTvjIKID
-gI6tflEATseWhvtDmHd9KMeP2Cpu54Rvl0EpABZeTeIT6lnAY2c6RPuY/ATTMHKm
-9ocJV612ph1jmv3XZch4gyt1O6VbuA1df74jrlZVlFjvH4GMKrLN5ptjnhi85WsG
-tAuYSyher4hYyw==
------END CERTIFICATE-----
-
 # Issuer: CN=Certinomis - Root CA O=Certinomis OU=0002 433998903
 # Subject: CN=Certinomis - Root CA O=Certinomis OU=0002 433998903
 # Label: "Certinomis - Root CA"
@@ -5402,3 +5252,37 @@ LSoSOcbDWjLtR5EWDrw4wVDej8oqkDQc7kGUnF4ZLvhFSZl0kbAEb+MEWrGrKqv+
 x9CWttrhSmQGbmBNvUJO/3jaJMobtNeWOWyu8Q6qp31IiyBMz2TWuJdGsE7RKlY6
 oJO9r4Ak4Ap+58rVyuiFVdw2KuGUaJPHZnJED4AhMmwlxyOAgwrr
 -----END CERTIFICATE-----
+
+# Issuer: CN=TUBITAK Kamu SM SSL Kok Sertifikasi - Surum 1 O=Turkiye Bilimsel ve Teknolojik Arastirma Kurumu - TUBITAK OU=Kamu Sertifikasyon Merkezi - Kamu SM
+# Subject: CN=TUBITAK Kamu SM SSL Kok Sertifikasi - Surum 1 O=Turkiye Bilimsel ve Teknolojik Arastirma Kurumu - TUBITAK OU=Kamu Sertifikasyon Merkezi - Kamu SM
+# Label: "TUBITAK Kamu SM SSL Kok Sertifikasi - Surum 1"
+# Serial: 1
+# MD5 Fingerprint: dc:00:81:dc:69:2f:3e:2f:b0:3b:f6:3d:5a:91:8e:49
+# SHA1 Fingerprint: 31:43:64:9b:ec:ce:27:ec:ed:3a:3f:0b:8f:0d:e4:e8:91:dd:ee:ca
+# SHA256 Fingerprint: 46:ed:c3:68:90:46:d5:3a:45:3f:b3:10:4a:b8:0d:ca:ec:65:8b:26:60:ea:16:29:dd:7e:86:79:90:64:87:16
+-----BEGIN CERTIFICATE-----
+MIIEYzCCA0ugAwIBAgIBATANBgkqhkiG9w0BAQsFADCB0jELMAkGA1UEBhMCVFIx
+GDAWBgNVBAcTD0dlYnplIC0gS29jYWVsaTFCMEAGA1UEChM5VHVya2l5ZSBCaWxp
+bXNlbCB2ZSBUZWtub2xvamlrIEFyYXN0aXJtYSBLdXJ1bXUgLSBUVUJJVEFLMS0w
+KwYDVQQLEyRLYW11IFNlcnRpZmlrYXN5b24gTWVya2V6aSAtIEthbXUgU00xNjA0
+BgNVBAMTLVRVQklUQUsgS2FtdSBTTSBTU0wgS29rIFNlcnRpZmlrYXNpIC0gU3Vy
+dW0gMTAeFw0xMzExMjUwODI1NTVaFw00MzEwMjUwODI1NTVaMIHSMQswCQYDVQQG
+EwJUUjEYMBYGA1UEBxMPR2ViemUgLSBLb2NhZWxpMUIwQAYDVQQKEzlUdXJraXll
+IEJpbGltc2VsIHZlIFRla25vbG9qaWsgQXJhc3Rpcm1hIEt1cnVtdSAtIFRVQklU
+QUsxLTArBgNVBAsTJEthbXUgU2VydGlmaWthc3lvbiBNZXJrZXppIC0gS2FtdSBT
+TTE2MDQGA1UEAxMtVFVCSVRBSyBLYW11IFNNIFNTTCBLb2sgU2VydGlmaWthc2kg
+LSBTdXJ1bSAxMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAr3UwM6q7
+a9OZLBI3hNmNe5eA027n/5tQlT6QlVZC1xl8JoSNkvoBHToP4mQ4t4y86Ij5iySr
+LqP1N+RAjhgleYN1Hzv/bKjFxlb4tO2KRKOrbEz8HdDc72i9z+SqzvBV96I01INr
+N3wcwv61A+xXzry0tcXtAA9TNypN9E8Mg/uGz8v+jE69h/mniyFXnHrfA2eJLJ2X
+YacQuFWQfw4tJzh03+f92k4S400VIgLI4OD8D62K18lUUMw7D8oWgITQUVbDjlZ/
+iSIzL+aFCr2lqBs23tPcLG07xxO9WSMs5uWk99gL7eqQQESolbuT1dCANLZGeA4f
+AJNG4e7p+exPFwIDAQABo0IwQDAdBgNVHQ4EFgQUZT/HiobGPN08VFw1+DrtUgxH
+V8gwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEL
+BQADggEBACo/4fEyjq7hmFxLXs9rHmoJ0iKpEsdeV31zVmSAhHqT5Am5EM2fKifh
+AHe+SMg1qIGf5LgsyX8OsNJLN13qudULXjS99HMpw+0mFZx+CFOKWI3QSyjfwbPf
+IPP54+M638yclNhOT8NrF7f3cuitZjO1JVOr4PhMqZ398g26rrnZqsZr+ZO7rqu4
+lzwDGrpDxpa5RXI4s6ehlj2Re37AIVNMh+3yC1SVUZPVIqUNivGTDj5UDrDYyU7c
+8jEyVupk+eq1nRZmQnLzf9OxMUP8pI4X8W0jq5Rm+K37DwhuJi1/FwcJsoz7UMCf
+lo3Ptv0AnVoUmr8CRPXBwp8iXqIPoeM=
+-----END CERTIFICATE-----
diff --git a/gRPC-Core.podspec b/gRPC-Core.podspec
index 9030a86edf7ae0616aeb603ddca2c2a0c2b5c0ad..aed17ae9c3dcf2a6c8976ec1dff7a5c537b7d13b 100644
--- a/gRPC-Core.podspec
+++ b/gRPC-Core.podspec
@@ -290,6 +290,7 @@ Pod::Spec.new do |s|
                       'src/core/lib/iomgr/iomgr_internal.h',
                       'src/core/lib/iomgr/iomgr_posix.h',
                       'src/core/lib/iomgr/load_file.h',
+                      'src/core/lib/iomgr/lockfree_event.h',
                       'src/core/lib/iomgr/network_status_tracker.h',
                       'src/core/lib/iomgr/polling_entity.h',
                       'src/core/lib/iomgr/pollset.h',
@@ -495,6 +496,7 @@ Pod::Spec.new do |s|
                       'src/core/lib/iomgr/iomgr_uv.c',
                       'src/core/lib/iomgr/iomgr_windows.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',
@@ -742,6 +744,7 @@ Pod::Spec.new do |s|
                               'src/core/lib/iomgr/iomgr_internal.h',
                               'src/core/lib/iomgr/iomgr_posix.h',
                               'src/core/lib/iomgr/load_file.h',
+                              'src/core/lib/iomgr/lockfree_event.h',
                               'src/core/lib/iomgr/network_status_tracker.h',
                               'src/core/lib/iomgr/polling_entity.h',
                               'src/core/lib/iomgr/pollset.h',
diff --git a/grpc.gemspec b/grpc.gemspec
index 85ec1a964e88b112b6aafec701d6b3b684994e03..4912872933bd35748e7aaf31330348860728b062 100755
--- a/grpc.gemspec
+++ b/grpc.gemspec
@@ -24,7 +24,7 @@ Gem::Specification.new do |s|
   s.files += Dir.glob('include/grpc/**/*')
   s.test_files = Dir.glob('src/ruby/spec/**/*')
   s.bindir = 'src/ruby/bin'
-  s.require_paths = %w( src/ruby/bin src/ruby/lib src/ruby/pb )
+  s.require_paths = %w( src/ruby/lib src/ruby/bin src/ruby/pb )
   s.platform      = Gem::Platform::RUBY
 
   s.add_dependency 'google-protobuf', '~> 3.1'
@@ -206,6 +206,7 @@ Gem::Specification.new do |s|
   s.files += %w( src/core/lib/iomgr/iomgr_internal.h )
   s.files += %w( src/core/lib/iomgr/iomgr_posix.h )
   s.files += %w( src/core/lib/iomgr/load_file.h )
+  s.files += %w( src/core/lib/iomgr/lockfree_event.h )
   s.files += %w( src/core/lib/iomgr/network_status_tracker.h )
   s.files += %w( src/core/lib/iomgr/polling_entity.h )
   s.files += %w( src/core/lib/iomgr/pollset.h )
@@ -411,6 +412,7 @@ Gem::Specification.new do |s|
   s.files += %w( src/core/lib/iomgr/iomgr_uv.c )
   s.files += %w( src/core/lib/iomgr/iomgr_windows.c )
   s.files += %w( src/core/lib/iomgr/load_file.c )
+  s.files += %w( src/core/lib/iomgr/lockfree_event.c )
   s.files += %w( src/core/lib/iomgr/network_status_tracker.c )
   s.files += %w( src/core/lib/iomgr/polling_entity.c )
   s.files += %w( src/core/lib/iomgr/pollset_set_uv.c )
diff --git a/include/grpc++/impl/codegen/call.h b/include/grpc++/impl/codegen/call.h
index be6857c4829c8552eb64c2c7a8b8b20b7584079b..dd63c21ff17bc406311b58e3434d802b61f7bc3a 100644
--- a/include/grpc++/impl/codegen/call.h
+++ b/include/grpc++/impl/codegen/call.h
@@ -63,21 +63,31 @@ class CallHook;
 class CompletionQueue;
 extern CoreCodegenInterface* g_core_codegen_interface;
 
+const char kBinaryErrorDetailsKey[] = "grpc-status-details-bin";
+
 // TODO(yangg) if the map is changed before we send, the pointers will be a
 // mess. Make sure it does not happen.
 inline grpc_metadata* FillMetadataArray(
-    const std::multimap<grpc::string, grpc::string>& metadata) {
-  if (metadata.empty()) {
+    const std::multimap<grpc::string, grpc::string>& metadata,
+    size_t* metadata_count, const grpc::string& optional_error_details) {
+  *metadata_count = metadata.size() + (optional_error_details.empty() ? 0 : 1);
+  if (*metadata_count == 0) {
     return nullptr;
   }
   grpc_metadata* metadata_array =
       (grpc_metadata*)(g_core_codegen_interface->gpr_malloc(
-          metadata.size() * sizeof(grpc_metadata)));
+          (*metadata_count) * sizeof(grpc_metadata)));
   size_t i = 0;
   for (auto iter = metadata.cbegin(); iter != metadata.cend(); ++iter, ++i) {
     metadata_array[i].key = SliceReferencingString(iter->first);
     metadata_array[i].value = SliceReferencingString(iter->second);
   }
+  if (!optional_error_details.empty()) {
+    metadata_array[i].key =
+        g_core_codegen_interface->grpc_slice_from_static_buffer(
+            kBinaryErrorDetailsKey, sizeof(kBinaryErrorDetailsKey) - 1);
+    metadata_array[i].value = SliceReferencingString(optional_error_details);
+  }
   return metadata_array;
 }
 
@@ -216,8 +226,8 @@ class CallOpSendInitialMetadata {
     maybe_compression_level_.is_set = false;
     send_ = true;
     flags_ = flags;
-    initial_metadata_count_ = metadata.size();
-    initial_metadata_ = FillMetadataArray(metadata);
+    initial_metadata_ =
+        FillMetadataArray(metadata, &initial_metadata_count_, "");
   }
 
   void set_compression_level(grpc_compression_level level) {
@@ -454,11 +464,12 @@ class CallOpServerSendStatus {
   void ServerSendStatus(
       const std::multimap<grpc::string, grpc::string>& trailing_metadata,
       const Status& status) {
-    trailing_metadata_count_ = trailing_metadata.size();
-    trailing_metadata_ = FillMetadataArray(trailing_metadata);
+    send_error_details_ = status.error_details();
+    trailing_metadata_ = FillMetadataArray(
+        trailing_metadata, &trailing_metadata_count_, send_error_details_);
     send_status_available_ = true;
     send_status_code_ = static_cast<grpc_status_code>(GetCanonicalCode(status));
-    send_status_details_ = status.error_message();
+    send_error_message_ = status.error_message();
   }
 
  protected:
@@ -470,9 +481,9 @@ class CallOpServerSendStatus {
         trailing_metadata_count_;
     op->data.send_status_from_server.trailing_metadata = trailing_metadata_;
     op->data.send_status_from_server.status = send_status_code_;
-    status_details_slice_ = SliceReferencingString(send_status_details_);
+    error_message_slice_ = SliceReferencingString(send_error_message_);
     op->data.send_status_from_server.status_details =
-        send_status_details_.empty() ? nullptr : &status_details_slice_;
+        send_error_message_.empty() ? nullptr : &error_message_slice_;
     op->flags = 0;
     op->reserved = NULL;
   }
@@ -486,10 +497,11 @@ class CallOpServerSendStatus {
  private:
   bool send_status_available_;
   grpc_status_code send_status_code_;
-  grpc::string send_status_details_;
+  grpc::string send_error_details_;
+  grpc::string send_error_message_;
   size_t trailing_metadata_count_;
   grpc_metadata* trailing_metadata_;
-  grpc_slice status_details_slice_;
+  grpc_slice error_message_slice_;
 };
 
 class CallOpRecvInitialMetadata {
@@ -528,7 +540,7 @@ class CallOpClientRecvStatus {
   void ClientRecvStatus(ClientContext* context, Status* status) {
     metadata_map_ = &context->trailing_metadata_;
     recv_status_ = status;
-    status_details_ = g_core_codegen_interface->grpc_empty_slice();
+    error_message_ = g_core_codegen_interface->grpc_empty_slice();
   }
 
  protected:
@@ -538,7 +550,7 @@ class CallOpClientRecvStatus {
     op->op = GRPC_OP_RECV_STATUS_ON_CLIENT;
     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 = &status_details_;
+    op->data.recv_status_on_client.status_details = &error_message_;
     op->flags = 0;
     op->reserved = NULL;
   }
@@ -546,10 +558,17 @@ class CallOpClientRecvStatus {
   void FinishOp(bool* status) {
     if (recv_status_ == nullptr) return;
     metadata_map_->FillMap();
+    grpc::string binary_error_details;
+    auto iter = metadata_map_->map()->find(kBinaryErrorDetailsKey);
+    if (iter != metadata_map_->map()->end()) {
+      binary_error_details =
+          grpc::string(iter->second.begin(), iter->second.length());
+    }
     *recv_status_ = Status(static_cast<StatusCode>(status_code_),
-                           grpc::string(GRPC_SLICE_START_PTR(status_details_),
-                                        GRPC_SLICE_END_PTR(status_details_)));
-    g_core_codegen_interface->grpc_slice_unref(status_details_);
+                           grpc::string(GRPC_SLICE_START_PTR(error_message_),
+                                        GRPC_SLICE_END_PTR(error_message_)),
+                           binary_error_details);
+    g_core_codegen_interface->grpc_slice_unref(error_message_);
     recv_status_ = nullptr;
   }
 
@@ -557,7 +576,7 @@ class CallOpClientRecvStatus {
   MetadataMap* metadata_map_;
   Status* recv_status_;
   grpc_status_code status_code_;
-  grpc_slice status_details_;
+  grpc_slice error_message_;
 };
 
 /// An abstract collection of CallOpSet's, to be used whenever
diff --git a/include/grpc++/impl/codegen/status.h b/include/grpc++/impl/codegen/status.h
index a509d311d4250e29b4826b322c04aa2982b57bce..5cce3c1672e69bcedeb237f47c0e6d0960df5e34 100644
--- a/include/grpc++/impl/codegen/status.h
+++ b/include/grpc++/impl/codegen/status.h
@@ -47,10 +47,16 @@ class Status {
   /// Construct an OK instance.
   Status() : code_(StatusCode::OK) {}
 
-  /// Construct an instance with associated \a code and \a details (also
-  // referred to as "error_message").
-  Status(StatusCode code, const grpc::string& details)
-      : code_(code), details_(details) {}
+  /// Construct an instance with associated \a code and \a error_message
+  Status(StatusCode code, const grpc::string& error_message)
+      : code_(code), error_message_(error_message) {}
+
+  /// Construct an instance with \a code,  \a error_message and \a error_details
+  Status(StatusCode code, const grpc::string& error_message,
+         const grpc::string error_details)
+      : code_(code),
+        error_message_(error_message),
+        binary_error_details_(error_details) {}
 
   // Pre-defined special status objects.
   /// An OK pre-defined instance.
@@ -61,14 +67,18 @@ class Status {
   /// Return the instance's error code.
   StatusCode error_code() const { return code_; }
   /// Return the instance's error message.
-  grpc::string error_message() const { return details_; }
+  grpc::string error_message() const { return error_message_; }
+  /// Return the (binary) error details.
+  // Usually it contains a serialized google.rpc.Status proto.
+  grpc::string error_details() const { return binary_error_details_; }
 
   /// Is the status OK?
   bool ok() const { return code_ == StatusCode::OK; }
 
  private:
   StatusCode code_;
-  grpc::string details_;
+  grpc::string error_message_;
+  grpc::string binary_error_details_;
 };
 
 }  // namespace grpc
diff --git a/include/grpc/impl/codegen/atm_windows.h b/include/grpc/impl/codegen/atm_windows.h
index b8f63da7587905ed9502b40c48ba91fa6625e445..a533651f6f9bf7aa37f61dea2406fd37b2e9f414 100644
--- a/include/grpc/impl/codegen/atm_windows.h
+++ b/include/grpc/impl/codegen/atm_windows.h
@@ -95,6 +95,16 @@ static __inline int gpr_atm_rel_cas(gpr_atm *p, gpr_atm o, gpr_atm n) {
 #endif
 }
 
+static __inline int gpr_atm_full_cas(gpr_atm *p, gpr_atm o, gpr_atm n) {
+#ifdef GPR_ARCH_64
+  return o == (gpr_atm)InterlockedCompareExchange64((volatile LONGLONG *)p,
+                                                    (LONGLONG)n, (LONGLONG)o);
+#else
+  return o == (gpr_atm)InterlockedCompareExchange((volatile LONG *)p, (LONG)n,
+                                                  (LONG)o);
+#endif
+}
+
 static __inline gpr_atm gpr_atm_no_barrier_fetch_add(gpr_atm *p,
                                                      gpr_atm delta) {
   /* Use the CAS operation to get pointer-sized fetch and add */
diff --git a/include/grpc/impl/codegen/grpc_types.h b/include/grpc/impl/codegen/grpc_types.h
index 9663b5b1eeb899302c18e56e2f814d017c501896..4380aceaf1321a0907d71dfdd52416ee2131a746 100644
--- a/include/grpc/impl/codegen/grpc_types.h
+++ b/include/grpc/impl/codegen/grpc_types.h
@@ -273,6 +273,14 @@ typedef struct {
  * possible. */
 #define GRPC_ARG_USE_CRONET_PACKET_COALESCING \
   "grpc.use_cronet_packet_coalescing"
+/* Channel arg (integer) setting how large a slice to try and read from the wire
+each time recvmsg (or equivalent) is called */
+#define GRPC_ARG_TCP_READ_CHUNK_SIZE "grpc.experimental.tcp_read_chunk_size"
+#define GRPC_TCP_DEFAULT_READ_SLICE_SIZE 8192
+#define GRPC_ARG_TCP_MIN_READ_CHUNK_SIZE \
+  "grpc.experimental.tcp_min_read_chunk_size"
+#define GRPC_ARG_TCP_MAX_READ_CHUNK_SIZE \
+  "grpc.experimental.tcp_max_read_chunk_size"
 /** \} */
 
 /** Result of a grpc call. If the caller satisfies the prerequisites of a
diff --git a/include/grpc/impl/codegen/port_platform.h b/include/grpc/impl/codegen/port_platform.h
index d525083cd04d67cc410738756ad855f352bf7d9d..813e08b86e3e05386b1036af26c47035f73916d3 100644
--- a/include/grpc/impl/codegen/port_platform.h
+++ b/include/grpc/impl/codegen/port_platform.h
@@ -157,7 +157,6 @@
 #define GPR_GETPID_IN_UNISTD_H 1
 #define GPR_SUPPORT_CHANNELS_FROM_FD 1
 #elif defined(__linux__)
-#define GPR_POSIX_CRASH_HANDLER 1
 #define GPR_PLATFORM_STRING "linux"
 #ifndef _BSD_SOURCE
 #define _BSD_SOURCE
@@ -187,6 +186,11 @@
 #else /* _LP64 */
 #define GPR_ARCH_32 1
 #endif /* _LP64 */
+#ifdef __GLIBC__
+#define GPR_POSIX_CRASH_HANDLER 1
+#else /* musl libc */
+#define GRPC_MSG_IOVLEN_TYPE int
+#endif
 #elif defined(__APPLE__)
 #include <Availability.h>
 #include <TargetConditionals.h>
diff --git a/package.json b/package.json
index 666e819fb58f29f05791af76240e341cc796e07e..7f242326d7ecd03feacb76126aa7defa87d18579 100644
--- a/package.json
+++ b/package.json
@@ -34,7 +34,7 @@
     "lodash": "^4.15.0",
     "nan": "^2.0.0",
     "node-pre-gyp": "^0.6.0",
-    "protobufjs": "^5.0.0",
+    "protobufjs": "^6.7.0",
     "cares": "^1.1.5"
   },
   "devDependencies": {
diff --git a/package.xml b/package.xml
index f615e82ddd94de72769d5a8f0794bfc96c484347..57e50725e8eb71b92c7d1d9a221ea88d75d6502a 100644
--- a/package.xml
+++ b/package.xml
@@ -215,6 +215,7 @@
     <file baseinstalldir="/" name="src/core/lib/iomgr/iomgr_internal.h" role="src" />
     <file baseinstalldir="/" name="src/core/lib/iomgr/iomgr_posix.h" role="src" />
     <file baseinstalldir="/" name="src/core/lib/iomgr/load_file.h" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/iomgr/lockfree_event.h" role="src" />
     <file baseinstalldir="/" name="src/core/lib/iomgr/network_status_tracker.h" role="src" />
     <file baseinstalldir="/" name="src/core/lib/iomgr/polling_entity.h" role="src" />
     <file baseinstalldir="/" name="src/core/lib/iomgr/pollset.h" role="src" />
@@ -420,6 +421,7 @@
     <file baseinstalldir="/" name="src/core/lib/iomgr/iomgr_uv.c" role="src" />
     <file baseinstalldir="/" name="src/core/lib/iomgr/iomgr_windows.c" role="src" />
     <file baseinstalldir="/" name="src/core/lib/iomgr/load_file.c" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/iomgr/lockfree_event.c" role="src" />
     <file baseinstalldir="/" name="src/core/lib/iomgr/network_status_tracker.c" role="src" />
     <file baseinstalldir="/" name="src/core/lib/iomgr/polling_entity.c" role="src" />
     <file baseinstalldir="/" name="src/core/lib/iomgr/pollset_set_uv.c" role="src" />
diff --git a/src/core/ext/census/grpc_plugin.c b/src/core/ext/census/grpc_plugin.c
index 28d266e22ae140e8ce98c70bd5414077b1af444b..7d0c9f14ae67d9ad01f179c639255552d317abef 100644
--- a/src/core/ext/census/grpc_plugin.c
+++ b/src/core/ext/census/grpc_plugin.c
@@ -31,6 +31,8 @@
  *
  */
 
+#include <grpc/support/port_platform.h>
+
 #include <limits.h>
 #include <string.h>
 
diff --git a/src/core/ext/filters/client_channel/client_channel.c b/src/core/ext/filters/client_channel/client_channel.c
index 93ad53aab93a4188d3b1460fec6ae8accbdca002..83e3b8f118d67c9bd6fadda251229e99e13f9495 100644
--- a/src/core/ext/filters/client_channel/client_channel.c
+++ b/src/core/ext/filters/client_channel/client_channel.c
@@ -914,14 +914,14 @@ static void subchannel_ready_locked(grpc_exec_ctx *exec_ctx, void *arg,
         .arena = calld->arena};
     grpc_error *new_error = grpc_connected_subchannel_create_call(
         exec_ctx, calld->connected_subchannel, &call_args, &subchannel_call);
+    gpr_atm_rel_store(&calld->subchannel_call,
+                      (gpr_atm)(uintptr_t)subchannel_call);
     if (new_error != GRPC_ERROR_NONE) {
       new_error = grpc_error_add_child(new_error, error);
-      subchannel_call = CANCELLED_CALL;
       fail_locked(exec_ctx, calld, new_error);
+    } else {
+      retry_waiting_locked(exec_ctx, calld);
     }
-    gpr_atm_rel_store(&calld->subchannel_call,
-                      (gpr_atm)(uintptr_t)subchannel_call);
-    retry_waiting_locked(exec_ctx, calld);
   }
   GRPC_CALL_STACK_UNREF(exec_ctx, calld->owning_call, "pick_subchannel");
 }
@@ -1152,16 +1152,16 @@ static void start_transport_stream_op_batch_locked_inner(
         .arena = calld->arena};
     grpc_error *error = grpc_connected_subchannel_create_call(
         exec_ctx, calld->connected_subchannel, &call_args, &subchannel_call);
+    gpr_atm_rel_store(&calld->subchannel_call,
+                      (gpr_atm)(uintptr_t)subchannel_call);
     if (error != GRPC_ERROR_NONE) {
-      subchannel_call = CANCELLED_CALL;
       fail_locked(exec_ctx, calld, GRPC_ERROR_REF(error));
       grpc_transport_stream_op_batch_finish_with_failure(exec_ctx, op, error);
+    } else {
+      retry_waiting_locked(exec_ctx, calld);
+      /* recurse to retry */
+      start_transport_stream_op_batch_locked_inner(exec_ctx, op, elem);
     }
-    gpr_atm_rel_store(&calld->subchannel_call,
-                      (gpr_atm)(uintptr_t)subchannel_call);
-    retry_waiting_locked(exec_ctx, calld);
-    /* recurse to retry */
-    start_transport_stream_op_batch_locked_inner(exec_ctx, op, elem);
     /* early out */
     return;
   }
diff --git a/src/core/ext/filters/client_channel/client_channel_plugin.c b/src/core/ext/filters/client_channel/client_channel_plugin.c
index 944af01af468fbf2434dfa0d1d35f7ccd46dc7af..a68c01c2227afe7013fe218b32e40250d14e4cf0 100644
--- a/src/core/ext/filters/client_channel/client_channel_plugin.c
+++ b/src/core/ext/filters/client_channel/client_channel_plugin.c
@@ -31,6 +31,8 @@
  *
  */
 
+#include <grpc/support/port_platform.h>
+
 #include <limits.h>
 #include <stdbool.h>
 #include <string.h>
diff --git a/src/core/ext/filters/client_channel/subchannel.c b/src/core/ext/filters/client_channel/subchannel.c
index 29a1a095553d2b0098fd3b9df67a1e1eb37ad363..9a7a7a0ee5f69112f59f752771c725ae9d5de797 100644
--- a/src/core/ext/filters/client_channel/subchannel.c
+++ b/src/core/ext/filters/client_channel/subchannel.c
@@ -769,7 +769,7 @@ grpc_error *grpc_connected_subchannel_create_call(
   *call = gpr_arena_alloc(
       args->arena, sizeof(grpc_subchannel_call) + chanstk->call_stack_size);
   grpc_call_stack *callstk = SUBCHANNEL_CALL_TO_CALL_STACK(*call);
-  (*call)->connection = con;  // Ref is added below.
+  (*call)->connection = GRPC_CONNECTED_SUBCHANNEL_REF(con, "subchannel_call");
   const grpc_call_element_args call_args = {.call_stack = callstk,
                                             .server_transport_data = NULL,
                                             .context = NULL,
@@ -784,7 +784,6 @@ grpc_error *grpc_connected_subchannel_create_call(
     gpr_log(GPR_ERROR, "error: %s", error_string);
     return error;
   }
-  GRPC_CONNECTED_SUBCHANNEL_REF(con, "subchannel_call");
   grpc_call_stack_set_pollset_or_pollset_set(exec_ctx, callstk, args->pollent);
   return GRPC_ERROR_NONE;
 }
diff --git a/src/core/ext/filters/load_reporting/load_reporting.c b/src/core/ext/filters/load_reporting/load_reporting.c
index 9fb33bab711bd539d363b3b969a803ec84bb47a3..f4dac15a604c58a2173d364177f35d9155851bdc 100644
--- a/src/core/ext/filters/load_reporting/load_reporting.c
+++ b/src/core/ext/filters/load_reporting/load_reporting.c
@@ -31,6 +31,8 @@
  *
  */
 
+#include <grpc/support/port_platform.h>
+
 #include <limits.h>
 #include <string.h>
 
diff --git a/src/core/ext/filters/max_age/max_age_filter.c b/src/core/ext/filters/max_age/max_age_filter.c
index f858220c010a63266bbaad8748cd59e82753e3a0..b9fde3628602bf8f5a1de3138b30048c4564c700 100644
--- a/src/core/ext/filters/max_age/max_age_filter.c
+++ b/src/core/ext/filters/max_age/max_age_filter.c
@@ -31,7 +31,7 @@
  *
  */
 
-#include "src/core/lib/channel/message_size_filter.h"
+#include "src/core/ext/filters/max_age/max_age_filter.h"
 
 #include <limits.h>
 #include <string.h>
@@ -41,7 +41,6 @@
 #include "src/core/lib/iomgr/timer.h"
 #include "src/core/lib/surface/channel_init.h"
 #include "src/core/lib/transport/http2_errors.h"
-#include "src/core/lib/transport/service_config.h"
 
 #define DEFAULT_MAX_CONNECTION_AGE_MS INT_MAX
 #define DEFAULT_MAX_CONNECTION_AGE_GRACE_MS INT_MAX
@@ -168,8 +167,9 @@ static void start_max_age_grace_timer_after_goaway_op(grpc_exec_ctx* exec_ctx,
 static void close_max_idle_channel(grpc_exec_ctx* exec_ctx, void* arg,
                                    grpc_error* error) {
   channel_data* chand = arg;
-  gpr_atm_no_barrier_fetch_add(&chand->call_count, 1);
   if (error == GRPC_ERROR_NONE) {
+    /* Prevent the max idle timer from being set again */
+    gpr_atm_no_barrier_fetch_add(&chand->call_count, 1);
     grpc_transport_op* op = grpc_make_transport_op(NULL);
     op->goaway_error =
         grpc_error_set_int(GRPC_ERROR_CREATE_FROM_STATIC_STRING("max_idle"),
diff --git a/src/core/ext/transport/chttp2/server/insecure/server_chttp2_posix.c b/src/core/ext/transport/chttp2/server/insecure/server_chttp2_posix.c
index f46e8499326d5a0ecea74368fa0fdc605581edf5..6ab176e8ad74eba529f1783986577c0e43523743 100644
--- a/src/core/ext/transport/chttp2/server/insecure/server_chttp2_posix.c
+++ b/src/core/ext/transport/chttp2/server/insecure/server_chttp2_posix.c
@@ -57,12 +57,9 @@ void grpc_server_add_insecure_channel_from_fd(grpc_server *server,
   char *name;
   gpr_asprintf(&name, "fd:%d", fd);
 
-  grpc_resource_quota *resource_quota = grpc_resource_quota_from_channel_args(
-      grpc_server_get_channel_args(server));
   grpc_endpoint *server_endpoint =
-      grpc_tcp_create(grpc_fd_create(fd, name), resource_quota,
-                      GRPC_TCP_DEFAULT_READ_SLICE_SIZE, name);
-  grpc_resource_quota_unref_internal(&exec_ctx, resource_quota);
+      grpc_tcp_create(&exec_ctx, grpc_fd_create(fd, name),
+                      grpc_server_get_channel_args(server), name);
 
   gpr_free(name);
 
diff --git a/src/core/lib/http/httpcli_security_connector.c b/src/core/lib/http/httpcli_security_connector.c
index fc338342e48af1cea38baa9c0f581ffa108a2442..9eab1360a4ab484d1f8b0fd2a764438d58a8ca5f 100644
--- a/src/core/lib/http/httpcli_security_connector.c
+++ b/src/core/lib/http/httpcli_security_connector.c
@@ -47,7 +47,7 @@
 
 typedef struct {
   grpc_channel_security_connector base;
-  tsi_ssl_handshaker_factory *handshaker_factory;
+  tsi_ssl_client_handshaker_factory *handshaker_factory;
   char *secure_peer_name;
 } grpc_httpcli_ssl_channel_security_connector;
 
@@ -56,7 +56,7 @@ static void httpcli_ssl_destroy(grpc_exec_ctx *exec_ctx,
   grpc_httpcli_ssl_channel_security_connector *c =
       (grpc_httpcli_ssl_channel_security_connector *)sc;
   if (c->handshaker_factory != NULL) {
-    tsi_ssl_handshaker_factory_destroy(c->handshaker_factory);
+    tsi_ssl_client_handshaker_factory_destroy(c->handshaker_factory);
   }
   if (c->secure_peer_name != NULL) gpr_free(c->secure_peer_name);
   gpr_free(sc);
@@ -69,7 +69,7 @@ static void httpcli_ssl_add_handshakers(grpc_exec_ctx *exec_ctx,
       (grpc_httpcli_ssl_channel_security_connector *)sc;
   tsi_handshaker *handshaker = NULL;
   if (c->handshaker_factory != NULL) {
-    tsi_result result = tsi_ssl_handshaker_factory_create_handshaker(
+    tsi_result result = tsi_ssl_client_handshaker_factory_create_handshaker(
         c->handshaker_factory, c->secure_peer_name, &handshaker);
     if (result != TSI_OK) {
       gpr_log(GPR_ERROR, "Handshaker creation failed with error %s.",
diff --git a/src/core/lib/iomgr/endpoint_pair.h b/src/core/lib/iomgr/endpoint_pair.h
index f9de0c715ecc0f6a6ce67add9a32c2089fc2966c..6407a6ad3f32ca225385a6aab76ae4a0d4d1488e 100644
--- a/src/core/lib/iomgr/endpoint_pair.h
+++ b/src/core/lib/iomgr/endpoint_pair.h
@@ -41,8 +41,7 @@ typedef struct {
   grpc_endpoint *server;
 } grpc_endpoint_pair;
 
-grpc_endpoint_pair grpc_iomgr_create_endpoint_pair(
-    const char *name, grpc_resource_quota *resource_quota,
-    size_t read_slice_size);
+grpc_endpoint_pair grpc_iomgr_create_endpoint_pair(const char *name,
+                                                   grpc_channel_args *args);
 
 #endif /* GRPC_CORE_LIB_IOMGR_ENDPOINT_PAIR_H */
diff --git a/src/core/lib/iomgr/endpoint_pair_posix.c b/src/core/lib/iomgr/endpoint_pair_posix.c
index b9ff969e8100c858616db042e2c0742a8113f442..5542a372d8bfdf007fe6fef511ed9d229b02ee04 100644
--- a/src/core/lib/iomgr/endpoint_pair_posix.c
+++ b/src/core/lib/iomgr/endpoint_pair_posix.c
@@ -62,22 +62,25 @@ static void create_sockets(int sv[2]) {
   GPR_ASSERT(grpc_set_socket_no_sigpipe_if_possible(sv[1]) == GRPC_ERROR_NONE);
 }
 
-grpc_endpoint_pair grpc_iomgr_create_endpoint_pair(
-    const char *name, grpc_resource_quota *resource_quota,
-    size_t read_slice_size) {
+grpc_endpoint_pair grpc_iomgr_create_endpoint_pair(const char *name,
+                                                   grpc_channel_args *args) {
   int sv[2];
   grpc_endpoint_pair p;
   char *final_name;
   create_sockets(sv);
 
+  grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+
   gpr_asprintf(&final_name, "%s:client", name);
-  p.client = grpc_tcp_create(grpc_fd_create(sv[1], final_name), resource_quota,
-                             read_slice_size, "socketpair-server");
+  p.client = grpc_tcp_create(&exec_ctx, grpc_fd_create(sv[1], final_name), args,
+                             "socketpair-server");
   gpr_free(final_name);
   gpr_asprintf(&final_name, "%s:server", name);
-  p.server = grpc_tcp_create(grpc_fd_create(sv[0], final_name), resource_quota,
-                             read_slice_size, "socketpair-client");
+  p.server = grpc_tcp_create(&exec_ctx, grpc_fd_create(sv[0], final_name), args,
+                             "socketpair-client");
   gpr_free(final_name);
+
+  grpc_exec_ctx_finish(&exec_ctx);
   return p;
 }
 
diff --git a/src/core/lib/iomgr/endpoint_pair_uv.c b/src/core/lib/iomgr/endpoint_pair_uv.c
index ff24894c6db8d3ff9977dc86ceb6e96b1fa4b2d3..9718eb0523727a133dcddb9cb2b96cd2f6b1d68b 100644
--- a/src/core/lib/iomgr/endpoint_pair_uv.c
+++ b/src/core/lib/iomgr/endpoint_pair_uv.c
@@ -41,9 +41,8 @@
 
 #include "src/core/lib/iomgr/endpoint_pair.h"
 
-grpc_endpoint_pair grpc_iomgr_create_endpoint_pair(
-    const char *name, grpc_resource_quota *resource_quota,
-    size_t read_slice_size) {
+grpc_endpoint_pair grpc_iomgr_create_endpoint_pair(const char *name,
+                                                   grpc_channel_args *args) {
   grpc_endpoint_pair endpoint_pair;
   // TODO(mlumish): implement this properly under libuv
   GPR_ASSERT(false &&
diff --git a/src/core/lib/iomgr/endpoint_pair_windows.c b/src/core/lib/iomgr/endpoint_pair_windows.c
index 93f71b745c6c0489e2c35474a34a8f639c8f5c81..25d6264dfb690cc2674cd849f7666be0268265e0 100644
--- a/src/core/lib/iomgr/endpoint_pair_windows.c
+++ b/src/core/lib/iomgr/endpoint_pair_windows.c
@@ -83,15 +83,18 @@ static void create_sockets(SOCKET sv[2]) {
 }
 
 grpc_endpoint_pair grpc_iomgr_create_endpoint_pair(
-    const char *name, grpc_resource_quota *resource_quota,
-    size_t read_slice_size) {
+    const char *name, grpc_channel_args *channel_args) {
   SOCKET sv[2];
   grpc_endpoint_pair p;
   create_sockets(sv);
-  p.client = grpc_tcp_create(grpc_winsocket_create(sv[1], "endpoint:client"),
-                             resource_quota, "endpoint:server");
-  p.server = grpc_tcp_create(grpc_winsocket_create(sv[0], "endpoint:server"),
-                             resource_quota, "endpoint:client");
+  grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+  p.client = grpc_tcp_create(&exec_ctx,
+                             grpc_winsocket_create(sv[1], "endpoint:client"),
+                             channel_args, "endpoint:server");
+  p.server = grpc_tcp_create(&exec_ctx,
+                             grpc_winsocket_create(sv[0], "endpoint:server"),
+                             channel_args, "endpoint:client");
+  grpc_exec_ctx_finish(&exec_ctx);
   return p;
 }
 
diff --git a/src/core/lib/iomgr/error.c b/src/core/lib/iomgr/error.c
index 1dbb64e8f376917fb55bf28e3015da51cbff77a9..fbbca6b4939b258f91ab89ed01a3702cc30d564d 100644
--- a/src/core/lib/iomgr/error.c
+++ b/src/core/lib/iomgr/error.c
@@ -212,7 +212,11 @@ static uint8_t get_placement(grpc_error **err, size_t size) {
   GPR_ASSERT(*err);
   uint8_t slots = (uint8_t)(size / sizeof(intptr_t));
   if ((*err)->arena_size + slots > (*err)->arena_capacity) {
-    (*err)->arena_capacity = (uint8_t)(3 * (*err)->arena_capacity / 2);
+    (*err)->arena_capacity =
+        (uint8_t)GPR_MIN(UINT8_MAX - 1, (3 * (*err)->arena_capacity / 2));
+    if ((*err)->arena_size + slots > (*err)->arena_capacity) {
+      return UINT8_MAX;
+    }
     *err = gpr_realloc(
         *err, sizeof(grpc_error) + (*err)->arena_capacity * sizeof(intptr_t));
   }
@@ -223,10 +227,14 @@ static uint8_t get_placement(grpc_error **err, size_t size) {
 
 static void internal_set_int(grpc_error **err, grpc_error_ints which,
                              intptr_t value) {
-  // GPR_ASSERT((*err)->ints[which] == UINT8_MAX); // TODO, enforce this
   uint8_t slot = (*err)->ints[which];
   if (slot == UINT8_MAX) {
     slot = get_placement(err, sizeof(value));
+    if (slot == UINT8_MAX) {
+      gpr_log(GPR_ERROR, "Error %p is full, dropping int {\"%s\":%" PRIiPTR "}",
+              *err, error_int_name(which), value);
+      return;
+    }
   }
   (*err)->ints[which] = slot;
   (*err)->arena[slot] = value;
@@ -234,10 +242,16 @@ static void internal_set_int(grpc_error **err, grpc_error_ints which,
 
 static void internal_set_str(grpc_error **err, grpc_error_strs which,
                              grpc_slice value) {
-  // GPR_ASSERT((*err)->strs[which] == UINT8_MAX); // TODO, enforce this
   uint8_t slot = (*err)->strs[which];
   if (slot == UINT8_MAX) {
     slot = get_placement(err, sizeof(value));
+    if (slot == UINT8_MAX) {
+      const char *str = grpc_slice_to_c_string(value);
+      gpr_log(GPR_ERROR, "Error %p is full, dropping string {\"%s\":\"%s\"}",
+              *err, error_str_name(which), str);
+      gpr_free((void *)str);
+      return;
+    }
   } else {
     unref_slice(*(grpc_slice *)((*err)->arena + slot));
   }
@@ -245,12 +259,19 @@ static void internal_set_str(grpc_error **err, grpc_error_strs which,
   memcpy((*err)->arena + slot, &value, sizeof(value));
 }
 
+static char *fmt_time(gpr_timespec tm);
 static void internal_set_time(grpc_error **err, grpc_error_times which,
                               gpr_timespec value) {
-  // GPR_ASSERT((*err)->times[which] == UINT8_MAX); // TODO, enforce this
   uint8_t slot = (*err)->times[which];
   if (slot == UINT8_MAX) {
     slot = get_placement(err, sizeof(value));
+    if (slot == UINT8_MAX) {
+      const char *time_str = fmt_time(value);
+      gpr_log(GPR_ERROR, "Error %p is full, dropping \"%s\":\"%s\"}", *err,
+              error_time_name(which), time_str);
+      gpr_free((void *)time_str);
+      return;
+    }
   }
   (*err)->times[which] = slot;
   memcpy((*err)->arena + slot, &value, sizeof(value));
@@ -259,6 +280,12 @@ static void internal_set_time(grpc_error **err, grpc_error_times which,
 static void internal_add_error(grpc_error **err, grpc_error *new) {
   grpc_linked_error new_last = {new, UINT8_MAX};
   uint8_t slot = get_placement(err, sizeof(grpc_linked_error));
+  if (slot == UINT8_MAX) {
+    gpr_log(GPR_ERROR, "Error %p is full, dropping error %p = %s", *err, new,
+            grpc_error_string(new));
+    GRPC_ERROR_UNREF(new);
+    return;
+  }
   if ((*err)->first_err == UINT8_MAX) {
     GPR_ASSERT((*err)->last_err == UINT8_MAX);
     (*err)->last_err = slot;
diff --git a/src/core/lib/iomgr/ev_epoll_linux.c b/src/core/lib/iomgr/ev_epoll_linux.c
index 7014b98349525c4fd3c55ff999f98c3a30aa322c..4a0f91391f2429011898a66a2ce02b39fe68684b 100644
--- a/src/core/lib/iomgr/ev_epoll_linux.c
+++ b/src/core/lib/iomgr/ev_epoll_linux.c
@@ -56,6 +56,7 @@
 
 #include "src/core/lib/iomgr/ev_posix.h"
 #include "src/core/lib/iomgr/iomgr_internal.h"
+#include "src/core/lib/iomgr/lockfree_event.h"
 #include "src/core/lib/iomgr/timer.h"
 #include "src/core/lib/iomgr/wakeup_fd_posix.h"
 #include "src/core/lib/iomgr/workqueue.h"
@@ -141,52 +142,11 @@ struct grpc_fd {
      Ref/Unref by two to avoid altering the orphaned bit */
   gpr_atm refst;
 
-  /* Internally stores data of type (grpc_error *). If the FD is shutdown, this
-     contains reason for shutdown (i.e a pointer to grpc_error) ORed with
-     FD_SHUTDOWN_BIT. Since address allocations are word-aligned, the lower bit
-     of (grpc_error *) addresses is guaranteed to be zero. Even if the
-     (grpc_error *), is of special types like GRPC_ERROR_NONE, GRPC_ERROR_OOM
-     etc, the lower bit is guaranteed to be zero.
-
-     Once an fd is shutdown, any pending or future read/write closures on the
-     fd should fail */
-  gpr_atm shutdown_error;
-
   /* The fd is either closed or we relinquished control of it. In either
      cases, this indicates that the 'fd' on this structure is no longer
      valid */
   bool orphaned;
 
-  /* Closures to call when the fd is readable or writable respectively. These
-     fields contain one of the following values:
-       CLOSURE_READY     : The fd has an I/O event of interest but there is no
-                           closure yet to execute
-
-       CLOSURE_NOT_READY : The fd has no I/O event of interest
-
-       closure ptr       : The closure to be executed when the fd has an I/O
-                           event of interest
-
-       shutdown_error | FD_SHUTDOWN_BIT :
-                          'shutdown_error' field ORed with FD_SHUTDOWN_BIT.
-                           This indicates that the fd is shutdown. Since all
-                           memory allocations are word-aligned, the lower two
-                           bits of the shutdown_error pointer are always 0. So
-                           it is safe to OR these with FD_SHUTDOWN_BIT
-
-     Valid state transitions:
-
-       <closure ptr> <-----3------ CLOSURE_NOT_READY ----1---->  CLOSURE_READY
-         |  |                         ^   |    ^                         |  |
-         |  |                         |   |    |                         |  |
-         |  +--------------4----------+   6    +---------2---------------+  |
-         |                                |                                 |
-         |                                v                                 |
-         +-----5------->  [shutdown_error | FD_SHUTDOWN_BIT] <----7---------+
-
-      For 1, 4 : See set_ready() function
-      For 2, 3 : See notify_on() function
-      For 5,6,7: See set_shutdown() function */
   gpr_atm read_closure;
   gpr_atm write_closure;
 
@@ -218,11 +178,6 @@ static void fd_unref(grpc_fd *fd);
 static void fd_global_init(void);
 static void fd_global_shutdown(void);
 
-#define CLOSURE_NOT_READY ((gpr_atm)0)
-#define CLOSURE_READY ((gpr_atm)2)
-
-#define FD_SHUTDOWN_BIT 1
-
 /*******************************************************************************
  * Polling island Declarations
  */
@@ -949,10 +904,8 @@ static void unref_by(grpc_fd *fd, int n) {
     fd_freelist = fd;
     grpc_iomgr_unregister_object(&fd->iomgr_object);
 
-    grpc_error *err = (grpc_error *)gpr_atm_acq_load(&fd->shutdown_error);
-    /* Clear the least significant bit if it set (in case fd was shutdown) */
-    err = (grpc_error *)((intptr_t)err & ~FD_SHUTDOWN_BIT);
-    GRPC_ERROR_UNREF(err);
+    grpc_lfev_destroy(&fd->read_closure);
+    grpc_lfev_destroy(&fd->write_closure);
 
     gpr_mu_unlock(&fd_freelist_mu);
   } else {
@@ -1016,10 +969,9 @@ static grpc_fd *fd_create(int fd, const char *name) {
 
   gpr_atm_rel_store(&new_fd->refst, (gpr_atm)1);
   new_fd->fd = fd;
-  gpr_atm_no_barrier_store(&new_fd->shutdown_error, (gpr_atm)GRPC_ERROR_NONE);
   new_fd->orphaned = false;
-  gpr_atm_no_barrier_store(&new_fd->read_closure, CLOSURE_NOT_READY);
-  gpr_atm_no_barrier_store(&new_fd->write_closure, CLOSURE_NOT_READY);
+  grpc_lfev_init(&new_fd->read_closure);
+  grpc_lfev_init(&new_fd->write_closure);
   gpr_atm_no_barrier_store(&new_fd->read_notifier_pollset, (gpr_atm)NULL);
 
   new_fd->freelist_next = NULL;
@@ -1105,153 +1057,6 @@ static void fd_orphan(grpc_exec_ctx *exec_ctx, grpc_fd *fd,
   GRPC_ERROR_UNREF(error);
 }
 
-static void notify_on(grpc_exec_ctx *exec_ctx, grpc_fd *fd, gpr_atm *state,
-                      grpc_closure *closure) {
-  while (true) {
-    gpr_atm curr = gpr_atm_no_barrier_load(state);
-    switch (curr) {
-      case CLOSURE_NOT_READY: {
-        /* CLOSURE_NOT_READY -> <closure>.
-
-           We're guaranteed by API that there's an acquire barrier before here,
-           so there's no need to double-dip and this can be a release-only.
-
-           The release itself pairs with the acquire half of a set_ready full
-           barrier. */
-        if (gpr_atm_rel_cas(state, CLOSURE_NOT_READY, (gpr_atm)closure)) {
-          return; /* Successful. Return */
-        }
-
-        break; /* retry */
-      }
-
-      case CLOSURE_READY: {
-        /* Change the state to CLOSURE_NOT_READY. Schedule the closure if
-           successful. If not, the state most likely transitioned to shutdown.
-           We should retry.
-
-           This can be a no-barrier cas since the state is being transitioned to
-           CLOSURE_NOT_READY; set_ready and set_shutdown do not schedule any
-           closure when transitioning out of CLOSURE_NO_READY state (i.e there
-           is no other code that needs to 'happen-after' this) */
-        if (gpr_atm_no_barrier_cas(state, CLOSURE_READY, CLOSURE_NOT_READY)) {
-          grpc_closure_sched(exec_ctx, closure, GRPC_ERROR_NONE);
-          return; /* Successful. Return */
-        }
-
-        break; /* retry */
-      }
-
-      default: {
-        /* 'curr' is either a closure or the fd is shutdown(in which case 'curr'
-           contains a pointer to the shutdown-error). If the fd is shutdown,
-           schedule the closure with the shutdown error */
-        if ((curr & FD_SHUTDOWN_BIT) > 0) {
-          grpc_error *shutdown_err = (grpc_error *)(curr & ~FD_SHUTDOWN_BIT);
-          grpc_closure_sched(exec_ctx, closure,
-                             GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING(
-                                 "FD Shutdown", &shutdown_err, 1));
-          return;
-        }
-
-        /* There is already a closure!. This indicates a bug in the code */
-        gpr_log(GPR_ERROR,
-                "notify_on called with a previous callback still pending");
-        abort();
-      }
-    }
-  }
-
-  GPR_UNREACHABLE_CODE(return );
-}
-
-static void set_shutdown(grpc_exec_ctx *exec_ctx, grpc_fd *fd, gpr_atm *state,
-                         grpc_error *shutdown_err) {
-  gpr_atm new_state = (gpr_atm)shutdown_err | FD_SHUTDOWN_BIT;
-
-  while (true) {
-    gpr_atm curr = gpr_atm_no_barrier_load(state);
-    switch (curr) {
-      case CLOSURE_READY:
-      case CLOSURE_NOT_READY:
-        /* Need a full barrier here so that the initial load in notify_on
-           doesn't need a barrier */
-        if (gpr_atm_full_cas(state, curr, new_state)) {
-          return; /* early out */
-        }
-        break; /* retry */
-
-      default: {
-        /* 'curr' is either a closure or the fd is already shutdown */
-
-        /* If fd is already shutdown, we are done */
-        if ((curr & FD_SHUTDOWN_BIT) > 0) {
-          return;
-        }
-
-        /* Fd is not shutdown. Schedule the closure and move the state to
-           shutdown state.
-           Needs an acquire to pair with setting the closure (and get a
-           happens-after on that edge), and a release to pair with anything
-           loading the shutdown state. */
-        if (gpr_atm_full_cas(state, curr, new_state)) {
-          grpc_closure_sched(exec_ctx, (grpc_closure *)curr,
-                             GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING(
-                                 "FD Shutdown", &shutdown_err, 1));
-          return;
-        }
-
-        /* 'curr' was a closure but now changed to a different state. We will
-          have to retry */
-        break;
-      }
-    }
-  }
-
-  GPR_UNREACHABLE_CODE(return );
-}
-
-static void set_ready(grpc_exec_ctx *exec_ctx, grpc_fd *fd, gpr_atm *state) {
-  while (true) {
-    gpr_atm curr = gpr_atm_no_barrier_load(state);
-
-    switch (curr) {
-      case CLOSURE_READY: {
-        /* Already ready. We are done here */
-        return;
-      }
-
-      case CLOSURE_NOT_READY: {
-        /* No barrier required as we're transitioning to a state that does not
-           involve a closure */
-        if (gpr_atm_no_barrier_cas(state, CLOSURE_NOT_READY, CLOSURE_READY)) {
-          return; /* early out */
-        }
-        break; /* retry */
-      }
-
-      default: {
-        /* 'curr' is either a closure or the fd is shutdown */
-        if ((curr & FD_SHUTDOWN_BIT) > 0) {
-          /* The fd is shutdown. Do nothing */
-          return;
-        }
-        /* Full cas: acquire pairs with this cas' release in the event of a
-           spurious set_ready; release pairs with this or the acquire in
-           notify_on (or set_shutdown) */
-        else if (gpr_atm_full_cas(state, curr, CLOSURE_NOT_READY)) {
-          grpc_closure_sched(exec_ctx, (grpc_closure *)curr, GRPC_ERROR_NONE);
-          return;
-        }
-        /* else the state changed again (only possible by either a racing
-           set_ready or set_shutdown functions. In both these cases, the closure
-           would have been scheduled for execution. So we are done here */
-        return;
-      }
-    }
-  }
-}
-
 static grpc_pollset *fd_get_read_notifier_pollset(grpc_exec_ctx *exec_ctx,
                                                   grpc_fd *fd) {
   gpr_atm notifier = gpr_atm_acq_load(&fd->read_notifier_pollset);
@@ -1259,33 +1064,27 @@ static grpc_pollset *fd_get_read_notifier_pollset(grpc_exec_ctx *exec_ctx,
 }
 
 static bool fd_is_shutdown(grpc_fd *fd) {
-  grpc_error *err = (grpc_error *)gpr_atm_acq_load(&fd->shutdown_error);
-  return (((intptr_t)err & FD_SHUTDOWN_BIT) > 0);
+  return grpc_lfev_is_shutdown(&fd->read_closure);
 }
 
 /* Might be called multiple times */
 static void fd_shutdown(grpc_exec_ctx *exec_ctx, grpc_fd *fd, grpc_error *why) {
-  /* Store the shutdown error ORed with FD_SHUTDOWN_BIT in fd->shutdown_error */
-  if (gpr_atm_rel_cas(&fd->shutdown_error, (gpr_atm)GRPC_ERROR_NONE,
-                      (gpr_atm)why | FD_SHUTDOWN_BIT)) {
+  if (grpc_lfev_set_shutdown(exec_ctx, &fd->read_closure,
+                             GRPC_ERROR_REF(why))) {
     shutdown(fd->fd, SHUT_RDWR);
-
-    set_shutdown(exec_ctx, fd, &fd->read_closure, why);
-    set_shutdown(exec_ctx, fd, &fd->write_closure, why);
-  } else {
-    /* Shutdown already called */
-    GRPC_ERROR_UNREF(why);
+    grpc_lfev_set_shutdown(exec_ctx, &fd->write_closure, GRPC_ERROR_REF(why));
   }
+  GRPC_ERROR_UNREF(why);
 }
 
 static void fd_notify_on_read(grpc_exec_ctx *exec_ctx, grpc_fd *fd,
                               grpc_closure *closure) {
-  notify_on(exec_ctx, fd, &fd->read_closure, closure);
+  grpc_lfev_notify_on(exec_ctx, &fd->read_closure, closure);
 }
 
 static void fd_notify_on_write(grpc_exec_ctx *exec_ctx, grpc_fd *fd,
                                grpc_closure *closure) {
-  notify_on(exec_ctx, fd, &fd->write_closure, closure);
+  grpc_lfev_notify_on(exec_ctx, &fd->write_closure, closure);
 }
 
 static grpc_workqueue *fd_get_workqueue(grpc_fd *fd) {
@@ -1333,7 +1132,7 @@ static grpc_error *pollset_worker_kick(grpc_pollset_worker *worker) {
   if (gpr_atm_no_barrier_cas(&worker->is_kicked, (gpr_atm)0, (gpr_atm)1)) {
     GRPC_POLLING_TRACE(
         "pollset_worker_kick: Kicking worker: %p (thread id: %ld)",
-        (void *)worker, worker->pt_id);
+        (void *)worker, (long int)worker->pt_id);
     int err_num = pthread_kill(worker->pt_id, grpc_wakeup_signal);
     if (err_num != 0) {
       err = GRPC_OS_ERROR(err_num, "pthread_kill");
@@ -1475,7 +1274,7 @@ static int poll_deadline_to_millis_timeout(gpr_timespec deadline,
 
 static void fd_become_readable(grpc_exec_ctx *exec_ctx, grpc_fd *fd,
                                grpc_pollset *notifier) {
-  set_ready(exec_ctx, fd, &fd->read_closure);
+  grpc_lfev_set_ready(exec_ctx, &fd->read_closure);
 
   /* Note, it is possible that fd_become_readable might be called twice with
      different 'notifier's when an fd becomes readable and it is in two epoll
@@ -1487,7 +1286,7 @@ static void fd_become_readable(grpc_exec_ctx *exec_ctx, grpc_fd *fd,
 }
 
 static void fd_become_writable(grpc_exec_ctx *exec_ctx, grpc_fd *fd) {
-  set_ready(exec_ctx, fd, &fd->write_closure);
+  grpc_lfev_set_ready(exec_ctx, &fd->write_closure);
 }
 
 static void pollset_release_polling_island(grpc_exec_ctx *exec_ctx,
@@ -1717,7 +1516,7 @@ static grpc_error *pollset_work(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset,
   worker.pt_id = pthread_self();
   gpr_atm_no_barrier_store(&worker.is_kicked, (gpr_atm)0);
 
-  *worker_hdl = &worker;
+  if (worker_hdl) *worker_hdl = &worker;
 
   gpr_tls_set(&g_current_thread_pollset, (intptr_t)pollset);
   gpr_tls_set(&g_current_thread_worker, (intptr_t)&worker);
@@ -1795,7 +1594,7 @@ static grpc_error *pollset_work(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset,
     gpr_mu_lock(&pollset->po.mu);
   }
 
-  *worker_hdl = NULL;
+  if (worker_hdl) *worker_hdl = NULL;
 
   gpr_tls_set(&g_current_thread_pollset, (intptr_t)0);
   gpr_tls_set(&g_current_thread_worker, (intptr_t)0);
diff --git a/src/core/lib/iomgr/ev_poll_posix.c b/src/core/lib/iomgr/ev_poll_posix.c
index d90f22336225399096e8a1a4efffcf968c198db7..9834cdd197963df9a92f1176297842f0bc700957 100644
--- a/src/core/lib/iomgr/ev_poll_posix.c
+++ b/src/core/lib/iomgr/ev_poll_posix.c
@@ -871,7 +871,7 @@ static grpc_error *pollset_work(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset,
                                 grpc_pollset_worker **worker_hdl,
                                 gpr_timespec now, gpr_timespec deadline) {
   grpc_pollset_worker worker;
-  *worker_hdl = &worker;
+  if (worker_hdl) *worker_hdl = &worker;
   grpc_error *error = GRPC_ERROR_NONE;
 
   /* Avoid malloc for small number of elements. */
@@ -1092,7 +1092,7 @@ static grpc_error *pollset_work(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset,
       gpr_mu_lock(&pollset->mu);
     }
   }
-  *worker_hdl = NULL;
+  if (worker_hdl) *worker_hdl = NULL;
   GPR_TIMER_END("pollset_work", 0);
   GRPC_LOG_IF_ERROR("pollset_work", GRPC_ERROR_REF(error));
   return error;
diff --git a/src/core/lib/iomgr/ev_posix.c b/src/core/lib/iomgr/ev_posix.c
index b5be5504b9d044462e6fff3b3999a56dae36fa8f..13409a4de83edd1d6efcd28c7d9bf6db6e09cc10 100644
--- a/src/core/lib/iomgr/ev_posix.c
+++ b/src/core/lib/iomgr/ev_posix.c
@@ -111,6 +111,12 @@ static void try_engine(const char *engine) {
   }
 }
 
+/* This should be used for testing purposes ONLY */
+void grpc_set_event_engine_test_only(
+    const grpc_event_engine_vtable *ev_engine) {
+  g_event_engine = ev_engine;
+}
+
 /* Call this only after calling grpc_event_engine_init() */
 const char *grpc_get_poll_strategy_name() { return g_poll_strategy_name; }
 
diff --git a/src/core/lib/iomgr/ev_posix.h b/src/core/lib/iomgr/ev_posix.h
index 1a9e5c115aec82206ec680cadc4ab2820adb70f4..becc4d359e52ad67479ac83791b7170e1d069eef 100644
--- a/src/core/lib/iomgr/ev_posix.h
+++ b/src/core/lib/iomgr/ev_posix.h
@@ -183,4 +183,7 @@ void grpc_pollset_set_del_fd(grpc_exec_ctx *exec_ctx,
 typedef int (*grpc_poll_function_type)(struct pollfd *, nfds_t, int);
 extern grpc_poll_function_type grpc_poll_function;
 
+/* This should be used for testing purposes ONLY */
+void grpc_set_event_engine_test_only(const grpc_event_engine_vtable *);
+
 #endif /* GRPC_CORE_LIB_IOMGR_EV_POSIX_H */
diff --git a/src/core/lib/iomgr/lockfree_event.c b/src/core/lib/iomgr/lockfree_event.c
new file mode 100644
index 0000000000000000000000000000000000000000..17e3bbf7278ee6065d27674efb858dd040e5b065
--- /dev/null
+++ b/src/core/lib/iomgr/lockfree_event.c
@@ -0,0 +1,238 @@
+/*
+ *
+ * Copyright 2017, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "src/core/lib/iomgr/lockfree_event.h"
+
+#include <grpc/support/log.h>
+
+/* 'state' holds the to call when the fd is readable or writable respectively.
+   It can contain one of the following values:
+     CLOSURE_READY     : The fd has an I/O event of interest but there is no
+                         closure yet to execute
+
+     CLOSURE_NOT_READY : The fd has no I/O event of interest
+
+     closure ptr       : The closure to be executed when the fd has an I/O
+                         event of interest
+
+     shutdown_error | FD_SHUTDOWN_BIT :
+                        'shutdown_error' field ORed with FD_SHUTDOWN_BIT.
+                         This indicates that the fd is shutdown. Since all
+                         memory allocations are word-aligned, the lower two
+                         bits of the shutdown_error pointer are always 0. So
+                         it is safe to OR these with FD_SHUTDOWN_BIT
+
+   Valid state transitions:
+
+     <closure ptr> <-----3------ CLOSURE_NOT_READY ----1---->  CLOSURE_READY
+       |  |                         ^   |    ^                         |  |
+       |  |                         |   |    |                         |  |
+       |  +--------------4----------+   6    +---------2---------------+  |
+       |                                |                                 |
+       |                                v                                 |
+       +-----5------->  [shutdown_error | FD_SHUTDOWN_BIT] <----7---------+
+
+    For 1, 4 : See grpc_lfev_set_ready() function
+    For 2, 3 : See grpc_lfev_notify_on() function
+    For 5,6,7: See grpc_lfev_set_shutdown() function */
+
+#define CLOSURE_NOT_READY ((gpr_atm)0)
+#define CLOSURE_READY ((gpr_atm)2)
+
+#define FD_SHUTDOWN_BIT ((gpr_atm)1)
+
+void grpc_lfev_init(gpr_atm *state) {
+  gpr_atm_no_barrier_store(state, CLOSURE_NOT_READY);
+}
+
+void grpc_lfev_destroy(gpr_atm *state) {
+  gpr_atm curr = gpr_atm_no_barrier_load(state);
+  if (curr & FD_SHUTDOWN_BIT) {
+    GRPC_ERROR_UNREF((grpc_error *)(curr & ~FD_SHUTDOWN_BIT));
+  } else {
+    GPR_ASSERT(curr == CLOSURE_NOT_READY || curr == CLOSURE_READY);
+  }
+}
+
+bool grpc_lfev_is_shutdown(gpr_atm *state) {
+  gpr_atm curr = gpr_atm_no_barrier_load(state);
+  return (curr & FD_SHUTDOWN_BIT) != 0;
+}
+
+void grpc_lfev_notify_on(grpc_exec_ctx *exec_ctx, gpr_atm *state,
+                         grpc_closure *closure) {
+  while (true) {
+    gpr_atm curr = gpr_atm_no_barrier_load(state);
+    switch (curr) {
+      case CLOSURE_NOT_READY: {
+        /* CLOSURE_NOT_READY -> <closure>.
+
+           We're guaranteed by API that there's an acquire barrier before here,
+           so there's no need to double-dip and this can be a release-only.
+
+           The release itself pairs with the acquire half of a set_ready full
+           barrier. */
+        if (gpr_atm_rel_cas(state, CLOSURE_NOT_READY, (gpr_atm)closure)) {
+          return; /* Successful. Return */
+        }
+
+        break; /* retry */
+      }
+
+      case CLOSURE_READY: {
+        /* Change the state to CLOSURE_NOT_READY. Schedule the closure if
+           successful. If not, the state most likely transitioned to shutdown.
+           We should retry.
+
+           This can be a no-barrier cas since the state is being transitioned to
+           CLOSURE_NOT_READY; set_ready and set_shutdown do not schedule any
+           closure when transitioning out of CLOSURE_NO_READY state (i.e there
+           is no other code that needs to 'happen-after' this) */
+        if (gpr_atm_no_barrier_cas(state, CLOSURE_READY, CLOSURE_NOT_READY)) {
+          grpc_closure_sched(exec_ctx, closure, GRPC_ERROR_NONE);
+          return; /* Successful. Return */
+        }
+
+        break; /* retry */
+      }
+
+      default: {
+        /* 'curr' is either a closure or the fd is shutdown(in which case 'curr'
+           contains a pointer to the shutdown-error). If the fd is shutdown,
+           schedule the closure with the shutdown error */
+        if ((curr & FD_SHUTDOWN_BIT) > 0) {
+          grpc_error *shutdown_err = (grpc_error *)(curr & ~FD_SHUTDOWN_BIT);
+          grpc_closure_sched(exec_ctx, closure,
+                             GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING(
+                                 "FD Shutdown", &shutdown_err, 1));
+          return;
+        }
+
+        /* There is already a closure!. This indicates a bug in the code */
+        gpr_log(GPR_ERROR,
+                "notify_on called with a previous callback still pending");
+        abort();
+      }
+    }
+  }
+
+  GPR_UNREACHABLE_CODE(return );
+}
+
+bool grpc_lfev_set_shutdown(grpc_exec_ctx *exec_ctx, gpr_atm *state,
+                            grpc_error *shutdown_err) {
+  gpr_atm new_state = (gpr_atm)shutdown_err | FD_SHUTDOWN_BIT;
+
+  while (true) {
+    gpr_atm curr = gpr_atm_no_barrier_load(state);
+    switch (curr) {
+      case CLOSURE_READY:
+      case CLOSURE_NOT_READY:
+        /* Need a full barrier here so that the initial load in notify_on
+           doesn't need a barrier */
+        if (gpr_atm_full_cas(state, curr, new_state)) {
+          return true; /* early out */
+        }
+        break; /* retry */
+
+      default: {
+        /* 'curr' is either a closure or the fd is already shutdown */
+
+        /* If fd is already shutdown, we are done */
+        if ((curr & FD_SHUTDOWN_BIT) > 0) {
+          GRPC_ERROR_UNREF(shutdown_err);
+          return false;
+        }
+
+        /* Fd is not shutdown. Schedule the closure and move the state to
+           shutdown state.
+           Needs an acquire to pair with setting the closure (and get a
+           happens-after on that edge), and a release to pair with anything
+           loading the shutdown state. */
+        if (gpr_atm_full_cas(state, curr, new_state)) {
+          grpc_closure_sched(exec_ctx, (grpc_closure *)curr,
+                             GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING(
+                                 "FD Shutdown", &shutdown_err, 1));
+          return true;
+        }
+
+        /* 'curr' was a closure but now changed to a different state. We will
+          have to retry */
+        break;
+      }
+    }
+  }
+
+  GPR_UNREACHABLE_CODE(return false);
+}
+
+void grpc_lfev_set_ready(grpc_exec_ctx *exec_ctx, gpr_atm *state) {
+  while (true) {
+    gpr_atm curr = gpr_atm_no_barrier_load(state);
+
+    switch (curr) {
+      case CLOSURE_READY: {
+        /* Already ready. We are done here */
+        return;
+      }
+
+      case CLOSURE_NOT_READY: {
+        /* No barrier required as we're transitioning to a state that does not
+           involve a closure */
+        if (gpr_atm_no_barrier_cas(state, CLOSURE_NOT_READY, CLOSURE_READY)) {
+          return; /* early out */
+        }
+        break; /* retry */
+      }
+
+      default: {
+        /* 'curr' is either a closure or the fd is shutdown */
+        if ((curr & FD_SHUTDOWN_BIT) > 0) {
+          /* The fd is shutdown. Do nothing */
+          return;
+        }
+        /* Full cas: acquire pairs with this cas' release in the event of a
+           spurious set_ready; release pairs with this or the acquire in
+           notify_on (or set_shutdown) */
+        else if (gpr_atm_full_cas(state, curr, CLOSURE_NOT_READY)) {
+          grpc_closure_sched(exec_ctx, (grpc_closure *)curr, GRPC_ERROR_NONE);
+          return;
+        }
+        /* else the state changed again (only possible by either a racing
+           set_ready or set_shutdown functions. In both these cases, the closure
+           would have been scheduled for execution. So we are done here */
+        return;
+      }
+    }
+  }
+}
diff --git a/src/core/lib/iomgr/lockfree_event.h b/src/core/lib/iomgr/lockfree_event.h
new file mode 100644
index 0000000000000000000000000000000000000000..1d9119204cab9da541795dd1d44590aa6aab6ea3
--- /dev/null
+++ b/src/core/lib/iomgr/lockfree_event.h
@@ -0,0 +1,54 @@
+/*
+ *
+ * Copyright 2017, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef GRPC_CORE_LIB_IOMGR_LOCKFREE_EVENT_H
+#define GRPC_CORE_LIB_IOMGR_LOCKFREE_EVENT_H
+
+/* Lock free event notification for file descriptors */
+
+#include <grpc/support/atm.h>
+
+#include "src/core/lib/iomgr/exec_ctx.h"
+
+void grpc_lfev_init(gpr_atm *state);
+void grpc_lfev_destroy(gpr_atm *state);
+bool grpc_lfev_is_shutdown(gpr_atm *state);
+
+void grpc_lfev_notify_on(grpc_exec_ctx *exec_ctx, gpr_atm *state,
+                         grpc_closure *closure);
+/* Returns true on first successful shutdown */
+bool grpc_lfev_set_shutdown(grpc_exec_ctx *exec_ctx, gpr_atm *state,
+                            grpc_error *shutdown_err);
+void grpc_lfev_set_ready(grpc_exec_ctx *exec_ctx, gpr_atm *state);
+
+#endif /* GRPC_CORE_LIB_IOMGR_LOCKFREE_EVENT_H */
diff --git a/src/core/lib/iomgr/pollset.h b/src/core/lib/iomgr/pollset.h
index e19ce697b8d3edba687fe404195dff68c9ee5692..9bf3cdac89e2a4152964a904886f5aabdebdb514 100644
--- a/src/core/lib/iomgr/pollset.h
+++ b/src/core/lib/iomgr/pollset.h
@@ -75,6 +75,10 @@ void grpc_pollset_destroy(grpc_pollset *pollset);
    and it is guaranteed that it will not be released by grpc_pollset_work
    AFTER worker has been destroyed.
 
+   It's legal for worker to be NULL: in that case, this specific thread can not
+   be directly woken with a kick, but maybe be indirectly (with a kick against
+   the pollset as a whole).
+
    Tries not to block past deadline.
    May call grpc_closure_list_run on grpc_closure_list, without holding the
    pollset
diff --git a/src/core/lib/iomgr/pollset_windows.c b/src/core/lib/iomgr/pollset_windows.c
index 17043c1ea1ada25f21946d249f1721bd26a1cb41..04c6b7174759d10821a4ed510c185a8b80259a84 100644
--- a/src/core/lib/iomgr/pollset_windows.c
+++ b/src/core/lib/iomgr/pollset_windows.c
@@ -120,7 +120,7 @@ grpc_error *grpc_pollset_work(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset,
                               grpc_pollset_worker **worker_hdl,
                               gpr_timespec now, gpr_timespec deadline) {
   grpc_pollset_worker worker;
-  *worker_hdl = &worker;
+  if (worker_hdl) *worker_hdl = &worker;
 
   int added_worker = 0;
   worker.links[GRPC_POLLSET_WORKER_LINK_POLLSET].next =
@@ -185,7 +185,7 @@ done:
     remove_worker(&worker, GRPC_POLLSET_WORKER_LINK_POLLSET);
   }
   gpr_cv_destroy(&worker.cv);
-  *worker_hdl = NULL;
+  if (worker_hdl) *worker_hdl = NULL;
   return GRPC_ERROR_NONE;
 }
 
diff --git a/src/core/lib/iomgr/port.h b/src/core/lib/iomgr/port.h
index 94a454c0b7c7e697827edc4043b9ba8d2d846b55..269dc35003e18d927a9033b1cfb5ec8ca9e06242 100644
--- a/src/core/lib/iomgr/port.h
+++ b/src/core/lib/iomgr/port.h
@@ -85,6 +85,10 @@
 #define GRPC_LINUX_SOCKETUTILS 1
 #endif
 #endif
+#ifndef __GLIBC__
+#define GRPC_LINUX_EPOLL 1
+#define GRPC_LINUX_EVENTFD 1
+#endif
 #ifndef GRPC_LINUX_EVENTFD
 #define GRPC_POSIX_NO_SPECIAL_WAKEUP_FD 1
 #endif
diff --git a/src/core/lib/iomgr/resource_quota.c b/src/core/lib/iomgr/resource_quota.c
index 8dcd80d001145afb122d89f79d00f7bcc6a161e3..c3ee8786517218549abc4a0b907a30a1c8ac6912 100644
--- a/src/core/lib/iomgr/resource_quota.c
+++ b/src/core/lib/iomgr/resource_quota.c
@@ -142,6 +142,8 @@ struct grpc_resource_quota {
   /* Amount of free memory in the resource quota */
   int64_t free_pool;
 
+  gpr_atm last_size;
+
   /* Has rq_step been scheduled to occur? */
   bool step_scheduled;
   /* Are we currently reclaiming memory */
@@ -581,6 +583,7 @@ grpc_resource_quota *grpc_resource_quota_create(const char *name) {
   resource_quota->combiner = grpc_combiner_create(NULL);
   resource_quota->free_pool = INT64_MAX;
   resource_quota->size = INT64_MAX;
+  gpr_atm_no_barrier_store(&resource_quota->last_size, GPR_ATM_MAX);
   resource_quota->step_scheduled = false;
   resource_quota->reclaiming = false;
   gpr_atm_no_barrier_store(&resource_quota->memory_usage_estimation, 0);
@@ -643,11 +646,17 @@ void grpc_resource_quota_resize(grpc_resource_quota *resource_quota,
   rq_resize_args *a = gpr_malloc(sizeof(*a));
   a->resource_quota = grpc_resource_quota_ref_internal(resource_quota);
   a->size = (int64_t)size;
+  gpr_atm_no_barrier_store(&resource_quota->last_size,
+                           (gpr_atm)GPR_MIN((size_t)GPR_ATM_MAX, size));
   grpc_closure_init(&a->closure, rq_resize, a, grpc_schedule_on_exec_ctx);
   grpc_closure_sched(&exec_ctx, &a->closure, GRPC_ERROR_NONE);
   grpc_exec_ctx_finish(&exec_ctx);
 }
 
+size_t grpc_resource_quota_peek_size(grpc_resource_quota *resource_quota) {
+  return (size_t)gpr_atm_no_barrier_load(&resource_quota->last_size);
+}
+
 /*******************************************************************************
  * grpc_resource_user channel args api
  */
diff --git a/src/core/lib/iomgr/resource_quota.h b/src/core/lib/iomgr/resource_quota.h
index b9f62cbf83f011d03801ba9416260f65f9a05108..6f99be0d512e48cdcbdbe5244bba221f79db30cd 100644
--- a/src/core/lib/iomgr/resource_quota.h
+++ b/src/core/lib/iomgr/resource_quota.h
@@ -90,6 +90,8 @@ grpc_resource_quota *grpc_resource_quota_from_channel_args(
 double grpc_resource_quota_get_memory_pressure(
     grpc_resource_quota *resource_quota);
 
+size_t grpc_resource_quota_peek_size(grpc_resource_quota *resource_quota);
+
 typedef struct grpc_resource_user grpc_resource_user;
 
 grpc_resource_user *grpc_resource_user_create(
diff --git a/src/core/lib/iomgr/tcp_client.h b/src/core/lib/iomgr/tcp_client.h
index 0485661316ad09b45d0c8a8a14c13cd90e047ef8..bc367bdfa5da47ae69cef99001d672d467b6172a 100644
--- a/src/core/lib/iomgr/tcp_client.h
+++ b/src/core/lib/iomgr/tcp_client.h
@@ -40,10 +40,6 @@
 #include "src/core/lib/iomgr/pollset_set.h"
 #include "src/core/lib/iomgr/resolve_address.h"
 
-/* Channel arg (integer) setting how large a slice to try and read from the wire
-   each time recvmsg (or equivalent) is called */
-#define GRPC_ARG_TCP_READ_CHUNK_SIZE "grpc.experimental.tcp_read_chunk_size"
-
 /* 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).
diff --git a/src/core/lib/iomgr/tcp_client_posix.c b/src/core/lib/iomgr/tcp_client_posix.c
index a108b10da6fe47827e3aafb5b02006198d29d909..a2692707d9ea5a887244174d4db0fdb4fc971b25 100644
--- a/src/core/lib/iomgr/tcp_client_posix.c
+++ b/src/core/lib/iomgr/tcp_client_posix.c
@@ -137,29 +137,7 @@ static void tc_on_alarm(grpc_exec_ctx *exec_ctx, void *acp, grpc_error *error) {
 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) {
-  size_t tcp_read_chunk_size = GRPC_TCP_DEFAULT_READ_SLICE_SIZE;
-  grpc_resource_quota *resource_quota = grpc_resource_quota_create(NULL);
-  if (channel_args != NULL) {
-    for (size_t i = 0; i < channel_args->num_args; i++) {
-      if (0 ==
-          strcmp(channel_args->args[i].key, GRPC_ARG_TCP_READ_CHUNK_SIZE)) {
-        grpc_integer_options options = {(int)tcp_read_chunk_size, 1,
-                                        8 * 1024 * 1024};
-        tcp_read_chunk_size = (size_t)grpc_channel_arg_get_integer(
-            &channel_args->args[i], options);
-      } else if (0 ==
-                 strcmp(channel_args->args[i].key, GRPC_ARG_RESOURCE_QUOTA)) {
-        grpc_resource_quota_unref_internal(exec_ctx, resource_quota);
-        resource_quota = grpc_resource_quota_ref_internal(
-            channel_args->args[i].value.pointer.p);
-      }
-    }
-  }
-
-  grpc_endpoint *ep =
-      grpc_tcp_create(fd, resource_quota, tcp_read_chunk_size, addr_str);
-  grpc_resource_quota_unref_internal(exec_ctx, resource_quota);
-  return ep;
+  return grpc_tcp_create(exec_ctx, fd, channel_args, addr_str);
 }
 
 static void on_writable(grpc_exec_ctx *exec_ctx, void *acp, grpc_error *error) {
diff --git a/src/core/lib/iomgr/tcp_client_windows.c b/src/core/lib/iomgr/tcp_client_windows.c
index a356564766aef850707986a47e7238da8c7ca86e..d6baca50baf363d367d4c0a975a0560d5d40f11b 100644
--- a/src/core/lib/iomgr/tcp_client_windows.c
+++ b/src/core/lib/iomgr/tcp_client_windows.c
@@ -63,7 +63,7 @@ typedef struct {
   int refs;
   grpc_closure on_connect;
   grpc_endpoint **endpoint;
-  grpc_resource_quota *resource_quota;
+  grpc_channel_args *channel_args;
 } async_connect;
 
 static void async_connect_unlock_and_cleanup(grpc_exec_ctx *exec_ctx,
@@ -72,7 +72,7 @@ static void async_connect_unlock_and_cleanup(grpc_exec_ctx *exec_ctx,
   int done = (--ac->refs == 0);
   gpr_mu_unlock(&ac->mu);
   if (done) {
-    grpc_resource_quota_unref_internal(exec_ctx, ac->resource_quota);
+    grpc_channel_args_destroy(exec_ctx, ac->channel_args);
     gpr_mu_destroy(&ac->mu);
     gpr_free(ac->addr_name);
     gpr_free(ac);
@@ -119,7 +119,8 @@ static void on_connect(grpc_exec_ctx *exec_ctx, void *acp, grpc_error *error) {
       if (!wsa_success) {
         error = GRPC_WSA_ERROR(WSAGetLastError(), "ConnectEx");
       } else {
-        *ep = grpc_tcp_create(socket, ac->resource_quota, ac->addr_name);
+        *ep =
+            grpc_tcp_create(exec_ctx, socket, ac->channel_args, ac->addr_name);
         socket = NULL;
       }
     } else {
@@ -152,17 +153,6 @@ static void tcp_client_connect_impl(
   grpc_winsocket_callback_info *info;
   grpc_error *error = GRPC_ERROR_NONE;
 
-  grpc_resource_quota *resource_quota = grpc_resource_quota_create(NULL);
-  if (channel_args != NULL) {
-    for (size_t i = 0; i < channel_args->num_args; i++) {
-      if (0 == strcmp(channel_args->args[i].key, GRPC_ARG_RESOURCE_QUOTA)) {
-        grpc_resource_quota_unref_internal(exec_ctx, resource_quota);
-        resource_quota = grpc_resource_quota_ref_internal(
-            channel_args->args[i].value.pointer.p);
-      }
-    }
-  }
-
   *endpoint = NULL;
 
   /* Use dualstack sockets where available. */
@@ -225,7 +215,7 @@ static void tcp_client_connect_impl(
   ac->refs = 2;
   ac->addr_name = grpc_sockaddr_to_uri(addr);
   ac->endpoint = endpoint;
-  ac->resource_quota = resource_quota;
+  ac->channel_args = grpc_channel_args_copy(channel_args);
   grpc_closure_init(&ac->on_connect, on_connect, ac, grpc_schedule_on_exec_ctx);
 
   grpc_closure_init(&ac->on_alarm, on_alarm, ac, grpc_schedule_on_exec_ctx);
@@ -247,7 +237,6 @@ failure:
   } else if (sock != INVALID_SOCKET) {
     closesocket(sock);
   }
-  grpc_resource_quota_unref_internal(exec_ctx, resource_quota);
   grpc_closure_sched(exec_ctx, on_done, final_error);
 }
 
diff --git a/src/core/lib/iomgr/tcp_posix.c b/src/core/lib/iomgr/tcp_posix.c
index 4d7cf3ff51eb440e862ac80c82b21b1d0ff0727a..5f4b38de2b9c17e0fb02f320dda5a694df75a190 100644
--- a/src/core/lib/iomgr/tcp_posix.c
+++ b/src/core/lib/iomgr/tcp_posix.c
@@ -52,7 +52,9 @@
 #include <grpc/support/string_util.h>
 #include <grpc/support/sync.h>
 #include <grpc/support/time.h>
+#include <grpc/support/useful.h>
 
+#include "src/core/lib/channel/channel_args.h"
 #include "src/core/lib/debug/trace.h"
 #include "src/core/lib/iomgr/ev_posix.h"
 #include "src/core/lib/profiling/timers.h"
@@ -80,10 +82,14 @@ typedef struct {
   int fd;
   bool finished_edge;
   msg_iovlen_type iov_size; /* Number of slices to allocate per read attempt */
-  size_t slice_size;
+  double target_length;
+  double bytes_read_this_round;
   gpr_refcount refcount;
   gpr_atm shutdown_count;
 
+  int min_read_chunk_size;
+  int max_read_chunk_size;
+
   /* garbage after the last read */
   grpc_slice_buffer last_read_buffer;
 
@@ -108,6 +114,42 @@ typedef struct {
   grpc_resource_user_slice_allocator slice_allocator;
 } grpc_tcp;
 
+static void add_to_estimate(grpc_tcp *tcp, size_t bytes) {
+  tcp->bytes_read_this_round += (double)bytes;
+}
+
+static void finish_estimate(grpc_tcp *tcp) {
+  /* If we read >80% of the target buffer in one read loop, increase the size
+     of the target buffer to either the amount read, or twice its previous
+     value */
+  if (tcp->bytes_read_this_round > tcp->target_length * 0.8) {
+    tcp->target_length =
+        GPR_MAX(2 * tcp->target_length, tcp->bytes_read_this_round);
+  } else {
+    tcp->target_length =
+        0.99 * tcp->target_length + 0.01 * tcp->bytes_read_this_round;
+  }
+  tcp->bytes_read_this_round = 0;
+}
+
+static size_t get_target_read_size(grpc_tcp *tcp) {
+  grpc_resource_quota *rq = grpc_resource_user_quota(tcp->resource_user);
+  double pressure = grpc_resource_quota_get_memory_pressure(rq);
+  double target =
+      tcp->target_length * (pressure > 0.8 ? (1.0 - pressure) / 0.2 : 1.0);
+  size_t sz = (((size_t)GPR_CLAMP(target, tcp->min_read_chunk_size,
+                                  tcp->max_read_chunk_size)) +
+               255) &
+              ~(size_t)255;
+  /* don't use more than 1/16th of the overall resource quota for a single read
+   * alloc */
+  size_t rqmax = grpc_resource_quota_peek_size(rq);
+  if (sz > rqmax / 16 && rqmax > 1024) {
+    sz = rqmax / 16;
+  }
+  return sz;
+}
+
 static grpc_error *tcp_annotate_error(grpc_error *src_error, grpc_tcp *tcp) {
   return grpc_error_set_str(
       grpc_error_set_int(src_error, GRPC_ERROR_INT_FD, tcp->fd),
@@ -232,9 +274,7 @@ static void tcp_do_read(grpc_exec_ctx *exec_ctx, grpc_tcp *tcp) {
     /* NB: After calling call_read_cb a parallel call of the read handler may
      * be running. */
     if (errno == EAGAIN) {
-      if (tcp->iov_size > 1) {
-        tcp->iov_size /= 2;
-      }
+      finish_estimate(tcp);
       /* We've consumed the edge, request a new one */
       grpc_fd_notify_on_read(exec_ctx, tcp->em_fd, &tcp->read_closure);
     } else {
@@ -253,14 +293,13 @@ static void tcp_do_read(grpc_exec_ctx *exec_ctx, grpc_tcp *tcp) {
             GRPC_ERROR_CREATE_FROM_STATIC_STRING("Socket closed"), tcp));
     TCP_UNREF(exec_ctx, tcp, "read");
   } else {
+    add_to_estimate(tcp, (size_t)read_bytes);
     GPR_ASSERT((size_t)read_bytes <= tcp->incoming_buffer->length);
     if ((size_t)read_bytes < tcp->incoming_buffer->length) {
       grpc_slice_buffer_trim_end(
           tcp->incoming_buffer,
           tcp->incoming_buffer->length - (size_t)read_bytes,
           &tcp->last_read_buffer);
-    } else if (tcp->iov_size < MAX_READ_IOVEC) {
-      ++tcp->iov_size;
     }
     GPR_ASSERT((size_t)read_bytes == tcp->incoming_buffer->length);
     call_read_cb(exec_ctx, tcp, GRPC_ERROR_NONE);
@@ -285,11 +324,11 @@ static void tcp_read_allocation_done(grpc_exec_ctx *exec_ctx, void *tcpp,
 }
 
 static void tcp_continue_read(grpc_exec_ctx *exec_ctx, grpc_tcp *tcp) {
-  if (tcp->incoming_buffer->count < (size_t)tcp->iov_size) {
-    grpc_resource_user_alloc_slices(
-        exec_ctx, &tcp->slice_allocator, tcp->slice_size,
-        (size_t)tcp->iov_size - tcp->incoming_buffer->count,
-        tcp->incoming_buffer);
+  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) {
+    grpc_resource_user_alloc_slices(exec_ctx, &tcp->slice_allocator,
+                                    target_read_size, 1, tcp->incoming_buffer);
   } else {
     tcp_do_read(exec_ctx, tcp);
   }
@@ -540,9 +579,50 @@ static const grpc_endpoint_vtable vtable = {tcp_read,
                                             tcp_get_peer,
                                             tcp_get_fd};
 
-grpc_endpoint *grpc_tcp_create(grpc_fd *em_fd,
-                               grpc_resource_quota *resource_quota,
-                               size_t slice_size, const char *peer_string) {
+#define MAX_CHUNK_SIZE 32 * 1024 * 1024
+
+grpc_endpoint *grpc_tcp_create(grpc_exec_ctx *exec_ctx, grpc_fd *em_fd,
+                               const grpc_channel_args *channel_args,
+                               const char *peer_string) {
+  int tcp_read_chunk_size = GRPC_TCP_DEFAULT_READ_SLICE_SIZE;
+  int tcp_max_read_chunk_size = 4 * 1024 * 1024;
+  int tcp_min_read_chunk_size = 256;
+  grpc_resource_quota *resource_quota = grpc_resource_quota_create(NULL);
+  if (channel_args != NULL) {
+    for (size_t i = 0; i < channel_args->num_args; i++) {
+      if (0 ==
+          strcmp(channel_args->args[i].key, GRPC_ARG_TCP_READ_CHUNK_SIZE)) {
+        grpc_integer_options options = {(int)tcp_read_chunk_size, 1,
+                                        MAX_CHUNK_SIZE};
+        tcp_read_chunk_size =
+            grpc_channel_arg_get_integer(&channel_args->args[i], options);
+      } else if (0 == strcmp(channel_args->args[i].key,
+                             GRPC_ARG_TCP_MIN_READ_CHUNK_SIZE)) {
+        grpc_integer_options options = {(int)tcp_read_chunk_size, 1,
+                                        MAX_CHUNK_SIZE};
+        tcp_min_read_chunk_size =
+            grpc_channel_arg_get_integer(&channel_args->args[i], options);
+      } else if (0 == strcmp(channel_args->args[i].key,
+                             GRPC_ARG_TCP_MAX_READ_CHUNK_SIZE)) {
+        grpc_integer_options options = {(int)tcp_read_chunk_size, 1,
+                                        MAX_CHUNK_SIZE};
+        tcp_max_read_chunk_size =
+            grpc_channel_arg_get_integer(&channel_args->args[i], options);
+      } else if (0 ==
+                 strcmp(channel_args->args[i].key, GRPC_ARG_RESOURCE_QUOTA)) {
+        grpc_resource_quota_unref_internal(exec_ctx, resource_quota);
+        resource_quota = grpc_resource_quota_ref_internal(
+            channel_args->args[i].value.pointer.p);
+      }
+    }
+  }
+
+  if (tcp_min_read_chunk_size > tcp_max_read_chunk_size) {
+    tcp_min_read_chunk_size = tcp_max_read_chunk_size;
+  }
+  tcp_read_chunk_size = GPR_CLAMP(tcp_read_chunk_size, tcp_min_read_chunk_size,
+                                  tcp_max_read_chunk_size);
+
   grpc_tcp *tcp = (grpc_tcp *)gpr_malloc(sizeof(grpc_tcp));
   tcp->base.vtable = &vtable;
   tcp->peer_string = gpr_strdup(peer_string);
@@ -552,7 +632,10 @@ grpc_endpoint *grpc_tcp_create(grpc_fd *em_fd,
   tcp->release_fd_cb = NULL;
   tcp->release_fd = NULL;
   tcp->incoming_buffer = NULL;
-  tcp->slice_size = slice_size;
+  tcp->target_length = (double)tcp_read_chunk_size;
+  tcp->min_read_chunk_size = tcp_min_read_chunk_size;
+  tcp->max_read_chunk_size = tcp_max_read_chunk_size;
+  tcp->bytes_read_this_round = 0;
   tcp->iov_size = 1;
   tcp->finished_edge = true;
   /* paired with unref in grpc_tcp_destroy */
@@ -569,6 +652,7 @@ grpc_endpoint *grpc_tcp_create(grpc_fd *em_fd,
       &tcp->slice_allocator, tcp->resource_user, tcp_read_allocation_done, tcp);
   /* Tell network status tracker about new endpoint */
   grpc_network_status_register_endpoint(&tcp->base);
+  grpc_resource_quota_unref_internal(exec_ctx, resource_quota);
 
   return &tcp->base;
 }
diff --git a/src/core/lib/iomgr/tcp_posix.h b/src/core/lib/iomgr/tcp_posix.h
index 1c0d13f96e2d3d2c726863cfabae6772e6c27141..1ad5788331ffd7cc0b525cd90a90ca839fe0b931 100644
--- a/src/core/lib/iomgr/tcp_posix.h
+++ b/src/core/lib/iomgr/tcp_posix.h
@@ -47,14 +47,13 @@
 #include "src/core/lib/iomgr/endpoint.h"
 #include "src/core/lib/iomgr/ev_posix.h"
 
-#define GRPC_TCP_DEFAULT_READ_SLICE_SIZE 8192
-
 extern int grpc_tcp_trace;
 
 /* Create a tcp endpoint given a file desciptor and a read slice size.
    Takes ownership of fd. */
-grpc_endpoint *grpc_tcp_create(grpc_fd *fd, grpc_resource_quota *resource_quota,
-                               size_t read_slice_size, const char *peer_string);
+grpc_endpoint *grpc_tcp_create(grpc_exec_ctx *exec_ctx, grpc_fd *fd,
+                               const grpc_channel_args *args,
+                               const char *peer_string);
 
 /* Return the tcp endpoint's fd, or -1 if this is not available. Does not
    release the fd.
diff --git a/src/core/lib/iomgr/tcp_server_posix.c b/src/core/lib/iomgr/tcp_server_posix.c
index d6a017cf7f687770fea031cb1c17eee5661b5a6c..e66ffc9b1c22cf8c56a1910c42d0b9f4b6595f0a 100644
--- a/src/core/lib/iomgr/tcp_server_posix.c
+++ b/src/core/lib/iomgr/tcp_server_posix.c
@@ -59,6 +59,7 @@
 #include <grpc/support/time.h>
 #include <grpc/support/useful.h>
 
+#include "src/core/lib/channel/channel_args.h"
 #include "src/core/lib/iomgr/resolve_address.h"
 #include "src/core/lib/iomgr/sockaddr.h"
 #include "src/core/lib/iomgr/sockaddr_utils.h"
@@ -90,7 +91,6 @@ grpc_error *grpc_tcp_server_create(grpc_exec_ctx *exec_ctx,
 
   grpc_tcp_server *s = gpr_zalloc(sizeof(grpc_tcp_server));
   s->so_reuseport = has_so_reuseport;
-  s->resource_quota = grpc_resource_quota_create(NULL);
   s->expand_wildcard_addrs = false;
   for (size_t i = 0; i < (args == NULL ? 0 : args->num_args); i++) {
     if (0 == strcmp(GRPC_ARG_ALLOW_REUSEPORT, args->args[i].key)) {
@@ -98,27 +98,14 @@ grpc_error *grpc_tcp_server_create(grpc_exec_ctx *exec_ctx,
         s->so_reuseport =
             has_so_reuseport && (args->args[i].value.integer != 0);
       } else {
-        grpc_resource_quota_unref_internal(exec_ctx, s->resource_quota);
         gpr_free(s);
         return GRPC_ERROR_CREATE_FROM_STATIC_STRING(GRPC_ARG_ALLOW_REUSEPORT
                                                     " must be an integer");
       }
-    } else if (0 == strcmp(GRPC_ARG_RESOURCE_QUOTA, args->args[i].key)) {
-      if (args->args[i].type == GRPC_ARG_POINTER) {
-        grpc_resource_quota_unref_internal(exec_ctx, s->resource_quota);
-        s->resource_quota =
-            grpc_resource_quota_ref_internal(args->args[i].value.pointer.p);
-      } else {
-        grpc_resource_quota_unref_internal(exec_ctx, s->resource_quota);
-        gpr_free(s);
-        return GRPC_ERROR_CREATE_FROM_STATIC_STRING(
-            GRPC_ARG_RESOURCE_QUOTA " must be a pointer to a buffer pool");
-      }
     } else if (0 == strcmp(GRPC_ARG_EXPAND_WILDCARD_ADDRS, args->args[i].key)) {
       if (args->args[i].type == GRPC_ARG_INTEGER) {
         s->expand_wildcard_addrs = (args->args[i].value.integer != 0);
       } else {
-        grpc_resource_quota_unref_internal(exec_ctx, s->resource_quota);
         gpr_free(s);
         return GRPC_ERROR_CREATE_FROM_STATIC_STRING(
             GRPC_ARG_EXPAND_WILDCARD_ADDRS " must be an integer");
@@ -138,6 +125,7 @@ grpc_error *grpc_tcp_server_create(grpc_exec_ctx *exec_ctx,
   s->head = NULL;
   s->tail = NULL;
   s->nports = 0;
+  s->channel_args = grpc_channel_args_copy(args);
   gpr_atm_no_barrier_store(&s->next_pollset_to_assign, 0);
   *server = s;
   return GRPC_ERROR_NONE;
@@ -158,8 +146,7 @@ static void finish_shutdown(grpc_exec_ctx *exec_ctx, grpc_tcp_server *s) {
     s->head = sp->next;
     gpr_free(sp);
   }
-
-  grpc_resource_quota_unref_internal(exec_ctx, s->resource_quota);
+  grpc_channel_args_destroy(exec_ctx, s->channel_args);
 
   gpr_free(s);
 }
@@ -286,8 +273,7 @@ static void on_read(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *err) {
 
     sp->server->on_accept_cb(
         exec_ctx, sp->server->on_accept_cb_arg,
-        grpc_tcp_create(fdobj, sp->server->resource_quota,
-                        GRPC_TCP_DEFAULT_READ_SLICE_SIZE, addr_str),
+        grpc_tcp_create(exec_ctx, fdobj, sp->server->channel_args, addr_str),
         read_notifier_pollset, acceptor);
 
     gpr_free(name);
diff --git a/src/core/lib/iomgr/tcp_server_utils_posix.h b/src/core/lib/iomgr/tcp_server_utils_posix.h
index f5dc8532f9fb56ad6855fa55b6f6564acc39e3ab..c15e2e1493a4e2462e066c2eb75c7b906016bd0d 100644
--- a/src/core/lib/iomgr/tcp_server_utils_posix.h
+++ b/src/core/lib/iomgr/tcp_server_utils_posix.h
@@ -103,7 +103,8 @@ struct grpc_tcp_server {
   /* next pollset to assign a channel to */
   gpr_atm next_pollset_to_assign;
 
-  grpc_resource_quota *resource_quota;
+  /* channel args for this server */
+  grpc_channel_args *channel_args;
 };
 
 /* If successful, add a listener to \a s for \a addr, set \a dsmode for the
diff --git a/src/core/lib/iomgr/tcp_server_windows.c b/src/core/lib/iomgr/tcp_server_windows.c
index 12ce7d3fdd5574d9ed10200cd94e79ff09c2e00a..4c17f08918b1ec86c7568a08fb2233276eeb161b 100644
--- a/src/core/lib/iomgr/tcp_server_windows.c
+++ b/src/core/lib/iomgr/tcp_server_windows.c
@@ -46,6 +46,7 @@
 #include <grpc/support/sync.h>
 #include <grpc/support/time.h>
 
+#include "src/core/lib/channel/channel_args.h"
 #include "src/core/lib/iomgr/iocp_windows.h"
 #include "src/core/lib/iomgr/pollset_windows.h"
 #include "src/core/lib/iomgr/resolve_address.h"
@@ -102,7 +103,7 @@ struct grpc_tcp_server {
   /* shutdown callback */
   grpc_closure *shutdown_complete;
 
-  grpc_resource_quota *resource_quota;
+  grpc_channel_args *channel_args;
 };
 
 /* Public function. Allocates the proper data structures to hold a
@@ -112,21 +113,7 @@ grpc_error *grpc_tcp_server_create(grpc_exec_ctx *exec_ctx,
                                    const grpc_channel_args *args,
                                    grpc_tcp_server **server) {
   grpc_tcp_server *s = gpr_malloc(sizeof(grpc_tcp_server));
-  s->resource_quota = grpc_resource_quota_create(NULL);
-  for (size_t i = 0; i < (args == NULL ? 0 : args->num_args); i++) {
-    if (0 == strcmp(GRPC_ARG_RESOURCE_QUOTA, args->args[i].key)) {
-      if (args->args[i].type == GRPC_ARG_POINTER) {
-        grpc_resource_quota_unref_internal(exec_ctx, s->resource_quota);
-        s->resource_quota =
-            grpc_resource_quota_ref_internal(args->args[i].value.pointer.p);
-      } else {
-        grpc_resource_quota_unref_internal(exec_ctx, s->resource_quota);
-        gpr_free(s);
-        return GRPC_ERROR_CREATE_FROM_STATIC_STRING(
-            GRPC_ARG_RESOURCE_QUOTA " must be a pointer to a buffer pool");
-      }
-    }
-  }
+  s->channel_args = grpc_channel_args_copy(args);
   gpr_ref_init(&s->refs, 1);
   gpr_mu_init(&s->mu);
   s->active_ports = 0;
@@ -155,7 +142,7 @@ static void destroy_server(grpc_exec_ctx *exec_ctx, void *arg,
     grpc_winsocket_destroy(sp->socket);
     gpr_free(sp);
   }
-  grpc_resource_quota_unref_internal(exec_ctx, s->resource_quota);
+  grpc_channel_args_destroy(exec_ctx, s->channel_args);
   gpr_free(s);
 }
 
@@ -383,8 +370,8 @@ static void on_accept(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *error) {
         gpr_free(utf8_message);
       }
       gpr_asprintf(&fd_name, "tcp_server:%s", peer_name_string);
-      ep = grpc_tcp_create(grpc_winsocket_create(sock, fd_name),
-                           sp->server->resource_quota, peer_name_string);
+      ep = grpc_tcp_create(exec_ctx, grpc_winsocket_create(sock, fd_name),
+                           sp->server->channel_args, peer_name_string);
       gpr_free(fd_name);
       gpr_free(peer_name_string);
     } else {
diff --git a/src/core/lib/iomgr/tcp_windows.c b/src/core/lib/iomgr/tcp_windows.c
index 91348832268b26487483769ad48817d0705c1dea..f74aa687936e92a8e1fa6f73522e6d15d3e4ffe5 100644
--- a/src/core/lib/iomgr/tcp_windows.c
+++ b/src/core/lib/iomgr/tcp_windows.c
@@ -430,9 +430,19 @@ static grpc_endpoint_vtable vtable = {win_read,
                                       win_get_peer,
                                       win_get_fd};
 
-grpc_endpoint *grpc_tcp_create(grpc_winsocket *socket,
-                               grpc_resource_quota *resource_quota,
+grpc_endpoint *grpc_tcp_create(grpc_exec_ctx *exec_ctx, grpc_winsocket *socket,
+                               grpc_channel_args *channel_args,
                                char *peer_string) {
+  grpc_resource_quota *resource_quota = grpc_resource_quota_create(NULL);
+  if (channel_args != NULL) {
+    for (size_t i = 0; i < channel_args->num_args; i++) {
+      if (0 == strcmp(channel_args->args[i].key, GRPC_ARG_RESOURCE_QUOTA)) {
+        grpc_resource_quota_unref_internal(exec_ctx, resource_quota);
+        resource_quota = grpc_resource_quota_ref_internal(
+            channel_args->args[i].value.pointer.p);
+      }
+    }
+  }
   grpc_tcp *tcp = (grpc_tcp *)gpr_malloc(sizeof(grpc_tcp));
   memset(tcp, 0, sizeof(grpc_tcp));
   tcp->base.vtable = &vtable;
diff --git a/src/core/lib/iomgr/tcp_windows.h b/src/core/lib/iomgr/tcp_windows.h
index 4402de1c385290eaed1839546571ab04c5223313..abafdb22d202292c84628e390e7c6dfbe16474ec 100644
--- a/src/core/lib/iomgr/tcp_windows.h
+++ b/src/core/lib/iomgr/tcp_windows.h
@@ -50,8 +50,8 @@
 /* Create a tcp endpoint given a winsock handle.
  * Takes ownership of the handle.
  */
-grpc_endpoint *grpc_tcp_create(grpc_winsocket *socket,
-                               grpc_resource_quota *resource_quota,
+grpc_endpoint *grpc_tcp_create(grpc_exec_ctx *exec_ctx, grpc_winsocket *socket,
+                               grpc_channel_args *channel_args,
                                char *peer_string);
 
 grpc_error *grpc_tcp_prepare_socket(SOCKET sock);
diff --git a/src/core/lib/security/credentials/credentials.h b/src/core/lib/security/credentials/credentials.h
index 510b79552a31be5fa9c82a4a3edc7ba50fc371cf..89b8e3c0b3834561b01ffd8701a0b824ce680917 100644
--- a/src/core/lib/security/credentials/credentials.h
+++ b/src/core/lib/security/credentials/credentials.h
@@ -71,7 +71,7 @@ typedef enum {
 
 #define GRPC_SECURE_TOKEN_REFRESH_THRESHOLD_SECS 60
 
-#define GRPC_COMPUTE_ENGINE_METADATA_HOST "metadata"
+#define GRPC_COMPUTE_ENGINE_METADATA_HOST "metadata.google.internal"
 #define GRPC_COMPUTE_ENGINE_METADATA_TOKEN_PATH \
   "/computeMetadata/v1/instance/service-accounts/default/token"
 
diff --git a/src/core/lib/security/transport/security_connector.c b/src/core/lib/security/transport/security_connector.c
index 2b517061611809e545d54b8d57d2f75be60b7c89..dbe3263f92a37e04ed6e545848cc021e8644119f 100644
--- a/src/core/lib/security/transport/security_connector.c
+++ b/src/core/lib/security/transport/security_connector.c
@@ -448,14 +448,14 @@ grpc_server_security_connector *grpc_fake_server_security_connector_create(
 
 typedef struct {
   grpc_channel_security_connector base;
-  tsi_ssl_handshaker_factory *handshaker_factory;
+  tsi_ssl_client_handshaker_factory *handshaker_factory;
   char *target_name;
   char *overridden_target_name;
 } grpc_ssl_channel_security_connector;
 
 typedef struct {
   grpc_server_security_connector base;
-  tsi_ssl_handshaker_factory *handshaker_factory;
+  tsi_ssl_server_handshaker_factory *handshaker_factory;
 } grpc_ssl_server_security_connector;
 
 static void ssl_channel_destroy(grpc_exec_ctx *exec_ctx,
@@ -464,7 +464,7 @@ static void ssl_channel_destroy(grpc_exec_ctx *exec_ctx,
       (grpc_ssl_channel_security_connector *)sc;
   grpc_call_credentials_unref(exec_ctx, c->base.request_metadata_creds);
   if (c->handshaker_factory != NULL) {
-    tsi_ssl_handshaker_factory_destroy(c->handshaker_factory);
+    tsi_ssl_client_handshaker_factory_destroy(c->handshaker_factory);
   }
   if (c->target_name != NULL) gpr_free(c->target_name);
   if (c->overridden_target_name != NULL) gpr_free(c->overridden_target_name);
@@ -476,26 +476,11 @@ static void ssl_server_destroy(grpc_exec_ctx *exec_ctx,
   grpc_ssl_server_security_connector *c =
       (grpc_ssl_server_security_connector *)sc;
   if (c->handshaker_factory != NULL) {
-    tsi_ssl_handshaker_factory_destroy(c->handshaker_factory);
+    tsi_ssl_server_handshaker_factory_destroy(c->handshaker_factory);
   }
   gpr_free(sc);
 }
 
-static grpc_security_status ssl_create_handshaker(
-    tsi_ssl_handshaker_factory *handshaker_factory, bool is_client,
-    const char *peer_name, tsi_handshaker **handshaker) {
-  tsi_result result = TSI_OK;
-  if (handshaker_factory == NULL) return GRPC_SECURITY_ERROR;
-  result = tsi_ssl_handshaker_factory_create_handshaker(
-      handshaker_factory, is_client ? peer_name : NULL, handshaker);
-  if (result != TSI_OK) {
-    gpr_log(GPR_ERROR, "Handshaker creation failed with error %s.",
-            tsi_result_to_string(result));
-    return GRPC_SECURITY_ERROR;
-  }
-  return GRPC_SECURITY_OK;
-}
-
 static void ssl_channel_add_handshakers(grpc_exec_ctx *exec_ctx,
                                         grpc_channel_security_connector *sc,
                                         grpc_handshake_manager *handshake_mgr) {
@@ -503,11 +488,17 @@ static void ssl_channel_add_handshakers(grpc_exec_ctx *exec_ctx,
       (grpc_ssl_channel_security_connector *)sc;
   // Instantiate TSI handshaker.
   tsi_handshaker *tsi_hs = NULL;
-  ssl_create_handshaker(c->handshaker_factory, true /* is_client */,
-                        c->overridden_target_name != NULL
-                            ? c->overridden_target_name
-                            : c->target_name,
-                        &tsi_hs);
+  tsi_result result = tsi_ssl_client_handshaker_factory_create_handshaker(
+      c->handshaker_factory,
+      c->overridden_target_name != NULL ? c->overridden_target_name
+                                        : c->target_name,
+      &tsi_hs);
+  if (result != TSI_OK) {
+    gpr_log(GPR_ERROR, "Handshaker creation failed with error %s.",
+            tsi_result_to_string(result));
+    return;
+  }
+
   // Create handshakers.
   grpc_handshake_manager_add(handshake_mgr, grpc_security_handshaker_create(
                                                 exec_ctx, tsi_hs, &sc->base));
@@ -520,8 +511,14 @@ static void ssl_server_add_handshakers(grpc_exec_ctx *exec_ctx,
       (grpc_ssl_server_security_connector *)sc;
   // Instantiate TSI handshaker.
   tsi_handshaker *tsi_hs = NULL;
-  ssl_create_handshaker(c->handshaker_factory, false /* is_client */,
-                        NULL /* peer_name */, &tsi_hs);
+  tsi_result result = tsi_ssl_server_handshaker_factory_create_handshaker(
+      c->handshaker_factory, &tsi_hs);
+  if (result != TSI_OK) {
+    gpr_log(GPR_ERROR, "Handshaker creation failed with error %s.",
+            tsi_result_to_string(result));
+    return;
+  }
+
   // Create handshakers.
   grpc_handshake_manager_add(handshake_mgr, grpc_security_handshaker_create(
                                                 exec_ctx, tsi_hs, &sc->base));
diff --git a/src/core/lib/slice/slice_buffer.c b/src/core/lib/slice/slice_buffer.c
index 9176dc8a4208a1c70ac3bc138cf966f278332afd..c96b9c3b281ba8873b68e547edb3df99648def73 100644
--- a/src/core/lib/slice/slice_buffer.c
+++ b/src/core/lib/slice/slice_buffer.c
@@ -46,27 +46,29 @@
 #define GROW(x) (3 * (x) / 2)
 
 static void maybe_embiggen(grpc_slice_buffer *sb) {
-  if (sb->base_slices != sb->slices) {
-    memmove(sb->base_slices, sb->slices, sb->count * sizeof(grpc_slice));
-    sb->slices = sb->base_slices;
-  }
-
   /* How far away from sb->base_slices is sb->slices pointer */
   size_t slice_offset = (size_t)(sb->slices - sb->base_slices);
   size_t slice_count = sb->count + slice_offset;
 
   if (slice_count == sb->capacity) {
-    sb->capacity = GROW(sb->capacity);
-    GPR_ASSERT(sb->capacity > slice_count);
-    if (sb->base_slices == sb->inlined) {
-      sb->base_slices = gpr_malloc(sb->capacity * sizeof(grpc_slice));
-      memcpy(sb->base_slices, sb->inlined, slice_count * sizeof(grpc_slice));
+    if (sb->base_slices != sb->slices) {
+      /* Make room by moving elements if there's still space unused */
+      memmove(sb->base_slices, sb->slices, sb->count * sizeof(grpc_slice));
+      sb->slices = sb->base_slices;
     } else {
-      sb->base_slices =
-          gpr_realloc(sb->base_slices, sb->capacity * sizeof(grpc_slice));
-    }
+      /* Allocate more memory if no more space is available */
+      sb->capacity = GROW(sb->capacity);
+      GPR_ASSERT(sb->capacity > slice_count);
+      if (sb->base_slices == sb->inlined) {
+        sb->base_slices = gpr_malloc(sb->capacity * sizeof(grpc_slice));
+        memcpy(sb->base_slices, sb->inlined, slice_count * sizeof(grpc_slice));
+      } else {
+        sb->base_slices =
+            gpr_realloc(sb->base_slices, sb->capacity * sizeof(grpc_slice));
+      }
 
-    sb->slices = sb->base_slices + slice_offset;
+      sb->slices = sb->base_slices + slice_offset;
+    }
   }
 }
 
diff --git a/src/core/lib/support/cpu_linux.c b/src/core/lib/support/cpu_linux.c
index d6f7e7d3da6ff355394dbcd055cfeb3a5ec03ae4..1e50f59823fa2022c11048b6a1551e959b5b62d3 100644
--- a/src/core/lib/support/cpu_linux.c
+++ b/src/core/lib/support/cpu_linux.c
@@ -67,12 +67,17 @@ unsigned gpr_cpu_num_cores(void) {
 }
 
 unsigned gpr_cpu_current_cpu(void) {
+#ifdef __GLIBC__
   int cpu = sched_getcpu();
   if (cpu < 0) {
     gpr_log(GPR_ERROR, "Error determining current CPU: %s\n", strerror(errno));
     return 0;
   }
   return (unsigned)cpu;
+#else
+  // sched_getcpu() is undefined on musl
+  return 0;
+#endif
 }
 
 #endif /* GPR_CPU_LINUX */
diff --git a/src/core/lib/support/wrap_memcpy.c b/src/core/lib/support/wrap_memcpy.c
index 15c289f7b8bb410b1b48296f6495e7081d5115b0..050cc6db5ec3cb2f89b2d56429d741d1023a346a 100644
--- a/src/core/lib/support/wrap_memcpy.c
+++ b/src/core/lib/support/wrap_memcpy.c
@@ -40,7 +40,7 @@
  */
 
 #ifdef __linux__
-#ifdef __x86_64__
+#if defined(__x86_64__) && defined(__GNU_LIBRARY__)
 __asm__(".symver memcpy,memcpy@GLIBC_2.2.5");
 void *__wrap_memcpy(void *destination, const void *source, size_t num) {
   return memcpy(destination, source, num);
diff --git a/src/core/lib/surface/call.c b/src/core/lib/surface/call.c
index c37ead2318253d0311d8e762007b05b753a535f4..97d50a91be58ce68c92680e1ed453b88472b925c 100644
--- a/src/core/lib/surface/call.c
+++ b/src/core/lib/surface/call.c
@@ -145,16 +145,28 @@ typedef struct batch_control {
   grpc_transport_stream_op_batch op;
 } batch_control;
 
+typedef struct {
+  gpr_mu child_list_mu;
+  grpc_call *first_child;
+} parent_call;
+
+typedef struct {
+  grpc_call *parent;
+  /** siblings: children of the same parent form a list, and this list is
+     protected under
+      parent->mu */
+  grpc_call *sibling_next;
+  grpc_call *sibling_prev;
+} child_call;
+
 struct grpc_call {
   gpr_arena *arena;
   grpc_completion_queue *cq;
   grpc_polling_entity pollent;
   grpc_channel *channel;
-  grpc_call *parent;
-  grpc_call *first_child;
   gpr_timespec start_time;
-  /* protects first_child, and child next/prev links */
-  gpr_mu child_list_mu;
+  /* parent_call* */ gpr_atm parent_call_atm;
+  child_call *child_call;
 
   /* client or server call */
   bool is_client;
@@ -206,12 +218,6 @@ struct grpc_call {
   int send_extra_metadata_count;
   gpr_timespec send_deadline;
 
-  /** siblings: children of the same parent form a list, and this list is
-     protected under
-      parent->mu */
-  grpc_call *sibling_next;
-  grpc_call *sibling_prev;
-
   grpc_slice_buffer_stream sending_stream;
 
   grpc_byte_stream *receiving_stream;
@@ -276,6 +282,23 @@ static void add_init_error(grpc_error **composite, grpc_error *new) {
   *composite = grpc_error_add_child(*composite, new);
 }
 
+static parent_call *get_or_create_parent_call(grpc_call *call) {
+  parent_call *p = (parent_call *)gpr_atm_acq_load(&call->parent_call_atm);
+  if (p == NULL) {
+    p = gpr_arena_alloc(call->arena, sizeof(*p));
+    gpr_mu_init(&p->child_list_mu);
+    if (!gpr_atm_rel_cas(&call->parent_call_atm, (gpr_atm)NULL, (gpr_atm)p)) {
+      gpr_mu_destroy(&p->child_list_mu);
+      p = (parent_call *)gpr_atm_acq_load(&call->parent_call_atm);
+    }
+  }
+  return p;
+}
+
+static parent_call *get_parent_call(grpc_call *call) {
+  return (parent_call *)gpr_atm_acq_load(&call->parent_call_atm);
+}
+
 grpc_error *grpc_call_create(grpc_exec_ctx *exec_ctx,
                              const grpc_call_create_args *args,
                              grpc_call **out_call) {
@@ -291,10 +314,8 @@ grpc_error *grpc_call_create(grpc_exec_ctx *exec_ctx,
                          sizeof(grpc_call) + channel_stack->call_stack_size);
   call->arena = arena;
   *out_call = call;
-  gpr_mu_init(&call->child_list_mu);
   call->channel = args->channel;
   call->cq = args->cq;
-  call->parent = args->parent_call;
   call->start_time = gpr_now(GPR_CLOCK_MONOTONIC);
   /* Always support no compression */
   GPR_BITSET(&call->encodings_accepted_by_peer, GRPC_COMPRESS_NONE);
@@ -326,11 +347,17 @@ grpc_error *grpc_call_create(grpc_exec_ctx *exec_ctx,
       gpr_convert_clock_type(args->send_deadline, GPR_CLOCK_MONOTONIC);
 
   if (args->parent_call != NULL) {
+    child_call *cc = call->child_call =
+        gpr_arena_alloc(arena, sizeof(child_call));
+    call->child_call->parent = args->parent_call;
+
     GRPC_CALL_INTERNAL_REF(args->parent_call, "child");
     GPR_ASSERT(call->is_client);
     GPR_ASSERT(!args->parent_call->is_client);
 
-    gpr_mu_lock(&args->parent_call->child_list_mu);
+    parent_call *pc = get_or_create_parent_call(args->parent_call);
+
+    gpr_mu_lock(&pc->child_list_mu);
 
     if (args->propagation_mask & GRPC_PROPAGATE_DEADLINE) {
       send_deadline = gpr_time_min(
@@ -364,17 +391,17 @@ grpc_error *grpc_call_create(grpc_exec_ctx *exec_ctx,
       }
     }
 
-    if (args->parent_call->first_child == NULL) {
-      args->parent_call->first_child = call;
-      call->sibling_next = call->sibling_prev = call;
+    if (pc->first_child == NULL) {
+      pc->first_child = call;
+      cc->sibling_next = cc->sibling_prev = call;
     } else {
-      call->sibling_next = args->parent_call->first_child;
-      call->sibling_prev = args->parent_call->first_child->sibling_prev;
-      call->sibling_next->sibling_prev = call->sibling_prev->sibling_next =
-          call;
+      cc->sibling_next = pc->first_child;
+      cc->sibling_prev = pc->first_child->child_call->sibling_prev;
+      cc->sibling_next->child_call->sibling_prev =
+          cc->sibling_prev->child_call->sibling_next = call;
     }
 
-    gpr_mu_unlock(&args->parent_call->child_list_mu);
+    gpr_mu_unlock(&pc->child_list_mu);
   }
 
   call->send_deadline = send_deadline;
@@ -469,7 +496,10 @@ static void destroy_call(grpc_exec_ctx *exec_ctx, void *call,
   if (c->receiving_stream != NULL) {
     grpc_byte_stream_destroy(exec_ctx, c->receiving_stream);
   }
-  gpr_mu_destroy(&c->child_list_mu);
+  parent_call *pc = get_parent_call(c);
+  if (pc != NULL) {
+    gpr_mu_destroy(&pc->child_list_mu);
+  }
   for (ii = 0; ii < c->send_extra_metadata_count; ii++) {
     GRPC_MDELEM_UNREF(exec_ctx, c->send_extra_metadata[ii].md);
   }
@@ -499,31 +529,31 @@ static void destroy_call(grpc_exec_ctx *exec_ctx, void *call,
 }
 
 void grpc_call_destroy(grpc_call *c) {
-  int cancel;
-  grpc_call *parent = c->parent;
+  child_call *cc = c->child_call;
   grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
 
   GPR_TIMER_BEGIN("grpc_call_destroy", 0);
   GRPC_API_TRACE("grpc_call_destroy(c=%p)", 1, (c));
 
-  if (parent) {
-    gpr_mu_lock(&parent->child_list_mu);
-    if (c == parent->first_child) {
-      parent->first_child = c->sibling_next;
-      if (c == parent->first_child) {
-        parent->first_child = NULL;
+  if (cc) {
+    parent_call *pc = get_parent_call(cc->parent);
+    gpr_mu_lock(&pc->child_list_mu);
+    if (c == pc->first_child) {
+      pc->first_child = cc->sibling_next;
+      if (c == pc->first_child) {
+        pc->first_child = NULL;
       }
     }
-    c->sibling_prev->sibling_next = c->sibling_next;
-    c->sibling_next->sibling_prev = c->sibling_prev;
-    gpr_mu_unlock(&parent->child_list_mu);
-    GRPC_CALL_INTERNAL_UNREF(&exec_ctx, parent, "child");
+    cc->sibling_prev->child_call->sibling_next = cc->sibling_next;
+    cc->sibling_next->child_call->sibling_prev = cc->sibling_prev;
+    gpr_mu_unlock(&pc->child_list_mu);
+    GRPC_CALL_INTERNAL_UNREF(&exec_ctx, cc->parent, "child");
   }
 
   GPR_ASSERT(!c->destroy_called);
   c->destroy_called = 1;
-  cancel = gpr_atm_acq_load(&c->any_ops_sent_atm) &&
-           !gpr_atm_acq_load(&c->received_final_op_atm);
+  bool cancel = gpr_atm_acq_load(&c->any_ops_sent_atm) != 0 &&
+                gpr_atm_acq_load(&c->received_final_op_atm) == 0;
   if (cancel) {
     cancel_with_error(&exec_ctx, c, STATUS_FROM_API_OVERRIDE,
                       GRPC_ERROR_CANCELLED);
@@ -1079,7 +1109,6 @@ static grpc_error *consolidate_batch_errors(batch_control *bctl) {
 
 static void post_batch_completion(grpc_exec_ctx *exec_ctx,
                                   batch_control *bctl) {
-  grpc_call *child_call;
   grpc_call *next_child_call;
   grpc_call *call = bctl->call;
   grpc_error *error = consolidate_batch_errors(bctl);
@@ -1104,21 +1133,25 @@ static void post_batch_completion(grpc_exec_ctx *exec_ctx,
 
     /* propagate cancellation to any interested children */
     gpr_atm_rel_store(&call->received_final_op_atm, 1);
-    gpr_mu_lock(&call->child_list_mu);
-    child_call = call->first_child;
-    if (child_call != NULL) {
-      do {
-        next_child_call = child_call->sibling_next;
-        if (child_call->cancellation_is_inherited) {
-          GRPC_CALL_INTERNAL_REF(child_call, "propagate_cancel");
-          cancel_with_error(exec_ctx, child_call, STATUS_FROM_API_OVERRIDE,
-                            GRPC_ERROR_CANCELLED);
-          GRPC_CALL_INTERNAL_UNREF(exec_ctx, child_call, "propagate_cancel");
-        }
-        child_call = next_child_call;
-      } while (child_call != call->first_child);
+    parent_call *pc = get_parent_call(call);
+    if (pc != NULL) {
+      grpc_call *child;
+      gpr_mu_lock(&pc->child_list_mu);
+      child = pc->first_child;
+      if (child != NULL) {
+        do {
+          next_child_call = child->child_call->sibling_next;
+          if (child->cancellation_is_inherited) {
+            GRPC_CALL_INTERNAL_REF(child, "propagate_cancel");
+            cancel_with_error(exec_ctx, child, STATUS_FROM_API_OVERRIDE,
+                              GRPC_ERROR_CANCELLED);
+            GRPC_CALL_INTERNAL_UNREF(exec_ctx, child, "propagate_cancel");
+          }
+          child = next_child_call;
+        } while (child != pc->first_child);
+      }
+      gpr_mu_unlock(&pc->child_list_mu);
     }
-    gpr_mu_unlock(&call->child_list_mu);
 
     if (call->is_client) {
       get_final_status(call, set_status_value_directly,
diff --git a/src/core/lib/surface/completion_queue.c b/src/core/lib/surface/completion_queue.c
index b4594817e45f034fd3953becbebf7a3b0ef97613..3273addf1d0e5b693f2d9e76270b733ea8e73828 100644
--- a/src/core/lib/surface/completion_queue.c
+++ b/src/core/lib/surface/completion_queue.c
@@ -345,7 +345,6 @@ static void dump_pending_tags(grpc_completion_queue *cc) {}
 grpc_event grpc_completion_queue_next(grpc_completion_queue *cc,
                                       gpr_timespec deadline, void *reserved) {
   grpc_event ret;
-  grpc_pollset_worker *worker = NULL;
   gpr_timespec now;
 
   GPR_TIMER_BEGIN("grpc_completion_queue_next", 0);
@@ -426,8 +425,8 @@ grpc_event grpc_completion_queue_next(grpc_completion_queue *cc,
       gpr_mu_lock(cc->mu);
       continue;
     } else {
-      grpc_error *err = grpc_pollset_work(&exec_ctx, POLLSET_FROM_CQ(cc),
-                                          &worker, now, iteration_deadline);
+      grpc_error *err = grpc_pollset_work(&exec_ctx, POLLSET_FROM_CQ(cc), NULL,
+                                          now, iteration_deadline);
       if (err != GRPC_ERROR_NONE) {
         gpr_mu_unlock(cc->mu);
         const char *msg = grpc_error_string(err);
diff --git a/src/core/lib/surface/init_secure.c b/src/core/lib/surface/init_secure.c
index 921ef87e366c4e046349afb3764fe73631d5c009..746134676f8ad9b22cf09a4ccd7e43c2eff16f9e 100644
--- a/src/core/lib/surface/init_secure.c
+++ b/src/core/lib/surface/init_secure.c
@@ -31,6 +31,8 @@
  *
  */
 
+#include <grpc/support/port_platform.h>
+
 #include "src/core/lib/surface/init.h"
 
 #include <limits.h>
diff --git a/src/core/tsi/ssl_transport_security.c b/src/core/tsi/ssl_transport_security.c
index a0325cc1835a3092c3bd0ec3313da28688059b47..984f745b01d07cacf32f426b9943565c9917b9bb 100644
--- a/src/core/tsi/ssl_transport_security.c
+++ b/src/core/tsi/ssl_transport_security.c
@@ -81,23 +81,13 @@
 
 /* --- Structure definitions. ---*/
 
-struct tsi_ssl_handshaker_factory {
-  tsi_result (*create_handshaker)(tsi_ssl_handshaker_factory *self,
-                                  const char *server_name_indication,
-                                  tsi_handshaker **handshaker);
-  void (*destroy)(tsi_ssl_handshaker_factory *self);
-};
-
-typedef struct {
-  tsi_ssl_handshaker_factory base;
+struct tsi_ssl_client_handshaker_factory {
   SSL_CTX *ssl_context;
   unsigned char *alpn_protocol_list;
   size_t alpn_protocol_list_length;
-} tsi_ssl_client_handshaker_factory;
-
-typedef struct {
-  tsi_ssl_handshaker_factory base;
+};
 
+struct tsi_ssl_server_handshaker_factory {
   /* Several contexts to support SNI.
      The tsi_peer array contains the subject names of the server certificates
      associated with the contexts at the same index.  */
@@ -106,7 +96,7 @@ typedef struct {
   size_t ssl_context_count;
   unsigned char *alpn_protocol_list;
   size_t alpn_protocol_list_length;
-} tsi_ssl_server_handshaker_factory;
+};
 
 typedef struct {
   tsi_handshaker base;
@@ -1053,18 +1043,6 @@ static const tsi_handshaker_vtable handshaker_vtable = {
 
 /* --- tsi_ssl_handshaker_factory common methods. --- */
 
-tsi_result tsi_ssl_handshaker_factory_create_handshaker(
-    tsi_ssl_handshaker_factory *self, const char *server_name_indication,
-    tsi_handshaker **handshaker) {
-  if (self == NULL || handshaker == NULL) return TSI_INVALID_ARGUMENT;
-  return self->create_handshaker(self, server_name_indication, handshaker);
-}
-
-void tsi_ssl_handshaker_factory_destroy(tsi_ssl_handshaker_factory *self) {
-  if (self == NULL) return;
-  self->destroy(self);
-}
-
 static tsi_result create_tsi_ssl_handshaker(SSL_CTX *ctx, int is_client,
                                             const char *server_name_indication,
                                             tsi_handshaker **handshaker) {
@@ -1152,24 +1130,20 @@ static int select_protocol_list(const unsigned char **out,
   return SSL_TLSEXT_ERR_NOACK;
 }
 
-/* --- tsi_ssl__client_handshaker_factory methods implementation. --- */
+/* --- tsi_ssl_client_handshaker_factory methods implementation. --- */
 
-static tsi_result ssl_client_handshaker_factory_create_handshaker(
-    tsi_ssl_handshaker_factory *self, const char *server_name_indication,
+tsi_result tsi_ssl_client_handshaker_factory_create_handshaker(
+    tsi_ssl_client_handshaker_factory *self, const char *server_name_indication,
     tsi_handshaker **handshaker) {
-  tsi_ssl_client_handshaker_factory *impl =
-      (tsi_ssl_client_handshaker_factory *)self;
-  return create_tsi_ssl_handshaker(impl->ssl_context, 1, server_name_indication,
+  return create_tsi_ssl_handshaker(self->ssl_context, 1, server_name_indication,
                                    handshaker);
 }
 
-static void ssl_client_handshaker_factory_destroy(
-    tsi_ssl_handshaker_factory *self) {
-  tsi_ssl_client_handshaker_factory *impl =
-      (tsi_ssl_client_handshaker_factory *)self;
-  if (impl->ssl_context != NULL) SSL_CTX_free(impl->ssl_context);
-  if (impl->alpn_protocol_list != NULL) gpr_free(impl->alpn_protocol_list);
-  gpr_free(impl);
+void tsi_ssl_client_handshaker_factory_destroy(
+    tsi_ssl_client_handshaker_factory *self) {
+  if (self->ssl_context != NULL) SSL_CTX_free(self->ssl_context);
+  if (self->alpn_protocol_list != NULL) gpr_free(self->alpn_protocol_list);
+  gpr_free(self);
 }
 
 static int client_handshaker_factory_npn_callback(SSL *ssl, unsigned char **out,
@@ -1186,36 +1160,29 @@ static int client_handshaker_factory_npn_callback(SSL *ssl, unsigned char **out,
 
 /* --- tsi_ssl_server_handshaker_factory methods implementation. --- */
 
-static tsi_result ssl_server_handshaker_factory_create_handshaker(
-    tsi_ssl_handshaker_factory *self, const char *server_name_indication,
-    tsi_handshaker **handshaker) {
-  tsi_ssl_server_handshaker_factory *impl =
-      (tsi_ssl_server_handshaker_factory *)self;
-  if (impl->ssl_context_count == 0 || server_name_indication != NULL) {
-    return TSI_INVALID_ARGUMENT;
-  }
+tsi_result tsi_ssl_server_handshaker_factory_create_handshaker(
+    tsi_ssl_server_handshaker_factory *self, tsi_handshaker **handshaker) {
+  if (self->ssl_context_count == 0) return TSI_INVALID_ARGUMENT;
   /* Create the handshaker with the first context. We will switch if needed
      because of SNI in ssl_server_handshaker_factory_servername_callback.  */
-  return create_tsi_ssl_handshaker(impl->ssl_contexts[0], 0, NULL, handshaker);
+  return create_tsi_ssl_handshaker(self->ssl_contexts[0], 0, NULL, handshaker);
 }
 
-static void ssl_server_handshaker_factory_destroy(
-    tsi_ssl_handshaker_factory *self) {
-  tsi_ssl_server_handshaker_factory *impl =
-      (tsi_ssl_server_handshaker_factory *)self;
+void tsi_ssl_server_handshaker_factory_destroy(
+    tsi_ssl_server_handshaker_factory *self) {
   size_t i;
-  for (i = 0; i < impl->ssl_context_count; i++) {
-    if (impl->ssl_contexts[i] != NULL) {
-      SSL_CTX_free(impl->ssl_contexts[i]);
-      tsi_peer_destruct(&impl->ssl_context_x509_subject_names[i]);
+  for (i = 0; i < self->ssl_context_count; i++) {
+    if (self->ssl_contexts[i] != NULL) {
+      SSL_CTX_free(self->ssl_contexts[i]);
+      tsi_peer_destruct(&self->ssl_context_x509_subject_names[i]);
     }
   }
-  if (impl->ssl_contexts != NULL) gpr_free(impl->ssl_contexts);
-  if (impl->ssl_context_x509_subject_names != NULL) {
-    gpr_free(impl->ssl_context_x509_subject_names);
+  if (self->ssl_contexts != NULL) gpr_free(self->ssl_contexts);
+  if (self->ssl_context_x509_subject_names != NULL) {
+    gpr_free(self->ssl_context_x509_subject_names);
   }
-  if (impl->alpn_protocol_list != NULL) gpr_free(impl->alpn_protocol_list);
-  gpr_free(impl);
+  if (self->alpn_protocol_list != NULL) gpr_free(self->alpn_protocol_list);
+  gpr_free(self);
 }
 
 static int does_entry_match_name(const char *entry, size_t entry_length,
@@ -1317,7 +1284,7 @@ tsi_result tsi_create_ssl_client_handshaker_factory(
     const unsigned char *pem_root_certs, size_t pem_root_certs_size,
     const char *cipher_list, const unsigned char **alpn_protocols,
     const unsigned char *alpn_protocols_lengths, uint16_t num_alpn_protocols,
-    tsi_ssl_handshaker_factory **factory) {
+    tsi_ssl_client_handshaker_factory **factory) {
   SSL_CTX *ssl_context = NULL;
   tsi_ssl_client_handshaker_factory *impl = NULL;
   tsi_result result = TSI_OK;
@@ -1373,16 +1340,13 @@ tsi_result tsi_create_ssl_client_handshaker_factory(
     }
   } while (0);
   if (result != TSI_OK) {
-    ssl_client_handshaker_factory_destroy(&impl->base);
+    tsi_ssl_client_handshaker_factory_destroy(impl);
     return result;
   }
   SSL_CTX_set_verify(ssl_context, SSL_VERIFY_PEER, NULL);
   /* TODO(jboeuf): Add revocation verification. */
 
-  impl->base.create_handshaker =
-      ssl_client_handshaker_factory_create_handshaker;
-  impl->base.destroy = ssl_client_handshaker_factory_destroy;
-  *factory = &impl->base;
+  *factory = impl;
   return TSI_OK;
 }
 
@@ -1394,7 +1358,7 @@ tsi_result tsi_create_ssl_server_handshaker_factory(
     size_t pem_client_root_certs_size, int force_client_auth,
     const char *cipher_list, const unsigned char **alpn_protocols,
     const unsigned char *alpn_protocols_lengths, uint16_t num_alpn_protocols,
-    tsi_ssl_handshaker_factory **factory) {
+    tsi_ssl_server_handshaker_factory **factory) {
   return tsi_create_ssl_server_handshaker_factory_ex(
       pem_private_keys, pem_private_keys_sizes, pem_cert_chains,
       pem_cert_chains_sizes, key_cert_pair_count, pem_client_root_certs,
@@ -1414,7 +1378,7 @@ tsi_result tsi_create_ssl_server_handshaker_factory_ex(
     tsi_client_certificate_request_type client_certificate_request,
     const char *cipher_list, const unsigned char **alpn_protocols,
     const unsigned char *alpn_protocols_lengths, uint16_t num_alpn_protocols,
-    tsi_ssl_handshaker_factory **factory) {
+    tsi_ssl_server_handshaker_factory **factory) {
   tsi_ssl_server_handshaker_factory *impl = NULL;
   tsi_result result = TSI_OK;
   size_t i = 0;
@@ -1429,15 +1393,12 @@ tsi_result tsi_create_ssl_server_handshaker_factory_ex(
   }
 
   impl = gpr_zalloc(sizeof(*impl));
-  impl->base.create_handshaker =
-      ssl_server_handshaker_factory_create_handshaker;
-  impl->base.destroy = ssl_server_handshaker_factory_destroy;
   impl->ssl_contexts = gpr_zalloc(key_cert_pair_count * sizeof(SSL_CTX *));
   impl->ssl_context_x509_subject_names =
       gpr_zalloc(key_cert_pair_count * sizeof(tsi_peer));
   if (impl->ssl_contexts == NULL ||
       impl->ssl_context_x509_subject_names == NULL) {
-    tsi_ssl_handshaker_factory_destroy(&impl->base);
+    tsi_ssl_server_handshaker_factory_destroy(impl);
     return TSI_OUT_OF_RESOURCES;
   }
   impl->ssl_context_count = key_cert_pair_count;
@@ -1447,7 +1408,7 @@ tsi_result tsi_create_ssl_server_handshaker_factory_ex(
         alpn_protocols, alpn_protocols_lengths, num_alpn_protocols,
         &impl->alpn_protocol_list, &impl->alpn_protocol_list_length);
     if (result != TSI_OK) {
-      tsi_ssl_handshaker_factory_destroy(&impl->base);
+      tsi_ssl_server_handshaker_factory_destroy(impl);
       return result;
     }
   }
@@ -1520,11 +1481,11 @@ tsi_result tsi_create_ssl_server_handshaker_factory_ex(
     } while (0);
 
     if (result != TSI_OK) {
-      tsi_ssl_handshaker_factory_destroy(&impl->base);
+      tsi_ssl_server_handshaker_factory_destroy(impl);
       return result;
     }
   }
-  *factory = &impl->base;
+  *factory = impl;
   return TSI_OK;
 }
 
diff --git a/src/core/tsi/ssl_transport_security.h b/src/core/tsi/ssl_transport_security.h
index 0a527e9021f18717b250485c8c43caab76e54bdc..48dcaec1212f2bd5b51ad4f47657124a06385bff 100644
--- a/src/core/tsi/ssl_transport_security.h
+++ b/src/core/tsi/ssl_transport_security.h
@@ -52,12 +52,13 @@ extern "C" {
 
 #define TSI_SSL_ALPN_SELECTED_PROTOCOL "ssl_alpn_selected_protocol"
 
-/* --- tsi_ssl_handshaker_factory object ---
+/* --- tsi_ssl_client_handshaker_factory object ---
 
-   This object creates tsi_handshaker objects implemented in terms of the
-   TLS 1.2 specificiation.  */
+   This object creates a client tsi_handshaker objects implemented in terms of
+   the TLS 1.2 specificiation.  */
 
-typedef struct tsi_ssl_handshaker_factory tsi_ssl_handshaker_factory;
+typedef struct tsi_ssl_client_handshaker_factory
+    tsi_ssl_client_handshaker_factory;
 
 /* Creates a client handshaker factory.
    - pem_private_key is the buffer containing the PEM encoding of the client's
@@ -92,7 +93,33 @@ tsi_result tsi_create_ssl_client_handshaker_factory(
     const unsigned char *pem_root_certs, size_t pem_root_certs_size,
     const char *cipher_suites, const unsigned char **alpn_protocols,
     const unsigned char *alpn_protocols_lengths, uint16_t num_alpn_protocols,
-    tsi_ssl_handshaker_factory **factory);
+    tsi_ssl_client_handshaker_factory **factory);
+
+/* Creates a client handshaker.
+  - self is the factory from which the handshaker will be created.
+  - server_name_indication indicates the name of the server the client is
+    trying to connect to which will be relayed to the server using the SNI
+    extension.
+  - handshaker is the address of the handshaker pointer to be created.
+
+  - This method returns TSI_OK on success or TSI_INVALID_PARAMETER in the case
+    where a parameter is invalid.  */
+tsi_result tsi_ssl_client_handshaker_factory_create_handshaker(
+    tsi_ssl_client_handshaker_factory *self, const char *server_name_indication,
+    tsi_handshaker **handshaker);
+
+/* Destroys the handshaker factory. WARNING: it is unsafe to destroy a factory
+   while handshakers created with this factory are still in use.  */
+void tsi_ssl_client_handshaker_factory_destroy(
+    tsi_ssl_client_handshaker_factory *self);
+
+/* --- tsi_ssl_server_handshaker_factory object ---
+
+   This object creates a client tsi_handshaker objects implemented in terms of
+   the TLS 1.2 specificiation.  */
+
+typedef struct tsi_ssl_server_handshaker_factory
+    tsi_ssl_server_handshaker_factory;
 
 /* Creates a server handshaker factory.
    - version indicates which version of the specification to use.
@@ -140,7 +167,7 @@ tsi_result tsi_create_ssl_server_handshaker_factory(
     size_t pem_client_root_certs_size, int force_client_auth,
     const char *cipher_suites, const unsigned char **alpn_protocols,
     const unsigned char *alpn_protocols_lengths, uint16_t num_alpn_protocols,
-    tsi_ssl_handshaker_factory **factory);
+    tsi_ssl_server_handshaker_factory **factory);
 
 /* Same as tsi_create_ssl_server_handshaker_factory method except uses
    tsi_client_certificate_request_type to support more ways to handle client
@@ -157,25 +184,21 @@ tsi_result tsi_create_ssl_server_handshaker_factory_ex(
     tsi_client_certificate_request_type client_certificate_request,
     const char *cipher_suites, const unsigned char **alpn_protocols,
     const unsigned char *alpn_protocols_lengths, uint16_t num_alpn_protocols,
-    tsi_ssl_handshaker_factory **factory);
+    tsi_ssl_server_handshaker_factory **factory);
 
-/* Creates a handshaker.
+/* Creates a server handshaker.
   - self is the factory from which the handshaker will be created.
-  - server_name_indication indicates the name of the server the client is
-    trying to connect to which will be relayed to the server using the SNI
-    extension.
-    This parameter must be NULL for a server handshaker factory.
-  - handhshaker is the address of the handshaker pointer to be created.
+  - handshaker is the address of the handshaker pointer to be created.
 
   - This method returns TSI_OK on success or TSI_INVALID_PARAMETER in the case
     where a parameter is invalid.  */
-tsi_result tsi_ssl_handshaker_factory_create_handshaker(
-    tsi_ssl_handshaker_factory *self, const char *server_name_indication,
-    tsi_handshaker **handshaker);
+tsi_result tsi_ssl_server_handshaker_factory_create_handshaker(
+    tsi_ssl_server_handshaker_factory *self, tsi_handshaker **handshaker);
 
 /* Destroys the handshaker factory. WARNING: it is unsafe to destroy a factory
    while handshakers created with this factory are still in use.  */
-void tsi_ssl_handshaker_factory_destroy(tsi_ssl_handshaker_factory *self);
+void tsi_ssl_server_handshaker_factory_destroy(
+    tsi_ssl_server_handshaker_factory *self);
 
 /* Util that checks that an ssl peer matches a specific name.
    Still TODO(jboeuf):
diff --git a/src/csharp/Grpc.Auth/Grpc.Auth.csproj b/src/csharp/Grpc.Auth/Grpc.Auth.csproj
old mode 100644
new mode 100755
index 9ef98529e858c6260eadbc138a5ef0f51864cc45..6ac25aa1f02dfa152106864fd2861736e53dbffe
--- a/src/csharp/Grpc.Auth/Grpc.Auth.csproj
+++ b/src/csharp/Grpc.Auth/Grpc.Auth.csproj
@@ -1,78 +1,38 @@
-<?xml version="1.0" encoding="utf-8"?>
-<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+<Project Sdk="Microsoft.NET.Sdk">
+
+  <Import Project="..\Grpc.Core\Version.csproj.include" />
+  <Import Project="..\Grpc.Core\Common.csproj.include" />
+
   <PropertyGroup>
-    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
-    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
-    <ProjectGuid>{AE21D0EE-9A2C-4C15-AB7F-5224EED5B0EA}</ProjectGuid>
-    <OutputType>Library</OutputType>
-    <RootNamespace>Grpc.Auth</RootNamespace>
+    <Copyright>Copyright 2015, Google Inc.</Copyright>
+    <AssemblyTitle>gRPC C# Auth</AssemblyTitle>
+    <VersionPrefix>$(GrpcCsharpVersion)</VersionPrefix>
+    <Authors>Google Inc.</Authors>
+    <TargetFrameworks>net45;netstandard1.5</TargetFrameworks>
+    <DefineConstants>$(DefineConstants);SIGNED</DefineConstants>
     <AssemblyName>Grpc.Auth</AssemblyName>
-    <TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
-    <DocumentationFile>bin\$(Configuration)\Grpc.Auth.Xml</DocumentationFile>
-    <NuGetPackageImportStamp>455903a2</NuGetPackageImportStamp>
-  </PropertyGroup>
-  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
-    <DebugSymbols>true</DebugSymbols>
-    <DebugType>full</DebugType>
-    <Optimize>false</Optimize>
-    <OutputPath>bin\Debug</OutputPath>
-    <DefineConstants>DEBUG;</DefineConstants>
-    <ErrorReport>prompt</ErrorReport>
-    <WarningLevel>4</WarningLevel>
-    <ConsolePause>false</ConsolePause>
-  </PropertyGroup>
-  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
-    <DebugType>pdbonly</DebugType>
-    <Optimize>true</Optimize>
-    <OutputPath>bin\Release</OutputPath>
-    <ErrorReport>prompt</ErrorReport>
-    <WarningLevel>4</WarningLevel>
-    <ConsolePause>false</ConsolePause>
+    <PackageId>Grpc.Auth</PackageId>
+    <PackageTags>gRPC RPC Protocol HTTP/2 Auth OAuth2</PackageTags>
+    <PackageProjectUrl>https://github.com/grpc/grpc</PackageProjectUrl>
+    <PackageLicenseUrl>https://github.com/grpc/grpc/blob/master/LICENSE</PackageLicenseUrl>
+    <NetStandardImplicitPackageVersion Condition=" '$(TargetFramework)' == 'netstandard1.5' ">1.6.0</NetStandardImplicitPackageVersion>
   </PropertyGroup>
+
   <ItemGroup>
-    <Reference Include="System" />
-    <Reference Include="System.Net" />
-    <Reference Include="System.Net.Http" />
-    <Reference Include="System.Net.Http.WebRequest" />
-    <Reference Include="Zlib.Portable">
-      <HintPath>..\packages\Zlib.Portable.Signed.1.11.0\lib\portable-net4+sl5+wp8+win8+wpa81+MonoTouch+MonoAndroid\Zlib.Portable.dll</HintPath>
-    </Reference>
-    <Reference Include="Google.Apis.Core">
-      <HintPath>..\packages\Google.Apis.Core.1.21.0\lib\net45\Google.Apis.Core.dll</HintPath>
-    </Reference>
-    <Reference Include="Google.Apis">
-      <HintPath>..\packages\Google.Apis.1.21.0\lib\net45\Google.Apis.dll</HintPath>
-    </Reference>
-    <Reference Include="Google.Apis.PlatformServices">
-      <HintPath>..\packages\Google.Apis.1.21.0\lib\net45\Google.Apis.PlatformServices.dll</HintPath>
-    </Reference>
-    <Reference Include="Google.Apis.Auth">
-      <HintPath>..\packages\Google.Apis.Auth.1.21.0\lib\net45\Google.Apis.Auth.dll</HintPath>
-    </Reference>
-    <Reference Include="Google.Apis.Auth.PlatformServices">
-      <HintPath>..\packages\Google.Apis.Auth.1.21.0\lib\net45\Google.Apis.Auth.PlatformServices.dll</HintPath>
-    </Reference>
-    <Reference Include="Newtonsoft.Json">
-      <HintPath>..\packages\Newtonsoft.Json.9.0.1\lib\net45\Newtonsoft.Json.dll</HintPath>
-    </Reference>
+    <Compile Include="..\Grpc.Core\Version.cs" />
   </ItemGroup>
+
   <ItemGroup>
-    <Compile Include="..\Grpc.Core\Version.cs">
-      <Link>Version.cs</Link>
-    </Compile>
-    <Compile Include="GoogleGrpcCredentials.cs" />
-    <Compile Include="Properties\AssemblyInfo.cs" />
-    <Compile Include="GoogleAuthInterceptors.cs" />
+    <ProjectReference Include="../Grpc.Core/Grpc.Core.csproj" />
   </ItemGroup>
-  <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
+
   <ItemGroup>
-    <ProjectReference Include="..\Grpc.Core\Grpc.Core.csproj">
-      <Project>{CCC4440E-49F7-4790-B0AF-FEABB0837AE7}</Project>
-      <Name>Grpc.Core</Name>
-    </ProjectReference>
+    <PackageReference Include="Google.Apis.Auth" Version="1.21.0" />
   </ItemGroup>
-  <ItemGroup>
-    <None Include="Grpc.Auth.project.json" />
-    <None Include="packages.config" />
+
+  <ItemGroup Condition=" '$(TargetFramework)' == 'net45' ">
+    <Reference Include="System" />
+    <Reference Include="Microsoft.CSharp" />
   </ItemGroup>
-</Project>
\ No newline at end of file
+
+</Project>
diff --git a/src/csharp/Grpc.Auth/Grpc.Auth.project.json b/src/csharp/Grpc.Auth/Grpc.Auth.project.json
deleted file mode 100644
index c2f5bcb1637badadff8959d672e04c942cb54d51..0000000000000000000000000000000000000000
--- a/src/csharp/Grpc.Auth/Grpc.Auth.project.json
+++ /dev/null
@@ -1,8 +0,0 @@
-{
-  "frameworks": {
-    "net45": { }
-  },
-  "runtimes": {
-    "win": { }
-  }
-}
diff --git a/src/csharp/Grpc.Auth/Grpc.Auth.xproj b/src/csharp/Grpc.Auth/Grpc.Auth.xproj
deleted file mode 100644
index dd3d94c574aab0ab6b5ca69bb7a82d889b75807c..0000000000000000000000000000000000000000
--- a/src/csharp/Grpc.Auth/Grpc.Auth.xproj
+++ /dev/null
@@ -1,18 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<Project ToolsVersion="14.0.25123" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
-  <PropertyGroup>
-    <VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">14.0.25123</VisualStudioVersion>
-    <VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
-  </PropertyGroup>
-  <Import Project="$(VSToolsPath)\DNX\Microsoft.DNX.Props" Condition="'$(VSToolsPath)' != ''" />
-  <PropertyGroup Label="Globals">
-    <ProjectGuid>c82631ed-06d1-4458-87bc-8257d12307a8</ProjectGuid>
-    <RootNamespace>Grpc.Auth</RootNamespace>
-    <BaseIntermediateOutputPath Condition="'$(BaseIntermediateOutputPath)'=='' ">..\Grpc.Core\artifacts\obj\$(MSBuildProjectName)</BaseIntermediateOutputPath>
-    <OutputPath Condition="'$(OutputPath)'=='' ">.\bin\</OutputPath>
-  </PropertyGroup>
-  <PropertyGroup>
-    <SchemaVersion>2.0</SchemaVersion>
-  </PropertyGroup>
-  <Import Project="$(VSToolsPath)\DNX\Microsoft.DNX.targets" Condition="'$(VSToolsPath)' != ''" />
-</Project>
\ No newline at end of file
diff --git a/src/csharp/Grpc.Auth/packages.config b/src/csharp/Grpc.Auth/packages.config
deleted file mode 100644
index aecc65e8499a49a27fece068532b828a062cbe9c..0000000000000000000000000000000000000000
--- a/src/csharp/Grpc.Auth/packages.config
+++ /dev/null
@@ -1,8 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<packages>
-  <package id="Google.Apis" version="1.21.0" targetFramework="net45" />
-  <package id="Google.Apis.Auth" version="1.21.0" targetFramework="net45" />
-  <package id="Google.Apis.Core" version="1.21.0" targetFramework="net45" />
-  <package id="Newtonsoft.Json" version="9.0.1" targetFramework="net45" />
-  <package id="Zlib.Portable.Signed" version="1.11.0" targetFramework="net45" />
-</packages>
\ No newline at end of file
diff --git a/src/csharp/Grpc.Core.Testing/Grpc.Core.Testing.csproj b/src/csharp/Grpc.Core.Testing/Grpc.Core.Testing.csproj
old mode 100644
new mode 100755
index 9b0b3abf107bc2ed18b5c279619a08deff67d289..f4dd5105fc77350ac4ed8156d0f701203482ea3a
--- a/src/csharp/Grpc.Core.Testing/Grpc.Core.Testing.csproj
+++ b/src/csharp/Grpc.Core.Testing/Grpc.Core.Testing.csproj
@@ -1,68 +1,36 @@
-<?xml version="1.0" encoding="utf-8"?>
-<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
-  <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
+<Project Sdk="Microsoft.NET.Sdk">
+
+  <Import Project="..\Grpc.Core\Version.csproj.include" />
+  <Import Project="..\Grpc.Core\Common.csproj.include" />
+
   <PropertyGroup>
-    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
-    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
-    <ProjectGuid>{3AB047CA-6CF9-435D-AA61-2D86C6FA2457}</ProjectGuid>
-    <OutputType>Library</OutputType>
-    <AppDesignerFolder>Properties</AppDesignerFolder>
-    <RootNamespace>Grpc.Core.Testing</RootNamespace>
+    <Copyright>Copyright 2017, Google Inc.</Copyright>
+    <AssemblyTitle>gRPC C# Core Testing</AssemblyTitle>
+    <VersionPrefix>$(GrpcCsharpVersion)</VersionPrefix>
+    <Authors>Google Inc.</Authors>
+    <TargetFrameworks>net45;netstandard1.5</TargetFrameworks>
+    <GenerateDocumentationFile>true</GenerateDocumentationFile>
     <AssemblyName>Grpc.Core.Testing</AssemblyName>
-    <TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
-    <FileAlignment>512</FileAlignment>
-    <DocumentationFile>bin\$(Configuration)\Grpc.Core.Testing.Xml</DocumentationFile>
-  </PropertyGroup>
-  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
-    <DebugSymbols>true</DebugSymbols>
-    <DebugType>full</DebugType>
-    <Optimize>false</Optimize>
-    <OutputPath>bin\Debug\</OutputPath>
-    <ErrorReport>prompt</ErrorReport>
-    <WarningLevel>4</WarningLevel>
-  </PropertyGroup>
-  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
-    <DebugType>pdbonly</DebugType>
-    <Optimize>true</Optimize>
-    <OutputPath>bin\Release\</OutputPath>
-    <ErrorReport>prompt</ErrorReport>
-    <WarningLevel>4</WarningLevel>
+    <PackageId>Grpc.Core.Testing</PackageId>
+    <PackageTags>gRPC test testing</PackageTags>
+    <PackageProjectUrl>https://github.com/grpc/grpc</PackageProjectUrl>
+    <PackageLicenseUrl>https://github.com/grpc/grpc/blob/master/LICENSE</PackageLicenseUrl>
+    <NetStandardImplicitPackageVersion Condition=" '$(TargetFramework)' == 'netstandard1.5' ">1.6.0</NetStandardImplicitPackageVersion>
   </PropertyGroup>
+
   <ItemGroup>
-    <Reference Include="System" />
-    <Reference Include="System.Core" />
-    <Reference Include="System.Xml.Linq" />
-    <Reference Include="System.Data.DataSetExtensions" />
-    <Reference Include="Microsoft.CSharp" />
-    <Reference Include="System.Data" />
-    <Reference Include="System.Xml" />
-    <Reference Include="System.Interactive.Async">
-      <HintPath>..\packages\System.Interactive.Async.3.1.1\lib\net45\System.Interactive.Async.dll</HintPath>
-    </Reference>
+    <Compile Include="..\Grpc.Core\Version.cs" />
   </ItemGroup>
+
   <ItemGroup>
-    <Compile Include="..\Grpc.Core\Version.cs">
-      <Link>Version.cs</Link>
-    </Compile>
-    <Compile Include="Properties\AssemblyInfo.cs" />
-    <Compile Include="TestCalls.cs" />
+    <ProjectReference Include="../Grpc.Core/Grpc.Core.csproj" />
   </ItemGroup>
-  <ItemGroup>
-    <None Include="Grpc.Core.Testing.project.json" />
-    <None Include="packages.config" />
-  </ItemGroup>
-  <ItemGroup>
-    <ProjectReference Include="..\Grpc.Core\Grpc.Core.csproj">
-      <Project>{CCC4440E-49F7-4790-B0AF-FEABB0837AE7}</Project>
-      <Name>Grpc.Core</Name>
-    </ProjectReference>
+
+  <ItemGroup Condition=" '$(TargetFramework)' == 'net45' ">
+    <Reference Include="System.Runtime" />
+    <Reference Include="System.IO" />
+    <Reference Include="System" />
+    <Reference Include="Microsoft.CSharp" />
   </ItemGroup>
-  <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
-  <!-- To modify your build process, add your task inside one of the targets below and uncomment it. 
-       Other similar extension points exist, see Microsoft.Common.targets.
-  <Target Name="BeforeBuild">
-  </Target>
-  <Target Name="AfterBuild">
-  </Target>
-  -->
-</Project>
\ No newline at end of file
+
+</Project>
diff --git a/src/csharp/Grpc.Core.Testing/Grpc.Core.Testing.project.json b/src/csharp/Grpc.Core.Testing/Grpc.Core.Testing.project.json
deleted file mode 100644
index c2f5bcb1637badadff8959d672e04c942cb54d51..0000000000000000000000000000000000000000
--- a/src/csharp/Grpc.Core.Testing/Grpc.Core.Testing.project.json
+++ /dev/null
@@ -1,8 +0,0 @@
-{
-  "frameworks": {
-    "net45": { }
-  },
-  "runtimes": {
-    "win": { }
-  }
-}
diff --git a/src/csharp/Grpc.Core.Testing/Grpc.Core.Testing.xproj b/src/csharp/Grpc.Core.Testing/Grpc.Core.Testing.xproj
deleted file mode 100644
index c972387003350e5cb8df4a3217f44eaea5cd4ccd..0000000000000000000000000000000000000000
--- a/src/csharp/Grpc.Core.Testing/Grpc.Core.Testing.xproj
+++ /dev/null
@@ -1,18 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<Project ToolsVersion="14.0.25123" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
-  <PropertyGroup>
-    <VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">14.0.25123</VisualStudioVersion>
-    <VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
-  </PropertyGroup>
-  <Import Project="$(VSToolsPath)\DNX\Microsoft.DNX.Props" Condition="'$(VSToolsPath)' != ''" />
-  <PropertyGroup Label="Globals">
-    <ProjectGuid>2b372155-80ba-4cf9-82d6-4b938e8ec3a0</ProjectGuid>
-    <RootNamespace>Grpc.Core.Testing</RootNamespace>
-    <BaseIntermediateOutputPath Condition="'$(BaseIntermediateOutputPath)'=='' ">..\artifacts\obj\$(MSBuildProjectName)</BaseIntermediateOutputPath>
-    <OutputPath Condition="'$(OutputPath)'=='' ">.\bin\</OutputPath>
-  </PropertyGroup>
-  <PropertyGroup>
-    <SchemaVersion>2.0</SchemaVersion>
-  </PropertyGroup>
-  <Import Project="$(VSToolsPath)\DNX\Microsoft.DNX.targets" Condition="'$(VSToolsPath)' != ''" />
-</Project>
\ No newline at end of file
diff --git a/src/csharp/Grpc.Core.Testing/packages.config b/src/csharp/Grpc.Core.Testing/packages.config
deleted file mode 100644
index 53cfad52f0bca1b3d030ddd2f3266170dcbe6801..0000000000000000000000000000000000000000
--- a/src/csharp/Grpc.Core.Testing/packages.config
+++ /dev/null
@@ -1,4 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<packages>
-  <package id="System.Interactive.Async" version="3.1.1" targetFramework="net45" />
-</packages>
\ No newline at end of file
diff --git a/src/csharp/Grpc.Core.Tests/Grpc.Core.Tests.csproj b/src/csharp/Grpc.Core.Tests/Grpc.Core.Tests.csproj
old mode 100644
new mode 100755
index a1a2e4eebd1aa9451f96a1da6b0f8a184497153e..9be77c8875dba18c15ead3465295d1f91d1fb210
--- a/src/csharp/Grpc.Core.Tests/Grpc.Core.Tests.csproj
+++ b/src/csharp/Grpc.Core.Tests/Grpc.Core.Tests.csproj
@@ -1,103 +1,37 @@
-<?xml version="1.0" encoding="utf-8"?>
-<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+<Project Sdk="Microsoft.NET.Sdk">
+
+  <Import Project="..\Grpc.Core\Version.csproj.include" />
+  <Import Project="..\Grpc.Core\Common.csproj.include" />
+
   <PropertyGroup>
-    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
-    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
-    <ProjectGuid>{86EC5CB4-4EA2-40A2-8057-86542A0353BB}</ProjectGuid>
-    <OutputType>Exe</OutputType>
-    <RootNamespace>Grpc.Core.Tests</RootNamespace>
+    <TargetFrameworks>net45;netcoreapp1.0</TargetFrameworks>
     <AssemblyName>Grpc.Core.Tests</AssemblyName>
-    <TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
-  </PropertyGroup>
-  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
-    <DebugSymbols>true</DebugSymbols>
-    <DebugType>full</DebugType>
-    <Optimize>false</Optimize>
-    <OutputPath>bin\Debug</OutputPath>
-    <DefineConstants>DEBUG;</DefineConstants>
-    <ErrorReport>prompt</ErrorReport>
-    <WarningLevel>4</WarningLevel>
-  </PropertyGroup>
-  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
-    <DebugType>pdbonly</DebugType>
-    <Optimize>true</Optimize>
-    <OutputPath>bin\Release</OutputPath>
-    <ErrorReport>prompt</ErrorReport>
-    <WarningLevel>4</WarningLevel>
+    <OutputType>Exe</OutputType>
+    <PackageId>Grpc.Core.Tests</PackageId>
+    <PackageTargetFallback Condition=" '$(TargetFramework)' == 'netcoreapp1.0' ">$(PackageTargetFallback);portable-net45</PackageTargetFallback>
+    <RuntimeFrameworkVersion Condition=" '$(TargetFramework)' == 'netcoreapp1.0' ">1.0.4</RuntimeFrameworkVersion>
   </PropertyGroup>
+
   <ItemGroup>
-    <Reference Include="System" />
-    <Reference Include="System.Interactive.Async">
-      <HintPath>..\packages\System.Interactive.Async.3.1.1\lib\net45\System.Interactive.Async.dll</HintPath>
-    </Reference>
-    <Reference Include="Newtonsoft.Json">
-      <HintPath>..\packages\Newtonsoft.Json.9.0.1\lib\net45\Newtonsoft.Json.dll</HintPath>
-    </Reference>
-    <Reference Include="nunit.framework">
-      <HintPath>..\packages\NUnit.3.6.0\lib\net45\nunit.framework.dll</HintPath>
-    </Reference>
-    <Reference Include="nunitlite">
-      <HintPath>..\packages\NUnitLite.3.6.0\lib\net45\nunitlite.dll</HintPath>
-    </Reference>
+    <ProjectReference Include="../Grpc.Core/Grpc.Core.csproj" />
   </ItemGroup>
+
   <ItemGroup>
-    <Compile Include="..\Grpc.Core\Version.cs">
-      <Link>Version.cs</Link>
-    </Compile>
-    <Compile Include="CallCredentialsTest.cs" />
-    <Compile Include="CallOptionsTest.cs" />
-    <Compile Include="UserAgentStringTest.cs" />
-    <Compile Include="FakeCredentials.cs" />
-    <Compile Include="MarshallingErrorsTest.cs" />
-    <Compile Include="ChannelCredentialsTest.cs" />
-    <Compile Include="ShutdownTest.cs" />
-    <Compile Include="Internal\AsyncCallTest.cs" />
-    <Compile Include="Properties\AssemblyInfo.cs" />
-    <Compile Include="ClientServerTest.cs" />
-    <Compile Include="ServerTest.cs" />
-    <Compile Include="GrpcEnvironmentTest.cs" />
-    <Compile Include="PInvokeTest.cs" />
-    <Compile Include="Internal\MetadataArraySafeHandleTest.cs" />
-    <Compile Include="Internal\CompletionQueueSafeHandleTest.cs" />
-    <Compile Include="Internal\CompletionQueueEventTest.cs" />
-    <Compile Include="Internal\ChannelArgsSafeHandleTest.cs" />
-    <Compile Include="ChannelOptionsTest.cs" />
-    <Compile Include="Internal\TimespecTest.cs" />
-    <Compile Include="TimeoutsTest.cs" />
-    <Compile Include="ChannelTest.cs" />
-    <Compile Include="MockServiceHelper.cs" />
-    <Compile Include="ResponseHeadersTest.cs" />
-    <Compile Include="CompressionTest.cs" />
-    <Compile Include="ContextPropagationTest.cs" />
-    <Compile Include="MetadataTest.cs" />
-    <Compile Include="PerformanceTest.cs" />
-    <Compile Include="SanityTest.cs" />
-    <Compile Include="HalfcloseTest.cs" />
-    <Compile Include="NUnitMain.cs" />
-    <Compile Include="Internal\FakeNativeCall.cs" />
-    <Compile Include="Internal\AsyncCallServerTest.cs" />
-    <Compile Include="ShutdownHookServerTest.cs" />
-    <Compile Include="ShutdownHookPendingCallTest.cs" />
-    <Compile Include="ShutdownHookClientTest.cs" />
-    <Compile Include="AppDomainUnloadTest.cs" />
-    <Compile Include="AuthContextTest.cs" />
-    <Compile Include="AuthPropertyTest.cs" />
+    <PackageReference Include="Newtonsoft.Json" Version="9.0.1" />
+    <PackageReference Include="NUnit" Version="3.6.0" />
+    <PackageReference Include="NUnitLite" Version="3.6.0" />
+    <PackageReference Include="NUnit.ConsoleRunner" Version="3.6.0" />
+    <PackageReference Include="OpenCover" Version="4.6.519" />
+    <PackageReference Include="ReportGenerator" Version="2.4.4.0" />
   </ItemGroup>
-  <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
-  <ItemGroup>
-    <ProjectReference Include="..\Grpc.Core\Grpc.Core.csproj">
-      <Project>{CCC4440E-49F7-4790-B0AF-FEABB0837AE7}</Project>
-      <Name>Grpc.Core</Name>
-    </ProjectReference>
-  </ItemGroup>
-  <ItemGroup>
-    <None Include="Grpc.Core.Tests.project.json" />
-    <None Include="packages.config">
-      <SubType>Designer</SubType>
-    </None>
+
+  <ItemGroup Condition=" '$(TargetFramework)' == 'net45' ">
+    <Reference Include="System" />
+    <Reference Include="Microsoft.CSharp" />
   </ItemGroup>
+
   <ItemGroup>
-    <Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" />
+    <Compile Include="..\Grpc.Core\Version.cs" />
   </ItemGroup>
-  <ItemGroup />
+
 </Project>
diff --git a/src/csharp/Grpc.Core.Tests/Grpc.Core.Tests.project.json b/src/csharp/Grpc.Core.Tests/Grpc.Core.Tests.project.json
deleted file mode 100644
index c2f5bcb1637badadff8959d672e04c942cb54d51..0000000000000000000000000000000000000000
--- a/src/csharp/Grpc.Core.Tests/Grpc.Core.Tests.project.json
+++ /dev/null
@@ -1,8 +0,0 @@
-{
-  "frameworks": {
-    "net45": { }
-  },
-  "runtimes": {
-    "win": { }
-  }
-}
diff --git a/src/csharp/Grpc.Core.Tests/Grpc.Core.Tests.xproj b/src/csharp/Grpc.Core.Tests/Grpc.Core.Tests.xproj
deleted file mode 100644
index 05823291542728459acbb90d04b099c42f12a295..0000000000000000000000000000000000000000
--- a/src/csharp/Grpc.Core.Tests/Grpc.Core.Tests.xproj
+++ /dev/null
@@ -1,18 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<Project ToolsVersion="14.0.25123" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
-  <PropertyGroup>
-    <VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">14.0.25123</VisualStudioVersion>
-    <VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
-  </PropertyGroup>
-  <Import Project="$(VSToolsPath)\DNX\Microsoft.DNX.Props" Condition="'$(VSToolsPath)' != ''" />
-  <PropertyGroup Label="Globals">
-    <ProjectGuid>759e23b2-fc04-4695-902d-b073cded3599</ProjectGuid>
-    <RootNamespace>Grpc.Core.Tests</RootNamespace>
-    <BaseIntermediateOutputPath Condition="'$(BaseIntermediateOutputPath)'=='' ">..\artifacts\obj\$(MSBuildProjectName)</BaseIntermediateOutputPath>
-    <OutputPath Condition="'$(OutputPath)'=='' ">.\bin\</OutputPath>
-  </PropertyGroup>
-  <PropertyGroup>
-    <SchemaVersion>2.0</SchemaVersion>
-  </PropertyGroup>
-  <Import Project="$(VSToolsPath)\DNX\Microsoft.DNX.targets" Condition="'$(VSToolsPath)' != ''" />
-</Project>
\ No newline at end of file
diff --git a/src/csharp/Grpc.Core.Tests/SanityTest.cs b/src/csharp/Grpc.Core.Tests/SanityTest.cs
index 1c28277df55eb1a39f62f7008cb354fee56bb468..e02f2c9e5464379084d085212c2a90daf6a8f604 100644
--- a/src/csharp/Grpc.Core.Tests/SanityTest.cs
+++ b/src/csharp/Grpc.Core.Tests/SanityTest.cs
@@ -101,7 +101,7 @@ namespace Grpc.Core.Tests
         private string ReadTestsJson()
         {
             var assemblyDir = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
-            var testsJsonFile = Path.Combine(assemblyDir, "..", "..", "..", "tests.json");
+            var testsJsonFile = Path.Combine(assemblyDir, "..", "..", "..", "..", "tests.json");
             return File.ReadAllText(testsJsonFile);
         }
 
diff --git a/src/csharp/Grpc.Core.Tests/packages.config b/src/csharp/Grpc.Core.Tests/packages.config
deleted file mode 100644
index 994a27876293bb1e1c41f891ce5d6a8256952fa4..0000000000000000000000000000000000000000
--- a/src/csharp/Grpc.Core.Tests/packages.config
+++ /dev/null
@@ -1,9 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<packages>
-  <package id="Newtonsoft.Json" version="9.0.1" targetFramework="net45" />
-  <package id="NUnit" version="3.6.0" targetFramework="net45" />
-  <package id="NUnitLite" version="3.6.0" targetFramework="net45" />
-  <package id="OpenCover" version="4.6.519" />
-  <package id="ReportGenerator" version="2.4.4.0" />
-  <package id="System.Interactive.Async" version="3.1.1" targetFramework="net45" />
-</packages>
\ No newline at end of file
diff --git a/src/csharp/Grpc.Core.Tests/project.json b/src/csharp/Grpc.Core.Tests/project.json
deleted file mode 100644
index 14e5ed51adb258199a8a6d1d4bec1c37b891ce8d..0000000000000000000000000000000000000000
--- a/src/csharp/Grpc.Core.Tests/project.json
+++ /dev/null
@@ -1,69 +0,0 @@
-{
-  "buildOptions": {
-    "emitEntryPoint": true
-  },
-  "configurations": {
-    "Debug": {
-      "buildOptions": {
-        "define": [ "SIGNED" ],
-        "keyFile": "../keys/Grpc.snk",
-        "xmlDoc": true,
-        "compile": {
-          "includeFiles": [ "../Grpc.Core/Version.cs" ]
-        },
-        "copyToOutput": {
-          "mappings": {
-            "grpc_csharp_ext.x64.dll": "../../../cmake/build/x64/Debug/grpc_csharp_ext.dll",
-            "grpc_csharp_ext.x86.dll": "../../../cmake/build/Win32/Debug/grpc_csharp_ext.dll",
-            "libgrpc_csharp_ext.x64.so": "../../../libs/dbg/libgrpc_csharp_ext.so",
-            "libgrpc_csharp_ext.x64.dylib": "../../../libs/dbg/libgrpc_csharp_ext.dylib"
-          }
-        }
-      }
-    },
-    "Release": {
-      "buildOptions": {
-        "define": [ "SIGNED" ],
-        "keyFile": "../keys/Grpc.snk",
-        "xmlDoc": true,
-        "compile": {
-          "includeFiles": [ "../Grpc.Core/Version.cs" ]
-        },
-        "copyToOutput": {
-          "mappings": {
-            "grpc_csharp_ext.x64.dll": "../../../cmake/build/x64/Release/grpc_csharp_ext.dll",
-            "grpc_csharp_ext.x86.dll": "../../../cmake/build/Win32/Release/grpc_csharp_ext.dll",
-            "libgrpc_csharp_ext.x64.so": "../../../libs/opt/libgrpc_csharp_ext.so",
-            "libgrpc_csharp_ext.x64.dylib": "../../../libs/opt/libgrpc_csharp_ext.dylib"
-          }
-        }
-      }
-    }
-  },
-
-  "dependencies": {
-    "Grpc.Core": {
-      "target": "project"
-    },
-    "Newtonsoft.Json": "9.0.1",
-    "NUnit": "3.6.0",
-    "NUnitLite": "3.6.0",
-    "NUnit.ConsoleRunner": "3.6.0",
-    "OpenCover": "4.6.519",
-    "ReportGenerator": "2.4.4.0"
-  },
-  "frameworks": {
-    "net45": { },
-    "netcoreapp1.0": {
-      "imports": [
-        "portable-net45"
-      ],
-      "dependencies": {
-        "Microsoft.NETCore.App": {
-          "type": "platform",
-          "version": "1.0.0"
-        }
-      }
-    }
-  },
-}
diff --git a/src/csharp/Grpc.Core/Common.csproj.include b/src/csharp/Grpc.Core/Common.csproj.include
new file mode 100755
index 0000000000000000000000000000000000000000..2cb990ba49ea8f1c07c623714e8f8b27b58c62d3
--- /dev/null
+++ b/src/csharp/Grpc.Core/Common.csproj.include
@@ -0,0 +1,32 @@
+<!-- Common definitions shared by all .csproj files -->
+<Project>
+  <PropertyGroup>
+    <GenerateAssemblyVersionAttribute>false</GenerateAssemblyVersionAttribute>
+    <GenerateAssemblyFileVersionAttribute>false</GenerateAssemblyFileVersionAttribute>
+    <GenerateAssemblyInformationalVersionAttribute>false</GenerateAssemblyInformationalVersionAttribute>
+    <GenerateAssemblyTitleAttribute>false</GenerateAssemblyTitleAttribute>
+    <GenerateAssemblyDescriptionAttribute>false</GenerateAssemblyDescriptionAttribute>
+    <GenerateAssemblyConfigurationAttribute>false</GenerateAssemblyConfigurationAttribute>
+    <GenerateAssemblyCompanyAttribute>false</GenerateAssemblyCompanyAttribute>
+    <GenerateAssemblyProductAttribute>false</GenerateAssemblyProductAttribute>
+    <GenerateAssemblyCopyrightAttribute>false</GenerateAssemblyCopyrightAttribute>
+  </PropertyGroup>
+
+  <PropertyGroup>
+    <GenerateDocumentationFile>true</GenerateDocumentationFile>
+  </PropertyGroup>
+
+  <PropertyGroup>
+    <DefineConstants>$(DefineConstants);SIGNED</DefineConstants>
+    <AssemblyOriginatorKeyFile>../keys/Grpc.snk</AssemblyOriginatorKeyFile>
+    <SignAssembly>true</SignAssembly>
+    <PublicSign Condition=" '$(OS)' != 'Windows_NT' ">true</PublicSign>
+  </PropertyGroup>
+
+  <PropertyGroup Condition="'$(OS)' != 'Windows_NT'">
+    <!-- Workaround for https://github.com/dotnet/sdk/issues/335 -->
+    <FrameworkPathOverride Condition="Exists('/usr/lib/mono/4.5-api')">/usr/lib/mono/4.5-api</FrameworkPathOverride>
+    <FrameworkPathOverride Condition="Exists('/usr/local/lib/mono/4.5-api')">/usr/local/lib/mono/4.5-api</FrameworkPathOverride>
+    <FrameworkPathOverride Condition="Exists('/Library/Frameworks/Mono.framework/Versions/Current/lib/mono/4.5-api')">/Library/Frameworks/Mono.framework/Versions/Current/lib/mono/4.5-api</FrameworkPathOverride>
+  </PropertyGroup>
+</Project>
diff --git a/src/csharp/Grpc.Core/Grpc.Core.csproj b/src/csharp/Grpc.Core/Grpc.Core.csproj
old mode 100644
new mode 100755
index d6d8dfac22409ad1ac6975b84e10e3ff8d0b3296..7e0f3f053d073a464734f3bf4198afec331f51b8
--- a/src/csharp/Grpc.Core/Grpc.Core.csproj
+++ b/src/csharp/Grpc.Core/Grpc.Core.csproj
@@ -1,151 +1,68 @@
-<?xml version="1.0" encoding="utf-8"?>
-<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+<Project Sdk="Microsoft.NET.Sdk">
+
+  <Import Project="Version.csproj.include" />
+  <Import Project="Common.csproj.include" />
+
   <PropertyGroup>
-    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
-    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
-    <ProjectGuid>{CCC4440E-49F7-4790-B0AF-FEABB0837AE7}</ProjectGuid>
-    <OutputType>Library</OutputType>
-    <RootNamespace>Grpc.Core</RootNamespace>
+    <Copyright>Copyright 2015, Google Inc.</Copyright>
+    <AssemblyTitle>gRPC C# Core</AssemblyTitle>
+    <VersionPrefix>$(GrpcCsharpVersion)</VersionPrefix>
+    <Authors>Google Inc.</Authors>
+    <TargetFrameworks>net45;netstandard1.5</TargetFrameworks>
     <AssemblyName>Grpc.Core</AssemblyName>
-    <TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
-    <NuGetPackageImportStamp>c0512805</NuGetPackageImportStamp>
-    <DocumentationFile>bin\$(Configuration)\Grpc.Core.Xml</DocumentationFile>
-  </PropertyGroup>
-  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
-    <DebugSymbols>true</DebugSymbols>
-    <DebugType>full</DebugType>
-    <Optimize>false</Optimize>
-    <OutputPath>bin\Debug</OutputPath>
-    <DefineConstants>DEBUG;</DefineConstants>
-    <ErrorReport>prompt</ErrorReport>
-    <WarningLevel>4</WarningLevel>
-  </PropertyGroup>
-  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
-    <DebugType>pdbonly</DebugType>
-    <Optimize>true</Optimize>
-    <OutputPath>bin\Release</OutputPath>
-    <ErrorReport>prompt</ErrorReport>
-    <WarningLevel>4</WarningLevel>
+    <PackageId>Grpc.Core</PackageId>
+    <PackageTags>gRPC RPC Protocol HTTP/2</PackageTags>
+    <PackageProjectUrl>https://github.com/grpc/grpc</PackageProjectUrl>
+    <PackageLicenseUrl>https://github.com/grpc/grpc/blob/master/LICENSE</PackageLicenseUrl>
+    <NetStandardImplicitPackageVersion Condition=" '$(TargetFramework)' == 'netstandard1.5' ">1.6.0</NetStandardImplicitPackageVersion>
   </PropertyGroup>
+
   <ItemGroup>
-    <Reference Include="System" />
-    <Reference Include="System.Interactive.Async">
-      <HintPath>..\packages\System.Interactive.Async.3.1.1\lib\net45\System.Interactive.Async.dll</HintPath>
-    </Reference>
+    <EmbeddedResource Include="..\..\..\etc\roots.pem" />
+    <Content Include="..\nativelibs\macosx_x64\libgrpc_csharp_ext.dylib">
+      <PackagePath>runtimes/osx/native/libgrpc_csharp_ext.x64.dylib</PackagePath>
+      <Pack>true</Pack>
+    </Content>
+    <Content Include="..\nativelibs\macosx_x86\libgrpc_csharp_ext.dylib">
+      <PackagePath>runtimes/osx/native/libgrpc_csharp_ext.x86.dylib</PackagePath>
+      <Pack>true</Pack>
+    </Content>
+    <Content Include="..\nativelibs\linux_x64\libgrpc_csharp_ext.so">
+      <PackagePath>runtimes/linux/native/libgrpc_csharp_ext.x64.so</PackagePath>
+      <Pack>true</Pack>
+    </Content>
+    <Content Include="..\nativelibs\linux_x86\libgrpc_csharp_ext.so">
+      <PackagePath>runtimes/linux/native/libgrpc_csharp_ext.x86.so</PackagePath>
+      <Pack>true</Pack>
+    </Content>
+    <Content Include="..\nativelibs\windows_x64\grpc_csharp_ext.dll">
+      <PackagePath>runtimes/win/native/grpc_csharp_ext.x64.dll</PackagePath>
+      <Pack>true</Pack>
+    </Content>
+    <Content Include="..\nativelibs\windows_x86\grpc_csharp_ext.dll">
+      <PackagePath>runtimes/win/native/grpc_csharp_ext.x86.dll</PackagePath>
+      <Pack>true</Pack>
+    </Content>
+    <Content Include="Grpc.Core.targets">
+      <PackagePath>build/net45/</PackagePath>
+      <Pack>true</Pack>
+    </Content>
   </ItemGroup>
+
   <ItemGroup>
-    <Compile Include="AsyncDuplexStreamingCall.cs" />
-    <Compile Include="AsyncServerStreamingCall.cs" />
-    <Compile Include="AsyncAuthInterceptor.cs" />
-    <Compile Include="CallCredentials.cs" />
-    <Compile Include="IClientStreamWriter.cs" />
-    <Compile Include="Internal\NativeMethods.cs" />
-    <Compile Include="Internal\PlatformApis.cs" />
-    <Compile Include="Internal\NativeExtension.cs" />
-    <Compile Include="Internal\UnmanagedLibrary.cs" />
-    <Compile Include="Internal\NativeMetadataCredentialsPlugin.cs" />
-    <Compile Include="Internal\INativeCall.cs" />
-    <Compile Include="IServerStreamWriter.cs" />
-    <Compile Include="IAsyncStreamWriter.cs" />
-    <Compile Include="IAsyncStreamReader.cs" />
-    <Compile Include="Logging\TextWriterLogger.cs" />
-    <Compile Include="Logging\NullLogger.cs" />
-    <Compile Include="ServerPort.cs" />
-    <Compile Include="Version.cs" />
-    <Compile Include="Properties\AssemblyInfo.cs" />
-    <Compile Include="RpcException.cs" />
-    <Compile Include="Calls.cs" />
-    <Compile Include="AsyncClientStreamingCall.cs" />
-    <Compile Include="GrpcEnvironment.cs" />
-    <Compile Include="Status.cs" />
-    <Compile Include="StatusCode.cs" />
-    <Compile Include="Server.cs" />
-    <Compile Include="Channel.cs" />
-    <Compile Include="Internal\CallSafeHandle.cs" />
-    <Compile Include="Internal\ChannelSafeHandle.cs" />
-    <Compile Include="Internal\CompletionQueueSafeHandle.cs" />
-    <Compile Include="Internal\SafeHandleZeroIsInvalid.cs" />
-    <Compile Include="Internal\Timespec.cs" />
-    <Compile Include="Internal\GrpcThreadPool.cs" />
-    <Compile Include="Internal\ServerSafeHandle.cs" />
-    <Compile Include="Method.cs" />
-    <Compile Include="Internal\ServerCallHandler.cs" />
-    <Compile Include="Marshaller.cs" />
-    <Compile Include="ServerServiceDefinition.cs" />
-    <Compile Include="Utils\AsyncStreamExtensions.cs" />
-    <Compile Include="Utils\BenchmarkUtil.cs" />
-    <Compile Include="ChannelCredentials.cs" />
-    <Compile Include="Internal\ChannelArgsSafeHandle.cs" />
-    <Compile Include="Internal\AsyncCallBase.cs" />
-    <Compile Include="Internal\AsyncCallServer.cs" />
-    <Compile Include="Internal\AsyncCall.cs" />
-    <Compile Include="Internal\ServerCredentialsSafeHandle.cs" />
-    <Compile Include="ServerCredentials.cs" />
-    <Compile Include="Metadata.cs" />
-    <Compile Include="Internal\MetadataArraySafeHandle.cs" />
-    <Compile Include="ClientBase.cs" />
-    <Compile Include="Internal\ServerCalls.cs" />
-    <Compile Include="ServerMethods.cs" />
-    <Compile Include="Internal\ClientRequestStream.cs" />
-    <Compile Include="Internal\ClientResponseStream.cs" />
-    <Compile Include="Internal\ServerRequestStream.cs" />
-    <Compile Include="Internal\ServerResponseStream.cs" />
-    <Compile Include="Internal\AtomicCounter.cs" />
-    <Compile Include="Internal\DebugStats.cs" />
-    <Compile Include="ServerCallContext.cs" />
-    <Compile Include="Internal\CompletionQueueEvent.cs" />
-    <Compile Include="Internal\CompletionRegistry.cs" />
-    <Compile Include="Internal\BatchContextSafeHandle.cs" />
-    <Compile Include="ChannelOptions.cs" />
-    <Compile Include="AsyncUnaryCall.cs" />
-    <Compile Include="VersionInfo.cs" />
-    <Compile Include="Internal\CStringSafeHandle.cs" />
-    <Compile Include="KeyCertificatePair.cs" />
-    <Compile Include="Logging\ILogger.cs" />
-    <Compile Include="Logging\ConsoleLogger.cs" />
-    <Compile Include="Internal\NativeLogRedirector.cs" />
-    <Compile Include="ChannelState.cs" />
-    <Compile Include="CallInvocationDetails.cs" />
-    <Compile Include="CallOptions.cs" />
-    <Compile Include="CompressionLevel.cs" />
-    <Compile Include="WriteOptions.cs" />
-    <Compile Include="ContextPropagationToken.cs" />
-    <Compile Include="Internal\CallCredentialsSafeHandle.cs" />
-    <Compile Include="Internal\ChannelCredentialsSafeHandle.cs" />
-    <Compile Include="Profiling\ProfilerEntry.cs" />
-    <Compile Include="Profiling\ProfilerScope.cs" />
-    <Compile Include="Profiling\IProfiler.cs" />
-    <Compile Include="Profiling\Profilers.cs" />
-    <Compile Include="Internal\DefaultSslRootsOverride.cs" />
-    <Compile Include="Utils\GrpcPreconditions.cs" />
-    <Compile Include="CallInvoker.cs" />
-    <Compile Include="DefaultCallInvoker.cs" />
-    <Compile Include="Internal\UnimplementedCallInvoker.cs" />
-    <Compile Include="Internal\InterceptingCallInvoker.cs" />
-    <Compile Include="Internal\ServerRpcNew.cs" />
-    <Compile Include="Internal\ClientSideStatus.cs" />
-    <Compile Include="Internal\ClockType.cs" />
-    <Compile Include="Internal\CallError.cs" />
-    <Compile Include="Logging\LogLevel.cs" />
-    <Compile Include="Logging\LogLevelFilterLogger.cs" />
-    <Compile Include="Internal\RequestCallContextSafeHandle.cs" />
-    <Compile Include="Utils\TaskUtils.cs" />
-    <Compile Include="Internal\CallFlags.cs" />
-    <Compile Include="AuthContext.cs" />
-    <Compile Include="Internal\AuthContextSafeHandle.cs" />
-    <Compile Include="Internal\MarshalUtils.cs" />
-    <Compile Include="AuthProperty.cs" />
+    <PackageReference Include="System.Interactive.Async" Version="3.1.1" />
   </ItemGroup>
-  <ItemGroup>
-    <None Include="Grpc.Core.project.json" />
-    <None Include="packages.config" />
+
+  <ItemGroup Condition=" '$(TargetFramework)' == 'net45' ">
+    <Reference Include="System" />
+    <Reference Include="Microsoft.CSharp" />
   </ItemGroup>
-  <Import Project="NativeDeps.targets" />
-  <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
-  <ItemGroup />
-  <ItemGroup>
-    <EmbeddedResource Include="..\..\..\etc\roots.pem">
-      <Link>roots.pem</Link>
-    </EmbeddedResource>
+
+  <ItemGroup Condition=" '$(TargetFramework)' == 'netstandard1.5' ">
+    <PackageReference Include="System.Runtime.Loader" Version="4.0.0" />
+    <PackageReference Include="System.Threading.Thread" Version="4.0.0" />
   </ItemGroup>
-</Project>
\ No newline at end of file
+
+  <Import Project="NativeDeps.csproj.include" />
+
+</Project>
diff --git a/src/csharp/Grpc.Core/Grpc.Core.project.json b/src/csharp/Grpc.Core/Grpc.Core.project.json
deleted file mode 100644
index c2f5bcb1637badadff8959d672e04c942cb54d51..0000000000000000000000000000000000000000
--- a/src/csharp/Grpc.Core/Grpc.Core.project.json
+++ /dev/null
@@ -1,8 +0,0 @@
-{
-  "frameworks": {
-    "net45": { }
-  },
-  "runtimes": {
-    "win": { }
-  }
-}
diff --git a/src/csharp/Grpc.Core/Grpc.Core.xproj b/src/csharp/Grpc.Core/Grpc.Core.xproj
deleted file mode 100644
index 137236ffdb61daa99a602132898d869bb2c35f14..0000000000000000000000000000000000000000
--- a/src/csharp/Grpc.Core/Grpc.Core.xproj
+++ /dev/null
@@ -1,18 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
-  <PropertyGroup>
-    <VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">14.0</VisualStudioVersion>
-    <VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
-  </PropertyGroup>
-  <Import Project="$(VSToolsPath)\DNX\Microsoft.DNX.Props" Condition="'$(VSToolsPath)' != ''" />
-  <PropertyGroup Label="Globals">
-    <ProjectGuid>dc9908b6-f291-4fc8-a46d-2ea2551790ec</ProjectGuid>
-    <RootNamespace>Grpc.Core</RootNamespace>
-    <BaseIntermediateOutputPath Condition="'$(BaseIntermediateOutputPath)'=='' ">..\artifacts\obj\$(MSBuildProjectName)</BaseIntermediateOutputPath>
-    <OutputPath Condition="'$(OutputPath)'=='' ">.\bin\</OutputPath>
-  </PropertyGroup>
-  <PropertyGroup>
-    <SchemaVersion>2.0</SchemaVersion>
-  </PropertyGroup>
-  <Import Project="$(VSToolsPath)\DNX\Microsoft.DNX.targets" Condition="'$(VSToolsPath)' != ''" />
-</Project>
\ No newline at end of file
diff --git a/src/csharp/Grpc.Core/Internal/CompletionRegistry.cs b/src/csharp/Grpc.Core/Internal/CompletionRegistry.cs
index 7e2f0e9c6c9ed4803309e76e1a2cdc459d9ae892..a4aa8d3ffe42b37d6ca6234e2480be18f783cb71 100644
--- a/src/csharp/Grpc.Core/Internal/CompletionRegistry.cs
+++ b/src/csharp/Grpc.Core/Internal/CompletionRegistry.cs
@@ -51,7 +51,7 @@ namespace Grpc.Core.Internal
         static readonly ILogger Logger = GrpcEnvironment.Logger.ForType<CompletionRegistry>();
 
         readonly GrpcEnvironment environment;
-        readonly ConcurrentDictionary<IntPtr, OpCompletionDelegate> dict = new ConcurrentDictionary<IntPtr, OpCompletionDelegate>();
+        readonly ConcurrentDictionary<IntPtr, OpCompletionDelegate> dict = new ConcurrentDictionary<IntPtr, OpCompletionDelegate>(new IntPtrComparer());
 
         public CompletionRegistry(GrpcEnvironment environment)
         {
@@ -121,5 +121,21 @@ namespace Grpc.Core.Internal
                 }
             }
         }
+
+        /// <summary>
+        /// IntPtr doesn't implement <c>IEquatable{IntPtr}</c> so we need to use custom comparer to avoid boxing.
+        /// </summary>
+        private class IntPtrComparer : IEqualityComparer<IntPtr>
+        {
+            public bool Equals(IntPtr x, IntPtr y)
+            {
+                return x == y;
+            }
+
+            public int GetHashCode(IntPtr obj)
+            {
+                return obj.GetHashCode();
+            }
+        }
     }
 }
diff --git a/src/csharp/Grpc.Core/NativeDeps.Linux.targets b/src/csharp/Grpc.Core/NativeDeps.Linux.csproj.include
similarity index 63%
rename from src/csharp/Grpc.Core/NativeDeps.Linux.targets
rename to src/csharp/Grpc.Core/NativeDeps.Linux.csproj.include
index e0c9132b1d5fe4db01aa01c8038ff5b5e5d0d7e8..e3bbeb071e758cefd9d71e4e213a7aa0ce404c26 100644
--- a/src/csharp/Grpc.Core/NativeDeps.Linux.targets
+++ b/src/csharp/Grpc.Core/NativeDeps.Linux.csproj.include
@@ -1,9 +1,9 @@
-<?xml version="1.0" encoding="utf-8"?>
-<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+<Project>
   <ItemGroup>
     <Content Include="..\..\..\libs\$(NativeDependenciesConfigurationUnix)\libgrpc_csharp_ext.so">
-      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
       <Link>libgrpc_csharp_ext.x64.so</Link>
+      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+      <Pack>false</Pack>
     </Content>
   </ItemGroup>
 </Project>
\ No newline at end of file
diff --git a/src/csharp/Grpc.Core/NativeDeps.Mac.csproj.include b/src/csharp/Grpc.Core/NativeDeps.Mac.csproj.include
new file mode 100644
index 0000000000000000000000000000000000000000..f1b85c3730e49dd64a85f2c5739f6b9dd8ab5cee
--- /dev/null
+++ b/src/csharp/Grpc.Core/NativeDeps.Mac.csproj.include
@@ -0,0 +1,17 @@
+<Project>
+  <ItemGroup>
+    <!-- We are relying on run_tests.py to build grpc_csharp_ext with the right bitness
+    and we copy it as both x86 (needed by net45) and x64 (needed by netcoreapp1.0) as we don't
+    know which one will be needed to run the tests. -->
+    <Content Include="..\..\..\libs\$(NativeDependenciesConfigurationUnix)\libgrpc_csharp_ext.dylib">
+      <Link>libgrpc_csharp_ext.x86.dylib</Link>
+      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+      <Pack>false</Pack>
+    </Content>
+    <Content Include="..\..\..\libs\$(NativeDependenciesConfigurationUnix)\libgrpc_csharp_ext.dylib">
+      <Link>libgrpc_csharp_ext.x64.dylib</Link>
+      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+      <Pack>false</Pack>
+    </Content>
+  </ItemGroup>
+</Project>
diff --git a/src/csharp/Grpc.Core/NativeDeps.Mac.targets b/src/csharp/Grpc.Core/NativeDeps.Mac.targets
deleted file mode 100644
index e22c7384fc5b8680870ef6da43884ea80133a47c..0000000000000000000000000000000000000000
--- a/src/csharp/Grpc.Core/NativeDeps.Mac.targets
+++ /dev/null
@@ -1,9 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
-  <ItemGroup>
-    <Content Include="..\..\..\libs\$(NativeDependenciesConfigurationUnix)\libgrpc_csharp_ext.dylib">
-      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
-      <Link>libgrpc_csharp_ext.x86.dylib</Link>
-    </Content>
-  </ItemGroup>
-</Project>
\ No newline at end of file
diff --git a/src/csharp/Grpc.Core/NativeDeps.Windows.csproj.include b/src/csharp/Grpc.Core/NativeDeps.Windows.csproj.include
new file mode 100644
index 0000000000000000000000000000000000000000..04f3b077ace0d8d28c2361ad7bc148e6c4d7122c
--- /dev/null
+++ b/src/csharp/Grpc.Core/NativeDeps.Windows.csproj.include
@@ -0,0 +1,9 @@
+<Project>
+  <ItemGroup>
+    <Content Include="..\..\..\cmake\build\x64\$(NativeDependenciesConfiguration)\grpc_csharp_ext.dll">
+      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+      <Link>grpc_csharp_ext.x64.dll</Link>
+      <Pack>false</Pack>
+    </Content>
+  </ItemGroup>
+</Project>
diff --git a/src/csharp/Grpc.Core/NativeDeps.Windows.targets b/src/csharp/Grpc.Core/NativeDeps.Windows.targets
deleted file mode 100644
index 623f58b95b0b9353b6b5df86d4f6a68d7dc15c4a..0000000000000000000000000000000000000000
--- a/src/csharp/Grpc.Core/NativeDeps.Windows.targets
+++ /dev/null
@@ -1,9 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
-  <ItemGroup>
-    <Content Include="..\..\..\cmake\build\Win32\$(NativeDependenciesConfiguration)\grpc_csharp_ext.dll">
-      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
-      <Link>grpc_csharp_ext.x86.dll</Link>
-    </Content>
-  </ItemGroup>
-</Project>
\ No newline at end of file
diff --git a/src/csharp/Grpc.Core/NativeDeps.targets b/src/csharp/Grpc.Core/NativeDeps.csproj.include
old mode 100644
new mode 100755
similarity index 83%
rename from src/csharp/Grpc.Core/NativeDeps.targets
rename to src/csharp/Grpc.Core/NativeDeps.csproj.include
index e187f72d266bd46d5f5ce0385926c7d1a53ee942..a62c63e11d09d2548ce2441cf6a46486f6d8f6c7
--- a/src/csharp/Grpc.Core/NativeDeps.targets
+++ b/src/csharp/Grpc.Core/NativeDeps.csproj.include
@@ -1,5 +1,5 @@
-<?xml version="1.0" encoding="utf-8"?>
-<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+<!-- Ensures that native libraries are copied to the output directory for Exe targets -->
+<Project>
 
   <PropertyGroup Condition=" '$(NativeDependenciesConfiguration)' == '' ">
     <NativeDependenciesConfiguration Condition=" '$(Configuration)' == 'Debug' ">Debug</NativeDependenciesConfiguration>
@@ -22,5 +22,6 @@
     <NativeDepsPlatform>Linux</NativeDepsPlatform>
   </PropertyGroup>
 
-  <Import Project="NativeDeps.$(NativeDepsPlatform).targets" />
-</Project>
\ No newline at end of file
+  <Import Project="NativeDeps.$(NativeDepsPlatform).csproj.include" />
+
+</Project>
diff --git a/src/csharp/Grpc.Core/Version.csproj.include b/src/csharp/Grpc.Core/Version.csproj.include
new file mode 100755
index 0000000000000000000000000000000000000000..ce9d0d2d5d287f616bda2ccdee308683e301ee22
--- /dev/null
+++ b/src/csharp/Grpc.Core/Version.csproj.include
@@ -0,0 +1,7 @@
+<!-- This file is generated -->
+<Project>
+  <PropertyGroup>
+    <GrpcCsharpVersion>1.3.0-dev</GrpcCsharpVersion>
+    <GoogleProtobufVersion>3.2.0</GoogleProtobufVersion>
+  </PropertyGroup>
+</Project>
diff --git a/src/csharp/Grpc.Core/packages.config b/src/csharp/Grpc.Core/packages.config
deleted file mode 100644
index 53cfad52f0bca1b3d030ddd2f3266170dcbe6801..0000000000000000000000000000000000000000
--- a/src/csharp/Grpc.Core/packages.config
+++ /dev/null
@@ -1,4 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<packages>
-  <package id="System.Interactive.Async" version="3.1.1" targetFramework="net45" />
-</packages>
\ No newline at end of file
diff --git a/src/csharp/Grpc.Core/project.json b/src/csharp/Grpc.Core/project.json
deleted file mode 100644
index a1306baa8763062fd9103c404703161ef5b20176..0000000000000000000000000000000000000000
--- a/src/csharp/Grpc.Core/project.json
+++ /dev/null
@@ -1,45 +0,0 @@
-{
-  "version": "1.3.0-dev",
-  "title": "gRPC C# Core",
-  "authors": [ "Google Inc." ],
-  "copyright": "Copyright 2015, Google Inc.",
-  "packOptions": {
-    "summary": "Core C# implementation of gRPC - an RPC library and framework",
-    "description": "Core C# implementation of gRPC - an RPC library and framework. See project site for more info.",
-    "owners": [ "grpc-packages" ],
-    "licenseUrl": "https://github.com/grpc/grpc/blob/master/LICENSE",
-    "projectUrl": "https://github.com/grpc/grpc",
-    "requireLicenseAcceptance": false,
-    "tags": [ "gRPC RPC Protocol HTTP/2" ],
-    "files": {
-      "mappings": {
-        "build/net45/": "Grpc.Core.targets",
-        "runtimes/win/native/grpc_csharp_ext.x86.dll": "../nativelibs/windows_x86/grpc_csharp_ext.dll",
-        "runtimes/win/native/grpc_csharp_ext.x64.dll": "../nativelibs/windows_x64/grpc_csharp_ext.dll",
-        "runtimes/linux/native/libgrpc_csharp_ext.x86.so": "../nativelibs/linux_x86/libgrpc_csharp_ext.so",
-        "runtimes/linux/native/libgrpc_csharp_ext.x64.so": "../nativelibs/linux_x64/libgrpc_csharp_ext.so",
-        "runtimes/osx/native/libgrpc_csharp_ext.x86.dylib": "../nativelibs/macosx_x86/libgrpc_csharp_ext.dylib",
-        "runtimes/osx/native/libgrpc_csharp_ext.x64.dylib": "../nativelibs/macosx_x64/libgrpc_csharp_ext.dylib"
-      }
-    }
-  },
-  "buildOptions": {
-    "embed": [ "../../../etc/roots.pem" ],
-    "define": [ "SIGNED" ],
-    "keyFile": "../keys/Grpc.snk",
-    "xmlDoc": true
-  },
-  "dependencies": {
-    "System.Interactive.Async": "3.1.1"
-  },
-  "frameworks": {
-    "net45": { },
-    "netstandard1.5": {
-      "dependencies": {
-        "NETStandard.Library": "1.6.0",
-        "System.Runtime.Loader": "4.0.0",
-        "System.Threading.Thread": "4.0.0"
-      }
-    }
-  }
-}
diff --git a/src/csharp/Grpc.Dotnet.sln b/src/csharp/Grpc.Dotnet.sln
deleted file mode 100644
index 824c6822f7e9aec2a634f2b1739c2f1630af2a6a..0000000000000000000000000000000000000000
--- a/src/csharp/Grpc.Dotnet.sln
+++ /dev/null
@@ -1,112 +0,0 @@
-
-Microsoft Visual Studio Solution File, Format Version 12.00
-# Visual Studio 14
-VisualStudioVersion = 14.0.25420.1
-MinimumVisualStudioVersion = 10.0.40219.1
-Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Grpc.Core", "Grpc.Core\Grpc.Core.xproj", "{DC9908B6-F291-4FC8-A46D-2EA2551790EC}"
-EndProject
-Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Grpc.Auth", "Grpc.Auth\Grpc.Auth.xproj", "{C82631ED-06D1-4458-87BC-8257D12307A8}"
-EndProject
-Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Grpc.Core.Tests", "Grpc.Core.Tests\Grpc.Core.Tests.xproj", "{759E23B2-FC04-4695-902D-B073CDED3599}"
-EndProject
-Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Grpc.Examples", "Grpc.Examples\Grpc.Examples.xproj", "{C77B792D-FC78-4CE2-9522-B40B0803C636}"
-EndProject
-Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Grpc.Examples.MathClient", "Grpc.Examples.MathClient\Grpc.Examples.MathClient.xproj", "{FD48DECA-1622-4173-B1D9-2101CF5E7C5F}"
-EndProject
-Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Grpc.Examples.MathServer", "Grpc.Examples.MathServer\Grpc.Examples.MathServer.xproj", "{58579368-5372-4E67-ACD6-9B59CB9FA698}"
-EndProject
-Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Grpc.Examples.Tests", "Grpc.Examples.Tests\Grpc.Examples.Tests.xproj", "{C61714A6-F633-44FB-97F4-C91F425C1D15}"
-EndProject
-Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Grpc.HealthCheck", "Grpc.HealthCheck\Grpc.HealthCheck.xproj", "{3BE4AD0B-2BF0-4D68-B625-F6018EF0DCFA}"
-EndProject
-Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Grpc.HealthCheck.Tests", "Grpc.HealthCheck.Tests\Grpc.HealthCheck.Tests.xproj", "{43DAFAC6-5343-4621-960E-A8A977EA3F0B}"
-EndProject
-Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Grpc.IntegrationTesting", "Grpc.IntegrationTesting\Grpc.IntegrationTesting.xproj", "{20354386-3E71-4046-A269-3BC2A06F3EC8}"
-EndProject
-Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Grpc.IntegrationTesting.Client", "Grpc.IntegrationTesting.Client\Grpc.IntegrationTesting.Client.xproj", "{48EA5BBE-70E2-4198-869D-D7E59C45F30D}"
-EndProject
-Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Grpc.IntegrationTesting.QpsWorker", "Grpc.IntegrationTesting.QpsWorker\Grpc.IntegrationTesting.QpsWorker.xproj", "{661B70D7-F56A-46E0-9B81-6227B591B5E7}"
-EndProject
-Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Grpc.IntegrationTesting.Server", "Grpc.IntegrationTesting.Server\Grpc.IntegrationTesting.Server.xproj", "{881F7AD1-A84E-47A2-9402-115C63C4031E}"
-EndProject
-Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Grpc.IntegrationTesting.StressClient", "Grpc.IntegrationTesting.StressClient\Grpc.IntegrationTesting.StressClient.xproj", "{0EBC910B-8867-4D3E-8686-91F34183D839}"
-EndProject
-Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Grpc.Reflection", "Grpc.Reflection\Grpc.Reflection.xproj", "{2B372155-80BA-4CF9-82D6-4B938E8EC3A0}"
-EndProject
-Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Grpc.Reflection.Tests", "Grpc.Reflection.Tests\Grpc.Reflection.Tests.xproj", "{FE90181D-A4B3-4A5C-8490-F07561E18E3B}"
-EndProject
-Global
-	GlobalSection(SolutionConfigurationPlatforms) = preSolution
-		Debug|Any CPU = Debug|Any CPU
-		Release|Any CPU = Release|Any CPU
-	EndGlobalSection
-	GlobalSection(ProjectConfigurationPlatforms) = postSolution
-		{DC9908B6-F291-4FC8-A46D-2EA2551790EC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
-		{DC9908B6-F291-4FC8-A46D-2EA2551790EC}.Debug|Any CPU.Build.0 = Debug|Any CPU
-		{DC9908B6-F291-4FC8-A46D-2EA2551790EC}.Release|Any CPU.ActiveCfg = Release|Any CPU
-		{DC9908B6-F291-4FC8-A46D-2EA2551790EC}.Release|Any CPU.Build.0 = Release|Any CPU
-		{C82631ED-06D1-4458-87BC-8257D12307A8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
-		{C82631ED-06D1-4458-87BC-8257D12307A8}.Debug|Any CPU.Build.0 = Debug|Any CPU
-		{C82631ED-06D1-4458-87BC-8257D12307A8}.Release|Any CPU.ActiveCfg = Release|Any CPU
-		{C82631ED-06D1-4458-87BC-8257D12307A8}.Release|Any CPU.Build.0 = Release|Any CPU
-		{759E23B2-FC04-4695-902D-B073CDED3599}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
-		{759E23B2-FC04-4695-902D-B073CDED3599}.Debug|Any CPU.Build.0 = Debug|Any CPU
-		{759E23B2-FC04-4695-902D-B073CDED3599}.Release|Any CPU.ActiveCfg = Release|Any CPU
-		{759E23B2-FC04-4695-902D-B073CDED3599}.Release|Any CPU.Build.0 = Release|Any CPU
-		{C77B792D-FC78-4CE2-9522-B40B0803C636}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
-		{C77B792D-FC78-4CE2-9522-B40B0803C636}.Debug|Any CPU.Build.0 = Debug|Any CPU
-		{C77B792D-FC78-4CE2-9522-B40B0803C636}.Release|Any CPU.ActiveCfg = Release|Any CPU
-		{C77B792D-FC78-4CE2-9522-B40B0803C636}.Release|Any CPU.Build.0 = Release|Any CPU
-		{FD48DECA-1622-4173-B1D9-2101CF5E7C5F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
-		{FD48DECA-1622-4173-B1D9-2101CF5E7C5F}.Debug|Any CPU.Build.0 = Debug|Any CPU
-		{FD48DECA-1622-4173-B1D9-2101CF5E7C5F}.Release|Any CPU.ActiveCfg = Release|Any CPU
-		{FD48DECA-1622-4173-B1D9-2101CF5E7C5F}.Release|Any CPU.Build.0 = Release|Any CPU
-		{58579368-5372-4E67-ACD6-9B59CB9FA698}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
-		{58579368-5372-4E67-ACD6-9B59CB9FA698}.Debug|Any CPU.Build.0 = Debug|Any CPU
-		{58579368-5372-4E67-ACD6-9B59CB9FA698}.Release|Any CPU.ActiveCfg = Release|Any CPU
-		{58579368-5372-4E67-ACD6-9B59CB9FA698}.Release|Any CPU.Build.0 = Release|Any CPU
-		{C61714A6-F633-44FB-97F4-C91F425C1D15}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
-		{C61714A6-F633-44FB-97F4-C91F425C1D15}.Debug|Any CPU.Build.0 = Debug|Any CPU
-		{C61714A6-F633-44FB-97F4-C91F425C1D15}.Release|Any CPU.ActiveCfg = Release|Any CPU
-		{C61714A6-F633-44FB-97F4-C91F425C1D15}.Release|Any CPU.Build.0 = Release|Any CPU
-		{3BE4AD0B-2BF0-4D68-B625-F6018EF0DCFA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
-		{3BE4AD0B-2BF0-4D68-B625-F6018EF0DCFA}.Debug|Any CPU.Build.0 = Debug|Any CPU
-		{3BE4AD0B-2BF0-4D68-B625-F6018EF0DCFA}.Release|Any CPU.ActiveCfg = Release|Any CPU
-		{3BE4AD0B-2BF0-4D68-B625-F6018EF0DCFA}.Release|Any CPU.Build.0 = Release|Any CPU
-		{43DAFAC6-5343-4621-960E-A8A977EA3F0B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
-		{43DAFAC6-5343-4621-960E-A8A977EA3F0B}.Debug|Any CPU.Build.0 = Debug|Any CPU
-		{43DAFAC6-5343-4621-960E-A8A977EA3F0B}.Release|Any CPU.ActiveCfg = Release|Any CPU
-		{43DAFAC6-5343-4621-960E-A8A977EA3F0B}.Release|Any CPU.Build.0 = Release|Any CPU
-		{20354386-3E71-4046-A269-3BC2A06F3EC8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
-		{20354386-3E71-4046-A269-3BC2A06F3EC8}.Debug|Any CPU.Build.0 = Debug|Any CPU
-		{20354386-3E71-4046-A269-3BC2A06F3EC8}.Release|Any CPU.ActiveCfg = Release|Any CPU
-		{20354386-3E71-4046-A269-3BC2A06F3EC8}.Release|Any CPU.Build.0 = Release|Any CPU
-		{48EA5BBE-70E2-4198-869D-D7E59C45F30D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
-		{48EA5BBE-70E2-4198-869D-D7E59C45F30D}.Debug|Any CPU.Build.0 = Debug|Any CPU
-		{48EA5BBE-70E2-4198-869D-D7E59C45F30D}.Release|Any CPU.ActiveCfg = Release|Any CPU
-		{48EA5BBE-70E2-4198-869D-D7E59C45F30D}.Release|Any CPU.Build.0 = Release|Any CPU
-		{661B70D7-F56A-46E0-9B81-6227B591B5E7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
-		{661B70D7-F56A-46E0-9B81-6227B591B5E7}.Debug|Any CPU.Build.0 = Debug|Any CPU
-		{661B70D7-F56A-46E0-9B81-6227B591B5E7}.Release|Any CPU.ActiveCfg = Release|Any CPU
-		{661B70D7-F56A-46E0-9B81-6227B591B5E7}.Release|Any CPU.Build.0 = Release|Any CPU
-		{881F7AD1-A84E-47A2-9402-115C63C4031E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
-		{881F7AD1-A84E-47A2-9402-115C63C4031E}.Debug|Any CPU.Build.0 = Debug|Any CPU
-		{881F7AD1-A84E-47A2-9402-115C63C4031E}.Release|Any CPU.ActiveCfg = Release|Any CPU
-		{881F7AD1-A84E-47A2-9402-115C63C4031E}.Release|Any CPU.Build.0 = Release|Any CPU
-		{0EBC910B-8867-4D3E-8686-91F34183D839}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
-		{0EBC910B-8867-4D3E-8686-91F34183D839}.Debug|Any CPU.Build.0 = Debug|Any CPU
-		{0EBC910B-8867-4D3E-8686-91F34183D839}.Release|Any CPU.ActiveCfg = Release|Any CPU
-		{0EBC910B-8867-4D3E-8686-91F34183D839}.Release|Any CPU.Build.0 = Release|Any CPU
-		{2B372155-80BA-4CF9-82D6-4B938E8EC3A0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
-		{2B372155-80BA-4CF9-82D6-4B938E8EC3A0}.Debug|Any CPU.Build.0 = Debug|Any CPU
-		{2B372155-80BA-4CF9-82D6-4B938E8EC3A0}.Release|Any CPU.ActiveCfg = Release|Any CPU
-		{2B372155-80BA-4CF9-82D6-4B938E8EC3A0}.Release|Any CPU.Build.0 = Release|Any CPU
-		{FE90181D-A4B3-4A5C-8490-F07561E18E3B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
-		{FE90181D-A4B3-4A5C-8490-F07561E18E3B}.Debug|Any CPU.Build.0 = Debug|Any CPU
-		{FE90181D-A4B3-4A5C-8490-F07561E18E3B}.Release|Any CPU.ActiveCfg = Release|Any CPU
-		{FE90181D-A4B3-4A5C-8490-F07561E18E3B}.Release|Any CPU.Build.0 = Release|Any CPU
-	EndGlobalSection
-	GlobalSection(SolutionProperties) = preSolution
-		HideSolutionNode = FALSE
-	EndGlobalSection
-EndGlobal
diff --git a/src/csharp/Grpc.Examples.MathClient/Grpc.Examples.MathClient.csproj b/src/csharp/Grpc.Examples.MathClient/Grpc.Examples.MathClient.csproj
old mode 100644
new mode 100755
index de4005c2f660f587142335883661ae1409c57279..08df026a53a417eb2496e7f8855c9c2942c2f0c8
--- a/src/csharp/Grpc.Examples.MathClient/Grpc.Examples.MathClient.csproj
+++ b/src/csharp/Grpc.Examples.MathClient/Grpc.Examples.MathClient.csproj
@@ -1,54 +1,27 @@
-<?xml version="1.0" encoding="utf-8"?>
-<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+<Project Sdk="Microsoft.NET.Sdk">
+
+  <Import Project="..\Grpc.Core\Version.csproj.include" />
+  <Import Project="..\Grpc.Core\Common.csproj.include" />
+
   <PropertyGroup>
-    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
-    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
-    <ProductVersion>10.0.0</ProductVersion>
-    <SchemaVersion>2.0</SchemaVersion>
-    <ProjectGuid>{61ECB8EE-0C96-4F8E-B187-8E4D227417C0}</ProjectGuid>
+    <TargetFrameworks>net45;netcoreapp1.0</TargetFrameworks>
+    <AssemblyName>Grpc.Examples.MathClient</AssemblyName>
     <OutputType>Exe</OutputType>
-    <RootNamespace>math</RootNamespace>
-    <AssemblyName>MathClient</AssemblyName>
-    <TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
-  </PropertyGroup>
-  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
-    <DebugSymbols>true</DebugSymbols>
-    <DebugType>full</DebugType>
-    <Optimize>false</Optimize>
-    <OutputPath>bin\Debug</OutputPath>
-    <DefineConstants>DEBUG;</DefineConstants>
-    <ErrorReport>prompt</ErrorReport>
-    <WarningLevel>4</WarningLevel>
-  </PropertyGroup>
-  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
-    <DebugType>pdbonly</DebugType>
-    <Optimize>true</Optimize>
-    <OutputPath>bin\Release</OutputPath>
-    <ErrorReport>prompt</ErrorReport>
-    <WarningLevel>4</WarningLevel>
+    <PackageId>Grpc.Examples.MathClient</PackageId>
+    <RuntimeFrameworkVersion Condition=" '$(TargetFramework)' == 'netcoreapp1.0' ">1.0.4</RuntimeFrameworkVersion>
   </PropertyGroup>
+
   <ItemGroup>
-    <Reference Include="System" />
+    <ProjectReference Include="../Grpc.Examples/Grpc.Examples.csproj" />
   </ItemGroup>
-  <ItemGroup>
-    <Compile Include="..\Grpc.Core\Version.cs">
-      <Link>Version.cs</Link>
-    </Compile>
-    <Compile Include="Properties\AssemblyInfo.cs" />
-    <Compile Include="MathClient.cs" />
-  </ItemGroup>
-  <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
-  <ItemGroup>
-    <ProjectReference Include="..\Grpc.Core\Grpc.Core.csproj">
-      <Project>{CCC4440E-49F7-4790-B0AF-FEABB0837AE7}</Project>
-      <Name>Grpc.Core</Name>
-    </ProjectReference>
-    <ProjectReference Include="..\Grpc.Examples\Grpc.Examples.csproj">
-      <Project>{7DC1433E-3225-42C7-B7EA-546D56E27A4B}</Project>
-      <Name>Grpc.Examples</Name>
-    </ProjectReference>
+
+  <ItemGroup Condition=" '$(TargetFramework)' == 'net45' ">
+    <Reference Include="System" />
+    <Reference Include="Microsoft.CSharp" />
   </ItemGroup>
+
   <ItemGroup>
-    <None Include="Grpc.Examples.MathClient.project.json" />
+    <Compile Include="..\Grpc.Core\Version.cs" />
   </ItemGroup>
-</Project>
\ No newline at end of file
+
+</Project>
diff --git a/src/csharp/Grpc.Examples.MathClient/Grpc.Examples.MathClient.project.json b/src/csharp/Grpc.Examples.MathClient/Grpc.Examples.MathClient.project.json
deleted file mode 100644
index c2f5bcb1637badadff8959d672e04c942cb54d51..0000000000000000000000000000000000000000
--- a/src/csharp/Grpc.Examples.MathClient/Grpc.Examples.MathClient.project.json
+++ /dev/null
@@ -1,8 +0,0 @@
-{
-  "frameworks": {
-    "net45": { }
-  },
-  "runtimes": {
-    "win": { }
-  }
-}
diff --git a/src/csharp/Grpc.Examples.MathClient/Grpc.Examples.MathClient.xproj b/src/csharp/Grpc.Examples.MathClient/Grpc.Examples.MathClient.xproj
deleted file mode 100644
index 4655bd4377432ec5bf52f1884f7f3bf142dfc171..0000000000000000000000000000000000000000
--- a/src/csharp/Grpc.Examples.MathClient/Grpc.Examples.MathClient.xproj
+++ /dev/null
@@ -1,18 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<Project ToolsVersion="14.0.25123" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
-  <PropertyGroup>
-    <VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">14.0.25123</VisualStudioVersion>
-    <VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
-  </PropertyGroup>
-  <Import Project="$(VSToolsPath)\DNX\Microsoft.DNX.Props" Condition="'$(VSToolsPath)' != ''" />
-  <PropertyGroup Label="Globals">
-    <ProjectGuid>fd48deca-1622-4173-b1d9-2101cf5e7c5f</ProjectGuid>
-    <RootNamespace>Grpc.Examples.MathClient</RootNamespace>
-    <BaseIntermediateOutputPath Condition="'$(BaseIntermediateOutputPath)'=='' ">..\artifacts\obj\$(MSBuildProjectName)</BaseIntermediateOutputPath>
-    <OutputPath Condition="'$(OutputPath)'=='' ">.\bin\</OutputPath>
-  </PropertyGroup>
-  <PropertyGroup>
-    <SchemaVersion>2.0</SchemaVersion>
-  </PropertyGroup>
-  <Import Project="$(VSToolsPath)\DNX\Microsoft.DNX.targets" Condition="'$(VSToolsPath)' != ''" />
-</Project>
\ No newline at end of file
diff --git a/src/csharp/Grpc.Examples.MathClient/packages.config b/src/csharp/Grpc.Examples.MathClient/packages.config
deleted file mode 100644
index 79ece06bef6a23c7f75492ed821f546d8bd403e2..0000000000000000000000000000000000000000
--- a/src/csharp/Grpc.Examples.MathClient/packages.config
+++ /dev/null
@@ -1,3 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<packages>
-</packages>
diff --git a/src/csharp/Grpc.Examples.MathClient/project.json b/src/csharp/Grpc.Examples.MathClient/project.json
deleted file mode 100644
index 81c17151aa5441569e09aba68d695ba9d0144c26..0000000000000000000000000000000000000000
--- a/src/csharp/Grpc.Examples.MathClient/project.json
+++ /dev/null
@@ -1,60 +0,0 @@
-{
-  "buildOptions": {
-    "emitEntryPoint": true
-  },
-  "configurations": {
-    "Debug": {
-      "buildOptions": {
-        "define": [ "SIGNED" ],
-        "keyFile": "../keys/Grpc.snk",
-        "xmlDoc": true,
-        "compile": {
-          "includeFiles": [ "../Grpc.Core/Version.cs" ]
-        },
-        "copyToOutput": {
-          "mappings": {
-            "grpc_csharp_ext.x64.dll": "../../../cmake/build/x64/Debug/grpc_csharp_ext.dll",
-            "grpc_csharp_ext.x86.dll": "../../../cmake/build/Win32/Debug/grpc_csharp_ext.dll",
-            "libgrpc_csharp_ext.x64.so": "../../../libs/dbg/libgrpc_csharp_ext.so",
-            "libgrpc_csharp_ext.x64.dylib": "../../../libs/dbg/libgrpc_csharp_ext.dylib"
-          }
-        }
-      }
-    },
-    "Release": {
-      "buildOptions": {
-        "define": [ "SIGNED" ],
-        "keyFile": "../keys/Grpc.snk",
-        "xmlDoc": true,
-        "compile": {
-          "includeFiles": [ "../Grpc.Core/Version.cs" ]
-        },
-        "copyToOutput": {
-          "mappings": {
-            "grpc_csharp_ext.x64.dll": "../../../cmake/build/x64/Release/grpc_csharp_ext.dll",
-            "grpc_csharp_ext.x86.dll": "../../../cmake/build/Win32/Release/grpc_csharp_ext.dll",
-            "libgrpc_csharp_ext.x64.so": "../../../libs/opt/libgrpc_csharp_ext.so",
-            "libgrpc_csharp_ext.x64.dylib": "../../../libs/opt/libgrpc_csharp_ext.dylib"
-          }
-        }
-      }
-    }
-  },
-
-  "dependencies": {
-    "Grpc.Examples": {
-      "target": "project"
-    }
-  },
-  "frameworks": {
-    "net45": { },
-    "netcoreapp1.0": {
-      "dependencies": {
-        "Microsoft.NETCore.App": {
-          "type": "platform",
-          "version": "1.0.0"
-        }
-      }
-    }
-  }
-}
diff --git a/src/csharp/Grpc.Examples.MathServer/Grpc.Examples.MathServer.csproj b/src/csharp/Grpc.Examples.MathServer/Grpc.Examples.MathServer.csproj
old mode 100644
new mode 100755
index 3f38de2b714293834d76690835304fd5f8298f9d..a02937474a18f0f2d2dc0fa92cadfb8d5c8ae041
--- a/src/csharp/Grpc.Examples.MathServer/Grpc.Examples.MathServer.csproj
+++ b/src/csharp/Grpc.Examples.MathServer/Grpc.Examples.MathServer.csproj
@@ -1,54 +1,27 @@
-<?xml version="1.0" encoding="utf-8"?>
-<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+<Project Sdk="Microsoft.NET.Sdk">
+
+  <Import Project="..\Grpc.Core\Version.csproj.include" />
+  <Import Project="..\Grpc.Core\Common.csproj.include" />
+
   <PropertyGroup>
-    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
-    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
-    <ProductVersion>10.0.0</ProductVersion>
-    <SchemaVersion>2.0</SchemaVersion>
-    <ProjectGuid>{BF62FE08-373A-43D6-9D73-41CAA38B7011}</ProjectGuid>
+    <TargetFrameworks>net45;netcoreapp1.0</TargetFrameworks>
+    <AssemblyName>Grpc.Examples.MathServer</AssemblyName>
     <OutputType>Exe</OutputType>
-    <RootNamespace>Grpc.Examples.MathServer</RootNamespace>
-    <AssemblyName>MathServer</AssemblyName>
-    <TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
-  </PropertyGroup>
-  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
-    <DebugSymbols>true</DebugSymbols>
-    <DebugType>full</DebugType>
-    <Optimize>false</Optimize>
-    <OutputPath>bin\Debug</OutputPath>
-    <DefineConstants>DEBUG;</DefineConstants>
-    <ErrorReport>prompt</ErrorReport>
-    <WarningLevel>4</WarningLevel>
-  </PropertyGroup>
-  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
-    <DebugType>pdbonly</DebugType>
-    <Optimize>true</Optimize>
-    <OutputPath>bin\Release</OutputPath>
-    <ErrorReport>prompt</ErrorReport>
-    <WarningLevel>4</WarningLevel>
+    <PackageId>Grpc.Examples.MathServer</PackageId>
+    <RuntimeFrameworkVersion Condition=" '$(TargetFramework)' == 'netcoreapp1.0' ">1.0.4</RuntimeFrameworkVersion>
   </PropertyGroup>
+
   <ItemGroup>
-    <Reference Include="System" />
+    <ProjectReference Include="../Grpc.Examples/Grpc.Examples.csproj" />
   </ItemGroup>
-  <ItemGroup>
-    <Compile Include="..\Grpc.Core\Version.cs">
-      <Link>Version.cs</Link>
-    </Compile>
-    <Compile Include="Properties\AssemblyInfo.cs" />
-    <Compile Include="MathServer.cs" />
-  </ItemGroup>
-  <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
-  <ItemGroup>
-    <ProjectReference Include="..\Grpc.Core\Grpc.Core.csproj">
-      <Project>{CCC4440E-49F7-4790-B0AF-FEABB0837AE7}</Project>
-      <Name>Grpc.Core</Name>
-    </ProjectReference>
-    <ProjectReference Include="..\Grpc.Examples\Grpc.Examples.csproj">
-      <Project>{7DC1433E-3225-42C7-B7EA-546D56E27A4B}</Project>
-      <Name>Grpc.Examples</Name>
-    </ProjectReference>
+
+  <ItemGroup Condition=" '$(TargetFramework)' == 'net45' ">
+    <Reference Include="System" />
+    <Reference Include="Microsoft.CSharp" />
   </ItemGroup>
+
   <ItemGroup>
-    <None Include="Grpc.Examples.MathServer.project.json" />
+    <Compile Include="..\Grpc.Core\Version.cs" />
   </ItemGroup>
-</Project>
\ No newline at end of file
+
+</Project>
diff --git a/src/csharp/Grpc.Examples.MathServer/Grpc.Examples.MathServer.project.json b/src/csharp/Grpc.Examples.MathServer/Grpc.Examples.MathServer.project.json
deleted file mode 100644
index c2f5bcb1637badadff8959d672e04c942cb54d51..0000000000000000000000000000000000000000
--- a/src/csharp/Grpc.Examples.MathServer/Grpc.Examples.MathServer.project.json
+++ /dev/null
@@ -1,8 +0,0 @@
-{
-  "frameworks": {
-    "net45": { }
-  },
-  "runtimes": {
-    "win": { }
-  }
-}
diff --git a/src/csharp/Grpc.Examples.MathServer/Grpc.Examples.MathServer.xproj b/src/csharp/Grpc.Examples.MathServer/Grpc.Examples.MathServer.xproj
deleted file mode 100644
index 38a449e8f29823936d4eebc6523bcd587641fbff..0000000000000000000000000000000000000000
--- a/src/csharp/Grpc.Examples.MathServer/Grpc.Examples.MathServer.xproj
+++ /dev/null
@@ -1,18 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<Project ToolsVersion="14.0.25123" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
-  <PropertyGroup>
-    <VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">14.0.25123</VisualStudioVersion>
-    <VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
-  </PropertyGroup>
-  <Import Project="$(VSToolsPath)\DNX\Microsoft.DNX.Props" Condition="'$(VSToolsPath)' != ''" />
-  <PropertyGroup Label="Globals">
-    <ProjectGuid>58579368-5372-4e67-acd6-9b59cb9fa698</ProjectGuid>
-    <RootNamespace>Grpc.Examples.MathServer</RootNamespace>
-    <BaseIntermediateOutputPath Condition="'$(BaseIntermediateOutputPath)'=='' ">..\artifacts\obj\$(MSBuildProjectName)</BaseIntermediateOutputPath>
-    <OutputPath Condition="'$(OutputPath)'=='' ">.\bin\</OutputPath>
-  </PropertyGroup>
-  <PropertyGroup>
-    <SchemaVersion>2.0</SchemaVersion>
-  </PropertyGroup>
-  <Import Project="$(VSToolsPath)\DNX\Microsoft.DNX.targets" Condition="'$(VSToolsPath)' != ''" />
-</Project>
\ No newline at end of file
diff --git a/src/csharp/Grpc.Examples.MathServer/packages.config b/src/csharp/Grpc.Examples.MathServer/packages.config
deleted file mode 100644
index 79ece06bef6a23c7f75492ed821f546d8bd403e2..0000000000000000000000000000000000000000
--- a/src/csharp/Grpc.Examples.MathServer/packages.config
+++ /dev/null
@@ -1,3 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<packages>
-</packages>
diff --git a/src/csharp/Grpc.Examples.MathServer/project.json b/src/csharp/Grpc.Examples.MathServer/project.json
deleted file mode 100644
index 81c17151aa5441569e09aba68d695ba9d0144c26..0000000000000000000000000000000000000000
--- a/src/csharp/Grpc.Examples.MathServer/project.json
+++ /dev/null
@@ -1,60 +0,0 @@
-{
-  "buildOptions": {
-    "emitEntryPoint": true
-  },
-  "configurations": {
-    "Debug": {
-      "buildOptions": {
-        "define": [ "SIGNED" ],
-        "keyFile": "../keys/Grpc.snk",
-        "xmlDoc": true,
-        "compile": {
-          "includeFiles": [ "../Grpc.Core/Version.cs" ]
-        },
-        "copyToOutput": {
-          "mappings": {
-            "grpc_csharp_ext.x64.dll": "../../../cmake/build/x64/Debug/grpc_csharp_ext.dll",
-            "grpc_csharp_ext.x86.dll": "../../../cmake/build/Win32/Debug/grpc_csharp_ext.dll",
-            "libgrpc_csharp_ext.x64.so": "../../../libs/dbg/libgrpc_csharp_ext.so",
-            "libgrpc_csharp_ext.x64.dylib": "../../../libs/dbg/libgrpc_csharp_ext.dylib"
-          }
-        }
-      }
-    },
-    "Release": {
-      "buildOptions": {
-        "define": [ "SIGNED" ],
-        "keyFile": "../keys/Grpc.snk",
-        "xmlDoc": true,
-        "compile": {
-          "includeFiles": [ "../Grpc.Core/Version.cs" ]
-        },
-        "copyToOutput": {
-          "mappings": {
-            "grpc_csharp_ext.x64.dll": "../../../cmake/build/x64/Release/grpc_csharp_ext.dll",
-            "grpc_csharp_ext.x86.dll": "../../../cmake/build/Win32/Release/grpc_csharp_ext.dll",
-            "libgrpc_csharp_ext.x64.so": "../../../libs/opt/libgrpc_csharp_ext.so",
-            "libgrpc_csharp_ext.x64.dylib": "../../../libs/opt/libgrpc_csharp_ext.dylib"
-          }
-        }
-      }
-    }
-  },
-
-  "dependencies": {
-    "Grpc.Examples": {
-      "target": "project"
-    }
-  },
-  "frameworks": {
-    "net45": { },
-    "netcoreapp1.0": {
-      "dependencies": {
-        "Microsoft.NETCore.App": {
-          "type": "platform",
-          "version": "1.0.0"
-        }
-      }
-    }
-  }
-}
diff --git a/src/csharp/Grpc.Examples.Tests/Grpc.Examples.Tests.csproj b/src/csharp/Grpc.Examples.Tests/Grpc.Examples.Tests.csproj
old mode 100644
new mode 100755
index c96243b1c70702b93843f268e90e10ff15384bee..9a8e62cc8be628f2134a00a10a6435837a912628
--- a/src/csharp/Grpc.Examples.Tests/Grpc.Examples.Tests.csproj
+++ b/src/csharp/Grpc.Examples.Tests/Grpc.Examples.Tests.csproj
@@ -1,69 +1,33 @@
-<?xml version="1.0" encoding="utf-8"?>
-<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+<Project Sdk="Microsoft.NET.Sdk">
+
+  <Import Project="..\Grpc.Core\Version.csproj.include" />
+  <Import Project="..\Grpc.Core\Common.csproj.include" />
+
   <PropertyGroup>
-    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
-    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
-    <ProjectGuid>{143B1C29-C442-4BE0-BF3F-A8F92288AC9F}</ProjectGuid>
-    <OutputType>Exe</OutputType>
-    <RootNamespace>Grpc.Examples.Tests</RootNamespace>
+    <TargetFrameworks>net45;netcoreapp1.0</TargetFrameworks>
     <AssemblyName>Grpc.Examples.Tests</AssemblyName>
-    <TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
-  </PropertyGroup>
-  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
-    <DebugSymbols>true</DebugSymbols>
-    <DebugType>full</DebugType>
-    <Optimize>false</Optimize>
-    <OutputPath>bin\Debug</OutputPath>
-    <DefineConstants>DEBUG;</DefineConstants>
-    <ErrorReport>prompt</ErrorReport>
-    <WarningLevel>4</WarningLevel>
-  </PropertyGroup>
-  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
-    <DebugType>pdbonly</DebugType>
-    <Optimize>true</Optimize>
-    <OutputPath>bin\Release</OutputPath>
-    <ErrorReport>prompt</ErrorReport>
-    <WarningLevel>4</WarningLevel>
+    <OutputType>Exe</OutputType>
+    <PackageId>Grpc.Examples.Tests</PackageId>
+    <PackageTargetFallback Condition=" '$(TargetFramework)' == 'netcoreapp1.0' ">$(PackageTargetFallback);portable-net45</PackageTargetFallback>
+    <RuntimeFrameworkVersion Condition=" '$(TargetFramework)' == 'netcoreapp1.0' ">1.0.4</RuntimeFrameworkVersion>
   </PropertyGroup>
+
   <ItemGroup>
-    <Reference Include="System" />
-    <Reference Include="System.Interactive.Async">
-      <HintPath>..\packages\System.Interactive.Async.3.1.1\lib\net45\System.Interactive.Async.dll</HintPath>
-    </Reference>
-    <Reference Include="nunit.framework">
-      <HintPath>..\packages\NUnit.3.6.0\lib\net45\nunit.framework.dll</HintPath>
-    </Reference>
-    <Reference Include="nunitlite">
-      <HintPath>..\packages\NUnitLite.3.6.0\lib\net45\nunitlite.dll</HintPath>
-    </Reference>
-    <Reference Include="Google.Protobuf">
-      <HintPath>..\packages\Google.Protobuf.3.2.0\lib\net45\Google.Protobuf.dll</HintPath>
-    </Reference>
+    <ProjectReference Include="../Grpc.Examples/Grpc.Examples.csproj" />
   </ItemGroup>
+
   <ItemGroup>
-    <Compile Include="..\Grpc.Core\Version.cs">
-      <Link>Version.cs</Link>
-    </Compile>
-    <Compile Include="Properties\AssemblyInfo.cs" />
-    <Compile Include="MathClientServerTests.cs" />
-    <Compile Include="NUnitMain.cs" />
+    <PackageReference Include="NUnit" Version="3.6.0" />
+    <PackageReference Include="NUnitLite" Version="3.6.0" />
   </ItemGroup>
-  <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
-  <ItemGroup>
-    <ProjectReference Include="..\Grpc.Core\Grpc.Core.csproj">
-      <Project>{CCC4440E-49F7-4790-B0AF-FEABB0837AE7}</Project>
-      <Name>Grpc.Core</Name>
-    </ProjectReference>
-    <ProjectReference Include="..\Grpc.Examples\Grpc.Examples.csproj">
-      <Project>{7DC1433E-3225-42C7-B7EA-546D56E27A4B}</Project>
-      <Name>Grpc.Examples</Name>
-    </ProjectReference>
-  </ItemGroup>
-  <ItemGroup>
-    <None Include="Grpc.Examples.Tests.project.json" />
-    <None Include="packages.config" />
+
+  <ItemGroup Condition=" '$(TargetFramework)' == 'net45' ">
+    <Reference Include="System" />
+    <Reference Include="Microsoft.CSharp" />
   </ItemGroup>
+
   <ItemGroup>
-    <Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" />
+    <Compile Include="..\Grpc.Core\Version.cs" />
   </ItemGroup>
+
 </Project>
diff --git a/src/csharp/Grpc.Examples.Tests/Grpc.Examples.Tests.project.json b/src/csharp/Grpc.Examples.Tests/Grpc.Examples.Tests.project.json
deleted file mode 100644
index c2f5bcb1637badadff8959d672e04c942cb54d51..0000000000000000000000000000000000000000
--- a/src/csharp/Grpc.Examples.Tests/Grpc.Examples.Tests.project.json
+++ /dev/null
@@ -1,8 +0,0 @@
-{
-  "frameworks": {
-    "net45": { }
-  },
-  "runtimes": {
-    "win": { }
-  }
-}
diff --git a/src/csharp/Grpc.Examples.Tests/Grpc.Examples.Tests.xproj b/src/csharp/Grpc.Examples.Tests/Grpc.Examples.Tests.xproj
deleted file mode 100644
index 9cecd18b2e4f2a52d92dbc9024c01ec99fe0b367..0000000000000000000000000000000000000000
--- a/src/csharp/Grpc.Examples.Tests/Grpc.Examples.Tests.xproj
+++ /dev/null
@@ -1,18 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<Project ToolsVersion="14.0.25123" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
-  <PropertyGroup>
-    <VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">14.0.25123</VisualStudioVersion>
-    <VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
-  </PropertyGroup>
-  <Import Project="$(VSToolsPath)\DNX\Microsoft.DNX.Props" Condition="'$(VSToolsPath)' != ''" />
-  <PropertyGroup Label="Globals">
-    <ProjectGuid>c61714a6-f633-44fb-97f4-c91f425c1d15</ProjectGuid>
-    <RootNamespace>Grpc.Examples.Tests</RootNamespace>
-    <BaseIntermediateOutputPath Condition="'$(BaseIntermediateOutputPath)'=='' ">..\artifacts\obj\$(MSBuildProjectName)</BaseIntermediateOutputPath>
-    <OutputPath Condition="'$(OutputPath)'=='' ">.\bin\</OutputPath>
-  </PropertyGroup>
-  <PropertyGroup>
-    <SchemaVersion>2.0</SchemaVersion>
-  </PropertyGroup>
-  <Import Project="$(VSToolsPath)\DNX\Microsoft.DNX.targets" Condition="'$(VSToolsPath)' != ''" />
-</Project>
\ No newline at end of file
diff --git a/src/csharp/Grpc.Examples.Tests/packages.config b/src/csharp/Grpc.Examples.Tests/packages.config
deleted file mode 100644
index 8a7f7a0652a4dd70cdfcf0f1b1cfab6819b57e9c..0000000000000000000000000000000000000000
--- a/src/csharp/Grpc.Examples.Tests/packages.config
+++ /dev/null
@@ -1,7 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<packages>
-  <package id="Google.Protobuf" version="3.2.0" targetFramework="net45" />
-  <package id="NUnit" version="3.6.0" targetFramework="net45" />
-  <package id="NUnitLite" version="3.6.0" targetFramework="net45" />
-  <package id="System.Interactive.Async" version="3.1.1" targetFramework="net45" />
-</packages>
\ No newline at end of file
diff --git a/src/csharp/Grpc.Examples.Tests/project.json b/src/csharp/Grpc.Examples.Tests/project.json
deleted file mode 100644
index 4ffcaf57fd9b9dcc4316fa730e5cb524c0848e2b..0000000000000000000000000000000000000000
--- a/src/csharp/Grpc.Examples.Tests/project.json
+++ /dev/null
@@ -1,65 +0,0 @@
-{
-  "buildOptions": {
-    "emitEntryPoint": true
-  },
-  "configurations": {
-    "Debug": {
-      "buildOptions": {
-        "define": [ "SIGNED" ],
-        "keyFile": "../keys/Grpc.snk",
-        "xmlDoc": true,
-        "compile": {
-          "includeFiles": [ "../Grpc.Core/Version.cs" ]
-        },
-        "copyToOutput": {
-          "mappings": {
-            "grpc_csharp_ext.x64.dll": "../../../cmake/build/x64/Debug/grpc_csharp_ext.dll",
-            "grpc_csharp_ext.x86.dll": "../../../cmake/build/Win32/Debug/grpc_csharp_ext.dll",
-            "libgrpc_csharp_ext.x64.so": "../../../libs/dbg/libgrpc_csharp_ext.so",
-            "libgrpc_csharp_ext.x64.dylib": "../../../libs/dbg/libgrpc_csharp_ext.dylib"
-          }
-        }
-      }
-    },
-    "Release": {
-      "buildOptions": {
-        "define": [ "SIGNED" ],
-        "keyFile": "../keys/Grpc.snk",
-        "xmlDoc": true,
-        "compile": {
-          "includeFiles": [ "../Grpc.Core/Version.cs" ]
-        },
-        "copyToOutput": {
-          "mappings": {
-            "grpc_csharp_ext.x64.dll": "../../../cmake/build/x64/Release/grpc_csharp_ext.dll",
-            "grpc_csharp_ext.x86.dll": "../../../cmake/build/Win32/Release/grpc_csharp_ext.dll",
-            "libgrpc_csharp_ext.x64.so": "../../../libs/opt/libgrpc_csharp_ext.so",
-            "libgrpc_csharp_ext.x64.dylib": "../../../libs/opt/libgrpc_csharp_ext.dylib"
-          }
-        }
-      }
-    }
-  },
-
-  "dependencies": {
-    "Grpc.Examples": {
-      "target": "project"
-    },
-    "NUnit": "3.6.0",
-    "NUnitLite": "3.6.0"
-  },
-  "frameworks": {
-    "net45": { },
-    "netcoreapp1.0": {
-      "imports": [
-        "portable-net45"
-      ],
-      "dependencies": {
-        "Microsoft.NETCore.App": {
-          "type": "platform",
-          "version": "1.0.0"
-        }
-      }
-    }
-  }
-}
diff --git a/src/csharp/Grpc.Examples/Grpc.Examples.csproj b/src/csharp/Grpc.Examples/Grpc.Examples.csproj
old mode 100644
new mode 100755
index fc927543f7354823c79beb110f9f9cd779b9ab56..625c1723bc835b119a8ebca41374c4513e122fab
--- a/src/csharp/Grpc.Examples/Grpc.Examples.csproj
+++ b/src/csharp/Grpc.Examples/Grpc.Examples.csproj
@@ -1,62 +1,30 @@
-<?xml version="1.0" encoding="utf-8"?>
-<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+<Project Sdk="Microsoft.NET.Sdk">
+
+  <Import Project="..\Grpc.Core\Version.csproj.include" />
+  <Import Project="..\Grpc.Core\Common.csproj.include" />
+
   <PropertyGroup>
-    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
-    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
-    <ProjectGuid>{7DC1433E-3225-42C7-B7EA-546D56E27A4B}</ProjectGuid>
-    <OutputType>Library</OutputType>
-    <RootNamespace>Grpc.Examples</RootNamespace>
+    <TargetFrameworks>net45;netcoreapp1.0</TargetFrameworks>
     <AssemblyName>Grpc.Examples</AssemblyName>
-    <TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
-  </PropertyGroup>
-  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
-    <DebugSymbols>true</DebugSymbols>
-    <DebugType>full</DebugType>
-    <Optimize>false</Optimize>
-    <OutputPath>bin\Debug</OutputPath>
-    <DefineConstants>DEBUG;</DefineConstants>
-    <ErrorReport>prompt</ErrorReport>
-    <WarningLevel>4</WarningLevel>
-  </PropertyGroup>
-  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
-    <DebugType>pdbonly</DebugType>
-    <Optimize>true</Optimize>
-    <OutputPath>bin\Release</OutputPath>
-    <ErrorReport>prompt</ErrorReport>
-    <WarningLevel>4</WarningLevel>
+    <PackageId>Grpc.Examples</PackageId>
+    <RuntimeFrameworkVersion Condition=" '$(TargetFramework)' == 'netcoreapp1.0' ">1.0.4</RuntimeFrameworkVersion>
   </PropertyGroup>
+
   <ItemGroup>
-    <Reference Include="System" />
-    <Reference Include="System.Data.Linq" />
-    <Reference Include="System.Interactive.Async">
-      <HintPath>..\packages\System.Interactive.Async.3.1.1\lib\net45\System.Interactive.Async.dll</HintPath>
-    </Reference>
-    <Reference Include="nunit.framework">
-      <HintPath>..\packages\NUnit.3.6.0\lib\net45\nunit.framework.dll</HintPath>
-    </Reference>
-    <Reference Include="Google.Protobuf">
-      <HintPath>..\packages\Google.Protobuf.3.2.0\lib\net45\Google.Protobuf.dll</HintPath>
-    </Reference>
+    <Compile Include="..\Grpc.Core\Version.cs" />
   </ItemGroup>
+
   <ItemGroup>
-    <Compile Include="..\Grpc.Core\Version.cs">
-      <Link>Version.cs</Link>
-    </Compile>
-    <Compile Include="Properties\AssemblyInfo.cs" />
-    <Compile Include="Math.cs" />
-    <Compile Include="MathGrpc.cs" />
-    <Compile Include="MathServiceImpl.cs" />
-    <Compile Include="MathExamples.cs" />
+    <ProjectReference Include="../Grpc.Core/Grpc.Core.csproj" />
   </ItemGroup>
-  <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
+
   <ItemGroup>
-    <ProjectReference Include="..\Grpc.Core\Grpc.Core.csproj">
-      <Project>{CCC4440E-49F7-4790-B0AF-FEABB0837AE7}</Project>
-      <Name>Grpc.Core</Name>
-    </ProjectReference>
+    <PackageReference Include="Google.Protobuf" Version="$(GoogleProtobufVersion)" />
   </ItemGroup>
-  <ItemGroup>
-    <None Include="Grpc.Examples.project.json" />
-    <None Include="packages.config" />
+
+  <ItemGroup Condition=" '$(TargetFramework)' == 'net45' ">
+    <Reference Include="System" />
+    <Reference Include="Microsoft.CSharp" />
   </ItemGroup>
+
 </Project>
diff --git a/src/csharp/Grpc.Examples/Grpc.Examples.project.json b/src/csharp/Grpc.Examples/Grpc.Examples.project.json
deleted file mode 100644
index c2f5bcb1637badadff8959d672e04c942cb54d51..0000000000000000000000000000000000000000
--- a/src/csharp/Grpc.Examples/Grpc.Examples.project.json
+++ /dev/null
@@ -1,8 +0,0 @@
-{
-  "frameworks": {
-    "net45": { }
-  },
-  "runtimes": {
-    "win": { }
-  }
-}
diff --git a/src/csharp/Grpc.Examples/Grpc.Examples.xproj b/src/csharp/Grpc.Examples/Grpc.Examples.xproj
deleted file mode 100644
index d1d7e6d981633fad59d3113d581f86a9a91facfd..0000000000000000000000000000000000000000
--- a/src/csharp/Grpc.Examples/Grpc.Examples.xproj
+++ /dev/null
@@ -1,18 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<Project ToolsVersion="14.0.25123" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
-  <PropertyGroup>
-    <VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">14.0.25123</VisualStudioVersion>
-    <VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
-  </PropertyGroup>
-  <Import Project="$(VSToolsPath)\DNX\Microsoft.DNX.Props" Condition="'$(VSToolsPath)' != ''" />
-  <PropertyGroup Label="Globals">
-    <ProjectGuid>c77b792d-fc78-4ce2-9522-b40b0803c636</ProjectGuid>
-    <RootNamespace>Grpc.Examples</RootNamespace>
-    <BaseIntermediateOutputPath Condition="'$(BaseIntermediateOutputPath)'=='' ">..\artifacts\obj\$(MSBuildProjectName)</BaseIntermediateOutputPath>
-    <OutputPath Condition="'$(OutputPath)'=='' ">.\bin\</OutputPath>
-  </PropertyGroup>
-  <PropertyGroup>
-    <SchemaVersion>2.0</SchemaVersion>
-  </PropertyGroup>
-  <Import Project="$(VSToolsPath)\DNX\Microsoft.DNX.targets" Condition="'$(VSToolsPath)' != ''" />
-</Project>
\ No newline at end of file
diff --git a/src/csharp/Grpc.Examples/packages.config b/src/csharp/Grpc.Examples/packages.config
deleted file mode 100644
index 79a898081ed28ef0ccfd32a71ae042a1a82f4a6d..0000000000000000000000000000000000000000
--- a/src/csharp/Grpc.Examples/packages.config
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<packages>
-  <package id="Google.Protobuf" version="3.2.0" targetFramework="net45" />
-  <package id="NUnit" version="3.6.0" targetFramework="net45" />
-  <package id="System.Interactive.Async" version="3.1.1" targetFramework="net45" />
-</packages>
\ No newline at end of file
diff --git a/src/csharp/Grpc.Examples/project.json b/src/csharp/Grpc.Examples/project.json
deleted file mode 100644
index 3ee0a71356940e804d3af278741395115bb7859e..0000000000000000000000000000000000000000
--- a/src/csharp/Grpc.Examples/project.json
+++ /dev/null
@@ -1,22 +0,0 @@
-{
-  "buildOptions": {
-  },
-
-  "dependencies": {
-    "Grpc.Core": {
-      "target": "project"
-    },
-    "Google.Protobuf": "3.2.0"
-  },
-  "frameworks": {
-    "net45": {},
-    "netcoreapp1.0": {
-      "dependencies": {
-        "Microsoft.NETCore.App": {
-          "type": "platform",
-          "version": "1.0.0"
-        }
-      }
-    }
-  }
-}
diff --git a/src/csharp/Grpc.HealthCheck.Tests/Grpc.HealthCheck.Tests.csproj b/src/csharp/Grpc.HealthCheck.Tests/Grpc.HealthCheck.Tests.csproj
old mode 100644
new mode 100755
index 71f0ee19b86ecd412a85b6f46dc6fbff9235fab7..b0e2716e7e5d7d72cabce989ba56efd91ac14e02
--- a/src/csharp/Grpc.HealthCheck.Tests/Grpc.HealthCheck.Tests.csproj
+++ b/src/csharp/Grpc.HealthCheck.Tests/Grpc.HealthCheck.Tests.csproj
@@ -1,82 +1,33 @@
-<?xml version="1.0" encoding="utf-8"?>
-<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
-  <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
+<Project Sdk="Microsoft.NET.Sdk">
+
+  <Import Project="..\Grpc.Core\Version.csproj.include" />
+  <Import Project="..\Grpc.Core\Common.csproj.include" />
+
   <PropertyGroup>
-    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
-    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
-    <ProjectGuid>{F8C6D937-C44B-4EE3-A431-B0FBAEACE47D}</ProjectGuid>
-    <OutputType>Exe</OutputType>
-    <AppDesignerFolder>Properties</AppDesignerFolder>
-    <RootNamespace>Grpc.HealthCheck.Tests</RootNamespace>
+    <TargetFrameworks>net45;netcoreapp1.0</TargetFrameworks>
     <AssemblyName>Grpc.HealthCheck.Tests</AssemblyName>
-    <TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
-    <FileAlignment>512</FileAlignment>
-  </PropertyGroup>
-  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
-    <DebugSymbols>true</DebugSymbols>
-    <DebugType>full</DebugType>
-    <Optimize>false</Optimize>
-    <OutputPath>bin\Debug\</OutputPath>
-    <ErrorReport>prompt</ErrorReport>
-    <WarningLevel>4</WarningLevel>
-  </PropertyGroup>
-  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
-    <DebugType>pdbonly</DebugType>
-    <Optimize>true</Optimize>
-    <OutputPath>bin\Release\</OutputPath>
-    <ErrorReport>prompt</ErrorReport>
-    <WarningLevel>4</WarningLevel>
+    <OutputType>Exe</OutputType>
+    <PackageId>Grpc.HealthCheck.Tests</PackageId>
+    <PackageTargetFallback Condition=" '$(TargetFramework)' == 'netcoreapp1.0' ">$(PackageTargetFallback);portable-net45</PackageTargetFallback>
+    <RuntimeFrameworkVersion Condition=" '$(TargetFramework)' == 'netcoreapp1.0' ">1.0.4</RuntimeFrameworkVersion>
   </PropertyGroup>
+
   <ItemGroup>
-    <Reference Include="System" />
-    <Reference Include="System.Core" />
-    <Reference Include="System.Xml.Linq" />
-    <Reference Include="System.Data.DataSetExtensions" />
-    <Reference Include="Microsoft.CSharp" />
-    <Reference Include="System.Data" />
-    <Reference Include="System.Xml" />
-    <Reference Include="Google.Protobuf">
-      <HintPath>..\packages\Google.Protobuf.3.2.0\lib\net45\Google.Protobuf.dll</HintPath>
-    </Reference>
-    <Reference Include="nunit.framework">
-      <HintPath>..\packages\NUnit.3.6.0\lib\net45\nunit.framework.dll</HintPath>
-    </Reference>
-    <Reference Include="nunitlite">
-      <HintPath>..\packages\NUnitLite.3.6.0\lib\net45\nunitlite.dll</HintPath>
-    </Reference>
+    <ProjectReference Include="../Grpc.HealthCheck/Grpc.HealthCheck.csproj" />
   </ItemGroup>
+
   <ItemGroup>
-    <Compile Include="..\Grpc.Core\Version.cs">
-      <Link>Version.cs</Link>
-    </Compile>
-    <Compile Include="HealthServiceImplTest.cs" />
-    <Compile Include="HealthClientServerTest.cs" />
-    <Compile Include="Properties\AssemblyInfo.cs" />
-    <Compile Include="NUnitMain.cs" />
+    <PackageReference Include="NUnit" Version="3.6.0" />
+    <PackageReference Include="NUnitLite" Version="3.6.0" />
   </ItemGroup>
-  <ItemGroup>
-    <ProjectReference Include="..\Grpc.Core\Grpc.Core.csproj">
-      <Project>{CCC4440E-49F7-4790-B0AF-FEABB0837AE7}</Project>
-      <Name>Grpc.Core</Name>
-    </ProjectReference>
-    <ProjectReference Include="..\Grpc.HealthCheck\Grpc.HealthCheck.csproj">
-      <Project>{AA5E328A-8835-49D7-98ED-C29F2B3049F0}</Project>
-      <Name>Grpc.HealthCheck</Name>
-    </ProjectReference>
-  </ItemGroup>
-  <ItemGroup>
-    <None Include="Grpc.HealthCheck.Tests.project.json" />
-    <None Include="packages.config" />
+
+  <ItemGroup Condition=" '$(TargetFramework)' == 'net45' ">
+    <Reference Include="System" />
+    <Reference Include="Microsoft.CSharp" />
   </ItemGroup>
+
   <ItemGroup>
-    <Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" />
+    <Compile Include="..\Grpc.Core\Version.cs" />
   </ItemGroup>
-  <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
-  <!-- To modify your build process, add your task inside one of the targets below and uncomment it. 
-       Other similar extension points exist, see Microsoft.Common.targets.
-  <Target Name="BeforeBuild">
-  </Target>
-  <Target Name="AfterBuild">
-  </Target>
-  -->
-</Project>
\ No newline at end of file
+
+</Project>
diff --git a/src/csharp/Grpc.HealthCheck.Tests/Grpc.HealthCheck.Tests.project.json b/src/csharp/Grpc.HealthCheck.Tests/Grpc.HealthCheck.Tests.project.json
deleted file mode 100644
index c2f5bcb1637badadff8959d672e04c942cb54d51..0000000000000000000000000000000000000000
--- a/src/csharp/Grpc.HealthCheck.Tests/Grpc.HealthCheck.Tests.project.json
+++ /dev/null
@@ -1,8 +0,0 @@
-{
-  "frameworks": {
-    "net45": { }
-  },
-  "runtimes": {
-    "win": { }
-  }
-}
diff --git a/src/csharp/Grpc.HealthCheck.Tests/Grpc.HealthCheck.Tests.xproj b/src/csharp/Grpc.HealthCheck.Tests/Grpc.HealthCheck.Tests.xproj
deleted file mode 100644
index 724c5b2a160503866b01320b904fa151e660b6de..0000000000000000000000000000000000000000
--- a/src/csharp/Grpc.HealthCheck.Tests/Grpc.HealthCheck.Tests.xproj
+++ /dev/null
@@ -1,18 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<Project ToolsVersion="14.0.25123" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
-  <PropertyGroup>
-    <VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">14.0.25123</VisualStudioVersion>
-    <VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
-  </PropertyGroup>
-  <Import Project="$(VSToolsPath)\DNX\Microsoft.DNX.Props" Condition="'$(VSToolsPath)' != ''" />
-  <PropertyGroup Label="Globals">
-    <ProjectGuid>43dafac6-5343-4621-960e-a8a977ea3f0b</ProjectGuid>
-    <RootNamespace>Grpc.HealthCheck.Tests</RootNamespace>
-    <BaseIntermediateOutputPath Condition="'$(BaseIntermediateOutputPath)'=='' ">..\artifacts\obj\$(MSBuildProjectName)</BaseIntermediateOutputPath>
-    <OutputPath Condition="'$(OutputPath)'=='' ">.\bin\</OutputPath>
-  </PropertyGroup>
-  <PropertyGroup>
-    <SchemaVersion>2.0</SchemaVersion>
-  </PropertyGroup>
-  <Import Project="$(VSToolsPath)\DNX\Microsoft.DNX.targets" Condition="'$(VSToolsPath)' != ''" />
-</Project>
\ No newline at end of file
diff --git a/src/csharp/Grpc.HealthCheck.Tests/packages.config b/src/csharp/Grpc.HealthCheck.Tests/packages.config
deleted file mode 100644
index 48c94bc4a301092ccf7d51119f38ec8f01374fcb..0000000000000000000000000000000000000000
--- a/src/csharp/Grpc.HealthCheck.Tests/packages.config
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<packages>
-  <package id="Google.Protobuf" version="3.2.0" targetFramework="net45" />
-  <package id="NUnit" version="3.6.0" targetFramework="net45" />
-  <package id="NUnitLite" version="3.6.0" targetFramework="net45" />
-</packages>
\ No newline at end of file
diff --git a/src/csharp/Grpc.HealthCheck.Tests/project.json b/src/csharp/Grpc.HealthCheck.Tests/project.json
deleted file mode 100644
index 2814cbfe4661a1ed7a9db106709287d0fae40497..0000000000000000000000000000000000000000
--- a/src/csharp/Grpc.HealthCheck.Tests/project.json
+++ /dev/null
@@ -1,65 +0,0 @@
-{
-  "buildOptions": {
-    "emitEntryPoint": true
-  },
-  "configurations": {
-    "Debug": {
-      "buildOptions": {
-        "define": [ "SIGNED" ],
-        "keyFile": "../keys/Grpc.snk",
-        "xmlDoc": true,
-        "compile": {
-          "includeFiles": [ "../Grpc.Core/Version.cs" ]
-        },
-        "copyToOutput": {
-          "mappings": {
-            "grpc_csharp_ext.x64.dll": "../../../cmake/build/x64/Debug/grpc_csharp_ext.dll",
-            "grpc_csharp_ext.x86.dll": "../../../cmake/build/Win32/Debug/grpc_csharp_ext.dll",
-            "libgrpc_csharp_ext.x64.so": "../../../libs/dbg/libgrpc_csharp_ext.so",
-            "libgrpc_csharp_ext.x64.dylib": "../../../libs/dbg/libgrpc_csharp_ext.dylib"
-          }
-        }
-      }
-    },
-    "Release": {
-      "buildOptions": {
-        "define": [ "SIGNED" ],
-        "keyFile": "../keys/Grpc.snk",
-        "xmlDoc": true,
-        "compile": {
-          "includeFiles": [ "../Grpc.Core/Version.cs" ]
-        },
-        "copyToOutput": {
-          "mappings": {
-            "grpc_csharp_ext.x64.dll": "../../../cmake/build/x64/Release/grpc_csharp_ext.dll",
-            "grpc_csharp_ext.x86.dll": "../../../cmake/build/Win32/Release/grpc_csharp_ext.dll",
-            "libgrpc_csharp_ext.x64.so": "../../../libs/opt/libgrpc_csharp_ext.so",
-            "libgrpc_csharp_ext.x64.dylib": "../../../libs/opt/libgrpc_csharp_ext.dylib"
-          }
-        }
-      }
-    }
-  },
-
-  "dependencies": {
-    "Grpc.HealthCheck": {
-      "target": "project"
-    },
-    "NUnit": "3.6.0",
-    "NUnitLite": "3.6.0"
-  },
-  "frameworks": {
-    "net45": { },
-    "netcoreapp1.0": {
-      "imports": [
-        "portable-net45"
-      ],
-      "dependencies": {
-        "Microsoft.NETCore.App": {
-          "type": "platform",
-          "version": "1.0.0"
-        }
-      }
-    }
-  }
-}
diff --git a/src/csharp/Grpc.HealthCheck/Grpc.HealthCheck.csproj b/src/csharp/Grpc.HealthCheck/Grpc.HealthCheck.csproj
old mode 100644
new mode 100755
index 171525b708685e1a2db2767f7d2500b9a846ecdd..eac6e1fc95ff6d2cd348f18f9d4836293e0945ea
--- a/src/csharp/Grpc.HealthCheck/Grpc.HealthCheck.csproj
+++ b/src/csharp/Grpc.HealthCheck/Grpc.HealthCheck.csproj
@@ -1,73 +1,37 @@
-<?xml version="1.0" encoding="utf-8"?>
-<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
-  <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
+<Project Sdk="Microsoft.NET.Sdk">
+
+  <Import Project="..\Grpc.Core\Version.csproj.include" />
+  <Import Project="..\Grpc.Core\Common.csproj.include" />
+
   <PropertyGroup>
-    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
-    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
-    <ProjectGuid>{AA5E328A-8835-49D7-98ED-C29F2B3049F0}</ProjectGuid>
-    <OutputType>Library</OutputType>
-    <AppDesignerFolder>Properties</AppDesignerFolder>
-    <RootNamespace>Grpc.HealthCheck</RootNamespace>
+    <Copyright>Copyright 2015, Google Inc.</Copyright>
+    <AssemblyTitle>gRPC C# Healthchecking</AssemblyTitle>
+    <VersionPrefix>$(GrpcCsharpVersion)</VersionPrefix>
+    <Authors>Google Inc.</Authors>
+    <TargetFrameworks>net45;netstandard1.5</TargetFrameworks>
     <AssemblyName>Grpc.HealthCheck</AssemblyName>
-    <TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
-    <FileAlignment>512</FileAlignment>
-    <DocumentationFile>bin\$(Configuration)\Grpc.HealthCheck.Xml</DocumentationFile>
-  </PropertyGroup>
-  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
-    <DebugSymbols>true</DebugSymbols>
-    <DebugType>full</DebugType>
-    <Optimize>false</Optimize>
-    <OutputPath>bin\Debug\</OutputPath>
-    <ErrorReport>prompt</ErrorReport>
-    <WarningLevel>4</WarningLevel>
-  </PropertyGroup>
-  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
-    <DebugType>pdbonly</DebugType>
-    <Optimize>true</Optimize>
-    <OutputPath>bin\Release\</OutputPath>
-    <ErrorReport>prompt</ErrorReport>
-    <WarningLevel>4</WarningLevel>
+    <PackageId>Grpc.HealthCheck</PackageId>
+    <PackageTags>gRPC health check</PackageTags>
+    <PackageProjectUrl>https://github.com/grpc/grpc</PackageProjectUrl>
+    <PackageLicenseUrl>https://github.com/grpc/grpc/blob/master/LICENSE</PackageLicenseUrl>
+    <NetStandardImplicitPackageVersion Condition=" '$(TargetFramework)' == 'netstandard1.5' ">1.6.0</NetStandardImplicitPackageVersion>
   </PropertyGroup>
+
   <ItemGroup>
-    <Reference Include="System" />
-    <Reference Include="System.Core" />
-    <Reference Include="System.Xml.Linq" />
-    <Reference Include="System.Data.DataSetExtensions" />
-    <Reference Include="Microsoft.CSharp" />
-    <Reference Include="System.Data" />
-    <Reference Include="System.Xml" />
-    <Reference Include="System.Interactive.Async">
-      <HintPath>..\packages\System.Interactive.Async.3.1.1\lib\net45\System.Interactive.Async.dll</HintPath>
-    </Reference>
-    <Reference Include="Google.Protobuf">
-      <HintPath>..\packages\Google.Protobuf.3.2.0\lib\net45\Google.Protobuf.dll</HintPath>
-    </Reference>
+    <Compile Include="..\Grpc.Core\Version.cs" />
   </ItemGroup>
+
   <ItemGroup>
-    <Compile Include="..\Grpc.Core\Version.cs">
-      <Link>Version.cs</Link>
-    </Compile>
-    <Compile Include="HealthServiceImpl.cs" />
-    <Compile Include="Health.cs" />
-    <Compile Include="HealthGrpc.cs" />
-    <Compile Include="Properties\AssemblyInfo.cs" />
+    <ProjectReference Include="../Grpc.Core/Grpc.Core.csproj" />
   </ItemGroup>
+
   <ItemGroup>
-    <None Include="Grpc.HealthCheck.project.json" />
-    <None Include="packages.config" />
+    <PackageReference Include="Google.Protobuf" Version="$(GoogleProtobufVersion)" />
   </ItemGroup>
-  <ItemGroup>
-    <ProjectReference Include="..\Grpc.Core\Grpc.Core.csproj">
-      <Project>{CCC4440E-49F7-4790-B0AF-FEABB0837AE7}</Project>
-      <Name>Grpc.Core</Name>
-    </ProjectReference>
+
+  <ItemGroup Condition=" '$(TargetFramework)' == 'net45' ">
+    <Reference Include="System" />
+    <Reference Include="Microsoft.CSharp" />
   </ItemGroup>
-  <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
-  <!-- To modify your build process, add your task inside one of the targets below and uncomment it. 
-       Other similar extension points exist, see Microsoft.Common.targets.
-  <Target Name="BeforeBuild">
-  </Target>
-  <Target Name="AfterBuild">
-  </Target>
-  -->
+
 </Project>
diff --git a/src/csharp/Grpc.HealthCheck/Grpc.HealthCheck.project.json b/src/csharp/Grpc.HealthCheck/Grpc.HealthCheck.project.json
deleted file mode 100644
index c2f5bcb1637badadff8959d672e04c942cb54d51..0000000000000000000000000000000000000000
--- a/src/csharp/Grpc.HealthCheck/Grpc.HealthCheck.project.json
+++ /dev/null
@@ -1,8 +0,0 @@
-{
-  "frameworks": {
-    "net45": { }
-  },
-  "runtimes": {
-    "win": { }
-  }
-}
diff --git a/src/csharp/Grpc.HealthCheck/Grpc.HealthCheck.xproj b/src/csharp/Grpc.HealthCheck/Grpc.HealthCheck.xproj
deleted file mode 100644
index 5806a7af979bb71350fdbb8c3e741387f6c756c4..0000000000000000000000000000000000000000
--- a/src/csharp/Grpc.HealthCheck/Grpc.HealthCheck.xproj
+++ /dev/null
@@ -1,18 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<Project ToolsVersion="14.0.25123" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
-  <PropertyGroup>
-    <VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">14.0.25123</VisualStudioVersion>
-    <VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
-  </PropertyGroup>
-  <Import Project="$(VSToolsPath)\DNX\Microsoft.DNX.Props" Condition="'$(VSToolsPath)' != ''" />
-  <PropertyGroup Label="Globals">
-    <ProjectGuid>3be4ad0b-2bf0-4d68-b625-f6018ef0dcfa</ProjectGuid>
-    <RootNamespace>Grpc.HealthCheck</RootNamespace>
-    <BaseIntermediateOutputPath Condition="'$(BaseIntermediateOutputPath)'=='' ">..\artifacts\obj\$(MSBuildProjectName)</BaseIntermediateOutputPath>
-    <OutputPath Condition="'$(OutputPath)'=='' ">.\bin\</OutputPath>
-  </PropertyGroup>
-  <PropertyGroup>
-    <SchemaVersion>2.0</SchemaVersion>
-  </PropertyGroup>
-  <Import Project="$(VSToolsPath)\DNX\Microsoft.DNX.targets" Condition="'$(VSToolsPath)' != ''" />
-</Project>
\ No newline at end of file
diff --git a/src/csharp/Grpc.HealthCheck/packages.config b/src/csharp/Grpc.HealthCheck/packages.config
deleted file mode 100644
index eec292b306d776ae4d6fdf583476ac63c3973c81..0000000000000000000000000000000000000000
--- a/src/csharp/Grpc.HealthCheck/packages.config
+++ /dev/null
@@ -1,5 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<packages>
-  <package id="Google.Protobuf" version="3.2.0" targetFramework="net45" />
-  <package id="System.Interactive.Async" version="3.1.1" targetFramework="net45" />
-</packages>
\ No newline at end of file
diff --git a/src/csharp/Grpc.IntegrationTesting.Client/Grpc.IntegrationTesting.Client.csproj b/src/csharp/Grpc.IntegrationTesting.Client/Grpc.IntegrationTesting.Client.csproj
old mode 100644
new mode 100755
index a793f3f6df8ad3d11b4f433580f93e2ee931e4a5..dcb24c721668b3380829c903ffc020ff508fd3ca
--- a/src/csharp/Grpc.IntegrationTesting.Client/Grpc.IntegrationTesting.Client.csproj
+++ b/src/csharp/Grpc.IntegrationTesting.Client/Grpc.IntegrationTesting.Client.csproj
@@ -1,59 +1,28 @@
-<?xml version="1.0" encoding="utf-8"?>
-<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+<Project Sdk="Microsoft.NET.Sdk">
+
+  <Import Project="..\Grpc.Core\Version.csproj.include" />
+  <Import Project="..\Grpc.Core\Common.csproj.include" />
+
   <PropertyGroup>
-    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
-    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
-    <ProjectGuid>{3D166931-BA2D-416E-95A3-D36E8F6E90B9}</ProjectGuid>
-    <OutputType>Exe</OutputType>
-    <RootNamespace>Grpc.IntegrationTesting.Client</RootNamespace>
+    <TargetFrameworks>net45;netcoreapp1.0</TargetFrameworks>
     <AssemblyName>Grpc.IntegrationTesting.Client</AssemblyName>
-    <StartupObject>Grpc.IntegrationTesting.Client.Program</StartupObject>
-    <TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
-    <NuGetPackageImportStamp>dfa56e6c</NuGetPackageImportStamp>
-  </PropertyGroup>
-  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
-    <DebugSymbols>true</DebugSymbols>
-    <DebugType>full</DebugType>
-    <Optimize>false</Optimize>
-    <OutputPath>bin\Debug</OutputPath>
-    <DefineConstants>DEBUG;</DefineConstants>
-    <ErrorReport>prompt</ErrorReport>
-    <WarningLevel>4</WarningLevel>
-    <PlatformTarget>AnyCPU</PlatformTarget>
-  </PropertyGroup>
-  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
-    <DebugType>pdbonly</DebugType>
-    <Optimize>true</Optimize>
-    <OutputPath>bin\Release</OutputPath>
-    <ErrorReport>prompt</ErrorReport>
-    <WarningLevel>4</WarningLevel>
-    <PlatformTarget>AnyCPU</PlatformTarget>
+    <OutputType>Exe</OutputType>
+    <PackageId>Grpc.IntegrationTesting.Client</PackageId>
+    <PackageTargetFallback Condition=" '$(TargetFramework)' == 'netcoreapp1.0' ">$(PackageTargetFallback);portable-net45</PackageTargetFallback>
+    <RuntimeFrameworkVersion Condition=" '$(TargetFramework)' == 'netcoreapp1.0' ">1.0.4</RuntimeFrameworkVersion>
   </PropertyGroup>
+
   <ItemGroup>
-    <Reference Include="System" />
-    <Reference Include="System.Net" />
-    <Reference Include="System.Net.Http" />
-    <Reference Include="System.Net.Http.WebRequest" />
+    <ProjectReference Include="../Grpc.IntegrationTesting/Grpc.IntegrationTesting.csproj" />
   </ItemGroup>
-  <ItemGroup>
-    <Compile Include="..\Grpc.Core\Version.cs">
-      <Link>Version.cs</Link>
-    </Compile>
-    <Compile Include="Program.cs" />
-    <Compile Include="Properties\AssemblyInfo.cs" />
-  </ItemGroup>
-  <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
-  <ItemGroup>
-    <ProjectReference Include="..\Grpc.IntegrationTesting\Grpc.IntegrationTesting.csproj">
-      <Project>{C61154BA-DD4A-4838-8420-0162A28925E0}</Project>
-      <Name>Grpc.IntegrationTesting</Name>
-    </ProjectReference>
-    <ProjectReference Include="..\Grpc.Core\Grpc.Core.csproj">
-      <Project>{CCC4440E-49F7-4790-B0AF-FEABB0837AE7}</Project>
-      <Name>Grpc.Core</Name>
-    </ProjectReference>
+
+  <ItemGroup Condition=" '$(TargetFramework)' == 'net45' ">
+    <Reference Include="System" />
+    <Reference Include="Microsoft.CSharp" />
   </ItemGroup>
+
   <ItemGroup>
-    <None Include="Grpc.IntegrationTesting.Client.project.json" />
+    <Compile Include="..\Grpc.Core\Version.cs" />
   </ItemGroup>
-</Project>
\ No newline at end of file
+
+</Project>
diff --git a/src/csharp/Grpc.IntegrationTesting.Client/Grpc.IntegrationTesting.Client.project.json b/src/csharp/Grpc.IntegrationTesting.Client/Grpc.IntegrationTesting.Client.project.json
deleted file mode 100644
index c2f5bcb1637badadff8959d672e04c942cb54d51..0000000000000000000000000000000000000000
--- a/src/csharp/Grpc.IntegrationTesting.Client/Grpc.IntegrationTesting.Client.project.json
+++ /dev/null
@@ -1,8 +0,0 @@
-{
-  "frameworks": {
-    "net45": { }
-  },
-  "runtimes": {
-    "win": { }
-  }
-}
diff --git a/src/csharp/Grpc.IntegrationTesting.Client/Grpc.IntegrationTesting.Client.xproj b/src/csharp/Grpc.IntegrationTesting.Client/Grpc.IntegrationTesting.Client.xproj
deleted file mode 100644
index 7f456cfaef1f6af687091aa05bdb0672c211227c..0000000000000000000000000000000000000000
--- a/src/csharp/Grpc.IntegrationTesting.Client/Grpc.IntegrationTesting.Client.xproj
+++ /dev/null
@@ -1,18 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<Project ToolsVersion="14.0.25123" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
-  <PropertyGroup>
-    <VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">14.0.25123</VisualStudioVersion>
-    <VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
-  </PropertyGroup>
-  <Import Project="$(VSToolsPath)\DNX\Microsoft.DNX.Props" Condition="'$(VSToolsPath)' != ''" />
-  <PropertyGroup Label="Globals">
-    <ProjectGuid>48ea5bbe-70e2-4198-869d-d7e59c45f30d</ProjectGuid>
-    <RootNamespace>Grpc.IntegrationTesting.Client</RootNamespace>
-    <BaseIntermediateOutputPath Condition="'$(BaseIntermediateOutputPath)'=='' ">..\artifacts\obj\$(MSBuildProjectName)</BaseIntermediateOutputPath>
-    <OutputPath Condition="'$(OutputPath)'=='' ">.\bin\</OutputPath>
-  </PropertyGroup>
-  <PropertyGroup>
-    <SchemaVersion>2.0</SchemaVersion>
-  </PropertyGroup>
-  <Import Project="$(VSToolsPath)\DNX\Microsoft.DNX.targets" Condition="'$(VSToolsPath)' != ''" />
-</Project>
\ No newline at end of file
diff --git a/src/csharp/Grpc.IntegrationTesting.Client/project.json b/src/csharp/Grpc.IntegrationTesting.Client/project.json
deleted file mode 100644
index f90528151b4519b9dd5a63660fc71e157d0052a2..0000000000000000000000000000000000000000
--- a/src/csharp/Grpc.IntegrationTesting.Client/project.json
+++ /dev/null
@@ -1,69 +0,0 @@
-{
-  "buildOptions": {
-    "emitEntryPoint": true
-  },
-  "configurations": {
-    "Debug": {
-      "buildOptions": {
-        "define": [ "SIGNED" ],
-        "keyFile": "../keys/Grpc.snk",
-        "xmlDoc": true,
-        "compile": {
-          "includeFiles": [ "../Grpc.Core/Version.cs" ]
-        },
-        "copyToOutput": {
-          "mappings": {
-            "data/ca.pem": "../Grpc.IntegrationTesting/data/ca.pem",
-            "data/server1.key": "../Grpc.IntegrationTesting/data/server1.key",
-            "data/server1.pem": "../Grpc.IntegrationTesting/data/server1.pem",
-            "grpc_csharp_ext.x64.dll": "../../../cmake/build/x64/Debug/grpc_csharp_ext.dll",
-            "grpc_csharp_ext.x86.dll": "../../../cmake/build/Win32/Debug/grpc_csharp_ext.dll",
-            "libgrpc_csharp_ext.x64.so": "../../../libs/dbg/libgrpc_csharp_ext.so",
-            "libgrpc_csharp_ext.x64.dylib": "../../../libs/dbg/libgrpc_csharp_ext.dylib"
-          }
-        }
-      }
-    },
-    "Release": {
-      "buildOptions": {
-        "define": [ "SIGNED" ],
-        "keyFile": "../keys/Grpc.snk",
-        "xmlDoc": true,
-        "compile": {
-          "includeFiles": [ "../Grpc.Core/Version.cs" ]
-        },
-        "copyToOutput": {
-          "mappings": {
-            "data/ca.pem": "../Grpc.IntegrationTesting/data/ca.pem",
-            "data/server1.key": "../Grpc.IntegrationTesting/data/server1.key",
-            "data/server1.pem": "../Grpc.IntegrationTesting/data/server1.pem",
-            "grpc_csharp_ext.x64.dll": "../../../cmake/build/x64/Release/grpc_csharp_ext.dll",
-            "grpc_csharp_ext.x86.dll": "../../../cmake/build/Win32/Release/grpc_csharp_ext.dll",
-            "libgrpc_csharp_ext.x64.so": "../../../libs/opt/libgrpc_csharp_ext.so",
-            "libgrpc_csharp_ext.x64.dylib": "../../../libs/opt/libgrpc_csharp_ext.dylib"
-          }
-        }
-      }
-    }
-  },
-
-  "dependencies": {
-    "Grpc.IntegrationTesting": {
-      "target": "project"
-    }
-  },
-  "frameworks": {
-    "net45": { },
-    "netcoreapp1.0": {
-      "imports": [
-        "portable-net45"
-      ],
-      "dependencies": {
-        "Microsoft.NETCore.App": {
-          "type": "platform",
-          "version": "1.0.0"
-        }
-      }
-    }
-  }
-}
diff --git a/src/csharp/Grpc.IntegrationTesting.QpsWorker/Grpc.IntegrationTesting.QpsWorker.csproj b/src/csharp/Grpc.IntegrationTesting.QpsWorker/Grpc.IntegrationTesting.QpsWorker.csproj
old mode 100644
new mode 100755
index 3b9587e31518a35e117e193d2bb769304311c1f1..43772020d6f105b20d9346d7d61a4f71ae8b7aeb
--- a/src/csharp/Grpc.IntegrationTesting.QpsWorker/Grpc.IntegrationTesting.QpsWorker.csproj
+++ b/src/csharp/Grpc.IntegrationTesting.QpsWorker/Grpc.IntegrationTesting.QpsWorker.csproj
@@ -1,54 +1,29 @@
-<?xml version="1.0" encoding="utf-8"?>
-<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+<Project Sdk="Microsoft.NET.Sdk">
+
+  <Import Project="..\Grpc.Core\Version.csproj.include" />
+  <Import Project="..\Grpc.Core\Common.csproj.include" />
+
   <PropertyGroup>
-    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
-    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
-    <ProjectGuid>{B82B7DFE-7F7B-40EF-B3D6-064FF2B01294}</ProjectGuid>
-    <OutputType>Exe</OutputType>
-    <RootNamespace>Grpc.IntegrationTesting.QpsWorker</RootNamespace>
+    <TargetFrameworks>net45;netcoreapp1.0</TargetFrameworks>
     <AssemblyName>Grpc.IntegrationTesting.QpsWorker</AssemblyName>
-    <TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
-  </PropertyGroup>
-  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
-    <DebugSymbols>true</DebugSymbols>
-    <DebugType>full</DebugType>
-    <Optimize>false</Optimize>
-    <OutputPath>bin\Debug</OutputPath>
-    <DefineConstants>DEBUG;</DefineConstants>
-    <ErrorReport>prompt</ErrorReport>
-    <WarningLevel>4</WarningLevel>
-    <PlatformTarget>AnyCPU</PlatformTarget>
-  </PropertyGroup>
-  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
-    <DebugType>pdbonly</DebugType>
-    <Optimize>true</Optimize>
-    <OutputPath>bin\Release</OutputPath>
-    <ErrorReport>prompt</ErrorReport>
-    <WarningLevel>4</WarningLevel>
-    <PlatformTarget>AnyCPU</PlatformTarget>
+    <OutputType>Exe</OutputType>
+    <PackageId>Grpc.IntegrationTesting.QpsWorker</PackageId>
+    <ServerGarbageCollection>true</ServerGarbageCollection>
+    <PackageTargetFallback Condition=" '$(TargetFramework)' == 'netcoreapp1.0' ">$(PackageTargetFallback);portable-net45</PackageTargetFallback>
+    <RuntimeFrameworkVersion Condition=" '$(TargetFramework)' == 'netcoreapp1.0' ">1.0.4</RuntimeFrameworkVersion>
   </PropertyGroup>
+
   <ItemGroup>
-    <Reference Include="System" />
+    <ProjectReference Include="../Grpc.IntegrationTesting/Grpc.IntegrationTesting.csproj" />
   </ItemGroup>
-  <ItemGroup>
-    <Compile Include="..\Grpc.Core\Version.cs">
-      <Link>Version.cs</Link>
-    </Compile>
-    <Compile Include="Program.cs" />
-    <Compile Include="Properties\AssemblyInfo.cs" />
-  </ItemGroup>
-  <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
-  <ItemGroup>
-    <ProjectReference Include="..\Grpc.Core\Grpc.Core.csproj">
-      <Project>{CCC4440E-49F7-4790-B0AF-FEABB0837AE7}</Project>
-      <Name>Grpc.Core</Name>
-    </ProjectReference>
-    <ProjectReference Include="..\Grpc.IntegrationTesting\Grpc.IntegrationTesting.csproj">
-      <Project>{C61154BA-DD4A-4838-8420-0162A28925E0}</Project>
-      <Name>Grpc.IntegrationTesting</Name>
-    </ProjectReference>
+
+  <ItemGroup Condition=" '$(TargetFramework)' == 'net45' ">
+    <Reference Include="System" />
+    <Reference Include="Microsoft.CSharp" />
   </ItemGroup>
+
   <ItemGroup>
-    <None Include="Grpc.IntegrationTesting.QpsWorker.project.json" />
+    <Compile Include="..\Grpc.Core\Version.cs" />
   </ItemGroup>
-</Project>
\ No newline at end of file
+
+</Project>
diff --git a/src/csharp/Grpc.IntegrationTesting.QpsWorker/Grpc.IntegrationTesting.QpsWorker.project.json b/src/csharp/Grpc.IntegrationTesting.QpsWorker/Grpc.IntegrationTesting.QpsWorker.project.json
deleted file mode 100644
index c2f5bcb1637badadff8959d672e04c942cb54d51..0000000000000000000000000000000000000000
--- a/src/csharp/Grpc.IntegrationTesting.QpsWorker/Grpc.IntegrationTesting.QpsWorker.project.json
+++ /dev/null
@@ -1,8 +0,0 @@
-{
-  "frameworks": {
-    "net45": { }
-  },
-  "runtimes": {
-    "win": { }
-  }
-}
diff --git a/src/csharp/Grpc.IntegrationTesting.QpsWorker/Grpc.IntegrationTesting.QpsWorker.xproj b/src/csharp/Grpc.IntegrationTesting.QpsWorker/Grpc.IntegrationTesting.QpsWorker.xproj
deleted file mode 100644
index 15bec443d6c0d332e2f17ba80df1cf923aac02ed..0000000000000000000000000000000000000000
--- a/src/csharp/Grpc.IntegrationTesting.QpsWorker/Grpc.IntegrationTesting.QpsWorker.xproj
+++ /dev/null
@@ -1,18 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<Project ToolsVersion="14.0.25123" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
-  <PropertyGroup>
-    <VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">14.0.25123</VisualStudioVersion>
-    <VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
-  </PropertyGroup>
-  <Import Project="$(VSToolsPath)\DNX\Microsoft.DNX.Props" Condition="'$(VSToolsPath)' != ''" />
-  <PropertyGroup Label="Globals">
-    <ProjectGuid>661b70d7-f56a-46e0-9b81-6227b591b5e7</ProjectGuid>
-    <RootNamespace>Grpc.IntegrationTesting.QpsWorker</RootNamespace>
-    <BaseIntermediateOutputPath Condition="'$(BaseIntermediateOutputPath)'=='' ">..\artifacts\obj\$(MSBuildProjectName)</BaseIntermediateOutputPath>
-    <OutputPath Condition="'$(OutputPath)'=='' ">.\bin\</OutputPath>
-  </PropertyGroup>
-  <PropertyGroup>
-    <SchemaVersion>2.0</SchemaVersion>
-  </PropertyGroup>
-  <Import Project="$(VSToolsPath)\DNX\Microsoft.DNX.targets" Condition="'$(VSToolsPath)' != ''" />
-</Project>
\ No newline at end of file
diff --git a/src/csharp/Grpc.IntegrationTesting.QpsWorker/project.json b/src/csharp/Grpc.IntegrationTesting.QpsWorker/project.json
deleted file mode 100644
index 161e602abcab260288517890dee18588721ce455..0000000000000000000000000000000000000000
--- a/src/csharp/Grpc.IntegrationTesting.QpsWorker/project.json
+++ /dev/null
@@ -1,74 +0,0 @@
-{
-  "buildOptions": {
-    "emitEntryPoint": true
-  },
-  "configurations": {
-    "Debug": {
-      "buildOptions": {
-        "define": [ "SIGNED" ],
-        "keyFile": "../keys/Grpc.snk",
-        "xmlDoc": true,
-        "compile": {
-          "includeFiles": [ "../Grpc.Core/Version.cs" ]
-        },
-        "copyToOutput": {
-          "mappings": {
-            "data/ca.pem": "../Grpc.IntegrationTesting/data/ca.pem",
-            "data/server1.key": "../Grpc.IntegrationTesting/data/server1.key",
-            "data/server1.pem": "../Grpc.IntegrationTesting/data/server1.pem",
-            "grpc_csharp_ext.x64.dll": "../../../cmake/build/x64/Debug/grpc_csharp_ext.dll",
-            "grpc_csharp_ext.x86.dll": "../../../cmake/build/Win32/Debug/grpc_csharp_ext.dll",
-            "libgrpc_csharp_ext.x64.so": "../../../libs/dbg/libgrpc_csharp_ext.so",
-            "libgrpc_csharp_ext.x64.dylib": "../../../libs/dbg/libgrpc_csharp_ext.dylib"
-          }
-        }
-      }
-    },
-    "Release": {
-      "buildOptions": {
-        "define": [ "SIGNED" ],
-        "keyFile": "../keys/Grpc.snk",
-        "xmlDoc": true,
-        "compile": {
-          "includeFiles": [ "../Grpc.Core/Version.cs" ]
-        },
-        "copyToOutput": {
-          "mappings": {
-            "data/ca.pem": "../Grpc.IntegrationTesting/data/ca.pem",
-            "data/server1.key": "../Grpc.IntegrationTesting/data/server1.key",
-            "data/server1.pem": "../Grpc.IntegrationTesting/data/server1.pem",
-            "grpc_csharp_ext.x64.dll": "../../../cmake/build/x64/Release/grpc_csharp_ext.dll",
-            "grpc_csharp_ext.x86.dll": "../../../cmake/build/Win32/Release/grpc_csharp_ext.dll",
-            "libgrpc_csharp_ext.x64.so": "../../../libs/opt/libgrpc_csharp_ext.so",
-            "libgrpc_csharp_ext.x64.dylib": "../../../libs/opt/libgrpc_csharp_ext.dylib"
-          }
-        }
-      }
-    }
-  },
-
-  "dependencies": {
-    "Grpc.IntegrationTesting": {
-      "target": "project"
-    }
-  },
-  "frameworks": {
-    "net45": { },
-    "netcoreapp1.0": {
-      "imports": [
-        "portable-net45"
-      ],
-      "dependencies": {
-        "Microsoft.NETCore.App": {
-          "type": "platform",
-          "version": "1.0.0"
-        }
-      }
-    }
-  },
-  "runtimeOptions": {
-    "configProperties": {
-      "System.GC.Server": true
-    }
-  }
-}
diff --git a/src/csharp/Grpc.IntegrationTesting.Server/Grpc.IntegrationTesting.Server.csproj b/src/csharp/Grpc.IntegrationTesting.Server/Grpc.IntegrationTesting.Server.csproj
old mode 100644
new mode 100755
index 80d36363f71f08a7760e471cabd5a913f9fd1433..db736baed0556a309f8f0b0c9e0b588c9d661ce5
--- a/src/csharp/Grpc.IntegrationTesting.Server/Grpc.IntegrationTesting.Server.csproj
+++ b/src/csharp/Grpc.IntegrationTesting.Server/Grpc.IntegrationTesting.Server.csproj
@@ -1,59 +1,28 @@
-<?xml version="1.0" encoding="utf-8"?>
-<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+<Project Sdk="Microsoft.NET.Sdk">
+
+  <Import Project="..\Grpc.Core\Version.csproj.include" />
+  <Import Project="..\Grpc.Core\Common.csproj.include" />
+
   <PropertyGroup>
-    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
-    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
-    <ProjectGuid>{A654F3B8-E859-4E6A-B30D-227527DBEF0D}</ProjectGuid>
-    <OutputType>Exe</OutputType>
-    <RootNamespace>Grpc.IntegrationTesting.Server</RootNamespace>
+    <TargetFrameworks>net45;netcoreapp1.0</TargetFrameworks>
     <AssemblyName>Grpc.IntegrationTesting.Server</AssemblyName>
-    <StartupObject>Grpc.IntegrationTesting.Server.Program</StartupObject>
-    <TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
-    <NuGetPackageImportStamp>7ceb739e</NuGetPackageImportStamp>
-  </PropertyGroup>
-  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
-    <DebugSymbols>true</DebugSymbols>
-    <DebugType>full</DebugType>
-    <Optimize>false</Optimize>
-    <OutputPath>bin\Debug</OutputPath>
-    <DefineConstants>DEBUG;</DefineConstants>
-    <ErrorReport>prompt</ErrorReport>
-    <WarningLevel>4</WarningLevel>
-    <PlatformTarget>AnyCPU</PlatformTarget>
-  </PropertyGroup>
-  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
-    <DebugType>pdbonly</DebugType>
-    <Optimize>true</Optimize>
-    <OutputPath>bin\Release</OutputPath>
-    <ErrorReport>prompt</ErrorReport>
-    <WarningLevel>4</WarningLevel>
-    <PlatformTarget>AnyCPU</PlatformTarget>
+    <OutputType>Exe</OutputType>
+    <PackageId>Grpc.IntegrationTesting.Server</PackageId>
+    <PackageTargetFallback Condition=" '$(TargetFramework)' == 'netcoreapp1.0' ">$(PackageTargetFallback);portable-net45</PackageTargetFallback>
+    <RuntimeFrameworkVersion Condition=" '$(TargetFramework)' == 'netcoreapp1.0' ">1.0.4</RuntimeFrameworkVersion>
   </PropertyGroup>
+
   <ItemGroup>
-    <Reference Include="System" />
-    <Reference Include="System.Net" />
-    <Reference Include="System.Net.Http" />
-    <Reference Include="System.Net.Http.WebRequest" />
+    <ProjectReference Include="../Grpc.IntegrationTesting/Grpc.IntegrationTesting.csproj" />
   </ItemGroup>
-  <ItemGroup>
-    <Compile Include="..\Grpc.Core\Version.cs">
-      <Link>Version.cs</Link>
-    </Compile>
-    <Compile Include="Program.cs" />
-    <Compile Include="Properties\AssemblyInfo.cs" />
-  </ItemGroup>
-  <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
-  <ItemGroup>
-    <ProjectReference Include="..\Grpc.IntegrationTesting\Grpc.IntegrationTesting.csproj">
-      <Project>{C61154BA-DD4A-4838-8420-0162A28925E0}</Project>
-      <Name>Grpc.IntegrationTesting</Name>
-    </ProjectReference>
-    <ProjectReference Include="..\Grpc.Core\Grpc.Core.csproj">
-      <Project>{CCC4440E-49F7-4790-B0AF-FEABB0837AE7}</Project>
-      <Name>Grpc.Core</Name>
-    </ProjectReference>
+
+  <ItemGroup Condition=" '$(TargetFramework)' == 'net45' ">
+    <Reference Include="System" />
+    <Reference Include="Microsoft.CSharp" />
   </ItemGroup>
+  
   <ItemGroup>
-    <None Include="Grpc.IntegrationTesting.Server.project.json" />
+    <Compile Include="..\Grpc.Core\Version.cs" />
   </ItemGroup>
-</Project>
\ No newline at end of file
+
+</Project>
diff --git a/src/csharp/Grpc.IntegrationTesting.Server/Grpc.IntegrationTesting.Server.project.json b/src/csharp/Grpc.IntegrationTesting.Server/Grpc.IntegrationTesting.Server.project.json
deleted file mode 100644
index c2f5bcb1637badadff8959d672e04c942cb54d51..0000000000000000000000000000000000000000
--- a/src/csharp/Grpc.IntegrationTesting.Server/Grpc.IntegrationTesting.Server.project.json
+++ /dev/null
@@ -1,8 +0,0 @@
-{
-  "frameworks": {
-    "net45": { }
-  },
-  "runtimes": {
-    "win": { }
-  }
-}
diff --git a/src/csharp/Grpc.IntegrationTesting.Server/Grpc.IntegrationTesting.Server.xproj b/src/csharp/Grpc.IntegrationTesting.Server/Grpc.IntegrationTesting.Server.xproj
deleted file mode 100644
index 689eb0b842544740f2b3d7d2998eb9ff91008c51..0000000000000000000000000000000000000000
--- a/src/csharp/Grpc.IntegrationTesting.Server/Grpc.IntegrationTesting.Server.xproj
+++ /dev/null
@@ -1,18 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<Project ToolsVersion="14.0.25123" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
-  <PropertyGroup>
-    <VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">14.0.25123</VisualStudioVersion>
-    <VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
-  </PropertyGroup>
-  <Import Project="$(VSToolsPath)\DNX\Microsoft.DNX.Props" Condition="'$(VSToolsPath)' != ''" />
-  <PropertyGroup Label="Globals">
-    <ProjectGuid>881f7ad1-a84e-47a2-9402-115c63c4031e</ProjectGuid>
-    <RootNamespace>Grpc.IntegrationTesting.Server</RootNamespace>
-    <BaseIntermediateOutputPath Condition="'$(BaseIntermediateOutputPath)'=='' ">..\artifacts\obj\$(MSBuildProjectName)</BaseIntermediateOutputPath>
-    <OutputPath Condition="'$(OutputPath)'=='' ">.\bin\</OutputPath>
-  </PropertyGroup>
-  <PropertyGroup>
-    <SchemaVersion>2.0</SchemaVersion>
-  </PropertyGroup>
-  <Import Project="$(VSToolsPath)\DNX\Microsoft.DNX.targets" Condition="'$(VSToolsPath)' != ''" />
-</Project>
\ No newline at end of file
diff --git a/src/csharp/Grpc.IntegrationTesting.Server/project.json b/src/csharp/Grpc.IntegrationTesting.Server/project.json
deleted file mode 100644
index f90528151b4519b9dd5a63660fc71e157d0052a2..0000000000000000000000000000000000000000
--- a/src/csharp/Grpc.IntegrationTesting.Server/project.json
+++ /dev/null
@@ -1,69 +0,0 @@
-{
-  "buildOptions": {
-    "emitEntryPoint": true
-  },
-  "configurations": {
-    "Debug": {
-      "buildOptions": {
-        "define": [ "SIGNED" ],
-        "keyFile": "../keys/Grpc.snk",
-        "xmlDoc": true,
-        "compile": {
-          "includeFiles": [ "../Grpc.Core/Version.cs" ]
-        },
-        "copyToOutput": {
-          "mappings": {
-            "data/ca.pem": "../Grpc.IntegrationTesting/data/ca.pem",
-            "data/server1.key": "../Grpc.IntegrationTesting/data/server1.key",
-            "data/server1.pem": "../Grpc.IntegrationTesting/data/server1.pem",
-            "grpc_csharp_ext.x64.dll": "../../../cmake/build/x64/Debug/grpc_csharp_ext.dll",
-            "grpc_csharp_ext.x86.dll": "../../../cmake/build/Win32/Debug/grpc_csharp_ext.dll",
-            "libgrpc_csharp_ext.x64.so": "../../../libs/dbg/libgrpc_csharp_ext.so",
-            "libgrpc_csharp_ext.x64.dylib": "../../../libs/dbg/libgrpc_csharp_ext.dylib"
-          }
-        }
-      }
-    },
-    "Release": {
-      "buildOptions": {
-        "define": [ "SIGNED" ],
-        "keyFile": "../keys/Grpc.snk",
-        "xmlDoc": true,
-        "compile": {
-          "includeFiles": [ "../Grpc.Core/Version.cs" ]
-        },
-        "copyToOutput": {
-          "mappings": {
-            "data/ca.pem": "../Grpc.IntegrationTesting/data/ca.pem",
-            "data/server1.key": "../Grpc.IntegrationTesting/data/server1.key",
-            "data/server1.pem": "../Grpc.IntegrationTesting/data/server1.pem",
-            "grpc_csharp_ext.x64.dll": "../../../cmake/build/x64/Release/grpc_csharp_ext.dll",
-            "grpc_csharp_ext.x86.dll": "../../../cmake/build/Win32/Release/grpc_csharp_ext.dll",
-            "libgrpc_csharp_ext.x64.so": "../../../libs/opt/libgrpc_csharp_ext.so",
-            "libgrpc_csharp_ext.x64.dylib": "../../../libs/opt/libgrpc_csharp_ext.dylib"
-          }
-        }
-      }
-    }
-  },
-
-  "dependencies": {
-    "Grpc.IntegrationTesting": {
-      "target": "project"
-    }
-  },
-  "frameworks": {
-    "net45": { },
-    "netcoreapp1.0": {
-      "imports": [
-        "portable-net45"
-      ],
-      "dependencies": {
-        "Microsoft.NETCore.App": {
-          "type": "platform",
-          "version": "1.0.0"
-        }
-      }
-    }
-  }
-}
diff --git a/src/csharp/Grpc.IntegrationTesting.StressClient/Grpc.IntegrationTesting.StressClient.csproj b/src/csharp/Grpc.IntegrationTesting.StressClient/Grpc.IntegrationTesting.StressClient.csproj
old mode 100644
new mode 100755
index 0f283404504062a78ec89efae62f17661c826d65..fe4e0da41717498cd2b2f48b8a278eb57bcc8d15
--- a/src/csharp/Grpc.IntegrationTesting.StressClient/Grpc.IntegrationTesting.StressClient.csproj
+++ b/src/csharp/Grpc.IntegrationTesting.StressClient/Grpc.IntegrationTesting.StressClient.csproj
@@ -1,54 +1,28 @@
-<?xml version="1.0" encoding="utf-8"?>
-<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+<Project Sdk="Microsoft.NET.Sdk">
+
+  <Import Project="..\Grpc.Core\Version.csproj.include" />
+  <Import Project="..\Grpc.Core\Common.csproj.include" />
+
   <PropertyGroup>
-    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
-    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
-    <ProjectGuid>{ADEBA147-80AE-4710-82E9-5B7F93690266}</ProjectGuid>
-    <OutputType>Exe</OutputType>
-    <RootNamespace>Grpc.IntegrationTesting.StressClient</RootNamespace>
+    <TargetFrameworks>net45;netcoreapp1.0</TargetFrameworks>
     <AssemblyName>Grpc.IntegrationTesting.StressClient</AssemblyName>
-    <TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
-  </PropertyGroup>
-  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
-    <DebugSymbols>true</DebugSymbols>
-    <DebugType>full</DebugType>
-    <Optimize>false</Optimize>
-    <OutputPath>bin\Debug</OutputPath>
-    <DefineConstants>DEBUG;</DefineConstants>
-    <ErrorReport>prompt</ErrorReport>
-    <WarningLevel>4</WarningLevel>
-    <PlatformTarget>AnyCPU</PlatformTarget>
-  </PropertyGroup>
-  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
-    <DebugType>pdbonly</DebugType>
-    <Optimize>true</Optimize>
-    <OutputPath>bin\Release</OutputPath>
-    <ErrorReport>prompt</ErrorReport>
-    <WarningLevel>4</WarningLevel>
-    <PlatformTarget>AnyCPU</PlatformTarget>
+    <OutputType>Exe</OutputType>
+    <PackageId>Grpc.IntegrationTesting.StressClient</PackageId>
+    <PackageTargetFallback Condition=" '$(TargetFramework)' == 'netcoreapp1.0' ">$(PackageTargetFallback);portable-net45</PackageTargetFallback>
+    <RuntimeFrameworkVersion Condition=" '$(TargetFramework)' == 'netcoreapp1.0' ">1.0.4</RuntimeFrameworkVersion>
   </PropertyGroup>
+
   <ItemGroup>
-    <Reference Include="System" />
+    <ProjectReference Include="../Grpc.IntegrationTesting/Grpc.IntegrationTesting.csproj" />
   </ItemGroup>
-  <ItemGroup>
-    <Compile Include="..\Grpc.Core\Version.cs">
-      <Link>Version.cs</Link>
-    </Compile>
-    <Compile Include="Program.cs" />
-    <Compile Include="Properties\AssemblyInfo.cs" />
-  </ItemGroup>
-  <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
-  <ItemGroup>
-    <ProjectReference Include="..\Grpc.Core\Grpc.Core.csproj">
-      <Project>{CCC4440E-49F7-4790-B0AF-FEABB0837AE7}</Project>
-      <Name>Grpc.Core</Name>
-    </ProjectReference>
-    <ProjectReference Include="..\Grpc.IntegrationTesting\Grpc.IntegrationTesting.csproj">
-      <Project>{C61154BA-DD4A-4838-8420-0162A28925E0}</Project>
-      <Name>Grpc.IntegrationTesting</Name>
-    </ProjectReference>
+
+  <ItemGroup Condition=" '$(TargetFramework)' == 'net45' ">
+    <Reference Include="System" />
+    <Reference Include="Microsoft.CSharp" />
   </ItemGroup>
+
   <ItemGroup>
-    <None Include="Grpc.IntegrationTesting.StressClient.project.json" />
+    <Compile Include="..\Grpc.Core\Version.cs" />
   </ItemGroup>
-</Project>
\ No newline at end of file
+
+</Project>
diff --git a/src/csharp/Grpc.IntegrationTesting.StressClient/Grpc.IntegrationTesting.StressClient.project.json b/src/csharp/Grpc.IntegrationTesting.StressClient/Grpc.IntegrationTesting.StressClient.project.json
deleted file mode 100644
index c2f5bcb1637badadff8959d672e04c942cb54d51..0000000000000000000000000000000000000000
--- a/src/csharp/Grpc.IntegrationTesting.StressClient/Grpc.IntegrationTesting.StressClient.project.json
+++ /dev/null
@@ -1,8 +0,0 @@
-{
-  "frameworks": {
-    "net45": { }
-  },
-  "runtimes": {
-    "win": { }
-  }
-}
diff --git a/src/csharp/Grpc.IntegrationTesting.StressClient/Grpc.IntegrationTesting.StressClient.xproj b/src/csharp/Grpc.IntegrationTesting.StressClient/Grpc.IntegrationTesting.StressClient.xproj
deleted file mode 100644
index 2f4fdcbb4709a3c652ae16a17004fab733239247..0000000000000000000000000000000000000000
--- a/src/csharp/Grpc.IntegrationTesting.StressClient/Grpc.IntegrationTesting.StressClient.xproj
+++ /dev/null
@@ -1,19 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<Project ToolsVersion="14.0.25123" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
-  <PropertyGroup>
-    <VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">14.0.25123</VisualStudioVersion>
-    <VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
-  </PropertyGroup>
-  <Import Project="$(VSToolsPath)\DotNet\Microsoft.DotNet.Props" Condition="'$(VSToolsPath)' != ''" />
-  <PropertyGroup Label="Globals">
-    <ProjectGuid>0ebc910b-8867-4d3e-8686-91f34183d839</ProjectGuid>
-    <RootNamespace>Grpc.IntegrationTesting.StressClient</RootNamespace>
-    <BaseIntermediateOutputPath Condition="'$(BaseIntermediateOutputPath)'=='' ">.\obj</BaseIntermediateOutputPath>
-    <OutputPath Condition="'$(OutputPath)'=='' ">.\bin\</OutputPath>
-  </PropertyGroup>
-
-  <PropertyGroup>
-    <SchemaVersion>2.0</SchemaVersion>
-  </PropertyGroup>
-  <Import Project="$(VSToolsPath)\DotNet\Microsoft.DotNet.targets" Condition="'$(VSToolsPath)' != ''" />
-</Project>
\ No newline at end of file
diff --git a/src/csharp/Grpc.IntegrationTesting.StressClient/project.json b/src/csharp/Grpc.IntegrationTesting.StressClient/project.json
deleted file mode 100644
index f90528151b4519b9dd5a63660fc71e157d0052a2..0000000000000000000000000000000000000000
--- a/src/csharp/Grpc.IntegrationTesting.StressClient/project.json
+++ /dev/null
@@ -1,69 +0,0 @@
-{
-  "buildOptions": {
-    "emitEntryPoint": true
-  },
-  "configurations": {
-    "Debug": {
-      "buildOptions": {
-        "define": [ "SIGNED" ],
-        "keyFile": "../keys/Grpc.snk",
-        "xmlDoc": true,
-        "compile": {
-          "includeFiles": [ "../Grpc.Core/Version.cs" ]
-        },
-        "copyToOutput": {
-          "mappings": {
-            "data/ca.pem": "../Grpc.IntegrationTesting/data/ca.pem",
-            "data/server1.key": "../Grpc.IntegrationTesting/data/server1.key",
-            "data/server1.pem": "../Grpc.IntegrationTesting/data/server1.pem",
-            "grpc_csharp_ext.x64.dll": "../../../cmake/build/x64/Debug/grpc_csharp_ext.dll",
-            "grpc_csharp_ext.x86.dll": "../../../cmake/build/Win32/Debug/grpc_csharp_ext.dll",
-            "libgrpc_csharp_ext.x64.so": "../../../libs/dbg/libgrpc_csharp_ext.so",
-            "libgrpc_csharp_ext.x64.dylib": "../../../libs/dbg/libgrpc_csharp_ext.dylib"
-          }
-        }
-      }
-    },
-    "Release": {
-      "buildOptions": {
-        "define": [ "SIGNED" ],
-        "keyFile": "../keys/Grpc.snk",
-        "xmlDoc": true,
-        "compile": {
-          "includeFiles": [ "../Grpc.Core/Version.cs" ]
-        },
-        "copyToOutput": {
-          "mappings": {
-            "data/ca.pem": "../Grpc.IntegrationTesting/data/ca.pem",
-            "data/server1.key": "../Grpc.IntegrationTesting/data/server1.key",
-            "data/server1.pem": "../Grpc.IntegrationTesting/data/server1.pem",
-            "grpc_csharp_ext.x64.dll": "../../../cmake/build/x64/Release/grpc_csharp_ext.dll",
-            "grpc_csharp_ext.x86.dll": "../../../cmake/build/Win32/Release/grpc_csharp_ext.dll",
-            "libgrpc_csharp_ext.x64.so": "../../../libs/opt/libgrpc_csharp_ext.so",
-            "libgrpc_csharp_ext.x64.dylib": "../../../libs/opt/libgrpc_csharp_ext.dylib"
-          }
-        }
-      }
-    }
-  },
-
-  "dependencies": {
-    "Grpc.IntegrationTesting": {
-      "target": "project"
-    }
-  },
-  "frameworks": {
-    "net45": { },
-    "netcoreapp1.0": {
-      "imports": [
-        "portable-net45"
-      ],
-      "dependencies": {
-        "Microsoft.NETCore.App": {
-          "type": "platform",
-          "version": "1.0.0"
-        }
-      }
-    }
-  }
-}
diff --git a/src/csharp/Grpc.IntegrationTesting/Grpc.IntegrationTesting.csproj b/src/csharp/Grpc.IntegrationTesting/Grpc.IntegrationTesting.csproj
old mode 100644
new mode 100755
index 38b9a5d3c5908415ccab0c0a668b4cce97571a47..6f2f06a652291ade7af46a81a8e0947e6f46ef87
--- a/src/csharp/Grpc.IntegrationTesting/Grpc.IntegrationTesting.csproj
+++ b/src/csharp/Grpc.IntegrationTesting/Grpc.IntegrationTesting.csproj
@@ -1,152 +1,56 @@
-<?xml version="1.0" encoding="utf-8"?>
-<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+<Project Sdk="Microsoft.NET.Sdk">
+
+  <Import Project="..\Grpc.Core\Version.csproj.include" />
+  <Import Project="..\Grpc.Core\Common.csproj.include" />
+
   <PropertyGroup>
-    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
-    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
-    <ProjectGuid>{C61154BA-DD4A-4838-8420-0162A28925E0}</ProjectGuid>
-    <OutputType>Exe</OutputType>
-    <RootNamespace>Grpc.IntegrationTesting</RootNamespace>
+    <TargetFrameworks>net45;netcoreapp1.0</TargetFrameworks>
     <AssemblyName>Grpc.IntegrationTesting</AssemblyName>
-    <TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
-    <NuGetPackageImportStamp>3a1c655d</NuGetPackageImportStamp>
-  </PropertyGroup>
-  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
-    <DebugSymbols>true</DebugSymbols>
-    <DebugType>full</DebugType>
-    <Optimize>false</Optimize>
-    <OutputPath>bin\Debug</OutputPath>
-    <DefineConstants>DEBUG;</DefineConstants>
-    <ErrorReport>prompt</ErrorReport>
-    <WarningLevel>4</WarningLevel>
-    <PlatformTarget>AnyCPU</PlatformTarget>
-  </PropertyGroup>
-  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
-    <DebugType>pdbonly</DebugType>
-    <Optimize>true</Optimize>
-    <OutputPath>bin\Release</OutputPath>
-    <ErrorReport>prompt</ErrorReport>
-    <WarningLevel>4</WarningLevel>
-    <PlatformTarget>AnyCPU</PlatformTarget>
+    <OutputType>Exe</OutputType>
+    <PackageId>Grpc.IntegrationTesting</PackageId>
+    <PackageTargetFallback Condition=" '$(TargetFramework)' == 'netcoreapp1.0' ">$(PackageTargetFallback);portable-net45</PackageTargetFallback>
+    <RuntimeFrameworkVersion Condition=" '$(TargetFramework)' == 'netcoreapp1.0' ">1.0.4</RuntimeFrameworkVersion>
   </PropertyGroup>
+
   <ItemGroup>
-    <Reference Include="System" />
-    <Reference Include="System.Net" />
-    <Reference Include="System.Net.Http" />
-    <Reference Include="System.Net.Http.WebRequest" />
-    <Reference Include="Zlib.Portable">
-      <HintPath>..\packages\Zlib.Portable.Signed.1.11.0\lib\portable-net4+sl5+wp8+win8+wpa81+MonoTouch+MonoAndroid\Zlib.Portable.dll</HintPath>
-    </Reference>
-    <Reference Include="System.Interactive.Async">
-      <HintPath>..\packages\System.Interactive.Async.3.1.1\lib\net45\System.Interactive.Async.dll</HintPath>
-    </Reference>
-    <Reference Include="Google.Apis.Core">
-      <HintPath>..\packages\Google.Apis.Core.1.21.0\lib\net45\Google.Apis.Core.dll</HintPath>
-    </Reference>
-    <Reference Include="Google.Apis">
-      <HintPath>..\packages\Google.Apis.1.21.0\lib\net45\Google.Apis.dll</HintPath>
-    </Reference>
-    <Reference Include="Google.Apis.PlatformServices">
-      <HintPath>..\packages\Google.Apis.1.21.0\lib\net45\Google.Apis.PlatformServices.dll</HintPath>
-    </Reference>
-    <Reference Include="Google.Apis.Auth">
-      <HintPath>..\packages\Google.Apis.Auth.1.21.0\lib\net45\Google.Apis.Auth.dll</HintPath>
-    </Reference>
-    <Reference Include="Google.Apis.Auth.PlatformServices">
-      <HintPath>..\packages\Google.Apis.Auth.1.21.0\lib\net45\Google.Apis.Auth.PlatformServices.dll</HintPath>
-    </Reference>
-    <Reference Include="Google.Protobuf">
-      <HintPath>..\packages\Google.Protobuf.3.2.0\lib\net45\Google.Protobuf.dll</HintPath>
-    </Reference>
-    <Reference Include="nunit.framework">
-      <HintPath>..\packages\NUnit.3.6.0\lib\net45\nunit.framework.dll</HintPath>
-    </Reference>
-    <Reference Include="nunitlite">
-      <HintPath>..\packages\NUnitLite.3.6.0\lib\net45\nunitlite.dll</HintPath>
-    </Reference>
-    <Reference Include="Newtonsoft.Json">
-      <HintPath>..\packages\Newtonsoft.Json.9.0.1\lib\net45\Newtonsoft.Json.dll</HintPath>
-    </Reference>
-    <Reference Include="Castle.Core">
-      <HintPath>..\packages\Castle.Core.4.0.0\lib\net45\Castle.Core.dll</HintPath>
-    </Reference>
-    <Reference Include="Moq">
-      <HintPath>..\packages\Moq.4.7.0\lib\net45\Moq.dll</HintPath>
-    </Reference>
-    <Reference Include="CommandLine">
-      <HintPath>..\packages\CommandLineParser.2.1.1-beta\lib\net45\CommandLine.dll</HintPath>
-    </Reference>
+    <ProjectReference Include="../Grpc.Auth/Grpc.Auth.csproj" />
+    <ProjectReference Include="../Grpc.Core/Grpc.Core.csproj" />
   </ItemGroup>
+
   <ItemGroup>
-    <Compile Include="..\Grpc.Core\Version.cs">
-      <Link>Version.cs</Link>
-    </Compile>
-    <Compile Include="Properties\AssemblyInfo.cs" />
-    <Compile Include="Empty.cs" />
-    <Compile Include="Messages.cs" />
-    <Compile Include="InteropClientServerTest.cs" />
-    <Compile Include="MetadataCredentialsTest.cs" />
-    <Compile Include="TestServiceImpl.cs" />
-    <Compile Include="InteropServer.cs" />
-    <Compile Include="InteropClient.cs" />
-    <Compile Include="TestCredentials.cs" />
-    <Compile Include="TestGrpc.cs" />
-    <Compile Include="SslCredentialsTest.cs" />
-    <Compile Include="Test.cs" />
-    <Compile Include="IClientRunner.cs" />
-    <Compile Include="ClientRunners.cs" />
-    <Compile Include="IServerRunner.cs" />
-    <Compile Include="ServerRunners.cs" />
-    <Compile Include="RunnerClientServerTest.cs" />
-    <Compile Include="Control.cs" />
-    <Compile Include="Payloads.cs" />
-    <Compile Include="Services.cs" />
-    <Compile Include="ServicesGrpc.cs" />
-    <Compile Include="Stats.cs" />
-    <Compile Include="BenchmarkServiceImpl.cs" />
-    <Compile Include="Histogram.cs" />
-    <Compile Include="HistogramTest.cs" />
-    <Compile Include="WorkerServiceImpl.cs" />
-    <Compile Include="QpsWorker.cs" />
-    <Compile Include="WallClockStopwatch.cs" />
-    <Compile Include="GenericService.cs" />
-    <Compile Include="GeneratedServiceBaseTest.cs" />
-    <Compile Include="GeneratedClientTest.cs" />
-    <Compile Include="InterarrivalTimers.cs" />
-    <Compile Include="NUnitMain.cs" />
-    <Compile Include="StressTestClient.cs" />
-    <Compile Include="Metrics.cs" />
-    <Compile Include="MetricsGrpc.cs" />
+    <PackageReference Include="Google.Protobuf" Version="$(GoogleProtobufVersion)" />
+    <PackageReference Include="CommandLineParser" Version="2.1.1-beta" />
+    <PackageReference Include="Moq" Version="4.7.0" />
+    <PackageReference Include="NUnit" Version="3.6.0" />
+    <PackageReference Include="NUnitLite" Version="3.6.0" />
   </ItemGroup>
-  <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
+
+  <ItemGroup Condition=" '$(TargetFramework)' == 'net45' ">
+    <Reference Include="System" />
+    <Reference Include="Microsoft.CSharp" />
+  </ItemGroup>
+
+  <ItemGroup Condition=" '$(TargetFramework)' == 'netcoreapp1.0' ">
+    <PackageReference Include="System.Linq.Expressions" Version="4.1.1" />
+  </ItemGroup>
+
   <ItemGroup>
-    <ProjectReference Include="..\Grpc.Core\Grpc.Core.csproj">
-      <Project>{CCC4440E-49F7-4790-B0AF-FEABB0837AE7}</Project>
-      <Name>Grpc.Core</Name>
-    </ProjectReference>
-    <ProjectReference Include="..\Grpc.Auth\Grpc.Auth.csproj">
-      <Project>{AE21D0EE-9A2C-4C15-AB7F-5224EED5B0EA}</Project>
-      <Name>Grpc.Auth</Name>
-    </ProjectReference>
+    <Compile Include="..\Grpc.Core\Version.cs" />
   </ItemGroup>
+
   <ItemGroup>
-    <None Include="Grpc.IntegrationTesting.project.json" />
-    <None Include="packages.config">
-      <SubType>Designer</SubType>
-    </None>
-    <None Include="data\README">
-      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
-    </None>
-    <None Include="data\ca.pem">
+    <Content Include="data\server1.pem">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
-    </None>
-    <None Include="data\server1.key">
+      <Pack>false</Pack>
+    </Content>
+    <Content Include="data\server1.key">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
-    </None>
-    <None Include="data\server1.pem">
+      <Pack>false</Pack>
+    </Content>
+    <Content Include="data\ca.pem">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
-    </None>
-  </ItemGroup>
-  <ItemGroup>
-    <Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" />
+      <Pack>false</Pack>
+    </Content>
   </ItemGroup>
+
 </Project>
diff --git a/src/csharp/Grpc.IntegrationTesting/Grpc.IntegrationTesting.project.json b/src/csharp/Grpc.IntegrationTesting/Grpc.IntegrationTesting.project.json
deleted file mode 100644
index c2f5bcb1637badadff8959d672e04c942cb54d51..0000000000000000000000000000000000000000
--- a/src/csharp/Grpc.IntegrationTesting/Grpc.IntegrationTesting.project.json
+++ /dev/null
@@ -1,8 +0,0 @@
-{
-  "frameworks": {
-    "net45": { }
-  },
-  "runtimes": {
-    "win": { }
-  }
-}
diff --git a/src/csharp/Grpc.IntegrationTesting/Grpc.IntegrationTesting.xproj b/src/csharp/Grpc.IntegrationTesting/Grpc.IntegrationTesting.xproj
deleted file mode 100644
index 357300ecb9b9a75cf035d0a062a8126727d0ca7d..0000000000000000000000000000000000000000
--- a/src/csharp/Grpc.IntegrationTesting/Grpc.IntegrationTesting.xproj
+++ /dev/null
@@ -1,18 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<Project ToolsVersion="14.0.25123" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
-  <PropertyGroup>
-    <VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">14.0.25123</VisualStudioVersion>
-    <VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
-  </PropertyGroup>
-  <Import Project="$(VSToolsPath)\DNX\Microsoft.DNX.Props" Condition="'$(VSToolsPath)' != ''" />
-  <PropertyGroup Label="Globals">
-    <ProjectGuid>20354386-3e71-4046-a269-3bc2a06f3ec8</ProjectGuid>
-    <RootNamespace>Grpc.IntegrationTesting</RootNamespace>
-    <BaseIntermediateOutputPath Condition="'$(BaseIntermediateOutputPath)'=='' ">..\artifacts\obj\$(MSBuildProjectName)</BaseIntermediateOutputPath>
-    <OutputPath Condition="'$(OutputPath)'=='' ">.\bin\</OutputPath>
-  </PropertyGroup>
-  <PropertyGroup>
-    <SchemaVersion>2.0</SchemaVersion>
-  </PropertyGroup>
-  <Import Project="$(VSToolsPath)\DNX\Microsoft.DNX.targets" Condition="'$(VSToolsPath)' != ''" />
-</Project>
\ No newline at end of file
diff --git a/src/csharp/Grpc.IntegrationTesting/packages.config b/src/csharp/Grpc.IntegrationTesting/packages.config
deleted file mode 100644
index 030f9d97b8964d2218cc07ca530ef530945ea44d..0000000000000000000000000000000000000000
--- a/src/csharp/Grpc.IntegrationTesting/packages.config
+++ /dev/null
@@ -1,15 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<packages>
-  <package id="Castle.Core" version="4.0.0" targetFramework="net45" />
-  <package id="CommandLineParser" version="2.1.1-beta" targetFramework="net45" />
-  <package id="Google.Apis" version="1.21.0" targetFramework="net45" />
-  <package id="Google.Apis.Auth" version="1.21.0" targetFramework="net45" />
-  <package id="Google.Apis.Core" version="1.21.0" targetFramework="net45" />
-  <package id="Google.Protobuf" version="3.2.0" targetFramework="net45" />
-  <package id="Moq" version="4.7.0" targetFramework="net45" />
-  <package id="Newtonsoft.Json" version="9.0.1" targetFramework="net45" />
-  <package id="NUnit" version="3.6.0" targetFramework="net45" />
-  <package id="NUnitLite" version="3.6.0" targetFramework="net45" />
-  <package id="System.Interactive.Async" version="3.1.1" targetFramework="net45" />
-  <package id="Zlib.Portable.Signed" version="1.11.0" targetFramework="net45" />
-</packages>
\ No newline at end of file
diff --git a/src/csharp/Grpc.IntegrationTesting/project.json b/src/csharp/Grpc.IntegrationTesting/project.json
deleted file mode 100644
index 40fc566adcf2d58aa48785edbec26911fef9743f..0000000000000000000000000000000000000000
--- a/src/csharp/Grpc.IntegrationTesting/project.json
+++ /dev/null
@@ -1,80 +0,0 @@
-{
-  "buildOptions": {
-    "emitEntryPoint": true
-  },
-  "configurations": {
-    "Debug": {
-      "buildOptions": {
-        "define": [ "SIGNED" ],
-        "keyFile": "../keys/Grpc.snk",
-        "xmlDoc": true,
-        "compile": {
-          "includeFiles": [ "../Grpc.Core/Version.cs" ]
-        },
-        "copyToOutput": {
-          "mappings": {
-            "data/ca.pem": "../Grpc.IntegrationTesting/data/ca.pem",
-            "data/server1.key": "../Grpc.IntegrationTesting/data/server1.key",
-            "data/server1.pem": "../Grpc.IntegrationTesting/data/server1.pem",
-            "grpc_csharp_ext.x64.dll": "../../../cmake/build/x64/Debug/grpc_csharp_ext.dll",
-            "grpc_csharp_ext.x86.dll": "../../../cmake/build/Win32/Debug/grpc_csharp_ext.dll",
-            "libgrpc_csharp_ext.x64.so": "../../../libs/dbg/libgrpc_csharp_ext.so",
-            "libgrpc_csharp_ext.x64.dylib": "../../../libs/dbg/libgrpc_csharp_ext.dylib"
-          }
-        }
-      }
-    },
-    "Release": {
-      "buildOptions": {
-        "define": [ "SIGNED" ],
-        "keyFile": "../keys/Grpc.snk",
-        "xmlDoc": true,
-        "compile": {
-          "includeFiles": [ "../Grpc.Core/Version.cs" ]
-        },
-        "copyToOutput": {
-          "mappings": {
-            "data/ca.pem": "../Grpc.IntegrationTesting/data/ca.pem",
-            "data/server1.key": "../Grpc.IntegrationTesting/data/server1.key",
-            "data/server1.pem": "../Grpc.IntegrationTesting/data/server1.pem",
-            "grpc_csharp_ext.x64.dll": "../../../cmake/build/x64/Release/grpc_csharp_ext.dll",
-            "grpc_csharp_ext.x86.dll": "../../../cmake/build/Win32/Release/grpc_csharp_ext.dll",
-            "libgrpc_csharp_ext.x64.so": "../../../libs/opt/libgrpc_csharp_ext.so",
-            "libgrpc_csharp_ext.x64.dylib": "../../../libs/opt/libgrpc_csharp_ext.dylib"
-          }
-        }
-      }
-    }
-  },
-
-  "dependencies": {
-    "Grpc.Auth": {
-      "target": "project"
-    },
-    "Grpc.Core": {
-      "target": "project"
-    },
-    "Google.Protobuf": "3.2.0",
-    "CommandLineParser": "2.1.1-beta",
-    "Moq": "4.7.0",
-    "NUnit": "3.6.0",
-    "NUnitLite": "3.6.0"
-  },
-  "frameworks": {
-    "net45": {
-      "frameworkAssemblies": {}
-    },
-    "netcoreapp1.0": {
-      "imports": [
-        "portable-net45"
-      ],
-      "dependencies": {
-        "Microsoft.NETCore.App": {
-          "type": "platform",
-          "version": "1.0.0"
-        },
-        "System.Linq.Expressions": "4.1.0"
-      }
-    }
-  }
-}
diff --git a/src/csharp/Grpc.Reflection.Tests/Grpc.Reflection.Tests.csproj b/src/csharp/Grpc.Reflection.Tests/Grpc.Reflection.Tests.csproj
old mode 100644
new mode 100755
index 7e2b551799ef386e5e47e4115f7aab085a194eea..af6ade852b2ddb4792c5aaba4d69a2323d92c6e8
--- a/src/csharp/Grpc.Reflection.Tests/Grpc.Reflection.Tests.csproj
+++ b/src/csharp/Grpc.Reflection.Tests/Grpc.Reflection.Tests.csproj
@@ -1,85 +1,33 @@
-<?xml version="1.0" encoding="utf-8"?>
-<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
-  <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
+<Project Sdk="Microsoft.NET.Sdk">
+
+  <Import Project="..\Grpc.Core\Version.csproj.include" />
+  <Import Project="..\Grpc.Core\Common.csproj.include" />
+
   <PropertyGroup>
-    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
-    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
-    <ProjectGuid>{B88F91D6-436D-4C78-8B99-47800FA8DE03}</ProjectGuid>
-    <OutputType>Exe</OutputType>
-    <AppDesignerFolder>Properties</AppDesignerFolder>
-    <RootNamespace>Grpc.Reflection.Tests</RootNamespace>
+    <TargetFrameworks>net45;netcoreapp1.0</TargetFrameworks>
     <AssemblyName>Grpc.Reflection.Tests</AssemblyName>
-    <TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
-    <FileAlignment>512</FileAlignment>
-  </PropertyGroup>
-  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
-    <DebugSymbols>true</DebugSymbols>
-    <DebugType>full</DebugType>
-    <Optimize>false</Optimize>
-    <OutputPath>bin\Debug\</OutputPath>
-    <ErrorReport>prompt</ErrorReport>
-    <WarningLevel>4</WarningLevel>
-  </PropertyGroup>
-  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
-    <DebugType>pdbonly</DebugType>
-    <Optimize>true</Optimize>
-    <OutputPath>bin\Release\</OutputPath>
-    <ErrorReport>prompt</ErrorReport>
-    <WarningLevel>4</WarningLevel>
+    <OutputType>Exe</OutputType>
+    <PackageId>Grpc.Reflection.Tests</PackageId>
+    <PackageTargetFallback Condition=" '$(TargetFramework)' == 'netcoreapp1.0' ">$(PackageTargetFallback);portable-net45</PackageTargetFallback>
+    <RuntimeFrameworkVersion Condition=" '$(TargetFramework)' == 'netcoreapp1.0' ">1.0.4</RuntimeFrameworkVersion>
   </PropertyGroup>
+
   <ItemGroup>
-    <Reference Include="System" />
-    <Reference Include="System.Core" />
-    <Reference Include="System.Xml.Linq" />
-    <Reference Include="System.Data.DataSetExtensions" />
-    <Reference Include="Microsoft.CSharp" />
-    <Reference Include="System.Data" />
-    <Reference Include="System.Xml" />
-    <Reference Include="System.Interactive.Async">
-      <HintPath>..\packages\System.Interactive.Async.3.1.1\lib\net45\System.Interactive.Async.dll</HintPath>
-    </Reference>
-    <Reference Include="Google.Protobuf">
-      <HintPath>..\packages\Google.Protobuf.3.2.0\lib\net45\Google.Protobuf.dll</HintPath>
-    </Reference>
-    <Reference Include="nunit.framework">
-      <HintPath>..\packages\NUnit.3.6.0\lib\net45\nunit.framework.dll</HintPath>
-    </Reference>
-    <Reference Include="nunitlite">
-      <HintPath>..\packages\NUnitLite.3.6.0\lib\net45\nunitlite.dll</HintPath>
-    </Reference>
+    <ProjectReference Include="../Grpc.Reflection/Grpc.Reflection.csproj" />
   </ItemGroup>
+
   <ItemGroup>
-    <Compile Include="..\Grpc.Core\Version.cs">
-      <Link>Version.cs</Link>
-    </Compile>
-    <Compile Include="SymbolRegistryTest.cs" />
-    <Compile Include="ReflectionClientServerTest.cs" />
-    <Compile Include="Properties\AssemblyInfo.cs" />
-    <Compile Include="NUnitMain.cs" />
+    <PackageReference Include="NUnit" Version="3.6.0" />
+    <PackageReference Include="NUnitLite" Version="3.6.0" />
   </ItemGroup>
-  <ItemGroup>
-    <ProjectReference Include="..\Grpc.Core\Grpc.Core.csproj">
-      <Project>{CCC4440E-49F7-4790-B0AF-FEABB0837AE7}</Project>
-      <Name>Grpc.Core</Name>
-    </ProjectReference>
-    <ProjectReference Include="..\Grpc.Reflection\Grpc.Reflection.csproj">
-      <Project>{4F18CF52-B3DB-4A77-97C5-7F7F4B6C1715}</Project>
-      <Name>Grpc.Reflection</Name>
-    </ProjectReference>
-  </ItemGroup>
-  <ItemGroup>
-    <None Include="Grpc.Reflection.Tests.project.json" />
-    <None Include="packages.config" />
+
+  <ItemGroup Condition=" '$(TargetFramework)' == 'net45' ">
+    <Reference Include="System" />
+    <Reference Include="Microsoft.CSharp" />
   </ItemGroup>
+
   <ItemGroup>
-    <Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" />
+    <Compile Include="..\Grpc.Core\Version.cs" />
   </ItemGroup>
-  <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
-  <!-- To modify your build process, add your task inside one of the targets below and uncomment it. 
-       Other similar extension points exist, see Microsoft.Common.targets.
-  <Target Name="BeforeBuild">
-  </Target>
-  <Target Name="AfterBuild">
-  </Target>
-  -->
-</Project>
\ No newline at end of file
+
+</Project>
diff --git a/src/csharp/Grpc.Reflection.Tests/Grpc.Reflection.Tests.project.json b/src/csharp/Grpc.Reflection.Tests/Grpc.Reflection.Tests.project.json
deleted file mode 100644
index c2f5bcb1637badadff8959d672e04c942cb54d51..0000000000000000000000000000000000000000
--- a/src/csharp/Grpc.Reflection.Tests/Grpc.Reflection.Tests.project.json
+++ /dev/null
@@ -1,8 +0,0 @@
-{
-  "frameworks": {
-    "net45": { }
-  },
-  "runtimes": {
-    "win": { }
-  }
-}
diff --git a/src/csharp/Grpc.Reflection.Tests/Grpc.Reflection.Tests.xproj b/src/csharp/Grpc.Reflection.Tests/Grpc.Reflection.Tests.xproj
deleted file mode 100644
index 4a3100853d15ec7f270a726f49f12daf7a4f69f9..0000000000000000000000000000000000000000
--- a/src/csharp/Grpc.Reflection.Tests/Grpc.Reflection.Tests.xproj
+++ /dev/null
@@ -1,18 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<Project ToolsVersion="14.0.25123" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
-  <PropertyGroup>
-    <VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">14.0.25123</VisualStudioVersion>
-    <VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
-  </PropertyGroup>
-  <Import Project="$(VSToolsPath)\DNX\Microsoft.DNX.Props" Condition="'$(VSToolsPath)' != ''" />
-  <PropertyGroup Label="Globals">
-    <ProjectGuid>fe90181d-a4b3-4a5c-8490-f07561e18e3b</ProjectGuid>
-    <RootNamespace>Grpc.Reflection.Tests</RootNamespace>
-    <BaseIntermediateOutputPath Condition="'$(BaseIntermediateOutputPath)'=='' ">..\artifacts\obj\$(MSBuildProjectName)</BaseIntermediateOutputPath>
-    <OutputPath Condition="'$(OutputPath)'=='' ">.\bin\</OutputPath>
-  </PropertyGroup>
-  <PropertyGroup>
-    <SchemaVersion>2.0</SchemaVersion>
-  </PropertyGroup>
-  <Import Project="$(VSToolsPath)\DNX\Microsoft.DNX.targets" Condition="'$(VSToolsPath)' != ''" />
-</Project>
\ No newline at end of file
diff --git a/src/csharp/Grpc.Reflection.Tests/packages.config b/src/csharp/Grpc.Reflection.Tests/packages.config
deleted file mode 100644
index 8a7f7a0652a4dd70cdfcf0f1b1cfab6819b57e9c..0000000000000000000000000000000000000000
--- a/src/csharp/Grpc.Reflection.Tests/packages.config
+++ /dev/null
@@ -1,7 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<packages>
-  <package id="Google.Protobuf" version="3.2.0" targetFramework="net45" />
-  <package id="NUnit" version="3.6.0" targetFramework="net45" />
-  <package id="NUnitLite" version="3.6.0" targetFramework="net45" />
-  <package id="System.Interactive.Async" version="3.1.1" targetFramework="net45" />
-</packages>
\ No newline at end of file
diff --git a/src/csharp/Grpc.Reflection.Tests/project.json b/src/csharp/Grpc.Reflection.Tests/project.json
deleted file mode 100644
index fc05557c88471ba82f35791d34fd1df7b59db7e8..0000000000000000000000000000000000000000
--- a/src/csharp/Grpc.Reflection.Tests/project.json
+++ /dev/null
@@ -1,65 +0,0 @@
-{
-  "buildOptions": {
-    "emitEntryPoint": true
-  },
-  "configurations": {
-    "Debug": {
-      "buildOptions": {
-        "define": [ "SIGNED" ],
-        "keyFile": "../keys/Grpc.snk",
-        "xmlDoc": true,
-        "compile": {
-          "includeFiles": [ "../Grpc.Core/Version.cs" ]
-        },
-        "copyToOutput": {
-          "mappings": {
-            "grpc_csharp_ext.x64.dll": "../../../cmake/build/x64/Debug/grpc_csharp_ext.dll",
-            "grpc_csharp_ext.x86.dll": "../../../cmake/build/Win32/Debug/grpc_csharp_ext.dll",
-            "libgrpc_csharp_ext.x64.so": "../../../libs/dbg/libgrpc_csharp_ext.so",
-            "libgrpc_csharp_ext.x64.dylib": "../../../libs/dbg/libgrpc_csharp_ext.dylib"
-          }
-        }
-      }
-    },
-    "Release": {
-      "buildOptions": {
-        "define": [ "SIGNED" ],
-        "keyFile": "../keys/Grpc.snk",
-        "xmlDoc": true,
-        "compile": {
-          "includeFiles": [ "../Grpc.Core/Version.cs" ]
-        },
-        "copyToOutput": {
-          "mappings": {
-            "grpc_csharp_ext.x64.dll": "../../../cmake/build/x64/Release/grpc_csharp_ext.dll",
-            "grpc_csharp_ext.x86.dll": "../../../cmake/build/Win32/Release/grpc_csharp_ext.dll",
-            "libgrpc_csharp_ext.x64.so": "../../../libs/opt/libgrpc_csharp_ext.so",
-            "libgrpc_csharp_ext.x64.dylib": "../../../libs/opt/libgrpc_csharp_ext.dylib"
-          }
-        }
-      }
-    }
-  },
-
-  "dependencies": {
-    "Grpc.Reflection": {
-      "target": "project"
-    },
-    "NUnit": "3.6.0",
-    "NUnitLite": "3.6.0"
-  },
-  "frameworks": {
-    "net45": { },
-    "netcoreapp1.0": {
-      "imports": [
-        "portable-net45"
-      ],
-      "dependencies": {
-        "Microsoft.NETCore.App": {
-          "type": "platform",
-          "version": "1.0.0"
-        }
-      }
-    }
-  }
-}
diff --git a/src/csharp/Grpc.Reflection/Grpc.Reflection.csproj b/src/csharp/Grpc.Reflection/Grpc.Reflection.csproj
old mode 100644
new mode 100755
index b0ab170e3f8eb05127f6088e2feb1b1d060ae2b7..70bfcc89c5cd633b0ee0f48f31e381f61a460d01
--- a/src/csharp/Grpc.Reflection/Grpc.Reflection.csproj
+++ b/src/csharp/Grpc.Reflection/Grpc.Reflection.csproj
@@ -1,74 +1,37 @@
-<?xml version="1.0" encoding="utf-8"?>
-<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
-  <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
+<Project Sdk="Microsoft.NET.Sdk">
+
+  <Import Project="..\Grpc.Core\Version.csproj.include" />
+  <Import Project="..\Grpc.Core\Common.csproj.include" />
+
   <PropertyGroup>
-    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
-    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
-    <ProjectGuid>{4F18CF52-B3DB-4A77-97C5-7F7F4B6C1715}</ProjectGuid>
-    <OutputType>Library</OutputType>
-    <AppDesignerFolder>Properties</AppDesignerFolder>
-    <RootNamespace>Grpc.Reflection</RootNamespace>
+    <Copyright>Copyright 2016, Google Inc.</Copyright>
+    <AssemblyTitle>gRPC C# Reflection</AssemblyTitle>
+    <VersionPrefix>$(GrpcCsharpVersion)</VersionPrefix>
+    <Authors>Google Inc.</Authors>
+    <TargetFrameworks>net45;netstandard1.5</TargetFrameworks>
     <AssemblyName>Grpc.Reflection</AssemblyName>
-    <TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
-    <FileAlignment>512</FileAlignment>
-    <DocumentationFile>bin\$(Configuration)\Grpc.Reflection.Xml</DocumentationFile>
-  </PropertyGroup>
-  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
-    <DebugSymbols>true</DebugSymbols>
-    <DebugType>full</DebugType>
-    <Optimize>false</Optimize>
-    <OutputPath>bin\Debug\</OutputPath>
-    <ErrorReport>prompt</ErrorReport>
-    <WarningLevel>4</WarningLevel>
-  </PropertyGroup>
-  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
-    <DebugType>pdbonly</DebugType>
-    <Optimize>true</Optimize>
-    <OutputPath>bin\Release\</OutputPath>
-    <ErrorReport>prompt</ErrorReport>
-    <WarningLevel>4</WarningLevel>
+    <PackageId>Grpc.Reflection</PackageId>
+    <PackageTags>gRPC reflection</PackageTags>
+    <PackageProjectUrl>https://github.com/grpc/grpc</PackageProjectUrl>
+    <PackageLicenseUrl>https://github.com/grpc/grpc/blob/master/LICENSE</PackageLicenseUrl>
+    <NetStandardImplicitPackageVersion Condition=" '$(TargetFramework)' == 'netstandard1.5' ">1.6.0</NetStandardImplicitPackageVersion>
   </PropertyGroup>
+
   <ItemGroup>
-    <Reference Include="System" />
-    <Reference Include="System.Core" />
-    <Reference Include="System.Xml.Linq" />
-    <Reference Include="System.Data.DataSetExtensions" />
-    <Reference Include="Microsoft.CSharp" />
-    <Reference Include="System.Data" />
-    <Reference Include="System.Xml" />
-    <Reference Include="System.Interactive.Async">
-      <HintPath>..\packages\System.Interactive.Async.3.1.1\lib\net45\System.Interactive.Async.dll</HintPath>
-    </Reference>
-    <Reference Include="Google.Protobuf">
-      <HintPath>..\packages\Google.Protobuf.3.2.0\lib\net45\Google.Protobuf.dll</HintPath>
-    </Reference>
+    <Compile Include="..\Grpc.Core\Version.cs" />
   </ItemGroup>
+
   <ItemGroup>
-    <Compile Include="..\Grpc.Core\Version.cs">
-      <Link>Version.cs</Link>
-    </Compile>
-    <Compile Include="SymbolRegistry.cs" />
-    <Compile Include="ReflectionServiceImpl.cs" />
-    <Compile Include="Reflection.cs" />
-    <Compile Include="ReflectionGrpc.cs" />
-    <Compile Include="Properties\AssemblyInfo.cs" />
+    <ProjectReference Include="../Grpc.Core/Grpc.Core.csproj" />
   </ItemGroup>
+
   <ItemGroup>
-    <None Include="Grpc.Reflection.project.json" />
-    <None Include="packages.config" />
+    <PackageReference Include="Google.Protobuf" Version="$(GoogleProtobufVersion)" />
   </ItemGroup>
-  <ItemGroup>
-    <ProjectReference Include="..\Grpc.Core\Grpc.Core.csproj">
-      <Project>{CCC4440E-49F7-4790-B0AF-FEABB0837AE7}</Project>
-      <Name>Grpc.Core</Name>
-    </ProjectReference>
+
+  <ItemGroup Condition=" '$(TargetFramework)' == 'net45' ">
+    <Reference Include="System" />
+    <Reference Include="Microsoft.CSharp" />
   </ItemGroup>
-  <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
-  <!-- To modify your build process, add your task inside one of the targets below and uncomment it. 
-       Other similar extension points exist, see Microsoft.Common.targets.
-  <Target Name="BeforeBuild">
-  </Target>
-  <Target Name="AfterBuild">
-  </Target>
-  -->
-</Project>
\ No newline at end of file
+
+</Project>
diff --git a/src/csharp/Grpc.Reflection/Grpc.Reflection.project.json b/src/csharp/Grpc.Reflection/Grpc.Reflection.project.json
deleted file mode 100644
index c2f5bcb1637badadff8959d672e04c942cb54d51..0000000000000000000000000000000000000000
--- a/src/csharp/Grpc.Reflection/Grpc.Reflection.project.json
+++ /dev/null
@@ -1,8 +0,0 @@
-{
-  "frameworks": {
-    "net45": { }
-  },
-  "runtimes": {
-    "win": { }
-  }
-}
diff --git a/src/csharp/Grpc.Reflection/Grpc.Reflection.xproj b/src/csharp/Grpc.Reflection/Grpc.Reflection.xproj
deleted file mode 100644
index 833d98b12168259b79a1a98cf3ef50a4d027f398..0000000000000000000000000000000000000000
--- a/src/csharp/Grpc.Reflection/Grpc.Reflection.xproj
+++ /dev/null
@@ -1,18 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<Project ToolsVersion="14.0.25123" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
-  <PropertyGroup>
-    <VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">14.0.25123</VisualStudioVersion>
-    <VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
-  </PropertyGroup>
-  <Import Project="$(VSToolsPath)\DNX\Microsoft.DNX.Props" Condition="'$(VSToolsPath)' != ''" />
-  <PropertyGroup Label="Globals">
-    <ProjectGuid>2b372155-80ba-4cf9-82d6-4b938e8ec3a0</ProjectGuid>
-    <RootNamespace>Grpc.Reflection</RootNamespace>
-    <BaseIntermediateOutputPath Condition="'$(BaseIntermediateOutputPath)'=='' ">..\artifacts\obj\$(MSBuildProjectName)</BaseIntermediateOutputPath>
-    <OutputPath Condition="'$(OutputPath)'=='' ">.\bin\</OutputPath>
-  </PropertyGroup>
-  <PropertyGroup>
-    <SchemaVersion>2.0</SchemaVersion>
-  </PropertyGroup>
-  <Import Project="$(VSToolsPath)\DNX\Microsoft.DNX.targets" Condition="'$(VSToolsPath)' != ''" />
-</Project>
\ No newline at end of file
diff --git a/src/csharp/Grpc.Reflection/packages.config b/src/csharp/Grpc.Reflection/packages.config
deleted file mode 100644
index eec292b306d776ae4d6fdf583476ac63c3973c81..0000000000000000000000000000000000000000
--- a/src/csharp/Grpc.Reflection/packages.config
+++ /dev/null
@@ -1,5 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<packages>
-  <package id="Google.Protobuf" version="3.2.0" targetFramework="net45" />
-  <package id="System.Interactive.Async" version="3.1.1" targetFramework="net45" />
-</packages>
\ No newline at end of file
diff --git a/src/csharp/Grpc.sln b/src/csharp/Grpc.sln
index 84ba46047f71a05df8b3c7f253fa8e7f96b44cd4..beab3ccb36c48a5564b9a3c0b7877c95ddeb747a 100644
--- a/src/csharp/Grpc.sln
+++ b/src/csharp/Grpc.sln
@@ -1,125 +1,118 @@
-
-Microsoft Visual Studio Solution File, Format Version 12.00
-# Visual Studio 2012
-VisualStudioVersion = 12.0.31101.0
-MinimumVisualStudioVersion = 10.0.40219.1
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Grpc.Examples", "Grpc.Examples\Grpc.Examples.csproj", "{7DC1433E-3225-42C7-B7EA-546D56E27A4B}"
-EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Grpc.Core", "Grpc.Core\Grpc.Core.csproj", "{CCC4440E-49F7-4790-B0AF-FEABB0837AE7}"
-EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Grpc.Core.Tests", "Grpc.Core.Tests\Grpc.Core.Tests.csproj", "{86EC5CB4-4EA2-40A2-8057-86542A0353BB}"
-EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Grpc.Examples.Tests", "Grpc.Examples.Tests\Grpc.Examples.Tests.csproj", "{143B1C29-C442-4BE0-BF3F-A8F92288AC9F}"
-EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Grpc.Examples.MathClient", "Grpc.Examples.MathClient\Grpc.Examples.MathClient.csproj", "{61ECB8EE-0C96-4F8E-B187-8E4D227417C0}"
-EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Grpc.IntegrationTesting", "Grpc.IntegrationTesting\Grpc.IntegrationTesting.csproj", "{C61154BA-DD4A-4838-8420-0162A28925E0}"
-EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Grpc.IntegrationTesting.Client", "Grpc.IntegrationTesting.Client\Grpc.IntegrationTesting.Client.csproj", "{3D166931-BA2D-416E-95A3-D36E8F6E90B9}"
-EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Grpc.IntegrationTesting.Server", "Grpc.IntegrationTesting.Server\Grpc.IntegrationTesting.Server.csproj", "{A654F3B8-E859-4E6A-B30D-227527DBEF0D}"
-EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Grpc.Examples.MathServer", "Grpc.Examples.MathServer\Grpc.Examples.MathServer.csproj", "{BF62FE08-373A-43D6-9D73-41CAA38B7011}"
-EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Grpc.Auth", "Grpc.Auth\Grpc.Auth.csproj", "{AE21D0EE-9A2C-4C15-AB7F-5224EED5B0EA}"
-EndProject
-Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".nuget", ".nuget", "{B5B87121-35FE-49D1-8CB1-8A91AAA398A9}"
-	ProjectSection(SolutionItems) = preProject
-		.nuget\packages.config = .nuget\packages.config
-	EndProjectSection
-EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Grpc.HealthCheck", "Grpc.HealthCheck\Grpc.HealthCheck.csproj", "{AA5E328A-8835-49D7-98ED-C29F2B3049F0}"
-EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Grpc.HealthCheck.Tests", "Grpc.HealthCheck.Tests\Grpc.HealthCheck.Tests.csproj", "{F8C6D937-C44B-4EE3-A431-B0FBAEACE47D}"
-EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Grpc.IntegrationTesting.QpsWorker", "Grpc.IntegrationTesting.QpsWorker\Grpc.IntegrationTesting.QpsWorker.csproj", "{B82B7DFE-7F7B-40EF-B3D6-064FF2B01294}"
-EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Grpc.IntegrationTesting.StressClient", "Grpc.IntegrationTesting.StressClient\Grpc.IntegrationTesting.StressClient.csproj", "{ADEBA147-80AE-4710-82E9-5B7F93690266}"
-EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Grpc.Reflection", "Grpc.Reflection\Grpc.Reflection.csproj", "{4F18CF52-B3DB-4A77-97C5-7F7F4B6C1715}"
-EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Grpc.Reflection.Tests", "Grpc.Reflection.Tests\Grpc.Reflection.Tests.csproj", "{B88F91D6-436D-4C78-8B99-47800FA8DE03}"
-EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Grpc.Core.Testing", "Grpc.Core.Testing\Grpc.Core.Testing.csproj", "{3AB047CA-6CF9-435D-AA61-2D86C6FA2457}"
-EndProject
-Global
-	GlobalSection(SolutionConfigurationPlatforms) = preSolution
-		Debug|Any CPU = Debug|Any CPU
-		Release|Any CPU = Release|Any CPU
-	EndGlobalSection
-	GlobalSection(ProjectConfigurationPlatforms) = postSolution
-		{143B1C29-C442-4BE0-BF3F-A8F92288AC9F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
-		{143B1C29-C442-4BE0-BF3F-A8F92288AC9F}.Debug|Any CPU.Build.0 = Debug|Any CPU
-		{143B1C29-C442-4BE0-BF3F-A8F92288AC9F}.Release|Any CPU.ActiveCfg = Release|Any CPU
-		{143B1C29-C442-4BE0-BF3F-A8F92288AC9F}.Release|Any CPU.Build.0 = Release|Any CPU
-		{3D166931-BA2D-416E-95A3-D36E8F6E90B9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
-		{3D166931-BA2D-416E-95A3-D36E8F6E90B9}.Debug|Any CPU.Build.0 = Debug|Any CPU
-		{3D166931-BA2D-416E-95A3-D36E8F6E90B9}.Release|Any CPU.ActiveCfg = Release|Any CPU
-		{3D166931-BA2D-416E-95A3-D36E8F6E90B9}.Release|Any CPU.Build.0 = Release|Any CPU
-		{4F18CF52-B3DB-4A77-97C5-7F7F4B6C1715}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
-		{4F18CF52-B3DB-4A77-97C5-7F7F4B6C1715}.Debug|Any CPU.Build.0 = Debug|Any CPU
-		{4F18CF52-B3DB-4A77-97C5-7F7F4B6C1715}.Release|Any CPU.ActiveCfg = Release|Any CPU
-		{4F18CF52-B3DB-4A77-97C5-7F7F4B6C1715}.Release|Any CPU.Build.0 = Release|Any CPU
-		{61ECB8EE-0C96-4F8E-B187-8E4D227417C0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
-		{61ECB8EE-0C96-4F8E-B187-8E4D227417C0}.Debug|Any CPU.Build.0 = Debug|Any CPU
-		{61ECB8EE-0C96-4F8E-B187-8E4D227417C0}.Release|Any CPU.ActiveCfg = Release|Any CPU
-		{61ECB8EE-0C96-4F8E-B187-8E4D227417C0}.Release|Any CPU.Build.0 = Release|Any CPU
-		{7DC1433E-3225-42C7-B7EA-546D56E27A4B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
-		{7DC1433E-3225-42C7-B7EA-546D56E27A4B}.Debug|Any CPU.Build.0 = Debug|Any CPU
-		{7DC1433E-3225-42C7-B7EA-546D56E27A4B}.Release|Any CPU.ActiveCfg = Release|Any CPU
-		{7DC1433E-3225-42C7-B7EA-546D56E27A4B}.Release|Any CPU.Build.0 = Release|Any CPU
-		{86EC5CB4-4EA2-40A2-8057-86542A0353BB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
-		{86EC5CB4-4EA2-40A2-8057-86542A0353BB}.Debug|Any CPU.Build.0 = Debug|Any CPU
-		{86EC5CB4-4EA2-40A2-8057-86542A0353BB}.Release|Any CPU.ActiveCfg = Release|Any CPU
-		{86EC5CB4-4EA2-40A2-8057-86542A0353BB}.Release|Any CPU.Build.0 = Release|Any CPU
-		{A654F3B8-E859-4E6A-B30D-227527DBEF0D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
-		{A654F3B8-E859-4E6A-B30D-227527DBEF0D}.Debug|Any CPU.Build.0 = Debug|Any CPU
-		{A654F3B8-E859-4E6A-B30D-227527DBEF0D}.Release|Any CPU.ActiveCfg = Release|Any CPU
-		{A654F3B8-E859-4E6A-B30D-227527DBEF0D}.Release|Any CPU.Build.0 = Release|Any CPU
-		{AA5E328A-8835-49D7-98ED-C29F2B3049F0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
-		{AA5E328A-8835-49D7-98ED-C29F2B3049F0}.Debug|Any CPU.Build.0 = Debug|Any CPU
-		{AA5E328A-8835-49D7-98ED-C29F2B3049F0}.Release|Any CPU.ActiveCfg = Release|Any CPU
-		{AA5E328A-8835-49D7-98ED-C29F2B3049F0}.Release|Any CPU.Build.0 = Release|Any CPU
-		{ADEBA147-80AE-4710-82E9-5B7F93690266}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
-		{ADEBA147-80AE-4710-82E9-5B7F93690266}.Debug|Any CPU.Build.0 = Debug|Any CPU
-		{ADEBA147-80AE-4710-82E9-5B7F93690266}.Release|Any CPU.ActiveCfg = Release|Any CPU
-		{ADEBA147-80AE-4710-82E9-5B7F93690266}.Release|Any CPU.Build.0 = Release|Any CPU
-		{AE21D0EE-9A2C-4C15-AB7F-5224EED5B0EA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
-		{AE21D0EE-9A2C-4C15-AB7F-5224EED5B0EA}.Debug|Any CPU.Build.0 = Debug|Any CPU
-		{AE21D0EE-9A2C-4C15-AB7F-5224EED5B0EA}.Release|Any CPU.ActiveCfg = Release|Any CPU
-		{AE21D0EE-9A2C-4C15-AB7F-5224EED5B0EA}.Release|Any CPU.Build.0 = Release|Any CPU
-		{B82B7DFE-7F7B-40EF-B3D6-064FF2B01294}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
-		{B82B7DFE-7F7B-40EF-B3D6-064FF2B01294}.Debug|Any CPU.Build.0 = Debug|Any CPU
-		{B82B7DFE-7F7B-40EF-B3D6-064FF2B01294}.Release|Any CPU.ActiveCfg = Release|Any CPU
-		{B82B7DFE-7F7B-40EF-B3D6-064FF2B01294}.Release|Any CPU.Build.0 = Release|Any CPU
-		{B88F91D6-436D-4C78-8B99-47800FA8DE03}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
-		{B88F91D6-436D-4C78-8B99-47800FA8DE03}.Debug|Any CPU.Build.0 = Debug|Any CPU
-		{B88F91D6-436D-4C78-8B99-47800FA8DE03}.Release|Any CPU.ActiveCfg = Release|Any CPU
-		{B88F91D6-436D-4C78-8B99-47800FA8DE03}.Release|Any CPU.Build.0 = Release|Any CPU
-		{BF62FE08-373A-43D6-9D73-41CAA38B7011}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
-		{BF62FE08-373A-43D6-9D73-41CAA38B7011}.Debug|Any CPU.Build.0 = Debug|Any CPU
-		{BF62FE08-373A-43D6-9D73-41CAA38B7011}.Release|Any CPU.ActiveCfg = Release|Any CPU
-		{BF62FE08-373A-43D6-9D73-41CAA38B7011}.Release|Any CPU.Build.0 = Release|Any CPU
-		{C61154BA-DD4A-4838-8420-0162A28925E0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
-		{C61154BA-DD4A-4838-8420-0162A28925E0}.Debug|Any CPU.Build.0 = Debug|Any CPU
-		{C61154BA-DD4A-4838-8420-0162A28925E0}.Release|Any CPU.ActiveCfg = Release|Any CPU
-		{C61154BA-DD4A-4838-8420-0162A28925E0}.Release|Any CPU.Build.0 = Release|Any CPU
-		{CCC4440E-49F7-4790-B0AF-FEABB0837AE7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
-		{CCC4440E-49F7-4790-B0AF-FEABB0837AE7}.Debug|Any CPU.Build.0 = Debug|Any CPU
-		{CCC4440E-49F7-4790-B0AF-FEABB0837AE7}.Release|Any CPU.ActiveCfg = Release|Any CPU
-		{CCC4440E-49F7-4790-B0AF-FEABB0837AE7}.Release|Any CPU.Build.0 = Release|Any CPU
-		{F8C6D937-C44B-4EE3-A431-B0FBAEACE47D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
-		{F8C6D937-C44B-4EE3-A431-B0FBAEACE47D}.Debug|Any CPU.Build.0 = Debug|Any CPU
-		{F8C6D937-C44B-4EE3-A431-B0FBAEACE47D}.Release|Any CPU.ActiveCfg = Release|Any CPU
-		{F8C6D937-C44B-4EE3-A431-B0FBAEACE47D}.Release|Any CPU.Build.0 = Release|Any CPU
-		{3AB047CA-6CF9-435D-AA61-2D86C6FA2457}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
-		{3AB047CA-6CF9-435D-AA61-2D86C6FA2457}.Debug|Any CPU.Build.0 = Debug|Any CPU
-		{3AB047CA-6CF9-435D-AA61-2D86C6FA2457}.Release|Any CPU.ActiveCfg = Release|Any CPU
-		{3AB047CA-6CF9-435D-AA61-2D86C6FA2457}.Release|Any CPU.Build.0 = Release|Any CPU
-	EndGlobalSection
-	GlobalSection(NestedProjects) = preSolution
-	EndGlobalSection
-	GlobalSection(SolutionProperties) = preSolution
-		HideSolutionNode = FALSE
-	EndGlobalSection
-EndGlobal
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio 15
+VisualStudioVersion = 15.0.26228.4
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Grpc.Core", "Grpc.Core\Grpc.Core.csproj", "{BD878CB3-BDB4-46AB-84EF-C3B4729F56BC}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Grpc.Auth", "Grpc.Auth\Grpc.Auth.csproj", "{2A16007A-5D67-4C53-BEC8-51E5064D18BF}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Grpc.Core.Testing", "Grpc.Core.Testing\Grpc.Core.Testing.csproj", "{05DC61DF-26F3-4F51-8577-1ABE4F4388B0}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Grpc.Core.Tests", "Grpc.Core.Tests\Grpc.Core.Tests.csproj", "{02C79983-6011-43E2-A52D-75F9FC64663F}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Grpc.Examples", "Grpc.Examples\Grpc.Examples.csproj", "{C643975D-5D26-4860-8002-3B62A132DA2B}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Grpc.Examples.MathClient", "Grpc.Examples.MathClient\Grpc.Examples.MathClient.csproj", "{1F498972-FD16-4A02-B133-C24652F14869}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Grpc.Examples.MathServer", "Grpc.Examples.MathServer\Grpc.Examples.MathServer.csproj", "{9F2A873E-83E0-44C4-81D0-DDBC1D36F8B0}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Grpc.Examples.Tests", "Grpc.Examples.Tests\Grpc.Examples.Tests.csproj", "{7022461C-0D5E-4817-9A5A-3C027FD22457}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Grpc.HealthCheck", "Grpc.HealthCheck\Grpc.HealthCheck.csproj", "{DBD57899-0148-4B0D-A8EA-DE3954FA657C}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Grpc.HealthCheck.Tests", "Grpc.HealthCheck.Tests\Grpc.HealthCheck.Tests.csproj", "{033E4DC1-5D79-4308-B8B1-9A1B71E39BA1}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Grpc.IntegrationTesting", "Grpc.IntegrationTesting\Grpc.IntegrationTesting.csproj", "{CB43BF5B-4D31-4347-A97A-0164B1248B39}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Grpc.IntegrationTesting.Client", "Grpc.IntegrationTesting.Client\Grpc.IntegrationTesting.Client.csproj", "{83CCB684-54E6-4552-A00D-3CF9291A1B27}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Grpc.IntegrationTesting.QpsWorker", "Grpc.IntegrationTesting.QpsWorker\Grpc.IntegrationTesting.QpsWorker.csproj", "{8ED094CD-DF46-4272-A981-99F3DD184590}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Grpc.IntegrationTesting.Server", "Grpc.IntegrationTesting.Server\Grpc.IntegrationTesting.Server.csproj", "{F3A264BE-A62F-4B6A-89A0-7CF7BB275460}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Grpc.IntegrationTesting.StressClient", "Grpc.IntegrationTesting.StressClient\Grpc.IntegrationTesting.StressClient.csproj", "{0BB94A8B-9CE3-4A87-95BC-90F8A53CC154}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Grpc.Reflection", "Grpc.Reflection\Grpc.Reflection.csproj", "{26807744-FD0B-494A-9F99-0B171E9A892E}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Grpc.Reflection.Tests", "Grpc.Reflection.Tests\Grpc.Reflection.Tests.csproj", "{335AD0A2-F2CC-4C2E-853C-26174206BEE7}"
+EndProject
+Global
+	GlobalSection(SolutionConfigurationPlatforms) = preSolution
+		Debug|Any CPU = Debug|Any CPU
+		Release|Any CPU = Release|Any CPU
+	EndGlobalSection
+	GlobalSection(ProjectConfigurationPlatforms) = postSolution
+		{BD878CB3-BDB4-46AB-84EF-C3B4729F56BC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{BD878CB3-BDB4-46AB-84EF-C3B4729F56BC}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{BD878CB3-BDB4-46AB-84EF-C3B4729F56BC}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{BD878CB3-BDB4-46AB-84EF-C3B4729F56BC}.Release|Any CPU.Build.0 = Release|Any CPU
+		{2A16007A-5D67-4C53-BEC8-51E5064D18BF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{2A16007A-5D67-4C53-BEC8-51E5064D18BF}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{2A16007A-5D67-4C53-BEC8-51E5064D18BF}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{2A16007A-5D67-4C53-BEC8-51E5064D18BF}.Release|Any CPU.Build.0 = Release|Any CPU
+		{05DC61DF-26F3-4F51-8577-1ABE4F4388B0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{05DC61DF-26F3-4F51-8577-1ABE4F4388B0}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{05DC61DF-26F3-4F51-8577-1ABE4F4388B0}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{05DC61DF-26F3-4F51-8577-1ABE4F4388B0}.Release|Any CPU.Build.0 = Release|Any CPU
+		{02C79983-6011-43E2-A52D-75F9FC64663F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{02C79983-6011-43E2-A52D-75F9FC64663F}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{02C79983-6011-43E2-A52D-75F9FC64663F}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{02C79983-6011-43E2-A52D-75F9FC64663F}.Release|Any CPU.Build.0 = Release|Any CPU
+		{C643975D-5D26-4860-8002-3B62A132DA2B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{C643975D-5D26-4860-8002-3B62A132DA2B}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{C643975D-5D26-4860-8002-3B62A132DA2B}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{C643975D-5D26-4860-8002-3B62A132DA2B}.Release|Any CPU.Build.0 = Release|Any CPU
+		{1F498972-FD16-4A02-B133-C24652F14869}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{1F498972-FD16-4A02-B133-C24652F14869}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{1F498972-FD16-4A02-B133-C24652F14869}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{1F498972-FD16-4A02-B133-C24652F14869}.Release|Any CPU.Build.0 = Release|Any CPU
+		{9F2A873E-83E0-44C4-81D0-DDBC1D36F8B0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{9F2A873E-83E0-44C4-81D0-DDBC1D36F8B0}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{9F2A873E-83E0-44C4-81D0-DDBC1D36F8B0}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{9F2A873E-83E0-44C4-81D0-DDBC1D36F8B0}.Release|Any CPU.Build.0 = Release|Any CPU
+		{7022461C-0D5E-4817-9A5A-3C027FD22457}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{7022461C-0D5E-4817-9A5A-3C027FD22457}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{7022461C-0D5E-4817-9A5A-3C027FD22457}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{7022461C-0D5E-4817-9A5A-3C027FD22457}.Release|Any CPU.Build.0 = Release|Any CPU
+		{DBD57899-0148-4B0D-A8EA-DE3954FA657C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{DBD57899-0148-4B0D-A8EA-DE3954FA657C}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{DBD57899-0148-4B0D-A8EA-DE3954FA657C}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{DBD57899-0148-4B0D-A8EA-DE3954FA657C}.Release|Any CPU.Build.0 = Release|Any CPU
+		{033E4DC1-5D79-4308-B8B1-9A1B71E39BA1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{033E4DC1-5D79-4308-B8B1-9A1B71E39BA1}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{033E4DC1-5D79-4308-B8B1-9A1B71E39BA1}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{033E4DC1-5D79-4308-B8B1-9A1B71E39BA1}.Release|Any CPU.Build.0 = Release|Any CPU
+		{CB43BF5B-4D31-4347-A97A-0164B1248B39}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{CB43BF5B-4D31-4347-A97A-0164B1248B39}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{CB43BF5B-4D31-4347-A97A-0164B1248B39}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{CB43BF5B-4D31-4347-A97A-0164B1248B39}.Release|Any CPU.Build.0 = Release|Any CPU
+		{83CCB684-54E6-4552-A00D-3CF9291A1B27}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{83CCB684-54E6-4552-A00D-3CF9291A1B27}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{83CCB684-54E6-4552-A00D-3CF9291A1B27}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{83CCB684-54E6-4552-A00D-3CF9291A1B27}.Release|Any CPU.Build.0 = Release|Any CPU
+		{8ED094CD-DF46-4272-A981-99F3DD184590}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{8ED094CD-DF46-4272-A981-99F3DD184590}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{8ED094CD-DF46-4272-A981-99F3DD184590}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{8ED094CD-DF46-4272-A981-99F3DD184590}.Release|Any CPU.Build.0 = Release|Any CPU
+		{F3A264BE-A62F-4B6A-89A0-7CF7BB275460}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{F3A264BE-A62F-4B6A-89A0-7CF7BB275460}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{F3A264BE-A62F-4B6A-89A0-7CF7BB275460}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{F3A264BE-A62F-4B6A-89A0-7CF7BB275460}.Release|Any CPU.Build.0 = Release|Any CPU
+		{0BB94A8B-9CE3-4A87-95BC-90F8A53CC154}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{0BB94A8B-9CE3-4A87-95BC-90F8A53CC154}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{0BB94A8B-9CE3-4A87-95BC-90F8A53CC154}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{0BB94A8B-9CE3-4A87-95BC-90F8A53CC154}.Release|Any CPU.Build.0 = Release|Any CPU
+		{26807744-FD0B-494A-9F99-0B171E9A892E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{26807744-FD0B-494A-9F99-0B171E9A892E}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{26807744-FD0B-494A-9F99-0B171E9A892E}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{26807744-FD0B-494A-9F99-0B171E9A892E}.Release|Any CPU.Build.0 = Release|Any CPU
+		{335AD0A2-F2CC-4C2E-853C-26174206BEE7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{335AD0A2-F2CC-4C2E-853C-26174206BEE7}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{335AD0A2-F2CC-4C2E-853C-26174206BEE7}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{335AD0A2-F2CC-4C2E-853C-26174206BEE7}.Release|Any CPU.Build.0 = Release|Any CPU
+	EndGlobalSection
+	GlobalSection(SolutionProperties) = preSolution
+		HideSolutionNode = FALSE
+	EndGlobalSection
+EndGlobal
diff --git a/src/csharp/README.md b/src/csharp/README.md
index a21b72f2253083a081997ee1bd60dd6c9bb92648..a973d2e59709f1c66e1dcb0993503a74ce086678 100644
--- a/src/csharp/README.md
+++ b/src/csharp/README.md
@@ -16,7 +16,7 @@ PREREQUISITES
 
 When using gRPC C# under .NET Core you only need to [install .NET Core](https://www.microsoft.com/net/core).
 
-- Windows: .NET Framework 4.5+, Visual Studio 2013 or 2015
+- Windows: .NET Framework 4.5+, Visual Studio 2013, 2015, 2017
 - Linux: Mono 4+, MonoDevelop 5.9+ (with NuGet add-in installed)
 - Mac OS X: Xamarin Studio 5.9+
 
@@ -45,7 +45,9 @@ If you are a user of gRPC C#, go to Usage section above.
   $ python tools/run_tests/run_tests.py -c dbg -l csharp --build_only
   ```
 
-- Use Visual Studio / MonoDevelop / Xamarin Studio to open the solution Grpc.sln
+- Use Visual Studio 2017 (on Windows) to open the solution `Grpc.sln` or use Visual Studio Code with C# extension (on Linux and Mac). gRPC C# code has been migrated to
+  dotnet SDK `.csproj` projects that are much simpler to maintain, but are not yet supported by Xamarin Studio or Monodevelop (the NuGet packages still
+  support both `net45` and `netstandard` and can be used in all IDEs).
 
 RUNNING TESTS
 -------------
@@ -55,9 +57,6 @@ gRPC C# is using NUnit as the testing framework.
 Under Visual Studio, make sure NUnit test adapter is installed (under "Extensions and Updates").
 Then you should be able to run all the tests using Test Explorer.
 
-Under Monodevelop or Xamarin Studio, make sure you installed "NUnit support" in Add-in manager.
-Then you should be able to run all the test from the Test View.
-
 gRPC team uses a Python script to simplify facilitate running tests for
 different languages.
 
diff --git a/src/csharp/build_packages_dotnetcli.bat b/src/csharp/build_packages_dotnetcli.bat
index 4fec2c71cf8b28761d6b7237cd5e526bb6abe226..7558ca60c71794d4435a1a1b01464566b4f09a35 100755
--- a/src/csharp/build_packages_dotnetcli.bat
+++ b/src/csharp/build_packages_dotnetcli.bat
@@ -29,11 +29,10 @@
 
 @rem Current package versions
 set VERSION=1.3.0-dev
-set PROTOBUF_VERSION=3.0.0
 
 @rem Adjust the location of nuget.exe
 set NUGET=C:\nuget\nuget.exe
-set DOTNET=C:\dotnet\dotnet.exe
+set DOTNET=dotnet
 
 set -ex
 
@@ -56,13 +55,16 @@ xcopy /Y /I ..\..\architecture=x64,language=protoc,platform=linux\artifacts\* pr
 xcopy /Y /I ..\..\architecture=x86,language=protoc,platform=macos\artifacts\* protoc_plugins\macosx_x86\
 xcopy /Y /I ..\..\architecture=x64,language=protoc,platform=macos\artifacts\* protoc_plugins\macosx_x64\
 
-%DOTNET% restore . || goto :error
+%DOTNET% restore Grpc.sln || goto :error
 
-%DOTNET% pack --configuration Release Grpc.Core\project.json --output ..\..\artifacts || goto :error
-%DOTNET% pack --configuration Release Grpc.Core.Testing\project.json --output ..\..\artifacts || goto :error
-%DOTNET% pack --configuration Release Grpc.Auth\project.json --output ..\..\artifacts || goto :error
-%DOTNET% pack --configuration Release Grpc.HealthCheck\project.json --output ..\..\artifacts || goto :error
-%DOTNET% pack --configuration Release Grpc.Reflection\project.json --output ..\..\artifacts || goto :error
+@rem To be able to build, we also need to put grpc_csharp_ext to its normal location
+xcopy /Y /I nativelibs\windows_x64\grpc_csharp_ext.dll ..\..\cmake\build\x64\Release\
+
+%DOTNET% pack --configuration Release Grpc.Core --output ..\..\..\artifacts || goto :error
+%DOTNET% pack --configuration Release Grpc.Core.Testing --output ..\..\..\artifacts || goto :error
+%DOTNET% pack --configuration Release Grpc.Auth --output ..\..\..\artifacts || goto :error
+%DOTNET% pack --configuration Release Grpc.HealthCheck --output ..\..\..\artifacts || goto :error
+%DOTNET% pack --configuration Release Grpc.Reflection --output ..\..\..\artifacts || goto :error
 
 %NUGET% pack Grpc.nuspec -Version %VERSION% -OutputDirectory ..\..\artifacts || goto :error
 %NUGET% pack Grpc.Tools.nuspec -Version %VERSION% -OutputDirectory ..\..\artifacts
diff --git a/src/csharp/build_packages_dotnetcli.sh b/src/csharp/build_packages_dotnetcli.sh
index f51b42bc8c10dffd533b50d24e94b196b88879bd..2186bd3c56805607343aa13cc753cab2be428658 100755
--- a/src/csharp/build_packages_dotnetcli.sh
+++ b/src/csharp/build_packages_dotnetcli.sh
@@ -58,13 +58,17 @@ cp $EXTERNAL_GIT_ROOT/architecture=x64,language=protoc,platform=linux/artifacts/
 cp $EXTERNAL_GIT_ROOT/architecture=x86,language=protoc,platform=macos/artifacts/* protoc_plugins/macosx_x86 || true
 cp $EXTERNAL_GIT_ROOT/architecture=x64,language=protoc,platform=macos/artifacts/* protoc_plugins/macosx_x64 || true
 
-dotnet restore .
+dotnet restore Grpc.sln
 
-dotnet pack --configuration Release Grpc.Core/project.json --output ../../artifacts
-dotnet pack --configuration Release Grpc.Core.Testing/project.json --output ../../artifacts
-dotnet pack --configuration Release Grpc.Auth/project.json --output ../../artifacts
-dotnet pack --configuration Release Grpc.HealthCheck/project.json --output ../../artifacts
-dotnet pack --configuration Release Grpc.Reflection/project.json --output ../../artifacts
+# To be able to build, we also need to put grpc_csharp_ext to its normal location
+mkdir -p ../../libs/opt
+cp nativelibs/linux_x64/libgrpc_csharp_ext.so ../../libs/opt
+
+dotnet pack --configuration Release Grpc.Core --output ../../../artifacts
+dotnet pack --configuration Release Grpc.Core.Testing --output ../../../artifacts
+dotnet pack --configuration Release Grpc.Auth --output ../../../artifacts
+dotnet pack --configuration Release Grpc.HealthCheck --output ../../../artifacts
+dotnet pack --configuration Release Grpc.Reflection --output ../../../artifacts
 
 nuget pack Grpc.nuspec -Version "1.3.0-dev" -OutputDirectory ../../artifacts
 nuget pack Grpc.Tools.nuspec -Version "1.3.0-dev" -OutputDirectory ../../artifacts
diff --git a/src/csharp/global.json b/src/csharp/global.json
deleted file mode 100644
index 32ff399ef948d2a97a69c8ede4bf04ffd9203326..0000000000000000000000000000000000000000
--- a/src/csharp/global.json
+++ /dev/null
@@ -1,5 +0,0 @@
-{
-    "sdk": {
-        "version": "1.0.0-preview2-003121"
-    }
-}
\ No newline at end of file
diff --git a/src/node/index.js b/src/node/index.js
index a294aad8ee6ca2a7261b5281dea9492aa003fa5d..071bfd7927bab798c2bf0920355be32c54cd7242 100644
--- a/src/node/index.js
+++ b/src/node/index.js
@@ -52,42 +52,89 @@ var Metadata = require('./src/metadata.js');
 
 var grpc = require('./src/grpc_extension');
 
+var protobuf_js_5_common = require('./src/protobuf_js_5_common');
+var protobuf_js_6_common = require('./src/protobuf_js_6_common');
+
 grpc.setDefaultRootsPem(fs.readFileSync(SSL_ROOTS_PATH, 'ascii'));
 
 /**
- * Load a gRPC object from an existing ProtoBuf.Reflect object.
- * @param {ProtoBuf.Reflect.Namespace} value The ProtoBuf object to load.
- * @param {Object=} options Options to apply to the loaded object
+ * Load a ProtoBuf.js object as a gRPC object. The options object can provide
+ * the following options:
+ * - binaryAsBase64: deserialize bytes values as base64 strings instead of
+ *   Buffers. Defaults to false
+ * - longsAsStrings: deserialize long values as strings instead of objects.
+ *   Defaults to true
+ * - enumsAsStrings: deserialize enum values as strings instead of numbers.
+ *   Defaults to true
+ * - deprecatedArgumentOrder: Use the beta method argument order for client
+ *   methods, with optional arguments after the callback. Defaults to false.
+ *   This option is only a temporary stopgap measure to smooth an API breakage.
+ *   It is deprecated, and new code should not use it.
+ * - protobufjsVersion: Available values are 5, 6, and 'detect'. 5 and 6
+ *   respectively indicate that an object from the corresponding version of
+ *   ProtoBuf.js is provided in the value argument. If the option is 'detect',
+ *   gRPC will guess what the version is based on the structure of the value.
+ *   Defaults to 'detect'.
+ * @param {Object} value The ProtoBuf.js reflection object to load
+ * @param {Object=} options Options to apply to the loaded file
  * @return {Object<string, *>} The resulting gRPC object
  */
 exports.loadObject = function loadObject(value, options) {
-  var result = {};
-  if (value.className === 'Namespace') {
-    _.each(value.children, function(child) {
-      result[child.name] = loadObject(child, options);
-    });
-    return result;
-  } else if (value.className === 'Service') {
-    return client.makeProtobufClientConstructor(value, options);
-  } else if (value.className === 'Message' || value.className === 'Enum') {
-    return value.build();
+  options = _.defaults(options, common.defaultGrpcOptions);
+  options = _.defaults(options, {'protobufjsVersion': 'detect'});
+  var protobufjsVersion;
+  if (options.protobufjsVersion === 'detect') {
+    if (protobuf_js_6_common.isProbablyProtobufJs6(value)) {
+      protobufjsVersion = 6;
+    } else if (protobuf_js_5_common.isProbablyProtobufJs5(value)) {
+      protobufjsVersion = 5;
+    } else {
+      var error_message = 'Could not detect ProtoBuf.js version. Please ' +
+          'specify the version number with the "protobufjs_version" option';
+      throw new Error(error_message);
+    }
   } else {
-    return value;
+    protobufjsVersion = options.protobufjsVersion;
+  }
+  switch (protobufjsVersion) {
+    case 6: return protobuf_js_6_common.loadObject(value, options);
+    case 5:
+    var deprecation_message = 'Calling grpc.loadObject with an object ' +
+        'generated by ProtoBuf.js 5 is deprecated. Please upgrade to ' +
+        'ProtoBuf.js 6.';
+    common.log(grpc.logVerbosity.INFO, deprecation_message);
+    return protobuf_js_5_common.loadObject(value, options);
+    default:
+    throw new Error('Unrecognized protobufjsVersion', protobufjsVersion);
   }
 };
 
 var loadObject = exports.loadObject;
 
+function applyProtoRoot(filename, root) {
+  if (_.isString(filename)) {
+    return filename;
+  }
+  filename.root = path.resolve(filename.root) + '/';
+  root.resolvePath = function(originPath, importPath, alreadyNormalized) {
+    return ProtoBuf.util.path.resolve(filename.root,
+                                      importPath,
+                                      alreadyNormalized);
+  };
+  return filename.file;
+}
+
 /**
  * Load a gRPC object from a .proto file. The options object can provide the
  * following options:
- * - convertFieldsToCamelCase: Loads this file with that option on protobuf.js
- *   set as specified. See
- *   https://github.com/dcodeIO/protobuf.js/wiki/Advanced-options for details
+ * - convertFieldsToCamelCase: Load this file with field names in camel case
+ *   instead of their original case
  * - binaryAsBase64: deserialize bytes values as base64 strings instead of
  *   Buffers. Defaults to false
  * - longsAsStrings: deserialize long values as strings instead of objects.
  *   Defaults to true
+ * - enumsAsStrings: deserialize enum values as strings instead of numbers.
+ *   Defaults to true
  * - deprecatedArgumentOrder: Use the beta method argument order for client
  *   methods, with optional arguments after the callback. Defaults to false.
  *   This option is only a temporary stopgap measure to smooth an API breakage.
@@ -99,29 +146,17 @@ var loadObject = exports.loadObject;
  * @return {Object<string, *>} The resulting gRPC object
  */
 exports.load = function load(filename, format, options) {
-  if (!format) {
-    format = 'proto';
-  }
-  var convertFieldsToCamelCaseOriginal = ProtoBuf.convertFieldsToCamelCase;
-  if(options && options.hasOwnProperty('convertFieldsToCamelCase')) {
-    ProtoBuf.convertFieldsToCamelCase = options.convertFieldsToCamelCase;
-  }
-  var builder;
-  try {
-    switch(format) {
-      case 'proto':
-      builder = ProtoBuf.loadProtoFile(filename);
-      break;
-      case 'json':
-      builder = ProtoBuf.loadJsonFile(filename);
-      break;
-      default:
-      throw new Error('Unrecognized format "' + format + '"');
-    }
-  } finally {
-    ProtoBuf.convertFieldsToCamelCase = convertFieldsToCamelCaseOriginal;
-  }
-  return loadObject(builder.ns, options);
+  /* Note: format is currently unused, because the API for loading a proto
+     file or a JSON file is identical in Protobuf.js 6. In the future, there is
+     still the possibility of adding other formats that would be loaded
+     differently */
+  options = _.defaults(options, common.defaultGrpcOptions);
+  options.protobufjs_version = 6;
+  var root = new ProtoBuf.Root();
+  var parse_options = {keepCase: !options.convertFieldsToCamelCase};
+  return loadObject(root.loadSync(applyProtoRoot(filename, root),
+                                  parse_options),
+                    options);
 };
 
 var log_template = _.template(
diff --git a/src/node/interop/interop_server.js b/src/node/interop/interop_server.js
index 05f52a1083de9d6a2e54d876405af7427518f775..83b8a7c1ec3c36b4e133f0e66950d1bdbaa08c21 100644
--- a/src/node/interop/interop_server.js
+++ b/src/node/interop/interop_server.js
@@ -228,7 +228,7 @@ function getServer(port, tls) {
     server_creds = grpc.ServerCredentials.createInsecure();
   }
   var server = new grpc.Server(options);
-  server.addProtoService(testProto.TestService.service, {
+  server.addService(testProto.TestService.service, {
     emptyCall: handleEmpty,
     unaryCall: handleUnary,
     streamingOutputCall: handleStreamingOutput,
diff --git a/src/node/performance/benchmark_client_express.js b/src/node/performance/benchmark_client_express.js
index 675eb5f28847926f7832c615eec82d7091b5ad79..e749956599dc15c30e49c9bf9bb9ce31ef4d6056 100644
--- a/src/node/performance/benchmark_client_express.js
+++ b/src/node/performance/benchmark_client_express.js
@@ -93,7 +93,7 @@ function BenchmarkClient(server_targets, channels, histogram_params,
 
   for (var i = 0; i < channels; i++) {
     var host_port;
-    host_port = server_targets[i % server_targets.length].split(':')
+    host_port = server_targets[i % server_targets.length].split(':');
     var new_options = _.assign({hostname: host_port[0], port: +host_port[1]}, options);
     new_options.agent = new protocol.Agent(new_options);
     this.client_options[i] = new_options;
@@ -149,6 +149,17 @@ BenchmarkClient.prototype.startClosedLoop = function(
     if (self.running) {
       self.pending_calls++;
       var start_time = process.hrtime();
+      function finishCall(success) {
+        if (success) {
+          var time_diff = process.hrtime(start_time);
+          self.histogram.add(timeDiffToNanos(time_diff));
+        }
+        makeCall(client_options);
+        self.pending_calls--;
+        if ((!self.running) && self.pending_calls == 0) {
+          self.emit('finished');
+        }
+      }
       var req = self.request(client_options, function(res) {
         var res_data = '';
         res.on('data', function(data) {
@@ -156,18 +167,16 @@ BenchmarkClient.prototype.startClosedLoop = function(
         });
         res.on('end', function() {
           JSON.parse(res_data);
-          var time_diff = process.hrtime(start_time);
-          self.histogram.add(timeDiffToNanos(time_diff));
-          makeCall(client_options);
-          self.pending_calls--;
-          if ((!self.running) && self.pending_calls == 0) {
-            self.emit('finished');
-          }
+          finishCall(true);
         });
       });
       req.write(JSON.stringify(argument));
       req.end();
       req.on('error', function(error) {
+        if (error.code === 'ECONNRESET' || error.code === 'ETIMEDOUT') {
+          finishCall(false);
+          return;
+        }
         self.emit('error', new Error('Client error: ' + error.message));
         self.running = false;
       });
diff --git a/src/node/performance/benchmark_server.js b/src/node/performance/benchmark_server.js
index 7158af775a49dfe2449a8a744a13c1b58cddd21a..ea85029d980dd3df3fa5cca6a0c1836fb8fca70b 100644
--- a/src/node/performance/benchmark_server.js
+++ b/src/node/performance/benchmark_server.js
@@ -140,7 +140,7 @@ function BenchmarkServer(host, port, tls, generic, response_size) {
       streamingCall: makeStreamingGenericCall(response_size)
     });
   } else {
-    server.addProtoService(serviceProto.BenchmarkService.service, {
+    server.addService(serviceProto.BenchmarkService.service, {
       unaryCall: unaryCall,
       streamingCall: streamingCall
     });
diff --git a/src/node/performance/benchmark_server_express.js b/src/node/performance/benchmark_server_express.js
index 065bcf660b6e5c0e4dc0a49b59d1513b52a55fb1..4b695eb467db12ad3b75ac8380f81c7c7c729e64 100644
--- a/src/node/performance/benchmark_server_express.js
+++ b/src/node/performance/benchmark_server_express.js
@@ -46,7 +46,7 @@ var EventEmitter = require('events');
 var util = require('util');
 
 var express = require('express');
-var bodyParser = require('body-parser')
+var bodyParser = require('body-parser');
 
 function unaryCall(req, res) {
   var reqObj = req.body;
@@ -56,7 +56,7 @@ function unaryCall(req, res) {
 
 function BenchmarkServer(host, port, tls, generic, response_size) {
   var app = express();
-  app.use(bodyParser.json())
+  app.use(bodyParser.json());
   app.put('/serviceProto.BenchmarkService.service/unaryCall', unaryCall);
   this.input_host = host;
   this.input_port = port;
diff --git a/src/node/performance/worker.js b/src/node/performance/worker.js
index 030bf7d7ba052683d46800e4be581930909203a3..90a9b7d59cd779f29aa195c037aa4486ba2eb020 100644
--- a/src/node/performance/worker.js
+++ b/src/node/performance/worker.js
@@ -44,8 +44,8 @@ var serviceProto = grpc.load({
 function runServer(port, benchmark_impl) {
   var server_creds = grpc.ServerCredentials.createInsecure();
   var server = new grpc.Server();
-  server.addProtoService(serviceProto.WorkerService.service,
-                         new WorkerServiceImpl(benchmark_impl, server));
+  server.addService(serviceProto.WorkerService.service,
+                    new WorkerServiceImpl(benchmark_impl, server));
   var address = '0.0.0.0:' + port;
   server.bind(address, server_creds);
   server.start();
diff --git a/src/node/src/client.js b/src/node/src/client.js
index 44081a3a6cd42965d0364d3e3c09fa438be3d6ab..1aaf35c16cbc918bdd220e3ba04b2832817576db 100644
--- a/src/node/src/client.js
+++ b/src/node/src/client.js
@@ -780,6 +780,8 @@ exports.makeClientConstructor = function(methods, serviceName,
     _.assign(Client.prototype[name], attrs);
   });
 
+  Client.service = methods;
+
   return Client;
 };
 
@@ -822,26 +824,6 @@ exports.waitForClientReady = function(client, deadline, callback) {
   checkState();
 };
 
-/**
- * Creates a constructor for clients for the given service
- * @param {ProtoBuf.Reflect.Service} service The service to generate a client
- *     for
- * @param {Object=} options Options to apply to the client
- * @return {function(string, Object)} New client constructor
- */
-exports.makeProtobufClientConstructor =  function(service, options) {
-  var method_attrs = common.getProtobufServiceAttrs(service, options);
-  if (!options) {
-    options = {deprecatedArgumentOrder: false};
-  }
-  var Client = exports.makeClientConstructor(
-      method_attrs, common.fullyQualifiedName(service),
-      options);
-  Client.service = service;
-  Client.service.grpc_options = options;
-  return Client;
-};
-
 /**
  * Map of status code names to status codes
  */
diff --git a/src/node/src/common.js b/src/node/src/common.js
index a0fe4480eab9f3e59785ef95002756e950d38536..757969dbddb147a162738d6e61977cd6904d7229 100644
--- a/src/node/src/common.js
+++ b/src/node/src/common.js
@@ -41,74 +41,6 @@
 
 var _ = require('lodash');
 
-/**
- * Get a function that deserializes a specific type of protobuf.
- * @param {function()} cls The constructor of the message type to deserialize
- * @param {bool=} binaryAsBase64 Deserialize bytes fields as base64 strings
- *     instead of Buffers. Defaults to false
- * @param {bool=} longsAsStrings Deserialize long values as strings instead of
- *     objects. Defaults to true
- * @return {function(Buffer):cls} The deserialization function
- */
-exports.deserializeCls = function deserializeCls(cls, binaryAsBase64,
-                                                 longsAsStrings) {
-  if (binaryAsBase64 === undefined || binaryAsBase64 === null) {
-    binaryAsBase64 = false;
-  }
-  if (longsAsStrings === undefined || longsAsStrings === null) {
-    longsAsStrings = true;
-  }
-  /**
-   * Deserialize a buffer to a message object
-   * @param {Buffer} arg_buf The buffer to deserialize
-   * @return {cls} The resulting object
-   */
-  return function deserialize(arg_buf) {
-    // Convert to a native object with binary fields as Buffers (first argument)
-    // and longs as strings (second argument)
-    return cls.decode(arg_buf).toRaw(binaryAsBase64, longsAsStrings);
-  };
-};
-
-var deserializeCls = exports.deserializeCls;
-
-/**
- * Get a function that serializes objects to a buffer by protobuf class.
- * @param {function()} Cls The constructor of the message type to serialize
- * @return {function(Cls):Buffer} The serialization function
- */
-exports.serializeCls = function serializeCls(Cls) {
-  /**
-   * Serialize an object to a Buffer
-   * @param {Object} arg The object to serialize
-   * @return {Buffer} The serialized object
-   */
-  return function serialize(arg) {
-    return new Buffer(new Cls(arg).encode().toBuffer());
-  };
-};
-
-var serializeCls = exports.serializeCls;
-
-/**
- * Get the fully qualified (dotted) name of a ProtoBuf.Reflect value.
- * @param {ProtoBuf.Reflect.Namespace} value The value to get the name of
- * @return {string} The fully qualified name of the value
- */
-exports.fullyQualifiedName = function fullyQualifiedName(value) {
-  if (value === null || value === undefined) {
-    return '';
-  }
-  var name = value.name;
-  var parent_name = fullyQualifiedName(value.parent);
-  if (parent_name !== '') {
-    name = parent_name + '.' + name;
-  }
-  return name;
-};
-
-var fullyQualifiedName = exports.fullyQualifiedName;
-
 /**
  * Wrap a function to pass null-like values through without calling it. If no
  * function is given, just uses the identity;
@@ -127,44 +59,6 @@ exports.wrapIgnoreNull = function wrapIgnoreNull(func) {
   };
 };
 
-/**
- * Return a map from method names to method attributes for the service.
- * @param {ProtoBuf.Reflect.Service} service The service to get attributes for
- * @param {Object=} options Options to apply to these attributes
- * @return {Object} The attributes map
- */
-exports.getProtobufServiceAttrs = function getProtobufServiceAttrs(service,
-                                                                   options) {
-  var prefix = '/' + fullyQualifiedName(service) + '/';
-  var binaryAsBase64, longsAsStrings;
-  if (options) {
-    binaryAsBase64 = options.binaryAsBase64;
-    longsAsStrings = options.longsAsStrings;
-  }
-  /* This slightly awkward construction is used to make sure we only use
-     lodash@3.10.1-compatible functions. A previous version used
-     _.fromPairs, which would be cleaner, but was introduced in lodash
-     version 4 */
-  return _.zipObject(_.map(service.children, function(method) {
-    return _.camelCase(method.name);
-  }), _.map(service.children, function(method) {
-    return {
-      originalName: method.name,
-      path: prefix + method.name,
-      requestStream: method.requestStream,
-      responseStream: method.responseStream,
-      requestType: method.resolvedRequestType,
-      responseType: method.resolvedResponseType,
-      requestSerialize: serializeCls(method.resolvedRequestType.build()),
-      requestDeserialize: deserializeCls(method.resolvedRequestType.build(),
-                                         binaryAsBase64, longsAsStrings),
-      responseSerialize: serializeCls(method.resolvedResponseType.build()),
-      responseDeserialize: deserializeCls(method.resolvedResponseType.build(),
-                                          binaryAsBase64, longsAsStrings)
-    };
-  }));
-};
-
 /**
  * The logger object for the gRPC module. Defaults to console.
  */
@@ -185,3 +79,14 @@ exports.log = function log(severity, message) {
     exports.logger.error(message);
   }
 };
+
+/**
+ * Default options for loading proto files into gRPC
+ */
+exports.defaultGrpcOptions = {
+  convertFieldsToCamelCase: false,
+  binaryAsBase64: false,
+  longsAsStrings: true,
+  enumsAsStrings: true,
+  deprecatedArgumentOrder: false
+};
diff --git a/src/node/src/protobuf_js_5_common.js b/src/node/src/protobuf_js_5_common.js
new file mode 100644
index 0000000000000000000000000000000000000000..62cf2f4acaa4ffffc600200ac7ace73d575a09d8
--- /dev/null
+++ b/src/node/src/protobuf_js_5_common.js
@@ -0,0 +1,181 @@
+/*
+ *
+ * Copyright 2017, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+'use strict';
+
+var _ = require('lodash');
+var client = require('./client');
+
+/**
+ * Get a function that deserializes a specific type of protobuf.
+ * @param {function()} cls The constructor of the message type to deserialize
+ * @param {bool=} binaryAsBase64 Deserialize bytes fields as base64 strings
+ *     instead of Buffers. Defaults to false
+ * @param {bool=} longsAsStrings Deserialize long values as strings instead of
+ *     objects. Defaults to true
+ * @return {function(Buffer):cls} The deserialization function
+ */
+exports.deserializeCls = function deserializeCls(cls, binaryAsBase64,
+                                                 longsAsStrings) {
+  /**
+   * Deserialize a buffer to a message object
+   * @param {Buffer} arg_buf The buffer to deserialize
+   * @return {cls} The resulting object
+   */
+  return function deserialize(arg_buf) {
+    // Convert to a native object with binary fields as Buffers (first argument)
+    // and longs as strings (second argument)
+    return cls.decode(arg_buf).toRaw(binaryAsBase64, longsAsStrings);
+  };
+};
+
+var deserializeCls = exports.deserializeCls;
+
+/**
+ * Get a function that serializes objects to a buffer by protobuf class.
+ * @param {function()} Cls The constructor of the message type to serialize
+ * @return {function(Cls):Buffer} The serialization function
+ */
+exports.serializeCls = function serializeCls(Cls) {
+  /**
+   * Serialize an object to a Buffer
+   * @param {Object} arg The object to serialize
+   * @return {Buffer} The serialized object
+   */
+  return function serialize(arg) {
+    return new Buffer(new Cls(arg).encode().toBuffer());
+  };
+};
+
+var serializeCls = exports.serializeCls;
+
+/**
+ * Get the fully qualified (dotted) name of a ProtoBuf.Reflect value.
+ * @param {ProtoBuf.Reflect.Namespace} value The value to get the name of
+ * @return {string} The fully qualified name of the value
+ */
+exports.fullyQualifiedName = function fullyQualifiedName(value) {
+  if (value === null || value === undefined) {
+    return '';
+  }
+  var name = value.name;
+  var parent_name = fullyQualifiedName(value.parent);
+  if (parent_name !== '') {
+    name = parent_name + '.' + name;
+  }
+  return name;
+};
+
+var fullyQualifiedName = exports.fullyQualifiedName;
+
+/**
+ * Return a map from method names to method attributes for the service.
+ * @param {ProtoBuf.Reflect.Service} service The service to get attributes for
+ * @param {Object=} options Options to apply to these attributes
+ * @return {Object} The attributes map
+ */
+exports.getProtobufServiceAttrs = function getProtobufServiceAttrs(service,
+                                                                   options) {
+  var prefix = '/' + fullyQualifiedName(service) + '/';
+  var binaryAsBase64, longsAsStrings;
+  if (options) {
+    binaryAsBase64 = options.binaryAsBase64;
+    longsAsStrings = options.longsAsStrings;
+  }
+  /* This slightly awkward construction is used to make sure we only use
+     lodash@3.10.1-compatible functions. A previous version used
+     _.fromPairs, which would be cleaner, but was introduced in lodash
+     version 4 */
+  return _.zipObject(_.map(service.children, function(method) {
+    return _.camelCase(method.name);
+  }), _.map(service.children, function(method) {
+    return {
+      originalName: method.name,
+      path: prefix + method.name,
+      requestStream: method.requestStream,
+      responseStream: method.responseStream,
+      requestType: method.resolvedRequestType,
+      responseType: method.resolvedResponseType,
+      requestSerialize: serializeCls(method.resolvedRequestType.build()),
+      requestDeserialize: deserializeCls(method.resolvedRequestType.build(),
+                                         binaryAsBase64, longsAsStrings),
+      responseSerialize: serializeCls(method.resolvedResponseType.build()),
+      responseDeserialize: deserializeCls(method.resolvedResponseType.build(),
+                                          binaryAsBase64, longsAsStrings)
+    };
+  }));
+};
+
+var getProtobufServiceAttrs = exports.getProtobufServiceAttrs;
+
+/**
+ * Load a gRPC object from an existing ProtoBuf.Reflect object.
+ * @param {ProtoBuf.Reflect.Namespace} value The ProtoBuf object to load.
+ * @param {Object=} options Options to apply to the loaded object
+ * @return {Object<string, *>} The resulting gRPC object
+ */
+exports.loadObject = function loadObject(value, options) {
+  var result = {};
+  if (!value) {
+    return value;
+  }
+  if (value.hasOwnProperty('ns')) {
+    return loadObject(value.ns, options);
+  }
+  if (value.className === 'Namespace') {
+    _.each(value.children, function(child) {
+      result[child.name] = loadObject(child, options);
+    });
+    return result;
+  } else if (value.className === 'Service') {
+    return client.makeClientConstructor(getProtobufServiceAttrs(value, options),
+                                        options);
+  } else if (value.className === 'Message' || value.className === 'Enum') {
+    return value.build();
+  } else {
+    return value;
+  }
+};
+
+/**
+ * The primary purpose of this method is to distinguish between reflection
+ * objects from different versions of ProtoBuf.js. This is just a heuristic,
+ * checking for properties that are (currently) specific to this version of
+ * ProtoBuf.js
+ * @param {Object} obj The object to check
+ * @return {boolean} Whether the object appears to be a Protobuf.js 5
+ *   ReflectionObject
+ */
+exports.isProbablyProtobufJs5 = function isProbablyProtobufJs5(obj) {
+  return _.isArray(obj.children) && (typeof obj.build === 'function');
+};
diff --git a/src/node/src/protobuf_js_6_common.js b/src/node/src/protobuf_js_6_common.js
new file mode 100644
index 0000000000000000000000000000000000000000..00f11f27363857ea30dfeb2f567fcf955040783a
--- /dev/null
+++ b/src/node/src/protobuf_js_6_common.js
@@ -0,0 +1,170 @@
+/*
+ *
+ * Copyright 2017, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+'use strict';
+
+var _ = require('lodash');
+var client = require('./client');
+
+/**
+ * Get a function that deserializes a specific type of protobuf.
+ * @param {function()} cls The constructor of the message type to deserialize
+ * @param {bool=} binaryAsBase64 Deserialize bytes fields as base64 strings
+ *     instead of Buffers. Defaults to false
+ * @param {bool=} longsAsStrings Deserialize long values as strings instead of
+ *     objects. Defaults to true
+ * @return {function(Buffer):cls} The deserialization function
+ */
+exports.deserializeCls = function deserializeCls(cls, options) {
+  var conversion_options = {
+    defaults: true,
+    bytes: options.binaryAsBase64 ? String : Buffer,
+    longs: options.longsAsStrings ? String : null,
+    enums: options.enumsAsStrings ? String : null,
+    oneofs: true
+  };
+  /**
+   * Deserialize a buffer to a message object
+   * @param {Buffer} arg_buf The buffer to deserialize
+   * @return {cls} The resulting object
+   */
+  return function deserialize(arg_buf) {
+    return cls.decode(arg_buf).toObject(conversion_options);
+  };
+};
+
+var deserializeCls = exports.deserializeCls;
+
+/**
+ * Get a function that serializes objects to a buffer by protobuf class.
+ * @param {function()} Cls The constructor of the message type to serialize
+ * @return {function(Cls):Buffer} The serialization function
+ */
+exports.serializeCls = function serializeCls(cls) {
+  /**
+   * Serialize an object to a Buffer
+   * @param {Object} arg The object to serialize
+   * @return {Buffer} The serialized object
+   */
+  return function serialize(arg) {
+    var message = cls.fromObject(arg);
+    return cls.encode(message).finish();
+  };
+};
+
+var serializeCls = exports.serializeCls;
+
+/**
+ * Get the fully qualified (dotted) name of a ProtoBuf.Reflect value.
+ * @param {ProtoBuf.ReflectionObject} value The value to get the name of
+ * @return {string} The fully qualified name of the value
+ */
+exports.fullyQualifiedName = function fullyQualifiedName(value) {
+  if (value === null || value === undefined) {
+    return '';
+  }
+  var name = value.name;
+  var parent_fqn = fullyQualifiedName(value.parent);
+  if (parent_fqn !== '') {
+    name = parent_fqn + '.' + name;
+  }
+  return name;
+};
+
+var fullyQualifiedName = exports.fullyQualifiedName;
+
+/**
+ * Return a map from method names to method attributes for the service.
+ * @param {ProtoBuf.Service} service The service to get attributes for
+ * @param {Object=} options Options to apply to these attributes
+ * @return {Object} The attributes map
+ */
+exports.getProtobufServiceAttrs = function getProtobufServiceAttrs(service,
+                                                                   options) {
+  var prefix = '/' + fullyQualifiedName(service) + '/';
+  service.resolveAll();
+  return _.zipObject(_.map(service.methods, function(method) {
+    return _.camelCase(method.name);
+  }), _.map(service.methods, function(method) {
+    return {
+      originalName: method.name,
+      path: prefix + method.name,
+      requestStream: !!method.requestStream,
+      responseStream: !!method.responseStream,
+      requestType: method.resolvedRequestType,
+      responseType: method.resolvedResponseType,
+      requestSerialize: serializeCls(method.resolvedRequestType),
+      requestDeserialize: deserializeCls(method.resolvedRequestType, options),
+      responseSerialize: serializeCls(method.resolvedResponseType),
+      responseDeserialize: deserializeCls(method.resolvedResponseType, options)
+    };
+  }));
+};
+
+var getProtobufServiceAttrs = exports.getProtobufServiceAttrs;
+
+exports.loadObject = function loadObject(value, options) {
+  var result = {};
+  if (!value) {
+    return value;
+  }
+  if (value.hasOwnProperty('methods')) {
+    // It's a service object
+    var service_attrs = getProtobufServiceAttrs(value, options);
+    return client.makeClientConstructor(service_attrs);
+  }
+
+  if (value.hasOwnProperty('nested')) {
+    // It's a namespace or root object
+    _.each(value.nested, function(nested, name) {
+      result[name] = loadObject(nested, options);
+    });
+    return result;
+  }
+
+  // Otherwise, it's not something we need to change
+  return value;
+};
+
+/**
+ * The primary purpose of this method is to distinguish between reflection
+ * objects from different versions of ProtoBuf.js. This is just a heuristic,
+ * checking for properties that are (currently) specific to this version of
+ * ProtoBuf.js
+ * @param {Object} obj The object to check
+ * @return {boolean} Whether the object appears to be a Protobuf.js 6
+ *   ReflectionObject
+ */
+exports.isProbablyProtobufJs6 = function isProbablyProtobufJs6(obj) {
+  return (typeof obj.root === 'object') && (typeof obj.resolve === 'function');
+};
diff --git a/src/node/src/server.js b/src/node/src/server.js
index bdb4a5620399f8c3196da425d0dde694c5b6605c..3450abed08f57fc90c43bb91491e92288ac684e1 100644
--- a/src/node/src/server.js
+++ b/src/node/src/server.js
@@ -781,17 +781,31 @@ Server.prototype.addService = function(service, implementation) {
 
 /**
  * Add a proto service to the server, with a corresponding implementation
+ * @deprecated Use grpc.load and Server#addService instead
  * @param {Protobuf.Reflect.Service} service The proto service descriptor
  * @param {Object<String, function>} implementation Map of method names to
  *     method implementation for the provided service.
  */
 Server.prototype.addProtoService = function(service, implementation) {
   var options;
-  if (service.grpc_options) {
-    options = service.grpc_options;
+  var protobuf_js_5_common = require('./protobuf_js_5_common');
+  var protobuf_js_6_common = require('./protobuf_js_6_common');
+  common.log(grpc.logVerbosity.INFO,
+             'Server#addProtoService is deprecated. Use addService instead');
+  if (protobuf_js_5_common.isProbablyProtobufJs5(service)) {
+    options = _.defaults(service.grpc_options, common.defaultGrpcOptions);
+    this.addService(
+        protobuf_js_5_common.getProtobufServiceAttrs(service, options),
+        implementation);
+  } else if (protobuf_js_6_common.isProbablyProtobufJs6(service)) {
+    options = _.defaults(service.grpc_options, common.defaultGrpcOptions);
+    this.addService(
+        protobuf_js_6_common.getProtobufServiceAttrs(service, options),
+        implementation);
+  } else {
+    // We assume that this is a service attributes object
+    this.addService(service, implementation);
   }
-  this.addService(common.getProtobufServiceAttrs(service, options),
-                  implementation);
 };
 
 /**
diff --git a/src/node/stress/metrics_server.js b/src/node/stress/metrics_server.js
index 3ab4b4c82d3e69bfba15e5b10a1700c779bf8fa5..b3f939e8f3d2c69d28c9755b5d5b72869312576e 100644
--- a/src/node/stress/metrics_server.js
+++ b/src/node/stress/metrics_server.js
@@ -63,7 +63,7 @@ function getAllGauges(call) {
 
 function MetricsServer(port) {
   var server = new grpc.Server();
-  server.addProtoService(metrics.MetricsService.service, {
+  server.addService(metrics.MetricsService.service, {
     getGauge: _.bind(getGauge, this),
     getAllGauges: _.bind(getAllGauges, this)
   });
diff --git a/src/node/test/common_test.js b/src/node/test/common_test.js
index c57b7388f67f5e7fde9e3d4a0055addb8f4b2ad5..e1ce864f97513a5b1bcc2a21ca25fcff197c1a3c 100644
--- a/src/node/test/common_test.js
+++ b/src/node/test/common_test.js
@@ -34,17 +34,26 @@
 'use strict';
 
 var assert = require('assert');
+var _ = require('lodash');
 
-var common = require('../src/common.js');
+var common = require('../src/common');
+var protobuf_js_6_common = require('../src/protobuf_js_6_common');
+
+var serializeCls = protobuf_js_6_common.serializeCls;
+var deserializeCls = protobuf_js_6_common.deserializeCls;
 
 var ProtoBuf = require('protobufjs');
 
-var messages_proto = ProtoBuf.loadProtoFile(
-    __dirname + '/test_messages.proto').build();
+var messages_proto = new ProtoBuf.Root();
+messages_proto = messages_proto.loadSync(
+    __dirname + '/test_messages.proto', {keepCase: true}).resolveAll();
+
+var default_options = common.defaultGrpcOptions;
 
 describe('Proto message long int serialize and deserialize', function() {
-  var longSerialize = common.serializeCls(messages_proto.LongValues);
-  var longDeserialize = common.deserializeCls(messages_proto.LongValues);
+  var longSerialize = serializeCls(messages_proto.LongValues);
+  var longDeserialize = deserializeCls(messages_proto.LongValues,
+                                       default_options);
   var pos_value = '314159265358979';
   var neg_value = '-27182818284590';
   it('should preserve positive int64 values', function() {
@@ -88,8 +97,9 @@ describe('Proto message long int serialize and deserialize', function() {
                        neg_value);
   });
   it('should deserialize as a number with the right option set', function() {
-    var longNumDeserialize = common.deserializeCls(messages_proto.LongValues,
-                                                   false, false);
+    var num_options = _.defaults({longsAsStrings: false}, default_options);
+    var longNumDeserialize = deserializeCls(messages_proto.LongValues,
+                                            num_options);
     var serialized = longSerialize({int_64: pos_value});
     assert.strictEqual(typeof longDeserialize(serialized).int_64, 'string');
     /* With the longsAsStrings option disabled, long values are represented as
@@ -98,11 +108,12 @@ describe('Proto message long int serialize and deserialize', function() {
   });
 });
 describe('Proto message bytes serialize and deserialize', function() {
-  var sequenceSerialize = common.serializeCls(messages_proto.SequenceValues);
-  var sequenceDeserialize = common.deserializeCls(
-      messages_proto.SequenceValues);
-  var sequenceBase64Deserialize = common.deserializeCls(
-      messages_proto.SequenceValues, true);
+  var sequenceSerialize = serializeCls(messages_proto.SequenceValues);
+  var sequenceDeserialize = deserializeCls(
+      messages_proto.SequenceValues, default_options);
+  var b64_options = _.defaults({binaryAsBase64: true}, default_options);
+  var sequenceBase64Deserialize = deserializeCls(
+      messages_proto.SequenceValues, b64_options);
   var buffer_val = new Buffer([0x69, 0xb7]);
   var base64_val = 'abc=';
   it('should preserve a buffer', function() {
@@ -120,19 +131,73 @@ describe('Proto message bytes serialize and deserialize', function() {
     var deserialized = sequenceBase64Deserialize(serialized);
     assert.strictEqual(deserialized.bytes_field, base64_val);
   });
-  /* The next two tests are specific tests to verify that issue
-   * https://github.com/grpc/grpc/issues/5174 has been fixed. They are skipped
-   * because they will not pass until a protobuf.js release has been published
-   * with a fix for https://github.com/dcodeIO/protobuf.js/issues/390 */
-  it.skip('should serialize a repeated field as packed by default', function() {
-    var expected_serialize = new Buffer([0x12, 0x01, 0x01, 0x0a]);
+  it('should serialize a repeated field as packed by default', function() {
+    var expected_serialize = new Buffer([0x12, 0x01, 0x0a]);
     var serialized = sequenceSerialize({repeated_field: [10]});
     assert.strictEqual(expected_serialize.compare(serialized), 0);
   });
-  it.skip('should deserialize packed or unpacked repeated', function() {
-    var serialized = new Buffer([0x12, 0x01, 0x01, 0x0a]);
+  it('should deserialize packed or unpacked repeated', function() {
+    var expectedDeserialize = {
+      bytes_field: new Buffer(''),
+      repeated_field: [10]
+    };
+    var packedSerialized = new Buffer([0x12, 0x01, 0x0a]);
+    var unpackedSerialized = new Buffer([0x10, 0x0a]);
+    var packedDeserialized;
+    var unpackedDeserialized;
     assert.doesNotThrow(function() {
-      sequenceDeserialize(serialized);
+      packedDeserialized = sequenceDeserialize(packedSerialized);
     });
+    assert.doesNotThrow(function() {
+      unpackedDeserialized = sequenceDeserialize(unpackedSerialized);
+    });
+    assert.deepEqual(packedDeserialized, expectedDeserialize);
+    assert.deepEqual(unpackedDeserialized, expectedDeserialize);
+  });
+});
+describe('Proto message oneof serialize and deserialize', function() {
+  var oneofSerialize = serializeCls(messages_proto.OneOfValues);
+  var oneofDeserialize = deserializeCls(
+      messages_proto.OneOfValues, default_options);
+  it('Should have idempotent round trips', function() {
+    var test_message = {oneof_choice: 'int_choice', int_choice: 5};
+    var serialized1 = oneofSerialize(test_message);
+    var deserialized1 = oneofDeserialize(serialized1);
+    assert.equal(deserialized1.int_choice, 5);
+    var serialized2 = oneofSerialize(deserialized1);
+    var deserialized2 = oneofDeserialize(serialized2);
+    assert.deepEqual(deserialized1, deserialized2);
+  });
+  it('Should emit a property indicating which field was chosen', function() {
+    var test_message1 = {oneof_choice: 'int_choice', int_choice: 5};
+    var serialized1 = oneofSerialize(test_message1);
+    var deserialized1 = oneofDeserialize(serialized1);
+    assert.equal(deserialized1.oneof_choice, 'int_choice');
+    var test_message2 = {oneof_choice: 'string_choice', string_choice: 'abc'};
+    var serialized2 = oneofSerialize(test_message2);
+    var deserialized2 = oneofDeserialize(serialized2);
+    assert.equal(deserialized2.oneof_choice, 'string_choice');
+  });
+});
+describe('Proto message enum serialize and deserialize', function() {
+  var enumSerialize = serializeCls(messages_proto.EnumValues);
+  var enumDeserialize = deserializeCls(
+      messages_proto.EnumValues, default_options);
+  var enumIntOptions = _.defaults({enumsAsStrings: false}, default_options);
+  var enumIntDeserialize = deserializeCls(
+      messages_proto.EnumValues, enumIntOptions);
+  it('Should accept both names and numbers', function() {
+    var nameSerialized = enumSerialize({enum_value: 'ONE'});
+    var numberSerialized = enumSerialize({enum_value: 1});
+    assert.strictEqual(messages_proto.TestEnum.ONE, 1);
+    assert.deepEqual(enumDeserialize(nameSerialized),
+                     enumDeserialize(numberSerialized));
+  });
+  it('Should deserialize as a string the enumsAsStrings option', function() {
+    var serialized = enumSerialize({enum_value: 'TWO'});
+    var nameDeserialized = enumDeserialize(serialized);
+    var numberDeserialized = enumIntDeserialize(serialized);
+    assert.deepEqual(nameDeserialized, {enum_value: 'TWO'});
+    assert.deepEqual(numberDeserialized, {enum_value: 2});
   });
 });
diff --git a/src/node/test/credentials_test.js b/src/node/test/credentials_test.js
index 305843f665ed0418e8198cac7b6b9ef9300f307d..b66b4bf5ea47c498dec17e3288158ba3c88da755 100644
--- a/src/node/test/credentials_test.js
+++ b/src/node/test/credentials_test.js
@@ -228,7 +228,7 @@ describe('client credentials', function() {
   before(function() {
     var proto = grpc.load(__dirname + '/test_service.proto');
     server = new grpc.Server();
-    server.addProtoService(proto.TestService.service, {
+    server.addService(proto.TestService.service, {
       unary: function(call, cb) {
         call.sendMetadata(call.metadata);
         cb(null, {});
diff --git a/src/node/test/surface_test.js b/src/node/test/surface_test.js
index 1d739562a698aa927b154bea4d66adeb9d3ba612..783028fa99f6ce4345c02fea160fafe21c297a65 100644
--- a/src/node/test/surface_test.js
+++ b/src/node/test/surface_test.js
@@ -34,19 +34,22 @@
 'use strict';
 
 var assert = require('assert');
+var _ = require('lodash');
 
 var surface_client = require('../src/client.js');
+var common = require('../src/common');
 
 var ProtoBuf = require('protobufjs');
 
 var grpc = require('..');
 
-var math_proto = ProtoBuf.loadProtoFile(__dirname +
-    '/../../proto/math/math.proto');
+var math_proto = new ProtoBuf.Root();
+math_proto = math_proto.loadSync(__dirname +
+    '/../../proto/math/math.proto', {keepCase: true});
 
 var mathService = math_proto.lookup('math.Math');
-
-var _ = require('lodash');
+var mathServiceAttrs = grpc.loadObject(
+    mathService, common.defaultGrpcOptions).service;
 
 /**
  * This is used for testing functions with multiple asynchronous calls that
@@ -87,11 +90,6 @@ describe('File loader', function() {
       grpc.load(__dirname + '/test_service.json', 'json');
     });
   });
-  it('Should fail to load a file with an unknown format', function() {
-    assert.throws(function() {
-      grpc.load(__dirname + '/test_service.proto', 'fake_format');
-    });
-  });
 });
 describe('surface Server', function() {
   var server;
@@ -132,15 +130,40 @@ describe('Server.prototype.addProtoService', function() {
   afterEach(function() {
     server.forceShutdown();
   });
-  it('Should succeed with a single service', function() {
+  it('Should succeed with a single proto service', function() {
     assert.doesNotThrow(function() {
       server.addProtoService(mathService, dummyImpls);
     });
   });
+  it('Should succeed with a single service attributes object', function() {
+    assert.doesNotThrow(function() {
+      server.addProtoService(mathServiceAttrs, dummyImpls);
+    });
+  });
+});
+describe('Server.prototype.addService', function() {
+  var server;
+  var dummyImpls = {
+    'div': function() {},
+    'divMany': function() {},
+    'fib': function() {},
+    'sum': function() {}
+  };
+  beforeEach(function() {
+    server = new grpc.Server();
+  });
+  afterEach(function() {
+    server.forceShutdown();
+  });
+  it('Should succeed with a single service', function() {
+    assert.doesNotThrow(function() {
+      server.addService(mathServiceAttrs, dummyImpls);
+    });
+  });
   it('Should fail with conflicting method names', function() {
-    server.addProtoService(mathService, dummyImpls);
+    server.addService(mathServiceAttrs, dummyImpls);
     assert.throws(function() {
-      server.addProtoService(mathService, dummyImpls);
+      server.addService(mathServiceAttrs, dummyImpls);
     });
   });
   it('Should allow method names as originally written', function() {
@@ -172,15 +195,15 @@ describe('Server.prototype.addProtoService', function() {
   it('Should fail if the server has been started', function() {
     server.start();
     assert.throws(function() {
-      server.addProtoService(mathService, dummyImpls);
+      server.addService(mathServiceAttrs, dummyImpls);
     });
   });
   describe('Default handlers', function() {
     var client;
     beforeEach(function() {
-      server.addProtoService(mathService, {});
+      server.addService(mathServiceAttrs, {});
       var port = server.bind('localhost:0', server_insecure_creds);
-      var Client = surface_client.makeProtobufClientConstructor(mathService);
+      var Client = grpc.loadObject(mathService);
       client = new Client('localhost:' + port,
                           grpc.credentials.createInsecure());
       server.start();
@@ -252,7 +275,7 @@ describe('waitForClientReady', function() {
     server = new grpc.Server();
     port = server.bind('localhost:0', grpc.ServerCredentials.createInsecure());
     server.start();
-    Client = surface_client.makeProtobufClientConstructor(mathService);
+    Client = grpc.loadObject(mathService);
   });
   beforeEach(function() {
     client = new Client('localhost:' + port, grpc.credentials.createInsecure());
@@ -309,16 +332,18 @@ describe('Echo service', function() {
   var server;
   var client;
   before(function() {
-    var test_proto = ProtoBuf.loadProtoFile(__dirname + '/echo_service.proto');
+    var test_proto = new ProtoBuf.Root();
+    test_proto = test_proto.loadSync(__dirname + '/echo_service.proto',
+                                         {keepCase: true});
     var echo_service = test_proto.lookup('EchoService');
+    var Client = grpc.loadObject(echo_service);
     server = new grpc.Server();
-    server.addProtoService(echo_service, {
+    server.addService(Client.service, {
       echo: function(call, callback) {
         callback(null, call.request);
       }
     });
     var port = server.bind('localhost:0', server_insecure_creds);
-    var Client = surface_client.makeProtobufClientConstructor(echo_service);
     client = new Client('localhost:' + port, grpc.credentials.createInsecure());
     server.start();
   });
@@ -432,10 +457,13 @@ describe('Echo metadata', function() {
   var server;
   var metadata;
   before(function() {
-    var test_proto = ProtoBuf.loadProtoFile(__dirname + '/test_service.proto');
+    var test_proto = new ProtoBuf.Root();
+    test_proto = test_proto.loadSync(__dirname + '/test_service.proto',
+                                         {keepCase: true});
     var test_service = test_proto.lookup('TestService');
+    var Client = grpc.loadObject(test_service);
     server = new grpc.Server();
-    server.addProtoService(test_service, {
+    server.addService(Client.service, {
       unary: function(call, cb) {
         call.sendMetadata(call.metadata);
         cb(null, {});
@@ -460,7 +488,6 @@ describe('Echo metadata', function() {
       }
     });
     var port = server.bind('localhost:0', server_insecure_creds);
-    var Client = surface_client.makeProtobufClientConstructor(test_service);
     client = new Client('localhost:' + port, grpc.credentials.createInsecure());
     server.start();
     metadata = new grpc.Metadata();
@@ -533,7 +560,9 @@ describe('Client malformed response handling', function() {
   var client;
   var badArg = new Buffer([0xFF]);
   before(function() {
-    var test_proto = ProtoBuf.loadProtoFile(__dirname + '/test_service.proto');
+    var test_proto = new ProtoBuf.Root();
+    test_proto = test_proto.loadSync(__dirname + '/test_service.proto',
+                                         {keepCase: true});
     var test_service = test_proto.lookup('TestService');
     var malformed_test_service = {
       unary: {
@@ -591,7 +620,7 @@ describe('Client malformed response handling', function() {
       }
     });
     var port = server.bind('localhost:0', server_insecure_creds);
-    var Client = surface_client.makeProtobufClientConstructor(test_service);
+    var Client = grpc.loadObject(test_service);
     client = new Client('localhost:' + port, grpc.credentials.createInsecure());
     server.start();
   });
@@ -640,7 +669,9 @@ describe('Server serialization failure handling', function() {
   var client;
   var server;
   before(function() {
-    var test_proto = ProtoBuf.loadProtoFile(__dirname + '/test_service.proto');
+    var test_proto = new ProtoBuf.Root();
+    test_proto = test_proto.loadSync(__dirname + '/test_service.proto',
+                                         {keepCase: true});
     var test_service = test_proto.lookup('TestService');
     var malformed_test_service = {
       unary: {
@@ -698,7 +729,7 @@ describe('Server serialization failure handling', function() {
       }
     });
     var port = server.bind('localhost:0', server_insecure_creds);
-    var Client = surface_client.makeProtobufClientConstructor(test_service);
+    var Client = grpc.loadObject(test_service);
     client = new Client('localhost:' + port, grpc.credentials.createInsecure());
     server.start();
   });
@@ -747,12 +778,15 @@ describe('Other conditions', function() {
   var server;
   var port;
   before(function() {
-    var test_proto = ProtoBuf.loadProtoFile(__dirname + '/test_service.proto');
+    var test_proto = new ProtoBuf.Root();
+    test_proto = test_proto.loadSync(__dirname + '/test_service.proto',
+                                         {keepCase: true});
     test_service = test_proto.lookup('TestService');
+    Client = grpc.loadObject(test_service);
     server = new grpc.Server();
     var trailer_metadata = new grpc.Metadata();
     trailer_metadata.add('trailer-present', 'yes');
-    server.addProtoService(test_service, {
+    server.addService(Client.service, {
       unary: function(call, cb) {
         var req = call.request;
         if (req.error) {
@@ -812,7 +846,6 @@ describe('Other conditions', function() {
       }
     });
     port = server.bind('localhost:0', server_insecure_creds);
-    Client = surface_client.makeProtobufClientConstructor(test_service);
     client = new Client('localhost:' + port, grpc.credentials.createInsecure());
     server.start();
   });
@@ -1093,17 +1126,19 @@ describe('Call propagation', function() {
   var client;
   var server;
   before(function() {
-    var test_proto = ProtoBuf.loadProtoFile(__dirname + '/test_service.proto');
+    var test_proto = new ProtoBuf.Root();
+    test_proto = test_proto.loadSync(__dirname + '/test_service.proto',
+                                         {keepCase: true});
     test_service = test_proto.lookup('TestService');
     server = new grpc.Server();
-    server.addProtoService(test_service, {
+    Client = grpc.loadObject(test_service);
+    server.addService(Client.service, {
       unary: function(call) {},
       clientStream: function(stream) {},
       serverStream: function(stream) {},
       bidiStream: function(stream) {}
     });
     var port = server.bind('localhost:0', server_insecure_creds);
-    Client = surface_client.makeProtobufClientConstructor(test_service);
     client = new Client('localhost:' + port, grpc.credentials.createInsecure());
     server.start();
   });
@@ -1138,7 +1173,7 @@ describe('Call propagation', function() {
         });
         call.cancel();
       };
-      proxy.addProtoService(test_service, proxy_impl);
+      proxy.addService(Client.service, proxy_impl);
       var proxy_port = proxy.bind('localhost:0', server_insecure_creds);
       proxy.start();
       var proxy_client = new Client('localhost:' + proxy_port,
@@ -1160,7 +1195,7 @@ describe('Call propagation', function() {
         });
         call.cancel();
       };
-      proxy.addProtoService(test_service, proxy_impl);
+      proxy.addService(Client.service, proxy_impl);
       var proxy_port = proxy.bind('localhost:0', server_insecure_creds);
       proxy.start();
       var proxy_client = new Client('localhost:' + proxy_port,
@@ -1180,7 +1215,7 @@ describe('Call propagation', function() {
         });
         call.cancel();
       };
-      proxy.addProtoService(test_service, proxy_impl);
+      proxy.addService(Client.service, proxy_impl);
       var proxy_port = proxy.bind('localhost:0', server_insecure_creds);
       proxy.start();
       var proxy_client = new Client('localhost:' + proxy_port,
@@ -1204,7 +1239,7 @@ describe('Call propagation', function() {
         });
         call.cancel();
       };
-      proxy.addProtoService(test_service, proxy_impl);
+      proxy.addService(Client.service, proxy_impl);
       var proxy_port = proxy.bind('localhost:0', server_insecure_creds);
       proxy.start();
       var proxy_client = new Client('localhost:' + proxy_port,
@@ -1235,7 +1270,7 @@ describe('Call propagation', function() {
           }
         });
       };
-      proxy.addProtoService(test_service, proxy_impl);
+      proxy.addService(Client.service, proxy_impl);
       var proxy_port = proxy.bind('localhost:0', server_insecure_creds);
       proxy.start();
       var proxy_client = new Client('localhost:' + proxy_port,
@@ -1259,7 +1294,7 @@ describe('Call propagation', function() {
           done();
         });
       };
-      proxy.addProtoService(test_service, proxy_impl);
+      proxy.addService(Client.service, proxy_impl);
       var proxy_port = proxy.bind('localhost:0', server_insecure_creds);
       proxy.start();
       var proxy_client = new Client('localhost:' + proxy_port,
@@ -1279,14 +1314,14 @@ describe('Cancelling surface client', function() {
   var server;
   before(function() {
     server = new grpc.Server();
-    server.addProtoService(mathService, {
+    server.addService(mathServiceAttrs, {
       'div': function(stream) {},
       'divMany': function(stream) {},
       'fib': function(stream) {},
       'sum': function(stream) {}
     });
     var port = server.bind('localhost:0', server_insecure_creds);
-    var Client = surface_client.makeProtobufClientConstructor(mathService);
+    var Client = surface_client.makeClientConstructor(mathServiceAttrs);
     client = new Client('localhost:' + port, grpc.credentials.createInsecure());
     server.start();
   });
diff --git a/src/node/test/test_messages.proto b/src/node/test/test_messages.proto
index a1a6a32833db492e5eed6c39812c1865d00c3957..ae70f6e152a5acc2141dd06db372776ccb2261d4 100644
--- a/src/node/test/test_messages.proto
+++ b/src/node/test/test_messages.proto
@@ -41,3 +41,20 @@ message SequenceValues {
   bytes bytes_field = 1;
   repeated int32 repeated_field = 2;
 }
+
+message OneOfValues {
+  oneof oneof_choice {
+    int32 int_choice = 1;
+    string string_choice = 2;
+  }
+}
+
+enum TestEnum {
+  ZERO = 0;
+  ONE = 1;
+  TWO = 2;
+}
+
+message EnumValues {
+  TestEnum enum_value = 1;
+}
\ No newline at end of file
diff --git a/src/proto/grpc/testing/BUILD b/src/proto/grpc/testing/BUILD
index 23a16a7cfc3ac35d2ef1f3f24bae2a8c9b5bd52a..6f3422e4d167a89c50a1c5ae6e1779122fee1ba5 100644
--- a/src/proto/grpc/testing/BUILD
+++ b/src/proto/grpc/testing/BUILD
@@ -83,7 +83,11 @@ grpc_proto_library(
 grpc_proto_library(
     name = "services_proto",
     srcs = ["services.proto"],
-    deps = ["control_proto", "messages_proto"],
+    deps = [
+        "control_proto",
+        "messages_proto",
+        "stats_proto",
+    ],
 )
 
 grpc_proto_library(
diff --git a/src/proto/grpc/testing/echo_messages.proto b/src/proto/grpc/testing/echo_messages.proto
index efb6f4d49350cf279614f6cb5b3a768df1a0f280..b82e80d8e34baebeae9a8d704272ca8f39032f8e 100644
--- a/src/proto/grpc/testing/echo_messages.proto
+++ b/src/proto/grpc/testing/echo_messages.proto
@@ -38,6 +38,13 @@ message DebugInfo {
   string detail = 2;
 }
 
+// Error status client expects to see.
+message ErrorStatus {
+  int32 code = 1;
+  string error_message = 2;
+  string binary_error_details = 3;
+}
+
 message RequestParams {
   bool echo_deadline = 1;
   int32 client_cancel_after_us = 2;
@@ -51,6 +58,8 @@ message RequestParams {
   string expected_transport_security_type = 10;
   DebugInfo debug_info = 11;
   bool server_die = 12; // Server should not see a request with this set.
+  string binary_error_details = 13;
+  ErrorStatus expected_error = 14;
 }
 
 message EchoRequest {
diff --git a/src/proto/grpc/testing/services.proto b/src/proto/grpc/testing/services.proto
index f71dae34eedfbab7fc153bd0897948cc6e1fa1e5..969782d6561d773271c4a97d0fa40662d868ce84 100644
--- a/src/proto/grpc/testing/services.proto
+++ b/src/proto/grpc/testing/services.proto
@@ -33,6 +33,7 @@ syntax = "proto3";
 
 import "src/proto/grpc/testing/messages.proto";
 import "src/proto/grpc/testing/control.proto";
+import "src/proto/grpc/testing/stats.proto";
 
 package grpc.testing;
 
@@ -69,3 +70,8 @@ service WorkerService {
   // Quit this worker
   rpc QuitWorker(Void) returns (Void);
 }
+
+service ReportQpsScenarioService {
+  // Report results of a QPS test benchmark scenario.
+  rpc ReportScenario(ScenarioResult) returns (Void);
+}
diff --git a/src/python/grpcio/grpc/_server.py b/src/python/grpcio/grpc/_server.py
index 47838c2c986c2cee2cb8fae735cf13292ee10b45..f29c44a4cfd3e35b9dfbc01b08f2cfe882423172 100644
--- a/src/python/grpcio/grpc/_server.py
+++ b/src/python/grpcio/grpc/_server.py
@@ -705,6 +705,10 @@ def _serve(state):
                     state.rpc_states.remove(rpc_state)
                     if _stop_serving(state):
                         return
+        # We want to force the deletion of the previous event
+        # ~before~ we poll again; if the event has a reference
+        # to a shutdown Call object, this can induce spinlock.
+        event = None
 
 
 def _stop(state, grace):
diff --git a/src/python/grpcio/grpc_core_dependencies.py b/src/python/grpcio/grpc_core_dependencies.py
index 20c07ed168e3ca1dab8870d464579e983ca46378..7f810bd0b4759f85edaaec26bb36d85dbd54b2c9 100644
--- a/src/python/grpcio/grpc_core_dependencies.py
+++ b/src/python/grpcio/grpc_core_dependencies.py
@@ -113,6 +113,7 @@ CORE_SOURCE_FILES = [
   'src/core/lib/iomgr/iomgr_uv.c',
   'src/core/lib/iomgr/iomgr_windows.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',
diff --git a/src/python/grpcio_reflection/MANIFEST.in b/src/python/grpcio_reflection/MANIFEST.in
new file mode 100644
index 0000000000000000000000000000000000000000..0f2130c0b58f1b8b932f52e2983dbdf0f6d279ff
--- /dev/null
+++ b/src/python/grpcio_reflection/MANIFEST.in
@@ -0,0 +1,4 @@
+include grpc_version.py
+include reflection_commands.py
+graft grpc_reflection
+global-exclude *.pyc
diff --git a/src/ruby/end2end/channel_closing_driver.rb b/src/ruby/end2end/channel_closing_driver.rb
index 43e2fe8cbbdcefbf360e174565afca5cecfa59df..d3e5373b0bb0e4724269d32353e98258d961db08 100755
--- a/src/ruby/end2end/channel_closing_driver.rb
+++ b/src/ruby/end2end/channel_closing_driver.rb
@@ -36,7 +36,7 @@ require_relative './end2end_common'
 
 def main
   STDERR.puts 'start server'
-  server_runner = ServerRunner.new
+  server_runner = ServerRunner.new(EchoServerImpl)
   server_port = server_runner.run
 
   sleep 1
diff --git a/src/ruby/end2end/channel_state_driver.rb b/src/ruby/end2end/channel_state_driver.rb
index c3184bf939259262f1af3946afb4a0a4850b5282..80fb62899e5aa59f99154ced8906cc5353ffc8ee 100755
--- a/src/ruby/end2end/channel_state_driver.rb
+++ b/src/ruby/end2end/channel_state_driver.rb
@@ -35,7 +35,7 @@ require_relative './end2end_common'
 
 def main
   STDERR.puts 'start server'
-  server_runner = ServerRunner.new
+  server_runner = ServerRunner.new(EchoServerImpl)
   server_port = server_runner.run
 
   sleep 1
diff --git a/src/ruby/end2end/end2end_common.rb b/src/ruby/end2end/end2end_common.rb
index 9534bb207875e4180ff17ec18bf2b26ece8b60a4..1c87ceddf1df77e12c974c469b38952b34cddff1 100755
--- a/src/ruby/end2end/end2end_common.rb
+++ b/src/ruby/end2end/end2end_common.rb
@@ -55,13 +55,14 @@ end
 
 # ServerRunner starts an "echo server" that test clients can make calls to
 class ServerRunner
-  def initialize
+  def initialize(service_impl)
+    @service_impl = service_impl
   end
 
   def run
     @srv = GRPC::RpcServer.new
     port = @srv.add_http2_port('0.0.0.0:0', :this_port_is_insecure)
-    @srv.handle(EchoServerImpl)
+    @srv.handle(@service_impl)
 
     @thd = Thread.new do
       @srv.run
diff --git a/src/ruby/end2end/killed_client_thread_client.rb b/src/ruby/end2end/killed_client_thread_client.rb
new file mode 100755
index 0000000000000000000000000000000000000000..d5a7db7d5866998ada4b4906e3659afb42b70389
--- /dev/null
+++ b/src/ruby/end2end/killed_client_thread_client.rb
@@ -0,0 +1,58 @@
+#!/usr/bin/env ruby
+
+# Copyright 2015, Google Inc.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+#     * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+#     * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+# Attempt to reproduce
+# https://github.com/GoogleCloudPlatform/google-cloud-ruby/issues/1327
+
+require_relative './end2end_common'
+
+def main
+  server_port = ''
+  OptionParser.new do |opts|
+    opts.on('--client_control_port=P', String) do
+      STDERR.puts 'client control port not used'
+    end
+    opts.on('--server_port=P', String) do |p|
+      server_port = p
+    end
+  end.parse!
+
+  thd = Thread.new do
+    stub = Echo::EchoServer::Stub.new("localhost:#{server_port}",
+                                      :this_channel_is_insecure)
+    stub.echo(Echo::EchoRequest.new(request: 'hello'))
+    fail 'the clients rpc in this test shouldnt complete. ' \
+      'expecting SIGINT to happen in the middle of the call'
+  end
+  thd.join
+end
+
+main
diff --git a/src/ruby/end2end/killed_client_thread_driver.rb b/src/ruby/end2end/killed_client_thread_driver.rb
new file mode 100755
index 0000000000000000000000000000000000000000..f76d3e1746df321bcdae1fb57645ebbdba5b8766
--- /dev/null
+++ b/src/ruby/end2end/killed_client_thread_driver.rb
@@ -0,0 +1,114 @@
+#!/usr/bin/env ruby
+
+# Copyright 2016, Google Inc.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+#     * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+#     * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+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.
+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
+  end
+
+  def echo(echo_req, _)
+    @call_started_mu.synchronize do
+      @call_started.set_true
+      @call_started_cv.signal
+    end
+    sleep 1000
+    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
+
+  service_impl = SleepingEchoServerImpl.new(call_started,
+                                            call_started_mu,
+                                            call_started_cv)
+  server_runner = ServerRunner.new(service_impl)
+  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
+  end
+
+  # SIGINT the child process now that it's
+  # in the middle of an RPC (happening on a non-main thread)
+  Process.kill('SIGINT', client_pid)
+  STDERR.puts 'sent shutdown'
+
+  begin
+    Timeout.timeout(10) do
+      Process.wait(client_pid)
+    end
+  rescue Timeout::Error
+    STDERR.puts "timeout wait for client pid #{client_pid}"
+    Process.kill('SIGKILL', client_pid)
+    Process.wait(client_pid)
+    STDERR.puts 'killed client child'
+    raise 'Timed out waiting for client process. ' \
+      'It likely hangs when killed while in the middle of an rpc'
+  end
+
+  client_exit_code = $CHILD_STATUS
+  if client_exit_code.termsig != 2 # SIGINT
+    fail 'expected client exit from SIGINT ' \
+      "but got child status: #{client_exit_code}"
+  end
+
+  server_runner.stop
+end
+
+main
diff --git a/src/ruby/end2end/sig_handling_driver.rb b/src/ruby/end2end/sig_handling_driver.rb
index c5d46e074cb719cdd9793bf25bf9b315343d5ab2..6691464dc69a50bff29502d0ee60a5d20aa76681 100755
--- a/src/ruby/end2end/sig_handling_driver.rb
+++ b/src/ruby/end2end/sig_handling_driver.rb
@@ -36,7 +36,7 @@ require_relative './end2end_common'
 
 def main
   STDERR.puts 'start server'
-  server_runner = ServerRunner.new
+  server_runner = ServerRunner.new(EchoServerImpl)
   server_port = server_runner.run
 
   sleep 1
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 84d039bf19da574cd8a65bc7050cd066d9b50a8c..670cda0919f869ac468f78f93e5317b948fcc64a 100755
--- a/src/ruby/end2end/sig_int_during_channel_watch_driver.rb
+++ b/src/ruby/end2end/sig_int_during_channel_watch_driver.rb
@@ -36,7 +36,7 @@ require_relative './end2end_common'
 
 def main
   STDERR.puts 'start server'
-  server_runner = ServerRunner.new
+  server_runner = ServerRunner.new(EchoServerImpl)
   server_port = server_runner.run
 
   sleep 1
diff --git a/src/ruby/ext/grpc/rb_call.c b/src/ruby/ext/grpc/rb_call.c
index 82d340b25442554d8de3f747efb8bc5c7c866297..344cb941ffb09eb8c5326e1d496718bfd0afbed3 100644
--- a/src/ruby/ext/grpc/rb_call.c
+++ b/src/ruby/ext/grpc/rb_call.c
@@ -784,7 +784,7 @@ static VALUE grpc_run_batch_stack_build_result(run_batch_stack *st) {
    Only one operation of each type can be active at once in any given
    batch */
 static VALUE grpc_rb_call_run_batch(VALUE self, VALUE ops_hash) {
-  run_batch_stack st;
+  run_batch_stack *st = NULL;
   grpc_rb_call *call = NULL;
   grpc_event ev;
   grpc_call_error err;
@@ -792,6 +792,7 @@ static VALUE grpc_rb_call_run_batch(VALUE self, VALUE ops_hash) {
   VALUE rb_write_flag = rb_ivar_get(self, id_write_flag);
   unsigned write_flag = 0;
   void *tag = (void*)&st;
+
   if (RTYPEDDATA_DATA(self) == NULL) {
     rb_raise(grpc_rb_eCallError, "Cannot run batch on closed call");
     return Qnil;
@@ -806,14 +807,16 @@ static VALUE grpc_rb_call_run_batch(VALUE self, VALUE ops_hash) {
   if (rb_write_flag != Qnil) {
     write_flag = NUM2UINT(rb_write_flag);
   }
-  grpc_run_batch_stack_init(&st, write_flag);
-  grpc_run_batch_stack_fill_ops(&st, ops_hash);
+  st = gpr_malloc(sizeof(run_batch_stack));
+  grpc_run_batch_stack_init(st, write_flag);
+  grpc_run_batch_stack_fill_ops(st, ops_hash);
 
   /* call grpc_call_start_batch, then wait for it to complete using
    * pluck_event */
-  err = grpc_call_start_batch(call->wrapped, st.ops, st.op_num, tag, NULL);
+  err = grpc_call_start_batch(call->wrapped, st->ops, st->op_num, tag, NULL);
   if (err != GRPC_CALL_OK) {
-    grpc_run_batch_stack_cleanup(&st);
+    grpc_run_batch_stack_cleanup(st);
+    gpr_free(st);
     rb_raise(grpc_rb_eCallError,
              "grpc_call_start_batch failed with %s (code=%d)",
              grpc_call_error_detail_of(err), err);
@@ -826,8 +829,9 @@ static VALUE grpc_rb_call_run_batch(VALUE self, VALUE ops_hash) {
   }
   /* Build and return the BatchResult struct result,
      if there is an error, it's reflected in the status */
-  result = grpc_run_batch_stack_build_result(&st);
-  grpc_run_batch_stack_cleanup(&st);
+  result = grpc_run_batch_stack_build_result(st);
+  grpc_run_batch_stack_cleanup(st);
+  gpr_free(st);
   return result;
 }
 
diff --git a/src/ruby/spec/generic/rpc_server_pool_spec.rb b/src/ruby/spec/generic/rpc_server_pool_spec.rb
index 69e8222cb97f4bf0031e3efbc7b06597fbe8c179..0803ca74ed67ae041fe97c9e44821244a00cce2a 100644
--- a/src/ruby/spec/generic/rpc_server_pool_spec.rb
+++ b/src/ruby/spec/generic/rpc_server_pool_spec.rb
@@ -52,28 +52,31 @@ describe GRPC::Pool do
       expect(p.ready_for_work?).to be(false)
     end
 
-    it 'it stops being ready after all workers jobs waiting or running' do
+    it 'it stops being ready after all workers are busy' do
       p = Pool.new(5)
       p.start
-      job = proc { sleep(3) } # sleep so workers busy when done scheduling
-      5.times do
-        expect(p.ready_for_work?).to be(true)
-        p.schedule(&job)
+
+      wait_mu = Mutex.new
+      wait_cv = ConditionVariable.new
+      wait = true
+
+      job = proc do
+        wait_mu.synchronize do
+          wait_cv.wait(wait_mu) while wait
+        end
       end
-      expect(p.ready_for_work?).to be(false)
-    end
 
-    it 'it becomes ready again after jobs complete' do
-      p = Pool.new(5)
-      p.start
-      job = proc {}
       5.times do
         expect(p.ready_for_work?).to be(true)
         p.schedule(&job)
       end
+
       expect(p.ready_for_work?).to be(false)
-      sleep 5 # give the pool time do get at least one task done
-      expect(p.ready_for_work?).to be(true)
+
+      wait_mu.synchronize do
+        wait = false
+        wait_cv.broadcast
+      end
     end
   end
 
@@ -105,13 +108,20 @@ describe GRPC::Pool do
     it 'stops jobs when there are long running jobs' do
       p = Pool.new(1)
       p.start
-      o, q = Object.new, Queue.new
+
+      wait_forever_mu = Mutex.new
+      wait_forever_cv = ConditionVariable.new
+      wait_forever = true
+
+      job_running = Queue.new
       job = proc do
-        sleep(5)  # long running
-        q.push(o)
+        job_running.push(Object.new)
+        wait_forever_mu.synchronize do
+          wait_forever_cv.wait while wait_forever
+        end
       end
       p.schedule(&job)
-      sleep(1)  # should ensure the long job gets scheduled
+      job_running.pop
       expect { p.stop }.not_to raise_error
     end
   end
diff --git a/templates/CMakeLists.txt.template b/templates/CMakeLists.txt.template
index e2fc216bca739ab0374b675f2fa7276a20962b39..cf69f0cc06f0c729cf9632dbba62d4af3542ef53 100644
--- a/templates/CMakeLists.txt.template
+++ b/templates/CMakeLists.txt.template
@@ -7,9 +7,6 @@
   # This file can be regenerated from the template by running
   # tools/buildgen/generate_projects.sh
   #
-  # Additionally, this is currently very experimental, and unsupported.
-  # Further work will happen on that file.
-  #
   # Copyright 2015, Google Inc.
   # All rights reserved.
   #
@@ -353,7 +350,7 @@
     foreach(FIL <%text>${ARGN}</%text>)
       get_filename_component(ABS_FIL <%text>${FIL}</%text> ABSOLUTE)
       get_filename_component(FIL_WE <%text>${FIL}</%text> NAME_WE)
-      file(RELATIVE_PATH REL_FIL <%text>${CMAKE_SOURCE_DIR}</%text> <%text>${ABS_FIL}</%text>)
+      file(RELATIVE_PATH REL_FIL <%text>${CMAKE_CURRENT_SOURCE_DIR}</%text> <%text>${ABS_FIL}</%text>)
       get_filename_component(REL_DIR <%text>${REL_FIL}</%text> DIRECTORY)
       set(RELFIL_WE "<%text>${REL_DIR}/${FIL_WE}</%text>")
 
@@ -369,7 +366,7 @@
              <%text>${_protobuf_include_path}</%text>
              <%text>${REL_FIL}</%text>
         DEPENDS <%text>${ABS_FIL}</%text> <%text>${_gRPC_PROTOBUF_PROTOC}</%text> grpc_cpp_plugin
-        WORKING_DIRECTORY <%text>${CMAKE_SOURCE_DIR}</%text>
+        WORKING_DIRECTORY <%text>${CMAKE_CURRENT_SOURCE_DIR}</%text>
         COMMENT "Running gRPC C++ protocol buffer compiler on <%text>${FIL}</%text>"
         VERBATIM)
 
@@ -511,8 +508,8 @@
     PRIVATE <%text>${CMAKE_CURRENT_BINARY_DIR}</%text>/third_party/cares/cares
     PRIVATE <%text>${CMAKE_CURRENT_BINARY_DIR}</%text>/third_party/gflags/include
   % if lib.build in ['test', 'private'] and lib.language == 'c++':
-    PRIVATE third_party/googletest/include
-    PRIVATE third_party/googletest
+    PRIVATE third_party/googletest/googletest/include
+    PRIVATE third_party/googletest/googletest
   % endif
   % if lib.language == 'c++':
     PRIVATE <%text>${_gRPC_PROTO_GENS_DIR}</%text>
@@ -555,7 +552,7 @@
   % endif
   % endfor
   % if tgt.build == 'test' and tgt.language == 'c++':
-    third_party/googletest/src/gtest-all.cc
+    third_party/googletest/googletest/src/gtest-all.cc
   % endif
   )
 
@@ -581,8 +578,8 @@
     PRIVATE <%text>${CMAKE_CURRENT_BINARY_DIR}</%text>/third_party/cares/cares
     PRIVATE <%text>${CMAKE_CURRENT_BINARY_DIR}</%text>/third_party/gflags/include
   % if tgt.build in ['test', 'private'] and tgt.language == 'c++':
-    PRIVATE third_party/googletest/include
-    PRIVATE third_party/googletest
+    PRIVATE third_party/googletest/googletest/include
+    PRIVATE third_party/googletest/googletest
   % endif
   % if tgt.language == 'c++':
     PRIVATE <%text>${_gRPC_PROTO_GENS_DIR}</%text>
diff --git a/templates/Makefile.template b/templates/Makefile.template
index 60362b6e43a8afdf13aa0826839d84acc6be6d53..8f61a8b99078be244ce0bb68fa0da7fe5c74f1ed 100644
--- a/templates/Makefile.template
+++ b/templates/Makefile.template
@@ -311,7 +311,7 @@
   USE_BUILT_PROTOC = false
   endif
 
-  GTEST_LIB = -Ithird_party/googletest/include -Ithird_party/googletest third_party/googletest/src/gtest-all.cc
+  GTEST_LIB = -Ithird_party/googletest/googletest/include -Ithird_party/googletest/googletest third_party/googletest/googletest/src/gtest-all.cc
   GTEST_LIB += -lgflags
   ifeq ($(V),1)
   E = @:
@@ -716,7 +716,7 @@
   PC_REQUIRES_GRPCXX =
   PC_LIBS_GRPCXX =
 
-  CPPFLAGS := -Ithird_party/googletest/include $(CPPFLAGS)
+  CPPFLAGS := -Ithird_party/googletest/googletest/include $(CPPFLAGS)
 
   PROTOC_PLUGINS_ALL =\
   % for tgt in targets:
diff --git a/templates/binding.gyp.template b/templates/binding.gyp.template
index aeeb56b9a6a998f1b73eedafb94c2056a284d3d3..55a91c5b93d57e9e1fcea9b609db27da46840fb8 100644
--- a/templates/binding.gyp.template
+++ b/templates/binding.gyp.template
@@ -217,9 +217,10 @@
             # the OpenSSL headers, from the downloaded Node development package,
             # which is typically located in `.node-gyp` in your home directory.
             'target_name': 'WINDOWS_BUILD_WARNING',
-            'actions': [
+            'rules': [
               {
-                'action_name': 'WINDOWS_BUILD_WARNING',
+                'rule_name': 'WINDOWS_BUILD_WARNING',
+                'extension': 'S',
                 'inputs': [
                   'package.json'
                 ],
diff --git a/templates/grpc.gemspec.template b/templates/grpc.gemspec.template
index 462ea52614069e651fab784b922a44c764d7019d..80ce643d8026201a51db87690a7d35058dda3ee0 100644
--- a/templates/grpc.gemspec.template
+++ b/templates/grpc.gemspec.template
@@ -26,7 +26,7 @@
     s.files += Dir.glob('include/grpc/**/*')
     s.test_files = Dir.glob('src/ruby/spec/**/*')
     s.bindir = 'src/ruby/bin'
-    s.require_paths = %w( src/ruby/bin src/ruby/lib src/ruby/pb )
+    s.require_paths = %w( src/ruby/lib src/ruby/bin src/ruby/pb )
     s.platform      = Gem::Platform::RUBY
 
     s.add_dependency 'google-protobuf', '~> 3.1'
diff --git a/templates/package.json.template b/templates/package.json.template
index d093883cf5a7df2000cfd300c0eaf2635878dc85..b69fd28d2abf3d807c5f26747dbd170f4395de65 100644
--- a/templates/package.json.template
+++ b/templates/package.json.template
@@ -36,7 +36,7 @@
       "lodash": "^4.15.0",
       "nan": "^2.0.0",
       "node-pre-gyp": "^0.6.0",
-      "protobufjs": "^5.0.0",
+      "protobufjs": "^6.7.0",
       "cares": "^1.1.5"
     },
     "devDependencies": {
diff --git a/templates/src/csharp/Grpc.Auth/project.json.template b/templates/src/csharp/Grpc.Auth/project.json.template
deleted file mode 100644
index aa233db586c149b846b1724521106b76bf3ef52e..0000000000000000000000000000000000000000
--- a/templates/src/csharp/Grpc.Auth/project.json.template
+++ /dev/null
@@ -1,37 +0,0 @@
-%YAML 1.2
---- |
-  {
-    "version": "${settings.csharp_version}",
-    "title": "gRPC C# Auth",
-    "authors": [ "Google Inc." ],
-    "copyright": "Copyright 2015, Google Inc.",
-    "packOptions": {
-      "summary": "Auth library for C# implementation of gRPC - an RPC library and framework",
-      "description": "Auth library for C# implementation of gRPC - an RPC library and framework. See project site for more info.",
-      "owners": [ "grpc-packages" ],
-      "licenseUrl": "https://github.com/grpc/grpc/blob/master/LICENSE",
-      "projectUrl": "https://github.com/grpc/grpc",
-      "requireLicenseAcceptance": false,
-      "tags": [ "gRPC RPC Protocol HTTP/2 Auth OAuth2" ],
-    },
-    "buildOptions": {
-      "define": [ "SIGNED" ],
-      "keyFile": "../keys/Grpc.snk",
-      "xmlDoc": true,
-      "compile": {
-        "includeFiles": [ "../Grpc.Core/Version.cs" ]
-      }
-    },
-    "dependencies": {
-      "Grpc.Core": "${settings.csharp_version}",
-      "Google.Apis.Auth": "1.21.0"
-    },
-    "frameworks": {
-      "net45": { },
-      "netstandard1.5": {
-        "dependencies": {
-          "NETStandard.Library": "1.6.0"
-        }
-      }
-    }
-  }
diff --git a/templates/src/csharp/Grpc.Core.Testing/project.json.template b/templates/src/csharp/Grpc.Core.Testing/project.json.template
deleted file mode 100644
index 7aff9911455467a5132edbb3dd7dc77fae71ffe5..0000000000000000000000000000000000000000
--- a/templates/src/csharp/Grpc.Core.Testing/project.json.template
+++ /dev/null
@@ -1,41 +0,0 @@
-%YAML 1.2
---- |
-  {
-    "version": "${settings.csharp_version}",
-    "title": "gRPC C# Core Testing",
-    "authors": [ "Google Inc." ],
-    "copyright": "Copyright 2017, Google Inc.",
-    "packOptions": {
-      "summary": "Testing support for gRPC C#",
-      "description": "Useful when testing code that uses gRPC.",
-      "owners": [ "grpc-packages" ],
-      "licenseUrl": "https://github.com/grpc/grpc/blob/master/LICENSE",
-      "projectUrl": "https://github.com/grpc/grpc",
-      "requireLicenseAcceptance": false,
-      "tags": [ "gRPC test testing" ]
-    },
-    "buildOptions": {
-      "define": [ "SIGNED" ],
-      "keyFile": "../keys/Grpc.snk",
-      "xmlDoc": true,
-      "compile": {
-        "includeFiles": [ "../Grpc.Core/Version.cs" ]
-      }
-    },
-    "dependencies": {
-      "Grpc.Core": "${settings.csharp_version}"
-    },
-    "frameworks": {
-      "net45": {
-        "frameworkAssemblies": {
-          "System.Runtime": "",
-          "System.IO": ""
-        }
-      },
-      "netstandard1.5": {
-        "dependencies": {
-          "NETStandard.Library": "1.6.0"
-        }
-      }
-    }
-  }
diff --git a/templates/src/csharp/Grpc.Core.Tests/project.json.template b/templates/src/csharp/Grpc.Core.Tests/project.json.template
deleted file mode 100644
index b5f8190443ad0c42afa2eecbc5b23c947a7effb0..0000000000000000000000000000000000000000
--- a/templates/src/csharp/Grpc.Core.Tests/project.json.template
+++ /dev/null
@@ -1,30 +0,0 @@
-%YAML 1.2
---- |
-  {
-    <%include file="../build_options.include" args="executable=True"/>
-    "dependencies": {
-      "Grpc.Core": {
-        "target": "project"
-      },
-      "Newtonsoft.Json": "9.0.1",
-      "NUnit": "3.6.0",
-      "NUnitLite": "3.6.0",
-      "NUnit.ConsoleRunner": "3.6.0",
-      "OpenCover": "4.6.519",
-      "ReportGenerator": "2.4.4.0"
-    },
-    "frameworks": {
-      "net45": { },
-      "netcoreapp1.0": {
-        "imports": [
-          "portable-net45"
-        ],
-        "dependencies": {
-          "Microsoft.NETCore.App": {
-            "type": "platform",
-            "version": "1.0.0"
-          }
-        }
-      }
-    },
-  }
diff --git a/templates/src/csharp/Grpc.Core/Version.csproj.include.template b/templates/src/csharp/Grpc.Core/Version.csproj.include.template
new file mode 100755
index 0000000000000000000000000000000000000000..30b8d26375bfc369a238ecd84b70ded67dd1f0f9
--- /dev/null
+++ b/templates/src/csharp/Grpc.Core/Version.csproj.include.template
@@ -0,0 +1,9 @@
+%YAML 1.2
+--- |
+  <!-- This file is generated -->
+  <Project>
+    <PropertyGroup>
+      <GrpcCsharpVersion>${settings.csharp_version}</GrpcCsharpVersion>
+      <GoogleProtobufVersion>3.2.0</GoogleProtobufVersion>
+    </PropertyGroup>
+  </Project>
diff --git a/templates/src/csharp/Grpc.Core/project.json.template b/templates/src/csharp/Grpc.Core/project.json.template
deleted file mode 100644
index 120a9943e30e543a709dbe37e0702279b1653572..0000000000000000000000000000000000000000
--- a/templates/src/csharp/Grpc.Core/project.json.template
+++ /dev/null
@@ -1,47 +0,0 @@
-%YAML 1.2
---- |
-  {
-    "version": "${settings.csharp_version}",
-    "title": "gRPC C# Core",
-    "authors": [ "Google Inc." ],
-    "copyright": "Copyright 2015, Google Inc.",
-    "packOptions": {
-      "summary": "Core C# implementation of gRPC - an RPC library and framework",
-      "description": "Core C# implementation of gRPC - an RPC library and framework. See project site for more info.",
-      "owners": [ "grpc-packages" ],
-      "licenseUrl": "https://github.com/grpc/grpc/blob/master/LICENSE",
-      "projectUrl": "https://github.com/grpc/grpc",
-      "requireLicenseAcceptance": false,
-      "tags": [ "gRPC RPC Protocol HTTP/2" ],
-      "files": {
-        "mappings": {
-          "build/net45/": "Grpc.Core.targets",
-          "runtimes/win/native/grpc_csharp_ext.x86.dll": "../nativelibs/windows_x86/grpc_csharp_ext.dll",
-          "runtimes/win/native/grpc_csharp_ext.x64.dll": "../nativelibs/windows_x64/grpc_csharp_ext.dll",
-          "runtimes/linux/native/libgrpc_csharp_ext.x86.so": "../nativelibs/linux_x86/libgrpc_csharp_ext.so",
-          "runtimes/linux/native/libgrpc_csharp_ext.x64.so": "../nativelibs/linux_x64/libgrpc_csharp_ext.so",
-          "runtimes/osx/native/libgrpc_csharp_ext.x86.dylib": "../nativelibs/macosx_x86/libgrpc_csharp_ext.dylib",
-          "runtimes/osx/native/libgrpc_csharp_ext.x64.dylib": "../nativelibs/macosx_x64/libgrpc_csharp_ext.dylib"
-        }
-      }
-    },
-    "buildOptions": {
-      "embed": [ "../../../etc/roots.pem" ],
-      "define": [ "SIGNED" ],
-      "keyFile": "../keys/Grpc.snk",
-      "xmlDoc": true
-    },
-    "dependencies": {
-      "System.Interactive.Async": "3.1.1"
-    },
-    "frameworks": {
-      "net45": { },
-      "netstandard1.5": {
-        "dependencies": {
-          "NETStandard.Library": "1.6.0",
-          "System.Runtime.Loader": "4.0.0",
-          "System.Threading.Thread": "4.0.0"
-        }
-      }
-    }
-  }
diff --git a/templates/src/csharp/Grpc.Examples.MathClient/project.json.template b/templates/src/csharp/Grpc.Examples.MathClient/project.json.template
deleted file mode 100644
index ae4ea2aaac77cb70891680217e67a97737b31700..0000000000000000000000000000000000000000
--- a/templates/src/csharp/Grpc.Examples.MathClient/project.json.template
+++ /dev/null
@@ -1,21 +0,0 @@
-%YAML 1.2
---- |
-  {
-    <%include file="../build_options.include" args="executable=True"/>
-    "dependencies": {
-      "Grpc.Examples": {
-        "target": "project"
-      }
-    },
-    "frameworks": {
-      "net45": { },
-      "netcoreapp1.0": {
-        "dependencies": {
-          "Microsoft.NETCore.App": {
-            "type": "platform",
-            "version": "1.0.0"
-          }
-        }
-      }
-    }
-  }
diff --git a/templates/src/csharp/Grpc.Examples.MathServer/project.json.template b/templates/src/csharp/Grpc.Examples.MathServer/project.json.template
deleted file mode 100644
index ae4ea2aaac77cb70891680217e67a97737b31700..0000000000000000000000000000000000000000
--- a/templates/src/csharp/Grpc.Examples.MathServer/project.json.template
+++ /dev/null
@@ -1,21 +0,0 @@
-%YAML 1.2
---- |
-  {
-    <%include file="../build_options.include" args="executable=True"/>
-    "dependencies": {
-      "Grpc.Examples": {
-        "target": "project"
-      }
-    },
-    "frameworks": {
-      "net45": { },
-      "netcoreapp1.0": {
-        "dependencies": {
-          "Microsoft.NETCore.App": {
-            "type": "platform",
-            "version": "1.0.0"
-          }
-        }
-      }
-    }
-  }
diff --git a/templates/src/csharp/Grpc.Examples.Tests/project.json.template b/templates/src/csharp/Grpc.Examples.Tests/project.json.template
deleted file mode 100644
index da60c017a3623c1976da1d75d02abbdfa175933b..0000000000000000000000000000000000000000
--- a/templates/src/csharp/Grpc.Examples.Tests/project.json.template
+++ /dev/null
@@ -1,26 +0,0 @@
-%YAML 1.2
---- |
-  {
-    <%include file="../build_options.include" args="executable=True"/>
-    "dependencies": {
-      "Grpc.Examples": {
-        "target": "project"
-      },
-      "NUnit": "3.6.0",
-      "NUnitLite": "3.6.0"
-    },
-    "frameworks": {
-      "net45": { },
-      "netcoreapp1.0": {
-        "imports": [
-          "portable-net45"
-        ],
-        "dependencies": {
-          "Microsoft.NETCore.App": {
-            "type": "platform",
-            "version": "1.0.0"
-          }
-        }
-      }
-    }
-  }
diff --git a/templates/src/csharp/Grpc.Examples/project.json.template b/templates/src/csharp/Grpc.Examples/project.json.template
deleted file mode 100644
index 5de965cb1b7e6eab8169fae9b1d0eed4c2f0c848..0000000000000000000000000000000000000000
--- a/templates/src/csharp/Grpc.Examples/project.json.template
+++ /dev/null
@@ -1,22 +0,0 @@
-%YAML 1.2
---- |
-  {
-    <%include file="../build_options.include" args="executable=False"/>
-    "dependencies": {
-      "Grpc.Core": {
-        "target": "project"
-      },
-      "Google.Protobuf": "3.2.0"
-    },
-    "frameworks": {
-      "net45": {},
-      "netcoreapp1.0": {
-        "dependencies": {
-          "Microsoft.NETCore.App": {
-            "type": "platform",
-            "version": "1.0.0"
-          }
-        }
-      }
-    }
-  }
diff --git a/templates/src/csharp/Grpc.HealthCheck.Tests/project.json.template b/templates/src/csharp/Grpc.HealthCheck.Tests/project.json.template
deleted file mode 100644
index 4a993326c3236ef54b9a0a963fbe71991b0116cc..0000000000000000000000000000000000000000
--- a/templates/src/csharp/Grpc.HealthCheck.Tests/project.json.template
+++ /dev/null
@@ -1,26 +0,0 @@
-%YAML 1.2
---- |
-  {
-    <%include file="../build_options.include" args="executable=True"/>
-    "dependencies": {
-      "Grpc.HealthCheck": {
-        "target": "project"
-      },
-      "NUnit": "3.6.0",
-      "NUnitLite": "3.6.0"
-    },
-    "frameworks": {
-      "net45": { },
-      "netcoreapp1.0": {
-        "imports": [
-          "portable-net45"
-        ],
-        "dependencies": {
-          "Microsoft.NETCore.App": {
-            "type": "platform",
-            "version": "1.0.0"
-          }
-        }
-      }
-    }
-  }
diff --git a/templates/src/csharp/Grpc.HealthCheck/project.json.template b/templates/src/csharp/Grpc.HealthCheck/project.json.template
deleted file mode 100644
index 9cd0d83a9be893944d80adead0168b22f11206b0..0000000000000000000000000000000000000000
--- a/templates/src/csharp/Grpc.HealthCheck/project.json.template
+++ /dev/null
@@ -1,37 +0,0 @@
-%YAML 1.2
---- |
-  {
-    "version": "${settings.csharp_version}",
-    "title": "gRPC C# Healthchecking",
-    "authors": [ "Google Inc." ],
-    "copyright": "Copyright 2015, Google Inc.",
-    "packOptions": {
-      "summary": "Implementation of gRPC health service",
-      "description": "Example implementation of grpc.health.v1 service that can be used for health-checking.",
-      "owners": [ "grpc-packages" ],
-      "licenseUrl": "https://github.com/grpc/grpc/blob/master/LICENSE",
-      "projectUrl": "https://github.com/grpc/grpc",
-      "requireLicenseAcceptance": false,
-      "tags": [ "gRPC health check" ]
-    },
-    "buildOptions": {
-      "define": [ "SIGNED" ],
-      "keyFile": "../keys/Grpc.snk",
-      "xmlDoc": true,
-      "compile": {
-        "includeFiles": [ "../Grpc.Core/Version.cs" ]
-      }
-    },
-    "dependencies": {
-      "Grpc.Core": "${settings.csharp_version}",
-      "Google.Protobuf": "3.2.0"
-    },
-    "frameworks": {
-      "net45": {},
-      "netstandard1.5": {
-        "dependencies": {
-          "NETStandard.Library": "1.6.0"
-        }
-      }
-    }
-  }
diff --git a/templates/src/csharp/Grpc.IntegrationTesting.Client/project.json.template b/templates/src/csharp/Grpc.IntegrationTesting.Client/project.json.template
deleted file mode 100644
index 83b8a9befa366dc047160eca6ecf7487ba51addd..0000000000000000000000000000000000000000
--- a/templates/src/csharp/Grpc.IntegrationTesting.Client/project.json.template
+++ /dev/null
@@ -1,24 +0,0 @@
-%YAML 1.2
---- |
-  {
-    <%include file="../build_options.include" args="executable=True,includeData=True"/>
-    "dependencies": {
-      "Grpc.IntegrationTesting": {
-        "target": "project"
-      }
-    },
-    "frameworks": {
-      "net45": { },
-      "netcoreapp1.0": {
-        "imports": [
-          "portable-net45"
-        ],
-        "dependencies": {
-          "Microsoft.NETCore.App": {
-            "type": "platform",
-            "version": "1.0.0"
-          }
-        }
-      }
-    }
-  }
diff --git a/templates/src/csharp/Grpc.IntegrationTesting.QpsWorker/project.json.template b/templates/src/csharp/Grpc.IntegrationTesting.QpsWorker/project.json.template
deleted file mode 100644
index 8304d20f2ec41a42a3402339dcc01f6a27de2d3b..0000000000000000000000000000000000000000
--- a/templates/src/csharp/Grpc.IntegrationTesting.QpsWorker/project.json.template
+++ /dev/null
@@ -1,29 +0,0 @@
-%YAML 1.2
---- |
-  {
-    <%include file="../build_options.include" args="executable=True,includeData=True"/>
-    "dependencies": {
-      "Grpc.IntegrationTesting": {
-        "target": "project"
-      }
-    },
-    "frameworks": {
-      "net45": { },
-      "netcoreapp1.0": {
-        "imports": [
-          "portable-net45"
-        ],
-        "dependencies": {
-          "Microsoft.NETCore.App": {
-            "type": "platform",
-            "version": "1.0.0"
-          }
-        }
-      }
-    },
-    "runtimeOptions": {
-      "configProperties": {
-        "System.GC.Server": true
-      }
-    }
-  }
diff --git a/templates/src/csharp/Grpc.IntegrationTesting.Server/project.json.template b/templates/src/csharp/Grpc.IntegrationTesting.Server/project.json.template
deleted file mode 100644
index 83b8a9befa366dc047160eca6ecf7487ba51addd..0000000000000000000000000000000000000000
--- a/templates/src/csharp/Grpc.IntegrationTesting.Server/project.json.template
+++ /dev/null
@@ -1,24 +0,0 @@
-%YAML 1.2
---- |
-  {
-    <%include file="../build_options.include" args="executable=True,includeData=True"/>
-    "dependencies": {
-      "Grpc.IntegrationTesting": {
-        "target": "project"
-      }
-    },
-    "frameworks": {
-      "net45": { },
-      "netcoreapp1.0": {
-        "imports": [
-          "portable-net45"
-        ],
-        "dependencies": {
-          "Microsoft.NETCore.App": {
-            "type": "platform",
-            "version": "1.0.0"
-          }
-        }
-      }
-    }
-  }
diff --git a/templates/src/csharp/Grpc.IntegrationTesting.StressClient/project.json.template b/templates/src/csharp/Grpc.IntegrationTesting.StressClient/project.json.template
deleted file mode 100644
index 83b8a9befa366dc047160eca6ecf7487ba51addd..0000000000000000000000000000000000000000
--- a/templates/src/csharp/Grpc.IntegrationTesting.StressClient/project.json.template
+++ /dev/null
@@ -1,24 +0,0 @@
-%YAML 1.2
---- |
-  {
-    <%include file="../build_options.include" args="executable=True,includeData=True"/>
-    "dependencies": {
-      "Grpc.IntegrationTesting": {
-        "target": "project"
-      }
-    },
-    "frameworks": {
-      "net45": { },
-      "netcoreapp1.0": {
-        "imports": [
-          "portable-net45"
-        ],
-        "dependencies": {
-          "Microsoft.NETCore.App": {
-            "type": "platform",
-            "version": "1.0.0"
-          }
-        }
-      }
-    }
-  }
diff --git a/templates/src/csharp/Grpc.IntegrationTesting/project.json.template b/templates/src/csharp/Grpc.IntegrationTesting/project.json.template
deleted file mode 100644
index 74b928110f1c9d7ea25badb592c6ab3b11d876ef..0000000000000000000000000000000000000000
--- a/templates/src/csharp/Grpc.IntegrationTesting/project.json.template
+++ /dev/null
@@ -1,35 +0,0 @@
-%YAML 1.2
---- |
-  {
-    <%include file="../build_options.include" args="executable=True,includeData=True"/>
-    "dependencies": {
-      "Grpc.Auth": {
-        "target": "project"
-      },
-      "Grpc.Core": {
-        "target": "project"
-      },
-      "Google.Protobuf": "3.2.0",
-      "CommandLineParser": "2.1.1-beta",
-      "Moq": "4.7.0",
-      "NUnit": "3.6.0",
-      "NUnitLite": "3.6.0"
-    },
-    "frameworks": {
-      "net45": {
-        "frameworkAssemblies": {}
-      },
-      "netcoreapp1.0": {
-        "imports": [
-          "portable-net45"
-        ],
-        "dependencies": {
-          "Microsoft.NETCore.App": {
-            "type": "platform",
-            "version": "1.0.0"
-          },
-          "System.Linq.Expressions": "4.1.0"
-        }
-      }
-    }
-  }
diff --git a/templates/src/csharp/Grpc.Reflection.Tests/project.json.template b/templates/src/csharp/Grpc.Reflection.Tests/project.json.template
deleted file mode 100644
index 65d200e30b52008fbc7bb5220eace8abf21aab96..0000000000000000000000000000000000000000
--- a/templates/src/csharp/Grpc.Reflection.Tests/project.json.template
+++ /dev/null
@@ -1,26 +0,0 @@
-%YAML 1.2
---- |
-  {
-    <%include file="../build_options.include" args="executable=True"/>
-    "dependencies": {
-      "Grpc.Reflection": {
-        "target": "project"
-      },
-      "NUnit": "3.6.0",
-      "NUnitLite": "3.6.0"
-    },
-    "frameworks": {
-      "net45": { },
-      "netcoreapp1.0": {
-        "imports": [
-          "portable-net45"
-        ],
-        "dependencies": {
-          "Microsoft.NETCore.App": {
-            "type": "platform",
-            "version": "1.0.0"
-          }
-        }
-      }
-    }
-  }
diff --git a/templates/src/csharp/Grpc.Reflection/project.json.template b/templates/src/csharp/Grpc.Reflection/project.json.template
deleted file mode 100644
index e6f65f8ab394604f104c4086092134c433ddddd6..0000000000000000000000000000000000000000
--- a/templates/src/csharp/Grpc.Reflection/project.json.template
+++ /dev/null
@@ -1,37 +0,0 @@
-%YAML 1.2
---- |
-  {
-    "version": "${settings.csharp_version}",
-    "title": "gRPC C# Reflection",
-    "authors": [ "Google Inc." ],
-    "copyright": "Copyright 2016, Google Inc.",
-    "packOptions": {
-      "summary": "Implementation of gRPC reflection service",
-      "description": "Provides information about services running on a gRPC C# server.",
-      "owners": [ "grpc-packages" ],
-      "licenseUrl": "https://github.com/grpc/grpc/blob/master/LICENSE",
-      "projectUrl": "https://github.com/grpc/grpc",
-      "requireLicenseAcceptance": false,
-      "tags": [ "gRPC reflection" ]
-    },
-    "buildOptions": {
-      "define": [ "SIGNED" ],
-      "keyFile": "../keys/Grpc.snk",
-      "xmlDoc": true,
-      "compile": {
-        "includeFiles": [ "../Grpc.Core/Version.cs" ]
-      }
-    },
-    "dependencies": {
-      "Grpc.Core": "${settings.csharp_version}",
-      "Google.Protobuf": "3.2.0"
-    },
-    "frameworks": {
-      "net45": {},
-      "netstandard1.5": {
-        "dependencies": {
-          "NETStandard.Library": "1.6.0"
-        }
-      }
-    }
-  }
diff --git a/templates/src/csharp/build_options.include b/templates/src/csharp/build_options.include
deleted file mode 100644
index db4cc198039cc30ee666086e422d7fd4739d4fb3..0000000000000000000000000000000000000000
--- a/templates/src/csharp/build_options.include
+++ /dev/null
@@ -1,56 +0,0 @@
-<%page args="executable=False,includeData=False"/>\
-"buildOptions": {
-  % if executable:
-    "emitEntryPoint": true
-  % endif
-  },
-  % if executable:
-  "configurations": {
-    "Debug": {
-      "buildOptions": {
-        "define": [ "SIGNED" ],
-        "keyFile": "../keys/Grpc.snk",
-        "xmlDoc": true,
-        "compile": {
-          "includeFiles": [ "../Grpc.Core/Version.cs" ]
-        },
-        "copyToOutput": {
-          "mappings": {
-            % if includeData:
-            "data/ca.pem": "../Grpc.IntegrationTesting/data/ca.pem",
-            "data/server1.key": "../Grpc.IntegrationTesting/data/server1.key",
-            "data/server1.pem": "../Grpc.IntegrationTesting/data/server1.pem",
-            % endif
-            "grpc_csharp_ext.x64.dll": "../../../cmake/build/x64/Debug/grpc_csharp_ext.dll",
-            "grpc_csharp_ext.x86.dll": "../../../cmake/build/Win32/Debug/grpc_csharp_ext.dll",
-            "libgrpc_csharp_ext.x64.so": "../../../libs/dbg/libgrpc_csharp_ext.so",
-            "libgrpc_csharp_ext.x64.dylib": "../../../libs/dbg/libgrpc_csharp_ext.dylib"
-          }
-        }
-      }
-    },
-    "Release": {
-      "buildOptions": {
-        "define": [ "SIGNED" ],
-        "keyFile": "../keys/Grpc.snk",
-        "xmlDoc": true,
-        "compile": {
-          "includeFiles": [ "../Grpc.Core/Version.cs" ]
-        },
-        "copyToOutput": {
-          "mappings": {
-            % if includeData:
-            "data/ca.pem": "../Grpc.IntegrationTesting/data/ca.pem",
-            "data/server1.key": "../Grpc.IntegrationTesting/data/server1.key",
-            "data/server1.pem": "../Grpc.IntegrationTesting/data/server1.pem",
-            % endif
-            "grpc_csharp_ext.x64.dll": "../../../cmake/build/x64/Release/grpc_csharp_ext.dll",
-            "grpc_csharp_ext.x86.dll": "../../../cmake/build/Win32/Release/grpc_csharp_ext.dll",
-            "libgrpc_csharp_ext.x64.so": "../../../libs/opt/libgrpc_csharp_ext.so",
-            "libgrpc_csharp_ext.x64.dylib": "../../../libs/opt/libgrpc_csharp_ext.dylib"
-          }
-        }
-      }
-    }
-  },
-  %endif
diff --git a/templates/src/csharp/build_packages_dotnetcli.bat.template b/templates/src/csharp/build_packages_dotnetcli.bat.template
index 2f91d485ec401945a1d3beb2e2cff2a7586f941f..91808e0d266875fdeab67de019873c24f975e400 100755
--- a/templates/src/csharp/build_packages_dotnetcli.bat.template
+++ b/templates/src/csharp/build_packages_dotnetcli.bat.template
@@ -31,11 +31,10 @@
   
   @rem Current package versions
   set VERSION=${settings.csharp_version}
-  set PROTOBUF_VERSION=3.0.0
   
   @rem Adjust the location of nuget.exe
   set NUGET=C:\nuget\nuget.exe
-  set DOTNET=C:\dotnet\dotnet.exe
+  set DOTNET=dotnet
   
   set -ex
   
@@ -58,13 +57,16 @@
   xcopy /Y /I ..\..\architecture=x86,language=protoc,platform=macos\artifacts\* protoc_plugins\macosx_x86${"\\"}
   xcopy /Y /I ..\..\architecture=x64,language=protoc,platform=macos\artifacts\* protoc_plugins\macosx_x64${"\\"}
   
-  %%DOTNET% restore . || goto :error
+  %%DOTNET% restore Grpc.sln || goto :error
   
-  %%DOTNET% pack --configuration Release Grpc.Core\project.json --output ..\..\artifacts || goto :error
-  %%DOTNET% pack --configuration Release Grpc.Core.Testing\project.json --output ..\..\artifacts || goto :error
-  %%DOTNET% pack --configuration Release Grpc.Auth\project.json --output ..\..\artifacts || goto :error
-  %%DOTNET% pack --configuration Release Grpc.HealthCheck\project.json --output ..\..\artifacts || goto :error
-  %%DOTNET% pack --configuration Release Grpc.Reflection\project.json --output ..\..\artifacts || goto :error
+  @rem To be able to build, we also need to put grpc_csharp_ext to its normal location
+  xcopy /Y /I nativelibs\windows_x64\grpc_csharp_ext.dll ..\..\cmake\build\x64\Release${"\\"}
+  
+  %%DOTNET% pack --configuration Release Grpc.Core --output ..\..\..\artifacts || goto :error
+  %%DOTNET% pack --configuration Release Grpc.Core.Testing --output ..\..\..\artifacts || goto :error
+  %%DOTNET% pack --configuration Release Grpc.Auth --output ..\..\..\artifacts || goto :error
+  %%DOTNET% pack --configuration Release Grpc.HealthCheck --output ..\..\..\artifacts || goto :error
+  %%DOTNET% pack --configuration Release Grpc.Reflection --output ..\..\..\artifacts || goto :error
   
   %%NUGET% pack Grpc.nuspec -Version %VERSION% -OutputDirectory ..\..\artifacts || goto :error
   %%NUGET% pack Grpc.Tools.nuspec -Version %VERSION% -OutputDirectory ..\..\artifacts
diff --git a/templates/src/csharp/build_packages_dotnetcli.sh.template b/templates/src/csharp/build_packages_dotnetcli.sh.template
index c5364377b99d6d22d0f7a49c02564f87dfc8e0e5..374b236f93cf49dd9da52fcbdac684f073e86541 100755
--- a/templates/src/csharp/build_packages_dotnetcli.sh.template
+++ b/templates/src/csharp/build_packages_dotnetcli.sh.template
@@ -60,13 +60,17 @@
   cp $EXTERNAL_GIT_ROOT/architecture=x86,language=protoc,platform=macos/artifacts/* protoc_plugins/macosx_x86 || true
   cp $EXTERNAL_GIT_ROOT/architecture=x64,language=protoc,platform=macos/artifacts/* protoc_plugins/macosx_x64 || true
   
-  dotnet restore .
+  dotnet restore Grpc.sln
   
-  dotnet pack --configuration Release Grpc.Core/project.json --output ../../artifacts
-  dotnet pack --configuration Release Grpc.Core.Testing/project.json --output ../../artifacts
-  dotnet pack --configuration Release Grpc.Auth/project.json --output ../../artifacts
-  dotnet pack --configuration Release Grpc.HealthCheck/project.json --output ../../artifacts
-  dotnet pack --configuration Release Grpc.Reflection/project.json --output ../../artifacts
+  # To be able to build, we also need to put grpc_csharp_ext to its normal location
+  mkdir -p ../../libs/opt
+  cp nativelibs/linux_x64/libgrpc_csharp_ext.so ../../libs/opt
+  
+  dotnet pack --configuration Release Grpc.Core --output ../../../artifacts
+  dotnet pack --configuration Release Grpc.Core.Testing --output ../../../artifacts
+  dotnet pack --configuration Release Grpc.Auth --output ../../../artifacts
+  dotnet pack --configuration Release Grpc.HealthCheck --output ../../../artifacts
+  dotnet pack --configuration Release Grpc.Reflection --output ../../../artifacts
   
   nuget pack Grpc.nuspec -Version "${settings.csharp_version}" -OutputDirectory ../../artifacts
   nuget pack Grpc.Tools.nuspec -Version "${settings.csharp_version}" -OutputDirectory ../../artifacts
diff --git a/templates/tools/dockerfile/csharp_deps.include b/templates/tools/dockerfile/csharp_deps.include
index 7e89dec2cc2ed5e42fce4ed833713dd372eb5279..612b119e1c9d1a33bf3e057e659aeeb47ed55637 100644
--- a/templates/tools/dockerfile/csharp_deps.include
+++ b/templates/tools/dockerfile/csharp_deps.include
@@ -6,7 +6,6 @@ RUN apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 3FA7E0328081BFF6A14
 RUN echo "deb http://download.mono-project.com/repo/debian wheezy main" | tee /etc/apt/sources.list.d/mono-xamarin.list
 RUN echo "deb http://download.mono-project.com/repo/debian wheezy-apache24-compat main" | tee -a /etc/apt/sources.list.d/mono-xamarin.list
 RUN echo "deb http://download.mono-project.com/repo/debian wheezy-libjpeg62-compat main" | tee -a /etc/apt/sources.list.d/mono-xamarin.list
-RUN echo "deb http://download.mono-project.com/repo/debian wheezy-libtiff-compat main" | tee -a /etc/apt/sources.list.d/mono-xamarin.list
 
 # Install dependencies
 RUN apt-get update && apt-get -y dist-upgrade && apt-get install -y ${'\\'}
diff --git a/templates/tools/dockerfile/csharp_dotnetcli_deps.include b/templates/tools/dockerfile/csharp_dotnetcli_deps.include
index 058ce15fb52ecd6cd0951738efcaf48aa30e265a..bc88d2bfa39ca4a70ba294cae3d4874917b4735e 100644
--- a/templates/tools/dockerfile/csharp_dotnetcli_deps.include
+++ b/templates/tools/dockerfile/csharp_dotnetcli_deps.include
@@ -1,7 +1,7 @@
 # Install dotnet SDK based on https://www.microsoft.com/net/core#debian
 RUN apt-get update && apt-get install -y curl libunwind8 gettext
-# dotnet-dev-1.0.0-preview2-003121
-RUN curl -sSL -o dotnet100.tar.gz https://go.microsoft.com/fwlink/?LinkID=809130
+# dotnet-dev-1.0.0-preview2-003131
+RUN curl -sSL -o dotnet100.tar.gz https://go.microsoft.com/fwlink/?LinkID=827530
 RUN mkdir -p /opt/dotnet && tar zxf dotnet100.tar.gz -C /opt/dotnet
 # dotnet-dev-1.0.1
 RUN curl -sSL -o dotnet101.tar.gz https://go.microsoft.com/fwlink/?LinkID=843453
diff --git a/templates/tools/dockerfile/interoptest/grpc_interop_csharp/Dockerfile.template b/templates/tools/dockerfile/interoptest/grpc_interop_csharp/Dockerfile.template
index da0c70aee0cd616b281ebbdaef8cf2143374780e..092f04dac6c991f902c80847b3064bce65bfcf97 100644
--- a/templates/tools/dockerfile/interoptest/grpc_interop_csharp/Dockerfile.template
+++ b/templates/tools/dockerfile/interoptest/grpc_interop_csharp/Dockerfile.template
@@ -34,6 +34,7 @@
   <%include file="../../apt_get_basic.include"/>
   <%include file="../../python_deps.include"/>
   <%include file="../../csharp_deps.include"/>
+  <%include file="../../csharp_dotnetcli_deps.include"/>
   <%include file="../../run_tests_addons.include"/>
   # Define the default command.
   CMD ["bash"]
diff --git a/templates/tools/dockerfile/interoptest/grpc_interop_csharpcoreclr/Dockerfile.template b/templates/tools/dockerfile/interoptest/grpc_interop_csharpcoreclr/Dockerfile.template
deleted file mode 100644
index 092f04dac6c991f902c80847b3064bce65bfcf97..0000000000000000000000000000000000000000
--- a/templates/tools/dockerfile/interoptest/grpc_interop_csharpcoreclr/Dockerfile.template
+++ /dev/null
@@ -1,41 +0,0 @@
-%YAML 1.2
---- |
-  # Copyright 2015, Google Inc.
-  # All rights reserved.
-  #
-  # Redistribution and use in source and binary forms, with or without
-  # modification, are permitted provided that the following conditions are
-  # met:
-  #
-  #     * Redistributions of source code must retain the above copyright
-  # notice, this list of conditions and the following disclaimer.
-  #     * Redistributions in binary form must reproduce the above
-  # copyright notice, this list of conditions and the following disclaimer
-  # in the documentation and/or other materials provided with the
-  # distribution.
-  #     * Neither the name of Google Inc. nor the names of its
-  # contributors may be used to endorse or promote products derived from
-  # this software without specific prior written permission.
-  #
-  # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-  # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-  # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-  # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-  # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-  # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-  # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-  # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-  # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-  # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-  # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-  
-  FROM debian:jessie
-  
-  <%include file="../../apt_get_basic.include"/>
-  <%include file="../../python_deps.include"/>
-  <%include file="../../csharp_deps.include"/>
-  <%include file="../../csharp_dotnetcli_deps.include"/>
-  <%include file="../../run_tests_addons.include"/>
-  # Define the default command.
-  CMD ["bash"]
-  
diff --git a/templates/tools/dockerfile/test/csharp_coreclr_x64/Dockerfile.template b/templates/tools/dockerfile/test/csharp_coreclr_x64/Dockerfile.template
deleted file mode 100644
index 092f04dac6c991f902c80847b3064bce65bfcf97..0000000000000000000000000000000000000000
--- a/templates/tools/dockerfile/test/csharp_coreclr_x64/Dockerfile.template
+++ /dev/null
@@ -1,41 +0,0 @@
-%YAML 1.2
---- |
-  # Copyright 2015, Google Inc.
-  # All rights reserved.
-  #
-  # Redistribution and use in source and binary forms, with or without
-  # modification, are permitted provided that the following conditions are
-  # met:
-  #
-  #     * Redistributions of source code must retain the above copyright
-  # notice, this list of conditions and the following disclaimer.
-  #     * Redistributions in binary form must reproduce the above
-  # copyright notice, this list of conditions and the following disclaimer
-  # in the documentation and/or other materials provided with the
-  # distribution.
-  #     * Neither the name of Google Inc. nor the names of its
-  # contributors may be used to endorse or promote products derived from
-  # this software without specific prior written permission.
-  #
-  # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-  # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-  # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-  # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-  # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-  # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-  # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-  # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-  # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-  # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-  # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-  
-  FROM debian:jessie
-  
-  <%include file="../../apt_get_basic.include"/>
-  <%include file="../../python_deps.include"/>
-  <%include file="../../csharp_deps.include"/>
-  <%include file="../../csharp_dotnetcli_deps.include"/>
-  <%include file="../../run_tests_addons.include"/>
-  # Define the default command.
-  CMD ["bash"]
-  
diff --git a/templates/tools/dockerfile/test/csharp_jessie_x64/Dockerfile.template b/templates/tools/dockerfile/test/csharp_jessie_x64/Dockerfile.template
index da0c70aee0cd616b281ebbdaef8cf2143374780e..092f04dac6c991f902c80847b3064bce65bfcf97 100644
--- a/templates/tools/dockerfile/test/csharp_jessie_x64/Dockerfile.template
+++ b/templates/tools/dockerfile/test/csharp_jessie_x64/Dockerfile.template
@@ -34,6 +34,7 @@
   <%include file="../../apt_get_basic.include"/>
   <%include file="../../python_deps.include"/>
   <%include file="../../csharp_deps.include"/>
+  <%include file="../../csharp_dotnetcli_deps.include"/>
   <%include file="../../run_tests_addons.include"/>
   # Define the default command.
   CMD ["bash"]
diff --git a/test/core/bad_client/bad_client.c b/test/core/bad_client/bad_client.c
index 4870dc1a536923d28460f9d7a173e756779c3ac7..9a566e6484cdba087e98f4449e9cdc7dfc28e7b8 100644
--- a/test/core/bad_client/bad_client.c
+++ b/test/core/bad_client/bad_client.c
@@ -117,10 +117,7 @@ void grpc_run_bad_client_test(
   grpc_init();
 
   /* Create endpoints */
-  grpc_resource_quota *resource_quota =
-      grpc_resource_quota_create("bad_client_test");
-  sfd = grpc_iomgr_create_endpoint_pair("fixture", resource_quota, 65536);
-  grpc_resource_quota_unref_internal(&exec_ctx, resource_quota);
+  sfd = grpc_iomgr_create_endpoint_pair("fixture", NULL);
 
   /* Create server, completion events */
   a.server = grpc_server_create(NULL, NULL);
diff --git a/test/core/end2end/fixtures/h2_sockpair+trace.c b/test/core/end2end/fixtures/h2_sockpair+trace.c
index 5ace922f058135d34013148527a4b63920b808c8..424241c1e47b8e6c8945c0131143225f26448949 100644
--- a/test/core/end2end/fixtures/h2_sockpair+trace.c
+++ b/test/core/end2end/fixtures/h2_sockpair+trace.c
@@ -96,9 +96,7 @@ static grpc_end2end_test_fixture chttp2_create_fixture_socketpair(
   f.fixture_data = sfd;
   f.cq = grpc_completion_queue_create(NULL);
 
-  grpc_resource_quota *resource_quota = grpc_resource_quota_create("fixture");
-  *sfd = grpc_iomgr_create_endpoint_pair("fixture", resource_quota, 65536);
-  grpc_resource_quota_unref(resource_quota);
+  *sfd = grpc_iomgr_create_endpoint_pair("fixture", NULL);
 
   return f;
 }
diff --git a/test/core/end2end/fixtures/h2_sockpair.c b/test/core/end2end/fixtures/h2_sockpair.c
index 3079a42dcebe4f3a3e851316dcf045d8ac6e5908..fe8d766e74e2e19b3a44d5ea69bd170a1d11d31c 100644
--- a/test/core/end2end/fixtures/h2_sockpair.c
+++ b/test/core/end2end/fixtures/h2_sockpair.c
@@ -90,9 +90,7 @@ static grpc_end2end_test_fixture chttp2_create_fixture_socketpair(
   f.fixture_data = sfd;
   f.cq = grpc_completion_queue_create(NULL);
 
-  grpc_resource_quota *resource_quota = grpc_resource_quota_create("fixture");
-  *sfd = grpc_iomgr_create_endpoint_pair("fixture", resource_quota, 65536);
-  grpc_resource_quota_unref(resource_quota);
+  *sfd = grpc_iomgr_create_endpoint_pair("fixture", NULL);
 
   return f;
 }
diff --git a/test/core/end2end/fixtures/h2_sockpair_1byte.c b/test/core/end2end/fixtures/h2_sockpair_1byte.c
index 70410d75f4cc3a3ddc7bc1ee979b164413bdabd3..04174fa5015b245dbca0bc73aafc1ed163d61ea4 100644
--- a/test/core/end2end/fixtures/h2_sockpair_1byte.c
+++ b/test/core/end2end/fixtures/h2_sockpair_1byte.c
@@ -90,9 +90,17 @@ static grpc_end2end_test_fixture chttp2_create_fixture_socketpair(
   f.fixture_data = sfd;
   f.cq = grpc_completion_queue_create(NULL);
 
-  grpc_resource_quota *resource_quota = grpc_resource_quota_create("fixture");
-  *sfd = grpc_iomgr_create_endpoint_pair("fixture", resource_quota, 1);
-  grpc_resource_quota_unref(resource_quota);
+  grpc_arg a[] = {{.key = GRPC_ARG_TCP_READ_CHUNK_SIZE,
+                   .type = GRPC_ARG_INTEGER,
+                   .value.integer = 1},
+                  {.key = GRPC_ARG_TCP_MIN_READ_CHUNK_SIZE,
+                   .type = GRPC_ARG_INTEGER,
+                   .value.integer = 1},
+                  {.key = GRPC_ARG_TCP_MAX_READ_CHUNK_SIZE,
+                   .type = GRPC_ARG_INTEGER,
+                   .value.integer = 1}};
+  grpc_channel_args args = {.num_args = GPR_ARRAY_SIZE(a), .args = a};
+  *sfd = grpc_iomgr_create_endpoint_pair("fixture", &args);
 
   return f;
 }
diff --git a/test/core/end2end/fuzzers/server_fuzzer_corpus/clusterfuzz-testcase-6312731374256128 b/test/core/end2end/fuzzers/server_fuzzer_corpus/clusterfuzz-testcase-6312731374256128
new file mode 100644
index 0000000000000000000000000000000000000000..4c6eb601ae342400eaccb7d4688136d152f2b06d
Binary files /dev/null and b/test/core/end2end/fuzzers/server_fuzzer_corpus/clusterfuzz-testcase-6312731374256128 differ
diff --git a/test/core/end2end/invalid_call_argument_test.c b/test/core/end2end/invalid_call_argument_test.c
index 2a9072570d39468eb7fedaa8cb471a63809e2466..bfd8e6fefa335174b8aee093498e44841479b7a3 100644
--- a/test/core/end2end/invalid_call_argument_test.c
+++ b/test/core/end2end/invalid_call_argument_test.c
@@ -31,6 +31,8 @@
  *
  */
 
+#include <grpc/impl/codegen/port_platform.h>
+
 #include <limits.h>
 #include <string.h>
 
diff --git a/test/core/end2end/tests/filter_call_init_fails.c b/test/core/end2end/tests/filter_call_init_fails.c
index ffeb2715c5b3e8af0bb0fa33026ddc9a53073e7e..0c4f0dd42fe2ba85e185a26d2ccbfa099656fa09 100644
--- a/test/core/end2end/tests/filter_call_init_fails.c
+++ b/test/core/end2end/tests/filter_call_init_fails.c
@@ -49,7 +49,9 @@
 
 enum { TIMEOUT = 200000 };
 
-static bool g_enable_filter = false;
+static bool g_enable_server_channel_filter = false;
+static bool g_enable_client_channel_filter = false;
+static bool g_enable_client_subchannel_filter = false;
 
 static void *tag(intptr_t t) { return (void *)t; }
 
@@ -105,9 +107,9 @@ static void end_test(grpc_end2end_test_fixture *f) {
   grpc_completion_queue_destroy(f->cq);
 }
 
-// Simple request via a server filter that always fails to initialize
-// the call.
-static void test_request(grpc_end2end_test_config config) {
+// Simple request via a SERVER_CHANNEL filter that always fails to
+// initialize the call.
+static void test_server_channel_filter(grpc_end2end_test_config config) {
   grpc_call *c;
   grpc_call *s;
   grpc_slice request_payload_slice =
@@ -201,6 +203,211 @@ static void test_request(grpc_end2end_test_config config) {
   config.tear_down_data(&f);
 }
 
+// Simple request via a CLIENT_CHANNEL or CLIENT_DIRECT_CHANNEL filter
+// that always fails to initialize the call.
+static void test_client_channel_filter(grpc_end2end_test_config config) {
+  grpc_call *c;
+  grpc_slice request_payload_slice =
+      grpc_slice_from_copied_string("hello world");
+  grpc_byte_buffer *request_payload =
+      grpc_raw_byte_buffer_create(&request_payload_slice, 1);
+  gpr_timespec deadline = five_seconds_from_now();
+  grpc_end2end_test_fixture f =
+      begin_test(config, "filter_call_init_fails", NULL, NULL);
+  cq_verifier *cqv = cq_verifier_create(f.cq);
+  grpc_op ops[6];
+  grpc_op *op;
+  grpc_metadata_array initial_metadata_recv;
+  grpc_metadata_array trailing_metadata_recv;
+  grpc_metadata_array request_metadata_recv;
+  grpc_byte_buffer *request_payload_recv = NULL;
+  grpc_call_details call_details;
+  grpc_status_code status;
+  grpc_call_error error;
+  grpc_slice details;
+
+  c = grpc_channel_create_call(
+      f.client, NULL, GRPC_PROPAGATE_DEFAULTS, f.cq,
+      grpc_slice_from_static_string("/foo"),
+      get_host_override_slice("foo.test.google.fr:1234", config), deadline,
+      NULL);
+  GPR_ASSERT(c);
+
+  grpc_metadata_array_init(&initial_metadata_recv);
+  grpc_metadata_array_init(&trailing_metadata_recv);
+  grpc_metadata_array_init(&request_metadata_recv);
+  grpc_call_details_init(&call_details);
+
+  memset(ops, 0, sizeof(ops));
+  op = ops;
+  op->op = GRPC_OP_SEND_INITIAL_METADATA;
+  op->data.send_initial_metadata.count = 0;
+  op->data.send_initial_metadata.metadata = NULL;
+  op->flags = 0;
+  op->reserved = NULL;
+  op++;
+  op->op = GRPC_OP_SEND_MESSAGE;
+  op->data.send_message.send_message = request_payload;
+  op->flags = 0;
+  op->reserved = NULL;
+  op++;
+  op->op = GRPC_OP_SEND_CLOSE_FROM_CLIENT;
+  op->flags = 0;
+  op->reserved = NULL;
+  op++;
+  op->op = GRPC_OP_RECV_INITIAL_METADATA;
+  op->data.recv_initial_metadata.recv_initial_metadata = &initial_metadata_recv;
+  op->flags = 0;
+  op->reserved = NULL;
+  op++;
+  op->op = GRPC_OP_RECV_STATUS_ON_CLIENT;
+  op->data.recv_status_on_client.trailing_metadata = &trailing_metadata_recv;
+  op->data.recv_status_on_client.status = &status;
+  op->data.recv_status_on_client.status_details = &details;
+  op->flags = 0;
+  op->reserved = NULL;
+  op++;
+  error = grpc_call_start_batch(c, ops, (size_t)(op - ops), tag(1), NULL);
+  GPR_ASSERT(GRPC_CALL_OK == error);
+
+  CQ_EXPECT_COMPLETION(cqv, tag(1), 1);
+  cq_verify(cqv);
+
+  GPR_ASSERT(status == GRPC_STATUS_PERMISSION_DENIED);
+  GPR_ASSERT(0 == grpc_slice_str_cmp(details, "access denied"));
+
+  grpc_slice_unref(details);
+  grpc_metadata_array_destroy(&initial_metadata_recv);
+  grpc_metadata_array_destroy(&trailing_metadata_recv);
+  grpc_metadata_array_destroy(&request_metadata_recv);
+  grpc_call_details_destroy(&call_details);
+
+  grpc_call_destroy(c);
+
+  cq_verifier_destroy(cqv);
+
+  grpc_byte_buffer_destroy(request_payload);
+  grpc_byte_buffer_destroy(request_payload_recv);
+
+  end_test(&f);
+  config.tear_down_data(&f);
+}
+
+// Simple request via a CLIENT_SUBCHANNEL filter that always fails to
+// initialize the call.
+static void test_client_subchannel_filter(grpc_end2end_test_config config) {
+  grpc_call *c;
+  grpc_slice request_payload_slice =
+      grpc_slice_from_copied_string("hello world");
+  grpc_byte_buffer *request_payload =
+      grpc_raw_byte_buffer_create(&request_payload_slice, 1);
+  gpr_timespec deadline = five_seconds_from_now();
+  grpc_end2end_test_fixture f =
+      begin_test(config, "filter_call_init_fails", NULL, NULL);
+  cq_verifier *cqv = cq_verifier_create(f.cq);
+  grpc_op ops[6];
+  grpc_op *op;
+  grpc_metadata_array initial_metadata_recv;
+  grpc_metadata_array trailing_metadata_recv;
+  grpc_metadata_array request_metadata_recv;
+  grpc_byte_buffer *request_payload_recv = NULL;
+  grpc_call_details call_details;
+  grpc_status_code status;
+  grpc_call_error error;
+  grpc_slice details;
+
+  c = grpc_channel_create_call(
+      f.client, NULL, GRPC_PROPAGATE_DEFAULTS, f.cq,
+      grpc_slice_from_static_string("/foo"),
+      get_host_override_slice("foo.test.google.fr:1234", config), deadline,
+      NULL);
+  GPR_ASSERT(c);
+
+  grpc_metadata_array_init(&initial_metadata_recv);
+  grpc_metadata_array_init(&trailing_metadata_recv);
+  grpc_metadata_array_init(&request_metadata_recv);
+  grpc_call_details_init(&call_details);
+
+  memset(ops, 0, sizeof(ops));
+  op = ops;
+  op->op = GRPC_OP_SEND_INITIAL_METADATA;
+  op->data.send_initial_metadata.count = 0;
+  op->data.send_initial_metadata.metadata = NULL;
+  op->flags = 0;
+  op->reserved = NULL;
+  op++;
+  op->op = GRPC_OP_SEND_MESSAGE;
+  op->data.send_message.send_message = request_payload;
+  op->flags = 0;
+  op->reserved = NULL;
+  op++;
+  op->op = GRPC_OP_SEND_CLOSE_FROM_CLIENT;
+  op->flags = 0;
+  op->reserved = NULL;
+  op++;
+  op->op = GRPC_OP_RECV_INITIAL_METADATA;
+  op->data.recv_initial_metadata.recv_initial_metadata = &initial_metadata_recv;
+  op->flags = 0;
+  op->reserved = NULL;
+  op++;
+  op->op = GRPC_OP_RECV_STATUS_ON_CLIENT;
+  op->data.recv_status_on_client.trailing_metadata = &trailing_metadata_recv;
+  op->data.recv_status_on_client.status = &status;
+  op->data.recv_status_on_client.status_details = &details;
+  op->flags = 0;
+  op->reserved = NULL;
+  op++;
+
+  error = grpc_call_start_batch(c, ops, (size_t)(op - ops), tag(1), NULL);
+  GPR_ASSERT(GRPC_CALL_OK == error);
+
+  CQ_EXPECT_COMPLETION(cqv, tag(1), 1);
+  cq_verify(cqv);
+
+  GPR_ASSERT(status == GRPC_STATUS_PERMISSION_DENIED);
+  GPR_ASSERT(0 == grpc_slice_str_cmp(details, "access denied"));
+
+  // Reset and create a new call.  (The first call uses a different code
+  // path in client_channel.c than subsequent calls on the same channel,
+  // and we need to test both.)
+  grpc_call_destroy(c);
+  status = GRPC_STATUS_OK;
+  grpc_slice_unref(details);
+  details = grpc_empty_slice();
+
+  c = grpc_channel_create_call(
+      f.client, NULL, GRPC_PROPAGATE_DEFAULTS, f.cq,
+      grpc_slice_from_static_string("/foo"),
+      get_host_override_slice("foo.test.google.fr:1234", config), deadline,
+      NULL);
+  GPR_ASSERT(c);
+
+  error = grpc_call_start_batch(c, ops, (size_t)(op - ops), tag(2), NULL);
+  GPR_ASSERT(GRPC_CALL_OK == error);
+
+  CQ_EXPECT_COMPLETION(cqv, tag(2), 1);
+  cq_verify(cqv);
+
+  GPR_ASSERT(status == GRPC_STATUS_PERMISSION_DENIED);
+  GPR_ASSERT(0 == grpc_slice_str_cmp(details, "access denied"));
+
+  grpc_slice_unref(details);
+  grpc_metadata_array_destroy(&initial_metadata_recv);
+  grpc_metadata_array_destroy(&trailing_metadata_recv);
+  grpc_metadata_array_destroy(&request_metadata_recv);
+  grpc_call_details_destroy(&call_details);
+
+  grpc_call_destroy(c);
+
+  cq_verifier_destroy(cqv);
+
+  grpc_byte_buffer_destroy(request_payload);
+  grpc_byte_buffer_destroy(request_payload_recv);
+
+  end_test(&f);
+  config.tear_down_data(&f);
+}
+
 /*******************************************************************************
  * Test filter - always fails to initialize a call
  */
@@ -244,9 +451,30 @@ static const grpc_channel_filter test_filter = {
  * Registration
  */
 
-static bool maybe_add_filter(grpc_exec_ctx *exec_ctx,
-                             grpc_channel_stack_builder *builder, void *arg) {
-  if (g_enable_filter) {
+static bool maybe_add_server_channel_filter(grpc_exec_ctx *exec_ctx,
+                                            grpc_channel_stack_builder *builder,
+                                            void *arg) {
+  if (g_enable_server_channel_filter) {
+    // Want to add the filter as close to the end as possible, to make
+    // sure that all of the filters work well together.  However, we
+    // can't add it at the very end, because the connected channel filter
+    // must be the last one.  So we add it right before the last one.
+    grpc_channel_stack_builder_iterator *it =
+        grpc_channel_stack_builder_create_iterator_at_last(builder);
+    GPR_ASSERT(grpc_channel_stack_builder_move_prev(it));
+    const bool retval = grpc_channel_stack_builder_add_filter_before(
+        it, &test_filter, NULL, NULL);
+    grpc_channel_stack_builder_iterator_destroy(it);
+    return retval;
+  } else {
+    return true;
+  }
+}
+
+static bool maybe_add_client_channel_filter(grpc_exec_ctx *exec_ctx,
+                                            grpc_channel_stack_builder *builder,
+                                            void *arg) {
+  if (g_enable_client_channel_filter) {
     // Want to add the filter as close to the end as possible, to make
     // sure that all of the filters work well together.  However, we
     // can't add it at the very end, because the connected channel filter
@@ -263,17 +491,53 @@ static bool maybe_add_filter(grpc_exec_ctx *exec_ctx,
   }
 }
 
+static bool maybe_add_client_subchannel_filter(
+    grpc_exec_ctx *exec_ctx, grpc_channel_stack_builder *builder, void *arg) {
+  if (g_enable_client_subchannel_filter) {
+    // Want to add the filter as close to the end as possible, to make
+    // sure that all of the filters work well together.  However, we
+    // can't add it at the very end, because the client channel filter
+    // must be the last one.  So we add it right before the last one.
+    grpc_channel_stack_builder_iterator *it =
+        grpc_channel_stack_builder_create_iterator_at_last(builder);
+    GPR_ASSERT(grpc_channel_stack_builder_move_prev(it));
+    const bool retval = grpc_channel_stack_builder_add_filter_before(
+        it, &test_filter, NULL, NULL);
+    grpc_channel_stack_builder_iterator_destroy(it);
+    return retval;
+  } else {
+    return true;
+  }
+}
+
 static void init_plugin(void) {
   grpc_channel_init_register_stage(GRPC_SERVER_CHANNEL, INT_MAX,
-                                   maybe_add_filter, NULL);
+                                   maybe_add_server_channel_filter, NULL);
+  grpc_channel_init_register_stage(GRPC_CLIENT_CHANNEL, INT_MAX,
+                                   maybe_add_client_channel_filter, NULL);
+  grpc_channel_init_register_stage(GRPC_CLIENT_SUBCHANNEL, INT_MAX,
+                                   maybe_add_client_subchannel_filter, NULL);
+  grpc_channel_init_register_stage(GRPC_CLIENT_DIRECT_CHANNEL, INT_MAX,
+                                   maybe_add_client_channel_filter, NULL);
 }
 
 static void destroy_plugin(void) {}
 
 void filter_call_init_fails(grpc_end2end_test_config config) {
-  g_enable_filter = true;
-  test_request(config);
-  g_enable_filter = false;
+  gpr_log(GPR_INFO, "Testing SERVER_CHANNEL filter.");
+  g_enable_server_channel_filter = true;
+  test_server_channel_filter(config);
+  g_enable_server_channel_filter = false;
+  gpr_log(GPR_INFO, "Testing CLIENT_CHANNEL / CLIENT_DIRECT_CHANNEL filter.");
+  g_enable_client_channel_filter = true;
+  test_client_channel_filter(config);
+  g_enable_client_channel_filter = false;
+  if (config.feature_mask & FEATURE_MASK_SUPPORTS_CLIENT_CHANNEL) {
+    gpr_log(GPR_INFO, "Testing CLIENT_SUBCHANNEL filter.");
+    g_enable_client_subchannel_filter = true;
+    test_client_subchannel_filter(config);
+    g_enable_client_subchannel_filter = false;
+  }
 }
 
 void filter_call_init_fails_pre_init(void) {
diff --git a/test/core/end2end/tests/max_connection_idle.c b/test/core/end2end/tests/max_connection_idle.c
index c0984e4d14e1c332a21ac1c56b2d1dfdc4412fa0..98bc08c6d5a559ecc9622a82f7413ef07f02a5e8 100644
--- a/test/core/end2end/tests/max_connection_idle.c
+++ b/test/core/end2end/tests/max_connection_idle.c
@@ -36,6 +36,7 @@
 #include <limits.h>
 #include <string.h>
 
+#include <grpc/support/alloc.h>
 #include <grpc/support/log.h>
 #include <grpc/support/sync.h>
 #include <grpc/support/time.h>
@@ -48,6 +49,138 @@
 
 static void *tag(intptr_t t) { return (void *)t; }
 
+static void drain_cq(grpc_completion_queue *cq) {
+  grpc_event ev;
+  do {
+    ev = grpc_completion_queue_next(cq, grpc_timeout_seconds_to_deadline(5),
+                                    NULL);
+  } while (ev.type != GRPC_QUEUE_SHUTDOWN);
+}
+
+static void simple_request_body(grpc_end2end_test_config config,
+                                grpc_end2end_test_fixture *f) {
+  grpc_call *c;
+  grpc_call *s;
+  cq_verifier *cqv = cq_verifier_create(f->cq);
+  grpc_op ops[6];
+  grpc_op *op;
+  grpc_metadata_array initial_metadata_recv;
+  grpc_metadata_array trailing_metadata_recv;
+  grpc_metadata_array request_metadata_recv;
+  grpc_call_details call_details;
+  grpc_status_code status;
+  grpc_call_error error;
+  grpc_slice details;
+  int was_cancelled = 2;
+  char *peer;
+
+  gpr_timespec deadline = grpc_timeout_seconds_to_deadline(5);
+  c = grpc_channel_create_call(
+      f->client, NULL, GRPC_PROPAGATE_DEFAULTS, f->cq,
+      grpc_slice_from_static_string("/foo"),
+      get_host_override_slice("foo.test.google.fr:1234", config), deadline,
+      NULL);
+  GPR_ASSERT(c);
+
+  peer = grpc_call_get_peer(c);
+  GPR_ASSERT(peer != NULL);
+  gpr_log(GPR_DEBUG, "client_peer_before_call=%s", peer);
+  gpr_free(peer);
+
+  grpc_metadata_array_init(&initial_metadata_recv);
+  grpc_metadata_array_init(&trailing_metadata_recv);
+  grpc_metadata_array_init(&request_metadata_recv);
+  grpc_call_details_init(&call_details);
+
+  memset(ops, 0, sizeof(ops));
+  op = ops;
+  op->op = GRPC_OP_SEND_INITIAL_METADATA;
+  op->data.send_initial_metadata.count = 0;
+  op->flags = 0;
+  op->reserved = NULL;
+  op++;
+  op->op = GRPC_OP_SEND_CLOSE_FROM_CLIENT;
+  op->flags = 0;
+  op->reserved = NULL;
+  op++;
+  op->op = GRPC_OP_RECV_INITIAL_METADATA;
+  op->data.recv_initial_metadata.recv_initial_metadata = &initial_metadata_recv;
+  op->flags = 0;
+  op->reserved = NULL;
+  op++;
+  op->op = GRPC_OP_RECV_STATUS_ON_CLIENT;
+  op->data.recv_status_on_client.trailing_metadata = &trailing_metadata_recv;
+  op->data.recv_status_on_client.status = &status;
+  op->data.recv_status_on_client.status_details = &details;
+  op->flags = 0;
+  op->reserved = NULL;
+  op++;
+  error = grpc_call_start_batch(c, ops, (size_t)(op - ops), tag(1), NULL);
+  GPR_ASSERT(GRPC_CALL_OK == error);
+
+  error =
+      grpc_server_request_call(f->server, &s, &call_details,
+                               &request_metadata_recv, f->cq, f->cq, tag(101));
+  GPR_ASSERT(GRPC_CALL_OK == error);
+  CQ_EXPECT_COMPLETION(cqv, tag(101), 1);
+  cq_verify(cqv);
+
+  peer = grpc_call_get_peer(s);
+  GPR_ASSERT(peer != NULL);
+  gpr_log(GPR_DEBUG, "server_peer=%s", peer);
+  gpr_free(peer);
+  peer = grpc_call_get_peer(c);
+  GPR_ASSERT(peer != NULL);
+  gpr_log(GPR_DEBUG, "client_peer=%s", peer);
+  gpr_free(peer);
+
+  memset(ops, 0, sizeof(ops));
+  op = ops;
+  op->op = GRPC_OP_SEND_INITIAL_METADATA;
+  op->data.send_initial_metadata.count = 0;
+  op->flags = 0;
+  op->reserved = NULL;
+  op++;
+  op->op = GRPC_OP_SEND_STATUS_FROM_SERVER;
+  op->data.send_status_from_server.trailing_metadata_count = 0;
+  op->data.send_status_from_server.status = GRPC_STATUS_UNIMPLEMENTED;
+  grpc_slice status_details = grpc_slice_from_static_string("xyz");
+  op->data.send_status_from_server.status_details = &status_details;
+  op->flags = 0;
+  op->reserved = NULL;
+  op++;
+  op->op = GRPC_OP_RECV_CLOSE_ON_SERVER;
+  op->data.recv_close_on_server.cancelled = &was_cancelled;
+  op->flags = 0;
+  op->reserved = NULL;
+  op++;
+  error = grpc_call_start_batch(s, ops, (size_t)(op - ops), tag(102), NULL);
+  GPR_ASSERT(GRPC_CALL_OK == error);
+
+  CQ_EXPECT_COMPLETION(cqv, tag(102), 1);
+  CQ_EXPECT_COMPLETION(cqv, tag(1), 1);
+  cq_verify(cqv);
+
+  GPR_ASSERT(status == GRPC_STATUS_UNIMPLEMENTED);
+  GPR_ASSERT(0 == grpc_slice_str_cmp(details, "xyz"));
+  GPR_ASSERT(0 == grpc_slice_str_cmp(call_details.method, "/foo"));
+  validate_host_override_string("foo.test.google.fr:1234", call_details.host,
+                                config);
+  GPR_ASSERT(0 == call_details.flags);
+  GPR_ASSERT(was_cancelled == 1);
+
+  grpc_slice_unref(details);
+  grpc_metadata_array_destroy(&initial_metadata_recv);
+  grpc_metadata_array_destroy(&trailing_metadata_recv);
+  grpc_metadata_array_destroy(&request_metadata_recv);
+  grpc_call_details_destroy(&call_details);
+
+  grpc_call_destroy(c);
+  grpc_call_destroy(s);
+
+  cq_verifier_destroy(cqv);
+}
+
 static void test_max_connection_idle(grpc_end2end_test_config config) {
   grpc_end2end_test_fixture f = config.create_fixture(NULL, NULL);
   grpc_connectivity_state state = GRPC_CHANNEL_IDLE;
@@ -86,6 +219,9 @@ static void test_max_connection_idle(grpc_end2end_test_config config) {
                state == GRPC_CHANNEL_TRANSIENT_FAILURE);
   }
 
+  /* Use a simple request to cancel and reset the max idle timer */
+  simple_request_body(config, &f);
+
   /* wait for the channel to reach its maximum idle time */
   grpc_channel_watch_connectivity_state(
       f.client, GRPC_CHANNEL_READY,
@@ -104,6 +240,7 @@ static void test_max_connection_idle(grpc_end2end_test_config config) {
   grpc_server_destroy(f.server);
   grpc_channel_destroy(f.client);
   grpc_completion_queue_shutdown(f.cq);
+  drain_cq(f.cq);
   grpc_completion_queue_destroy(f.cq);
   config.tear_down_data(&f);
 
diff --git a/test/core/iomgr/endpoint_pair_test.c b/test/core/iomgr/endpoint_pair_test.c
index 4b98ef257e5ab1a8a479d08063b1e35268c9d25b..c8a60776b9c7b9ae5a72c1bffad25d558459f5a9 100644
--- a/test/core/iomgr/endpoint_pair_test.c
+++ b/test/core/iomgr/endpoint_pair_test.c
@@ -49,11 +49,11 @@ static grpc_endpoint_test_fixture create_fixture_endpoint_pair(
     size_t slice_size) {
   grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
   grpc_endpoint_test_fixture f;
-  grpc_resource_quota *resource_quota =
-      grpc_resource_quota_create("endpoint_pair_test");
-  grpc_endpoint_pair p =
-      grpc_iomgr_create_endpoint_pair("test", resource_quota, slice_size);
-  grpc_resource_quota_unref(resource_quota);
+  grpc_arg a[] = {{.key = GRPC_ARG_TCP_READ_CHUNK_SIZE,
+                   .type = GRPC_ARG_INTEGER,
+                   .value.integer = (int)slice_size}};
+  grpc_channel_args args = {.num_args = GPR_ARRAY_SIZE(a), .args = a};
+  grpc_endpoint_pair p = grpc_iomgr_create_endpoint_pair("test", &args);
 
   f.client_ep = p.client;
   f.server_ep = p.server;
diff --git a/test/core/iomgr/error_test.c b/test/core/iomgr/error_test.c
index 5c60a4ddb85a84535045f1ef10bba300b3a8f7cb..607dbeea3e7b8eedffaf3326cda29a33ff13ff15 100644
--- a/test/core/iomgr/error_test.c
+++ b/test/core/iomgr/error_test.c
@@ -182,8 +182,6 @@ static void print_error_string_reference() {
   grpc_error* parent =
       GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING("Parent", children, 2);
 
-  gpr_log(GPR_DEBUG, "%s", grpc_error_string(parent));
-
   for (size_t i = 0; i < 2; ++i) {
     GRPC_ERROR_UNREF(children[i]);
   }
@@ -216,6 +214,33 @@ static void test_special() {
   GRPC_ERROR_UNREF(error);
 }
 
+static void test_overflow() {
+  grpc_error* error = GRPC_ERROR_CREATE_FROM_STATIC_STRING("Overflow");
+
+  for (size_t i = 0; i < 150; ++i) {
+    error = grpc_error_add_child(error,
+                                 GRPC_ERROR_CREATE_FROM_STATIC_STRING("Child"));
+  }
+
+  error = grpc_error_set_int(error, GRPC_ERROR_INT_HTTP2_ERROR, 5);
+  error =
+      grpc_error_set_str(error, GRPC_ERROR_STR_GRPC_MESSAGE,
+                         grpc_slice_from_static_string("message for child 2"));
+  error = grpc_error_set_int(error, GRPC_ERROR_INT_GRPC_STATUS, 5);
+
+  intptr_t i;
+  GPR_ASSERT(grpc_error_get_int(error, GRPC_ERROR_INT_HTTP2_ERROR, &i));
+  GPR_ASSERT(i == 5);
+  GPR_ASSERT(!grpc_error_get_int(error, GRPC_ERROR_INT_GRPC_STATUS, &i));
+
+  error = grpc_error_set_int(error, GRPC_ERROR_INT_HTTP2_ERROR, 10);
+  GPR_ASSERT(grpc_error_get_int(error, GRPC_ERROR_INT_HTTP2_ERROR, &i));
+  GPR_ASSERT(i == 10);
+
+  GRPC_ERROR_UNREF(error);
+  ;
+}
+
 int main(int argc, char** argv) {
   grpc_test_init(argc, argv);
   grpc_init();
@@ -228,6 +253,7 @@ int main(int argc, char** argv) {
   test_create_referencing();
   test_create_referencing_many();
   test_special();
+  test_overflow();
   grpc_shutdown();
 
   return 0;
diff --git a/test/core/iomgr/ev_epoll_linux_test.c b/test/core/iomgr/ev_epoll_linux_test.c
index 5f8124aedaef672507caedfc40e467037e00058c..0856023b14f6878483836515327609c64399cf51 100644
--- a/test/core/iomgr/ev_epoll_linux_test.c
+++ b/test/core/iomgr/ev_epoll_linux_test.c
@@ -346,11 +346,13 @@ static void test_threading_wakeup(grpc_exec_ctx *exec_ctx, void *arg,
   threading_shared *shared = arg;
   ++shared->wakeups;
   ++thread_wakeups;
-  GPR_ASSERT(GRPC_LOG_IF_ERROR(
-      "consume_wakeup", grpc_wakeup_fd_consume_wakeup(shared->wakeup_fd)));
-  grpc_fd_notify_on_read(exec_ctx, shared->wakeup_desc, &shared->on_wakeup);
-  GPR_ASSERT(GRPC_LOG_IF_ERROR("wakeup_next",
-                               grpc_wakeup_fd_wakeup(shared->wakeup_fd)));
+  if (error == GRPC_ERROR_NONE) {
+    GPR_ASSERT(GRPC_LOG_IF_ERROR(
+        "consume_wakeup", grpc_wakeup_fd_consume_wakeup(shared->wakeup_fd)));
+    grpc_fd_notify_on_read(exec_ctx, shared->wakeup_desc, &shared->on_wakeup);
+    GPR_ASSERT(GRPC_LOG_IF_ERROR("wakeup_next",
+                                 grpc_wakeup_fd_wakeup(shared->wakeup_fd)));
+  }
 }
 
 static void test_threading(void) {
@@ -387,6 +389,7 @@ static void test_threading(void) {
   grpc_wakeup_fd_destroy(&fd);
   {
     grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+    grpc_fd_shutdown(&exec_ctx, shared.wakeup_desc, GRPC_ERROR_CANCELLED);
     grpc_fd_orphan(&exec_ctx, shared.wakeup_desc, NULL, NULL, "done");
     grpc_pollset_shutdown(&exec_ctx, shared.pollset,
                           grpc_closure_create(destroy_pollset, shared.pollset,
diff --git a/test/core/iomgr/fd_conservation_posix_test.c b/test/core/iomgr/fd_conservation_posix_test.c
index 3dffa02c3c809b3790b375b5f28d92943c7e084a..6ac322bb01458f8532dd955f14bc50958e4a6384 100644
--- a/test/core/iomgr/fd_conservation_posix_test.c
+++ b/test/core/iomgr/fd_conservation_posix_test.c
@@ -57,7 +57,7 @@ int main(int argc, char **argv) {
 
   for (i = 0; i < 100; i++) {
     grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
-    p = grpc_iomgr_create_endpoint_pair("test", resource_quota, 1);
+    p = grpc_iomgr_create_endpoint_pair("test", NULL);
     grpc_endpoint_destroy(&exec_ctx, p.client);
     grpc_endpoint_destroy(&exec_ctx, p.server);
     grpc_exec_ctx_finish(&exec_ctx);
diff --git a/test/core/iomgr/sockaddr_utils_test.c b/test/core/iomgr/sockaddr_utils_test.c
index 70a6c323e5767594c36f38648e189ef9140b8c70..09c514c8e6ffa60b2f0345f6e65376d1a72a260f 100644
--- a/test/core/iomgr/sockaddr_utils_test.c
+++ b/test/core/iomgr/sockaddr_utils_test.c
@@ -254,8 +254,6 @@ static void test_sockaddr_to_string(void) {
   expect_sockaddr_str("(sockaddr family=123)", &dummy, 0);
   expect_sockaddr_str("(sockaddr family=123)", &dummy, 1);
   GPR_ASSERT(grpc_sockaddr_to_uri(&dummy) == NULL);
-
-  GPR_ASSERT(errno == 0x7EADBEEF);
 }
 
 static void test_sockaddr_set_get_port(void) {
diff --git a/test/core/iomgr/tcp_posix_test.c b/test/core/iomgr/tcp_posix_test.c
index 5a55be888fe89b72e23a475211e4a7b58f099f87..2c53a003d23a83dd86a57866c6ca9e1c8ab2ae47 100644
--- a/test/core/iomgr/tcp_posix_test.c
+++ b/test/core/iomgr/tcp_posix_test.c
@@ -183,10 +183,12 @@ static void read_test(size_t num_bytes, size_t slice_size) {
 
   create_sockets(sv);
 
-  grpc_resource_quota *resource_quota = grpc_resource_quota_create("read_test");
-  ep = grpc_tcp_create(grpc_fd_create(sv[1], "read_test"), resource_quota,
-                       slice_size, "test");
-  grpc_resource_quota_unref_internal(&exec_ctx, resource_quota);
+  grpc_arg a[] = {{.key = GRPC_ARG_TCP_READ_CHUNK_SIZE,
+                   .type = GRPC_ARG_INTEGER,
+                   .value.integer = (int)slice_size}};
+  grpc_channel_args args = {.num_args = GPR_ARRAY_SIZE(a), .args = a};
+  ep = grpc_tcp_create(&exec_ctx, grpc_fd_create(sv[1], "read_test"), &args,
+                       "test");
   grpc_endpoint_add_to_pollset(&exec_ctx, ep, g_pollset);
 
   written_bytes = fill_socket_partial(sv[0], num_bytes);
@@ -233,11 +235,12 @@ static void large_read_test(size_t slice_size) {
 
   create_sockets(sv);
 
-  grpc_resource_quota *resource_quota =
-      grpc_resource_quota_create("large_read_test");
-  ep = grpc_tcp_create(grpc_fd_create(sv[1], "large_read_test"), resource_quota,
-                       slice_size, "test");
-  grpc_resource_quota_unref_internal(&exec_ctx, resource_quota);
+  grpc_arg a[] = {{.key = GRPC_ARG_TCP_READ_CHUNK_SIZE,
+                   .type = GRPC_ARG_INTEGER,
+                   .value.integer = (int)slice_size}};
+  grpc_channel_args args = {.num_args = GPR_ARRAY_SIZE(a), .args = a};
+  ep = grpc_tcp_create(&exec_ctx, grpc_fd_create(sv[1], "large_read_test"),
+                       &args, "test");
   grpc_endpoint_add_to_pollset(&exec_ctx, ep, g_pollset);
 
   written_bytes = fill_socket(sv[0]);
@@ -372,11 +375,12 @@ static void write_test(size_t num_bytes, size_t slice_size) {
 
   create_sockets(sv);
 
-  grpc_resource_quota *resource_quota =
-      grpc_resource_quota_create("write_test");
-  ep = grpc_tcp_create(grpc_fd_create(sv[1], "write_test"), resource_quota,
-                       GRPC_TCP_DEFAULT_READ_SLICE_SIZE, "test");
-  grpc_resource_quota_unref_internal(&exec_ctx, resource_quota);
+  grpc_arg a[] = {{.key = GRPC_ARG_TCP_READ_CHUNK_SIZE,
+                   .type = GRPC_ARG_INTEGER,
+                   .value.integer = (int)slice_size}};
+  grpc_channel_args args = {.num_args = GPR_ARRAY_SIZE(a), .args = a};
+  ep = grpc_tcp_create(&exec_ctx, grpc_fd_create(sv[1], "write_test"), &args,
+                       "test");
   grpc_endpoint_add_to_pollset(&exec_ctx, ep, g_pollset);
 
   state.ep = ep;
@@ -441,12 +445,13 @@ static void release_fd_test(size_t num_bytes, size_t slice_size) {
 
   create_sockets(sv);
 
-  grpc_resource_quota *resource_quota =
-      grpc_resource_quota_create("release_fd_test");
-  ep = grpc_tcp_create(grpc_fd_create(sv[1], "read_test"), resource_quota,
-                       slice_size, "test");
+  grpc_arg a[] = {{.key = GRPC_ARG_TCP_READ_CHUNK_SIZE,
+                   .type = GRPC_ARG_INTEGER,
+                   .value.integer = (int)slice_size}};
+  grpc_channel_args args = {.num_args = GPR_ARRAY_SIZE(a), .args = a};
+  ep = grpc_tcp_create(&exec_ctx, grpc_fd_create(sv[1], "read_test"), &args,
+                       "test");
   GPR_ASSERT(grpc_tcp_fd(ep) == sv[1] && sv[1] >= 0);
-  grpc_resource_quota_unref_internal(&exec_ctx, resource_quota);
   grpc_endpoint_add_to_pollset(&exec_ctx, ep, g_pollset);
 
   written_bytes = fill_socket_partial(sv[0], num_bytes);
@@ -534,10 +539,14 @@ static grpc_endpoint_test_fixture create_fixture_tcp_socketpair(
   create_sockets(sv);
   grpc_resource_quota *resource_quota =
       grpc_resource_quota_create("tcp_posix_test_socketpair");
-  f.client_ep = grpc_tcp_create(grpc_fd_create(sv[0], "fixture:client"),
-                                resource_quota, slice_size, "test");
-  f.server_ep = grpc_tcp_create(grpc_fd_create(sv[1], "fixture:server"),
-                                resource_quota, slice_size, "test");
+  grpc_arg a[] = {{.key = GRPC_ARG_TCP_READ_CHUNK_SIZE,
+                   .type = GRPC_ARG_INTEGER,
+                   .value.integer = (int)slice_size}};
+  grpc_channel_args args = {.num_args = GPR_ARRAY_SIZE(a), .args = a};
+  f.client_ep = grpc_tcp_create(
+      &exec_ctx, grpc_fd_create(sv[0], "fixture:client"), &args, "test");
+  f.server_ep = grpc_tcp_create(
+      &exec_ctx, grpc_fd_create(sv[1], "fixture:server"), &args, "test");
   grpc_resource_quota_unref_internal(&exec_ctx, resource_quota);
   grpc_endpoint_add_to_pollset(&exec_ctx, f.client_ep, g_pollset);
   grpc_endpoint_add_to_pollset(&exec_ctx, f.server_ep, g_pollset);
diff --git a/test/core/security/credentials_test.c b/test/core/security/credentials_test.c
index c0933c64a6884e31bb622f28455c2e7387c1693c..9bdce71ba0cd55d0017c72b9d14dc13b292f6b84 100644
--- a/test/core/security/credentials_test.c
+++ b/test/core/security/credentials_test.c
@@ -582,7 +582,7 @@ static void on_oauth2_creds_get_metadata_failure(
 static void validate_compute_engine_http_request(
     const grpc_httpcli_request *request) {
   GPR_ASSERT(request->handshaker != &grpc_httpcli_ssl);
-  GPR_ASSERT(strcmp(request->host, "metadata") == 0);
+  GPR_ASSERT(strcmp(request->host, "metadata.google.internal") == 0);
   GPR_ASSERT(
       strcmp(request->http.path,
              "/computeMetadata/v1/instance/service-accounts/default/token") ==
diff --git a/test/core/security/secure_endpoint_test.c b/test/core/security/secure_endpoint_test.c
index 8f11f98a9cd9ec823dcc75f3b298f01f411664bb..71d8057ac3140b74d3c6712ccb835675b74e4588 100644
--- a/test/core/security/secure_endpoint_test.c
+++ b/test/core/security/secure_endpoint_test.c
@@ -39,6 +39,7 @@
 #include <grpc/grpc.h>
 #include <grpc/support/alloc.h>
 #include <grpc/support/log.h>
+#include <grpc/support/useful.h>
 #include "src/core/lib/iomgr/endpoint_pair.h"
 #include "src/core/lib/iomgr/iomgr.h"
 #include "src/core/lib/security/transport/secure_endpoint.h"
@@ -57,10 +58,11 @@ static grpc_endpoint_test_fixture secure_endpoint_create_fixture_tcp_socketpair(
   grpc_endpoint_test_fixture f;
   grpc_endpoint_pair tcp;
 
-  grpc_resource_quota *resource_quota =
-      grpc_resource_quota_create("secure_endpoint_test");
-  tcp = grpc_iomgr_create_endpoint_pair("fixture", resource_quota, slice_size);
-  grpc_resource_quota_unref_internal(&exec_ctx, resource_quota);
+  grpc_arg a[] = {{.key = GRPC_ARG_TCP_READ_CHUNK_SIZE,
+                   .type = GRPC_ARG_INTEGER,
+                   .value.integer = (int)slice_size}};
+  grpc_channel_args args = {.num_args = GPR_ARRAY_SIZE(a), .args = a};
+  tcp = grpc_iomgr_create_endpoint_pair("fixture", &args);
   grpc_endpoint_add_to_pollset(&exec_ctx, tcp.client, g_pollset);
   grpc_endpoint_add_to_pollset(&exec_ctx, tcp.server, g_pollset);
 
diff --git a/test/cpp/end2end/end2end_test.cc b/test/cpp/end2end/end2end_test.cc
index d3a83b188f944c3377772f7f2cd07ec6a66a8179..df71777e4bdb2e65ce4f67af036c1df8e41104e1 100644
--- a/test/cpp/end2end/end2end_test.cc
+++ b/test/cpp/end2end/end2end_test.cc
@@ -1130,6 +1130,39 @@ TEST_P(End2endTest, BinaryTrailerTest) {
   EXPECT_TRUE(returned_info.ParseFromString(ToString(iter->second)));
 }
 
+TEST_P(End2endTest, ExpectErrorTest) {
+  ResetStub();
+
+  std::vector<ErrorStatus> expected_status;
+  expected_status.emplace_back();
+  expected_status.back().set_code(13);  // INTERNAL
+  expected_status.back().set_error_message("text error message");
+  expected_status.back().set_binary_error_details("text error details");
+  expected_status.emplace_back();
+  expected_status.back().set_code(13);  // INTERNAL
+  expected_status.back().set_error_message("text error message");
+  expected_status.back().set_binary_error_details(
+      "\x0\x1\x2\x3\x4\x5\x6\x8\x9\xA\xB");
+
+  for (auto iter = expected_status.begin(); iter != expected_status.end();
+       ++iter) {
+    EchoRequest request;
+    EchoResponse response;
+    ClientContext context;
+    request.set_message("Hello");
+    auto* error = request.mutable_param()->mutable_expected_error();
+    error->set_code(iter->code());
+    error->set_error_message(iter->error_message());
+    error->set_binary_error_details(iter->binary_error_details());
+
+    Status s = stub_->Echo(&context, request, &response);
+    EXPECT_FALSE(s.ok());
+    EXPECT_EQ(iter->code(), s.error_code());
+    EXPECT_EQ(iter->error_message(), s.error_message());
+    EXPECT_EQ(iter->binary_error_details(), s.error_details());
+  }
+}
+
 //////////////////////////////////////////////////////////////////////////
 // Test with and without a proxy.
 class ProxyEnd2endTest : public End2endTest {
diff --git a/test/cpp/end2end/test_service_impl.cc b/test/cpp/end2end/test_service_impl.cc
index 11729c425cda646d799016ae057e4bc61ab5c487..b473dd1f52ee5091d84dc55b0f910d7ded5f6a3d 100644
--- a/test/cpp/end2end/test_service_impl.cc
+++ b/test/cpp/end2end/test_service_impl.cc
@@ -92,6 +92,11 @@ Status TestServiceImpl::Echo(ServerContext* context, const EchoRequest* request,
     gpr_log(GPR_ERROR, "The request should not reach application handler.");
     GPR_ASSERT(0);
   }
+  if (request->has_param() && request->param().has_expected_error()) {
+    const auto& error = request->param().expected_error();
+    return Status(static_cast<StatusCode>(error.code()), error.error_message(),
+                  error.binary_error_details());
+  }
   int server_try_cancel = GetIntValueFromMetadata(
       kServerTryCancelRequest, context->client_metadata(), DO_NOT_CANCEL);
   if (server_try_cancel > DO_NOT_CANCEL) {
diff --git a/test/cpp/microbenchmarks/BUILD b/test/cpp/microbenchmarks/BUILD
index 38619666dcb3f36e1740c58814af4a8e52e952c8..cae3fa1a1461bcb30837cdcf7fb9a81b8e0f5ebc 100644
--- a/test/cpp/microbenchmarks/BUILD
+++ b/test/cpp/microbenchmarks/BUILD
@@ -32,16 +32,25 @@ licenses(["notice"])  # 3-clause BSD
 cc_test(
     name = "noop-benchmark",
     srcs = ["noop-benchmark.cc"],
-    deps = ["//external:benchmark"],
     linkopts = ["-pthread"],
+    deps = ["//external:benchmark"],
 )
 
 cc_library(
     name = "helpers",
     srcs = ["helpers.cc"],
-    hdrs = ["helpers.h", "fullstack_fixtures.h", "fullstack_context_mutators.h"],
-    deps = ["//:grpc++", "//external:benchmark", "//test/core/util:grpc_test_util", "//src/proto/grpc/testing:echo_proto"],
+    hdrs = [
+        "fullstack_context_mutators.h",
+        "fullstack_fixtures.h",
+        "helpers.h",
+    ],
     linkopts = ["-pthread"],
+    deps = [
+        "//:grpc++",
+        "//external:benchmark",
+        "//src/proto/grpc/testing:echo_proto",
+        "//test/core/util:grpc_test_util",
+    ],
 )
 
 cc_test(
@@ -56,6 +65,12 @@ cc_test(
     deps = [":helpers"],
 )
 
+cc_test(
+    name = "bm_cq_multiple_threads",
+    srcs = ["bm_cq_multiple_threads.cc"],
+    deps = [":helpers"],
+)
+
 cc_test(
     name = "bm_error",
     srcs = ["bm_error.cc"],
@@ -66,8 +81,8 @@ cc_test(
     name = "bm_fullstack_streaming_ping_pong",
     srcs = ["bm_fullstack_streaming_ping_pong.cc"],
     deps = [":helpers"],
+)
 
-    )
 cc_test(
     name = "bm_fullstack_streaming_pump",
     srcs = ["bm_fullstack_streaming_pump.cc"],
diff --git a/test/cpp/microbenchmarks/bm_cq_multiple_threads.cc b/test/cpp/microbenchmarks/bm_cq_multiple_threads.cc
new file mode 100644
index 0000000000000000000000000000000000000000..8627463204233cddfcf11198cff86fc3a899ac59
--- /dev/null
+++ b/test/cpp/microbenchmarks/bm_cq_multiple_threads.cc
@@ -0,0 +1,160 @@
+/*
+ *
+ * Copyright 2017, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <benchmark/benchmark.h>
+#include <string.h>
+#include <atomic>
+
+#include <grpc/grpc.h>
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+#include "test/cpp/microbenchmarks/helpers.h"
+
+extern "C" {
+#include "src/core/lib/iomgr/ev_posix.h"
+#include "src/core/lib/iomgr/port.h"
+#include "src/core/lib/surface/completion_queue.h"
+}
+
+struct grpc_pollset {
+  gpr_mu mu;
+};
+
+namespace grpc {
+namespace testing {
+
+static void* g_tag = (void*)(intptr_t)10;  // Some random number
+static grpc_completion_queue* g_cq;
+static grpc_event_engine_vtable g_vtable;
+
+static void pollset_shutdown(grpc_exec_ctx* exec_ctx, grpc_pollset* ps,
+                             grpc_closure* closure) {
+  grpc_closure_sched(exec_ctx, closure, GRPC_ERROR_NONE);
+}
+
+static void pollset_init(grpc_pollset* ps, gpr_mu** mu) {
+  gpr_mu_init(&ps->mu);
+  *mu = &ps->mu;
+}
+
+static void pollset_destroy(grpc_pollset* ps) { gpr_mu_destroy(&ps->mu); }
+
+static grpc_error* pollset_kick(grpc_pollset* p, grpc_pollset_worker* worker) {
+  return GRPC_ERROR_NONE;
+}
+
+/* Callback when the tag is dequeued from the completion queue. Does nothing */
+static void cq_done_cb(grpc_exec_ctx* exec_ctx, void* done_arg,
+                       grpc_cq_completion* cq_completion) {
+  gpr_free(cq_completion);
+}
+
+/* Queues a completion tag. ZERO polling overhead */
+static grpc_error* pollset_work(grpc_exec_ctx* exec_ctx, grpc_pollset* ps,
+                                grpc_pollset_worker** worker, gpr_timespec now,
+                                gpr_timespec deadline) {
+  gpr_mu_unlock(&ps->mu);
+  grpc_cq_begin_op(g_cq, g_tag);
+  grpc_cq_end_op(exec_ctx, g_cq, g_tag, GRPC_ERROR_NONE, cq_done_cb, NULL,
+                 (grpc_cq_completion*)gpr_malloc(sizeof(grpc_cq_completion)));
+  grpc_exec_ctx_flush(exec_ctx);
+  gpr_mu_lock(&ps->mu);
+  return GRPC_ERROR_NONE;
+}
+
+static void init_engine_vtable() {
+  memset(&g_vtable, 0, sizeof(g_vtable));
+
+  g_vtable.pollset_size = sizeof(grpc_pollset);
+  g_vtable.pollset_init = pollset_init;
+  g_vtable.pollset_shutdown = pollset_shutdown;
+  g_vtable.pollset_destroy = pollset_destroy;
+  g_vtable.pollset_work = pollset_work;
+  g_vtable.pollset_kick = pollset_kick;
+}
+
+static void setup() {
+  grpc_init();
+  init_engine_vtable();
+  grpc_set_event_engine_test_only(&g_vtable);
+
+  g_cq = grpc_completion_queue_create(NULL);
+}
+
+static void teardown() {
+  grpc_completion_queue_shutdown(g_cq);
+  grpc_completion_queue_destroy(g_cq);
+}
+
+/* A few notes about Multi-threaded benchmarks:
+
+ Setup:
+  The benchmark framework ensures that none of the threads proceed beyond the
+  state.KeepRunning() call unless all the threads have called state.keepRunning
+  atleast once.  So it is safe to do the initialization in one of the threads
+  before state.KeepRunning() is called.
+
+ Teardown:
+  The benchmark framework also ensures that no thread is running the benchmark
+  code (i.e the code between two successive calls of state.KeepRunning()) if
+  state.KeepRunning() returns false. So it is safe to do the teardown in one
+  of the threads after state.keepRunning() returns false.
+*/
+static void BM_Cq_Throughput(benchmark::State& state) {
+  TrackCounters track_counters;
+  gpr_timespec deadline = gpr_inf_future(GPR_CLOCK_MONOTONIC);
+
+  if (state.thread_index == 0) {
+    setup();
+  }
+
+  while (state.KeepRunning()) {
+    GPR_ASSERT(grpc_completion_queue_next(g_cq, deadline, NULL).type ==
+               GRPC_OP_COMPLETE);
+  }
+
+  state.SetItemsProcessed(state.iterations());
+
+  if (state.thread_index == 0) {
+    teardown();
+  }
+
+  track_counters.Finish(state);
+}
+
+BENCHMARK(BM_Cq_Throughput)->ThreadRange(1, 16)->UseRealTime();
+
+}  // namespace testing
+}  // namespace grpc
+
+BENCHMARK_MAIN();
diff --git a/test/cpp/microbenchmarks/fullstack_fixtures.h b/test/cpp/microbenchmarks/fullstack_fixtures.h
index dc2970105991cb8d682fb77331656333e1d818e6..acc56bf39bf15ae7715b824ddd29bb9ec9ef39de 100644
--- a/test/cpp/microbenchmarks/fullstack_fixtures.h
+++ b/test/cpp/microbenchmarks/fullstack_fixtures.h
@@ -212,8 +212,8 @@ class EndpointPairFixture : public BaseFixture {
 class SockPair : public EndpointPairFixture {
  public:
   SockPair(Service* service)
-      : EndpointPairFixture(service, grpc_iomgr_create_endpoint_pair(
-                                         "test", Library::get().rq(), 8192)) {}
+      : EndpointPairFixture(service,
+                            grpc_iomgr_create_endpoint_pair("test", NULL)) {}
 };
 
 class InProcessCHTTP2 : public EndpointPairFixture {
diff --git a/test/cpp/qps/benchmark_config.cc b/test/cpp/qps/benchmark_config.cc
index 98b8d0ba3794b70e1b46720752410230fef567fa..d33f3e9ae10f909e47bf1fa82df2c5bf9a383ba8 100644
--- a/test/cpp/qps/benchmark_config.cc
+++ b/test/cpp/qps/benchmark_config.cc
@@ -33,6 +33,9 @@
 
 #include "test/cpp/qps/benchmark_config.h"
 #include <gflags/gflags.h>
+#include <grpc++/create_channel.h>
+#include <grpc++/security/credentials.h>
+#include <grpc/support/log.h>
 
 DEFINE_bool(enable_log_reporter, true,
             "Enable reporting of benchmark results through GprLog");
@@ -51,6 +54,11 @@ DEFINE_string(server_address, "localhost:50052",
 
 DEFINE_string(tag, "", "Optional tag for the test");
 
+DEFINE_string(rpc_reporter_server_address, "",
+              "Server address for rpc reporter to send results to");
+
+DEFINE_bool(enable_rpc_reporter, false, "Enable use of RPC reporter");
+
 // In some distros, gflags is in the namespace google, and in some others,
 // in gflags. This hack is enabling us to find both.
 namespace google {}
@@ -75,6 +83,13 @@ static std::shared_ptr<Reporter> InitBenchmarkReporters() {
     composite_reporter->add(std::unique_ptr<Reporter>(
         new JsonReporter("JsonReporter", FLAGS_scenario_result_file)));
   }
+  if (FLAGS_enable_rpc_reporter) {
+    GPR_ASSERT(!FLAGS_rpc_reporter_server_address.empty());
+    composite_reporter->add(std::unique_ptr<Reporter>(new RpcReporter(
+        "RpcReporter",
+        grpc::CreateChannel(FLAGS_rpc_reporter_server_address,
+                            grpc::InsecureChannelCredentials()))));
+  }
 
   return std::shared_ptr<Reporter>(composite_reporter);
 }
diff --git a/test/cpp/qps/report.cc b/test/cpp/qps/report.cc
index 7f8481642190803f11fc51331893692f5a24be34..a9130bf5d425b3dd8970eff3874a3647b6d25439 100644
--- a/test/cpp/qps/report.cc
+++ b/test/cpp/qps/report.cc
@@ -40,6 +40,9 @@
 #include "test/cpp/qps/parse_json.h"
 #include "test/cpp/qps/stats.h"
 
+#include <grpc++/client_context.h>
+#include "src/proto/grpc/testing/services.grpc.pb.h"
+
 namespace grpc {
 namespace testing {
 
@@ -142,5 +145,37 @@ void JsonReporter::ReportCpuUsage(const ScenarioResult& result) {
   // NOP - all reporting is handled by ReportQPS.
 }
 
+void RpcReporter::ReportQPS(const ScenarioResult& result) {
+  grpc::ClientContext context;
+  grpc::Status status;
+  Void dummy;
+
+  gpr_log(GPR_INFO, "RPC reporter sending scenario result to server");
+  status = stub_->ReportScenario(&context, result, &dummy);
+
+  if (status.ok()) {
+    gpr_log(GPR_INFO, "RpcReporter report RPC success!");
+  } else {
+    gpr_log(GPR_ERROR, "RpcReporter report RPC: code: %d. message: %s",
+            status.error_code(), status.error_message().c_str());
+  }
+}
+
+void RpcReporter::ReportQPSPerCore(const ScenarioResult& result) {
+  // NOP - all reporting is handled by ReportQPS.
+}
+
+void RpcReporter::ReportLatency(const ScenarioResult& result) {
+  // NOP - all reporting is handled by ReportQPS.
+}
+
+void RpcReporter::ReportTimes(const ScenarioResult& result) {
+  // NOP - all reporting is handled by ReportQPS.
+}
+
+void RpcReporter::ReportCpuUsage(const ScenarioResult& result) {
+  // NOP - all reporting is handled by ReportQPS.
+}
+
 }  // namespace testing
 }  // namespace grpc
diff --git a/test/cpp/qps/report.h b/test/cpp/qps/report.h
index faf87ff060f6f4832ec1d17bf45ff3e5e7d016b9..1749be98c6f9ce95b9d97e664340e85d004c40e0 100644
--- a/test/cpp/qps/report.h
+++ b/test/cpp/qps/report.h
@@ -42,6 +42,9 @@
 
 #include "test/cpp/qps/driver.h"
 
+#include <grpc++/channel.h>
+#include "src/proto/grpc/testing/services.grpc.pb.h"
+
 namespace grpc {
 namespace testing {
 
@@ -124,6 +127,21 @@ class JsonReporter : public Reporter {
   const string report_file_;
 };
 
+class RpcReporter : public Reporter {
+ public:
+  RpcReporter(const string& name, std::shared_ptr<grpc::Channel> channel)
+      : Reporter(name), stub_(ReportQpsScenarioService::NewStub(channel)) {}
+
+ private:
+  void ReportQPS(const ScenarioResult& result) override;
+  void ReportQPSPerCore(const ScenarioResult& result) override;
+  void ReportLatency(const ScenarioResult& result) override;
+  void ReportTimes(const ScenarioResult& result) override;
+  void ReportCpuUsage(const ScenarioResult& result) override;
+
+  std::unique_ptr<ReportQpsScenarioService::Stub> stub_;
+};
+
 }  // namespace testing
 }  // namespace grpc
 
diff --git a/test/cpp/util/grpc_tool.cc b/test/cpp/util/grpc_tool.cc
index 856cd32c3ce0f8fed980137132167615239ba59a..c7acb7c63135c5fd3c9d36bb01020d1148295983 100644
--- a/test/cpp/util/grpc_tool.cc
+++ b/test/cpp/util/grpc_tool.cc
@@ -321,6 +321,7 @@ bool GrpcTool::ListServices(int argc, const char** argv,
 
   std::vector<grpc::string> service_list;
   if (!desc_db.GetServices(&service_list)) {
+    fprintf(stderr, "Received an error when querying services endpoint.\n");
     return false;
   }
 
diff --git a/test/distrib/csharp/run_distrib_test.bat b/test/distrib/csharp/run_distrib_test.bat
index 6cf381142f4b5a8add9d633ea4260c59d044e2e7..cb5dd55273989eb8e750930205b5ab3fbff963c4 100644
--- a/test/distrib/csharp/run_distrib_test.bat
+++ b/test/distrib/csharp/run_distrib_test.bat
@@ -31,7 +31,7 @@
 cd /d %~dp0
 
 @rem extract input artifacts
-powershell -Command "Add-Type -Assembly 'System.IO.Compression.FileSystem'; [System.IO.Compression.ZipFile]::ExtractToDirectory('../../../input_artifacts/csharp_nugets_dotnetcli.zip', 'TestNugetFeed');"
+powershell -Command "Add-Type -Assembly 'System.IO.Compression.FileSystem'; [System.IO.Compression.ZipFile]::ExtractToDirectory('../../../input_artifacts/csharp_nugets_windows_dotnetcli.zip', 'TestNugetFeed');"
 
 update_version.sh auto
 
diff --git a/test/distrib/csharp/run_distrib_test.sh b/test/distrib/csharp/run_distrib_test.sh
index 0a77c1af4407a16259da7cda77b663a38676aa2e..9de5ce0cd32b452d25dce11dcc68c07798502ac5 100755
--- a/test/distrib/csharp/run_distrib_test.sh
+++ b/test/distrib/csharp/run_distrib_test.sh
@@ -32,7 +32,7 @@ set -ex
 
 cd $(dirname $0)
 
-unzip -o "$EXTERNAL_GIT_ROOT/input_artifacts/csharp_nugets_dotnetcli.zip" -d TestNugetFeed
+unzip -o "$EXTERNAL_GIT_ROOT/input_artifacts/csharp_nugets_windows_dotnetcli.zip" -d TestNugetFeed
 
 ./update_version.sh auto
 
diff --git a/test/distrib/csharp/run_distrib_test_dotnetcli.sh b/test/distrib/csharp/run_distrib_test_dotnetcli.sh
index 493c5049fb8e00a4c63e0d3b0d5afe637b148cbb..cdfc91bf42775fb88d00f395a99a16fa7859a52a 100755
--- a/test/distrib/csharp/run_distrib_test_dotnetcli.sh
+++ b/test/distrib/csharp/run_distrib_test_dotnetcli.sh
@@ -32,7 +32,7 @@ set -ex
 
 cd $(dirname $0)
 
-unzip -o "$EXTERNAL_GIT_ROOT/input_artifacts/csharp_nugets_dotnetcli.zip" -d TestNugetFeed
+unzip -o "$EXTERNAL_GIT_ROOT/input_artifacts/csharp_nugets_windows_dotnetcli.zip" -d TestNugetFeed
 
 ./update_version.sh auto
 
diff --git a/third_party/googletest b/third_party/googletest
index c99458533a9b4c743ed51537e25989ea55944908..ec44c6c1675c25b9827aacd08c02433cccde7780 160000
--- a/third_party/googletest
+++ b/third_party/googletest
@@ -1 +1 @@
-Subproject commit c99458533a9b4c743ed51537e25989ea55944908
+Subproject commit ec44c6c1675c25b9827aacd08c02433cccde7780
diff --git a/third_party/gtest.BUILD b/third_party/gtest.BUILD
index a07db65b91b2732eeecdb6e0682ee1b2e2b910da..52c9ca2ba7c2537b204929b6d8fe3d7294e1af17 100644
--- a/third_party/gtest.BUILD
+++ b/third_party/gtest.BUILD
@@ -1,11 +1,12 @@
 cc_library(
     name = "gtest",
     srcs = [
-        "src/gtest-all.cc",
+        "googletest/src/gtest-all.cc",
     ],
-    hdrs = glob(["include/**/*.h", "src/*.cc", "src/*.h"]),
+    hdrs = glob(["googletest/include/**/*.h", "googletest/src/*.cc", "googletest/src/*.h"]),
     includes = [
-        "include",
+        "googletest",
+        "googletest/include",
     ],
     linkstatic = 1,
     visibility = [
diff --git a/third_party/protobuf b/third_party/protobuf
index 593e917c176b5bc5aafa57bf9f6030d749d91cd5..4a0dd03e52e09332c8fd0f8f26a8e0ae9f911182 160000
--- a/third_party/protobuf
+++ b/third_party/protobuf
@@ -1 +1 @@
-Subproject commit 593e917c176b5bc5aafa57bf9f6030d749d91cd5
+Subproject commit 4a0dd03e52e09332c8fd0f8f26a8e0ae9f911182
diff --git a/tools/distrib/python/grpcio_tools/protoc_lib_deps.py b/tools/distrib/python/grpcio_tools/protoc_lib_deps.py
index c2aa6198b3d7c442548f2f1c4fa9dd5c18a76e63..7e8cd987d5de0dbb9d5b3e92687471de14abf41e 100644
--- a/tools/distrib/python/grpcio_tools/protoc_lib_deps.py
+++ b/tools/distrib/python/grpcio_tools/protoc_lib_deps.py
@@ -29,7 +29,7 @@
 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 # 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/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_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/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/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_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_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/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/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'
diff --git a/tools/dockerfile/grpc_clang_format/clang_format_all_the_things.sh b/tools/dockerfile/grpc_clang_format/clang_format_all_the_things.sh
index c6e4aabfe63fcb88f4e961451699275f753c1bb5..02e811f664b9f455cf5ab0390a2344d819736659 100755
--- a/tools/dockerfile/grpc_clang_format/clang_format_all_the_things.sh
+++ b/tools/dockerfile/grpc_clang_format/clang_format_all_the_things.sh
@@ -31,7 +31,7 @@
 set -e
 
 # directories to run against
-DIRS="src/core/lib src/core/ext src/cpp test/core test/cpp include src/compiler"
+DIRS="src/core/lib src/core/tsi src/core/ext src/cpp test/core test/cpp include src/compiler"
 
 # file matching patterns to check
 GLOB="*.h *.c *.cc"
diff --git a/tools/dockerfile/interoptest/grpc_interop_csharp/Dockerfile b/tools/dockerfile/interoptest/grpc_interop_csharp/Dockerfile
index 14a2468abc7d7d4c2ed918e7b513e2503c951bda..f9e709dccb1fbfc6a9bc0aa4ae28f7742f76838f 100644
--- a/tools/dockerfile/interoptest/grpc_interop_csharp/Dockerfile
+++ b/tools/dockerfile/interoptest/grpc_interop_csharp/Dockerfile
@@ -86,7 +86,6 @@ RUN apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 3FA7E0328081BFF6A14
 RUN echo "deb http://download.mono-project.com/repo/debian wheezy main" | tee /etc/apt/sources.list.d/mono-xamarin.list
 RUN echo "deb http://download.mono-project.com/repo/debian wheezy-apache24-compat main" | tee -a /etc/apt/sources.list.d/mono-xamarin.list
 RUN echo "deb http://download.mono-project.com/repo/debian wheezy-libjpeg62-compat main" | tee -a /etc/apt/sources.list.d/mono-xamarin.list
-RUN echo "deb http://download.mono-project.com/repo/debian wheezy-libtiff-compat main" | tee -a /etc/apt/sources.list.d/mono-xamarin.list
 
 # Install dependencies
 RUN apt-get update && apt-get -y dist-upgrade && apt-get install -y \
@@ -97,6 +96,24 @@ RUN apt-get update && apt-get -y dist-upgrade && apt-get install -y \
 
 RUN nuget update -self
 
+# Install dotnet SDK based on https://www.microsoft.com/net/core#debian
+RUN apt-get update && apt-get install -y curl libunwind8 gettext
+# dotnet-dev-1.0.0-preview2-003131
+RUN curl -sSL -o dotnet100.tar.gz https://go.microsoft.com/fwlink/?LinkID=827530
+RUN mkdir -p /opt/dotnet && tar zxf dotnet100.tar.gz -C /opt/dotnet
+# dotnet-dev-1.0.1
+RUN curl -sSL -o dotnet101.tar.gz https://go.microsoft.com/fwlink/?LinkID=843453
+RUN mkdir -p /opt/dotnet && tar zxf dotnet101.tar.gz -C /opt/dotnet
+RUN ln -s /opt/dotnet/dotnet /usr/local/bin
+
+# Trigger the population of the local package cache
+ENV NUGET_XMLDOC_MODE skip
+RUN mkdir warmup \
+    && cd warmup \
+    && dotnet new \
+    && cd .. \
+    && rm -rf warmup
+
 # Prepare ccache
 RUN ln -s /usr/bin/ccache /usr/local/bin/gcc
 RUN ln -s /usr/bin/ccache /usr/local/bin/g++
diff --git a/tools/dockerfile/interoptest/grpc_interop_csharpcoreclr/Dockerfile b/tools/dockerfile/interoptest/grpc_interop_csharpcoreclr/Dockerfile
index c26c9a2826ea15ae42913b1e9bc0da0576e59b37..f9e709dccb1fbfc6a9bc0aa4ae28f7742f76838f 100644
--- a/tools/dockerfile/interoptest/grpc_interop_csharpcoreclr/Dockerfile
+++ b/tools/dockerfile/interoptest/grpc_interop_csharpcoreclr/Dockerfile
@@ -86,7 +86,6 @@ RUN apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 3FA7E0328081BFF6A14
 RUN echo "deb http://download.mono-project.com/repo/debian wheezy main" | tee /etc/apt/sources.list.d/mono-xamarin.list
 RUN echo "deb http://download.mono-project.com/repo/debian wheezy-apache24-compat main" | tee -a /etc/apt/sources.list.d/mono-xamarin.list
 RUN echo "deb http://download.mono-project.com/repo/debian wheezy-libjpeg62-compat main" | tee -a /etc/apt/sources.list.d/mono-xamarin.list
-RUN echo "deb http://download.mono-project.com/repo/debian wheezy-libtiff-compat main" | tee -a /etc/apt/sources.list.d/mono-xamarin.list
 
 # Install dependencies
 RUN apt-get update && apt-get -y dist-upgrade && apt-get install -y \
@@ -99,8 +98,8 @@ RUN nuget update -self
 
 # Install dotnet SDK based on https://www.microsoft.com/net/core#debian
 RUN apt-get update && apt-get install -y curl libunwind8 gettext
-# dotnet-dev-1.0.0-preview2-003121
-RUN curl -sSL -o dotnet100.tar.gz https://go.microsoft.com/fwlink/?LinkID=809130
+# dotnet-dev-1.0.0-preview2-003131
+RUN curl -sSL -o dotnet100.tar.gz https://go.microsoft.com/fwlink/?LinkID=827530
 RUN mkdir -p /opt/dotnet && tar zxf dotnet100.tar.gz -C /opt/dotnet
 # dotnet-dev-1.0.1
 RUN curl -sSL -o dotnet101.tar.gz https://go.microsoft.com/fwlink/?LinkID=843453
diff --git a/tools/dockerfile/stress_test/grpc_interop_stress_csharp/Dockerfile b/tools/dockerfile/stress_test/grpc_interop_stress_csharp/Dockerfile
index cd1e9343417c9608047bf979cf1cd069d42abdd4..12d8d091848444787da1ad59c1103727a99a48d7 100644
--- a/tools/dockerfile/stress_test/grpc_interop_stress_csharp/Dockerfile
+++ b/tools/dockerfile/stress_test/grpc_interop_stress_csharp/Dockerfile
@@ -103,7 +103,6 @@ RUN apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 3FA7E0328081BFF6A14
 RUN echo "deb http://download.mono-project.com/repo/debian wheezy main" | tee /etc/apt/sources.list.d/mono-xamarin.list
 RUN echo "deb http://download.mono-project.com/repo/debian wheezy-apache24-compat main" | tee -a /etc/apt/sources.list.d/mono-xamarin.list
 RUN echo "deb http://download.mono-project.com/repo/debian wheezy-libjpeg62-compat main" | tee -a /etc/apt/sources.list.d/mono-xamarin.list
-RUN echo "deb http://download.mono-project.com/repo/debian wheezy-libtiff-compat main" | tee -a /etc/apt/sources.list.d/mono-xamarin.list
 
 # Install dependencies
 RUN apt-get update && apt-get -y dist-upgrade && apt-get install -y \
diff --git a/tools/dockerfile/test/bazel/Dockerfile b/tools/dockerfile/test/bazel/Dockerfile
index cc41384833796c76186f054d842cbea4f02a2d9a..6ea8ef316c6fe8cf749e1e9df721bee265ff7574 100644
--- a/tools/dockerfile/test/bazel/Dockerfile
+++ b/tools/dockerfile/test/bazel/Dockerfile
@@ -72,6 +72,13 @@ RUN curl https://bazel.build/bazel-release.pub.gpg | apt-key add -
 RUN apt-get -y update
 RUN apt-get -y install bazel
 
+# Pin Bazel to 0.4.4
+# Installing Bazel via apt-get first is required before installing 0.4.4 to
+# allow gRPC to build without errors. See https://github.com/grpc/grpc/issues/10553
+RUN curl -fSsL -O https://github.com/bazelbuild/bazel/releases/download/0.4.4/bazel-0.4.4-installer-linux-x86_64.sh
+RUN chmod +x ./bazel-0.4.4-installer-linux-x86_64.sh
+RUN ./bazel-0.4.4-installer-linux-x86_64.sh
+
 RUN mkdir -p /var/local/jenkins
 
 # Define the default command.
diff --git a/tools/dockerfile/test/csharp_coreclr_x64/Dockerfile b/tools/dockerfile/test/csharp_coreclr_x64/Dockerfile
index c26c9a2826ea15ae42913b1e9bc0da0576e59b37..f9e709dccb1fbfc6a9bc0aa4ae28f7742f76838f 100644
--- a/tools/dockerfile/test/csharp_coreclr_x64/Dockerfile
+++ b/tools/dockerfile/test/csharp_coreclr_x64/Dockerfile
@@ -86,7 +86,6 @@ RUN apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 3FA7E0328081BFF6A14
 RUN echo "deb http://download.mono-project.com/repo/debian wheezy main" | tee /etc/apt/sources.list.d/mono-xamarin.list
 RUN echo "deb http://download.mono-project.com/repo/debian wheezy-apache24-compat main" | tee -a /etc/apt/sources.list.d/mono-xamarin.list
 RUN echo "deb http://download.mono-project.com/repo/debian wheezy-libjpeg62-compat main" | tee -a /etc/apt/sources.list.d/mono-xamarin.list
-RUN echo "deb http://download.mono-project.com/repo/debian wheezy-libtiff-compat main" | tee -a /etc/apt/sources.list.d/mono-xamarin.list
 
 # Install dependencies
 RUN apt-get update && apt-get -y dist-upgrade && apt-get install -y \
@@ -99,8 +98,8 @@ RUN nuget update -self
 
 # Install dotnet SDK based on https://www.microsoft.com/net/core#debian
 RUN apt-get update && apt-get install -y curl libunwind8 gettext
-# dotnet-dev-1.0.0-preview2-003121
-RUN curl -sSL -o dotnet100.tar.gz https://go.microsoft.com/fwlink/?LinkID=809130
+# dotnet-dev-1.0.0-preview2-003131
+RUN curl -sSL -o dotnet100.tar.gz https://go.microsoft.com/fwlink/?LinkID=827530
 RUN mkdir -p /opt/dotnet && tar zxf dotnet100.tar.gz -C /opt/dotnet
 # dotnet-dev-1.0.1
 RUN curl -sSL -o dotnet101.tar.gz https://go.microsoft.com/fwlink/?LinkID=843453
diff --git a/tools/dockerfile/test/csharp_jessie_x64/Dockerfile b/tools/dockerfile/test/csharp_jessie_x64/Dockerfile
index 14a2468abc7d7d4c2ed918e7b513e2503c951bda..f9e709dccb1fbfc6a9bc0aa4ae28f7742f76838f 100644
--- a/tools/dockerfile/test/csharp_jessie_x64/Dockerfile
+++ b/tools/dockerfile/test/csharp_jessie_x64/Dockerfile
@@ -86,7 +86,6 @@ RUN apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 3FA7E0328081BFF6A14
 RUN echo "deb http://download.mono-project.com/repo/debian wheezy main" | tee /etc/apt/sources.list.d/mono-xamarin.list
 RUN echo "deb http://download.mono-project.com/repo/debian wheezy-apache24-compat main" | tee -a /etc/apt/sources.list.d/mono-xamarin.list
 RUN echo "deb http://download.mono-project.com/repo/debian wheezy-libjpeg62-compat main" | tee -a /etc/apt/sources.list.d/mono-xamarin.list
-RUN echo "deb http://download.mono-project.com/repo/debian wheezy-libtiff-compat main" | tee -a /etc/apt/sources.list.d/mono-xamarin.list
 
 # Install dependencies
 RUN apt-get update && apt-get -y dist-upgrade && apt-get install -y \
@@ -97,6 +96,24 @@ RUN apt-get update && apt-get -y dist-upgrade && apt-get install -y \
 
 RUN nuget update -self
 
+# Install dotnet SDK based on https://www.microsoft.com/net/core#debian
+RUN apt-get update && apt-get install -y curl libunwind8 gettext
+# dotnet-dev-1.0.0-preview2-003131
+RUN curl -sSL -o dotnet100.tar.gz https://go.microsoft.com/fwlink/?LinkID=827530
+RUN mkdir -p /opt/dotnet && tar zxf dotnet100.tar.gz -C /opt/dotnet
+# dotnet-dev-1.0.1
+RUN curl -sSL -o dotnet101.tar.gz https://go.microsoft.com/fwlink/?LinkID=843453
+RUN mkdir -p /opt/dotnet && tar zxf dotnet101.tar.gz -C /opt/dotnet
+RUN ln -s /opt/dotnet/dotnet /usr/local/bin
+
+# Trigger the population of the local package cache
+ENV NUGET_XMLDOC_MODE skip
+RUN mkdir warmup \
+    && cd warmup \
+    && dotnet new \
+    && cd .. \
+    && rm -rf warmup
+
 # Prepare ccache
 RUN ln -s /usr/bin/ccache /usr/local/bin/gcc
 RUN ln -s /usr/bin/ccache /usr/local/bin/g++
diff --git a/tools/dockerfile/test/cxx_alpine_x64/Dockerfile b/tools/dockerfile/test/cxx_alpine_x64/Dockerfile
new file mode 100644
index 0000000000000000000000000000000000000000..f9468757da206d4f455d6c1afbb1a55ca90c83aa
--- /dev/null
+++ b/tools/dockerfile/test/cxx_alpine_x64/Dockerfile
@@ -0,0 +1,72 @@
+# Copyright 2015, Google Inc.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+#     * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+#     * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+FROM alpine:3.3
+
+# Install Git and basic packages.
+RUN apk update && apk add \
+  autoconf \
+  automake \
+  bzip2 \
+  build-base \
+  cmake \
+  ccache \
+  curl \
+  gcc \
+  git \
+  libtool \
+  make \
+  perl \
+  strace \
+  python-dev \
+  py-pip \
+  unzip \
+  wget \
+  zip
+
+# Install Python packages from PyPI
+RUN pip install pip --upgrade
+RUN pip install virtualenv
+RUN pip install futures==2.2.0 enum34==1.0.4 protobuf==3.2.0 six==1.10.0
+
+# Prepare ccache
+RUN ln -s /usr/bin/ccache /usr/local/bin/gcc
+RUN ln -s /usr/bin/ccache /usr/local/bin/g++
+RUN ln -s /usr/bin/ccache /usr/local/bin/cc 
+RUN ln -s /usr/bin/ccache /usr/local/bin/c++
+
+# Install gflags
+RUN git clone https://github.com/gflags/gflags.git && cd gflags && git checkout v2.2.0
+RUN cd gflags && cmake . && make && make install
+RUN ln -s /usr/local/include/gflags /usr/include/gflags
+
+RUN mkdir -p /var/local/jenkins
+
+# Define the default command.
+CMD ["bash"]
diff --git a/tools/dockerfile/test/multilang_jessie_x64/Dockerfile b/tools/dockerfile/test/multilang_jessie_x64/Dockerfile
index ea57d88c870883fa77f8a06cc1ba896e3cd807aa..c1cce0a1417097fe4a6a4790c0789d692d800dc6 100644
--- a/tools/dockerfile/test/multilang_jessie_x64/Dockerfile
+++ b/tools/dockerfile/test/multilang_jessie_x64/Dockerfile
@@ -71,7 +71,6 @@ RUN apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 3FA7E0328081BFF6A14
 RUN echo "deb http://download.mono-project.com/repo/debian wheezy main" | tee /etc/apt/sources.list.d/mono-xamarin.list
 RUN echo "deb http://download.mono-project.com/repo/debian wheezy-apache24-compat main" | tee -a /etc/apt/sources.list.d/mono-xamarin.list
 RUN echo "deb http://download.mono-project.com/repo/debian wheezy-libjpeg62-compat main" | tee -a /etc/apt/sources.list.d/mono-xamarin.list
-RUN echo "deb http://download.mono-project.com/repo/debian wheezy-libtiff-compat main" | tee -a /etc/apt/sources.list.d/mono-xamarin.list
 
 # Install dependencies
 RUN apt-get update && apt-get -y dist-upgrade && apt-get install -y \
diff --git a/tools/run_tests/helper_scripts/build_csharp_coreclr.sh b/tools/dockerfile/test/python_alpine_x64/Dockerfile
old mode 100755
new mode 100644
similarity index 68%
rename from tools/run_tests/helper_scripts/build_csharp_coreclr.sh
rename to tools/dockerfile/test/python_alpine_x64/Dockerfile
index dd5fd31c759cd3317b16385b3e6190cf78f3e5e4..bdffbd35982bb9e09eb6f2c6322f91ef950318b0
--- a/tools/run_tests/helper_scripts/build_csharp_coreclr.sh
+++ b/tools/dockerfile/test/python_alpine_x64/Dockerfile
@@ -1,4 +1,3 @@
-#!/bin/bash
 # Copyright 2015, Google Inc.
 # All rights reserved.
 #
@@ -28,11 +27,41 @@
 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
-set -ex
+FROM alpine:3.3
 
-cd $(dirname $0)/../../../src/csharp
+# Install Git and basic packages.
+RUN apk update && apk add \
+  autoconf \
+  automake \
+  bzip2 \
+  build-base \
+  cmake \
+  ccache \
+  curl \
+  gcc \
+  git \
+  libtool \
+  make \
+  perl \
+  strace \
+  python-dev \
+  py-pip \
+  unzip \
+  wget \
+  zip
 
-# TODO(jtattermusch): introduce caching
-dotnet restore .
+# Install Python packages from PyPI
+RUN pip install pip --upgrade
+RUN pip install virtualenv
+RUN pip install futures==2.2.0 enum34==1.0.4 protobuf==3.2.0 six==1.10.0
 
-dotnet build --configuration $MSBUILD_CONFIG '**/project.json'
+# Prepare ccache
+RUN ln -s /usr/bin/ccache /usr/local/bin/gcc
+RUN ln -s /usr/bin/ccache /usr/local/bin/g++
+RUN ln -s /usr/bin/ccache /usr/local/bin/cc
+RUN ln -s /usr/bin/ccache /usr/local/bin/c++
+
+RUN mkdir -p /var/local/jenkins
+
+# Define the default command.
+CMD ["bash"]
diff --git a/tools/doxygen/Doxyfile.c++.internal b/tools/doxygen/Doxyfile.c++.internal
index 209d5445dbc7c1d6052fd470c269e71129d39bec..afab2296a020424e7cf0ed42a5c216d10fa692bf 100644
--- a/tools/doxygen/Doxyfile.c++.internal
+++ b/tools/doxygen/Doxyfile.c++.internal
@@ -971,6 +971,8 @@ src/core/lib/iomgr/iomgr_uv.c \
 src/core/lib/iomgr/iomgr_windows.c \
 src/core/lib/iomgr/load_file.c \
 src/core/lib/iomgr/load_file.h \
+src/core/lib/iomgr/lockfree_event.c \
+src/core/lib/iomgr/lockfree_event.h \
 src/core/lib/iomgr/network_status_tracker.c \
 src/core/lib/iomgr/network_status_tracker.h \
 src/core/lib/iomgr/polling_entity.c \
diff --git a/tools/doxygen/Doxyfile.core.internal b/tools/doxygen/Doxyfile.core.internal
index c01bcd6738c3e7ae1517aec6a1704c85b3a0a2f1..915648640f6b77eb825ce1f816463a8590ec3bca 100644
--- a/tools/doxygen/Doxyfile.core.internal
+++ b/tools/doxygen/Doxyfile.core.internal
@@ -1094,6 +1094,8 @@ src/core/lib/iomgr/iomgr_uv.c \
 src/core/lib/iomgr/iomgr_windows.c \
 src/core/lib/iomgr/load_file.c \
 src/core/lib/iomgr/load_file.h \
+src/core/lib/iomgr/lockfree_event.c \
+src/core/lib/iomgr/lockfree_event.h \
 src/core/lib/iomgr/network_status_tracker.c \
 src/core/lib/iomgr/network_status_tracker.h \
 src/core/lib/iomgr/polling_entity.c \
diff --git a/tools/gce/linux_performance_worker_init.sh b/tools/gce/linux_performance_worker_init.sh
index 63fb0d81c544af8279f4b4f69c32ebc70d7f4245..641271214eed61fbba6f6f10fdf516b52efb88f4 100755
--- a/tools/gce/linux_performance_worker_init.sh
+++ b/tools/gce/linux_performance_worker_init.sh
@@ -126,6 +126,7 @@ sudo sh -c 'echo "deb [arch=amd64] https://apt-mo.trafficmanager.net/repos/dotne
 sudo apt-key adv --keyserver apt-mo.trafficmanager.net --recv-keys 417A0893
 sudo apt-get update
 sudo apt-get install -y dotnet-dev-1.0.0-preview2-003131
+sudo apt-get install -y dotnet-dev-1.0.1
 
 # Ruby dependencies
 gpg --keyserver hkp://keys.gnupg.net --recv-keys 409B6B1796C275462A1703113804BB82D39DC0E3
diff --git a/tools/run_tests/generated/sources_and_headers.json b/tools/run_tests/generated/sources_and_headers.json
index 337703e1881eb3d6013d01e21db52d83e7f6330c..8c229af020e8c6ede9257195a091ad0e4614cc60 100644
--- a/tools/run_tests/generated/sources_and_headers.json
+++ b/tools/run_tests/generated/sources_and_headers.json
@@ -2552,6 +2552,27 @@
     "third_party": false, 
     "type": "target"
   }, 
+  {
+    "deps": [
+      "benchmark", 
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc++", 
+      "grpc++_test_util", 
+      "grpc_benchmark", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "is_filegroup": false, 
+    "language": "c++", 
+    "name": "bm_cq_multiple_threads", 
+    "src": [
+      "test/cpp/microbenchmarks/bm_cq_multiple_threads.cc"
+    ], 
+    "third_party": false, 
+    "type": "target"
+  }, 
   {
     "deps": [
       "benchmark", 
@@ -7549,6 +7570,7 @@
       "src/core/lib/iomgr/iomgr_internal.h", 
       "src/core/lib/iomgr/iomgr_posix.h", 
       "src/core/lib/iomgr/load_file.h", 
+      "src/core/lib/iomgr/lockfree_event.h", 
       "src/core/lib/iomgr/network_status_tracker.h", 
       "src/core/lib/iomgr/polling_entity.h", 
       "src/core/lib/iomgr/pollset.h", 
@@ -7710,6 +7732,8 @@
       "src/core/lib/iomgr/iomgr_windows.c", 
       "src/core/lib/iomgr/load_file.c", 
       "src/core/lib/iomgr/load_file.h", 
+      "src/core/lib/iomgr/lockfree_event.c", 
+      "src/core/lib/iomgr/lockfree_event.h", 
       "src/core/lib/iomgr/network_status_tracker.c", 
       "src/core/lib/iomgr/network_status_tracker.h", 
       "src/core/lib/iomgr/polling_entity.c", 
diff --git a/tools/run_tests/generated/tests.json b/tools/run_tests/generated/tests.json
index 88bac795e4981f06c646676b0fb1679ed731df98..12d48f219d780d1bbfe751782f3aecd44577022a 100644
--- a/tools/run_tests/generated/tests.json
+++ b/tools/run_tests/generated/tests.json
@@ -2737,6 +2737,28 @@
       "posix"
     ]
   }, 
+  {
+    "args": [
+      "--benchmark_min_time=0"
+    ], 
+    "ci_platforms": [
+      "linux", 
+      "mac", 
+      "posix"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [], 
+    "exclude_iomgrs": [], 
+    "flaky": false, 
+    "gtest": false, 
+    "language": "c++", 
+    "name": "bm_cq_multiple_threads", 
+    "platforms": [
+      "linux", 
+      "mac", 
+      "posix"
+    ]
+  }, 
   {
     "args": [
       "--benchmark_min_time=0"
@@ -150765,6 +150787,29 @@
     ], 
     "uses_polling": false
   }, 
+  {
+    "args": [
+      "test/core/end2end/fuzzers/server_fuzzer_corpus/clusterfuzz-testcase-6312731374256128"
+    ], 
+    "ci_platforms": [
+      "linux"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [
+      "tsan"
+    ], 
+    "exclude_iomgrs": [
+      "uv"
+    ], 
+    "flaky": false, 
+    "language": "c", 
+    "name": "server_fuzzer_one_entry", 
+    "platforms": [
+      "mac", 
+      "linux"
+    ], 
+    "uses_polling": false
+  }, 
   {
     "args": [
       "test/core/end2end/fuzzers/server_fuzzer_corpus/crash-0f4b135c0242669ce425d2662168e9440f8a628d"
diff --git a/tools/run_tests/helper_scripts/build_csharp_coreclr.bat b/tools/run_tests/helper_scripts/build_csharp.bat
similarity index 93%
rename from tools/run_tests/helper_scripts/build_csharp_coreclr.bat
rename to tools/run_tests/helper_scripts/build_csharp.bat
index 78e5f5998b810db19483d003618e2392bdf445c5..05ea78564c4d9ed02b24d893e11df2e8b3235c62 100644
--- a/tools/run_tests/helper_scripts/build_csharp_coreclr.bat
+++ b/tools/run_tests/helper_scripts/build_csharp.bat
@@ -31,9 +31,7 @@ setlocal
 
 cd /d %~dp0\..\..\..\src\csharp
 
-dotnet restore . || goto :error
-
-dotnet build --configuration %MSBUILD_CONFIG% "**/project.json" || goto :error
+dotnet build --configuration %MSBUILD_CONFIG% Grpc.sln || goto :error
 
 endlocal
 
diff --git a/tools/run_tests/helper_scripts/build_csharp.sh b/tools/run_tests/helper_scripts/build_csharp.sh
index 84c5b1c77786969fc9cf930613c6a35ffcda2eb2..a7562a7f4a374954ced9e7dc0ebd5444b3070393 100755
--- a/tools/run_tests/helper_scripts/build_csharp.sh
+++ b/tools/run_tests/helper_scripts/build_csharp.sh
@@ -32,5 +32,10 @@ set -ex
 
 cd $(dirname $0)/../../../src/csharp
 
-# overriding NativeDependenciesConfigurationUnix is needed to make gcov code coverage work.
-xbuild /p:Configuration=$MSBUILD_CONFIG /p:NativeDependenciesConfigurationUnix=$CONFIG Grpc.sln
+if [ "$CONFIG" == "gcov" ]
+then
+  # overriding NativeDependenciesConfigurationUnix makes C# project pick up the gcov flavor of grpc_csharp_ext
+  dotnet build --configuration $MSBUILD_CONFIG /p:NativeDependenciesConfigurationUnix=gcov Grpc.sln
+else
+  dotnet build --configuration $MSBUILD_CONFIG Grpc.sln
+fi
diff --git a/tools/run_tests/helper_scripts/build_python.sh b/tools/run_tests/helper_scripts/build_python.sh
index 5647d9c2fcb3569b1bab631b8c39bdffc8e52493..28397be13ef8ff5cbcfe9d95612758c6b3faa915 100755
--- a/tools/run_tests/helper_scripts/build_python.sh
+++ b/tools/run_tests/helper_scripts/build_python.sh
@@ -155,7 +155,7 @@ fi
 ($PYTHON -m virtualenv $VENV ||
  $HOST_PYTHON -m virtualenv -p $PYTHON $VENV ||
  true)
-VENV_PYTHON=`script_realpath -s "$VENV/$VENV_RELATIVE_PYTHON"`
+VENV_PYTHON=`script_realpath "$VENV/$VENV_RELATIVE_PYTHON"`
 
 # pip-installs the directory specified. Used because on MSYS the vanilla Windows
 # Python gets confused when parsing paths.
diff --git a/tools/run_tests/helper_scripts/pre_build_csharp.bat b/tools/run_tests/helper_scripts/pre_build_csharp.bat
index 99df1c66268ed2cf8a45ff30ff6810b927862787..e59dac4edce8879866cc8f6cf38bc4e83569574b 100644
--- a/tools/run_tests/helper_scripts/pre_build_csharp.bat
+++ b/tools/run_tests/helper_scripts/pre_build_csharp.bat
@@ -43,57 +43,11 @@ cd build
 mkdir %ARCHITECTURE%
 cd %ARCHITECTURE%
 @rem TODO(jtattermusch): Stop hardcoding path to yasm once Jenkins workers can locate yasm correctly
-cmake -G "Visual Studio 14 2015" -A %ARCHITECTURE% -DgRPC_BUILD_TESTS=OFF -DCMAKE_ASM_NASM_COMPILER="C:/Program Files (x86)/yasm/yasm.exe" ../../.. || goto :error
-cd ..\..\..
+cmake -G "Visual Studio 14 2015" -A %ARCHITECTURE% -DgRPC_BUILD_TESTS=OFF -DgRPC_MSVC_STATIC_RUNTIME=ON -DCMAKE_ASM_NASM_COMPILER="C:/Program Files (x86)/yasm/yasm.exe" ../../.. || goto :error
 
-@rem Location of nuget.exe
-set NUGET=C:\nuget\nuget.exe
+cd ..\..\..\src\csharp
 
-if exist %NUGET% (
-  @rem TODO(jtattermusch): Get rid of this hack. See #8034
-  @rem Restore Grpc packages by packages since Nuget client 3.4.4 doesnt support restore
-  @rem by solution
-  @rem Moving into each directory to let the restores work based on per-project packages.config files
-
-  cd src/csharp
-
-  cd Grpc.Auth || goto :error
-  %NUGET% restore -PackagesDirectory ../packages || goto :error
-  cd ..
-
-  cd Grpc.Core || goto :error
-  %NUGET% restore -PackagesDirectory ../packages || goto :error
-  cd ..
-
-  cd Grpc.Core.Tests || goto :error
-  %NUGET% restore -PackagesDirectory ../packages || goto :error
-  cd ..
-
-  cd Grpc.Examples.MathClient || goto :error
-  %NUGET% restore -PackagesDirectory ../packages || goto :error
-  cd ..
-
-  cd Grpc.Examples.MathServer || goto :error
-  %NUGET% restore -PackagesDirectory ../packages || goto :error
-  cd ..
-
-  cd Grpc.Examples || goto :error
-  %NUGET% restore -PackagesDirectory ../packages || goto :error
-  cd ..
-
-  cd Grpc.HealthCheck.Tests || goto :error
-  %NUGET% restore -PackagesDirectory ../packages || goto :error
-  cd ..
-
-  cd Grpc.HealthCheck || goto :error
-  %NUGET% restore -PackagesDirectory ../packages || goto :error
-  cd ..
-
-  cd Grpc.IntegrationTesting || goto :error
-  %NUGET% restore -PackagesDirectory ../packages || goto :error
-
-  cd /d %~dp0\..\.. || goto :error
-)
+dotnet restore Grpc.sln || goto :error
 
 endlocal
 
diff --git a/tools/run_tests/helper_scripts/pre_build_csharp.sh b/tools/run_tests/helper_scripts/pre_build_csharp.sh
index d7665e15af641df4d3a002b195c0d63843727ea0..40be1b6b64216130a11d519816591e0b990f9e7e 100755
--- a/tools/run_tests/helper_scripts/pre_build_csharp.sh
+++ b/tools/run_tests/helper_scripts/pre_build_csharp.sh
@@ -33,47 +33,4 @@ set -ex
 # cd to gRPC csharp directory
 cd $(dirname $0)/../../../src/csharp
 
-root=`pwd`
-
-if [ -x "$(command -v nuget)" ]
-then
-  # TODO(jtattermusch): Get rid of this hack. See #8034
-  # Restoring Nuget packages by packages rather than by solution because of
-  # inability to restore by solution with Nuget client 3.4.4
-  # Moving into each directory to let the restores work based on per-project packages.config files
-  cd Grpc.Auth
-  nuget restore -PackagesDirectory ../packages
-  cd ..
-
-  cd Grpc.Core.Tests
-  nuget restore -PackagesDirectory ../packages
-  cd ..
-
-  cd Grpc.Core
-  nuget restore -PackagesDirectory ../packages
-  cd ..
-
-  cd Grpc.Examples.MathClient
-  nuget restore -PackagesDirectory ../packages
-  cd ..
-
-  cd Grpc.Examples.MathServer
-  nuget restore -PackagesDirectory ../packages
-  cd ..
-
-  cd Grpc.Examples
-  nuget restore -PackagesDirectory ../packages
-  cd ..
-
-  cd Grpc.HealthCheck.Tests
-  nuget restore -PackagesDirectory ../packages
-  cd ..
-
-  cd Grpc.HealthCheck
-  nuget restore -PackagesDirectory ../packages
-  cd ..
-
-  cd Grpc.IntegrationTesting
-  nuget restore -PackagesDirectory ../packages
-  cd ..
-fi
+dotnet restore Grpc.sln
diff --git a/tools/run_tests/helper_scripts/run_python.sh b/tools/run_tests/helper_scripts/run_python.sh
index 7be473428fba587cc3be66b55b7c7ca0afb45bd0..e510ef40154e2962f2471c37defb0071d915d8d5 100755
--- a/tools/run_tests/helper_scripts/run_python.sh
+++ b/tools/run_tests/helper_scripts/run_python.sh
@@ -33,7 +33,7 @@ set -ex
 # change to grpc repo root
 cd $(dirname $0)/../../..
 
-PYTHON=`realpath -s "${1:-py27/bin/python}"`
+PYTHON=`realpath "${1:-py27/bin/python}"`
 
 ROOT=`pwd`
 
diff --git a/tools/run_tests/helper_scripts/run_ruby_end2end_tests.sh b/tools/run_tests/helper_scripts/run_ruby_end2end_tests.sh
index d7da6364d8f72ac8b43992d266ee7760ff97f896..92d6975707389a3352ed677f319144c398504558 100755
--- a/tools/run_tests/helper_scripts/run_ruby_end2end_tests.sh
+++ b/tools/run_tests/helper_scripts/run_ruby_end2end_tests.sh
@@ -38,4 +38,5 @@ ruby src/ruby/end2end/sig_handling_driver.rb || EXIT_CODE=1
 ruby src/ruby/end2end/channel_state_driver.rb || EXIT_CODE=1
 ruby src/ruby/end2end/channel_closing_driver.rb || EXIT_CODE=1
 ruby src/ruby/end2end/sig_int_during_channel_watch_driver.rb || EXIT_CODE=1
+ruby src/ruby/end2end/killed_client_thread_driver.rb || EXIT_CODE=1
 exit $EXIT_CODE
diff --git a/tools/run_tests/run_interop_tests.py b/tools/run_tests/run_interop_tests.py
index 2d7f4a625d61e3eb3f4703ac79cb6d8cb20db945..d2bf529fef33a59503cfac736fb69df43093e6e0 100755
--- a/tools/run_tests/run_interop_tests.py
+++ b/tools/run_tests/run_interop_tests.py
@@ -114,8 +114,8 @@ class CXXLanguage:
 class CSharpLanguage:
 
   def __init__(self):
-    self.client_cwd = 'src/csharp/Grpc.IntegrationTesting.Client/bin/Debug'
-    self.server_cwd = 'src/csharp/Grpc.IntegrationTesting.Server/bin/Debug'
+    self.client_cwd = 'src/csharp/Grpc.IntegrationTesting.Client/bin/Debug/net45'
+    self.server_cwd = 'src/csharp/Grpc.IntegrationTesting.Server/bin/Debug/net45'
     self.safename = str(self)
 
   def client_cmd(self, args):
diff --git a/tools/run_tests/run_tests.py b/tools/run_tests/run_tests.py
index 0b4f26ca4401576d17fc9df89507f8725df42abf..cfa7071e002db3dd7513ae850b3cdf4b68f65d4e 100755
--- a/tools/run_tests/run_tests.py
+++ b/tools/run_tests/run_tests.py
@@ -395,6 +395,8 @@ class CLanguage(object):
       return ('jessie', self._gcc_make_options(version_suffix='-4.8'))
     elif compiler == 'gcc5.3':
       return ('ubuntu1604', [])
+    elif compiler == 'gcc_musl':
+      return ('alpine', [])
     elif compiler == 'clang3.4':
       # on ubuntu1404, clang-3.4 alias doesn't exist, just use 'clang'
       return ('ubuntu1404', self._clang_make_options())
@@ -626,7 +628,12 @@ class PythonLanguage(object):
     return 'tools/dockerfile/test/python_%s_%s' % (self.python_manager_name(), _docker_arch_suffix(self.args.arch))
 
   def python_manager_name(self):
-    return 'pyenv' if self.args.compiler in ['python3.5', 'python3.6'] else 'jessie'
+    if self.args.compiler in ['python3.5', 'python3.6']:
+      return 'pyenv'
+    elif self.args.compiler == 'python_alpine':
+      return 'alpine'
+    else:
+      return 'jessie'
 
   def _get_pythons(self, args):
     if args.arch == 'x86':
@@ -684,6 +691,8 @@ class PythonLanguage(object):
       return (pypy27_config,)
     elif args.compiler == 'pypy3':
       return (pypy32_config,)
+    elif args.compiler == 'python_alpine':
+      return (python27_config,)
     else:
       raise Exception('Compiler %s not supported.' % args.compiler)
 
@@ -743,14 +752,11 @@ class CSharpLanguage(object):
     if self.platform == 'windows':
       _check_compiler(self.args.compiler, ['coreclr', 'default'])
       _check_arch(self.args.arch, ['default'])
-      self._cmake_arch_option = 'x64' if self.args.compiler == 'coreclr' else 'Win32'
+      self._cmake_arch_option = 'x64'
       self._make_options = []
     else:
       _check_compiler(self.args.compiler, ['default', 'coreclr'])
-      if self.platform == 'linux' and self.args.compiler == 'coreclr':
-        self._docker_distro = 'coreclr'
-      else:
-        self._docker_distro = 'jessie'
+      self._docker_distro = 'jessie'
 
       if self.platform == 'mac':
         # TODO(jtattermusch): EMBED_ZLIB=true currently breaks the mac build
@@ -766,7 +772,7 @@ class CSharpLanguage(object):
       tests_by_assembly = json.load(f)
 
     msbuild_config = _MSBUILD_CONFIG[self.config.build_config]
-    nunit_args = ['--labels=All']
+    nunit_args = ['--labels=All', '--noresult', '--workers=1']
     assembly_subdir = 'bin/%s' % msbuild_config
     assembly_extension = '.exe'
 
@@ -775,7 +781,7 @@ class CSharpLanguage(object):
       runtime_cmd = ['dotnet', 'exec']
       assembly_extension = '.dll'
     else:
-      nunit_args += ['--noresult', '--workers=1']
+      assembly_subdir += '/net45'
       if self.platform == 'windows':
         runtime_cmd = []
       else:
@@ -827,18 +833,10 @@ class CSharpLanguage(object):
     return self._make_options;
 
   def build_steps(self):
-    if self.args.compiler == 'coreclr':
-      if self.platform == 'windows':
-        return [['tools\\run_tests\\helper_scripts\\build_csharp_coreclr.bat']]
-      else:
-        return [['tools/run_tests/helper_scripts/build_csharp_coreclr.sh']]
+    if self.platform == 'windows':
+      return [['tools\\run_tests\\helper_scripts\\build_csharp.bat']]
     else:
-      if self.platform == 'windows':
-        return [['vsprojects\\build_vs2015.bat',
-                 'src/csharp/Grpc.sln',
-                 '/p:Configuration=%s' % _MSBUILD_CONFIG[self.config.build_config]]]
-      else:
-        return [['tools/run_tests/helper_scripts/build_csharp.sh']]
+      return [['tools/run_tests/helper_scripts/build_csharp.sh']]
 
   def post_tests_steps(self):
     if self.platform == 'windows':
@@ -1175,10 +1173,10 @@ argp.add_argument('--arch',
                   help='Selects architecture to target. For some platforms "default" is the only supported choice.')
 argp.add_argument('--compiler',
                   choices=['default',
-                           'gcc4.4', 'gcc4.6', 'gcc4.8', 'gcc4.9', 'gcc5.3',
+                           'gcc4.4', 'gcc4.6', 'gcc4.8', 'gcc4.9', 'gcc5.3', 'gcc_musl',
                            'clang3.4', 'clang3.5', 'clang3.6', 'clang3.7',
                            'vs2013', 'vs2015',
-                           'python2.7', 'python3.4', 'python3.5', 'python3.6', 'pypy', 'pypy3',
+                           'python2.7', 'python3.4', 'python3.5', 'python3.6', 'pypy', 'pypy3', 'python_alpine',
                            'node0.12', 'node4', 'node5', 'node6', 'node7',
                            'electron1.3',
                            'coreclr',
diff --git a/tools/run_tests/run_tests_matrix.py b/tools/run_tests/run_tests_matrix.py
index 6c1d4bd15dd7938f6e2a84208be8d135c3feb5ad..a00d84fd9a77f8f4d75c9bf483ae163a60db8cd8 100755
--- a/tools/run_tests/run_tests_matrix.py
+++ b/tools/run_tests/run_tests_matrix.py
@@ -187,7 +187,7 @@ def _create_portability_test_jobs(extra_args=[], inner_jobs=_DEFAULT_INNER_JOBS)
                               inner_jobs=inner_jobs)
 
   # portability C and C++ on x64
-  for compiler in ['gcc4.4', 'gcc4.6', 'gcc5.3',
+  for compiler in ['gcc4.4', 'gcc4.6', 'gcc5.3', 'gcc_musl',
                    'clang3.5', 'clang3.6', 'clang3.7']:
     test_jobs += _generate_jobs(languages=['c'],
                                 configs=['dbg'],
@@ -198,7 +198,7 @@ def _create_portability_test_jobs(extra_args=[], inner_jobs=_DEFAULT_INNER_JOBS)
                                 extra_args=extra_args,
                                 inner_jobs=inner_jobs)
 
-  for compiler in ['gcc4.8', 'gcc5.3',
+  for compiler in ['gcc4.8', 'gcc5.3', 'gcc_musl',
                    'clang3.5', 'clang3.6', 'clang3.7']:
     test_jobs += _generate_jobs(languages=['c++'],
                                 configs=['dbg'],
@@ -257,6 +257,15 @@ def _create_portability_test_jobs(extra_args=[], inner_jobs=_DEFAULT_INNER_JOBS)
                               extra_args=extra_args,
                               inner_jobs=inner_jobs)
 
+  test_jobs += _generate_jobs(languages=['python'],
+                              configs=['dbg'],
+                              platforms=['linux'],
+                              arch='default',
+                              compiler='python_alpine',
+                              labels=['portability'],
+                              extra_args=extra_args,
+                              inner_jobs=inner_jobs)
+
   test_jobs += _generate_jobs(languages=['csharp'],
                               configs=['dbg'],
                               platforms=['linux'],
diff --git a/tools/run_tests/sanity/check_submodules.sh b/tools/run_tests/sanity/check_submodules.sh
index 38dfe277ae3f8e4c7909bfd7c659dae260a001f8..eaf5a0580e5e4ac88873da7e8aacece64c380018 100755
--- a/tools/run_tests/sanity/check_submodules.sh
+++ b/tools/run_tests/sanity/check_submodules.sh
@@ -45,8 +45,8 @@ cat << EOF | awk '{ print $1 }' | sort > $want_submodules
  78684e5b222645828ca302e56b40b9daff2b2d27 third_party/boringssl (78684e5)
  886e7d75368e3f4fab3f4d0d3584e4abfc557755 third_party/boringssl-with-bazel (version_for_cocoapods_7.0-857-g886e7d7)
  30dbc81fb5ffdc98ea9b14b1918bfe4e8779b26e third_party/gflags (v2.2.0)
- c99458533a9b4c743ed51537e25989ea55944908 third_party/googletest (release-1.7.0)
- 593e917c176b5bc5aafa57bf9f6030d749d91cd5 third_party/protobuf (v3.1.0-alpha-1-326-g593e917)
+ ec44c6c1675c25b9827aacd08c02433cccde7780 third_party/googletest (release-1.8.0)
+ 4a0dd03e52e09332c8fd0f8f26a8e0ae9f911182 third_party/protobuf (v3.1.0-alpha-1-548-g4a0dd03e)
  bcad91771b7f0bff28a1cac1981d7ef2b9bcef3c third_party/thrift (bcad917)
  50893291621658f355bc5b4d450a8d06a563053d third_party/zlib (v1.2.8)
  7691f773af79bf75a62d1863fd0f13ebf9dc51b1 third_party/cares/cares (1.12.0)
diff --git a/vsprojects/vcxproj/grpc++/grpc++.vcxproj b/vsprojects/vcxproj/grpc++/grpc++.vcxproj
index caa22a019db270e2b66205a92d81b7c31807d0aa..cae44c5e2343723991d0e36a2436672e6f596c8b 100644
--- a/vsprojects/vcxproj/grpc++/grpc++.vcxproj
+++ b/vsprojects/vcxproj/grpc++/grpc++.vcxproj
@@ -412,6 +412,7 @@
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\iomgr_internal.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\iomgr_posix.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\load_file.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\lockfree_event.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\network_status_tracker.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\polling_entity.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\pollset.h" />
@@ -647,6 +648,8 @@
     </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\load_file.c">
     </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\lockfree_event.c">
+    </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\network_status_tracker.c">
     </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\polling_entity.c">
diff --git a/vsprojects/vcxproj/grpc++/grpc++.vcxproj.filters b/vsprojects/vcxproj/grpc++/grpc++.vcxproj.filters
index 6fc1c969309cf975e6b74ed248012082d41cf62c..36da089470b132b9b0d7ee6647fae623ec8a6c69 100644
--- a/vsprojects/vcxproj/grpc++/grpc++.vcxproj.filters
+++ b/vsprojects/vcxproj/grpc++/grpc++.vcxproj.filters
@@ -232,6 +232,9 @@
     <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\load_file.c">
       <Filter>src\core\lib\iomgr</Filter>
     </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\lockfree_event.c">
+      <Filter>src\core\lib\iomgr</Filter>
+    </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\network_status_tracker.c">
       <Filter>src\core\lib\iomgr</Filter>
     </ClCompile>
@@ -968,6 +971,9 @@
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\load_file.h">
       <Filter>src\core\lib\iomgr</Filter>
     </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\lockfree_event.h">
+      <Filter>src\core\lib\iomgr</Filter>
+    </ClInclude>
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\network_status_tracker.h">
       <Filter>src\core\lib\iomgr</Filter>
     </ClInclude>
diff --git a/vsprojects/vcxproj/grpc++_unsecure/grpc++_unsecure.vcxproj b/vsprojects/vcxproj/grpc++_unsecure/grpc++_unsecure.vcxproj
index 674818182e879a5704062be1d822a65fa997f936..4d284006e677d86706ede88718811bb270d90031 100644
--- a/vsprojects/vcxproj/grpc++_unsecure/grpc++_unsecure.vcxproj
+++ b/vsprojects/vcxproj/grpc++_unsecure/grpc++_unsecure.vcxproj
@@ -406,6 +406,7 @@
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\iomgr_internal.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\iomgr_posix.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\load_file.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\lockfree_event.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\network_status_tracker.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\polling_entity.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\pollset.h" />
@@ -631,6 +632,8 @@
     </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\load_file.c">
     </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\lockfree_event.c">
+    </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\network_status_tracker.c">
     </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\polling_entity.c">
diff --git a/vsprojects/vcxproj/grpc++_unsecure/grpc++_unsecure.vcxproj.filters b/vsprojects/vcxproj/grpc++_unsecure/grpc++_unsecure.vcxproj.filters
index 2b9a5b13c1a9fcaec79101cc432126cc4d8c9172..9d641553a2b499822800778dae96e8d53fcfdd0c 100644
--- a/vsprojects/vcxproj/grpc++_unsecure/grpc++_unsecure.vcxproj.filters
+++ b/vsprojects/vcxproj/grpc++_unsecure/grpc++_unsecure.vcxproj.filters
@@ -217,6 +217,9 @@
     <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\load_file.c">
       <Filter>src\core\lib\iomgr</Filter>
     </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\lockfree_event.c">
+      <Filter>src\core\lib\iomgr</Filter>
+    </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\network_status_tracker.c">
       <Filter>src\core\lib\iomgr</Filter>
     </ClCompile>
@@ -935,6 +938,9 @@
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\load_file.h">
       <Filter>src\core\lib\iomgr</Filter>
     </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\lockfree_event.h">
+      <Filter>src\core\lib\iomgr</Filter>
+    </ClInclude>
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\network_status_tracker.h">
       <Filter>src\core\lib\iomgr</Filter>
     </ClInclude>
diff --git a/vsprojects/vcxproj/grpc/grpc.vcxproj b/vsprojects/vcxproj/grpc/grpc.vcxproj
index 3b3a08082af463a8eb6de1c9444bbb9bc13ab3bd..a956a4f2be3fc3bfc584d8f0119569134e364138 100644
--- a/vsprojects/vcxproj/grpc/grpc.vcxproj
+++ b/vsprojects/vcxproj/grpc/grpc.vcxproj
@@ -335,6 +335,7 @@
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\iomgr_internal.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\iomgr_posix.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\load_file.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\lockfree_event.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\network_status_tracker.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\polling_entity.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\pollset.h" />
@@ -579,6 +580,8 @@
     </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\load_file.c">
     </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\lockfree_event.c">
+    </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\network_status_tracker.c">
     </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\polling_entity.c">
diff --git a/vsprojects/vcxproj/grpc/grpc.vcxproj.filters b/vsprojects/vcxproj/grpc/grpc.vcxproj.filters
index 1274bbd9167563bbb9d017e4de18129ce7938cae..2ccac30d7adf53161a119f27477819c1437b721a 100644
--- a/vsprojects/vcxproj/grpc/grpc.vcxproj.filters
+++ b/vsprojects/vcxproj/grpc/grpc.vcxproj.filters
@@ -112,6 +112,9 @@
     <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\load_file.c">
       <Filter>src\core\lib\iomgr</Filter>
     </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\lockfree_event.c">
+      <Filter>src\core\lib\iomgr</Filter>
+    </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\network_status_tracker.c">
       <Filter>src\core\lib\iomgr</Filter>
     </ClCompile>
@@ -905,6 +908,9 @@
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\load_file.h">
       <Filter>src\core\lib\iomgr</Filter>
     </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\lockfree_event.h">
+      <Filter>src\core\lib\iomgr</Filter>
+    </ClInclude>
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\network_status_tracker.h">
       <Filter>src\core\lib\iomgr</Filter>
     </ClInclude>
diff --git a/vsprojects/vcxproj/grpc_test_util/grpc_test_util.vcxproj b/vsprojects/vcxproj/grpc_test_util/grpc_test_util.vcxproj
index c675cda122fb30c4d69d4daba3546d9a4d4b8d4c..b1db7e5d15d541c711c765834a7fe2a9d0197c70 100644
--- a/vsprojects/vcxproj/grpc_test_util/grpc_test_util.vcxproj
+++ b/vsprojects/vcxproj/grpc_test_util/grpc_test_util.vcxproj
@@ -230,6 +230,7 @@
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\iomgr_internal.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\iomgr_posix.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\load_file.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\lockfree_event.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\network_status_tracker.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\polling_entity.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\pollset.h" />
@@ -419,6 +420,8 @@
     </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\load_file.c">
     </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\lockfree_event.c">
+    </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\network_status_tracker.c">
     </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\polling_entity.c">
diff --git a/vsprojects/vcxproj/grpc_test_util/grpc_test_util.vcxproj.filters b/vsprojects/vcxproj/grpc_test_util/grpc_test_util.vcxproj.filters
index c6bd2d6c9f1e45e03d311160b6b926b627186140..a7ecbea87c7e0028e107e72513fc5f65ba3d5708 100644
--- a/vsprojects/vcxproj/grpc_test_util/grpc_test_util.vcxproj.filters
+++ b/vsprojects/vcxproj/grpc_test_util/grpc_test_util.vcxproj.filters
@@ -169,6 +169,9 @@
     <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\load_file.c">
       <Filter>src\core\lib\iomgr</Filter>
     </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\lockfree_event.c">
+      <Filter>src\core\lib\iomgr</Filter>
+    </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\network_status_tracker.c">
       <Filter>src\core\lib\iomgr</Filter>
     </ClCompile>
@@ -680,6 +683,9 @@
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\load_file.h">
       <Filter>src\core\lib\iomgr</Filter>
     </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\lockfree_event.h">
+      <Filter>src\core\lib\iomgr</Filter>
+    </ClInclude>
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\network_status_tracker.h">
       <Filter>src\core\lib\iomgr</Filter>
     </ClInclude>
diff --git a/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj b/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj
index e1f8eb7c170c3717104ebde7d746115f787c43a9..e3e62da213ee9c54fe97551fb8c227bd9ff50a10 100644
--- a/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj
+++ b/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj
@@ -325,6 +325,7 @@
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\iomgr_internal.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\iomgr_posix.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\load_file.h" />
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\lockfree_event.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\network_status_tracker.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\polling_entity.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\pollset.h" />
@@ -547,6 +548,8 @@
     </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\load_file.c">
     </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\lockfree_event.c">
+    </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\network_status_tracker.c">
     </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\polling_entity.c">
diff --git a/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj.filters b/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj.filters
index c244e8605365793e82363845a198caaaea09ddf4..e79d212f9c42db19c0efaa412f3ac937e9c51059 100644
--- a/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj.filters
+++ b/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj.filters
@@ -115,6 +115,9 @@
     <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\load_file.c">
       <Filter>src\core\lib\iomgr</Filter>
     </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\lockfree_event.c">
+      <Filter>src\core\lib\iomgr</Filter>
+    </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\lib\iomgr\network_status_tracker.c">
       <Filter>src\core\lib\iomgr</Filter>
     </ClCompile>
@@ -818,6 +821,9 @@
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\load_file.h">
       <Filter>src\core\lib\iomgr</Filter>
     </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\lockfree_event.h">
+      <Filter>src\core\lib\iomgr</Filter>
+    </ClInclude>
     <ClInclude Include="$(SolutionDir)\..\src\core\lib\iomgr\network_status_tracker.h">
       <Filter>src\core\lib\iomgr</Filter>
     </ClInclude>