Merge pull request #4926 from gitter-badger/gitter-badge

Add a Gitter chat badge to README.md
diff --git a/.gitignore b/.gitignore
index cc70659..9a1dc00 100644
--- a/.gitignore
+++ b/.gitignore
@@ -5,6 +5,7 @@
 objs
 
 # Python items
+python_build/
 .coverage*
 .eggs
 .tox
@@ -12,6 +13,10 @@
 dist/
 *.egg
 
+# Node installation output
+node_modules/
+src/node/extension_binary/
+
 # gcov coverage data
 reports
 coverage
@@ -40,6 +45,9 @@
 # Makefile's cache
 cache.mk
 
+# Ruby's local gem information
+Gemfile.lock
+
 # Temporary test reports
 report.xml
 latency_trace.txt
@@ -56,7 +64,7 @@
 .ycm_extra_conf.py
 
 # XCode
-build/
+^build/
 *.pbxuser
 !default.pbxuser
 *.mode1v3
diff --git a/.gitmodules b/.gitmodules
index 4ca1b8d..008bc5f 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -4,7 +4,7 @@
 [submodule "third_party/protobuf"]
 	path = third_party/protobuf
 	url = https://github.com/google/protobuf.git
-	branch = v3.0.0-alpha-4.1
+	branch = v3.0.0-beta-2
 [submodule "third_party/gflags"]
 	path = third_party/gflags
 	url = https://github.com/gflags/gflags.git
diff --git a/BUILD b/BUILD
index fa19d3d..72d5caa 100644
--- a/BUILD
+++ b/BUILD
@@ -84,6 +84,7 @@
     "src/core/support/string_posix.c",
     "src/core/support/string_win32.c",
     "src/core/support/subprocess_posix.c",
+    "src/core/support/subprocess_windows.c",
     "src/core/support/sync.c",
     "src/core/support/sync_posix.c",
     "src/core/support/sync_win32.c",
@@ -95,6 +96,7 @@
     "src/core/support/time_precise.c",
     "src/core/support/time_win32.c",
     "src/core/support/tls_pthread.c",
+    "src/core/support/wrap_memcpy.c",
   ],
   hdrs = [
     "include/grpc/support/alloc.h",
@@ -125,6 +127,20 @@
     "include/grpc/support/tls_msvc.h",
     "include/grpc/support/tls_pthread.h",
     "include/grpc/support/useful.h",
+    "include/grpc/impl/codegen/alloc.h",
+    "include/grpc/impl/codegen/atm.h",
+    "include/grpc/impl/codegen/atm_gcc_atomic.h",
+    "include/grpc/impl/codegen/atm_gcc_sync.h",
+    "include/grpc/impl/codegen/atm_win32.h",
+    "include/grpc/impl/codegen/log.h",
+    "include/grpc/impl/codegen/port_platform.h",
+    "include/grpc/impl/codegen/slice.h",
+    "include/grpc/impl/codegen/slice_buffer.h",
+    "include/grpc/impl/codegen/sync.h",
+    "include/grpc/impl/codegen/sync_generic.h",
+    "include/grpc/impl/codegen/sync_posix.h",
+    "include/grpc/impl/codegen/sync_win32.h",
+    "include/grpc/impl/codegen/time.h",
   ],
   includes = [
     "include",
@@ -266,7 +282,6 @@
     "src/core/transport/transport.h",
     "src/core/transport/transport_impl.h",
     "src/core/census/aggregation.h",
-    "src/core/census/context.h",
     "src/core/census/rpc_metric_id.h",
     "src/core/httpcli/httpcli_security_connector.c",
     "src/core/security/base64.c",
@@ -367,6 +382,7 @@
     "src/core/json/json_reader.c",
     "src/core/json/json_string.c",
     "src/core/json/json_writer.c",
+    "src/core/surface/alarm.c",
     "src/core/surface/api_trace.c",
     "src/core/surface/byte_buffer.c",
     "src/core/surface/byte_buffer_reader.c",
@@ -418,11 +434,17 @@
     "src/core/census/context.c",
     "src/core/census/initialize.c",
     "src/core/census/operation.c",
-    "src/core/census/tag_set.c",
+    "src/core/census/placeholders.c",
     "src/core/census/tracing.c",
   ],
   hdrs = [
     "include/grpc/grpc_security.h",
+    "include/grpc/impl/codegen/byte_buffer.h",
+    "include/grpc/impl/codegen/compression_types.h",
+    "include/grpc/impl/codegen/connectivity_state.h",
+    "include/grpc/impl/codegen/grpc_types.h",
+    "include/grpc/impl/codegen/propagation_bits.h",
+    "include/grpc/impl/codegen/status.h",
     "include/grpc/byte_buffer.h",
     "include/grpc/byte_buffer_reader.h",
     "include/grpc/compression.h",
@@ -562,7 +584,6 @@
     "src/core/transport/transport.h",
     "src/core/transport/transport_impl.h",
     "src/core/census/aggregation.h",
-    "src/core/census/context.h",
     "src/core/census/rpc_metric_id.h",
     "src/core/surface/init_unsecure.c",
     "src/core/census/grpc_context.c",
@@ -643,6 +664,7 @@
     "src/core/json/json_reader.c",
     "src/core/json/json_string.c",
     "src/core/json/json_writer.c",
+    "src/core/surface/alarm.c",
     "src/core/surface/api_trace.c",
     "src/core/surface/byte_buffer.c",
     "src/core/surface/byte_buffer_reader.c",
@@ -694,7 +716,7 @@
     "src/core/census/context.c",
     "src/core/census/initialize.c",
     "src/core/census/operation.c",
-    "src/core/census/tag_set.c",
+    "src/core/census/placeholders.c",
     "src/core/census/tracing.c",
   ],
   hdrs = [
@@ -703,6 +725,12 @@
     "include/grpc/compression.h",
     "include/grpc/grpc.h",
     "include/grpc/status.h",
+    "include/grpc/impl/codegen/byte_buffer.h",
+    "include/grpc/impl/codegen/compression_types.h",
+    "include/grpc/impl/codegen/connectivity_state.h",
+    "include/grpc/impl/codegen/grpc_types.h",
+    "include/grpc/impl/codegen/propagation_bits.h",
+    "include/grpc/impl/codegen/status.h",
     "include/grpc/census.h",
   ],
   includes = [
@@ -762,6 +790,7 @@
     "src/cpp/client/credentials.cc",
     "src/cpp/client/generic_stub.cc",
     "src/cpp/client/insecure_credentials.cc",
+    "src/cpp/common/alarm.cc",
     "src/cpp/common/call.cc",
     "src/cpp/common/channel_arguments.cc",
     "src/cpp/common/completion_queue.cc",
@@ -781,8 +810,10 @@
     "src/cpp/util/status.cc",
     "src/cpp/util/string_ref.cc",
     "src/cpp/util/time.cc",
+    "src/cpp/codegen/grpc_library.cc",
   ],
   hdrs = [
+    "include/grpc++/alarm.h",
     "include/grpc++/channel.h",
     "include/grpc++/client_context.h",
     "include/grpc++/completion_queue.h",
@@ -793,6 +824,7 @@
     "include/grpc++/impl/call.h",
     "include/grpc++/impl/client_unary_call.h",
     "include/grpc++/impl/grpc_library.h",
+    "include/grpc++/impl/method_handler_impl.h",
     "include/grpc++/impl/proto_utils.h",
     "include/grpc++/impl/rpc_method.h",
     "include/grpc++/impl/rpc_service_method.h",
@@ -825,6 +857,36 @@
     "include/grpc++/support/stub_options.h",
     "include/grpc++/support/sync_stream.h",
     "include/grpc++/support/time.h",
+    "include/grpc++/impl/codegen/async_stream.h",
+    "include/grpc++/impl/codegen/async_unary_call.h",
+    "include/grpc++/impl/codegen/call.h",
+    "include/grpc++/impl/codegen/call_hook.h",
+    "include/grpc++/impl/codegen/channel_interface.h",
+    "include/grpc++/impl/codegen/client_context.h",
+    "include/grpc++/impl/codegen/client_unary_call.h",
+    "include/grpc++/impl/codegen/completion_queue.h",
+    "include/grpc++/impl/codegen/completion_queue_tag.h",
+    "include/grpc++/impl/codegen/config.h",
+    "include/grpc++/impl/codegen/config_protobuf.h",
+    "include/grpc++/impl/codegen/grpc_library.h",
+    "include/grpc++/impl/codegen/method_handler_impl.h",
+    "include/grpc++/impl/codegen/proto_utils.h",
+    "include/grpc++/impl/codegen/rpc_method.h",
+    "include/grpc++/impl/codegen/rpc_service_method.h",
+    "include/grpc++/impl/codegen/security/auth_context.h",
+    "include/grpc++/impl/codegen/serialization_traits.h",
+    "include/grpc++/impl/codegen/server_context.h",
+    "include/grpc++/impl/codegen/server_interface.h",
+    "include/grpc++/impl/codegen/service_type.h",
+    "include/grpc++/impl/codegen/status.h",
+    "include/grpc++/impl/codegen/status_code_enum.h",
+    "include/grpc++/impl/codegen/string_ref.h",
+    "include/grpc++/impl/codegen/stub_options.h",
+    "include/grpc++/impl/codegen/sync.h",
+    "include/grpc++/impl/codegen/sync_cxx11.h",
+    "include/grpc++/impl/codegen/sync_no_cxx11.h",
+    "include/grpc++/impl/codegen/sync_stream.h",
+    "include/grpc++/impl/codegen/time.h",
   ],
   includes = [
     "include",
@@ -833,7 +895,6 @@
   deps = [
     "//external:libssl",
     "//external:protobuf_clib",
-    ":gpr",
     ":grpc",
   ],
 )
@@ -855,6 +916,7 @@
     "src/cpp/client/credentials.cc",
     "src/cpp/client/generic_stub.cc",
     "src/cpp/client/insecure_credentials.cc",
+    "src/cpp/common/alarm.cc",
     "src/cpp/common/call.cc",
     "src/cpp/common/channel_arguments.cc",
     "src/cpp/common/completion_queue.cc",
@@ -874,8 +936,10 @@
     "src/cpp/util/status.cc",
     "src/cpp/util/string_ref.cc",
     "src/cpp/util/time.cc",
+    "src/cpp/codegen/grpc_library.cc",
   ],
   hdrs = [
+    "include/grpc++/alarm.h",
     "include/grpc++/channel.h",
     "include/grpc++/client_context.h",
     "include/grpc++/completion_queue.h",
@@ -886,6 +950,7 @@
     "include/grpc++/impl/call.h",
     "include/grpc++/impl/client_unary_call.h",
     "include/grpc++/impl/grpc_library.h",
+    "include/grpc++/impl/method_handler_impl.h",
     "include/grpc++/impl/proto_utils.h",
     "include/grpc++/impl/rpc_method.h",
     "include/grpc++/impl/rpc_service_method.h",
@@ -918,6 +983,36 @@
     "include/grpc++/support/stub_options.h",
     "include/grpc++/support/sync_stream.h",
     "include/grpc++/support/time.h",
+    "include/grpc++/impl/codegen/async_stream.h",
+    "include/grpc++/impl/codegen/async_unary_call.h",
+    "include/grpc++/impl/codegen/call.h",
+    "include/grpc++/impl/codegen/call_hook.h",
+    "include/grpc++/impl/codegen/channel_interface.h",
+    "include/grpc++/impl/codegen/client_context.h",
+    "include/grpc++/impl/codegen/client_unary_call.h",
+    "include/grpc++/impl/codegen/completion_queue.h",
+    "include/grpc++/impl/codegen/completion_queue_tag.h",
+    "include/grpc++/impl/codegen/config.h",
+    "include/grpc++/impl/codegen/config_protobuf.h",
+    "include/grpc++/impl/codegen/grpc_library.h",
+    "include/grpc++/impl/codegen/method_handler_impl.h",
+    "include/grpc++/impl/codegen/proto_utils.h",
+    "include/grpc++/impl/codegen/rpc_method.h",
+    "include/grpc++/impl/codegen/rpc_service_method.h",
+    "include/grpc++/impl/codegen/security/auth_context.h",
+    "include/grpc++/impl/codegen/serialization_traits.h",
+    "include/grpc++/impl/codegen/server_context.h",
+    "include/grpc++/impl/codegen/server_interface.h",
+    "include/grpc++/impl/codegen/service_type.h",
+    "include/grpc++/impl/codegen/status.h",
+    "include/grpc++/impl/codegen/status_code_enum.h",
+    "include/grpc++/impl/codegen/string_ref.h",
+    "include/grpc++/impl/codegen/stub_options.h",
+    "include/grpc++/impl/codegen/sync.h",
+    "include/grpc++/impl/codegen/sync_cxx11.h",
+    "include/grpc++/impl/codegen/sync_no_cxx11.h",
+    "include/grpc++/impl/codegen/sync_stream.h",
+    "include/grpc++/impl/codegen/time.h",
   ],
   includes = [
     "include",
@@ -954,8 +1049,59 @@
     "src/compiler/objective_c_generator.cc",
     "src/compiler/python_generator.cc",
     "src/compiler/ruby_generator.cc",
+    "src/cpp/codegen/grpc_library.cc",
   ],
   hdrs = [
+    "include/grpc++/impl/codegen/async_stream.h",
+    "include/grpc++/impl/codegen/async_unary_call.h",
+    "include/grpc++/impl/codegen/call.h",
+    "include/grpc++/impl/codegen/call_hook.h",
+    "include/grpc++/impl/codegen/channel_interface.h",
+    "include/grpc++/impl/codegen/client_context.h",
+    "include/grpc++/impl/codegen/client_unary_call.h",
+    "include/grpc++/impl/codegen/completion_queue.h",
+    "include/grpc++/impl/codegen/completion_queue_tag.h",
+    "include/grpc++/impl/codegen/config.h",
+    "include/grpc++/impl/codegen/config_protobuf.h",
+    "include/grpc++/impl/codegen/grpc_library.h",
+    "include/grpc++/impl/codegen/method_handler_impl.h",
+    "include/grpc++/impl/codegen/proto_utils.h",
+    "include/grpc++/impl/codegen/rpc_method.h",
+    "include/grpc++/impl/codegen/rpc_service_method.h",
+    "include/grpc++/impl/codegen/security/auth_context.h",
+    "include/grpc++/impl/codegen/serialization_traits.h",
+    "include/grpc++/impl/codegen/server_context.h",
+    "include/grpc++/impl/codegen/server_interface.h",
+    "include/grpc++/impl/codegen/service_type.h",
+    "include/grpc++/impl/codegen/status.h",
+    "include/grpc++/impl/codegen/status_code_enum.h",
+    "include/grpc++/impl/codegen/string_ref.h",
+    "include/grpc++/impl/codegen/stub_options.h",
+    "include/grpc++/impl/codegen/sync.h",
+    "include/grpc++/impl/codegen/sync_cxx11.h",
+    "include/grpc++/impl/codegen/sync_no_cxx11.h",
+    "include/grpc++/impl/codegen/sync_stream.h",
+    "include/grpc++/impl/codegen/time.h",
+    "include/grpc/impl/codegen/byte_buffer.h",
+    "include/grpc/impl/codegen/compression_types.h",
+    "include/grpc/impl/codegen/connectivity_state.h",
+    "include/grpc/impl/codegen/grpc_types.h",
+    "include/grpc/impl/codegen/propagation_bits.h",
+    "include/grpc/impl/codegen/status.h",
+    "include/grpc/impl/codegen/alloc.h",
+    "include/grpc/impl/codegen/atm.h",
+    "include/grpc/impl/codegen/atm_gcc_atomic.h",
+    "include/grpc/impl/codegen/atm_gcc_sync.h",
+    "include/grpc/impl/codegen/atm_win32.h",
+    "include/grpc/impl/codegen/log.h",
+    "include/grpc/impl/codegen/port_platform.h",
+    "include/grpc/impl/codegen/slice.h",
+    "include/grpc/impl/codegen/slice_buffer.h",
+    "include/grpc/impl/codegen/sync.h",
+    "include/grpc/impl/codegen/sync_generic.h",
+    "include/grpc/impl/codegen/sync_posix.h",
+    "include/grpc/impl/codegen/sync_win32.h",
+    "include/grpc/impl/codegen/time.h",
   ],
   includes = [
     "include",
@@ -1019,6 +1165,7 @@
     "src/core/support/string_posix.c",
     "src/core/support/string_win32.c",
     "src/core/support/subprocess_posix.c",
+    "src/core/support/subprocess_windows.c",
     "src/core/support/sync.c",
     "src/core/support/sync_posix.c",
     "src/core/support/sync_win32.c",
@@ -1030,6 +1177,7 @@
     "src/core/support/time_precise.c",
     "src/core/support/time_win32.c",
     "src/core/support/tls_pthread.c",
+    "src/core/support/wrap_memcpy.c",
   ],
   hdrs = [
     "include/grpc/support/alloc.h",
@@ -1060,6 +1208,20 @@
     "include/grpc/support/tls_msvc.h",
     "include/grpc/support/tls_pthread.h",
     "include/grpc/support/useful.h",
+    "include/grpc/impl/codegen/alloc.h",
+    "include/grpc/impl/codegen/atm.h",
+    "include/grpc/impl/codegen/atm_gcc_atomic.h",
+    "include/grpc/impl/codegen/atm_gcc_sync.h",
+    "include/grpc/impl/codegen/atm_win32.h",
+    "include/grpc/impl/codegen/log.h",
+    "include/grpc/impl/codegen/port_platform.h",
+    "include/grpc/impl/codegen/slice.h",
+    "include/grpc/impl/codegen/slice_buffer.h",
+    "include/grpc/impl/codegen/sync.h",
+    "include/grpc/impl/codegen/sync_generic.h",
+    "include/grpc/impl/codegen/sync_posix.h",
+    "include/grpc/impl/codegen/sync_win32.h",
+    "include/grpc/impl/codegen/time.h",
     "src/core/profiling/timers.h",
     "src/core/support/block_annotate.h",
     "src/core/support/env.h",
@@ -1182,6 +1344,7 @@
     "src/core/json/json_reader.c",
     "src/core/json/json_string.c",
     "src/core/json/json_writer.c",
+    "src/core/surface/alarm.c",
     "src/core/surface/api_trace.c",
     "src/core/surface/byte_buffer.c",
     "src/core/surface/byte_buffer_reader.c",
@@ -1233,11 +1396,17 @@
     "src/core/census/context.c",
     "src/core/census/initialize.c",
     "src/core/census/operation.c",
-    "src/core/census/tag_set.c",
+    "src/core/census/placeholders.c",
     "src/core/census/tracing.c",
   ],
   hdrs = [
     "include/grpc/grpc_security.h",
+    "include/grpc/impl/codegen/byte_buffer.h",
+    "include/grpc/impl/codegen/compression_types.h",
+    "include/grpc/impl/codegen/connectivity_state.h",
+    "include/grpc/impl/codegen/grpc_types.h",
+    "include/grpc/impl/codegen/propagation_bits.h",
+    "include/grpc/impl/codegen/status.h",
     "include/grpc/byte_buffer.h",
     "include/grpc/byte_buffer_reader.h",
     "include/grpc/compression.h",
@@ -1372,7 +1541,6 @@
     "src/core/transport/transport.h",
     "src/core/transport/transport_impl.h",
     "src/core/census/aggregation.h",
-    "src/core/census/context.h",
     "src/core/census/rpc_metric_id.h",
   ],
   includes = [
diff --git a/Makefile b/Makefile
index f753921..3c215b3 100644
--- a/Makefile
+++ b/Makefile
@@ -41,9 +41,7 @@
 
 # Basic platform detection
 HOST_SYSTEM = $(shell uname | cut -f 1 -d_)
-ifeq ($(SYSTEM),)
-SYSTEM = $(HOST_SYSTEM)
-endif
+SYSTEM ?= $(HOST_SYSTEM)
 ifeq ($(SYSTEM),MSYS)
 SYSTEM = MINGW32
 endif
@@ -95,7 +93,6 @@
 LD_opt = $(DEFAULT_CC)
 LDXX_opt = $(DEFAULT_CXX)
 CPPFLAGS_opt = -O2
-LDFLAGS_opt = -rdynamic
 DEFINES_opt = NDEBUG
 
 VALID_CONFIG_basicprof = 1
@@ -122,8 +119,7 @@
 CXX_asan-noleaks = clang++
 LD_asan-noleaks = clang
 LDXX_asan-noleaks = clang++
-CFLAGS_asan-noleaks = -O0 -fsanitize=address -fno-omit-frame-pointer -Wno-unused-command-line-argument
-CXXFLAGS_asan-noleaks = -O0 -fsanitize=address -fno-omit-frame-pointer -Wno-unused-command-line-argument
+CPPFLAGS_asan-noleaks = -O0 -fsanitize=address -fno-omit-frame-pointer -Wno-unused-command-line-argument -DGPR_NO_DIRECT_SYSCALLS
 LDFLAGS_asan-noleaks = -fsanitize=address
 DEFINES_asan-noleaks += GRPC_TEST_SLOWDOWN_BUILD_FACTOR=1.5
 
@@ -133,8 +129,7 @@
 CXX_ubsan = clang++
 LD_ubsan = clang
 LDXX_ubsan = clang++
-CFLAGS_ubsan = -O1 -fsanitize=undefined -fno-omit-frame-pointer -Wno-unused-command-line-argument
-CXXFLAGS_ubsan = -O1 -fsanitize=undefined -fno-omit-frame-pointer -Wno-unused-command-line-argument
+CPPFLAGS_ubsan = -O1 -fsanitize=undefined -fno-omit-frame-pointer -Wno-unused-command-line-argument
 LDFLAGS_ubsan = -fsanitize=undefined
 DEFINES_ubsan = NDEBUG
 DEFINES_ubsan += GRPC_TEST_SLOWDOWN_BUILD_FACTOR=1.5
@@ -145,7 +140,6 @@
 LD_dbg = $(DEFAULT_CC)
 LDXX_dbg = $(DEFAULT_CXX)
 CPPFLAGS_dbg = -O0
-LDFLAGS_dbg = -rdynamic
 DEFINES_dbg = _DEBUG DEBUG
 
 VALID_CONFIG_stapprof = 1
@@ -161,8 +155,7 @@
 CXX_gcov = g++
 LD_gcov = gcc
 LDXX_gcov = g++
-CFLAGS_gcov = -O0 -fprofile-arcs -ftest-coverage -Wno-return-type
-CXXFLAGS_gcov = -O0 -fprofile-arcs -ftest-coverage -Wno-return-type
+CPPFLAGS_gcov = -O0 -fprofile-arcs -ftest-coverage -Wno-return-type
 LDFLAGS_gcov = -fprofile-arcs -ftest-coverage -rdynamic
 DEFINES_gcov = _DEBUG DEBUG GPR_GCOV
 
@@ -182,8 +175,7 @@
 CXX_asan = clang++
 LD_asan = clang
 LDXX_asan = clang++
-CFLAGS_asan = -O0 -fsanitize=address -fno-omit-frame-pointer -Wno-unused-command-line-argument
-CXXFLAGS_asan = -O0 -fsanitize=address -fno-omit-frame-pointer -Wno-unused-command-line-argument
+CPPFLAGS_asan = -O0 -fsanitize=address -fno-omit-frame-pointer -Wno-unused-command-line-argument -DGPR_NO_DIRECT_SYSCALLS
 LDFLAGS_asan = -fsanitize=address
 DEFINES_asan += GRPC_TEST_SLOWDOWN_BUILD_FACTOR=1.5
 
@@ -193,8 +185,7 @@
 CXX_tsan = clang++
 LD_tsan = clang
 LDXX_tsan = clang++
-CFLAGS_tsan = -O0 -fsanitize=thread -fno-omit-frame-pointer -Wno-unused-command-line-argument -fPIE -pie
-CXXFLAGS_tsan = -O0 -fsanitize=thread -fno-omit-frame-pointer -Wno-unused-command-line-argument -fPIE -pie
+CPPFLAGS_tsan = -O0 -fsanitize=thread -fno-omit-frame-pointer -Wno-unused-command-line-argument -fPIE -pie -DGPR_NO_DIRECT_SYSCALLS
 LDFLAGS_tsan = -fsanitize=thread -fPIE -pie $(if $(JENKINS_BUILD),-Wl$(comma)-Ttext-segment=0x7e0000000000,)
 DEFINES_tsan += GRPC_TEST_SLOWDOWN_BUILD_FACTOR=2
 
@@ -204,11 +195,10 @@
 CXX_msan = clang++
 LD_msan = clang
 LDXX_msan = clang++
-CFLAGS_msan = -O0 -fsanitize=memory -fsanitize-memory-track-origins -fno-omit-frame-pointer -DGTEST_HAS_TR1_TUPLE=0 -DGTEST_USE_OWN_TR1_TUPLE=1 -Wno-unused-command-line-argument -fPIE -pie
-CXXFLAGS_msan = -O0 -fsanitize=memory -fsanitize-memory-track-origins -fno-omit-frame-pointer -DGTEST_HAS_TR1_TUPLE=0 -DGTEST_USE_OWN_TR1_TUPLE=1 -Wno-unused-command-line-argument -fPIE -pie
+CPPFLAGS_msan = -O0 -fsanitize=memory -fsanitize-memory-track-origins -fno-omit-frame-pointer -DGTEST_HAS_TR1_TUPLE=0 -DGTEST_USE_OWN_TR1_TUPLE=1 -Wno-unused-command-line-argument -fPIE -pie -DGPR_NO_DIRECT_SYSCALLS
 LDFLAGS_msan = -fsanitize=memory -DGTEST_HAS_TR1_TUPLE=0 -DGTEST_USE_OWN_TR1_TUPLE=1 -fPIE -pie $(if $(JENKINS_BUILD),-Wl$(comma)-Ttext-segment=0x7e0000000000,)
 DEFINES_msan = NDEBUG
-DEFINES_msan += GRPC_TEST_SLOWDOWN_BUILD_FACTOR=1.5
+DEFINES_msan += GRPC_TEST_SLOWDOWN_BUILD_FACTOR=2
 
 VALID_CONFIG_mutrace = 1
 CC_mutrace = $(DEFAULT_CC)
@@ -249,15 +239,21 @@
 LD = $(LD_$(CONFIG))
 endif
 LDXX ?= $(LDXX_$(CONFIG))
-ifeq ($(origin AR), default)
-AR = ar
-endif
 ifeq ($(SYSTEM),Linux)
+ifeq ($(origin AR), default)
+AR = ar rcs
+endif
 STRIP ?= strip --strip-unneeded
 else
 ifeq ($(SYSTEM),Darwin)
+ifeq ($(origin AR), default)
+AR = libtool -o
+endif
 STRIP ?= strip -x
 else
+ifeq ($(origin AR), default)
+AR = ar rcs
+endif
 STRIP ?= strip
 endif
 endif
@@ -305,8 +301,7 @@
 else
 CXXFLAGS += -std=c++0x
 endif
-CFLAGS += -g -Wall -Wextra -Werror -Wno-long-long -Wno-unused-parameter
-CXXFLAGS += -g -Wall -Wextra -Werror -Wno-long-long -Wno-unused-parameter
+CPPFLAGS += -g -Wall -Wextra -Werror -Wno-long-long -Wno-unused-parameter
 LDFLAGS += -g
 
 CPPFLAGS += $(CPPFLAGS_$(CONFIG))
@@ -347,12 +342,12 @@
 endif
 
 ifeq ($(SYSTEM),Linux)
-LIBS = rt m pthread
+LIBS = dl rt m pthread
 LDFLAGS += -pthread
 endif
 
 ifeq ($(SYSTEM),MINGW32)
-LIBS = m pthread
+LIBS = m pthread ws2_32
 LDFLAGS += -pthread
 endif
 
@@ -366,7 +361,7 @@
 Q = @
 endif
 
-VERSION = 0.13.0.0
+VERSION = 0.14.0-dev
 
 CPPFLAGS_NO_ARCH += $(addprefix -I, $(INCLUDES)) $(addprefix -D, $(DEFINES))
 CPPFLAGS += $(CPPFLAGS_NO_ARCH) $(ARCH_FLAGS)
@@ -396,26 +391,18 @@
 
 PC_TEMPLATE = prefix=$(prefix),exec_prefix=\$${prefix},includedir=\$${prefix}/include,libdir=\$${exec_prefix}/lib,,Name: $(PC_NAME),Description: $(PC_DESCRIPTION),Version: $(VERSION),Cflags: -I\$${includedir} $(PC_CFLAGS),Requires.private: $(PC_REQUIRES_PRIVATE),Libs: -L\$${libdir} $(PC_LIB),Libs.private: $(PC_LIBS_PRIVATE)
 
-# gpr .pc file
-PC_NAME = gRPC Portable Runtime
-PC_DESCRIPTION = gRPC Portable Runtime
-PC_CFLAGS = -pthread
-PC_REQUIRES_PRIVATE =
-PC_LIBS_PRIVATE = -lpthread
-PC_LIB = -lgpr
-ifneq ($(SYSTEM),Darwin)
-PC_LIBS_PRIVATE += -lrt
-endif
-GPR_PC_FILE := $(PC_TEMPLATE)
-
 ifeq ($(SYSTEM),MINGW32)
 SHARED_EXT = dll
-endif
-ifeq ($(SYSTEM),Darwin)
+SHARED_PREFIX =
+SHARED_VERSION = -0
+else ifeq ($(SYSTEM),Darwin)
 SHARED_EXT = dylib
-endif
-ifeq ($(SHARED_EXT),)
+SHARED_PREFIX = lib
+SHARED_VERSION =
+else
 SHARED_EXT = so.$(VERSION)
+SHARED_PREFIX = lib
+SHARED_VERSION =
 endif
 
 ifeq ($(wildcard .git),)
@@ -437,20 +424,20 @@
 OPENSSL_LIBS = ssl crypto
 endif
 
-OPENSSL_ALPN_CHECK_CMD = $(CC) $(CFLAGS) $(CPPFLAGS) -o $(TMPOUT) test/build/openssl-alpn.c $(addprefix -l, $(OPENSSL_LIBS)) $(LDFLAGS)
-OPENSSL_NPN_CHECK_CMD = $(CC) $(CFLAGS) $(CPPFLAGS) -o $(TMPOUT) test/build/openssl-npn.c $(addprefix -l, $(OPENSSL_LIBS)) $(LDFLAGS)
-ZLIB_CHECK_CMD = $(CC) $(CFLAGS) $(CPPFLAGS) -o $(TMPOUT) test/build/zlib.c -lz $(LDFLAGS)
-PROTOBUF_CHECK_CMD = $(CXX) $(CXXFLAGS) $(CPPFLAGS) -o $(TMPOUT) test/build/protobuf.cc -lprotobuf $(LDFLAGS)
+OPENSSL_ALPN_CHECK_CMD = $(CC) $(CPPFLAGS) $(CFLAGS) -o $(TMPOUT) test/build/openssl-alpn.c $(addprefix -l, $(OPENSSL_LIBS)) $(LDFLAGS)
+OPENSSL_NPN_CHECK_CMD = $(CC) $(CPPFLAGS) $(CFLAGS) -o $(TMPOUT) test/build/openssl-npn.c $(addprefix -l, $(OPENSSL_LIBS)) $(LDFLAGS)
+ZLIB_CHECK_CMD = $(CC) $(CPPFLAGS) $(CFLAGS) -o $(TMPOUT) test/build/zlib.c -lz $(LDFLAGS)
+PROTOBUF_CHECK_CMD = $(CXX) $(CPPFLAGS) $(CXXFLAGS) -o $(TMPOUT) test/build/protobuf.cc -lprotobuf $(LDFLAGS)
 
 endif # HAS_PKG_CONFIG
 
-PERFTOOLS_CHECK_CMD = $(CC) $(CFLAGS) $(CPPFLAGS) -o $(TMPOUT) test/build/perftools.c -lprofiler $(LDFLAGS)
+PERFTOOLS_CHECK_CMD = $(CC) $(CPPFLAGS) $(CFLAGS) -o $(TMPOUT) test/build/perftools.c -lprofiler $(LDFLAGS)
 
 PROTOC_CHECK_CMD = which protoc > /dev/null
 PROTOC_CHECK_VERSION_CMD = protoc --version | grep -q libprotoc.3
 DTRACE_CHECK_CMD = which dtrace > /dev/null
-SYSTEMTAP_HEADERS_CHECK_CMD = $(CC) $(CFLAGS) $(CPPFLAGS) -o $(TMPOUT) test/build/systemtap.c $(LDFLAGS)
-ZOOKEEPER_CHECK_CMD = $(CC) $(CFLAGS) $(CPPFLAGS) -o $(TMPOUT) test/build/zookeeper.c $(LDFLAGS) -lzookeeper_mt
+SYSTEMTAP_HEADERS_CHECK_CMD = $(CC) $(CPPFLAGS) $(CFLAGS) -o $(TMPOUT) test/build/systemtap.c $(LDFLAGS)
+ZOOKEEPER_CHECK_CMD = $(CC) $(CPPFLAGS) $(CFLAGS) -o $(TMPOUT) test/build/zookeeper.c $(LDFLAGS) -lzookeeper_mt
 
 ifndef REQUIRE_CUSTOM_LIBRARIES_$(CONFIG)
 HAS_SYSTEM_PERFTOOLS ?= $(shell $(PERFTOOLS_CHECK_CMD) 2> /dev/null && echo true || echo false)
@@ -544,7 +531,7 @@
 HAS_EMBEDDED_PROTOBUF = true
 endif
 
-PC_REQUIRES_GRPC = gpr
+PC_REQUIRES_GRPC =
 PC_LIBS_GRPC =
 
 ifeq ($(HAS_SYSTEM_ZLIB),false)
@@ -561,6 +548,7 @@
 ifeq ($(EMBED_ZLIB),true)
 ZLIB_DEP = $(LIBDIR)/$(CONFIG)/libz.a
 ZLIB_MERGE_LIBS = $(LIBDIR)/$(CONFIG)/libz.a
+ZLIB_MERGE_OBJS = $(LIBZ_OBJS)
 CPPFLAGS += -Ithird_party/zlib
 LDFLAGS += -L$(LIBDIR)/$(CONFIG)/zlib
 else
@@ -603,6 +591,7 @@
 ifeq ($(EMBED_OPENSSL),true)
 OPENSSL_DEP += $(LIBDIR)/$(CONFIG)/libboringssl.a
 OPENSSL_MERGE_LIBS += $(LIBDIR)/$(CONFIG)/libboringssl.a
+OPENSSL_MERGE_OBJS += $(LIBBORINGSSL_OBJS)
 # need to prefix these to ensure overriding system libraries
 CPPFLAGS := -Ithird_party/boringssl/include $(CPPFLAGS)
 else # EMBED_OPENSSL=false
@@ -643,7 +632,7 @@
 PC_LIB = -lgrpc
 GRPC_PC_FILE := $(PC_TEMPLATE)
 
-# gprc_unsecure .pc file
+# grpc_unsecure .pc file
 PC_NAME = gRPC unsecure
 PC_DESCRIPTION = high performance general RPC framework without SSL
 PC_CFLAGS =
@@ -652,7 +641,7 @@
 PC_LIB = -lgrpc
 GRPC_UNSECURE_PC_FILE := $(PC_TEMPLATE)
 
-# gprc_zookeeper .pc file
+# grpc_zookeeper .pc file
 PC_NAME = gRPC zookeeper
 PC_DESCRIPTION = gRPC's zookeeper plugin
 PC_CFLAGS =
@@ -831,10 +820,12 @@
 stop:
 	@false
 
+alarm_test: $(BINDIR)/$(CONFIG)/alarm_test
 algorithm_test: $(BINDIR)/$(CONFIG)/algorithm_test
 alloc_test: $(BINDIR)/$(CONFIG)/alloc_test
 alpn_test: $(BINDIR)/$(CONFIG)/alpn_test
 bin_encoder_test: $(BINDIR)/$(CONFIG)/bin_encoder_test
+census_context_test: $(BINDIR)/$(CONFIG)/census_context_test
 channel_create_test: $(BINDIR)/$(CONFIG)/channel_create_test
 chttp2_hpack_encoder_test: $(BINDIR)/$(CONFIG)/chttp2_hpack_encoder_test
 chttp2_status_conversion_test: $(BINDIR)/$(CONFIG)/chttp2_status_conversion_test
@@ -912,7 +903,6 @@
 sockaddr_resolver_test: $(BINDIR)/$(CONFIG)/sockaddr_resolver_test
 sockaddr_utils_test: $(BINDIR)/$(CONFIG)/sockaddr_utils_test
 socket_utils_test: $(BINDIR)/$(CONFIG)/socket_utils_test
-tag_set_test: $(BINDIR)/$(CONFIG)/tag_set_test
 tcp_client_posix_test: $(BINDIR)/$(CONFIG)/tcp_client_posix_test
 tcp_posix_test: $(BINDIR)/$(CONFIG)/tcp_posix_test
 tcp_server_posix_test: $(BINDIR)/$(CONFIG)/tcp_server_posix_test
@@ -927,6 +917,7 @@
 udp_server_test: $(BINDIR)/$(CONFIG)/udp_server_test
 uri_parser_test: $(BINDIR)/$(CONFIG)/uri_parser_test
 workqueue_test: $(BINDIR)/$(CONFIG)/workqueue_test
+alarm_cpp_test: $(BINDIR)/$(CONFIG)/alarm_cpp_test
 async_end2end_test: $(BINDIR)/$(CONFIG)/async_end2end_test
 async_streaming_ping_pong_test: $(BINDIR)/$(CONFIG)/async_streaming_ping_pong_test
 async_unary_ping_pong_test: $(BINDIR)/$(CONFIG)/async_unary_ping_pong_test
@@ -949,6 +940,7 @@
 grpc_objective_c_plugin: $(BINDIR)/$(CONFIG)/grpc_objective_c_plugin
 grpc_python_plugin: $(BINDIR)/$(CONFIG)/grpc_python_plugin
 grpc_ruby_plugin: $(BINDIR)/$(CONFIG)/grpc_ruby_plugin
+hybrid_end2end_test: $(BINDIR)/$(CONFIG)/hybrid_end2end_test
 interop_client: $(BINDIR)/$(CONFIG)/interop_client
 interop_server: $(BINDIR)/$(CONFIG)/interop_server
 interop_test: $(BINDIR)/$(CONFIG)/interop_test
@@ -1080,21 +1072,21 @@
 
 static: static_c static_cxx
 
-static_c: pc_c pc_c_unsecure cache.mk pc_gpr pc_c_zookeeper $(LIBDIR)/$(CONFIG)/libgpr.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgrpc_unsecure.a static_zookeeper_libs
+static_c: pc_c pc_c_unsecure cache.mk pc_c_zookeeper $(LIBDIR)/$(CONFIG)/libgpr.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgrpc_unsecure.a static_zookeeper_libs
 
 
-static_cxx: pc_cxx pc_cxx_unsecure pc_gpr cache.mk  $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc++_unsecure.a
+static_cxx: pc_cxx pc_cxx_unsecure cache.mk  $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc++_unsecure.a
 
 shared: shared_c shared_cxx
 
-shared_c: pc_c pc_c_unsecure pc_gpr cache.mk pc_c_zookeeper $(LIBDIR)/$(CONFIG)/libgpr.$(SHARED_EXT) $(LIBDIR)/$(CONFIG)/libgrpc.$(SHARED_EXT) $(LIBDIR)/$(CONFIG)/libgrpc_unsecure.$(SHARED_EXT) shared_zookeeper_libs
+shared_c: pc_c pc_c_unsecure cache.mk pc_c_zookeeper $(LIBDIR)/$(CONFIG)/$(SHARED_PREFIX)gpr$(SHARED_VERSION).$(SHARED_EXT) $(LIBDIR)/$(CONFIG)/$(SHARED_PREFIX)grpc$(SHARED_VERSION).$(SHARED_EXT) $(LIBDIR)/$(CONFIG)/$(SHARED_PREFIX)grpc_unsecure$(SHARED_VERSION).$(SHARED_EXT) shared_zookeeper_libs
 
-shared_cxx: pc_cxx pc_cxx_unsecure cache.mk $(LIBDIR)/$(CONFIG)/libgrpc++.$(SHARED_EXT) $(LIBDIR)/$(CONFIG)/libgrpc++_unsecure.$(SHARED_EXT)
+shared_cxx: pc_cxx pc_cxx_unsecure cache.mk $(LIBDIR)/$(CONFIG)/$(SHARED_PREFIX)grpc++$(SHARED_VERSION).$(SHARED_EXT) $(LIBDIR)/$(CONFIG)/$(SHARED_PREFIX)grpc++_unsecure$(SHARED_VERSION).$(SHARED_EXT)
 
-shared_csharp: shared_c  $(LIBDIR)/$(CONFIG)/libgrpc_csharp_ext.$(SHARED_EXT)
+shared_csharp: shared_c  $(LIBDIR)/$(CONFIG)/$(SHARED_PREFIX)grpc_csharp_ext$(SHARED_VERSION).$(SHARED_EXT)
 ifeq ($(HAS_ZOOKEEPER),true)
 static_zookeeper_libs: $(LIBDIR)/$(CONFIG)/libgrpc_zookeeper.a
-shared_zookeeper_libs: $(LIBDIR)/$(CONFIG)/libgrpc_zookeeper.$(SHARED_EXT)
+shared_zookeeper_libs: $(LIBDIR)/$(CONFIG)/$(SHARED_PREFIX)grpc_zookeeper$(SHARED_VERSION).$(SHARED_EXT)
 else
 
 static_zookeeper_libs:
@@ -1110,8 +1102,6 @@
 privatelibs: privatelibs_c privatelibs_cxx
 
 privatelibs_c:  $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util_unsecure.a $(LIBDIR)/$(CONFIG)/libreconnect_server.a $(LIBDIR)/$(CONFIG)/libtest_tcp_server.a $(LIBDIR)/$(CONFIG)/libz.a $(LIBDIR)/$(CONFIG)/libbad_client_test.a $(LIBDIR)/$(CONFIG)/libbad_ssl_test_server.a $(LIBDIR)/$(CONFIG)/libend2end_tests.a $(LIBDIR)/$(CONFIG)/libend2end_nosec_tests.a $(LIBDIR)/$(CONFIG)/libend2end_certs.a
-pc_gpr: $(LIBDIR)/$(CONFIG)/pkgconfig/gpr.pc
-
 pc_c: $(LIBDIR)/$(CONFIG)/pkgconfig/grpc.pc
 
 pc_c_unsecure: $(LIBDIR)/$(CONFIG)/pkgconfig/grpc_unsecure.pc
@@ -1138,10 +1128,12 @@
 buildtests: buildtests_c buildtests_cxx buildtests_zookeeper
 
 buildtests_c: privatelibs_c \
+  $(BINDIR)/$(CONFIG)/alarm_test \
   $(BINDIR)/$(CONFIG)/algorithm_test \
   $(BINDIR)/$(CONFIG)/alloc_test \
   $(BINDIR)/$(CONFIG)/alpn_test \
   $(BINDIR)/$(CONFIG)/bin_encoder_test \
+  $(BINDIR)/$(CONFIG)/census_context_test \
   $(BINDIR)/$(CONFIG)/channel_create_test \
   $(BINDIR)/$(CONFIG)/chttp2_hpack_encoder_test \
   $(BINDIR)/$(CONFIG)/chttp2_status_conversion_test \
@@ -1212,7 +1204,6 @@
   $(BINDIR)/$(CONFIG)/sockaddr_resolver_test \
   $(BINDIR)/$(CONFIG)/sockaddr_utils_test \
   $(BINDIR)/$(CONFIG)/socket_utils_test \
-  $(BINDIR)/$(CONFIG)/tag_set_test \
   $(BINDIR)/$(CONFIG)/tcp_client_posix_test \
   $(BINDIR)/$(CONFIG)/tcp_posix_test \
   $(BINDIR)/$(CONFIG)/tcp_server_posix_test \
@@ -1274,6 +1265,7 @@
 
 
 buildtests_cxx: buildtests_zookeeper privatelibs_cxx \
+  $(BINDIR)/$(CONFIG)/alarm_cpp_test \
   $(BINDIR)/$(CONFIG)/async_end2end_test \
   $(BINDIR)/$(CONFIG)/async_streaming_ping_pong_test \
   $(BINDIR)/$(CONFIG)/async_unary_ping_pong_test \
@@ -1291,6 +1283,7 @@
   $(BINDIR)/$(CONFIG)/generic_async_streaming_ping_pong_test \
   $(BINDIR)/$(CONFIG)/generic_end2end_test \
   $(BINDIR)/$(CONFIG)/grpc_cli \
+  $(BINDIR)/$(CONFIG)/hybrid_end2end_test \
   $(BINDIR)/$(CONFIG)/interop_client \
   $(BINDIR)/$(CONFIG)/interop_server \
   $(BINDIR)/$(CONFIG)/interop_test \
@@ -1364,6 +1357,8 @@
 flaky_test: flaky_test_c flaky_test_cxx flaky_test_zookeeper
 
 test_c: buildtests_c
+	$(E) "[RUN]     Testing alarm_test"
+	$(Q) $(BINDIR)/$(CONFIG)/alarm_test || ( echo test alarm_test failed ; exit 1 )
 	$(E) "[RUN]     Testing algorithm_test"
 	$(Q) $(BINDIR)/$(CONFIG)/algorithm_test || ( echo test algorithm_test failed ; exit 1 )
 	$(E) "[RUN]     Testing alloc_test"
@@ -1372,6 +1367,8 @@
 	$(Q) $(BINDIR)/$(CONFIG)/alpn_test || ( echo test alpn_test failed ; exit 1 )
 	$(E) "[RUN]     Testing bin_encoder_test"
 	$(Q) $(BINDIR)/$(CONFIG)/bin_encoder_test || ( echo test bin_encoder_test failed ; exit 1 )
+	$(E) "[RUN]     Testing census_context_test"
+	$(Q) $(BINDIR)/$(CONFIG)/census_context_test || ( echo test census_context_test failed ; exit 1 )
 	$(E) "[RUN]     Testing channel_create_test"
 	$(Q) $(BINDIR)/$(CONFIG)/channel_create_test || ( echo test channel_create_test failed ; exit 1 )
 	$(E) "[RUN]     Testing chttp2_hpack_encoder_test"
@@ -1506,8 +1503,6 @@
 	$(Q) $(BINDIR)/$(CONFIG)/sockaddr_utils_test || ( echo test sockaddr_utils_test failed ; exit 1 )
 	$(E) "[RUN]     Testing socket_utils_test"
 	$(Q) $(BINDIR)/$(CONFIG)/socket_utils_test || ( echo test socket_utils_test failed ; exit 1 )
-	$(E) "[RUN]     Testing tag_set_test"
-	$(Q) $(BINDIR)/$(CONFIG)/tag_set_test || ( echo test tag_set_test failed ; exit 1 )
 	$(E) "[RUN]     Testing tcp_client_posix_test"
 	$(Q) $(BINDIR)/$(CONFIG)/tcp_client_posix_test || ( echo test tcp_client_posix_test failed ; exit 1 )
 	$(E) "[RUN]     Testing tcp_posix_test"
@@ -1564,6 +1559,8 @@
 
 
 test_cxx: test_zookeeper buildtests_cxx
+	$(E) "[RUN]     Testing alarm_cpp_test"
+	$(Q) $(BINDIR)/$(CONFIG)/alarm_cpp_test || ( echo test alarm_cpp_test failed ; exit 1 )
 	$(E) "[RUN]     Testing async_end2end_test"
 	$(Q) $(BINDIR)/$(CONFIG)/async_end2end_test || ( echo test async_end2end_test failed ; exit 1 )
 	$(E) "[RUN]     Testing async_streaming_ping_pong_test"
@@ -1594,6 +1591,8 @@
 	$(Q) $(BINDIR)/$(CONFIG)/generic_async_streaming_ping_pong_test || ( echo test generic_async_streaming_ping_pong_test failed ; exit 1 )
 	$(E) "[RUN]     Testing generic_end2end_test"
 	$(Q) $(BINDIR)/$(CONFIG)/generic_end2end_test || ( echo test generic_end2end_test failed ; exit 1 )
+	$(E) "[RUN]     Testing hybrid_end2end_test"
+	$(Q) $(BINDIR)/$(CONFIG)/hybrid_end2end_test || ( echo test hybrid_end2end_test failed ; exit 1 )
 	$(E) "[RUN]     Testing interop_test"
 	$(Q) $(BINDIR)/$(CONFIG)/interop_test || ( echo test interop_test failed ; exit 1 )
 	$(E) "[RUN]     Testing mock_test"
@@ -1686,41 +1685,36 @@
 
 strip-shared_c: shared_c
 ifeq ($(CONFIG),opt)
-	$(E) "[STRIP]   Stripping libgpr.so"
-	$(Q) $(STRIP) $(LIBDIR)/$(CONFIG)/libgpr.$(SHARED_EXT)
-	$(E) "[STRIP]   Stripping libgrpc.so"
-	$(Q) $(STRIP) $(LIBDIR)/$(CONFIG)/libgrpc.$(SHARED_EXT)
-	$(E) "[STRIP]   Stripping libgrpc_unsecure.so"
-	$(Q) $(STRIP) $(LIBDIR)/$(CONFIG)/libgrpc_unsecure.$(SHARED_EXT)
+	$(E) "[STRIP]   Stripping $(SHARED_PREFIX)gpr$(SHARED_VERSION).$(SHARED_EXT)"
+	$(Q) $(STRIP) $(LIBDIR)/$(CONFIG)/$(SHARED_PREFIX)gpr$(SHARED_VERSION).$(SHARED_EXT)
+	$(E) "[STRIP]   Stripping $(SHARED_PREFIX)grpc$(SHARED_VERSION).$(SHARED_EXT)"
+	$(Q) $(STRIP) $(LIBDIR)/$(CONFIG)/$(SHARED_PREFIX)grpc$(SHARED_VERSION).$(SHARED_EXT)
+	$(E) "[STRIP]   Stripping $(SHARED_PREFIX)grpc_unsecure$(SHARED_VERSION).$(SHARED_EXT)"
+	$(Q) $(STRIP) $(LIBDIR)/$(CONFIG)/$(SHARED_PREFIX)grpc_unsecure$(SHARED_VERSION).$(SHARED_EXT)
 ifeq ($(HAS_ZOOKEEPER),true)
-	$(E) "[STRIP]   Stripping libgrpc_zookeeper.so"
-	$(Q) $(STRIP) $(LIBDIR)/$(CONFIG)/libgrpc_zookeeper.$(SHARED_EXT)
+	$(E) "[STRIP]   Stripping $(SHARED_PREFIX)grpc_zookeeper$(SHARED_VERSION).$(SHARED_EXT)"
+	$(Q) $(STRIP) $(LIBDIR)/$(CONFIG)/$(SHARED_PREFIX)grpc_zookeeper$(SHARED_VERSION).$(SHARED_EXT)
 endif
 endif
 
 strip-shared_cxx: shared_cxx
 ifeq ($(CONFIG),opt)
-	$(E) "[STRIP]   Stripping libgrpc++.so"
-	$(Q) $(STRIP) $(LIBDIR)/$(CONFIG)/libgrpc++.$(SHARED_EXT)
-	$(E) "[STRIP]   Stripping libgrpc++_unsecure.so"
-	$(Q) $(STRIP) $(LIBDIR)/$(CONFIG)/libgrpc++_unsecure.$(SHARED_EXT)
+	$(E) "[STRIP]   Stripping $(SHARED_PREFIX)grpc++$(SHARED_VERSION).$(SHARED_EXT)"
+	$(Q) $(STRIP) $(LIBDIR)/$(CONFIG)/$(SHARED_PREFIX)grpc++$(SHARED_VERSION).$(SHARED_EXT)
+	$(E) "[STRIP]   Stripping $(SHARED_PREFIX)grpc++_unsecure$(SHARED_VERSION).$(SHARED_EXT)"
+	$(Q) $(STRIP) $(LIBDIR)/$(CONFIG)/$(SHARED_PREFIX)grpc++_unsecure$(SHARED_VERSION).$(SHARED_EXT)
 endif
 
 strip-shared_csharp: shared_csharp
 ifeq ($(CONFIG),opt)
-	$(E) "[STRIP]   Stripping libgrpc_csharp_ext.so"
-	$(Q) $(STRIP) $(LIBDIR)/$(CONFIG)/libgrpc_csharp_ext.$(SHARED_EXT)
+	$(E) "[STRIP]   Stripping $(SHARED_PREFIX)grpc_csharp_ext$(SHARED_VERSION).$(SHARED_EXT)"
+	$(Q) $(STRIP) $(LIBDIR)/$(CONFIG)/$(SHARED_PREFIX)grpc_csharp_ext$(SHARED_VERSION).$(SHARED_EXT)
 endif
 
 cache.mk::
 	$(E) "[MAKE]    Generating $@"
 	$(Q) echo "$(CACHE_MK)" | tr , '\n' >$@
 
-$(LIBDIR)/$(CONFIG)/pkgconfig/gpr.pc:
-	$(E) "[MAKE]    Generating $@"
-	$(Q) mkdir -p $(@D)
-	$(Q) echo "$(GPR_PC_FILE)" | tr , '\n' >$@
-
 $(LIBDIR)/$(CONFIG)/pkgconfig/grpc.pc:
 	$(E) "[MAKE]    Generating $@"
 	$(Q) mkdir -p $(@D)
@@ -1942,12 +1936,12 @@
 $(OBJDIR)/$(CONFIG)/%.o : %.c
 	$(E) "[C]       Compiling $<"
 	$(Q) mkdir -p `dirname $@`
-	$(Q) $(CC) $(CFLAGS) $(CPPFLAGS) -MMD -MF $(addsuffix .dep, $(basename $@)) -c -o $@ $<
+	$(Q) $(CC) $(CPPFLAGS) $(CFLAGS) -MMD -MF $(addsuffix .dep, $(basename $@)) -c -o $@ $<
 
 $(OBJDIR)/$(CONFIG)/%.o : $(GENDIR)/%.pb.cc
 	$(E) "[CXX]     Compiling $<"
 	$(Q) mkdir -p `dirname $@`
-	$(Q) $(CXX) $(CXXFLAGS) $(CPPFLAGS) -MMD -MF $(addsuffix .dep, $(basename $@)) -c -o $@ $<
+	$(Q) $(CXX) $(CPPFLAGS) $(CXXFLAGS) -MMD -MF $(addsuffix .dep, $(basename $@)) -c -o $@ $<
 
 $(OBJDIR)/$(CONFIG)/src/compiler/%.o : src/compiler/%.cc
 	$(E) "[HOSTCXX] Compiling $<"
@@ -1957,7 +1951,7 @@
 $(OBJDIR)/$(CONFIG)/%.o : %.cc
 	$(E) "[CXX]     Compiling $<"
 	$(Q) mkdir -p `dirname $@`
-	$(Q) $(CXX) $(CXXFLAGS) $(CPPFLAGS) -MMD -MF $(addsuffix .dep, $(basename $@)) -c -o $@ $<
+	$(Q) $(CXX) $(CPPFLAGS) $(CXXFLAGS) -MMD -MF $(addsuffix .dep, $(basename $@)) -c -o $@ $<
 
 install: install_c install_cxx install-plugins install-certs verify-install
 
@@ -2010,62 +2004,42 @@
 
 
 install-shared_c: shared_c strip-shared_c install-pkg-config_c
-ifeq ($(SYSTEM),MINGW32)
-	$(E) "[INSTALL] Installing gpr.$(SHARED_EXT)"
+	$(E) "[INSTALL] Installing $(SHARED_PREFIX)gpr$(SHARED_VERSION).$(SHARED_EXT)"
 	$(Q) $(INSTALL) -d $(prefix)/lib
-	$(Q) $(INSTALL) $(LIBDIR)/$(CONFIG)/gpr.$(SHARED_EXT) $(prefix)/lib/gpr.$(SHARED_EXT)
+	$(Q) $(INSTALL) $(LIBDIR)/$(CONFIG)/$(SHARED_PREFIX)gpr$(SHARED_VERSION).$(SHARED_EXT) $(prefix)/lib/$(SHARED_PREFIX)gpr$(SHARED_VERSION).$(SHARED_EXT)
+ifeq ($(SYSTEM),MINGW32)
 	$(Q) $(INSTALL) $(LIBDIR)/$(CONFIG)/libgpr-imp.a $(prefix)/lib/libgpr-imp.a
-else
-	$(E) "[INSTALL] Installing libgpr.$(SHARED_EXT)"
+else ifneq ($(SYSTEM),Darwin)
+	$(Q) ln -sf $(SHARED_PREFIX)gpr$(SHARED_VERSION).$(SHARED_EXT) $(prefix)/lib/libgpr.so.0
+	$(Q) ln -sf $(SHARED_PREFIX)gpr$(SHARED_VERSION).$(SHARED_EXT) $(prefix)/lib/libgpr.so
+endif
+	$(E) "[INSTALL] Installing $(SHARED_PREFIX)grpc$(SHARED_VERSION).$(SHARED_EXT)"
 	$(Q) $(INSTALL) -d $(prefix)/lib
-	$(Q) $(INSTALL) $(LIBDIR)/$(CONFIG)/libgpr.$(SHARED_EXT) $(prefix)/lib/libgpr.$(SHARED_EXT)
-ifneq ($(SYSTEM),Darwin)
-	$(Q) ln -sf libgpr.$(SHARED_EXT) $(prefix)/lib/libgpr.so.0
-	$(Q) ln -sf libgpr.$(SHARED_EXT) $(prefix)/lib/libgpr.so
-endif
-endif
+	$(Q) $(INSTALL) $(LIBDIR)/$(CONFIG)/$(SHARED_PREFIX)grpc$(SHARED_VERSION).$(SHARED_EXT) $(prefix)/lib/$(SHARED_PREFIX)grpc$(SHARED_VERSION).$(SHARED_EXT)
 ifeq ($(SYSTEM),MINGW32)
-	$(E) "[INSTALL] Installing grpc.$(SHARED_EXT)"
-	$(Q) $(INSTALL) -d $(prefix)/lib
-	$(Q) $(INSTALL) $(LIBDIR)/$(CONFIG)/grpc.$(SHARED_EXT) $(prefix)/lib/grpc.$(SHARED_EXT)
 	$(Q) $(INSTALL) $(LIBDIR)/$(CONFIG)/libgrpc-imp.a $(prefix)/lib/libgrpc-imp.a
-else
-	$(E) "[INSTALL] Installing libgrpc.$(SHARED_EXT)"
+else ifneq ($(SYSTEM),Darwin)
+	$(Q) ln -sf $(SHARED_PREFIX)grpc$(SHARED_VERSION).$(SHARED_EXT) $(prefix)/lib/libgrpc.so.0
+	$(Q) ln -sf $(SHARED_PREFIX)grpc$(SHARED_VERSION).$(SHARED_EXT) $(prefix)/lib/libgrpc.so
+endif
+	$(E) "[INSTALL] Installing $(SHARED_PREFIX)grpc_unsecure$(SHARED_VERSION).$(SHARED_EXT)"
 	$(Q) $(INSTALL) -d $(prefix)/lib
-	$(Q) $(INSTALL) $(LIBDIR)/$(CONFIG)/libgrpc.$(SHARED_EXT) $(prefix)/lib/libgrpc.$(SHARED_EXT)
-ifneq ($(SYSTEM),Darwin)
-	$(Q) ln -sf libgrpc.$(SHARED_EXT) $(prefix)/lib/libgrpc.so.0
-	$(Q) ln -sf libgrpc.$(SHARED_EXT) $(prefix)/lib/libgrpc.so
-endif
-endif
+	$(Q) $(INSTALL) $(LIBDIR)/$(CONFIG)/$(SHARED_PREFIX)grpc_unsecure$(SHARED_VERSION).$(SHARED_EXT) $(prefix)/lib/$(SHARED_PREFIX)grpc_unsecure$(SHARED_VERSION).$(SHARED_EXT)
 ifeq ($(SYSTEM),MINGW32)
-	$(E) "[INSTALL] Installing grpc_unsecure.$(SHARED_EXT)"
-	$(Q) $(INSTALL) -d $(prefix)/lib
-	$(Q) $(INSTALL) $(LIBDIR)/$(CONFIG)/grpc_unsecure.$(SHARED_EXT) $(prefix)/lib/grpc_unsecure.$(SHARED_EXT)
 	$(Q) $(INSTALL) $(LIBDIR)/$(CONFIG)/libgrpc_unsecure-imp.a $(prefix)/lib/libgrpc_unsecure-imp.a
-else
-	$(E) "[INSTALL] Installing libgrpc_unsecure.$(SHARED_EXT)"
-	$(Q) $(INSTALL) -d $(prefix)/lib
-	$(Q) $(INSTALL) $(LIBDIR)/$(CONFIG)/libgrpc_unsecure.$(SHARED_EXT) $(prefix)/lib/libgrpc_unsecure.$(SHARED_EXT)
-ifneq ($(SYSTEM),Darwin)
-	$(Q) ln -sf libgrpc_unsecure.$(SHARED_EXT) $(prefix)/lib/libgrpc_unsecure.so.0
-	$(Q) ln -sf libgrpc_unsecure.$(SHARED_EXT) $(prefix)/lib/libgrpc_unsecure.so
-endif
+else ifneq ($(SYSTEM),Darwin)
+	$(Q) ln -sf $(SHARED_PREFIX)grpc_unsecure$(SHARED_VERSION).$(SHARED_EXT) $(prefix)/lib/libgrpc_unsecure.so.0
+	$(Q) ln -sf $(SHARED_PREFIX)grpc_unsecure$(SHARED_VERSION).$(SHARED_EXT) $(prefix)/lib/libgrpc_unsecure.so
 endif
 ifeq ($(HAS_ZOOKEEPER),true)
+	$(E) "[INSTALL] Installing $(SHARED_PREFIX)grpc_zookeeper$(SHARED_VERSION).$(SHARED_EXT)"
+	$(Q) $(INSTALL) -d $(prefix)/lib
+	$(Q) $(INSTALL) $(LIBDIR)/$(CONFIG)/$(SHARED_PREFIX)grpc_zookeeper$(SHARED_VERSION).$(SHARED_EXT) $(prefix)/lib/$(SHARED_PREFIX)grpc_zookeeper$(SHARED_VERSION).$(SHARED_EXT)
 ifeq ($(SYSTEM),MINGW32)
-	$(E) "[INSTALL] Installing grpc_zookeeper.$(SHARED_EXT)"
-	$(Q) $(INSTALL) -d $(prefix)/lib
-	$(Q) $(INSTALL) $(LIBDIR)/$(CONFIG)/grpc_zookeeper.$(SHARED_EXT) $(prefix)/lib/grpc_zookeeper.$(SHARED_EXT)
 	$(Q) $(INSTALL) $(LIBDIR)/$(CONFIG)/libgrpc_zookeeper-imp.a $(prefix)/lib/libgrpc_zookeeper-imp.a
-else
-	$(E) "[INSTALL] Installing libgrpc_zookeeper.$(SHARED_EXT)"
-	$(Q) $(INSTALL) -d $(prefix)/lib
-	$(Q) $(INSTALL) $(LIBDIR)/$(CONFIG)/libgrpc_zookeeper.$(SHARED_EXT) $(prefix)/lib/libgrpc_zookeeper.$(SHARED_EXT)
-ifneq ($(SYSTEM),Darwin)
-	$(Q) ln -sf libgrpc_zookeeper.$(SHARED_EXT) $(prefix)/lib/libgrpc_zookeeper.so.0
-	$(Q) ln -sf libgrpc_zookeeper.$(SHARED_EXT) $(prefix)/lib/libgrpc_zookeeper.so
-endif
+else ifneq ($(SYSTEM),Darwin)
+	$(Q) ln -sf $(SHARED_PREFIX)grpc_zookeeper$(SHARED_VERSION).$(SHARED_EXT) $(prefix)/lib/libgrpc_zookeeper.so.0
+	$(Q) ln -sf $(SHARED_PREFIX)grpc_zookeeper$(SHARED_VERSION).$(SHARED_EXT) $(prefix)/lib/libgrpc_zookeeper.so
 endif
 endif
 ifneq ($(SYSTEM),MINGW32)
@@ -2076,33 +2050,23 @@
 
 
 install-shared_cxx: shared_cxx strip-shared_cxx install-shared_c install-pkg-config_cxx
-ifeq ($(SYSTEM),MINGW32)
-	$(E) "[INSTALL] Installing grpc++.$(SHARED_EXT)"
+	$(E) "[INSTALL] Installing $(SHARED_PREFIX)grpc++$(SHARED_VERSION).$(SHARED_EXT)"
 	$(Q) $(INSTALL) -d $(prefix)/lib
-	$(Q) $(INSTALL) $(LIBDIR)/$(CONFIG)/grpc++.$(SHARED_EXT) $(prefix)/lib/grpc++.$(SHARED_EXT)
+	$(Q) $(INSTALL) $(LIBDIR)/$(CONFIG)/$(SHARED_PREFIX)grpc++$(SHARED_VERSION).$(SHARED_EXT) $(prefix)/lib/$(SHARED_PREFIX)grpc++$(SHARED_VERSION).$(SHARED_EXT)
+ifeq ($(SYSTEM),MINGW32)
 	$(Q) $(INSTALL) $(LIBDIR)/$(CONFIG)/libgrpc++-imp.a $(prefix)/lib/libgrpc++-imp.a
-else
-	$(E) "[INSTALL] Installing libgrpc++.$(SHARED_EXT)"
+else ifneq ($(SYSTEM),Darwin)
+	$(Q) ln -sf $(SHARED_PREFIX)grpc++$(SHARED_VERSION).$(SHARED_EXT) $(prefix)/lib/libgrpc++.so.0
+	$(Q) ln -sf $(SHARED_PREFIX)grpc++$(SHARED_VERSION).$(SHARED_EXT) $(prefix)/lib/libgrpc++.so
+endif
+	$(E) "[INSTALL] Installing $(SHARED_PREFIX)grpc++_unsecure$(SHARED_VERSION).$(SHARED_EXT)"
 	$(Q) $(INSTALL) -d $(prefix)/lib
-	$(Q) $(INSTALL) $(LIBDIR)/$(CONFIG)/libgrpc++.$(SHARED_EXT) $(prefix)/lib/libgrpc++.$(SHARED_EXT)
-ifneq ($(SYSTEM),Darwin)
-	$(Q) ln -sf libgrpc++.$(SHARED_EXT) $(prefix)/lib/libgrpc++.so.0
-	$(Q) ln -sf libgrpc++.$(SHARED_EXT) $(prefix)/lib/libgrpc++.so
-endif
-endif
+	$(Q) $(INSTALL) $(LIBDIR)/$(CONFIG)/$(SHARED_PREFIX)grpc++_unsecure$(SHARED_VERSION).$(SHARED_EXT) $(prefix)/lib/$(SHARED_PREFIX)grpc++_unsecure$(SHARED_VERSION).$(SHARED_EXT)
 ifeq ($(SYSTEM),MINGW32)
-	$(E) "[INSTALL] Installing grpc++_unsecure.$(SHARED_EXT)"
-	$(Q) $(INSTALL) -d $(prefix)/lib
-	$(Q) $(INSTALL) $(LIBDIR)/$(CONFIG)/grpc++_unsecure.$(SHARED_EXT) $(prefix)/lib/grpc++_unsecure.$(SHARED_EXT)
 	$(Q) $(INSTALL) $(LIBDIR)/$(CONFIG)/libgrpc++_unsecure-imp.a $(prefix)/lib/libgrpc++_unsecure-imp.a
-else
-	$(E) "[INSTALL] Installing libgrpc++_unsecure.$(SHARED_EXT)"
-	$(Q) $(INSTALL) -d $(prefix)/lib
-	$(Q) $(INSTALL) $(LIBDIR)/$(CONFIG)/libgrpc++_unsecure.$(SHARED_EXT) $(prefix)/lib/libgrpc++_unsecure.$(SHARED_EXT)
-ifneq ($(SYSTEM),Darwin)
-	$(Q) ln -sf libgrpc++_unsecure.$(SHARED_EXT) $(prefix)/lib/libgrpc++_unsecure.so.0
-	$(Q) ln -sf libgrpc++_unsecure.$(SHARED_EXT) $(prefix)/lib/libgrpc++_unsecure.so
-endif
+else ifneq ($(SYSTEM),Darwin)
+	$(Q) ln -sf $(SHARED_PREFIX)grpc++_unsecure$(SHARED_VERSION).$(SHARED_EXT) $(prefix)/lib/libgrpc++_unsecure.so.0
+	$(Q) ln -sf $(SHARED_PREFIX)grpc++_unsecure$(SHARED_VERSION).$(SHARED_EXT) $(prefix)/lib/libgrpc++_unsecure.so
 endif
 ifeq ($(HAS_ZOOKEEPER),true)
 endif
@@ -2114,19 +2078,14 @@
 
 
 install-shared_csharp: shared_csharp strip-shared_csharp
+	$(E) "[INSTALL] Installing $(SHARED_PREFIX)grpc_csharp_ext$(SHARED_VERSION).$(SHARED_EXT)"
+	$(Q) $(INSTALL) -d $(prefix)/lib
+	$(Q) $(INSTALL) $(LIBDIR)/$(CONFIG)/$(SHARED_PREFIX)grpc_csharp_ext$(SHARED_VERSION).$(SHARED_EXT) $(prefix)/lib/$(SHARED_PREFIX)grpc_csharp_ext$(SHARED_VERSION).$(SHARED_EXT)
 ifeq ($(SYSTEM),MINGW32)
-	$(E) "[INSTALL] Installing grpc_csharp_ext.$(SHARED_EXT)"
-	$(Q) $(INSTALL) -d $(prefix)/lib
-	$(Q) $(INSTALL) $(LIBDIR)/$(CONFIG)/grpc_csharp_ext.$(SHARED_EXT) $(prefix)/lib/grpc_csharp_ext.$(SHARED_EXT)
 	$(Q) $(INSTALL) $(LIBDIR)/$(CONFIG)/libgrpc_csharp_ext-imp.a $(prefix)/lib/libgrpc_csharp_ext-imp.a
-else
-	$(E) "[INSTALL] Installing libgrpc_csharp_ext.$(SHARED_EXT)"
-	$(Q) $(INSTALL) -d $(prefix)/lib
-	$(Q) $(INSTALL) $(LIBDIR)/$(CONFIG)/libgrpc_csharp_ext.$(SHARED_EXT) $(prefix)/lib/libgrpc_csharp_ext.$(SHARED_EXT)
-ifneq ($(SYSTEM),Darwin)
-	$(Q) ln -sf libgrpc_csharp_ext.$(SHARED_EXT) $(prefix)/lib/libgrpc_csharp_ext.so.0
-	$(Q) ln -sf libgrpc_csharp_ext.$(SHARED_EXT) $(prefix)/lib/libgrpc_csharp_ext.so
-endif
+else ifneq ($(SYSTEM),Darwin)
+	$(Q) ln -sf $(SHARED_PREFIX)grpc_csharp_ext$(SHARED_VERSION).$(SHARED_EXT) $(prefix)/lib/libgrpc_csharp_ext.so.0
+	$(Q) ln -sf $(SHARED_PREFIX)grpc_csharp_ext$(SHARED_VERSION).$(SHARED_EXT) $(prefix)/lib/libgrpc_csharp_ext.so
 endif
 ifeq ($(HAS_ZOOKEEPER),true)
 endif
@@ -2154,10 +2113,9 @@
 	$(Q) $(INSTALL) $(BINDIR)/$(CONFIG)/grpc_ruby_plugin $(prefix)/bin/grpc_ruby_plugin
 endif
 
-install-pkg-config_c: pc_gpr pc_c pc_c_unsecure pc_c_zookeeper
+install-pkg-config_c: pc_c pc_c_unsecure pc_c_zookeeper
 	$(E) "[INSTALL] Installing C pkg-config files"
 	$(Q) $(INSTALL) -d $(prefix)/lib/pkgconfig
-	$(Q) $(INSTALL) $(LIBDIR)/$(CONFIG)/pkgconfig/gpr.pc $(prefix)/lib/pkgconfig/gpr.pc
 	$(Q) $(INSTALL) $(LIBDIR)/$(CONFIG)/pkgconfig/grpc.pc $(prefix)/lib/pkgconfig/grpc.pc
 	$(Q) $(INSTALL) $(LIBDIR)/$(CONFIG)/pkgconfig/grpc_unsecure.pc $(prefix)/lib/pkgconfig/grpc_unsecure.pc
 ifeq ($(HAS_ZOOKEEPER),true)
@@ -2234,6 +2192,7 @@
     src/core/support/string_posix.c \
     src/core/support/string_win32.c \
     src/core/support/subprocess_posix.c \
+    src/core/support/subprocess_windows.c \
     src/core/support/sync.c \
     src/core/support/sync_posix.c \
     src/core/support/sync_win32.c \
@@ -2245,6 +2204,7 @@
     src/core/support/time_precise.c \
     src/core/support/time_win32.c \
     src/core/support/tls_pthread.c \
+    src/core/support/wrap_memcpy.c \
 
 PUBLIC_HEADERS_C += \
     include/grpc/support/alloc.h \
@@ -2275,15 +2235,29 @@
     include/grpc/support/tls_msvc.h \
     include/grpc/support/tls_pthread.h \
     include/grpc/support/useful.h \
+    include/grpc/impl/codegen/alloc.h \
+    include/grpc/impl/codegen/atm.h \
+    include/grpc/impl/codegen/atm_gcc_atomic.h \
+    include/grpc/impl/codegen/atm_gcc_sync.h \
+    include/grpc/impl/codegen/atm_win32.h \
+    include/grpc/impl/codegen/log.h \
+    include/grpc/impl/codegen/port_platform.h \
+    include/grpc/impl/codegen/slice.h \
+    include/grpc/impl/codegen/slice_buffer.h \
+    include/grpc/impl/codegen/sync.h \
+    include/grpc/impl/codegen/sync_generic.h \
+    include/grpc/impl/codegen/sync_posix.h \
+    include/grpc/impl/codegen/sync_win32.h \
+    include/grpc/impl/codegen/time.h \
 
 LIBGPR_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(LIBGPR_SRC))))
 
 
-$(LIBDIR)/$(CONFIG)/libgpr.a: $(ZLIB_DEP) $(OPENSSL_DEP)  $(LIBGPR_OBJS)
+$(LIBDIR)/$(CONFIG)/libgpr.a: $(ZLIB_DEP)  $(LIBGPR_OBJS) 
 	$(E) "[AR]      Creating $@"
 	$(Q) mkdir -p `dirname $@`
 	$(Q) rm -f $(LIBDIR)/$(CONFIG)/libgpr.a
-	$(Q) $(AR) rcs $(LIBDIR)/$(CONFIG)/libgpr.a $(LIBGPR_OBJS)
+	$(Q) $(AR) $(LIBDIR)/$(CONFIG)/libgpr.a $(LIBGPR_OBJS) 
 ifeq ($(SYSTEM),Darwin)
 	$(Q) ranlib $(LIBDIR)/$(CONFIG)/libgpr.a
 endif
@@ -2291,20 +2265,20 @@
 
 
 ifeq ($(SYSTEM),MINGW32)
-$(LIBDIR)/$(CONFIG)/gpr.$(SHARED_EXT): $(LIBGPR_OBJS)  $(ZLIB_DEP)
+$(LIBDIR)/$(CONFIG)/gpr$(SHARED_VERSION).$(SHARED_EXT): $(LIBGPR_OBJS)  $(ZLIB_DEP)
 	$(E) "[LD]      Linking $@"
 	$(Q) mkdir -p `dirname $@`
-	$(Q) $(LD) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -shared -Wl,--output-def=$(LIBDIR)/$(CONFIG)/gpr.def -Wl,--out-implib=$(LIBDIR)/$(CONFIG)/libgpr-imp.a -o $(LIBDIR)/$(CONFIG)/gpr.$(SHARED_EXT) $(LIBGPR_OBJS) $(LDLIBS) $(ZLIB_MERGE_LIBS)
+	$(Q) $(LD) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -shared gpr.def -Wl,--output-def=$(LIBDIR)/$(CONFIG)/gpr$(SHARED_VERSION).def -Wl,--out-implib=$(LIBDIR)/$(CONFIG)/libgpr$(SHARED_VERSION)-dll.a -o $(LIBDIR)/$(CONFIG)/gpr$(SHARED_VERSION).$(SHARED_EXT) $(LIBGPR_OBJS) $(LDLIBS) $(ZLIB_MERGE_LIBS)
 else
-$(LIBDIR)/$(CONFIG)/libgpr.$(SHARED_EXT): $(LIBGPR_OBJS)  $(ZLIB_DEP)
+$(LIBDIR)/$(CONFIG)/libgpr$(SHARED_VERSION).$(SHARED_EXT): $(LIBGPR_OBJS)  $(ZLIB_DEP)
 	$(E) "[LD]      Linking $@"
 	$(Q) mkdir -p `dirname $@`
 ifeq ($(SYSTEM),Darwin)
-	$(Q) $(LD) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -install_name libgpr.$(SHARED_EXT) -dynamiclib -o $(LIBDIR)/$(CONFIG)/libgpr.$(SHARED_EXT) $(LIBGPR_OBJS) $(LDLIBS) $(ZLIB_MERGE_LIBS)
+	$(Q) $(LD) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -install_name $(SHARED_PREFIX)gpr$(SHARED_VERSION).$(SHARED_EXT) -dynamiclib -o $(LIBDIR)/$(CONFIG)/libgpr$(SHARED_VERSION).$(SHARED_EXT) $(LIBGPR_OBJS) $(LDLIBS) $(ZLIB_MERGE_LIBS)
 else
-	$(Q) $(LD) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -shared -Wl,-soname,libgpr.so.0 -o $(LIBDIR)/$(CONFIG)/libgpr.$(SHARED_EXT) $(LIBGPR_OBJS) $(LDLIBS) $(ZLIB_MERGE_LIBS)
-	$(Q) ln -sf libgpr.$(SHARED_EXT) $(LIBDIR)/$(CONFIG)/libgpr.so.0
-	$(Q) ln -sf libgpr.$(SHARED_EXT) $(LIBDIR)/$(CONFIG)/libgpr.so
+	$(Q) $(LD) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -shared -Wl,-soname,libgpr.so.0 -o $(LIBDIR)/$(CONFIG)/libgpr$(SHARED_VERSION).$(SHARED_EXT) $(LIBGPR_OBJS) $(LDLIBS) $(ZLIB_MERGE_LIBS)
+	$(Q) ln -sf $(SHARED_PREFIX)gpr$(SHARED_VERSION).$(SHARED_EXT) $(LIBDIR)/$(CONFIG)/libgpr$(SHARED_VERSION).so.0
+	$(Q) ln -sf $(SHARED_PREFIX)gpr$(SHARED_VERSION).$(SHARED_EXT) $(LIBDIR)/$(CONFIG)/libgpr$(SHARED_VERSION).so
 endif
 endif
 
@@ -2320,11 +2294,11 @@
 LIBGPR_TEST_UTIL_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(LIBGPR_TEST_UTIL_SRC))))
 
 
-$(LIBDIR)/$(CONFIG)/libgpr_test_util.a: $(ZLIB_DEP) $(OPENSSL_DEP)  $(LIBGPR_TEST_UTIL_OBJS)
+$(LIBDIR)/$(CONFIG)/libgpr_test_util.a: $(ZLIB_DEP)  $(LIBGPR_TEST_UTIL_OBJS) 
 	$(E) "[AR]      Creating $@"
 	$(Q) mkdir -p `dirname $@`
 	$(Q) rm -f $(LIBDIR)/$(CONFIG)/libgpr_test_util.a
-	$(Q) $(AR) rcs $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBGPR_TEST_UTIL_OBJS)
+	$(Q) $(AR) $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBGPR_TEST_UTIL_OBJS) 
 ifeq ($(SYSTEM),Darwin)
 	$(Q) ranlib $(LIBDIR)/$(CONFIG)/libgpr_test_util.a
 endif
@@ -2437,6 +2411,7 @@
     src/core/json/json_reader.c \
     src/core/json/json_string.c \
     src/core/json/json_writer.c \
+    src/core/surface/alarm.c \
     src/core/surface/api_trace.c \
     src/core/surface/byte_buffer.c \
     src/core/surface/byte_buffer_reader.c \
@@ -2488,11 +2463,17 @@
     src/core/census/context.c \
     src/core/census/initialize.c \
     src/core/census/operation.c \
-    src/core/census/tag_set.c \
+    src/core/census/placeholders.c \
     src/core/census/tracing.c \
 
 PUBLIC_HEADERS_C += \
     include/grpc/grpc_security.h \
+    include/grpc/impl/codegen/byte_buffer.h \
+    include/grpc/impl/codegen/compression_types.h \
+    include/grpc/impl/codegen/connectivity_state.h \
+    include/grpc/impl/codegen/grpc_types.h \
+    include/grpc/impl/codegen/propagation_bits.h \
+    include/grpc/impl/codegen/status.h \
     include/grpc/byte_buffer.h \
     include/grpc/byte_buffer_reader.h \
     include/grpc/compression.h \
@@ -2509,43 +2490,16 @@
 
 $(LIBDIR)/$(CONFIG)/libgrpc.a: openssl_dep_error
 
-ifeq ($(SYSTEM),MINGW32)
-$(LIBDIR)/$(CONFIG)/grpc.$(SHARED_EXT): openssl_dep_error
-else
-$(LIBDIR)/$(CONFIG)/libgrpc.$(SHARED_EXT): openssl_dep_error
-endif
+$(LIBDIR)/$(CONFIG)/$(SHARED_PREFIX)grpc$(SHARED_VERSION).$(SHARED_EXT): openssl_dep_error
 
 else
 
 
-$(LIBDIR)/$(CONFIG)/libgrpc.a: $(ZLIB_DEP) $(OPENSSL_DEP) $(LIBGRPC_OBJS)
+$(LIBDIR)/$(CONFIG)/libgrpc.a: $(ZLIB_DEP) $(OPENSSL_DEP) $(LIBGRPC_OBJS)  $(LIBGPR_OBJS)  $(ZLIB_MERGE_OBJS)  $(OPENSSL_MERGE_OBJS) 
 	$(E) "[AR]      Creating $@"
 	$(Q) mkdir -p `dirname $@`
 	$(Q) rm -f $(LIBDIR)/$(CONFIG)/libgrpc.a
-	$(Q) $(AR) rcs $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBGRPC_OBJS)
-	$(Q) rm -rf $(BUILDDIR_ABSOLUTE)/tmp-merge-grpc
-	$(Q) ( mkdir -p $(BUILDDIR_ABSOLUTE)/tmp-merge-grpc/grpc ; \
-	       cd $(BUILDDIR_ABSOLUTE)/tmp-merge-grpc/grpc ; \
-	       $(AR) x $(LIBDIR)/$(CONFIG)/libgrpc.a )
-	$(Q) for l in $(ZLIB_MERGE_LIBS) ; do ( \
-	       mkdir -p $(BUILDDIR_ABSOLUTE)/tmp-merge-grpc/zlib ; \
-	       cd $(BUILDDIR_ABSOLUTE)/tmp-merge-grpc/zlib ; \
-	       $(AR) x $${l} ) ; done
-	$(Q) for l in $(ZLIB_MERGE_LIBS) ; do ( \
-	       mkdir -p $(BUILDDIR_ABSOLUTE)/tmp-merge-grpc/zlib ; \
-	       cd $(BUILDDIR_ABSOLUTE)/tmp-merge-grpc/zlib ; \
-	       $(AR) x $${l} ) ; done
-	$(Q) for l in $(OPENSSL_MERGE_LIBS) ; do ( \
-	       mkdir -p $(BUILDDIR_ABSOLUTE)/tmp-merge-grpc/ssl ; \
-	       cd $(BUILDDIR_ABSOLUTE)/tmp-merge-grpc/ssl ; \
-	       $(AR) x $${l} ) ; done
-	$(Q) for l in $(OPENSSL_MERGE_LIBS) ; do ( \
-	       mkdir -p $(BUILDDIR_ABSOLUTE)/tmp-merge-grpc/ssl ; \
-	       cd $(BUILDDIR_ABSOLUTE)/tmp-merge-grpc/ssl ; \
-	       $(AR) x $${l} ) ; done
-	$(Q) rm -f $(LIBDIR)/$(CONFIG)/libgrpc.a $(BUILDDIR_ABSOLUTE)/tmp-merge-grpc/*/__.SYMDEF*
-	$(Q) ar rcs $(LIBDIR)/$(CONFIG)/libgrpc.a $(BUILDDIR_ABSOLUTE)/tmp-merge-grpc/*/*
-	$(Q) rm -rf $(BUILDDIR_ABSOLUTE)/tmp-merge-grpc
+	$(Q) $(AR) $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBGRPC_OBJS)  $(LIBGPR_OBJS)  $(ZLIB_MERGE_OBJS)  $(OPENSSL_MERGE_OBJS) 
 ifeq ($(SYSTEM),Darwin)
 	$(Q) ranlib $(LIBDIR)/$(CONFIG)/libgrpc.a
 endif
@@ -2553,20 +2507,20 @@
 
 
 ifeq ($(SYSTEM),MINGW32)
-$(LIBDIR)/$(CONFIG)/grpc.$(SHARED_EXT): $(LIBGRPC_OBJS)  $(ZLIB_DEP) $(LIBDIR)/$(CONFIG)/gpr.$(SHARED_EXT) $(OPENSSL_DEP)
+$(LIBDIR)/$(CONFIG)/grpc$(SHARED_VERSION).$(SHARED_EXT): $(LIBGRPC_OBJS)  $(ZLIB_DEP) $(LIBDIR)/$(CONFIG)/libgpr.a $(OPENSSL_DEP)
 	$(E) "[LD]      Linking $@"
 	$(Q) mkdir -p `dirname $@`
-	$(Q) $(LD) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -shared -Wl,--output-def=$(LIBDIR)/$(CONFIG)/grpc.def -Wl,--out-implib=$(LIBDIR)/$(CONFIG)/libgrpc-imp.a -o $(LIBDIR)/$(CONFIG)/grpc.$(SHARED_EXT) $(LIBGRPC_OBJS) $(LDLIBS) $(OPENSSL_MERGE_LIBS) $(LDLIBS_SECURE) $(ZLIB_MERGE_LIBS) -lgpr-imp
+	$(Q) $(LD) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -shared grpc.def -Wl,--output-def=$(LIBDIR)/$(CONFIG)/grpc$(SHARED_VERSION).def -Wl,--out-implib=$(LIBDIR)/$(CONFIG)/libgrpc$(SHARED_VERSION)-dll.a -o $(LIBDIR)/$(CONFIG)/grpc$(SHARED_VERSION).$(SHARED_EXT) $(LIBGRPC_OBJS) $(LDLIBS) $(LIBDIR)/$(CONFIG)/libgpr.a $(OPENSSL_MERGE_LIBS) $(LDLIBS_SECURE) $(ZLIB_MERGE_LIBS)
 else
-$(LIBDIR)/$(CONFIG)/libgrpc.$(SHARED_EXT): $(LIBGRPC_OBJS)  $(ZLIB_DEP) $(LIBDIR)/$(CONFIG)/libgpr.$(SHARED_EXT) $(OPENSSL_DEP)
+$(LIBDIR)/$(CONFIG)/libgrpc$(SHARED_VERSION).$(SHARED_EXT): $(LIBGRPC_OBJS)  $(ZLIB_DEP) $(LIBDIR)/$(CONFIG)/libgpr.a $(OPENSSL_DEP)
 	$(E) "[LD]      Linking $@"
 	$(Q) mkdir -p `dirname $@`
 ifeq ($(SYSTEM),Darwin)
-	$(Q) $(LD) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -install_name libgrpc.$(SHARED_EXT) -dynamiclib -o $(LIBDIR)/$(CONFIG)/libgrpc.$(SHARED_EXT) $(LIBGRPC_OBJS) $(LDLIBS) $(OPENSSL_MERGE_LIBS) $(LDLIBS_SECURE) $(ZLIB_MERGE_LIBS) -lgpr
+	$(Q) $(LD) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -install_name $(SHARED_PREFIX)grpc$(SHARED_VERSION).$(SHARED_EXT) -dynamiclib -o $(LIBDIR)/$(CONFIG)/libgrpc$(SHARED_VERSION).$(SHARED_EXT) $(LIBGRPC_OBJS) $(LDLIBS) $(LIBDIR)/$(CONFIG)/libgpr.a $(OPENSSL_MERGE_LIBS) $(LDLIBS_SECURE) $(ZLIB_MERGE_LIBS)
 else
-	$(Q) $(LD) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -shared -Wl,-soname,libgrpc.so.0 -o $(LIBDIR)/$(CONFIG)/libgrpc.$(SHARED_EXT) $(LIBGRPC_OBJS) $(LDLIBS) $(OPENSSL_MERGE_LIBS) $(LDLIBS_SECURE) $(ZLIB_MERGE_LIBS) -lgpr
-	$(Q) ln -sf libgrpc.$(SHARED_EXT) $(LIBDIR)/$(CONFIG)/libgrpc.so.0
-	$(Q) ln -sf libgrpc.$(SHARED_EXT) $(LIBDIR)/$(CONFIG)/libgrpc.so
+	$(Q) $(LD) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -shared -Wl,-soname,libgrpc.so.0 -o $(LIBDIR)/$(CONFIG)/libgrpc$(SHARED_VERSION).$(SHARED_EXT) $(LIBGRPC_OBJS) $(LDLIBS) $(LIBDIR)/$(CONFIG)/libgpr.a $(OPENSSL_MERGE_LIBS) $(LDLIBS_SECURE) $(ZLIB_MERGE_LIBS)
+	$(Q) ln -sf $(SHARED_PREFIX)grpc$(SHARED_VERSION).$(SHARED_EXT) $(LIBDIR)/$(CONFIG)/libgrpc$(SHARED_VERSION).so.0
+	$(Q) ln -sf $(SHARED_PREFIX)grpc$(SHARED_VERSION).$(SHARED_EXT) $(LIBDIR)/$(CONFIG)/libgrpc$(SHARED_VERSION).so
 endif
 endif
 
@@ -2608,11 +2562,11 @@
 else
 
 
-$(LIBDIR)/$(CONFIG)/libgrpc_test_util.a: $(ZLIB_DEP) $(OPENSSL_DEP) $(LIBGRPC_TEST_UTIL_OBJS)
+$(LIBDIR)/$(CONFIG)/libgrpc_test_util.a: $(ZLIB_DEP) $(OPENSSL_DEP) $(LIBGRPC_TEST_UTIL_OBJS) 
 	$(E) "[AR]      Creating $@"
 	$(Q) mkdir -p `dirname $@`
 	$(Q) rm -f $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a
-	$(Q) $(AR) rcs $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBGRPC_TEST_UTIL_OBJS)
+	$(Q) $(AR) $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBGRPC_TEST_UTIL_OBJS) 
 ifeq ($(SYSTEM),Darwin)
 	$(Q) ranlib $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a
 endif
@@ -2644,11 +2598,11 @@
 LIBGRPC_TEST_UTIL_UNSECURE_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(LIBGRPC_TEST_UTIL_UNSECURE_SRC))))
 
 
-$(LIBDIR)/$(CONFIG)/libgrpc_test_util_unsecure.a: $(ZLIB_DEP) $(OPENSSL_DEP)  $(LIBGRPC_TEST_UTIL_UNSECURE_OBJS)
+$(LIBDIR)/$(CONFIG)/libgrpc_test_util_unsecure.a: $(ZLIB_DEP)  $(LIBGRPC_TEST_UTIL_UNSECURE_OBJS) 
 	$(E) "[AR]      Creating $@"
 	$(Q) mkdir -p `dirname $@`
 	$(Q) rm -f $(LIBDIR)/$(CONFIG)/libgrpc_test_util_unsecure.a
-	$(Q) $(AR) rcs $(LIBDIR)/$(CONFIG)/libgrpc_test_util_unsecure.a $(LIBGRPC_TEST_UTIL_UNSECURE_OBJS)
+	$(Q) $(AR) $(LIBDIR)/$(CONFIG)/libgrpc_test_util_unsecure.a $(LIBGRPC_TEST_UTIL_UNSECURE_OBJS) 
 ifeq ($(SYSTEM),Darwin)
 	$(Q) ranlib $(LIBDIR)/$(CONFIG)/libgrpc_test_util_unsecure.a
 endif
@@ -2741,6 +2695,7 @@
     src/core/json/json_reader.c \
     src/core/json/json_string.c \
     src/core/json/json_writer.c \
+    src/core/surface/alarm.c \
     src/core/surface/api_trace.c \
     src/core/surface/byte_buffer.c \
     src/core/surface/byte_buffer_reader.c \
@@ -2792,7 +2747,7 @@
     src/core/census/context.c \
     src/core/census/initialize.c \
     src/core/census/operation.c \
-    src/core/census/tag_set.c \
+    src/core/census/placeholders.c \
     src/core/census/tracing.c \
 
 PUBLIC_HEADERS_C += \
@@ -2801,31 +2756,22 @@
     include/grpc/compression.h \
     include/grpc/grpc.h \
     include/grpc/status.h \
+    include/grpc/impl/codegen/byte_buffer.h \
+    include/grpc/impl/codegen/compression_types.h \
+    include/grpc/impl/codegen/connectivity_state.h \
+    include/grpc/impl/codegen/grpc_types.h \
+    include/grpc/impl/codegen/propagation_bits.h \
+    include/grpc/impl/codegen/status.h \
     include/grpc/census.h \
 
 LIBGRPC_UNSECURE_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(LIBGRPC_UNSECURE_SRC))))
 
 
-$(LIBDIR)/$(CONFIG)/libgrpc_unsecure.a: $(ZLIB_DEP) $(OPENSSL_DEP)  $(LIBGRPC_UNSECURE_OBJS)
+$(LIBDIR)/$(CONFIG)/libgrpc_unsecure.a: $(ZLIB_DEP)  $(LIBGRPC_UNSECURE_OBJS)  $(LIBGPR_OBJS)  $(ZLIB_MERGE_OBJS) 
 	$(E) "[AR]      Creating $@"
 	$(Q) mkdir -p `dirname $@`
 	$(Q) rm -f $(LIBDIR)/$(CONFIG)/libgrpc_unsecure.a
-	$(Q) $(AR) rcs $(LIBDIR)/$(CONFIG)/libgrpc_unsecure.a $(LIBGRPC_UNSECURE_OBJS)
-	$(Q) rm -rf $(BUILDDIR_ABSOLUTE)/tmp-merge-grpc_unsecure
-	$(Q) ( mkdir -p $(BUILDDIR_ABSOLUTE)/tmp-merge-grpc_unsecure/grpc ; \
-	       cd $(BUILDDIR_ABSOLUTE)/tmp-merge-grpc_unsecure/grpc ; \
-	       $(AR) x $(LIBDIR)/$(CONFIG)/libgrpc_unsecure.a )
-	$(Q) for l in $(ZLIB_MERGE_LIBS) ; do ( \
-	       mkdir -p $(BUILDDIR_ABSOLUTE)/tmp-merge-grpc_unsecure/zlib ; \
-	       cd $(BUILDDIR_ABSOLUTE)/tmp-merge-grpc_unsecure/zlib ; \
-	       $(AR) x $${l} ) ; done
-	$(Q) for l in $(ZLIB_MERGE_LIBS) ; do ( \
-	       mkdir -p $(BUILDDIR_ABSOLUTE)/tmp-merge-grpc_unsecure/zlib ; \
-	       cd $(BUILDDIR_ABSOLUTE)/tmp-merge-grpc_unsecure/zlib ; \
-	       $(AR) x $${l} ) ; done
-	$(Q) rm -f $(LIBDIR)/$(CONFIG)/libgrpc_unsecure.a $(BUILDDIR_ABSOLUTE)/tmp-merge-grpc_unsecure/*/__.SYMDEF*
-	$(Q) ar rcs $(LIBDIR)/$(CONFIG)/libgrpc_unsecure.a $(BUILDDIR_ABSOLUTE)/tmp-merge-grpc_unsecure/*/*
-	$(Q) rm -rf $(BUILDDIR_ABSOLUTE)/tmp-merge-grpc_unsecure
+	$(Q) $(AR) $(LIBDIR)/$(CONFIG)/libgrpc_unsecure.a $(LIBGRPC_UNSECURE_OBJS)  $(LIBGPR_OBJS)  $(ZLIB_MERGE_OBJS) 
 ifeq ($(SYSTEM),Darwin)
 	$(Q) ranlib $(LIBDIR)/$(CONFIG)/libgrpc_unsecure.a
 endif
@@ -2833,20 +2779,20 @@
 
 
 ifeq ($(SYSTEM),MINGW32)
-$(LIBDIR)/$(CONFIG)/grpc_unsecure.$(SHARED_EXT): $(LIBGRPC_UNSECURE_OBJS)  $(ZLIB_DEP) $(LIBDIR)/$(CONFIG)/gpr.$(SHARED_EXT)
+$(LIBDIR)/$(CONFIG)/grpc_unsecure$(SHARED_VERSION).$(SHARED_EXT): $(LIBGRPC_UNSECURE_OBJS)  $(ZLIB_DEP) $(LIBDIR)/$(CONFIG)/libgpr.a
 	$(E) "[LD]      Linking $@"
 	$(Q) mkdir -p `dirname $@`
-	$(Q) $(LD) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -shared -Wl,--output-def=$(LIBDIR)/$(CONFIG)/grpc_unsecure.def -Wl,--out-implib=$(LIBDIR)/$(CONFIG)/libgrpc_unsecure-imp.a -o $(LIBDIR)/$(CONFIG)/grpc_unsecure.$(SHARED_EXT) $(LIBGRPC_UNSECURE_OBJS) $(LDLIBS) $(ZLIB_MERGE_LIBS) -lgpr-imp
+	$(Q) $(LD) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -shared grpc_unsecure.def -Wl,--output-def=$(LIBDIR)/$(CONFIG)/grpc_unsecure$(SHARED_VERSION).def -Wl,--out-implib=$(LIBDIR)/$(CONFIG)/libgrpc_unsecure$(SHARED_VERSION)-dll.a -o $(LIBDIR)/$(CONFIG)/grpc_unsecure$(SHARED_VERSION).$(SHARED_EXT) $(LIBGRPC_UNSECURE_OBJS) $(LDLIBS) $(LIBDIR)/$(CONFIG)/libgpr.a $(ZLIB_MERGE_LIBS)
 else
-$(LIBDIR)/$(CONFIG)/libgrpc_unsecure.$(SHARED_EXT): $(LIBGRPC_UNSECURE_OBJS)  $(ZLIB_DEP) $(LIBDIR)/$(CONFIG)/libgpr.$(SHARED_EXT)
+$(LIBDIR)/$(CONFIG)/libgrpc_unsecure$(SHARED_VERSION).$(SHARED_EXT): $(LIBGRPC_UNSECURE_OBJS)  $(ZLIB_DEP) $(LIBDIR)/$(CONFIG)/libgpr.a
 	$(E) "[LD]      Linking $@"
 	$(Q) mkdir -p `dirname $@`
 ifeq ($(SYSTEM),Darwin)
-	$(Q) $(LD) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -install_name libgrpc_unsecure.$(SHARED_EXT) -dynamiclib -o $(LIBDIR)/$(CONFIG)/libgrpc_unsecure.$(SHARED_EXT) $(LIBGRPC_UNSECURE_OBJS) $(LDLIBS) $(ZLIB_MERGE_LIBS) -lgpr
+	$(Q) $(LD) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -install_name $(SHARED_PREFIX)grpc_unsecure$(SHARED_VERSION).$(SHARED_EXT) -dynamiclib -o $(LIBDIR)/$(CONFIG)/libgrpc_unsecure$(SHARED_VERSION).$(SHARED_EXT) $(LIBGRPC_UNSECURE_OBJS) $(LDLIBS) $(LIBDIR)/$(CONFIG)/libgpr.a $(ZLIB_MERGE_LIBS)
 else
-	$(Q) $(LD) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -shared -Wl,-soname,libgrpc_unsecure.so.0 -o $(LIBDIR)/$(CONFIG)/libgrpc_unsecure.$(SHARED_EXT) $(LIBGRPC_UNSECURE_OBJS) $(LDLIBS) $(ZLIB_MERGE_LIBS) -lgpr
-	$(Q) ln -sf libgrpc_unsecure.$(SHARED_EXT) $(LIBDIR)/$(CONFIG)/libgrpc_unsecure.so.0
-	$(Q) ln -sf libgrpc_unsecure.$(SHARED_EXT) $(LIBDIR)/$(CONFIG)/libgrpc_unsecure.so
+	$(Q) $(LD) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -shared -Wl,-soname,libgrpc_unsecure.so.0 -o $(LIBDIR)/$(CONFIG)/libgrpc_unsecure$(SHARED_VERSION).$(SHARED_EXT) $(LIBGRPC_UNSECURE_OBJS) $(LDLIBS) $(LIBDIR)/$(CONFIG)/libgpr.a $(ZLIB_MERGE_LIBS)
+	$(Q) ln -sf $(SHARED_PREFIX)grpc_unsecure$(SHARED_VERSION).$(SHARED_EXT) $(LIBDIR)/$(CONFIG)/libgrpc_unsecure$(SHARED_VERSION).so.0
+	$(Q) ln -sf $(SHARED_PREFIX)grpc_unsecure$(SHARED_VERSION).$(SHARED_EXT) $(LIBDIR)/$(CONFIG)/libgrpc_unsecure$(SHARED_VERSION).so
 endif
 endif
 
@@ -2864,11 +2810,11 @@
 LIBGRPC_ZOOKEEPER_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(LIBGRPC_ZOOKEEPER_SRC))))
 
 
-$(LIBDIR)/$(CONFIG)/libgrpc_zookeeper.a: $(ZLIB_DEP) $(OPENSSL_DEP)  $(LIBGRPC_ZOOKEEPER_OBJS)
+$(LIBDIR)/$(CONFIG)/libgrpc_zookeeper.a: $(ZLIB_DEP)  $(LIBGRPC_ZOOKEEPER_OBJS) 
 	$(E) "[AR]      Creating $@"
 	$(Q) mkdir -p `dirname $@`
 	$(Q) rm -f $(LIBDIR)/$(CONFIG)/libgrpc_zookeeper.a
-	$(Q) $(AR) rcs $(LIBDIR)/$(CONFIG)/libgrpc_zookeeper.a $(LIBGRPC_ZOOKEEPER_OBJS)
+	$(Q) $(AR) $(LIBDIR)/$(CONFIG)/libgrpc_zookeeper.a $(LIBGRPC_ZOOKEEPER_OBJS) 
 ifeq ($(SYSTEM),Darwin)
 	$(Q) ranlib $(LIBDIR)/$(CONFIG)/libgrpc_zookeeper.a
 endif
@@ -2876,20 +2822,20 @@
 
 
 ifeq ($(SYSTEM),MINGW32)
-$(LIBDIR)/$(CONFIG)/grpc_zookeeper.$(SHARED_EXT): $(LIBGRPC_ZOOKEEPER_OBJS)  $(ZLIB_DEP) $(LIBDIR)/$(CONFIG)/gpr.$(SHARED_EXT) $(LIBDIR)/$(CONFIG)/grpc.$(SHARED_EXT)
+$(LIBDIR)/$(CONFIG)/grpc_zookeeper$(SHARED_VERSION).$(SHARED_EXT): $(LIBGRPC_ZOOKEEPER_OBJS)  $(ZLIB_DEP) $(LIBDIR)/$(CONFIG)/gpr.$(SHARED_EXT) $(LIBDIR)/$(CONFIG)/grpc.$(SHARED_EXT)
 	$(E) "[LD]      Linking $@"
 	$(Q) mkdir -p `dirname $@`
-	$(Q) $(LD) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -shared -Wl,--output-def=$(LIBDIR)/$(CONFIG)/grpc_zookeeper.def -Wl,--out-implib=$(LIBDIR)/$(CONFIG)/libgrpc_zookeeper-imp.a -o $(LIBDIR)/$(CONFIG)/grpc_zookeeper.$(SHARED_EXT) $(LIBGRPC_ZOOKEEPER_OBJS) $(LDLIBS) $(ZLIB_MERGE_LIBS) -lgpr-imp -lgrpc-imp
+	$(Q) $(LD) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -shared grpc_zookeeper.def -Wl,--output-def=$(LIBDIR)/$(CONFIG)/grpc_zookeeper$(SHARED_VERSION).def -Wl,--out-implib=$(LIBDIR)/$(CONFIG)/libgrpc_zookeeper$(SHARED_VERSION)-dll.a -o $(LIBDIR)/$(CONFIG)/grpc_zookeeper$(SHARED_VERSION).$(SHARED_EXT) $(LIBGRPC_ZOOKEEPER_OBJS) $(LDLIBS) $(ZLIB_MERGE_LIBS) -lgpr-imp -lgrpc-imp
 else
-$(LIBDIR)/$(CONFIG)/libgrpc_zookeeper.$(SHARED_EXT): $(LIBGRPC_ZOOKEEPER_OBJS)  $(ZLIB_DEP) $(LIBDIR)/$(CONFIG)/libgpr.$(SHARED_EXT) $(LIBDIR)/$(CONFIG)/libgrpc.$(SHARED_EXT)
+$(LIBDIR)/$(CONFIG)/libgrpc_zookeeper$(SHARED_VERSION).$(SHARED_EXT): $(LIBGRPC_ZOOKEEPER_OBJS)  $(ZLIB_DEP) $(LIBDIR)/$(CONFIG)/libgpr.$(SHARED_EXT) $(LIBDIR)/$(CONFIG)/libgrpc.$(SHARED_EXT)
 	$(E) "[LD]      Linking $@"
 	$(Q) mkdir -p `dirname $@`
 ifeq ($(SYSTEM),Darwin)
-	$(Q) $(LD) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -install_name libgrpc_zookeeper.$(SHARED_EXT) -dynamiclib -o $(LIBDIR)/$(CONFIG)/libgrpc_zookeeper.$(SHARED_EXT) $(LIBGRPC_ZOOKEEPER_OBJS) $(LDLIBS) $(ZLIB_MERGE_LIBS) -lgpr -lgrpc -lzookeeper_mt
+	$(Q) $(LD) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -install_name $(SHARED_PREFIX)grpc_zookeeper$(SHARED_VERSION).$(SHARED_EXT) -dynamiclib -o $(LIBDIR)/$(CONFIG)/libgrpc_zookeeper$(SHARED_VERSION).$(SHARED_EXT) $(LIBGRPC_ZOOKEEPER_OBJS) $(LDLIBS) $(ZLIB_MERGE_LIBS) -lgpr -lgrpc -lzookeeper_mt
 else
-	$(Q) $(LD) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -shared -Wl,-soname,libgrpc_zookeeper.so.0 -o $(LIBDIR)/$(CONFIG)/libgrpc_zookeeper.$(SHARED_EXT) $(LIBGRPC_ZOOKEEPER_OBJS) $(LDLIBS) $(ZLIB_MERGE_LIBS) -lgpr -lgrpc -lzookeeper_mt
-	$(Q) ln -sf libgrpc_zookeeper.$(SHARED_EXT) $(LIBDIR)/$(CONFIG)/libgrpc_zookeeper.so.0
-	$(Q) ln -sf libgrpc_zookeeper.$(SHARED_EXT) $(LIBDIR)/$(CONFIG)/libgrpc_zookeeper.so
+	$(Q) $(LD) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -shared -Wl,-soname,libgrpc_zookeeper.so.0 -o $(LIBDIR)/$(CONFIG)/libgrpc_zookeeper$(SHARED_VERSION).$(SHARED_EXT) $(LIBGRPC_ZOOKEEPER_OBJS) $(LDLIBS) $(ZLIB_MERGE_LIBS) -lgpr -lgrpc -lzookeeper_mt
+	$(Q) ln -sf $(SHARED_PREFIX)grpc_zookeeper$(SHARED_VERSION).$(SHARED_EXT) $(LIBDIR)/$(CONFIG)/libgrpc_zookeeper$(SHARED_VERSION).so.0
+	$(Q) ln -sf $(SHARED_PREFIX)grpc_zookeeper$(SHARED_VERSION).$(SHARED_EXT) $(LIBDIR)/$(CONFIG)/libgrpc_zookeeper$(SHARED_VERSION).so
 endif
 endif
 
@@ -2915,11 +2861,11 @@
 else
 
 
-$(LIBDIR)/$(CONFIG)/libreconnect_server.a: $(ZLIB_DEP) $(OPENSSL_DEP) $(LIBRECONNECT_SERVER_OBJS)
+$(LIBDIR)/$(CONFIG)/libreconnect_server.a: $(ZLIB_DEP) $(OPENSSL_DEP) $(LIBRECONNECT_SERVER_OBJS) 
 	$(E) "[AR]      Creating $@"
 	$(Q) mkdir -p `dirname $@`
 	$(Q) rm -f $(LIBDIR)/$(CONFIG)/libreconnect_server.a
-	$(Q) $(AR) rcs $(LIBDIR)/$(CONFIG)/libreconnect_server.a $(LIBRECONNECT_SERVER_OBJS)
+	$(Q) $(AR) $(LIBDIR)/$(CONFIG)/libreconnect_server.a $(LIBRECONNECT_SERVER_OBJS) 
 ifeq ($(SYSTEM),Darwin)
 	$(Q) ranlib $(LIBDIR)/$(CONFIG)/libreconnect_server.a
 endif
@@ -2953,11 +2899,11 @@
 else
 
 
-$(LIBDIR)/$(CONFIG)/libtest_tcp_server.a: $(ZLIB_DEP) $(OPENSSL_DEP) $(LIBTEST_TCP_SERVER_OBJS)
+$(LIBDIR)/$(CONFIG)/libtest_tcp_server.a: $(ZLIB_DEP) $(OPENSSL_DEP) $(LIBTEST_TCP_SERVER_OBJS) 
 	$(E) "[AR]      Creating $@"
 	$(Q) mkdir -p `dirname $@`
 	$(Q) rm -f $(LIBDIR)/$(CONFIG)/libtest_tcp_server.a
-	$(Q) $(AR) rcs $(LIBDIR)/$(CONFIG)/libtest_tcp_server.a $(LIBTEST_TCP_SERVER_OBJS)
+	$(Q) $(AR) $(LIBDIR)/$(CONFIG)/libtest_tcp_server.a $(LIBTEST_TCP_SERVER_OBJS) 
 ifeq ($(SYSTEM),Darwin)
 	$(Q) ranlib $(LIBDIR)/$(CONFIG)/libtest_tcp_server.a
 endif
@@ -2988,6 +2934,7 @@
     src/cpp/client/credentials.cc \
     src/cpp/client/generic_stub.cc \
     src/cpp/client/insecure_credentials.cc \
+    src/cpp/common/alarm.cc \
     src/cpp/common/call.cc \
     src/cpp/common/channel_arguments.cc \
     src/cpp/common/completion_queue.cc \
@@ -3007,8 +2954,10 @@
     src/cpp/util/status.cc \
     src/cpp/util/string_ref.cc \
     src/cpp/util/time.cc \
+    src/cpp/codegen/grpc_library.cc \
 
 PUBLIC_HEADERS_CXX += \
+    include/grpc++/alarm.h \
     include/grpc++/channel.h \
     include/grpc++/client_context.h \
     include/grpc++/completion_queue.h \
@@ -3019,6 +2968,7 @@
     include/grpc++/impl/call.h \
     include/grpc++/impl/client_unary_call.h \
     include/grpc++/impl/grpc_library.h \
+    include/grpc++/impl/method_handler_impl.h \
     include/grpc++/impl/proto_utils.h \
     include/grpc++/impl/rpc_method.h \
     include/grpc++/impl/rpc_service_method.h \
@@ -3051,6 +3001,36 @@
     include/grpc++/support/stub_options.h \
     include/grpc++/support/sync_stream.h \
     include/grpc++/support/time.h \
+    include/grpc++/impl/codegen/async_stream.h \
+    include/grpc++/impl/codegen/async_unary_call.h \
+    include/grpc++/impl/codegen/call.h \
+    include/grpc++/impl/codegen/call_hook.h \
+    include/grpc++/impl/codegen/channel_interface.h \
+    include/grpc++/impl/codegen/client_context.h \
+    include/grpc++/impl/codegen/client_unary_call.h \
+    include/grpc++/impl/codegen/completion_queue.h \
+    include/grpc++/impl/codegen/completion_queue_tag.h \
+    include/grpc++/impl/codegen/config.h \
+    include/grpc++/impl/codegen/config_protobuf.h \
+    include/grpc++/impl/codegen/grpc_library.h \
+    include/grpc++/impl/codegen/method_handler_impl.h \
+    include/grpc++/impl/codegen/proto_utils.h \
+    include/grpc++/impl/codegen/rpc_method.h \
+    include/grpc++/impl/codegen/rpc_service_method.h \
+    include/grpc++/impl/codegen/security/auth_context.h \
+    include/grpc++/impl/codegen/serialization_traits.h \
+    include/grpc++/impl/codegen/server_context.h \
+    include/grpc++/impl/codegen/server_interface.h \
+    include/grpc++/impl/codegen/service_type.h \
+    include/grpc++/impl/codegen/status.h \
+    include/grpc++/impl/codegen/status_code_enum.h \
+    include/grpc++/impl/codegen/string_ref.h \
+    include/grpc++/impl/codegen/stub_options.h \
+    include/grpc++/impl/codegen/sync.h \
+    include/grpc++/impl/codegen/sync_cxx11.h \
+    include/grpc++/impl/codegen/sync_no_cxx11.h \
+    include/grpc++/impl/codegen/sync_stream.h \
+    include/grpc++/impl/codegen/time.h \
 
 LIBGRPC++_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(LIBGRPC++_SRC))))
 
@@ -3061,11 +3041,7 @@
 
 $(LIBDIR)/$(CONFIG)/libgrpc++.a: openssl_dep_error
 
-ifeq ($(SYSTEM),MINGW32)
-$(LIBDIR)/$(CONFIG)/grpc++.$(SHARED_EXT): openssl_dep_error
-else
-$(LIBDIR)/$(CONFIG)/libgrpc++.$(SHARED_EXT): openssl_dep_error
-endif
+$(LIBDIR)/$(CONFIG)/$(SHARED_PREFIX)grpc++$(SHARED_VERSION).$(SHARED_EXT): openssl_dep_error
 
 else
 
@@ -3075,34 +3051,15 @@
 
 $(LIBDIR)/$(CONFIG)/libgrpc++.a: protobuf_dep_error
 
-ifeq ($(SYSTEM),MINGW32)
-$(LIBDIR)/$(CONFIG)/grpc++.$(SHARED_EXT): protobuf_dep_error
-else
-$(LIBDIR)/$(CONFIG)/libgrpc++.$(SHARED_EXT): protobuf_dep_error
-endif
+$(LIBDIR)/$(CONFIG)/$(SHARED_PREFIX)grpc++$(SHARED_VERSION).$(SHARED_EXT): protobuf_dep_error
 
 else
 
-$(LIBDIR)/$(CONFIG)/libgrpc++.a: $(ZLIB_DEP) $(OPENSSL_DEP) $(PROTOBUF_DEP) $(LIBGRPC++_OBJS)
+$(LIBDIR)/$(CONFIG)/libgrpc++.a: $(ZLIB_DEP) $(OPENSSL_DEP) $(PROTOBUF_DEP) $(LIBGRPC++_OBJS)  $(LIBGPR_OBJS)  $(ZLIB_MERGE_OBJS) 
 	$(E) "[AR]      Creating $@"
 	$(Q) mkdir -p `dirname $@`
 	$(Q) rm -f $(LIBDIR)/$(CONFIG)/libgrpc++.a
-	$(Q) $(AR) rcs $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBGRPC++_OBJS)
-	$(Q) rm -rf $(BUILDDIR_ABSOLUTE)/tmp-merge-grpc++
-	$(Q) ( mkdir -p $(BUILDDIR_ABSOLUTE)/tmp-merge-grpc++/grpc ; \
-	       cd $(BUILDDIR_ABSOLUTE)/tmp-merge-grpc++/grpc ; \
-	       $(AR) x $(LIBDIR)/$(CONFIG)/libgrpc++.a )
-	$(Q) for l in $(ZLIB_MERGE_LIBS) ; do ( \
-	       mkdir -p $(BUILDDIR_ABSOLUTE)/tmp-merge-grpc++/zlib ; \
-	       cd $(BUILDDIR_ABSOLUTE)/tmp-merge-grpc++/zlib ; \
-	       $(AR) x $${l} ) ; done
-	$(Q) for l in $(ZLIB_MERGE_LIBS) ; do ( \
-	       mkdir -p $(BUILDDIR_ABSOLUTE)/tmp-merge-grpc++/zlib ; \
-	       cd $(BUILDDIR_ABSOLUTE)/tmp-merge-grpc++/zlib ; \
-	       $(AR) x $${l} ) ; done
-	$(Q) rm -f $(LIBDIR)/$(CONFIG)/libgrpc++.a $(BUILDDIR_ABSOLUTE)/tmp-merge-grpc++/*/__.SYMDEF*
-	$(Q) ar rcs $(LIBDIR)/$(CONFIG)/libgrpc++.a $(BUILDDIR_ABSOLUTE)/tmp-merge-grpc++/*/*
-	$(Q) rm -rf $(BUILDDIR_ABSOLUTE)/tmp-merge-grpc++
+	$(Q) $(AR) $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBGRPC++_OBJS)  $(LIBGPR_OBJS)  $(ZLIB_MERGE_OBJS) 
 ifeq ($(SYSTEM),Darwin)
 	$(Q) ranlib $(LIBDIR)/$(CONFIG)/libgrpc++.a
 endif
@@ -3110,20 +3067,20 @@
 
 
 ifeq ($(SYSTEM),MINGW32)
-$(LIBDIR)/$(CONFIG)/grpc++.$(SHARED_EXT): $(LIBGRPC++_OBJS)  $(ZLIB_DEP) $(PROTOBUF_DEP) $(LIBDIR)/$(CONFIG)/gpr.$(SHARED_EXT) $(LIBDIR)/$(CONFIG)/grpc.$(SHARED_EXT) $(OPENSSL_DEP)
+$(LIBDIR)/$(CONFIG)/grpc++$(SHARED_VERSION).$(SHARED_EXT): $(LIBGRPC++_OBJS)  $(ZLIB_DEP) $(PROTOBUF_DEP) $(LIBDIR)/$(CONFIG)/grpc.$(SHARED_EXT) $(OPENSSL_DEP)
 	$(E) "[LD]      Linking $@"
 	$(Q) mkdir -p `dirname $@`
-	$(Q) $(LDXX) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -shared -Wl,--output-def=$(LIBDIR)/$(CONFIG)/grpc++.def -Wl,--out-implib=$(LIBDIR)/$(CONFIG)/libgrpc++-imp.a -o $(LIBDIR)/$(CONFIG)/grpc++.$(SHARED_EXT) $(LIBGRPC++_OBJS) $(LDLIBS) $(ZLIB_MERGE_LIBS) $(LDLIBSXX) $(LDLIBS_PROTOBUF) -lgpr-imp -lgrpc-imp
+	$(Q) $(LDXX) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -shared grpc++.def -Wl,--output-def=$(LIBDIR)/$(CONFIG)/grpc++$(SHARED_VERSION).def -Wl,--out-implib=$(LIBDIR)/$(CONFIG)/libgrpc++$(SHARED_VERSION)-dll.a -o $(LIBDIR)/$(CONFIG)/grpc++$(SHARED_VERSION).$(SHARED_EXT) $(LIBGRPC++_OBJS) $(LDLIBS) $(ZLIB_MERGE_LIBS) $(LDLIBSXX) $(LDLIBS_PROTOBUF) -lgrpc-imp
 else
-$(LIBDIR)/$(CONFIG)/libgrpc++.$(SHARED_EXT): $(LIBGRPC++_OBJS)  $(ZLIB_DEP) $(PROTOBUF_DEP) $(LIBDIR)/$(CONFIG)/libgpr.$(SHARED_EXT) $(LIBDIR)/$(CONFIG)/libgrpc.$(SHARED_EXT) $(OPENSSL_DEP)
+$(LIBDIR)/$(CONFIG)/libgrpc++$(SHARED_VERSION).$(SHARED_EXT): $(LIBGRPC++_OBJS)  $(ZLIB_DEP) $(PROTOBUF_DEP) $(LIBDIR)/$(CONFIG)/libgrpc.$(SHARED_EXT) $(OPENSSL_DEP)
 	$(E) "[LD]      Linking $@"
 	$(Q) mkdir -p `dirname $@`
 ifeq ($(SYSTEM),Darwin)
-	$(Q) $(LDXX) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -install_name libgrpc++.$(SHARED_EXT) -dynamiclib -o $(LIBDIR)/$(CONFIG)/libgrpc++.$(SHARED_EXT) $(LIBGRPC++_OBJS) $(LDLIBS) $(ZLIB_MERGE_LIBS) $(LDLIBSXX) $(LDLIBS_PROTOBUF) -lgpr -lgrpc
+	$(Q) $(LDXX) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -install_name $(SHARED_PREFIX)grpc++$(SHARED_VERSION).$(SHARED_EXT) -dynamiclib -o $(LIBDIR)/$(CONFIG)/libgrpc++$(SHARED_VERSION).$(SHARED_EXT) $(LIBGRPC++_OBJS) $(LDLIBS) $(ZLIB_MERGE_LIBS) $(LDLIBSXX) $(LDLIBS_PROTOBUF) -lgrpc
 else
-	$(Q) $(LDXX) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -shared -Wl,-soname,libgrpc++.so.0 -o $(LIBDIR)/$(CONFIG)/libgrpc++.$(SHARED_EXT) $(LIBGRPC++_OBJS) $(LDLIBS) $(ZLIB_MERGE_LIBS) $(LDLIBSXX) $(LDLIBS_PROTOBUF) -lgpr -lgrpc
-	$(Q) ln -sf libgrpc++.$(SHARED_EXT) $(LIBDIR)/$(CONFIG)/libgrpc++.so.0
-	$(Q) ln -sf libgrpc++.$(SHARED_EXT) $(LIBDIR)/$(CONFIG)/libgrpc++.so
+	$(Q) $(LDXX) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -shared -Wl,-soname,libgrpc++.so.0 -o $(LIBDIR)/$(CONFIG)/libgrpc++$(SHARED_VERSION).$(SHARED_EXT) $(LIBGRPC++_OBJS) $(LDLIBS) $(ZLIB_MERGE_LIBS) $(LDLIBSXX) $(LDLIBS_PROTOBUF) -lgrpc
+	$(Q) ln -sf $(SHARED_PREFIX)grpc++$(SHARED_VERSION).$(SHARED_EXT) $(LIBDIR)/$(CONFIG)/libgrpc++$(SHARED_VERSION).so.0
+	$(Q) ln -sf $(SHARED_PREFIX)grpc++$(SHARED_VERSION).$(SHARED_EXT) $(LIBDIR)/$(CONFIG)/libgrpc++$(SHARED_VERSION).so
 endif
 endif
 
@@ -3163,11 +3120,11 @@
 
 else
 
-$(LIBDIR)/$(CONFIG)/libgrpc++_test_config.a: $(ZLIB_DEP) $(OPENSSL_DEP) $(PROTOBUF_DEP) $(LIBGRPC++_TEST_CONFIG_OBJS)
+$(LIBDIR)/$(CONFIG)/libgrpc++_test_config.a: $(ZLIB_DEP) $(OPENSSL_DEP) $(PROTOBUF_DEP) $(LIBGRPC++_TEST_CONFIG_OBJS) 
 	$(E) "[AR]      Creating $@"
 	$(Q) mkdir -p `dirname $@`
 	$(Q) rm -f $(LIBDIR)/$(CONFIG)/libgrpc++_test_config.a
-	$(Q) $(AR) rcs $(LIBDIR)/$(CONFIG)/libgrpc++_test_config.a $(LIBGRPC++_TEST_CONFIG_OBJS)
+	$(Q) $(AR) $(LIBDIR)/$(CONFIG)/libgrpc++_test_config.a $(LIBGRPC++_TEST_CONFIG_OBJS) 
 ifeq ($(SYSTEM),Darwin)
 	$(Q) ranlib $(LIBDIR)/$(CONFIG)/libgrpc++_test_config.a
 endif
@@ -3190,6 +3147,8 @@
     $(GENDIR)/src/proto/grpc/testing/echo_messages.pb.cc $(GENDIR)/src/proto/grpc/testing/echo_messages.grpc.pb.cc \
     $(GENDIR)/src/proto/grpc/testing/echo.pb.cc $(GENDIR)/src/proto/grpc/testing/echo.grpc.pb.cc \
     $(GENDIR)/src/proto/grpc/testing/duplicate/echo_duplicate.pb.cc $(GENDIR)/src/proto/grpc/testing/duplicate/echo_duplicate.grpc.pb.cc \
+    test/cpp/end2end/test_service_impl.cc \
+    test/cpp/util/byte_buffer_proto_helper.cc \
     test/cpp/util/cli_call.cc \
     test/cpp/util/create_test_channel.cc \
     test/cpp/util/string_ref_helper.cc \
@@ -3217,11 +3176,11 @@
 
 else
 
-$(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a: $(ZLIB_DEP) $(OPENSSL_DEP) $(PROTOBUF_DEP) $(LIBGRPC++_TEST_UTIL_OBJS)
+$(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a: $(ZLIB_DEP) $(OPENSSL_DEP) $(PROTOBUF_DEP) $(LIBGRPC++_TEST_UTIL_OBJS) 
 	$(E) "[AR]      Creating $@"
 	$(Q) mkdir -p `dirname $@`
 	$(Q) rm -f $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a
-	$(Q) $(AR) rcs $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBGRPC++_TEST_UTIL_OBJS)
+	$(Q) $(AR) $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBGRPC++_TEST_UTIL_OBJS) 
 ifeq ($(SYSTEM),Darwin)
 	$(Q) ranlib $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a
 endif
@@ -3238,6 +3197,8 @@
 -include $(LIBGRPC++_TEST_UTIL_OBJS:.o=.dep)
 endif
 endif
+$(OBJDIR)/$(CONFIG)/test/cpp/end2end/test_service_impl.o: $(GENDIR)/src/proto/grpc/testing/echo_messages.pb.cc $(GENDIR)/src/proto/grpc/testing/echo_messages.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/echo.pb.cc $(GENDIR)/src/proto/grpc/testing/echo.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/duplicate/echo_duplicate.pb.cc $(GENDIR)/src/proto/grpc/testing/duplicate/echo_duplicate.grpc.pb.cc
+$(OBJDIR)/$(CONFIG)/test/cpp/util/byte_buffer_proto_helper.o: $(GENDIR)/src/proto/grpc/testing/echo_messages.pb.cc $(GENDIR)/src/proto/grpc/testing/echo_messages.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/echo.pb.cc $(GENDIR)/src/proto/grpc/testing/echo.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/duplicate/echo_duplicate.pb.cc $(GENDIR)/src/proto/grpc/testing/duplicate/echo_duplicate.grpc.pb.cc
 $(OBJDIR)/$(CONFIG)/test/cpp/util/cli_call.o: $(GENDIR)/src/proto/grpc/testing/echo_messages.pb.cc $(GENDIR)/src/proto/grpc/testing/echo_messages.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/echo.pb.cc $(GENDIR)/src/proto/grpc/testing/echo.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/duplicate/echo_duplicate.pb.cc $(GENDIR)/src/proto/grpc/testing/duplicate/echo_duplicate.grpc.pb.cc
 $(OBJDIR)/$(CONFIG)/test/cpp/util/create_test_channel.o: $(GENDIR)/src/proto/grpc/testing/echo_messages.pb.cc $(GENDIR)/src/proto/grpc/testing/echo_messages.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/echo.pb.cc $(GENDIR)/src/proto/grpc/testing/echo.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/duplicate/echo_duplicate.pb.cc $(GENDIR)/src/proto/grpc/testing/duplicate/echo_duplicate.grpc.pb.cc
 $(OBJDIR)/$(CONFIG)/test/cpp/util/string_ref_helper.o: $(GENDIR)/src/proto/grpc/testing/echo_messages.pb.cc $(GENDIR)/src/proto/grpc/testing/echo_messages.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/echo.pb.cc $(GENDIR)/src/proto/grpc/testing/echo.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/duplicate/echo_duplicate.pb.cc $(GENDIR)/src/proto/grpc/testing/duplicate/echo_duplicate.grpc.pb.cc
@@ -3253,6 +3214,7 @@
     src/cpp/client/credentials.cc \
     src/cpp/client/generic_stub.cc \
     src/cpp/client/insecure_credentials.cc \
+    src/cpp/common/alarm.cc \
     src/cpp/common/call.cc \
     src/cpp/common/channel_arguments.cc \
     src/cpp/common/completion_queue.cc \
@@ -3272,8 +3234,10 @@
     src/cpp/util/status.cc \
     src/cpp/util/string_ref.cc \
     src/cpp/util/time.cc \
+    src/cpp/codegen/grpc_library.cc \
 
 PUBLIC_HEADERS_CXX += \
+    include/grpc++/alarm.h \
     include/grpc++/channel.h \
     include/grpc++/client_context.h \
     include/grpc++/completion_queue.h \
@@ -3284,6 +3248,7 @@
     include/grpc++/impl/call.h \
     include/grpc++/impl/client_unary_call.h \
     include/grpc++/impl/grpc_library.h \
+    include/grpc++/impl/method_handler_impl.h \
     include/grpc++/impl/proto_utils.h \
     include/grpc++/impl/rpc_method.h \
     include/grpc++/impl/rpc_service_method.h \
@@ -3316,6 +3281,36 @@
     include/grpc++/support/stub_options.h \
     include/grpc++/support/sync_stream.h \
     include/grpc++/support/time.h \
+    include/grpc++/impl/codegen/async_stream.h \
+    include/grpc++/impl/codegen/async_unary_call.h \
+    include/grpc++/impl/codegen/call.h \
+    include/grpc++/impl/codegen/call_hook.h \
+    include/grpc++/impl/codegen/channel_interface.h \
+    include/grpc++/impl/codegen/client_context.h \
+    include/grpc++/impl/codegen/client_unary_call.h \
+    include/grpc++/impl/codegen/completion_queue.h \
+    include/grpc++/impl/codegen/completion_queue_tag.h \
+    include/grpc++/impl/codegen/config.h \
+    include/grpc++/impl/codegen/config_protobuf.h \
+    include/grpc++/impl/codegen/grpc_library.h \
+    include/grpc++/impl/codegen/method_handler_impl.h \
+    include/grpc++/impl/codegen/proto_utils.h \
+    include/grpc++/impl/codegen/rpc_method.h \
+    include/grpc++/impl/codegen/rpc_service_method.h \
+    include/grpc++/impl/codegen/security/auth_context.h \
+    include/grpc++/impl/codegen/serialization_traits.h \
+    include/grpc++/impl/codegen/server_context.h \
+    include/grpc++/impl/codegen/server_interface.h \
+    include/grpc++/impl/codegen/service_type.h \
+    include/grpc++/impl/codegen/status.h \
+    include/grpc++/impl/codegen/status_code_enum.h \
+    include/grpc++/impl/codegen/string_ref.h \
+    include/grpc++/impl/codegen/stub_options.h \
+    include/grpc++/impl/codegen/sync.h \
+    include/grpc++/impl/codegen/sync_cxx11.h \
+    include/grpc++/impl/codegen/sync_no_cxx11.h \
+    include/grpc++/impl/codegen/sync_stream.h \
+    include/grpc++/impl/codegen/time.h \
 
 LIBGRPC++_UNSECURE_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(LIBGRPC++_UNSECURE_SRC))))
 
@@ -3326,34 +3321,15 @@
 
 $(LIBDIR)/$(CONFIG)/libgrpc++_unsecure.a: protobuf_dep_error
 
-ifeq ($(SYSTEM),MINGW32)
-$(LIBDIR)/$(CONFIG)/grpc++_unsecure.$(SHARED_EXT): protobuf_dep_error
-else
-$(LIBDIR)/$(CONFIG)/libgrpc++_unsecure.$(SHARED_EXT): protobuf_dep_error
-endif
+$(LIBDIR)/$(CONFIG)/$(SHARED_PREFIX)grpc++_unsecure$(SHARED_VERSION).$(SHARED_EXT): protobuf_dep_error
 
 else
 
-$(LIBDIR)/$(CONFIG)/libgrpc++_unsecure.a: $(ZLIB_DEP) $(OPENSSL_DEP)  $(PROTOBUF_DEP) $(LIBGRPC++_UNSECURE_OBJS)
+$(LIBDIR)/$(CONFIG)/libgrpc++_unsecure.a: $(ZLIB_DEP)  $(PROTOBUF_DEP) $(LIBGRPC++_UNSECURE_OBJS)  $(LIBGPR_OBJS)  $(ZLIB_MERGE_OBJS) 
 	$(E) "[AR]      Creating $@"
 	$(Q) mkdir -p `dirname $@`
 	$(Q) rm -f $(LIBDIR)/$(CONFIG)/libgrpc++_unsecure.a
-	$(Q) $(AR) rcs $(LIBDIR)/$(CONFIG)/libgrpc++_unsecure.a $(LIBGRPC++_UNSECURE_OBJS)
-	$(Q) rm -rf $(BUILDDIR_ABSOLUTE)/tmp-merge-grpc++_unsecure
-	$(Q) ( mkdir -p $(BUILDDIR_ABSOLUTE)/tmp-merge-grpc++_unsecure/grpc ; \
-	       cd $(BUILDDIR_ABSOLUTE)/tmp-merge-grpc++_unsecure/grpc ; \
-	       $(AR) x $(LIBDIR)/$(CONFIG)/libgrpc++_unsecure.a )
-	$(Q) for l in $(ZLIB_MERGE_LIBS) ; do ( \
-	       mkdir -p $(BUILDDIR_ABSOLUTE)/tmp-merge-grpc++_unsecure/zlib ; \
-	       cd $(BUILDDIR_ABSOLUTE)/tmp-merge-grpc++_unsecure/zlib ; \
-	       $(AR) x $${l} ) ; done
-	$(Q) for l in $(ZLIB_MERGE_LIBS) ; do ( \
-	       mkdir -p $(BUILDDIR_ABSOLUTE)/tmp-merge-grpc++_unsecure/zlib ; \
-	       cd $(BUILDDIR_ABSOLUTE)/tmp-merge-grpc++_unsecure/zlib ; \
-	       $(AR) x $${l} ) ; done
-	$(Q) rm -f $(LIBDIR)/$(CONFIG)/libgrpc++_unsecure.a $(BUILDDIR_ABSOLUTE)/tmp-merge-grpc++_unsecure/*/__.SYMDEF*
-	$(Q) ar rcs $(LIBDIR)/$(CONFIG)/libgrpc++_unsecure.a $(BUILDDIR_ABSOLUTE)/tmp-merge-grpc++_unsecure/*/*
-	$(Q) rm -rf $(BUILDDIR_ABSOLUTE)/tmp-merge-grpc++_unsecure
+	$(Q) $(AR) $(LIBDIR)/$(CONFIG)/libgrpc++_unsecure.a $(LIBGRPC++_UNSECURE_OBJS)  $(LIBGPR_OBJS)  $(ZLIB_MERGE_OBJS) 
 ifeq ($(SYSTEM),Darwin)
 	$(Q) ranlib $(LIBDIR)/$(CONFIG)/libgrpc++_unsecure.a
 endif
@@ -3361,20 +3337,20 @@
 
 
 ifeq ($(SYSTEM),MINGW32)
-$(LIBDIR)/$(CONFIG)/grpc++_unsecure.$(SHARED_EXT): $(LIBGRPC++_UNSECURE_OBJS)  $(ZLIB_DEP) $(PROTOBUF_DEP) $(LIBDIR)/$(CONFIG)/gpr.$(SHARED_EXT) $(LIBDIR)/$(CONFIG)/grpc_unsecure.$(SHARED_EXT)
+$(LIBDIR)/$(CONFIG)/grpc++_unsecure$(SHARED_VERSION).$(SHARED_EXT): $(LIBGRPC++_UNSECURE_OBJS)  $(ZLIB_DEP) $(PROTOBUF_DEP) $(LIBDIR)/$(CONFIG)/gpr.$(SHARED_EXT) $(LIBDIR)/$(CONFIG)/grpc_unsecure.$(SHARED_EXT)
 	$(E) "[LD]      Linking $@"
 	$(Q) mkdir -p `dirname $@`
-	$(Q) $(LDXX) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -shared -Wl,--output-def=$(LIBDIR)/$(CONFIG)/grpc++_unsecure.def -Wl,--out-implib=$(LIBDIR)/$(CONFIG)/libgrpc++_unsecure-imp.a -o $(LIBDIR)/$(CONFIG)/grpc++_unsecure.$(SHARED_EXT) $(LIBGRPC++_UNSECURE_OBJS) $(LDLIBS) $(ZLIB_MERGE_LIBS) $(LDLIBSXX) $(LDLIBS_PROTOBUF) -lgpr-imp -lgrpc_unsecure-imp
+	$(Q) $(LDXX) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -shared grpc++_unsecure.def -Wl,--output-def=$(LIBDIR)/$(CONFIG)/grpc++_unsecure$(SHARED_VERSION).def -Wl,--out-implib=$(LIBDIR)/$(CONFIG)/libgrpc++_unsecure$(SHARED_VERSION)-dll.a -o $(LIBDIR)/$(CONFIG)/grpc++_unsecure$(SHARED_VERSION).$(SHARED_EXT) $(LIBGRPC++_UNSECURE_OBJS) $(LDLIBS) $(ZLIB_MERGE_LIBS) $(LDLIBSXX) $(LDLIBS_PROTOBUF) -lgpr-imp -lgrpc_unsecure-imp
 else
-$(LIBDIR)/$(CONFIG)/libgrpc++_unsecure.$(SHARED_EXT): $(LIBGRPC++_UNSECURE_OBJS)  $(ZLIB_DEP) $(PROTOBUF_DEP) $(LIBDIR)/$(CONFIG)/libgpr.$(SHARED_EXT) $(LIBDIR)/$(CONFIG)/libgrpc_unsecure.$(SHARED_EXT)
+$(LIBDIR)/$(CONFIG)/libgrpc++_unsecure$(SHARED_VERSION).$(SHARED_EXT): $(LIBGRPC++_UNSECURE_OBJS)  $(ZLIB_DEP) $(PROTOBUF_DEP) $(LIBDIR)/$(CONFIG)/libgpr.$(SHARED_EXT) $(LIBDIR)/$(CONFIG)/libgrpc_unsecure.$(SHARED_EXT)
 	$(E) "[LD]      Linking $@"
 	$(Q) mkdir -p `dirname $@`
 ifeq ($(SYSTEM),Darwin)
-	$(Q) $(LDXX) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -install_name libgrpc++_unsecure.$(SHARED_EXT) -dynamiclib -o $(LIBDIR)/$(CONFIG)/libgrpc++_unsecure.$(SHARED_EXT) $(LIBGRPC++_UNSECURE_OBJS) $(LDLIBS) $(ZLIB_MERGE_LIBS) $(LDLIBSXX) $(LDLIBS_PROTOBUF) -lgpr -lgrpc_unsecure
+	$(Q) $(LDXX) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -install_name $(SHARED_PREFIX)grpc++_unsecure$(SHARED_VERSION).$(SHARED_EXT) -dynamiclib -o $(LIBDIR)/$(CONFIG)/libgrpc++_unsecure$(SHARED_VERSION).$(SHARED_EXT) $(LIBGRPC++_UNSECURE_OBJS) $(LDLIBS) $(ZLIB_MERGE_LIBS) $(LDLIBSXX) $(LDLIBS_PROTOBUF) -lgpr -lgrpc_unsecure
 else
-	$(Q) $(LDXX) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -shared -Wl,-soname,libgrpc++_unsecure.so.0 -o $(LIBDIR)/$(CONFIG)/libgrpc++_unsecure.$(SHARED_EXT) $(LIBGRPC++_UNSECURE_OBJS) $(LDLIBS) $(ZLIB_MERGE_LIBS) $(LDLIBSXX) $(LDLIBS_PROTOBUF) -lgpr -lgrpc_unsecure
-	$(Q) ln -sf libgrpc++_unsecure.$(SHARED_EXT) $(LIBDIR)/$(CONFIG)/libgrpc++_unsecure.so.0
-	$(Q) ln -sf libgrpc++_unsecure.$(SHARED_EXT) $(LIBDIR)/$(CONFIG)/libgrpc++_unsecure.so
+	$(Q) $(LDXX) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -shared -Wl,-soname,libgrpc++_unsecure.so.0 -o $(LIBDIR)/$(CONFIG)/libgrpc++_unsecure$(SHARED_VERSION).$(SHARED_EXT) $(LIBGRPC++_UNSECURE_OBJS) $(LDLIBS) $(ZLIB_MERGE_LIBS) $(LDLIBSXX) $(LDLIBS_PROTOBUF) -lgpr -lgrpc_unsecure
+	$(Q) ln -sf $(SHARED_PREFIX)grpc++_unsecure$(SHARED_VERSION).$(SHARED_EXT) $(LIBDIR)/$(CONFIG)/libgrpc++_unsecure$(SHARED_VERSION).so.0
+	$(Q) ln -sf $(SHARED_PREFIX)grpc++_unsecure$(SHARED_VERSION).$(SHARED_EXT) $(LIBDIR)/$(CONFIG)/libgrpc++_unsecure$(SHARED_VERSION).so
 endif
 endif
 
@@ -3391,7 +3367,59 @@
     src/compiler/objective_c_generator.cc \
     src/compiler/python_generator.cc \
     src/compiler/ruby_generator.cc \
+    src/cpp/codegen/grpc_library.cc \
 
+PUBLIC_HEADERS_CXX += \
+    include/grpc++/impl/codegen/async_stream.h \
+    include/grpc++/impl/codegen/async_unary_call.h \
+    include/grpc++/impl/codegen/call.h \
+    include/grpc++/impl/codegen/call_hook.h \
+    include/grpc++/impl/codegen/channel_interface.h \
+    include/grpc++/impl/codegen/client_context.h \
+    include/grpc++/impl/codegen/client_unary_call.h \
+    include/grpc++/impl/codegen/completion_queue.h \
+    include/grpc++/impl/codegen/completion_queue_tag.h \
+    include/grpc++/impl/codegen/config.h \
+    include/grpc++/impl/codegen/config_protobuf.h \
+    include/grpc++/impl/codegen/grpc_library.h \
+    include/grpc++/impl/codegen/method_handler_impl.h \
+    include/grpc++/impl/codegen/proto_utils.h \
+    include/grpc++/impl/codegen/rpc_method.h \
+    include/grpc++/impl/codegen/rpc_service_method.h \
+    include/grpc++/impl/codegen/security/auth_context.h \
+    include/grpc++/impl/codegen/serialization_traits.h \
+    include/grpc++/impl/codegen/server_context.h \
+    include/grpc++/impl/codegen/server_interface.h \
+    include/grpc++/impl/codegen/service_type.h \
+    include/grpc++/impl/codegen/status.h \
+    include/grpc++/impl/codegen/status_code_enum.h \
+    include/grpc++/impl/codegen/string_ref.h \
+    include/grpc++/impl/codegen/stub_options.h \
+    include/grpc++/impl/codegen/sync.h \
+    include/grpc++/impl/codegen/sync_cxx11.h \
+    include/grpc++/impl/codegen/sync_no_cxx11.h \
+    include/grpc++/impl/codegen/sync_stream.h \
+    include/grpc++/impl/codegen/time.h \
+    include/grpc/impl/codegen/byte_buffer.h \
+    include/grpc/impl/codegen/compression_types.h \
+    include/grpc/impl/codegen/connectivity_state.h \
+    include/grpc/impl/codegen/grpc_types.h \
+    include/grpc/impl/codegen/propagation_bits.h \
+    include/grpc/impl/codegen/status.h \
+    include/grpc/impl/codegen/alloc.h \
+    include/grpc/impl/codegen/atm.h \
+    include/grpc/impl/codegen/atm_gcc_atomic.h \
+    include/grpc/impl/codegen/atm_gcc_sync.h \
+    include/grpc/impl/codegen/atm_win32.h \
+    include/grpc/impl/codegen/log.h \
+    include/grpc/impl/codegen/port_platform.h \
+    include/grpc/impl/codegen/slice.h \
+    include/grpc/impl/codegen/slice_buffer.h \
+    include/grpc/impl/codegen/sync.h \
+    include/grpc/impl/codegen/sync_generic.h \
+    include/grpc/impl/codegen/sync_posix.h \
+    include/grpc/impl/codegen/sync_win32.h \
+    include/grpc/impl/codegen/time.h \
 
 LIBGRPC_PLUGIN_SUPPORT_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(LIBGRPC_PLUGIN_SUPPORT_SRC))))
 
@@ -3405,11 +3433,11 @@
 
 else
 
-$(LIBDIR)/$(CONFIG)/libgrpc_plugin_support.a: $(ZLIB_DEP) $(OPENSSL_DEP)  $(PROTOBUF_DEP) $(LIBGRPC_PLUGIN_SUPPORT_OBJS)
+$(LIBDIR)/$(CONFIG)/libgrpc_plugin_support.a: $(ZLIB_DEP)  $(PROTOBUF_DEP) $(LIBGRPC_PLUGIN_SUPPORT_OBJS) 
 	$(E) "[AR]      Creating $@"
 	$(Q) mkdir -p `dirname $@`
 	$(Q) rm -f $(LIBDIR)/$(CONFIG)/libgrpc_plugin_support.a
-	$(Q) $(AR) rcs $(LIBDIR)/$(CONFIG)/libgrpc_plugin_support.a $(LIBGRPC_PLUGIN_SUPPORT_OBJS)
+	$(Q) $(AR) $(LIBDIR)/$(CONFIG)/libgrpc_plugin_support.a $(LIBGRPC_PLUGIN_SUPPORT_OBJS) 
 ifeq ($(SYSTEM),Darwin)
 	$(Q) ranlib $(LIBDIR)/$(CONFIG)/libgrpc_plugin_support.a
 endif
@@ -3450,11 +3478,11 @@
 
 else
 
-$(LIBDIR)/$(CONFIG)/libinterop_client_helper.a: $(ZLIB_DEP) $(OPENSSL_DEP) $(PROTOBUF_DEP) $(LIBINTEROP_CLIENT_HELPER_OBJS)
+$(LIBDIR)/$(CONFIG)/libinterop_client_helper.a: $(ZLIB_DEP) $(OPENSSL_DEP) $(PROTOBUF_DEP) $(LIBINTEROP_CLIENT_HELPER_OBJS) 
 	$(E) "[AR]      Creating $@"
 	$(Q) mkdir -p `dirname $@`
 	$(Q) rm -f $(LIBDIR)/$(CONFIG)/libinterop_client_helper.a
-	$(Q) $(AR) rcs $(LIBDIR)/$(CONFIG)/libinterop_client_helper.a $(LIBINTEROP_CLIENT_HELPER_OBJS)
+	$(Q) $(AR) $(LIBDIR)/$(CONFIG)/libinterop_client_helper.a $(LIBINTEROP_CLIENT_HELPER_OBJS) 
 ifeq ($(SYSTEM),Darwin)
 	$(Q) ranlib $(LIBDIR)/$(CONFIG)/libinterop_client_helper.a
 endif
@@ -3503,11 +3531,11 @@
 
 else
 
-$(LIBDIR)/$(CONFIG)/libinterop_client_main.a: $(ZLIB_DEP) $(OPENSSL_DEP) $(PROTOBUF_DEP) $(LIBINTEROP_CLIENT_MAIN_OBJS)
+$(LIBDIR)/$(CONFIG)/libinterop_client_main.a: $(ZLIB_DEP) $(OPENSSL_DEP) $(PROTOBUF_DEP) $(LIBINTEROP_CLIENT_MAIN_OBJS) 
 	$(E) "[AR]      Creating $@"
 	$(Q) mkdir -p `dirname $@`
 	$(Q) rm -f $(LIBDIR)/$(CONFIG)/libinterop_client_main.a
-	$(Q) $(AR) rcs $(LIBDIR)/$(CONFIG)/libinterop_client_main.a $(LIBINTEROP_CLIENT_MAIN_OBJS)
+	$(Q) $(AR) $(LIBDIR)/$(CONFIG)/libinterop_client_main.a $(LIBINTEROP_CLIENT_MAIN_OBJS) 
 ifeq ($(SYSTEM),Darwin)
 	$(Q) ranlib $(LIBDIR)/$(CONFIG)/libinterop_client_main.a
 endif
@@ -3553,11 +3581,11 @@
 
 else
 
-$(LIBDIR)/$(CONFIG)/libinterop_server_helper.a: $(ZLIB_DEP) $(OPENSSL_DEP) $(PROTOBUF_DEP) $(LIBINTEROP_SERVER_HELPER_OBJS)
+$(LIBDIR)/$(CONFIG)/libinterop_server_helper.a: $(ZLIB_DEP) $(OPENSSL_DEP) $(PROTOBUF_DEP) $(LIBINTEROP_SERVER_HELPER_OBJS) 
 	$(E) "[AR]      Creating $@"
 	$(Q) mkdir -p `dirname $@`
 	$(Q) rm -f $(LIBDIR)/$(CONFIG)/libinterop_server_helper.a
-	$(Q) $(AR) rcs $(LIBDIR)/$(CONFIG)/libinterop_server_helper.a $(LIBINTEROP_SERVER_HELPER_OBJS)
+	$(Q) $(AR) $(LIBDIR)/$(CONFIG)/libinterop_server_helper.a $(LIBINTEROP_SERVER_HELPER_OBJS) 
 ifeq ($(SYSTEM),Darwin)
 	$(Q) ranlib $(LIBDIR)/$(CONFIG)/libinterop_server_helper.a
 endif
@@ -3604,11 +3632,11 @@
 
 else
 
-$(LIBDIR)/$(CONFIG)/libinterop_server_main.a: $(ZLIB_DEP) $(OPENSSL_DEP) $(PROTOBUF_DEP) $(LIBINTEROP_SERVER_MAIN_OBJS)
+$(LIBDIR)/$(CONFIG)/libinterop_server_main.a: $(ZLIB_DEP) $(OPENSSL_DEP) $(PROTOBUF_DEP) $(LIBINTEROP_SERVER_MAIN_OBJS) 
 	$(E) "[AR]      Creating $@"
 	$(Q) mkdir -p `dirname $@`
 	$(Q) rm -f $(LIBDIR)/$(CONFIG)/libinterop_server_main.a
-	$(Q) $(AR) rcs $(LIBDIR)/$(CONFIG)/libinterop_server_main.a $(LIBINTEROP_SERVER_MAIN_OBJS)
+	$(Q) $(AR) $(LIBDIR)/$(CONFIG)/libinterop_server_main.a $(LIBINTEROP_SERVER_MAIN_OBJS) 
 ifeq ($(SYSTEM),Darwin)
 	$(Q) ranlib $(LIBDIR)/$(CONFIG)/libinterop_server_main.a
 endif
@@ -3638,6 +3666,7 @@
     test/cpp/qps/client_async.cc \
     test/cpp/qps/client_sync.cc \
     test/cpp/qps/driver.cc \
+    test/cpp/qps/limit_cores.cc \
     test/cpp/qps/perf_db_client.cc \
     test/cpp/qps/qps_worker.cc \
     test/cpp/qps/report.cc \
@@ -3668,11 +3697,11 @@
 
 else
 
-$(LIBDIR)/$(CONFIG)/libqps.a: $(ZLIB_DEP) $(OPENSSL_DEP) $(PROTOBUF_DEP) $(LIBQPS_OBJS)
+$(LIBDIR)/$(CONFIG)/libqps.a: $(ZLIB_DEP) $(OPENSSL_DEP) $(PROTOBUF_DEP) $(LIBQPS_OBJS) 
 	$(E) "[AR]      Creating $@"
 	$(Q) mkdir -p `dirname $@`
 	$(Q) rm -f $(LIBDIR)/$(CONFIG)/libqps.a
-	$(Q) $(AR) rcs $(LIBDIR)/$(CONFIG)/libqps.a $(LIBQPS_OBJS)
+	$(Q) $(AR) $(LIBDIR)/$(CONFIG)/libqps.a $(LIBQPS_OBJS) 
 ifeq ($(SYSTEM),Darwin)
 	$(Q) ranlib $(LIBDIR)/$(CONFIG)/libqps.a
 endif
@@ -3692,6 +3721,7 @@
 $(OBJDIR)/$(CONFIG)/test/cpp/qps/client_async.o: $(GENDIR)/src/proto/grpc/testing/messages.pb.cc $(GENDIR)/src/proto/grpc/testing/messages.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/payloads.pb.cc $(GENDIR)/src/proto/grpc/testing/payloads.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/stats.pb.cc $(GENDIR)/src/proto/grpc/testing/stats.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.pb.cc $(GENDIR)/src/proto/grpc/testing/services.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/perf_db.pb.cc $(GENDIR)/src/proto/grpc/testing/perf_db.grpc.pb.cc
 $(OBJDIR)/$(CONFIG)/test/cpp/qps/client_sync.o: $(GENDIR)/src/proto/grpc/testing/messages.pb.cc $(GENDIR)/src/proto/grpc/testing/messages.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/payloads.pb.cc $(GENDIR)/src/proto/grpc/testing/payloads.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/stats.pb.cc $(GENDIR)/src/proto/grpc/testing/stats.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.pb.cc $(GENDIR)/src/proto/grpc/testing/services.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/perf_db.pb.cc $(GENDIR)/src/proto/grpc/testing/perf_db.grpc.pb.cc
 $(OBJDIR)/$(CONFIG)/test/cpp/qps/driver.o: $(GENDIR)/src/proto/grpc/testing/messages.pb.cc $(GENDIR)/src/proto/grpc/testing/messages.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/payloads.pb.cc $(GENDIR)/src/proto/grpc/testing/payloads.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/stats.pb.cc $(GENDIR)/src/proto/grpc/testing/stats.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.pb.cc $(GENDIR)/src/proto/grpc/testing/services.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/perf_db.pb.cc $(GENDIR)/src/proto/grpc/testing/perf_db.grpc.pb.cc
+$(OBJDIR)/$(CONFIG)/test/cpp/qps/limit_cores.o: $(GENDIR)/src/proto/grpc/testing/messages.pb.cc $(GENDIR)/src/proto/grpc/testing/messages.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/payloads.pb.cc $(GENDIR)/src/proto/grpc/testing/payloads.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/stats.pb.cc $(GENDIR)/src/proto/grpc/testing/stats.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.pb.cc $(GENDIR)/src/proto/grpc/testing/services.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/perf_db.pb.cc $(GENDIR)/src/proto/grpc/testing/perf_db.grpc.pb.cc
 $(OBJDIR)/$(CONFIG)/test/cpp/qps/perf_db_client.o: $(GENDIR)/src/proto/grpc/testing/messages.pb.cc $(GENDIR)/src/proto/grpc/testing/messages.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/payloads.pb.cc $(GENDIR)/src/proto/grpc/testing/payloads.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/stats.pb.cc $(GENDIR)/src/proto/grpc/testing/stats.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.pb.cc $(GENDIR)/src/proto/grpc/testing/services.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/perf_db.pb.cc $(GENDIR)/src/proto/grpc/testing/perf_db.grpc.pb.cc
 $(OBJDIR)/$(CONFIG)/test/cpp/qps/qps_worker.o: $(GENDIR)/src/proto/grpc/testing/messages.pb.cc $(GENDIR)/src/proto/grpc/testing/messages.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/payloads.pb.cc $(GENDIR)/src/proto/grpc/testing/payloads.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/stats.pb.cc $(GENDIR)/src/proto/grpc/testing/stats.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.pb.cc $(GENDIR)/src/proto/grpc/testing/services.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/perf_db.pb.cc $(GENDIR)/src/proto/grpc/testing/perf_db.grpc.pb.cc
 $(OBJDIR)/$(CONFIG)/test/cpp/qps/report.o: $(GENDIR)/src/proto/grpc/testing/messages.pb.cc $(GENDIR)/src/proto/grpc/testing/messages.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/payloads.pb.cc $(GENDIR)/src/proto/grpc/testing/payloads.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/stats.pb.cc $(GENDIR)/src/proto/grpc/testing/stats.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.pb.cc $(GENDIR)/src/proto/grpc/testing/services.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/perf_db.pb.cc $(GENDIR)/src/proto/grpc/testing/perf_db.grpc.pb.cc
@@ -3714,20 +3744,16 @@
 
 $(LIBDIR)/$(CONFIG)/libgrpc_csharp_ext.a: openssl_dep_error
 
-ifeq ($(SYSTEM),MINGW32)
-$(LIBDIR)/$(CONFIG)/grpc_csharp_ext.$(SHARED_EXT): openssl_dep_error
-else
-$(LIBDIR)/$(CONFIG)/libgrpc_csharp_ext.$(SHARED_EXT): openssl_dep_error
-endif
+$(LIBDIR)/$(CONFIG)/$(SHARED_PREFIX)grpc_csharp_ext$(SHARED_VERSION).$(SHARED_EXT): openssl_dep_error
 
 else
 
 
-$(LIBDIR)/$(CONFIG)/libgrpc_csharp_ext.a: $(ZLIB_DEP) $(OPENSSL_DEP) $(LIBGRPC_CSHARP_EXT_OBJS)
+$(LIBDIR)/$(CONFIG)/libgrpc_csharp_ext.a: $(ZLIB_DEP) $(OPENSSL_DEP) $(LIBGRPC_CSHARP_EXT_OBJS) 
 	$(E) "[AR]      Creating $@"
 	$(Q) mkdir -p `dirname $@`
 	$(Q) rm -f $(LIBDIR)/$(CONFIG)/libgrpc_csharp_ext.a
-	$(Q) $(AR) rcs $(LIBDIR)/$(CONFIG)/libgrpc_csharp_ext.a $(LIBGRPC_CSHARP_EXT_OBJS)
+	$(Q) $(AR) $(LIBDIR)/$(CONFIG)/libgrpc_csharp_ext.a $(LIBGRPC_CSHARP_EXT_OBJS) 
 ifeq ($(SYSTEM),Darwin)
 	$(Q) ranlib $(LIBDIR)/$(CONFIG)/libgrpc_csharp_ext.a
 endif
@@ -3735,20 +3761,20 @@
 
 
 ifeq ($(SYSTEM),MINGW32)
-$(LIBDIR)/$(CONFIG)/grpc_csharp_ext.$(SHARED_EXT): $(LIBGRPC_CSHARP_EXT_OBJS)  $(ZLIB_DEP) $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr.a $(OPENSSL_DEP)
+$(LIBDIR)/$(CONFIG)/grpc_csharp_ext$(SHARED_VERSION).$(SHARED_EXT): $(LIBGRPC_CSHARP_EXT_OBJS)  $(ZLIB_DEP) $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr.a $(OPENSSL_DEP)
 	$(E) "[LD]      Linking $@"
 	$(Q) mkdir -p `dirname $@`
-	$(Q) $(LD) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -shared -Wl,--output-def=$(LIBDIR)/$(CONFIG)/grpc_csharp_ext.def -Wl,--out-implib=$(LIBDIR)/$(CONFIG)/libgrpc_csharp_ext-imp.a -o $(LIBDIR)/$(CONFIG)/grpc_csharp_ext.$(SHARED_EXT) $(LIBGRPC_CSHARP_EXT_OBJS) $(LDLIBS) $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr.a $(ZLIB_MERGE_LIBS)
+	$(Q) $(LD) $(LDFLAGS) $(if $(subst Linux,,$(SYSTEM)),,-Wl$(comma)-wrap$(comma)memcpy) -L$(LIBDIR)/$(CONFIG) -shared grpc_csharp_ext.def -Wl,--output-def=$(LIBDIR)/$(CONFIG)/grpc_csharp_ext$(SHARED_VERSION).def -Wl,--out-implib=$(LIBDIR)/$(CONFIG)/libgrpc_csharp_ext$(SHARED_VERSION)-dll.a -o $(LIBDIR)/$(CONFIG)/grpc_csharp_ext$(SHARED_VERSION).$(SHARED_EXT) $(LIBGRPC_CSHARP_EXT_OBJS) $(LDLIBS) $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr.a $(ZLIB_MERGE_LIBS)
 else
-$(LIBDIR)/$(CONFIG)/libgrpc_csharp_ext.$(SHARED_EXT): $(LIBGRPC_CSHARP_EXT_OBJS)  $(ZLIB_DEP) $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr.a $(OPENSSL_DEP)
+$(LIBDIR)/$(CONFIG)/libgrpc_csharp_ext$(SHARED_VERSION).$(SHARED_EXT): $(LIBGRPC_CSHARP_EXT_OBJS)  $(ZLIB_DEP) $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr.a $(OPENSSL_DEP)
 	$(E) "[LD]      Linking $@"
 	$(Q) mkdir -p `dirname $@`
 ifeq ($(SYSTEM),Darwin)
-	$(Q) $(LD) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -install_name libgrpc_csharp_ext.$(SHARED_EXT) -dynamiclib -o $(LIBDIR)/$(CONFIG)/libgrpc_csharp_ext.$(SHARED_EXT) $(LIBGRPC_CSHARP_EXT_OBJS) $(LDLIBS) $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr.a $(ZLIB_MERGE_LIBS)
+	$(Q) $(LD) $(LDFLAGS) $(if $(subst Linux,,$(SYSTEM)),,-Wl$(comma)-wrap$(comma)memcpy) -L$(LIBDIR)/$(CONFIG) -install_name $(SHARED_PREFIX)grpc_csharp_ext$(SHARED_VERSION).$(SHARED_EXT) -dynamiclib -o $(LIBDIR)/$(CONFIG)/libgrpc_csharp_ext$(SHARED_VERSION).$(SHARED_EXT) $(LIBGRPC_CSHARP_EXT_OBJS) $(LDLIBS) $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr.a $(ZLIB_MERGE_LIBS)
 else
-	$(Q) $(LD) $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -shared -Wl,-soname,libgrpc_csharp_ext.so.0 -o $(LIBDIR)/$(CONFIG)/libgrpc_csharp_ext.$(SHARED_EXT) $(LIBGRPC_CSHARP_EXT_OBJS) $(LDLIBS) $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr.a $(ZLIB_MERGE_LIBS)
-	$(Q) ln -sf libgrpc_csharp_ext.$(SHARED_EXT) $(LIBDIR)/$(CONFIG)/libgrpc_csharp_ext.so.0
-	$(Q) ln -sf libgrpc_csharp_ext.$(SHARED_EXT) $(LIBDIR)/$(CONFIG)/libgrpc_csharp_ext.so
+	$(Q) $(LD) $(LDFLAGS) $(if $(subst Linux,,$(SYSTEM)),,-Wl$(comma)-wrap$(comma)memcpy) -L$(LIBDIR)/$(CONFIG) -shared -Wl,-soname,libgrpc_csharp_ext.so.0 -o $(LIBDIR)/$(CONFIG)/libgrpc_csharp_ext$(SHARED_VERSION).$(SHARED_EXT) $(LIBGRPC_CSHARP_EXT_OBJS) $(LDLIBS) $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr.a $(ZLIB_MERGE_LIBS)
+	$(Q) ln -sf $(SHARED_PREFIX)grpc_csharp_ext$(SHARED_VERSION).$(SHARED_EXT) $(LIBDIR)/$(CONFIG)/libgrpc_csharp_ext$(SHARED_VERSION).so.0
+	$(Q) ln -sf $(SHARED_PREFIX)grpc_csharp_ext$(SHARED_VERSION).$(SHARED_EXT) $(LIBDIR)/$(CONFIG)/libgrpc_csharp_ext$(SHARED_VERSION).so
 endif
 endif
 
@@ -4060,18 +4086,14 @@
 
 LIBBORINGSSL_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(LIBBORINGSSL_SRC))))
 
-# boringssl needs an override to ensure that it does not include
-# system openssl headers regardless of other configuration
-# we do so here with a target specific variable assignment
-$(LIBBORINGSSL_OBJS): CFLAGS := -Ithird_party/boringssl/include $(CFLAGS) -Wno-sign-conversion -Wno-conversion -Wno-unused-value -fvisibility=hidden
-$(LIBBORINGSSL_OBJS): CXXFLAGS := -Ithird_party/boringssl/include $(CXXFLAGS) -fvisibility=hidden
-$(LIBBORINGSSL_OBJS): CPPFLAGS += -DOPENSSL_NO_ASM -D_GNU_SOURCE
+$(LIBBORINGSSL_OBJS): CPPFLAGS += -Ithird_party/boringssl/include -fvisibility=hidden -DOPENSSL_NO_ASM -D_GNU_SOURCE -DWIN32_LEAN_AND_MEAN -D_HAS_EXCEPTIONS=0 -DNOMINMAX
+$(LIBBORINGSSL_OBJS): CFLAGS += -Wno-sign-conversion -Wno-conversion -Wno-unused-value -Wno-unknown-pragmas -Wno-implicit-function-declaration -Wno-unused-variable -Wno-sign-compare
 
-$(LIBDIR)/$(CONFIG)/libboringssl.a: $(ZLIB_DEP) $(OPENSSL_DEP)  $(LIBBORINGSSL_OBJS)
+$(LIBDIR)/$(CONFIG)/libboringssl.a: $(ZLIB_DEP)  $(LIBBORINGSSL_OBJS) 
 	$(E) "[AR]      Creating $@"
 	$(Q) mkdir -p `dirname $@`
 	$(Q) rm -f $(LIBDIR)/$(CONFIG)/libboringssl.a
-	$(Q) $(AR) rcs $(LIBDIR)/$(CONFIG)/libboringssl.a $(LIBBORINGSSL_OBJS)
+	$(Q) $(AR) $(LIBDIR)/$(CONFIG)/libboringssl.a $(LIBBORINGSSL_OBJS) 
 ifeq ($(SYSTEM),Darwin)
 	$(Q) ranlib $(LIBDIR)/$(CONFIG)/libboringssl.a
 endif
@@ -4092,12 +4114,8 @@
 
 LIBBORINGSSL_TEST_UTIL_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(LIBBORINGSSL_TEST_UTIL_SRC))))
 
-# boringssl needs an override to ensure that it does not include
-# system openssl headers regardless of other configuration
-# we do so here with a target specific variable assignment
-$(LIBBORINGSSL_TEST_UTIL_OBJS): CFLAGS := -Ithird_party/boringssl/include $(CFLAGS) -Wno-sign-conversion -Wno-conversion -Wno-unused-value -fvisibility=hidden
-$(LIBBORINGSSL_TEST_UTIL_OBJS): CXXFLAGS := -Ithird_party/boringssl/include $(CXXFLAGS) -fvisibility=hidden
-$(LIBBORINGSSL_TEST_UTIL_OBJS): CPPFLAGS += -DOPENSSL_NO_ASM -D_GNU_SOURCE
+$(LIBBORINGSSL_TEST_UTIL_OBJS): CPPFLAGS += -Ithird_party/boringssl/include -fvisibility=hidden -DOPENSSL_NO_ASM -D_GNU_SOURCE -DWIN32_LEAN_AND_MEAN -D_HAS_EXCEPTIONS=0 -DNOMINMAX
+$(LIBBORINGSSL_TEST_UTIL_OBJS): CFLAGS += -Wno-sign-conversion -Wno-conversion -Wno-unused-value -Wno-unknown-pragmas -Wno-implicit-function-declaration -Wno-unused-variable -Wno-sign-compare
 
 ifeq ($(NO_PROTOBUF),true)
 
@@ -4108,11 +4126,11 @@
 
 else
 
-$(LIBDIR)/$(CONFIG)/libboringssl_test_util.a: $(ZLIB_DEP) $(OPENSSL_DEP)  $(PROTOBUF_DEP) $(LIBBORINGSSL_TEST_UTIL_OBJS)
+$(LIBDIR)/$(CONFIG)/libboringssl_test_util.a: $(ZLIB_DEP)  $(PROTOBUF_DEP) $(LIBBORINGSSL_TEST_UTIL_OBJS) 
 	$(E) "[AR]      Creating $@"
 	$(Q) mkdir -p `dirname $@`
 	$(Q) rm -f $(LIBDIR)/$(CONFIG)/libboringssl_test_util.a
-	$(Q) $(AR) rcs $(LIBDIR)/$(CONFIG)/libboringssl_test_util.a $(LIBBORINGSSL_TEST_UTIL_OBJS)
+	$(Q) $(AR) $(LIBDIR)/$(CONFIG)/libboringssl_test_util.a $(LIBBORINGSSL_TEST_UTIL_OBJS) 
 ifeq ($(SYSTEM),Darwin)
 	$(Q) ranlib $(LIBDIR)/$(CONFIG)/libboringssl_test_util.a
 endif
@@ -4133,12 +4151,8 @@
 
 LIBBORINGSSL_AES_TEST_LIB_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(LIBBORINGSSL_AES_TEST_LIB_SRC))))
 
-# boringssl needs an override to ensure that it does not include
-# system openssl headers regardless of other configuration
-# we do so here with a target specific variable assignment
-$(LIBBORINGSSL_AES_TEST_LIB_OBJS): CFLAGS := -Ithird_party/boringssl/include $(CFLAGS) -Wno-sign-conversion -Wno-conversion -Wno-unused-value -fvisibility=hidden
-$(LIBBORINGSSL_AES_TEST_LIB_OBJS): CXXFLAGS := -Ithird_party/boringssl/include $(CXXFLAGS) -fvisibility=hidden
-$(LIBBORINGSSL_AES_TEST_LIB_OBJS): CPPFLAGS += -DOPENSSL_NO_ASM -D_GNU_SOURCE
+$(LIBBORINGSSL_AES_TEST_LIB_OBJS): CPPFLAGS += -Ithird_party/boringssl/include -fvisibility=hidden -DOPENSSL_NO_ASM -D_GNU_SOURCE -DWIN32_LEAN_AND_MEAN -D_HAS_EXCEPTIONS=0 -DNOMINMAX
+$(LIBBORINGSSL_AES_TEST_LIB_OBJS): CFLAGS += -Wno-sign-conversion -Wno-conversion -Wno-unused-value -Wno-unknown-pragmas -Wno-implicit-function-declaration -Wno-unused-variable -Wno-sign-compare
 
 ifeq ($(NO_PROTOBUF),true)
 
@@ -4149,11 +4163,11 @@
 
 else
 
-$(LIBDIR)/$(CONFIG)/libboringssl_aes_test_lib.a: $(ZLIB_DEP) $(OPENSSL_DEP)  $(PROTOBUF_DEP) $(LIBBORINGSSL_AES_TEST_LIB_OBJS)
+$(LIBDIR)/$(CONFIG)/libboringssl_aes_test_lib.a: $(ZLIB_DEP)  $(PROTOBUF_DEP) $(LIBBORINGSSL_AES_TEST_LIB_OBJS) 
 	$(E) "[AR]      Creating $@"
 	$(Q) mkdir -p `dirname $@`
 	$(Q) rm -f $(LIBDIR)/$(CONFIG)/libboringssl_aes_test_lib.a
-	$(Q) $(AR) rcs $(LIBDIR)/$(CONFIG)/libboringssl_aes_test_lib.a $(LIBBORINGSSL_AES_TEST_LIB_OBJS)
+	$(Q) $(AR) $(LIBDIR)/$(CONFIG)/libboringssl_aes_test_lib.a $(LIBBORINGSSL_AES_TEST_LIB_OBJS) 
 ifeq ($(SYSTEM),Darwin)
 	$(Q) ranlib $(LIBDIR)/$(CONFIG)/libboringssl_aes_test_lib.a
 endif
@@ -4174,12 +4188,8 @@
 
 LIBBORINGSSL_BASE64_TEST_LIB_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(LIBBORINGSSL_BASE64_TEST_LIB_SRC))))
 
-# boringssl needs an override to ensure that it does not include
-# system openssl headers regardless of other configuration
-# we do so here with a target specific variable assignment
-$(LIBBORINGSSL_BASE64_TEST_LIB_OBJS): CFLAGS := -Ithird_party/boringssl/include $(CFLAGS) -Wno-sign-conversion -Wno-conversion -Wno-unused-value -fvisibility=hidden
-$(LIBBORINGSSL_BASE64_TEST_LIB_OBJS): CXXFLAGS := -Ithird_party/boringssl/include $(CXXFLAGS) -fvisibility=hidden
-$(LIBBORINGSSL_BASE64_TEST_LIB_OBJS): CPPFLAGS += -DOPENSSL_NO_ASM -D_GNU_SOURCE
+$(LIBBORINGSSL_BASE64_TEST_LIB_OBJS): CPPFLAGS += -Ithird_party/boringssl/include -fvisibility=hidden -DOPENSSL_NO_ASM -D_GNU_SOURCE -DWIN32_LEAN_AND_MEAN -D_HAS_EXCEPTIONS=0 -DNOMINMAX
+$(LIBBORINGSSL_BASE64_TEST_LIB_OBJS): CFLAGS += -Wno-sign-conversion -Wno-conversion -Wno-unused-value -Wno-unknown-pragmas -Wno-implicit-function-declaration -Wno-unused-variable -Wno-sign-compare
 
 ifeq ($(NO_PROTOBUF),true)
 
@@ -4190,11 +4200,11 @@
 
 else
 
-$(LIBDIR)/$(CONFIG)/libboringssl_base64_test_lib.a: $(ZLIB_DEP) $(OPENSSL_DEP)  $(PROTOBUF_DEP) $(LIBBORINGSSL_BASE64_TEST_LIB_OBJS)
+$(LIBDIR)/$(CONFIG)/libboringssl_base64_test_lib.a: $(ZLIB_DEP)  $(PROTOBUF_DEP) $(LIBBORINGSSL_BASE64_TEST_LIB_OBJS) 
 	$(E) "[AR]      Creating $@"
 	$(Q) mkdir -p `dirname $@`
 	$(Q) rm -f $(LIBDIR)/$(CONFIG)/libboringssl_base64_test_lib.a
-	$(Q) $(AR) rcs $(LIBDIR)/$(CONFIG)/libboringssl_base64_test_lib.a $(LIBBORINGSSL_BASE64_TEST_LIB_OBJS)
+	$(Q) $(AR) $(LIBDIR)/$(CONFIG)/libboringssl_base64_test_lib.a $(LIBBORINGSSL_BASE64_TEST_LIB_OBJS) 
 ifeq ($(SYSTEM),Darwin)
 	$(Q) ranlib $(LIBDIR)/$(CONFIG)/libboringssl_base64_test_lib.a
 endif
@@ -4215,12 +4225,8 @@
 
 LIBBORINGSSL_BIO_TEST_LIB_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(LIBBORINGSSL_BIO_TEST_LIB_SRC))))
 
-# boringssl needs an override to ensure that it does not include
-# system openssl headers regardless of other configuration
-# we do so here with a target specific variable assignment
-$(LIBBORINGSSL_BIO_TEST_LIB_OBJS): CFLAGS := -Ithird_party/boringssl/include $(CFLAGS) -Wno-sign-conversion -Wno-conversion -Wno-unused-value -fvisibility=hidden
-$(LIBBORINGSSL_BIO_TEST_LIB_OBJS): CXXFLAGS := -Ithird_party/boringssl/include $(CXXFLAGS) -fvisibility=hidden
-$(LIBBORINGSSL_BIO_TEST_LIB_OBJS): CPPFLAGS += -DOPENSSL_NO_ASM -D_GNU_SOURCE
+$(LIBBORINGSSL_BIO_TEST_LIB_OBJS): CPPFLAGS += -Ithird_party/boringssl/include -fvisibility=hidden -DOPENSSL_NO_ASM -D_GNU_SOURCE -DWIN32_LEAN_AND_MEAN -D_HAS_EXCEPTIONS=0 -DNOMINMAX
+$(LIBBORINGSSL_BIO_TEST_LIB_OBJS): CFLAGS += -Wno-sign-conversion -Wno-conversion -Wno-unused-value -Wno-unknown-pragmas -Wno-implicit-function-declaration -Wno-unused-variable -Wno-sign-compare
 
 ifeq ($(NO_PROTOBUF),true)
 
@@ -4231,11 +4237,11 @@
 
 else
 
-$(LIBDIR)/$(CONFIG)/libboringssl_bio_test_lib.a: $(ZLIB_DEP) $(OPENSSL_DEP)  $(PROTOBUF_DEP) $(LIBBORINGSSL_BIO_TEST_LIB_OBJS)
+$(LIBDIR)/$(CONFIG)/libboringssl_bio_test_lib.a: $(ZLIB_DEP)  $(PROTOBUF_DEP) $(LIBBORINGSSL_BIO_TEST_LIB_OBJS) 
 	$(E) "[AR]      Creating $@"
 	$(Q) mkdir -p `dirname $@`
 	$(Q) rm -f $(LIBDIR)/$(CONFIG)/libboringssl_bio_test_lib.a
-	$(Q) $(AR) rcs $(LIBDIR)/$(CONFIG)/libboringssl_bio_test_lib.a $(LIBBORINGSSL_BIO_TEST_LIB_OBJS)
+	$(Q) $(AR) $(LIBDIR)/$(CONFIG)/libboringssl_bio_test_lib.a $(LIBBORINGSSL_BIO_TEST_LIB_OBJS) 
 ifeq ($(SYSTEM),Darwin)
 	$(Q) ranlib $(LIBDIR)/$(CONFIG)/libboringssl_bio_test_lib.a
 endif
@@ -4256,12 +4262,8 @@
 
 LIBBORINGSSL_BN_TEST_LIB_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(LIBBORINGSSL_BN_TEST_LIB_SRC))))
 
-# boringssl needs an override to ensure that it does not include
-# system openssl headers regardless of other configuration
-# we do so here with a target specific variable assignment
-$(LIBBORINGSSL_BN_TEST_LIB_OBJS): CFLAGS := -Ithird_party/boringssl/include $(CFLAGS) -Wno-sign-conversion -Wno-conversion -Wno-unused-value -fvisibility=hidden
-$(LIBBORINGSSL_BN_TEST_LIB_OBJS): CXXFLAGS := -Ithird_party/boringssl/include $(CXXFLAGS) -fvisibility=hidden
-$(LIBBORINGSSL_BN_TEST_LIB_OBJS): CPPFLAGS += -DOPENSSL_NO_ASM -D_GNU_SOURCE
+$(LIBBORINGSSL_BN_TEST_LIB_OBJS): CPPFLAGS += -Ithird_party/boringssl/include -fvisibility=hidden -DOPENSSL_NO_ASM -D_GNU_SOURCE -DWIN32_LEAN_AND_MEAN -D_HAS_EXCEPTIONS=0 -DNOMINMAX
+$(LIBBORINGSSL_BN_TEST_LIB_OBJS): CFLAGS += -Wno-sign-conversion -Wno-conversion -Wno-unused-value -Wno-unknown-pragmas -Wno-implicit-function-declaration -Wno-unused-variable -Wno-sign-compare
 
 ifeq ($(NO_PROTOBUF),true)
 
@@ -4272,11 +4274,11 @@
 
 else
 
-$(LIBDIR)/$(CONFIG)/libboringssl_bn_test_lib.a: $(ZLIB_DEP) $(OPENSSL_DEP)  $(PROTOBUF_DEP) $(LIBBORINGSSL_BN_TEST_LIB_OBJS)
+$(LIBDIR)/$(CONFIG)/libboringssl_bn_test_lib.a: $(ZLIB_DEP)  $(PROTOBUF_DEP) $(LIBBORINGSSL_BN_TEST_LIB_OBJS) 
 	$(E) "[AR]      Creating $@"
 	$(Q) mkdir -p `dirname $@`
 	$(Q) rm -f $(LIBDIR)/$(CONFIG)/libboringssl_bn_test_lib.a
-	$(Q) $(AR) rcs $(LIBDIR)/$(CONFIG)/libboringssl_bn_test_lib.a $(LIBBORINGSSL_BN_TEST_LIB_OBJS)
+	$(Q) $(AR) $(LIBDIR)/$(CONFIG)/libboringssl_bn_test_lib.a $(LIBBORINGSSL_BN_TEST_LIB_OBJS) 
 ifeq ($(SYSTEM),Darwin)
 	$(Q) ranlib $(LIBDIR)/$(CONFIG)/libboringssl_bn_test_lib.a
 endif
@@ -4297,12 +4299,8 @@
 
 LIBBORINGSSL_BYTESTRING_TEST_LIB_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(LIBBORINGSSL_BYTESTRING_TEST_LIB_SRC))))
 
-# boringssl needs an override to ensure that it does not include
-# system openssl headers regardless of other configuration
-# we do so here with a target specific variable assignment
-$(LIBBORINGSSL_BYTESTRING_TEST_LIB_OBJS): CFLAGS := -Ithird_party/boringssl/include $(CFLAGS) -Wno-sign-conversion -Wno-conversion -Wno-unused-value -fvisibility=hidden
-$(LIBBORINGSSL_BYTESTRING_TEST_LIB_OBJS): CXXFLAGS := -Ithird_party/boringssl/include $(CXXFLAGS) -fvisibility=hidden
-$(LIBBORINGSSL_BYTESTRING_TEST_LIB_OBJS): CPPFLAGS += -DOPENSSL_NO_ASM -D_GNU_SOURCE
+$(LIBBORINGSSL_BYTESTRING_TEST_LIB_OBJS): CPPFLAGS += -Ithird_party/boringssl/include -fvisibility=hidden -DOPENSSL_NO_ASM -D_GNU_SOURCE -DWIN32_LEAN_AND_MEAN -D_HAS_EXCEPTIONS=0 -DNOMINMAX
+$(LIBBORINGSSL_BYTESTRING_TEST_LIB_OBJS): CFLAGS += -Wno-sign-conversion -Wno-conversion -Wno-unused-value -Wno-unknown-pragmas -Wno-implicit-function-declaration -Wno-unused-variable -Wno-sign-compare
 
 ifeq ($(NO_PROTOBUF),true)
 
@@ -4313,11 +4311,11 @@
 
 else
 
-$(LIBDIR)/$(CONFIG)/libboringssl_bytestring_test_lib.a: $(ZLIB_DEP) $(OPENSSL_DEP)  $(PROTOBUF_DEP) $(LIBBORINGSSL_BYTESTRING_TEST_LIB_OBJS)
+$(LIBDIR)/$(CONFIG)/libboringssl_bytestring_test_lib.a: $(ZLIB_DEP)  $(PROTOBUF_DEP) $(LIBBORINGSSL_BYTESTRING_TEST_LIB_OBJS) 
 	$(E) "[AR]      Creating $@"
 	$(Q) mkdir -p `dirname $@`
 	$(Q) rm -f $(LIBDIR)/$(CONFIG)/libboringssl_bytestring_test_lib.a
-	$(Q) $(AR) rcs $(LIBDIR)/$(CONFIG)/libboringssl_bytestring_test_lib.a $(LIBBORINGSSL_BYTESTRING_TEST_LIB_OBJS)
+	$(Q) $(AR) $(LIBDIR)/$(CONFIG)/libboringssl_bytestring_test_lib.a $(LIBBORINGSSL_BYTESTRING_TEST_LIB_OBJS) 
 ifeq ($(SYSTEM),Darwin)
 	$(Q) ranlib $(LIBDIR)/$(CONFIG)/libboringssl_bytestring_test_lib.a
 endif
@@ -4338,12 +4336,8 @@
 
 LIBBORINGSSL_AEAD_TEST_LIB_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(LIBBORINGSSL_AEAD_TEST_LIB_SRC))))
 
-# boringssl needs an override to ensure that it does not include
-# system openssl headers regardless of other configuration
-# we do so here with a target specific variable assignment
-$(LIBBORINGSSL_AEAD_TEST_LIB_OBJS): CFLAGS := -Ithird_party/boringssl/include $(CFLAGS) -Wno-sign-conversion -Wno-conversion -Wno-unused-value -fvisibility=hidden
-$(LIBBORINGSSL_AEAD_TEST_LIB_OBJS): CXXFLAGS := -Ithird_party/boringssl/include $(CXXFLAGS) -fvisibility=hidden
-$(LIBBORINGSSL_AEAD_TEST_LIB_OBJS): CPPFLAGS += -DOPENSSL_NO_ASM -D_GNU_SOURCE
+$(LIBBORINGSSL_AEAD_TEST_LIB_OBJS): CPPFLAGS += -Ithird_party/boringssl/include -fvisibility=hidden -DOPENSSL_NO_ASM -D_GNU_SOURCE -DWIN32_LEAN_AND_MEAN -D_HAS_EXCEPTIONS=0 -DNOMINMAX
+$(LIBBORINGSSL_AEAD_TEST_LIB_OBJS): CFLAGS += -Wno-sign-conversion -Wno-conversion -Wno-unused-value -Wno-unknown-pragmas -Wno-implicit-function-declaration -Wno-unused-variable -Wno-sign-compare
 
 ifeq ($(NO_PROTOBUF),true)
 
@@ -4354,11 +4348,11 @@
 
 else
 
-$(LIBDIR)/$(CONFIG)/libboringssl_aead_test_lib.a: $(ZLIB_DEP) $(OPENSSL_DEP)  $(PROTOBUF_DEP) $(LIBBORINGSSL_AEAD_TEST_LIB_OBJS)
+$(LIBDIR)/$(CONFIG)/libboringssl_aead_test_lib.a: $(ZLIB_DEP)  $(PROTOBUF_DEP) $(LIBBORINGSSL_AEAD_TEST_LIB_OBJS) 
 	$(E) "[AR]      Creating $@"
 	$(Q) mkdir -p `dirname $@`
 	$(Q) rm -f $(LIBDIR)/$(CONFIG)/libboringssl_aead_test_lib.a
-	$(Q) $(AR) rcs $(LIBDIR)/$(CONFIG)/libboringssl_aead_test_lib.a $(LIBBORINGSSL_AEAD_TEST_LIB_OBJS)
+	$(Q) $(AR) $(LIBDIR)/$(CONFIG)/libboringssl_aead_test_lib.a $(LIBBORINGSSL_AEAD_TEST_LIB_OBJS) 
 ifeq ($(SYSTEM),Darwin)
 	$(Q) ranlib $(LIBDIR)/$(CONFIG)/libboringssl_aead_test_lib.a
 endif
@@ -4379,12 +4373,8 @@
 
 LIBBORINGSSL_CIPHER_TEST_LIB_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(LIBBORINGSSL_CIPHER_TEST_LIB_SRC))))
 
-# boringssl needs an override to ensure that it does not include
-# system openssl headers regardless of other configuration
-# we do so here with a target specific variable assignment
-$(LIBBORINGSSL_CIPHER_TEST_LIB_OBJS): CFLAGS := -Ithird_party/boringssl/include $(CFLAGS) -Wno-sign-conversion -Wno-conversion -Wno-unused-value -fvisibility=hidden
-$(LIBBORINGSSL_CIPHER_TEST_LIB_OBJS): CXXFLAGS := -Ithird_party/boringssl/include $(CXXFLAGS) -fvisibility=hidden
-$(LIBBORINGSSL_CIPHER_TEST_LIB_OBJS): CPPFLAGS += -DOPENSSL_NO_ASM -D_GNU_SOURCE
+$(LIBBORINGSSL_CIPHER_TEST_LIB_OBJS): CPPFLAGS += -Ithird_party/boringssl/include -fvisibility=hidden -DOPENSSL_NO_ASM -D_GNU_SOURCE -DWIN32_LEAN_AND_MEAN -D_HAS_EXCEPTIONS=0 -DNOMINMAX
+$(LIBBORINGSSL_CIPHER_TEST_LIB_OBJS): CFLAGS += -Wno-sign-conversion -Wno-conversion -Wno-unused-value -Wno-unknown-pragmas -Wno-implicit-function-declaration -Wno-unused-variable -Wno-sign-compare
 
 ifeq ($(NO_PROTOBUF),true)
 
@@ -4395,11 +4385,11 @@
 
 else
 
-$(LIBDIR)/$(CONFIG)/libboringssl_cipher_test_lib.a: $(ZLIB_DEP) $(OPENSSL_DEP)  $(PROTOBUF_DEP) $(LIBBORINGSSL_CIPHER_TEST_LIB_OBJS)
+$(LIBDIR)/$(CONFIG)/libboringssl_cipher_test_lib.a: $(ZLIB_DEP)  $(PROTOBUF_DEP) $(LIBBORINGSSL_CIPHER_TEST_LIB_OBJS) 
 	$(E) "[AR]      Creating $@"
 	$(Q) mkdir -p `dirname $@`
 	$(Q) rm -f $(LIBDIR)/$(CONFIG)/libboringssl_cipher_test_lib.a
-	$(Q) $(AR) rcs $(LIBDIR)/$(CONFIG)/libboringssl_cipher_test_lib.a $(LIBBORINGSSL_CIPHER_TEST_LIB_OBJS)
+	$(Q) $(AR) $(LIBDIR)/$(CONFIG)/libboringssl_cipher_test_lib.a $(LIBBORINGSSL_CIPHER_TEST_LIB_OBJS) 
 ifeq ($(SYSTEM),Darwin)
 	$(Q) ranlib $(LIBDIR)/$(CONFIG)/libboringssl_cipher_test_lib.a
 endif
@@ -4420,12 +4410,8 @@
 
 LIBBORINGSSL_CMAC_TEST_LIB_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(LIBBORINGSSL_CMAC_TEST_LIB_SRC))))
 
-# boringssl needs an override to ensure that it does not include
-# system openssl headers regardless of other configuration
-# we do so here with a target specific variable assignment
-$(LIBBORINGSSL_CMAC_TEST_LIB_OBJS): CFLAGS := -Ithird_party/boringssl/include $(CFLAGS) -Wno-sign-conversion -Wno-conversion -Wno-unused-value -fvisibility=hidden
-$(LIBBORINGSSL_CMAC_TEST_LIB_OBJS): CXXFLAGS := -Ithird_party/boringssl/include $(CXXFLAGS) -fvisibility=hidden
-$(LIBBORINGSSL_CMAC_TEST_LIB_OBJS): CPPFLAGS += -DOPENSSL_NO_ASM -D_GNU_SOURCE
+$(LIBBORINGSSL_CMAC_TEST_LIB_OBJS): CPPFLAGS += -Ithird_party/boringssl/include -fvisibility=hidden -DOPENSSL_NO_ASM -D_GNU_SOURCE -DWIN32_LEAN_AND_MEAN -D_HAS_EXCEPTIONS=0 -DNOMINMAX
+$(LIBBORINGSSL_CMAC_TEST_LIB_OBJS): CFLAGS += -Wno-sign-conversion -Wno-conversion -Wno-unused-value -Wno-unknown-pragmas -Wno-implicit-function-declaration -Wno-unused-variable -Wno-sign-compare
 
 ifeq ($(NO_PROTOBUF),true)
 
@@ -4436,11 +4422,11 @@
 
 else
 
-$(LIBDIR)/$(CONFIG)/libboringssl_cmac_test_lib.a: $(ZLIB_DEP) $(OPENSSL_DEP)  $(PROTOBUF_DEP) $(LIBBORINGSSL_CMAC_TEST_LIB_OBJS)
+$(LIBDIR)/$(CONFIG)/libboringssl_cmac_test_lib.a: $(ZLIB_DEP)  $(PROTOBUF_DEP) $(LIBBORINGSSL_CMAC_TEST_LIB_OBJS) 
 	$(E) "[AR]      Creating $@"
 	$(Q) mkdir -p `dirname $@`
 	$(Q) rm -f $(LIBDIR)/$(CONFIG)/libboringssl_cmac_test_lib.a
-	$(Q) $(AR) rcs $(LIBDIR)/$(CONFIG)/libboringssl_cmac_test_lib.a $(LIBBORINGSSL_CMAC_TEST_LIB_OBJS)
+	$(Q) $(AR) $(LIBDIR)/$(CONFIG)/libboringssl_cmac_test_lib.a $(LIBBORINGSSL_CMAC_TEST_LIB_OBJS) 
 ifeq ($(SYSTEM),Darwin)
 	$(Q) ranlib $(LIBDIR)/$(CONFIG)/libboringssl_cmac_test_lib.a
 endif
@@ -4461,18 +4447,14 @@
 
 LIBBORINGSSL_CONSTANT_TIME_TEST_LIB_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(LIBBORINGSSL_CONSTANT_TIME_TEST_LIB_SRC))))
 
-# boringssl needs an override to ensure that it does not include
-# system openssl headers regardless of other configuration
-# we do so here with a target specific variable assignment
-$(LIBBORINGSSL_CONSTANT_TIME_TEST_LIB_OBJS): CFLAGS := -Ithird_party/boringssl/include $(CFLAGS) -Wno-sign-conversion -Wno-conversion -Wno-unused-value -fvisibility=hidden
-$(LIBBORINGSSL_CONSTANT_TIME_TEST_LIB_OBJS): CXXFLAGS := -Ithird_party/boringssl/include $(CXXFLAGS) -fvisibility=hidden
-$(LIBBORINGSSL_CONSTANT_TIME_TEST_LIB_OBJS): CPPFLAGS += -DOPENSSL_NO_ASM -D_GNU_SOURCE
+$(LIBBORINGSSL_CONSTANT_TIME_TEST_LIB_OBJS): CPPFLAGS += -Ithird_party/boringssl/include -fvisibility=hidden -DOPENSSL_NO_ASM -D_GNU_SOURCE -DWIN32_LEAN_AND_MEAN -D_HAS_EXCEPTIONS=0 -DNOMINMAX
+$(LIBBORINGSSL_CONSTANT_TIME_TEST_LIB_OBJS): CFLAGS += -Wno-sign-conversion -Wno-conversion -Wno-unused-value -Wno-unknown-pragmas -Wno-implicit-function-declaration -Wno-unused-variable -Wno-sign-compare
 
-$(LIBDIR)/$(CONFIG)/libboringssl_constant_time_test_lib.a: $(ZLIB_DEP) $(OPENSSL_DEP)  $(LIBBORINGSSL_CONSTANT_TIME_TEST_LIB_OBJS)
+$(LIBDIR)/$(CONFIG)/libboringssl_constant_time_test_lib.a: $(ZLIB_DEP)  $(LIBBORINGSSL_CONSTANT_TIME_TEST_LIB_OBJS) 
 	$(E) "[AR]      Creating $@"
 	$(Q) mkdir -p `dirname $@`
 	$(Q) rm -f $(LIBDIR)/$(CONFIG)/libboringssl_constant_time_test_lib.a
-	$(Q) $(AR) rcs $(LIBDIR)/$(CONFIG)/libboringssl_constant_time_test_lib.a $(LIBBORINGSSL_CONSTANT_TIME_TEST_LIB_OBJS)
+	$(Q) $(AR) $(LIBDIR)/$(CONFIG)/libboringssl_constant_time_test_lib.a $(LIBBORINGSSL_CONSTANT_TIME_TEST_LIB_OBJS) 
 ifeq ($(SYSTEM),Darwin)
 	$(Q) ranlib $(LIBDIR)/$(CONFIG)/libboringssl_constant_time_test_lib.a
 endif
@@ -4491,12 +4473,8 @@
 
 LIBBORINGSSL_ED25519_TEST_LIB_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(LIBBORINGSSL_ED25519_TEST_LIB_SRC))))
 
-# boringssl needs an override to ensure that it does not include
-# system openssl headers regardless of other configuration
-# we do so here with a target specific variable assignment
-$(LIBBORINGSSL_ED25519_TEST_LIB_OBJS): CFLAGS := -Ithird_party/boringssl/include $(CFLAGS) -Wno-sign-conversion -Wno-conversion -Wno-unused-value -fvisibility=hidden
-$(LIBBORINGSSL_ED25519_TEST_LIB_OBJS): CXXFLAGS := -Ithird_party/boringssl/include $(CXXFLAGS) -fvisibility=hidden
-$(LIBBORINGSSL_ED25519_TEST_LIB_OBJS): CPPFLAGS += -DOPENSSL_NO_ASM -D_GNU_SOURCE
+$(LIBBORINGSSL_ED25519_TEST_LIB_OBJS): CPPFLAGS += -Ithird_party/boringssl/include -fvisibility=hidden -DOPENSSL_NO_ASM -D_GNU_SOURCE -DWIN32_LEAN_AND_MEAN -D_HAS_EXCEPTIONS=0 -DNOMINMAX
+$(LIBBORINGSSL_ED25519_TEST_LIB_OBJS): CFLAGS += -Wno-sign-conversion -Wno-conversion -Wno-unused-value -Wno-unknown-pragmas -Wno-implicit-function-declaration -Wno-unused-variable -Wno-sign-compare
 
 ifeq ($(NO_PROTOBUF),true)
 
@@ -4507,11 +4485,11 @@
 
 else
 
-$(LIBDIR)/$(CONFIG)/libboringssl_ed25519_test_lib.a: $(ZLIB_DEP) $(OPENSSL_DEP)  $(PROTOBUF_DEP) $(LIBBORINGSSL_ED25519_TEST_LIB_OBJS)
+$(LIBDIR)/$(CONFIG)/libboringssl_ed25519_test_lib.a: $(ZLIB_DEP)  $(PROTOBUF_DEP) $(LIBBORINGSSL_ED25519_TEST_LIB_OBJS) 
 	$(E) "[AR]      Creating $@"
 	$(Q) mkdir -p `dirname $@`
 	$(Q) rm -f $(LIBDIR)/$(CONFIG)/libboringssl_ed25519_test_lib.a
-	$(Q) $(AR) rcs $(LIBDIR)/$(CONFIG)/libboringssl_ed25519_test_lib.a $(LIBBORINGSSL_ED25519_TEST_LIB_OBJS)
+	$(Q) $(AR) $(LIBDIR)/$(CONFIG)/libboringssl_ed25519_test_lib.a $(LIBBORINGSSL_ED25519_TEST_LIB_OBJS) 
 ifeq ($(SYSTEM),Darwin)
 	$(Q) ranlib $(LIBDIR)/$(CONFIG)/libboringssl_ed25519_test_lib.a
 endif
@@ -4532,12 +4510,8 @@
 
 LIBBORINGSSL_X25519_TEST_LIB_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(LIBBORINGSSL_X25519_TEST_LIB_SRC))))
 
-# boringssl needs an override to ensure that it does not include
-# system openssl headers regardless of other configuration
-# we do so here with a target specific variable assignment
-$(LIBBORINGSSL_X25519_TEST_LIB_OBJS): CFLAGS := -Ithird_party/boringssl/include $(CFLAGS) -Wno-sign-conversion -Wno-conversion -Wno-unused-value -fvisibility=hidden
-$(LIBBORINGSSL_X25519_TEST_LIB_OBJS): CXXFLAGS := -Ithird_party/boringssl/include $(CXXFLAGS) -fvisibility=hidden
-$(LIBBORINGSSL_X25519_TEST_LIB_OBJS): CPPFLAGS += -DOPENSSL_NO_ASM -D_GNU_SOURCE
+$(LIBBORINGSSL_X25519_TEST_LIB_OBJS): CPPFLAGS += -Ithird_party/boringssl/include -fvisibility=hidden -DOPENSSL_NO_ASM -D_GNU_SOURCE -DWIN32_LEAN_AND_MEAN -D_HAS_EXCEPTIONS=0 -DNOMINMAX
+$(LIBBORINGSSL_X25519_TEST_LIB_OBJS): CFLAGS += -Wno-sign-conversion -Wno-conversion -Wno-unused-value -Wno-unknown-pragmas -Wno-implicit-function-declaration -Wno-unused-variable -Wno-sign-compare
 
 ifeq ($(NO_PROTOBUF),true)
 
@@ -4548,11 +4522,11 @@
 
 else
 
-$(LIBDIR)/$(CONFIG)/libboringssl_x25519_test_lib.a: $(ZLIB_DEP) $(OPENSSL_DEP)  $(PROTOBUF_DEP) $(LIBBORINGSSL_X25519_TEST_LIB_OBJS)
+$(LIBDIR)/$(CONFIG)/libboringssl_x25519_test_lib.a: $(ZLIB_DEP)  $(PROTOBUF_DEP) $(LIBBORINGSSL_X25519_TEST_LIB_OBJS) 
 	$(E) "[AR]      Creating $@"
 	$(Q) mkdir -p `dirname $@`
 	$(Q) rm -f $(LIBDIR)/$(CONFIG)/libboringssl_x25519_test_lib.a
-	$(Q) $(AR) rcs $(LIBDIR)/$(CONFIG)/libboringssl_x25519_test_lib.a $(LIBBORINGSSL_X25519_TEST_LIB_OBJS)
+	$(Q) $(AR) $(LIBDIR)/$(CONFIG)/libboringssl_x25519_test_lib.a $(LIBBORINGSSL_X25519_TEST_LIB_OBJS) 
 ifeq ($(SYSTEM),Darwin)
 	$(Q) ranlib $(LIBDIR)/$(CONFIG)/libboringssl_x25519_test_lib.a
 endif
@@ -4573,12 +4547,8 @@
 
 LIBBORINGSSL_DH_TEST_LIB_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(LIBBORINGSSL_DH_TEST_LIB_SRC))))
 
-# boringssl needs an override to ensure that it does not include
-# system openssl headers regardless of other configuration
-# we do so here with a target specific variable assignment
-$(LIBBORINGSSL_DH_TEST_LIB_OBJS): CFLAGS := -Ithird_party/boringssl/include $(CFLAGS) -Wno-sign-conversion -Wno-conversion -Wno-unused-value -fvisibility=hidden
-$(LIBBORINGSSL_DH_TEST_LIB_OBJS): CXXFLAGS := -Ithird_party/boringssl/include $(CXXFLAGS) -fvisibility=hidden
-$(LIBBORINGSSL_DH_TEST_LIB_OBJS): CPPFLAGS += -DOPENSSL_NO_ASM -D_GNU_SOURCE
+$(LIBBORINGSSL_DH_TEST_LIB_OBJS): CPPFLAGS += -Ithird_party/boringssl/include -fvisibility=hidden -DOPENSSL_NO_ASM -D_GNU_SOURCE -DWIN32_LEAN_AND_MEAN -D_HAS_EXCEPTIONS=0 -DNOMINMAX
+$(LIBBORINGSSL_DH_TEST_LIB_OBJS): CFLAGS += -Wno-sign-conversion -Wno-conversion -Wno-unused-value -Wno-unknown-pragmas -Wno-implicit-function-declaration -Wno-unused-variable -Wno-sign-compare
 
 ifeq ($(NO_PROTOBUF),true)
 
@@ -4589,11 +4559,11 @@
 
 else
 
-$(LIBDIR)/$(CONFIG)/libboringssl_dh_test_lib.a: $(ZLIB_DEP) $(OPENSSL_DEP)  $(PROTOBUF_DEP) $(LIBBORINGSSL_DH_TEST_LIB_OBJS)
+$(LIBDIR)/$(CONFIG)/libboringssl_dh_test_lib.a: $(ZLIB_DEP)  $(PROTOBUF_DEP) $(LIBBORINGSSL_DH_TEST_LIB_OBJS) 
 	$(E) "[AR]      Creating $@"
 	$(Q) mkdir -p `dirname $@`
 	$(Q) rm -f $(LIBDIR)/$(CONFIG)/libboringssl_dh_test_lib.a
-	$(Q) $(AR) rcs $(LIBDIR)/$(CONFIG)/libboringssl_dh_test_lib.a $(LIBBORINGSSL_DH_TEST_LIB_OBJS)
+	$(Q) $(AR) $(LIBDIR)/$(CONFIG)/libboringssl_dh_test_lib.a $(LIBBORINGSSL_DH_TEST_LIB_OBJS) 
 ifeq ($(SYSTEM),Darwin)
 	$(Q) ranlib $(LIBDIR)/$(CONFIG)/libboringssl_dh_test_lib.a
 endif
@@ -4614,12 +4584,8 @@
 
 LIBBORINGSSL_DIGEST_TEST_LIB_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(LIBBORINGSSL_DIGEST_TEST_LIB_SRC))))
 
-# boringssl needs an override to ensure that it does not include
-# system openssl headers regardless of other configuration
-# we do so here with a target specific variable assignment
-$(LIBBORINGSSL_DIGEST_TEST_LIB_OBJS): CFLAGS := -Ithird_party/boringssl/include $(CFLAGS) -Wno-sign-conversion -Wno-conversion -Wno-unused-value -fvisibility=hidden
-$(LIBBORINGSSL_DIGEST_TEST_LIB_OBJS): CXXFLAGS := -Ithird_party/boringssl/include $(CXXFLAGS) -fvisibility=hidden
-$(LIBBORINGSSL_DIGEST_TEST_LIB_OBJS): CPPFLAGS += -DOPENSSL_NO_ASM -D_GNU_SOURCE
+$(LIBBORINGSSL_DIGEST_TEST_LIB_OBJS): CPPFLAGS += -Ithird_party/boringssl/include -fvisibility=hidden -DOPENSSL_NO_ASM -D_GNU_SOURCE -DWIN32_LEAN_AND_MEAN -D_HAS_EXCEPTIONS=0 -DNOMINMAX
+$(LIBBORINGSSL_DIGEST_TEST_LIB_OBJS): CFLAGS += -Wno-sign-conversion -Wno-conversion -Wno-unused-value -Wno-unknown-pragmas -Wno-implicit-function-declaration -Wno-unused-variable -Wno-sign-compare
 
 ifeq ($(NO_PROTOBUF),true)
 
@@ -4630,11 +4596,11 @@
 
 else
 
-$(LIBDIR)/$(CONFIG)/libboringssl_digest_test_lib.a: $(ZLIB_DEP) $(OPENSSL_DEP)  $(PROTOBUF_DEP) $(LIBBORINGSSL_DIGEST_TEST_LIB_OBJS)
+$(LIBDIR)/$(CONFIG)/libboringssl_digest_test_lib.a: $(ZLIB_DEP)  $(PROTOBUF_DEP) $(LIBBORINGSSL_DIGEST_TEST_LIB_OBJS) 
 	$(E) "[AR]      Creating $@"
 	$(Q) mkdir -p `dirname $@`
 	$(Q) rm -f $(LIBDIR)/$(CONFIG)/libboringssl_digest_test_lib.a
-	$(Q) $(AR) rcs $(LIBDIR)/$(CONFIG)/libboringssl_digest_test_lib.a $(LIBBORINGSSL_DIGEST_TEST_LIB_OBJS)
+	$(Q) $(AR) $(LIBDIR)/$(CONFIG)/libboringssl_digest_test_lib.a $(LIBBORINGSSL_DIGEST_TEST_LIB_OBJS) 
 ifeq ($(SYSTEM),Darwin)
 	$(Q) ranlib $(LIBDIR)/$(CONFIG)/libboringssl_digest_test_lib.a
 endif
@@ -4655,18 +4621,14 @@
 
 LIBBORINGSSL_DSA_TEST_LIB_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(LIBBORINGSSL_DSA_TEST_LIB_SRC))))
 
-# boringssl needs an override to ensure that it does not include
-# system openssl headers regardless of other configuration
-# we do so here with a target specific variable assignment
-$(LIBBORINGSSL_DSA_TEST_LIB_OBJS): CFLAGS := -Ithird_party/boringssl/include $(CFLAGS) -Wno-sign-conversion -Wno-conversion -Wno-unused-value -fvisibility=hidden
-$(LIBBORINGSSL_DSA_TEST_LIB_OBJS): CXXFLAGS := -Ithird_party/boringssl/include $(CXXFLAGS) -fvisibility=hidden
-$(LIBBORINGSSL_DSA_TEST_LIB_OBJS): CPPFLAGS += -DOPENSSL_NO_ASM -D_GNU_SOURCE
+$(LIBBORINGSSL_DSA_TEST_LIB_OBJS): CPPFLAGS += -Ithird_party/boringssl/include -fvisibility=hidden -DOPENSSL_NO_ASM -D_GNU_SOURCE -DWIN32_LEAN_AND_MEAN -D_HAS_EXCEPTIONS=0 -DNOMINMAX
+$(LIBBORINGSSL_DSA_TEST_LIB_OBJS): CFLAGS += -Wno-sign-conversion -Wno-conversion -Wno-unused-value -Wno-unknown-pragmas -Wno-implicit-function-declaration -Wno-unused-variable -Wno-sign-compare
 
-$(LIBDIR)/$(CONFIG)/libboringssl_dsa_test_lib.a: $(ZLIB_DEP) $(OPENSSL_DEP)  $(LIBBORINGSSL_DSA_TEST_LIB_OBJS)
+$(LIBDIR)/$(CONFIG)/libboringssl_dsa_test_lib.a: $(ZLIB_DEP)  $(LIBBORINGSSL_DSA_TEST_LIB_OBJS) 
 	$(E) "[AR]      Creating $@"
 	$(Q) mkdir -p `dirname $@`
 	$(Q) rm -f $(LIBDIR)/$(CONFIG)/libboringssl_dsa_test_lib.a
-	$(Q) $(AR) rcs $(LIBDIR)/$(CONFIG)/libboringssl_dsa_test_lib.a $(LIBBORINGSSL_DSA_TEST_LIB_OBJS)
+	$(Q) $(AR) $(LIBDIR)/$(CONFIG)/libboringssl_dsa_test_lib.a $(LIBBORINGSSL_DSA_TEST_LIB_OBJS) 
 ifeq ($(SYSTEM),Darwin)
 	$(Q) ranlib $(LIBDIR)/$(CONFIG)/libboringssl_dsa_test_lib.a
 endif
@@ -4685,12 +4647,8 @@
 
 LIBBORINGSSL_EC_TEST_LIB_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(LIBBORINGSSL_EC_TEST_LIB_SRC))))
 
-# boringssl needs an override to ensure that it does not include
-# system openssl headers regardless of other configuration
-# we do so here with a target specific variable assignment
-$(LIBBORINGSSL_EC_TEST_LIB_OBJS): CFLAGS := -Ithird_party/boringssl/include $(CFLAGS) -Wno-sign-conversion -Wno-conversion -Wno-unused-value -fvisibility=hidden
-$(LIBBORINGSSL_EC_TEST_LIB_OBJS): CXXFLAGS := -Ithird_party/boringssl/include $(CXXFLAGS) -fvisibility=hidden
-$(LIBBORINGSSL_EC_TEST_LIB_OBJS): CPPFLAGS += -DOPENSSL_NO_ASM -D_GNU_SOURCE
+$(LIBBORINGSSL_EC_TEST_LIB_OBJS): CPPFLAGS += -Ithird_party/boringssl/include -fvisibility=hidden -DOPENSSL_NO_ASM -D_GNU_SOURCE -DWIN32_LEAN_AND_MEAN -D_HAS_EXCEPTIONS=0 -DNOMINMAX
+$(LIBBORINGSSL_EC_TEST_LIB_OBJS): CFLAGS += -Wno-sign-conversion -Wno-conversion -Wno-unused-value -Wno-unknown-pragmas -Wno-implicit-function-declaration -Wno-unused-variable -Wno-sign-compare
 
 ifeq ($(NO_PROTOBUF),true)
 
@@ -4701,11 +4659,11 @@
 
 else
 
-$(LIBDIR)/$(CONFIG)/libboringssl_ec_test_lib.a: $(ZLIB_DEP) $(OPENSSL_DEP)  $(PROTOBUF_DEP) $(LIBBORINGSSL_EC_TEST_LIB_OBJS)
+$(LIBDIR)/$(CONFIG)/libboringssl_ec_test_lib.a: $(ZLIB_DEP)  $(PROTOBUF_DEP) $(LIBBORINGSSL_EC_TEST_LIB_OBJS) 
 	$(E) "[AR]      Creating $@"
 	$(Q) mkdir -p `dirname $@`
 	$(Q) rm -f $(LIBDIR)/$(CONFIG)/libboringssl_ec_test_lib.a
-	$(Q) $(AR) rcs $(LIBDIR)/$(CONFIG)/libboringssl_ec_test_lib.a $(LIBBORINGSSL_EC_TEST_LIB_OBJS)
+	$(Q) $(AR) $(LIBDIR)/$(CONFIG)/libboringssl_ec_test_lib.a $(LIBBORINGSSL_EC_TEST_LIB_OBJS) 
 ifeq ($(SYSTEM),Darwin)
 	$(Q) ranlib $(LIBDIR)/$(CONFIG)/libboringssl_ec_test_lib.a
 endif
@@ -4726,18 +4684,14 @@
 
 LIBBORINGSSL_EXAMPLE_MUL_LIB_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(LIBBORINGSSL_EXAMPLE_MUL_LIB_SRC))))
 
-# boringssl needs an override to ensure that it does not include
-# system openssl headers regardless of other configuration
-# we do so here with a target specific variable assignment
-$(LIBBORINGSSL_EXAMPLE_MUL_LIB_OBJS): CFLAGS := -Ithird_party/boringssl/include $(CFLAGS) -Wno-sign-conversion -Wno-conversion -Wno-unused-value -fvisibility=hidden
-$(LIBBORINGSSL_EXAMPLE_MUL_LIB_OBJS): CXXFLAGS := -Ithird_party/boringssl/include $(CXXFLAGS) -fvisibility=hidden
-$(LIBBORINGSSL_EXAMPLE_MUL_LIB_OBJS): CPPFLAGS += -DOPENSSL_NO_ASM -D_GNU_SOURCE
+$(LIBBORINGSSL_EXAMPLE_MUL_LIB_OBJS): CPPFLAGS += -Ithird_party/boringssl/include -fvisibility=hidden -DOPENSSL_NO_ASM -D_GNU_SOURCE -DWIN32_LEAN_AND_MEAN -D_HAS_EXCEPTIONS=0 -DNOMINMAX
+$(LIBBORINGSSL_EXAMPLE_MUL_LIB_OBJS): CFLAGS += -Wno-sign-conversion -Wno-conversion -Wno-unused-value -Wno-unknown-pragmas -Wno-implicit-function-declaration -Wno-unused-variable -Wno-sign-compare
 
-$(LIBDIR)/$(CONFIG)/libboringssl_example_mul_lib.a: $(ZLIB_DEP) $(OPENSSL_DEP)  $(LIBBORINGSSL_EXAMPLE_MUL_LIB_OBJS)
+$(LIBDIR)/$(CONFIG)/libboringssl_example_mul_lib.a: $(ZLIB_DEP)  $(LIBBORINGSSL_EXAMPLE_MUL_LIB_OBJS) 
 	$(E) "[AR]      Creating $@"
 	$(Q) mkdir -p `dirname $@`
 	$(Q) rm -f $(LIBDIR)/$(CONFIG)/libboringssl_example_mul_lib.a
-	$(Q) $(AR) rcs $(LIBDIR)/$(CONFIG)/libboringssl_example_mul_lib.a $(LIBBORINGSSL_EXAMPLE_MUL_LIB_OBJS)
+	$(Q) $(AR) $(LIBDIR)/$(CONFIG)/libboringssl_example_mul_lib.a $(LIBBORINGSSL_EXAMPLE_MUL_LIB_OBJS) 
 ifeq ($(SYSTEM),Darwin)
 	$(Q) ranlib $(LIBDIR)/$(CONFIG)/libboringssl_example_mul_lib.a
 endif
@@ -4756,12 +4710,8 @@
 
 LIBBORINGSSL_ECDSA_TEST_LIB_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(LIBBORINGSSL_ECDSA_TEST_LIB_SRC))))
 
-# boringssl needs an override to ensure that it does not include
-# system openssl headers regardless of other configuration
-# we do so here with a target specific variable assignment
-$(LIBBORINGSSL_ECDSA_TEST_LIB_OBJS): CFLAGS := -Ithird_party/boringssl/include $(CFLAGS) -Wno-sign-conversion -Wno-conversion -Wno-unused-value -fvisibility=hidden
-$(LIBBORINGSSL_ECDSA_TEST_LIB_OBJS): CXXFLAGS := -Ithird_party/boringssl/include $(CXXFLAGS) -fvisibility=hidden
-$(LIBBORINGSSL_ECDSA_TEST_LIB_OBJS): CPPFLAGS += -DOPENSSL_NO_ASM -D_GNU_SOURCE
+$(LIBBORINGSSL_ECDSA_TEST_LIB_OBJS): CPPFLAGS += -Ithird_party/boringssl/include -fvisibility=hidden -DOPENSSL_NO_ASM -D_GNU_SOURCE -DWIN32_LEAN_AND_MEAN -D_HAS_EXCEPTIONS=0 -DNOMINMAX
+$(LIBBORINGSSL_ECDSA_TEST_LIB_OBJS): CFLAGS += -Wno-sign-conversion -Wno-conversion -Wno-unused-value -Wno-unknown-pragmas -Wno-implicit-function-declaration -Wno-unused-variable -Wno-sign-compare
 
 ifeq ($(NO_PROTOBUF),true)
 
@@ -4772,11 +4722,11 @@
 
 else
 
-$(LIBDIR)/$(CONFIG)/libboringssl_ecdsa_test_lib.a: $(ZLIB_DEP) $(OPENSSL_DEP)  $(PROTOBUF_DEP) $(LIBBORINGSSL_ECDSA_TEST_LIB_OBJS)
+$(LIBDIR)/$(CONFIG)/libboringssl_ecdsa_test_lib.a: $(ZLIB_DEP)  $(PROTOBUF_DEP) $(LIBBORINGSSL_ECDSA_TEST_LIB_OBJS) 
 	$(E) "[AR]      Creating $@"
 	$(Q) mkdir -p `dirname $@`
 	$(Q) rm -f $(LIBDIR)/$(CONFIG)/libboringssl_ecdsa_test_lib.a
-	$(Q) $(AR) rcs $(LIBDIR)/$(CONFIG)/libboringssl_ecdsa_test_lib.a $(LIBBORINGSSL_ECDSA_TEST_LIB_OBJS)
+	$(Q) $(AR) $(LIBDIR)/$(CONFIG)/libboringssl_ecdsa_test_lib.a $(LIBBORINGSSL_ECDSA_TEST_LIB_OBJS) 
 ifeq ($(SYSTEM),Darwin)
 	$(Q) ranlib $(LIBDIR)/$(CONFIG)/libboringssl_ecdsa_test_lib.a
 endif
@@ -4797,12 +4747,8 @@
 
 LIBBORINGSSL_ERR_TEST_LIB_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(LIBBORINGSSL_ERR_TEST_LIB_SRC))))
 
-# boringssl needs an override to ensure that it does not include
-# system openssl headers regardless of other configuration
-# we do so here with a target specific variable assignment
-$(LIBBORINGSSL_ERR_TEST_LIB_OBJS): CFLAGS := -Ithird_party/boringssl/include $(CFLAGS) -Wno-sign-conversion -Wno-conversion -Wno-unused-value -fvisibility=hidden
-$(LIBBORINGSSL_ERR_TEST_LIB_OBJS): CXXFLAGS := -Ithird_party/boringssl/include $(CXXFLAGS) -fvisibility=hidden
-$(LIBBORINGSSL_ERR_TEST_LIB_OBJS): CPPFLAGS += -DOPENSSL_NO_ASM -D_GNU_SOURCE
+$(LIBBORINGSSL_ERR_TEST_LIB_OBJS): CPPFLAGS += -Ithird_party/boringssl/include -fvisibility=hidden -DOPENSSL_NO_ASM -D_GNU_SOURCE -DWIN32_LEAN_AND_MEAN -D_HAS_EXCEPTIONS=0 -DNOMINMAX
+$(LIBBORINGSSL_ERR_TEST_LIB_OBJS): CFLAGS += -Wno-sign-conversion -Wno-conversion -Wno-unused-value -Wno-unknown-pragmas -Wno-implicit-function-declaration -Wno-unused-variable -Wno-sign-compare
 
 ifeq ($(NO_PROTOBUF),true)
 
@@ -4813,11 +4759,11 @@
 
 else
 
-$(LIBDIR)/$(CONFIG)/libboringssl_err_test_lib.a: $(ZLIB_DEP) $(OPENSSL_DEP)  $(PROTOBUF_DEP) $(LIBBORINGSSL_ERR_TEST_LIB_OBJS)
+$(LIBDIR)/$(CONFIG)/libboringssl_err_test_lib.a: $(ZLIB_DEP)  $(PROTOBUF_DEP) $(LIBBORINGSSL_ERR_TEST_LIB_OBJS) 
 	$(E) "[AR]      Creating $@"
 	$(Q) mkdir -p `dirname $@`
 	$(Q) rm -f $(LIBDIR)/$(CONFIG)/libboringssl_err_test_lib.a
-	$(Q) $(AR) rcs $(LIBDIR)/$(CONFIG)/libboringssl_err_test_lib.a $(LIBBORINGSSL_ERR_TEST_LIB_OBJS)
+	$(Q) $(AR) $(LIBDIR)/$(CONFIG)/libboringssl_err_test_lib.a $(LIBBORINGSSL_ERR_TEST_LIB_OBJS) 
 ifeq ($(SYSTEM),Darwin)
 	$(Q) ranlib $(LIBDIR)/$(CONFIG)/libboringssl_err_test_lib.a
 endif
@@ -4838,12 +4784,8 @@
 
 LIBBORINGSSL_EVP_EXTRA_TEST_LIB_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(LIBBORINGSSL_EVP_EXTRA_TEST_LIB_SRC))))
 
-# boringssl needs an override to ensure that it does not include
-# system openssl headers regardless of other configuration
-# we do so here with a target specific variable assignment
-$(LIBBORINGSSL_EVP_EXTRA_TEST_LIB_OBJS): CFLAGS := -Ithird_party/boringssl/include $(CFLAGS) -Wno-sign-conversion -Wno-conversion -Wno-unused-value -fvisibility=hidden
-$(LIBBORINGSSL_EVP_EXTRA_TEST_LIB_OBJS): CXXFLAGS := -Ithird_party/boringssl/include $(CXXFLAGS) -fvisibility=hidden
-$(LIBBORINGSSL_EVP_EXTRA_TEST_LIB_OBJS): CPPFLAGS += -DOPENSSL_NO_ASM -D_GNU_SOURCE
+$(LIBBORINGSSL_EVP_EXTRA_TEST_LIB_OBJS): CPPFLAGS += -Ithird_party/boringssl/include -fvisibility=hidden -DOPENSSL_NO_ASM -D_GNU_SOURCE -DWIN32_LEAN_AND_MEAN -D_HAS_EXCEPTIONS=0 -DNOMINMAX
+$(LIBBORINGSSL_EVP_EXTRA_TEST_LIB_OBJS): CFLAGS += -Wno-sign-conversion -Wno-conversion -Wno-unused-value -Wno-unknown-pragmas -Wno-implicit-function-declaration -Wno-unused-variable -Wno-sign-compare
 
 ifeq ($(NO_PROTOBUF),true)
 
@@ -4854,11 +4796,11 @@
 
 else
 
-$(LIBDIR)/$(CONFIG)/libboringssl_evp_extra_test_lib.a: $(ZLIB_DEP) $(OPENSSL_DEP)  $(PROTOBUF_DEP) $(LIBBORINGSSL_EVP_EXTRA_TEST_LIB_OBJS)
+$(LIBDIR)/$(CONFIG)/libboringssl_evp_extra_test_lib.a: $(ZLIB_DEP)  $(PROTOBUF_DEP) $(LIBBORINGSSL_EVP_EXTRA_TEST_LIB_OBJS) 
 	$(E) "[AR]      Creating $@"
 	$(Q) mkdir -p `dirname $@`
 	$(Q) rm -f $(LIBDIR)/$(CONFIG)/libboringssl_evp_extra_test_lib.a
-	$(Q) $(AR) rcs $(LIBDIR)/$(CONFIG)/libboringssl_evp_extra_test_lib.a $(LIBBORINGSSL_EVP_EXTRA_TEST_LIB_OBJS)
+	$(Q) $(AR) $(LIBDIR)/$(CONFIG)/libboringssl_evp_extra_test_lib.a $(LIBBORINGSSL_EVP_EXTRA_TEST_LIB_OBJS) 
 ifeq ($(SYSTEM),Darwin)
 	$(Q) ranlib $(LIBDIR)/$(CONFIG)/libboringssl_evp_extra_test_lib.a
 endif
@@ -4879,12 +4821,8 @@
 
 LIBBORINGSSL_EVP_TEST_LIB_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(LIBBORINGSSL_EVP_TEST_LIB_SRC))))
 
-# boringssl needs an override to ensure that it does not include
-# system openssl headers regardless of other configuration
-# we do so here with a target specific variable assignment
-$(LIBBORINGSSL_EVP_TEST_LIB_OBJS): CFLAGS := -Ithird_party/boringssl/include $(CFLAGS) -Wno-sign-conversion -Wno-conversion -Wno-unused-value -fvisibility=hidden
-$(LIBBORINGSSL_EVP_TEST_LIB_OBJS): CXXFLAGS := -Ithird_party/boringssl/include $(CXXFLAGS) -fvisibility=hidden
-$(LIBBORINGSSL_EVP_TEST_LIB_OBJS): CPPFLAGS += -DOPENSSL_NO_ASM -D_GNU_SOURCE
+$(LIBBORINGSSL_EVP_TEST_LIB_OBJS): CPPFLAGS += -Ithird_party/boringssl/include -fvisibility=hidden -DOPENSSL_NO_ASM -D_GNU_SOURCE -DWIN32_LEAN_AND_MEAN -D_HAS_EXCEPTIONS=0 -DNOMINMAX
+$(LIBBORINGSSL_EVP_TEST_LIB_OBJS): CFLAGS += -Wno-sign-conversion -Wno-conversion -Wno-unused-value -Wno-unknown-pragmas -Wno-implicit-function-declaration -Wno-unused-variable -Wno-sign-compare
 
 ifeq ($(NO_PROTOBUF),true)
 
@@ -4895,11 +4833,11 @@
 
 else
 
-$(LIBDIR)/$(CONFIG)/libboringssl_evp_test_lib.a: $(ZLIB_DEP) $(OPENSSL_DEP)  $(PROTOBUF_DEP) $(LIBBORINGSSL_EVP_TEST_LIB_OBJS)
+$(LIBDIR)/$(CONFIG)/libboringssl_evp_test_lib.a: $(ZLIB_DEP)  $(PROTOBUF_DEP) $(LIBBORINGSSL_EVP_TEST_LIB_OBJS) 
 	$(E) "[AR]      Creating $@"
 	$(Q) mkdir -p `dirname $@`
 	$(Q) rm -f $(LIBDIR)/$(CONFIG)/libboringssl_evp_test_lib.a
-	$(Q) $(AR) rcs $(LIBDIR)/$(CONFIG)/libboringssl_evp_test_lib.a $(LIBBORINGSSL_EVP_TEST_LIB_OBJS)
+	$(Q) $(AR) $(LIBDIR)/$(CONFIG)/libboringssl_evp_test_lib.a $(LIBBORINGSSL_EVP_TEST_LIB_OBJS) 
 ifeq ($(SYSTEM),Darwin)
 	$(Q) ranlib $(LIBDIR)/$(CONFIG)/libboringssl_evp_test_lib.a
 endif
@@ -4920,12 +4858,8 @@
 
 LIBBORINGSSL_PBKDF_TEST_LIB_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(LIBBORINGSSL_PBKDF_TEST_LIB_SRC))))
 
-# boringssl needs an override to ensure that it does not include
-# system openssl headers regardless of other configuration
-# we do so here with a target specific variable assignment
-$(LIBBORINGSSL_PBKDF_TEST_LIB_OBJS): CFLAGS := -Ithird_party/boringssl/include $(CFLAGS) -Wno-sign-conversion -Wno-conversion -Wno-unused-value -fvisibility=hidden
-$(LIBBORINGSSL_PBKDF_TEST_LIB_OBJS): CXXFLAGS := -Ithird_party/boringssl/include $(CXXFLAGS) -fvisibility=hidden
-$(LIBBORINGSSL_PBKDF_TEST_LIB_OBJS): CPPFLAGS += -DOPENSSL_NO_ASM -D_GNU_SOURCE
+$(LIBBORINGSSL_PBKDF_TEST_LIB_OBJS): CPPFLAGS += -Ithird_party/boringssl/include -fvisibility=hidden -DOPENSSL_NO_ASM -D_GNU_SOURCE -DWIN32_LEAN_AND_MEAN -D_HAS_EXCEPTIONS=0 -DNOMINMAX
+$(LIBBORINGSSL_PBKDF_TEST_LIB_OBJS): CFLAGS += -Wno-sign-conversion -Wno-conversion -Wno-unused-value -Wno-unknown-pragmas -Wno-implicit-function-declaration -Wno-unused-variable -Wno-sign-compare
 
 ifeq ($(NO_PROTOBUF),true)
 
@@ -4936,11 +4870,11 @@
 
 else
 
-$(LIBDIR)/$(CONFIG)/libboringssl_pbkdf_test_lib.a: $(ZLIB_DEP) $(OPENSSL_DEP)  $(PROTOBUF_DEP) $(LIBBORINGSSL_PBKDF_TEST_LIB_OBJS)
+$(LIBDIR)/$(CONFIG)/libboringssl_pbkdf_test_lib.a: $(ZLIB_DEP)  $(PROTOBUF_DEP) $(LIBBORINGSSL_PBKDF_TEST_LIB_OBJS) 
 	$(E) "[AR]      Creating $@"
 	$(Q) mkdir -p `dirname $@`
 	$(Q) rm -f $(LIBDIR)/$(CONFIG)/libboringssl_pbkdf_test_lib.a
-	$(Q) $(AR) rcs $(LIBDIR)/$(CONFIG)/libboringssl_pbkdf_test_lib.a $(LIBBORINGSSL_PBKDF_TEST_LIB_OBJS)
+	$(Q) $(AR) $(LIBDIR)/$(CONFIG)/libboringssl_pbkdf_test_lib.a $(LIBBORINGSSL_PBKDF_TEST_LIB_OBJS) 
 ifeq ($(SYSTEM),Darwin)
 	$(Q) ranlib $(LIBDIR)/$(CONFIG)/libboringssl_pbkdf_test_lib.a
 endif
@@ -4961,18 +4895,14 @@
 
 LIBBORINGSSL_HKDF_TEST_LIB_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(LIBBORINGSSL_HKDF_TEST_LIB_SRC))))
 
-# boringssl needs an override to ensure that it does not include
-# system openssl headers regardless of other configuration
-# we do so here with a target specific variable assignment
-$(LIBBORINGSSL_HKDF_TEST_LIB_OBJS): CFLAGS := -Ithird_party/boringssl/include $(CFLAGS) -Wno-sign-conversion -Wno-conversion -Wno-unused-value -fvisibility=hidden
-$(LIBBORINGSSL_HKDF_TEST_LIB_OBJS): CXXFLAGS := -Ithird_party/boringssl/include $(CXXFLAGS) -fvisibility=hidden
-$(LIBBORINGSSL_HKDF_TEST_LIB_OBJS): CPPFLAGS += -DOPENSSL_NO_ASM -D_GNU_SOURCE
+$(LIBBORINGSSL_HKDF_TEST_LIB_OBJS): CPPFLAGS += -Ithird_party/boringssl/include -fvisibility=hidden -DOPENSSL_NO_ASM -D_GNU_SOURCE -DWIN32_LEAN_AND_MEAN -D_HAS_EXCEPTIONS=0 -DNOMINMAX
+$(LIBBORINGSSL_HKDF_TEST_LIB_OBJS): CFLAGS += -Wno-sign-conversion -Wno-conversion -Wno-unused-value -Wno-unknown-pragmas -Wno-implicit-function-declaration -Wno-unused-variable -Wno-sign-compare
 
-$(LIBDIR)/$(CONFIG)/libboringssl_hkdf_test_lib.a: $(ZLIB_DEP) $(OPENSSL_DEP)  $(LIBBORINGSSL_HKDF_TEST_LIB_OBJS)
+$(LIBDIR)/$(CONFIG)/libboringssl_hkdf_test_lib.a: $(ZLIB_DEP)  $(LIBBORINGSSL_HKDF_TEST_LIB_OBJS) 
 	$(E) "[AR]      Creating $@"
 	$(Q) mkdir -p `dirname $@`
 	$(Q) rm -f $(LIBDIR)/$(CONFIG)/libboringssl_hkdf_test_lib.a
-	$(Q) $(AR) rcs $(LIBDIR)/$(CONFIG)/libboringssl_hkdf_test_lib.a $(LIBBORINGSSL_HKDF_TEST_LIB_OBJS)
+	$(Q) $(AR) $(LIBDIR)/$(CONFIG)/libboringssl_hkdf_test_lib.a $(LIBBORINGSSL_HKDF_TEST_LIB_OBJS) 
 ifeq ($(SYSTEM),Darwin)
 	$(Q) ranlib $(LIBDIR)/$(CONFIG)/libboringssl_hkdf_test_lib.a
 endif
@@ -4991,12 +4921,8 @@
 
 LIBBORINGSSL_HMAC_TEST_LIB_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(LIBBORINGSSL_HMAC_TEST_LIB_SRC))))
 
-# boringssl needs an override to ensure that it does not include
-# system openssl headers regardless of other configuration
-# we do so here with a target specific variable assignment
-$(LIBBORINGSSL_HMAC_TEST_LIB_OBJS): CFLAGS := -Ithird_party/boringssl/include $(CFLAGS) -Wno-sign-conversion -Wno-conversion -Wno-unused-value -fvisibility=hidden
-$(LIBBORINGSSL_HMAC_TEST_LIB_OBJS): CXXFLAGS := -Ithird_party/boringssl/include $(CXXFLAGS) -fvisibility=hidden
-$(LIBBORINGSSL_HMAC_TEST_LIB_OBJS): CPPFLAGS += -DOPENSSL_NO_ASM -D_GNU_SOURCE
+$(LIBBORINGSSL_HMAC_TEST_LIB_OBJS): CPPFLAGS += -Ithird_party/boringssl/include -fvisibility=hidden -DOPENSSL_NO_ASM -D_GNU_SOURCE -DWIN32_LEAN_AND_MEAN -D_HAS_EXCEPTIONS=0 -DNOMINMAX
+$(LIBBORINGSSL_HMAC_TEST_LIB_OBJS): CFLAGS += -Wno-sign-conversion -Wno-conversion -Wno-unused-value -Wno-unknown-pragmas -Wno-implicit-function-declaration -Wno-unused-variable -Wno-sign-compare
 
 ifeq ($(NO_PROTOBUF),true)
 
@@ -5007,11 +4933,11 @@
 
 else
 
-$(LIBDIR)/$(CONFIG)/libboringssl_hmac_test_lib.a: $(ZLIB_DEP) $(OPENSSL_DEP)  $(PROTOBUF_DEP) $(LIBBORINGSSL_HMAC_TEST_LIB_OBJS)
+$(LIBDIR)/$(CONFIG)/libboringssl_hmac_test_lib.a: $(ZLIB_DEP)  $(PROTOBUF_DEP) $(LIBBORINGSSL_HMAC_TEST_LIB_OBJS) 
 	$(E) "[AR]      Creating $@"
 	$(Q) mkdir -p `dirname $@`
 	$(Q) rm -f $(LIBDIR)/$(CONFIG)/libboringssl_hmac_test_lib.a
-	$(Q) $(AR) rcs $(LIBDIR)/$(CONFIG)/libboringssl_hmac_test_lib.a $(LIBBORINGSSL_HMAC_TEST_LIB_OBJS)
+	$(Q) $(AR) $(LIBDIR)/$(CONFIG)/libboringssl_hmac_test_lib.a $(LIBBORINGSSL_HMAC_TEST_LIB_OBJS) 
 ifeq ($(SYSTEM),Darwin)
 	$(Q) ranlib $(LIBDIR)/$(CONFIG)/libboringssl_hmac_test_lib.a
 endif
@@ -5032,18 +4958,14 @@
 
 LIBBORINGSSL_LHASH_TEST_LIB_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(LIBBORINGSSL_LHASH_TEST_LIB_SRC))))
 
-# boringssl needs an override to ensure that it does not include
-# system openssl headers regardless of other configuration
-# we do so here with a target specific variable assignment
-$(LIBBORINGSSL_LHASH_TEST_LIB_OBJS): CFLAGS := -Ithird_party/boringssl/include $(CFLAGS) -Wno-sign-conversion -Wno-conversion -Wno-unused-value -fvisibility=hidden
-$(LIBBORINGSSL_LHASH_TEST_LIB_OBJS): CXXFLAGS := -Ithird_party/boringssl/include $(CXXFLAGS) -fvisibility=hidden
-$(LIBBORINGSSL_LHASH_TEST_LIB_OBJS): CPPFLAGS += -DOPENSSL_NO_ASM -D_GNU_SOURCE
+$(LIBBORINGSSL_LHASH_TEST_LIB_OBJS): CPPFLAGS += -Ithird_party/boringssl/include -fvisibility=hidden -DOPENSSL_NO_ASM -D_GNU_SOURCE -DWIN32_LEAN_AND_MEAN -D_HAS_EXCEPTIONS=0 -DNOMINMAX
+$(LIBBORINGSSL_LHASH_TEST_LIB_OBJS): CFLAGS += -Wno-sign-conversion -Wno-conversion -Wno-unused-value -Wno-unknown-pragmas -Wno-implicit-function-declaration -Wno-unused-variable -Wno-sign-compare
 
-$(LIBDIR)/$(CONFIG)/libboringssl_lhash_test_lib.a: $(ZLIB_DEP) $(OPENSSL_DEP)  $(LIBBORINGSSL_LHASH_TEST_LIB_OBJS)
+$(LIBDIR)/$(CONFIG)/libboringssl_lhash_test_lib.a: $(ZLIB_DEP)  $(LIBBORINGSSL_LHASH_TEST_LIB_OBJS) 
 	$(E) "[AR]      Creating $@"
 	$(Q) mkdir -p `dirname $@`
 	$(Q) rm -f $(LIBDIR)/$(CONFIG)/libboringssl_lhash_test_lib.a
-	$(Q) $(AR) rcs $(LIBDIR)/$(CONFIG)/libboringssl_lhash_test_lib.a $(LIBBORINGSSL_LHASH_TEST_LIB_OBJS)
+	$(Q) $(AR) $(LIBDIR)/$(CONFIG)/libboringssl_lhash_test_lib.a $(LIBBORINGSSL_LHASH_TEST_LIB_OBJS) 
 ifeq ($(SYSTEM),Darwin)
 	$(Q) ranlib $(LIBDIR)/$(CONFIG)/libboringssl_lhash_test_lib.a
 endif
@@ -5062,18 +4984,14 @@
 
 LIBBORINGSSL_GCM_TEST_LIB_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(LIBBORINGSSL_GCM_TEST_LIB_SRC))))
 
-# boringssl needs an override to ensure that it does not include
-# system openssl headers regardless of other configuration
-# we do so here with a target specific variable assignment
-$(LIBBORINGSSL_GCM_TEST_LIB_OBJS): CFLAGS := -Ithird_party/boringssl/include $(CFLAGS) -Wno-sign-conversion -Wno-conversion -Wno-unused-value -fvisibility=hidden
-$(LIBBORINGSSL_GCM_TEST_LIB_OBJS): CXXFLAGS := -Ithird_party/boringssl/include $(CXXFLAGS) -fvisibility=hidden
-$(LIBBORINGSSL_GCM_TEST_LIB_OBJS): CPPFLAGS += -DOPENSSL_NO_ASM -D_GNU_SOURCE
+$(LIBBORINGSSL_GCM_TEST_LIB_OBJS): CPPFLAGS += -Ithird_party/boringssl/include -fvisibility=hidden -DOPENSSL_NO_ASM -D_GNU_SOURCE -DWIN32_LEAN_AND_MEAN -D_HAS_EXCEPTIONS=0 -DNOMINMAX
+$(LIBBORINGSSL_GCM_TEST_LIB_OBJS): CFLAGS += -Wno-sign-conversion -Wno-conversion -Wno-unused-value -Wno-unknown-pragmas -Wno-implicit-function-declaration -Wno-unused-variable -Wno-sign-compare
 
-$(LIBDIR)/$(CONFIG)/libboringssl_gcm_test_lib.a: $(ZLIB_DEP) $(OPENSSL_DEP)  $(LIBBORINGSSL_GCM_TEST_LIB_OBJS)
+$(LIBDIR)/$(CONFIG)/libboringssl_gcm_test_lib.a: $(ZLIB_DEP)  $(LIBBORINGSSL_GCM_TEST_LIB_OBJS) 
 	$(E) "[AR]      Creating $@"
 	$(Q) mkdir -p `dirname $@`
 	$(Q) rm -f $(LIBDIR)/$(CONFIG)/libboringssl_gcm_test_lib.a
-	$(Q) $(AR) rcs $(LIBDIR)/$(CONFIG)/libboringssl_gcm_test_lib.a $(LIBBORINGSSL_GCM_TEST_LIB_OBJS)
+	$(Q) $(AR) $(LIBDIR)/$(CONFIG)/libboringssl_gcm_test_lib.a $(LIBBORINGSSL_GCM_TEST_LIB_OBJS) 
 ifeq ($(SYSTEM),Darwin)
 	$(Q) ranlib $(LIBDIR)/$(CONFIG)/libboringssl_gcm_test_lib.a
 endif
@@ -5092,12 +5010,8 @@
 
 LIBBORINGSSL_PKCS12_TEST_LIB_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(LIBBORINGSSL_PKCS12_TEST_LIB_SRC))))
 
-# boringssl needs an override to ensure that it does not include
-# system openssl headers regardless of other configuration
-# we do so here with a target specific variable assignment
-$(LIBBORINGSSL_PKCS12_TEST_LIB_OBJS): CFLAGS := -Ithird_party/boringssl/include $(CFLAGS) -Wno-sign-conversion -Wno-conversion -Wno-unused-value -fvisibility=hidden
-$(LIBBORINGSSL_PKCS12_TEST_LIB_OBJS): CXXFLAGS := -Ithird_party/boringssl/include $(CXXFLAGS) -fvisibility=hidden
-$(LIBBORINGSSL_PKCS12_TEST_LIB_OBJS): CPPFLAGS += -DOPENSSL_NO_ASM -D_GNU_SOURCE
+$(LIBBORINGSSL_PKCS12_TEST_LIB_OBJS): CPPFLAGS += -Ithird_party/boringssl/include -fvisibility=hidden -DOPENSSL_NO_ASM -D_GNU_SOURCE -DWIN32_LEAN_AND_MEAN -D_HAS_EXCEPTIONS=0 -DNOMINMAX
+$(LIBBORINGSSL_PKCS12_TEST_LIB_OBJS): CFLAGS += -Wno-sign-conversion -Wno-conversion -Wno-unused-value -Wno-unknown-pragmas -Wno-implicit-function-declaration -Wno-unused-variable -Wno-sign-compare
 
 ifeq ($(NO_PROTOBUF),true)
 
@@ -5108,11 +5022,11 @@
 
 else
 
-$(LIBDIR)/$(CONFIG)/libboringssl_pkcs12_test_lib.a: $(ZLIB_DEP) $(OPENSSL_DEP)  $(PROTOBUF_DEP) $(LIBBORINGSSL_PKCS12_TEST_LIB_OBJS)
+$(LIBDIR)/$(CONFIG)/libboringssl_pkcs12_test_lib.a: $(ZLIB_DEP)  $(PROTOBUF_DEP) $(LIBBORINGSSL_PKCS12_TEST_LIB_OBJS) 
 	$(E) "[AR]      Creating $@"
 	$(Q) mkdir -p `dirname $@`
 	$(Q) rm -f $(LIBDIR)/$(CONFIG)/libboringssl_pkcs12_test_lib.a
-	$(Q) $(AR) rcs $(LIBDIR)/$(CONFIG)/libboringssl_pkcs12_test_lib.a $(LIBBORINGSSL_PKCS12_TEST_LIB_OBJS)
+	$(Q) $(AR) $(LIBDIR)/$(CONFIG)/libboringssl_pkcs12_test_lib.a $(LIBBORINGSSL_PKCS12_TEST_LIB_OBJS) 
 ifeq ($(SYSTEM),Darwin)
 	$(Q) ranlib $(LIBDIR)/$(CONFIG)/libboringssl_pkcs12_test_lib.a
 endif
@@ -5133,12 +5047,8 @@
 
 LIBBORINGSSL_PKCS8_TEST_LIB_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(LIBBORINGSSL_PKCS8_TEST_LIB_SRC))))
 
-# boringssl needs an override to ensure that it does not include
-# system openssl headers regardless of other configuration
-# we do so here with a target specific variable assignment
-$(LIBBORINGSSL_PKCS8_TEST_LIB_OBJS): CFLAGS := -Ithird_party/boringssl/include $(CFLAGS) -Wno-sign-conversion -Wno-conversion -Wno-unused-value -fvisibility=hidden
-$(LIBBORINGSSL_PKCS8_TEST_LIB_OBJS): CXXFLAGS := -Ithird_party/boringssl/include $(CXXFLAGS) -fvisibility=hidden
-$(LIBBORINGSSL_PKCS8_TEST_LIB_OBJS): CPPFLAGS += -DOPENSSL_NO_ASM -D_GNU_SOURCE
+$(LIBBORINGSSL_PKCS8_TEST_LIB_OBJS): CPPFLAGS += -Ithird_party/boringssl/include -fvisibility=hidden -DOPENSSL_NO_ASM -D_GNU_SOURCE -DWIN32_LEAN_AND_MEAN -D_HAS_EXCEPTIONS=0 -DNOMINMAX
+$(LIBBORINGSSL_PKCS8_TEST_LIB_OBJS): CFLAGS += -Wno-sign-conversion -Wno-conversion -Wno-unused-value -Wno-unknown-pragmas -Wno-implicit-function-declaration -Wno-unused-variable -Wno-sign-compare
 
 ifeq ($(NO_PROTOBUF),true)
 
@@ -5149,11 +5059,11 @@
 
 else
 
-$(LIBDIR)/$(CONFIG)/libboringssl_pkcs8_test_lib.a: $(ZLIB_DEP) $(OPENSSL_DEP)  $(PROTOBUF_DEP) $(LIBBORINGSSL_PKCS8_TEST_LIB_OBJS)
+$(LIBDIR)/$(CONFIG)/libboringssl_pkcs8_test_lib.a: $(ZLIB_DEP)  $(PROTOBUF_DEP) $(LIBBORINGSSL_PKCS8_TEST_LIB_OBJS) 
 	$(E) "[AR]      Creating $@"
 	$(Q) mkdir -p `dirname $@`
 	$(Q) rm -f $(LIBDIR)/$(CONFIG)/libboringssl_pkcs8_test_lib.a
-	$(Q) $(AR) rcs $(LIBDIR)/$(CONFIG)/libboringssl_pkcs8_test_lib.a $(LIBBORINGSSL_PKCS8_TEST_LIB_OBJS)
+	$(Q) $(AR) $(LIBDIR)/$(CONFIG)/libboringssl_pkcs8_test_lib.a $(LIBBORINGSSL_PKCS8_TEST_LIB_OBJS) 
 ifeq ($(SYSTEM),Darwin)
 	$(Q) ranlib $(LIBDIR)/$(CONFIG)/libboringssl_pkcs8_test_lib.a
 endif
@@ -5174,12 +5084,8 @@
 
 LIBBORINGSSL_POLY1305_TEST_LIB_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(LIBBORINGSSL_POLY1305_TEST_LIB_SRC))))
 
-# boringssl needs an override to ensure that it does not include
-# system openssl headers regardless of other configuration
-# we do so here with a target specific variable assignment
-$(LIBBORINGSSL_POLY1305_TEST_LIB_OBJS): CFLAGS := -Ithird_party/boringssl/include $(CFLAGS) -Wno-sign-conversion -Wno-conversion -Wno-unused-value -fvisibility=hidden
-$(LIBBORINGSSL_POLY1305_TEST_LIB_OBJS): CXXFLAGS := -Ithird_party/boringssl/include $(CXXFLAGS) -fvisibility=hidden
-$(LIBBORINGSSL_POLY1305_TEST_LIB_OBJS): CPPFLAGS += -DOPENSSL_NO_ASM -D_GNU_SOURCE
+$(LIBBORINGSSL_POLY1305_TEST_LIB_OBJS): CPPFLAGS += -Ithird_party/boringssl/include -fvisibility=hidden -DOPENSSL_NO_ASM -D_GNU_SOURCE -DWIN32_LEAN_AND_MEAN -D_HAS_EXCEPTIONS=0 -DNOMINMAX
+$(LIBBORINGSSL_POLY1305_TEST_LIB_OBJS): CFLAGS += -Wno-sign-conversion -Wno-conversion -Wno-unused-value -Wno-unknown-pragmas -Wno-implicit-function-declaration -Wno-unused-variable -Wno-sign-compare
 
 ifeq ($(NO_PROTOBUF),true)
 
@@ -5190,11 +5096,11 @@
 
 else
 
-$(LIBDIR)/$(CONFIG)/libboringssl_poly1305_test_lib.a: $(ZLIB_DEP) $(OPENSSL_DEP)  $(PROTOBUF_DEP) $(LIBBORINGSSL_POLY1305_TEST_LIB_OBJS)
+$(LIBDIR)/$(CONFIG)/libboringssl_poly1305_test_lib.a: $(ZLIB_DEP)  $(PROTOBUF_DEP) $(LIBBORINGSSL_POLY1305_TEST_LIB_OBJS) 
 	$(E) "[AR]      Creating $@"
 	$(Q) mkdir -p `dirname $@`
 	$(Q) rm -f $(LIBDIR)/$(CONFIG)/libboringssl_poly1305_test_lib.a
-	$(Q) $(AR) rcs $(LIBDIR)/$(CONFIG)/libboringssl_poly1305_test_lib.a $(LIBBORINGSSL_POLY1305_TEST_LIB_OBJS)
+	$(Q) $(AR) $(LIBDIR)/$(CONFIG)/libboringssl_poly1305_test_lib.a $(LIBBORINGSSL_POLY1305_TEST_LIB_OBJS) 
 ifeq ($(SYSTEM),Darwin)
 	$(Q) ranlib $(LIBDIR)/$(CONFIG)/libboringssl_poly1305_test_lib.a
 endif
@@ -5215,18 +5121,14 @@
 
 LIBBORINGSSL_REFCOUNT_TEST_LIB_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(LIBBORINGSSL_REFCOUNT_TEST_LIB_SRC))))
 
-# boringssl needs an override to ensure that it does not include
-# system openssl headers regardless of other configuration
-# we do so here with a target specific variable assignment
-$(LIBBORINGSSL_REFCOUNT_TEST_LIB_OBJS): CFLAGS := -Ithird_party/boringssl/include $(CFLAGS) -Wno-sign-conversion -Wno-conversion -Wno-unused-value -fvisibility=hidden
-$(LIBBORINGSSL_REFCOUNT_TEST_LIB_OBJS): CXXFLAGS := -Ithird_party/boringssl/include $(CXXFLAGS) -fvisibility=hidden
-$(LIBBORINGSSL_REFCOUNT_TEST_LIB_OBJS): CPPFLAGS += -DOPENSSL_NO_ASM -D_GNU_SOURCE
+$(LIBBORINGSSL_REFCOUNT_TEST_LIB_OBJS): CPPFLAGS += -Ithird_party/boringssl/include -fvisibility=hidden -DOPENSSL_NO_ASM -D_GNU_SOURCE -DWIN32_LEAN_AND_MEAN -D_HAS_EXCEPTIONS=0 -DNOMINMAX
+$(LIBBORINGSSL_REFCOUNT_TEST_LIB_OBJS): CFLAGS += -Wno-sign-conversion -Wno-conversion -Wno-unused-value -Wno-unknown-pragmas -Wno-implicit-function-declaration -Wno-unused-variable -Wno-sign-compare
 
-$(LIBDIR)/$(CONFIG)/libboringssl_refcount_test_lib.a: $(ZLIB_DEP) $(OPENSSL_DEP)  $(LIBBORINGSSL_REFCOUNT_TEST_LIB_OBJS)
+$(LIBDIR)/$(CONFIG)/libboringssl_refcount_test_lib.a: $(ZLIB_DEP)  $(LIBBORINGSSL_REFCOUNT_TEST_LIB_OBJS) 
 	$(E) "[AR]      Creating $@"
 	$(Q) mkdir -p `dirname $@`
 	$(Q) rm -f $(LIBDIR)/$(CONFIG)/libboringssl_refcount_test_lib.a
-	$(Q) $(AR) rcs $(LIBDIR)/$(CONFIG)/libboringssl_refcount_test_lib.a $(LIBBORINGSSL_REFCOUNT_TEST_LIB_OBJS)
+	$(Q) $(AR) $(LIBDIR)/$(CONFIG)/libboringssl_refcount_test_lib.a $(LIBBORINGSSL_REFCOUNT_TEST_LIB_OBJS) 
 ifeq ($(SYSTEM),Darwin)
 	$(Q) ranlib $(LIBDIR)/$(CONFIG)/libboringssl_refcount_test_lib.a
 endif
@@ -5245,12 +5147,8 @@
 
 LIBBORINGSSL_RSA_TEST_LIB_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(LIBBORINGSSL_RSA_TEST_LIB_SRC))))
 
-# boringssl needs an override to ensure that it does not include
-# system openssl headers regardless of other configuration
-# we do so here with a target specific variable assignment
-$(LIBBORINGSSL_RSA_TEST_LIB_OBJS): CFLAGS := -Ithird_party/boringssl/include $(CFLAGS) -Wno-sign-conversion -Wno-conversion -Wno-unused-value -fvisibility=hidden
-$(LIBBORINGSSL_RSA_TEST_LIB_OBJS): CXXFLAGS := -Ithird_party/boringssl/include $(CXXFLAGS) -fvisibility=hidden
-$(LIBBORINGSSL_RSA_TEST_LIB_OBJS): CPPFLAGS += -DOPENSSL_NO_ASM -D_GNU_SOURCE
+$(LIBBORINGSSL_RSA_TEST_LIB_OBJS): CPPFLAGS += -Ithird_party/boringssl/include -fvisibility=hidden -DOPENSSL_NO_ASM -D_GNU_SOURCE -DWIN32_LEAN_AND_MEAN -D_HAS_EXCEPTIONS=0 -DNOMINMAX
+$(LIBBORINGSSL_RSA_TEST_LIB_OBJS): CFLAGS += -Wno-sign-conversion -Wno-conversion -Wno-unused-value -Wno-unknown-pragmas -Wno-implicit-function-declaration -Wno-unused-variable -Wno-sign-compare
 
 ifeq ($(NO_PROTOBUF),true)
 
@@ -5261,11 +5159,11 @@
 
 else
 
-$(LIBDIR)/$(CONFIG)/libboringssl_rsa_test_lib.a: $(ZLIB_DEP) $(OPENSSL_DEP)  $(PROTOBUF_DEP) $(LIBBORINGSSL_RSA_TEST_LIB_OBJS)
+$(LIBDIR)/$(CONFIG)/libboringssl_rsa_test_lib.a: $(ZLIB_DEP)  $(PROTOBUF_DEP) $(LIBBORINGSSL_RSA_TEST_LIB_OBJS) 
 	$(E) "[AR]      Creating $@"
 	$(Q) mkdir -p `dirname $@`
 	$(Q) rm -f $(LIBDIR)/$(CONFIG)/libboringssl_rsa_test_lib.a
-	$(Q) $(AR) rcs $(LIBDIR)/$(CONFIG)/libboringssl_rsa_test_lib.a $(LIBBORINGSSL_RSA_TEST_LIB_OBJS)
+	$(Q) $(AR) $(LIBDIR)/$(CONFIG)/libboringssl_rsa_test_lib.a $(LIBBORINGSSL_RSA_TEST_LIB_OBJS) 
 ifeq ($(SYSTEM),Darwin)
 	$(Q) ranlib $(LIBDIR)/$(CONFIG)/libboringssl_rsa_test_lib.a
 endif
@@ -5286,18 +5184,14 @@
 
 LIBBORINGSSL_THREAD_TEST_LIB_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(LIBBORINGSSL_THREAD_TEST_LIB_SRC))))
 
-# boringssl needs an override to ensure that it does not include
-# system openssl headers regardless of other configuration
-# we do so here with a target specific variable assignment
-$(LIBBORINGSSL_THREAD_TEST_LIB_OBJS): CFLAGS := -Ithird_party/boringssl/include $(CFLAGS) -Wno-sign-conversion -Wno-conversion -Wno-unused-value -fvisibility=hidden
-$(LIBBORINGSSL_THREAD_TEST_LIB_OBJS): CXXFLAGS := -Ithird_party/boringssl/include $(CXXFLAGS) -fvisibility=hidden
-$(LIBBORINGSSL_THREAD_TEST_LIB_OBJS): CPPFLAGS += -DOPENSSL_NO_ASM -D_GNU_SOURCE
+$(LIBBORINGSSL_THREAD_TEST_LIB_OBJS): CPPFLAGS += -Ithird_party/boringssl/include -fvisibility=hidden -DOPENSSL_NO_ASM -D_GNU_SOURCE -DWIN32_LEAN_AND_MEAN -D_HAS_EXCEPTIONS=0 -DNOMINMAX
+$(LIBBORINGSSL_THREAD_TEST_LIB_OBJS): CFLAGS += -Wno-sign-conversion -Wno-conversion -Wno-unused-value -Wno-unknown-pragmas -Wno-implicit-function-declaration -Wno-unused-variable -Wno-sign-compare
 
-$(LIBDIR)/$(CONFIG)/libboringssl_thread_test_lib.a: $(ZLIB_DEP) $(OPENSSL_DEP)  $(LIBBORINGSSL_THREAD_TEST_LIB_OBJS)
+$(LIBDIR)/$(CONFIG)/libboringssl_thread_test_lib.a: $(ZLIB_DEP)  $(LIBBORINGSSL_THREAD_TEST_LIB_OBJS) 
 	$(E) "[AR]      Creating $@"
 	$(Q) mkdir -p `dirname $@`
 	$(Q) rm -f $(LIBDIR)/$(CONFIG)/libboringssl_thread_test_lib.a
-	$(Q) $(AR) rcs $(LIBDIR)/$(CONFIG)/libboringssl_thread_test_lib.a $(LIBBORINGSSL_THREAD_TEST_LIB_OBJS)
+	$(Q) $(AR) $(LIBDIR)/$(CONFIG)/libboringssl_thread_test_lib.a $(LIBBORINGSSL_THREAD_TEST_LIB_OBJS) 
 ifeq ($(SYSTEM),Darwin)
 	$(Q) ranlib $(LIBDIR)/$(CONFIG)/libboringssl_thread_test_lib.a
 endif
@@ -5316,18 +5210,14 @@
 
 LIBBORINGSSL_PKCS7_TEST_LIB_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(LIBBORINGSSL_PKCS7_TEST_LIB_SRC))))
 
-# boringssl needs an override to ensure that it does not include
-# system openssl headers regardless of other configuration
-# we do so here with a target specific variable assignment
-$(LIBBORINGSSL_PKCS7_TEST_LIB_OBJS): CFLAGS := -Ithird_party/boringssl/include $(CFLAGS) -Wno-sign-conversion -Wno-conversion -Wno-unused-value -fvisibility=hidden
-$(LIBBORINGSSL_PKCS7_TEST_LIB_OBJS): CXXFLAGS := -Ithird_party/boringssl/include $(CXXFLAGS) -fvisibility=hidden
-$(LIBBORINGSSL_PKCS7_TEST_LIB_OBJS): CPPFLAGS += -DOPENSSL_NO_ASM -D_GNU_SOURCE
+$(LIBBORINGSSL_PKCS7_TEST_LIB_OBJS): CPPFLAGS += -Ithird_party/boringssl/include -fvisibility=hidden -DOPENSSL_NO_ASM -D_GNU_SOURCE -DWIN32_LEAN_AND_MEAN -D_HAS_EXCEPTIONS=0 -DNOMINMAX
+$(LIBBORINGSSL_PKCS7_TEST_LIB_OBJS): CFLAGS += -Wno-sign-conversion -Wno-conversion -Wno-unused-value -Wno-unknown-pragmas -Wno-implicit-function-declaration -Wno-unused-variable -Wno-sign-compare
 
-$(LIBDIR)/$(CONFIG)/libboringssl_pkcs7_test_lib.a: $(ZLIB_DEP) $(OPENSSL_DEP)  $(LIBBORINGSSL_PKCS7_TEST_LIB_OBJS)
+$(LIBDIR)/$(CONFIG)/libboringssl_pkcs7_test_lib.a: $(ZLIB_DEP)  $(LIBBORINGSSL_PKCS7_TEST_LIB_OBJS) 
 	$(E) "[AR]      Creating $@"
 	$(Q) mkdir -p `dirname $@`
 	$(Q) rm -f $(LIBDIR)/$(CONFIG)/libboringssl_pkcs7_test_lib.a
-	$(Q) $(AR) rcs $(LIBDIR)/$(CONFIG)/libboringssl_pkcs7_test_lib.a $(LIBBORINGSSL_PKCS7_TEST_LIB_OBJS)
+	$(Q) $(AR) $(LIBDIR)/$(CONFIG)/libboringssl_pkcs7_test_lib.a $(LIBBORINGSSL_PKCS7_TEST_LIB_OBJS) 
 ifeq ($(SYSTEM),Darwin)
 	$(Q) ranlib $(LIBDIR)/$(CONFIG)/libboringssl_pkcs7_test_lib.a
 endif
@@ -5346,18 +5236,14 @@
 
 LIBBORINGSSL_TAB_TEST_LIB_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(LIBBORINGSSL_TAB_TEST_LIB_SRC))))
 
-# boringssl needs an override to ensure that it does not include
-# system openssl headers regardless of other configuration
-# we do so here with a target specific variable assignment
-$(LIBBORINGSSL_TAB_TEST_LIB_OBJS): CFLAGS := -Ithird_party/boringssl/include $(CFLAGS) -Wno-sign-conversion -Wno-conversion -Wno-unused-value -fvisibility=hidden
-$(LIBBORINGSSL_TAB_TEST_LIB_OBJS): CXXFLAGS := -Ithird_party/boringssl/include $(CXXFLAGS) -fvisibility=hidden
-$(LIBBORINGSSL_TAB_TEST_LIB_OBJS): CPPFLAGS += -DOPENSSL_NO_ASM -D_GNU_SOURCE
+$(LIBBORINGSSL_TAB_TEST_LIB_OBJS): CPPFLAGS += -Ithird_party/boringssl/include -fvisibility=hidden -DOPENSSL_NO_ASM -D_GNU_SOURCE -DWIN32_LEAN_AND_MEAN -D_HAS_EXCEPTIONS=0 -DNOMINMAX
+$(LIBBORINGSSL_TAB_TEST_LIB_OBJS): CFLAGS += -Wno-sign-conversion -Wno-conversion -Wno-unused-value -Wno-unknown-pragmas -Wno-implicit-function-declaration -Wno-unused-variable -Wno-sign-compare
 
-$(LIBDIR)/$(CONFIG)/libboringssl_tab_test_lib.a: $(ZLIB_DEP) $(OPENSSL_DEP)  $(LIBBORINGSSL_TAB_TEST_LIB_OBJS)
+$(LIBDIR)/$(CONFIG)/libboringssl_tab_test_lib.a: $(ZLIB_DEP)  $(LIBBORINGSSL_TAB_TEST_LIB_OBJS) 
 	$(E) "[AR]      Creating $@"
 	$(Q) mkdir -p `dirname $@`
 	$(Q) rm -f $(LIBDIR)/$(CONFIG)/libboringssl_tab_test_lib.a
-	$(Q) $(AR) rcs $(LIBDIR)/$(CONFIG)/libboringssl_tab_test_lib.a $(LIBBORINGSSL_TAB_TEST_LIB_OBJS)
+	$(Q) $(AR) $(LIBDIR)/$(CONFIG)/libboringssl_tab_test_lib.a $(LIBBORINGSSL_TAB_TEST_LIB_OBJS) 
 ifeq ($(SYSTEM),Darwin)
 	$(Q) ranlib $(LIBDIR)/$(CONFIG)/libboringssl_tab_test_lib.a
 endif
@@ -5376,18 +5262,14 @@
 
 LIBBORINGSSL_V3NAME_TEST_LIB_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(LIBBORINGSSL_V3NAME_TEST_LIB_SRC))))
 
-# boringssl needs an override to ensure that it does not include
-# system openssl headers regardless of other configuration
-# we do so here with a target specific variable assignment
-$(LIBBORINGSSL_V3NAME_TEST_LIB_OBJS): CFLAGS := -Ithird_party/boringssl/include $(CFLAGS) -Wno-sign-conversion -Wno-conversion -Wno-unused-value -fvisibility=hidden
-$(LIBBORINGSSL_V3NAME_TEST_LIB_OBJS): CXXFLAGS := -Ithird_party/boringssl/include $(CXXFLAGS) -fvisibility=hidden
-$(LIBBORINGSSL_V3NAME_TEST_LIB_OBJS): CPPFLAGS += -DOPENSSL_NO_ASM -D_GNU_SOURCE
+$(LIBBORINGSSL_V3NAME_TEST_LIB_OBJS): CPPFLAGS += -Ithird_party/boringssl/include -fvisibility=hidden -DOPENSSL_NO_ASM -D_GNU_SOURCE -DWIN32_LEAN_AND_MEAN -D_HAS_EXCEPTIONS=0 -DNOMINMAX
+$(LIBBORINGSSL_V3NAME_TEST_LIB_OBJS): CFLAGS += -Wno-sign-conversion -Wno-conversion -Wno-unused-value -Wno-unknown-pragmas -Wno-implicit-function-declaration -Wno-unused-variable -Wno-sign-compare
 
-$(LIBDIR)/$(CONFIG)/libboringssl_v3name_test_lib.a: $(ZLIB_DEP) $(OPENSSL_DEP)  $(LIBBORINGSSL_V3NAME_TEST_LIB_OBJS)
+$(LIBDIR)/$(CONFIG)/libboringssl_v3name_test_lib.a: $(ZLIB_DEP)  $(LIBBORINGSSL_V3NAME_TEST_LIB_OBJS) 
 	$(E) "[AR]      Creating $@"
 	$(Q) mkdir -p `dirname $@`
 	$(Q) rm -f $(LIBDIR)/$(CONFIG)/libboringssl_v3name_test_lib.a
-	$(Q) $(AR) rcs $(LIBDIR)/$(CONFIG)/libboringssl_v3name_test_lib.a $(LIBBORINGSSL_V3NAME_TEST_LIB_OBJS)
+	$(Q) $(AR) $(LIBDIR)/$(CONFIG)/libboringssl_v3name_test_lib.a $(LIBBORINGSSL_V3NAME_TEST_LIB_OBJS) 
 ifeq ($(SYSTEM),Darwin)
 	$(Q) ranlib $(LIBDIR)/$(CONFIG)/libboringssl_v3name_test_lib.a
 endif
@@ -5406,18 +5288,14 @@
 
 LIBBORINGSSL_PQUEUE_TEST_LIB_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(LIBBORINGSSL_PQUEUE_TEST_LIB_SRC))))
 
-# boringssl needs an override to ensure that it does not include
-# system openssl headers regardless of other configuration
-# we do so here with a target specific variable assignment
-$(LIBBORINGSSL_PQUEUE_TEST_LIB_OBJS): CFLAGS := -Ithird_party/boringssl/include $(CFLAGS) -Wno-sign-conversion -Wno-conversion -Wno-unused-value -fvisibility=hidden
-$(LIBBORINGSSL_PQUEUE_TEST_LIB_OBJS): CXXFLAGS := -Ithird_party/boringssl/include $(CXXFLAGS) -fvisibility=hidden
-$(LIBBORINGSSL_PQUEUE_TEST_LIB_OBJS): CPPFLAGS += -DOPENSSL_NO_ASM -D_GNU_SOURCE
+$(LIBBORINGSSL_PQUEUE_TEST_LIB_OBJS): CPPFLAGS += -Ithird_party/boringssl/include -fvisibility=hidden -DOPENSSL_NO_ASM -D_GNU_SOURCE -DWIN32_LEAN_AND_MEAN -D_HAS_EXCEPTIONS=0 -DNOMINMAX
+$(LIBBORINGSSL_PQUEUE_TEST_LIB_OBJS): CFLAGS += -Wno-sign-conversion -Wno-conversion -Wno-unused-value -Wno-unknown-pragmas -Wno-implicit-function-declaration -Wno-unused-variable -Wno-sign-compare
 
-$(LIBDIR)/$(CONFIG)/libboringssl_pqueue_test_lib.a: $(ZLIB_DEP) $(OPENSSL_DEP)  $(LIBBORINGSSL_PQUEUE_TEST_LIB_OBJS)
+$(LIBDIR)/$(CONFIG)/libboringssl_pqueue_test_lib.a: $(ZLIB_DEP)  $(LIBBORINGSSL_PQUEUE_TEST_LIB_OBJS) 
 	$(E) "[AR]      Creating $@"
 	$(Q) mkdir -p `dirname $@`
 	$(Q) rm -f $(LIBDIR)/$(CONFIG)/libboringssl_pqueue_test_lib.a
-	$(Q) $(AR) rcs $(LIBDIR)/$(CONFIG)/libboringssl_pqueue_test_lib.a $(LIBBORINGSSL_PQUEUE_TEST_LIB_OBJS)
+	$(Q) $(AR) $(LIBDIR)/$(CONFIG)/libboringssl_pqueue_test_lib.a $(LIBBORINGSSL_PQUEUE_TEST_LIB_OBJS) 
 ifeq ($(SYSTEM),Darwin)
 	$(Q) ranlib $(LIBDIR)/$(CONFIG)/libboringssl_pqueue_test_lib.a
 endif
@@ -5436,12 +5314,8 @@
 
 LIBBORINGSSL_SSL_TEST_LIB_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(LIBBORINGSSL_SSL_TEST_LIB_SRC))))
 
-# boringssl needs an override to ensure that it does not include
-# system openssl headers regardless of other configuration
-# we do so here with a target specific variable assignment
-$(LIBBORINGSSL_SSL_TEST_LIB_OBJS): CFLAGS := -Ithird_party/boringssl/include $(CFLAGS) -Wno-sign-conversion -Wno-conversion -Wno-unused-value -fvisibility=hidden
-$(LIBBORINGSSL_SSL_TEST_LIB_OBJS): CXXFLAGS := -Ithird_party/boringssl/include $(CXXFLAGS) -fvisibility=hidden
-$(LIBBORINGSSL_SSL_TEST_LIB_OBJS): CPPFLAGS += -DOPENSSL_NO_ASM -D_GNU_SOURCE
+$(LIBBORINGSSL_SSL_TEST_LIB_OBJS): CPPFLAGS += -Ithird_party/boringssl/include -fvisibility=hidden -DOPENSSL_NO_ASM -D_GNU_SOURCE -DWIN32_LEAN_AND_MEAN -D_HAS_EXCEPTIONS=0 -DNOMINMAX
+$(LIBBORINGSSL_SSL_TEST_LIB_OBJS): CFLAGS += -Wno-sign-conversion -Wno-conversion -Wno-unused-value -Wno-unknown-pragmas -Wno-implicit-function-declaration -Wno-unused-variable -Wno-sign-compare
 
 ifeq ($(NO_PROTOBUF),true)
 
@@ -5452,11 +5326,11 @@
 
 else
 
-$(LIBDIR)/$(CONFIG)/libboringssl_ssl_test_lib.a: $(ZLIB_DEP) $(OPENSSL_DEP)  $(PROTOBUF_DEP) $(LIBBORINGSSL_SSL_TEST_LIB_OBJS)
+$(LIBDIR)/$(CONFIG)/libboringssl_ssl_test_lib.a: $(ZLIB_DEP)  $(PROTOBUF_DEP) $(LIBBORINGSSL_SSL_TEST_LIB_OBJS) 
 	$(E) "[AR]      Creating $@"
 	$(Q) mkdir -p `dirname $@`
 	$(Q) rm -f $(LIBDIR)/$(CONFIG)/libboringssl_ssl_test_lib.a
-	$(Q) $(AR) rcs $(LIBDIR)/$(CONFIG)/libboringssl_ssl_test_lib.a $(LIBBORINGSSL_SSL_TEST_LIB_OBJS)
+	$(Q) $(AR) $(LIBDIR)/$(CONFIG)/libboringssl_ssl_test_lib.a $(LIBBORINGSSL_SSL_TEST_LIB_OBJS) 
 ifeq ($(SYSTEM),Darwin)
 	$(Q) ranlib $(LIBDIR)/$(CONFIG)/libboringssl_ssl_test_lib.a
 endif
@@ -5491,13 +5365,13 @@
 
 LIBZ_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(LIBZ_SRC))))
 
-$(LIBZ_OBJS): CFLAGS := $(CFLAGS) -Wno-sign-conversion -Wno-conversion -Wno-unused-value -Wno-implicit-function-declaration $(W_NO_SHIFT_NEGATIVE_VALUE) -fvisibility=hidden
+$(LIBZ_OBJS): CFLAGS += -Wno-sign-conversion -Wno-conversion -Wno-unused-value -Wno-implicit-function-declaration $(W_NO_SHIFT_NEGATIVE_VALUE) -fvisibility=hidden
 
-$(LIBDIR)/$(CONFIG)/libz.a: $(ZLIB_DEP) $(OPENSSL_DEP)  $(LIBZ_OBJS)
+$(LIBDIR)/$(CONFIG)/libz.a:  $(LIBZ_OBJS) 
 	$(E) "[AR]      Creating $@"
 	$(Q) mkdir -p `dirname $@`
 	$(Q) rm -f $(LIBDIR)/$(CONFIG)/libz.a
-	$(Q) $(AR) rcs $(LIBDIR)/$(CONFIG)/libz.a $(LIBZ_OBJS)
+	$(Q) $(AR) $(LIBDIR)/$(CONFIG)/libz.a $(LIBZ_OBJS) 
 ifeq ($(SYSTEM),Darwin)
 	$(Q) ranlib $(LIBDIR)/$(CONFIG)/libz.a
 endif
@@ -5527,11 +5401,11 @@
 else
 
 
-$(LIBDIR)/$(CONFIG)/libbad_client_test.a: $(ZLIB_DEP) $(OPENSSL_DEP) $(LIBBAD_CLIENT_TEST_OBJS)
+$(LIBDIR)/$(CONFIG)/libbad_client_test.a: $(ZLIB_DEP) $(OPENSSL_DEP) $(LIBBAD_CLIENT_TEST_OBJS) 
 	$(E) "[AR]      Creating $@"
 	$(Q) mkdir -p `dirname $@`
 	$(Q) rm -f $(LIBDIR)/$(CONFIG)/libbad_client_test.a
-	$(Q) $(AR) rcs $(LIBDIR)/$(CONFIG)/libbad_client_test.a $(LIBBAD_CLIENT_TEST_OBJS)
+	$(Q) $(AR) $(LIBDIR)/$(CONFIG)/libbad_client_test.a $(LIBBAD_CLIENT_TEST_OBJS) 
 ifeq ($(SYSTEM),Darwin)
 	$(Q) ranlib $(LIBDIR)/$(CONFIG)/libbad_client_test.a
 endif
@@ -5565,11 +5439,11 @@
 else
 
 
-$(LIBDIR)/$(CONFIG)/libbad_ssl_test_server.a: $(ZLIB_DEP) $(OPENSSL_DEP) $(LIBBAD_SSL_TEST_SERVER_OBJS)
+$(LIBDIR)/$(CONFIG)/libbad_ssl_test_server.a: $(ZLIB_DEP) $(OPENSSL_DEP) $(LIBBAD_SSL_TEST_SERVER_OBJS) 
 	$(E) "[AR]      Creating $@"
 	$(Q) mkdir -p `dirname $@`
 	$(Q) rm -f $(LIBDIR)/$(CONFIG)/libbad_ssl_test_server.a
-	$(Q) $(AR) rcs $(LIBDIR)/$(CONFIG)/libbad_ssl_test_server.a $(LIBBAD_SSL_TEST_SERVER_OBJS)
+	$(Q) $(AR) $(LIBDIR)/$(CONFIG)/libbad_ssl_test_server.a $(LIBBAD_SSL_TEST_SERVER_OBJS) 
 ifeq ($(SYSTEM),Darwin)
 	$(Q) ranlib $(LIBDIR)/$(CONFIG)/libbad_ssl_test_server.a
 endif
@@ -5639,11 +5513,11 @@
 else
 
 
-$(LIBDIR)/$(CONFIG)/libend2end_tests.a: $(ZLIB_DEP) $(OPENSSL_DEP) $(LIBEND2END_TESTS_OBJS)
+$(LIBDIR)/$(CONFIG)/libend2end_tests.a: $(ZLIB_DEP) $(OPENSSL_DEP) $(LIBEND2END_TESTS_OBJS) 
 	$(E) "[AR]      Creating $@"
 	$(Q) mkdir -p `dirname $@`
 	$(Q) rm -f $(LIBDIR)/$(CONFIG)/libend2end_tests.a
-	$(Q) $(AR) rcs $(LIBDIR)/$(CONFIG)/libend2end_tests.a $(LIBEND2END_TESTS_OBJS)
+	$(Q) $(AR) $(LIBDIR)/$(CONFIG)/libend2end_tests.a $(LIBEND2END_TESTS_OBJS) 
 ifeq ($(SYSTEM),Darwin)
 	$(Q) ranlib $(LIBDIR)/$(CONFIG)/libend2end_tests.a
 endif
@@ -5702,11 +5576,11 @@
 LIBEND2END_NOSEC_TESTS_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(LIBEND2END_NOSEC_TESTS_SRC))))
 
 
-$(LIBDIR)/$(CONFIG)/libend2end_nosec_tests.a: $(ZLIB_DEP) $(OPENSSL_DEP)  $(LIBEND2END_NOSEC_TESTS_OBJS)
+$(LIBDIR)/$(CONFIG)/libend2end_nosec_tests.a: $(ZLIB_DEP)  $(LIBEND2END_NOSEC_TESTS_OBJS) 
 	$(E) "[AR]      Creating $@"
 	$(Q) mkdir -p `dirname $@`
 	$(Q) rm -f $(LIBDIR)/$(CONFIG)/libend2end_nosec_tests.a
-	$(Q) $(AR) rcs $(LIBDIR)/$(CONFIG)/libend2end_nosec_tests.a $(LIBEND2END_NOSEC_TESTS_OBJS)
+	$(Q) $(AR) $(LIBDIR)/$(CONFIG)/libend2end_nosec_tests.a $(LIBEND2END_NOSEC_TESTS_OBJS) 
 ifeq ($(SYSTEM),Darwin)
 	$(Q) ranlib $(LIBDIR)/$(CONFIG)/libend2end_nosec_tests.a
 endif
@@ -5738,11 +5612,11 @@
 else
 
 
-$(LIBDIR)/$(CONFIG)/libend2end_certs.a: $(ZLIB_DEP) $(OPENSSL_DEP) $(LIBEND2END_CERTS_OBJS)
+$(LIBDIR)/$(CONFIG)/libend2end_certs.a: $(ZLIB_DEP) $(OPENSSL_DEP) $(LIBEND2END_CERTS_OBJS) 
 	$(E) "[AR]      Creating $@"
 	$(Q) mkdir -p `dirname $@`
 	$(Q) rm -f $(LIBDIR)/$(CONFIG)/libend2end_certs.a
-	$(Q) $(AR) rcs $(LIBDIR)/$(CONFIG)/libend2end_certs.a $(LIBEND2END_CERTS_OBJS)
+	$(Q) $(AR) $(LIBDIR)/$(CONFIG)/libend2end_certs.a $(LIBEND2END_CERTS_OBJS) 
 ifeq ($(SYSTEM),Darwin)
 	$(Q) ranlib $(LIBDIR)/$(CONFIG)/libend2end_certs.a
 endif
@@ -5763,6 +5637,38 @@
 # All of the test targets, and protoc plugins
 
 
+ALARM_TEST_SRC = \
+    test/core/surface/alarm_test.c \
+
+ALARM_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(ALARM_TEST_SRC))))
+ifeq ($(NO_SECURE),true)
+
+# You can't build secure targets if you don't have OpenSSL.
+
+$(BINDIR)/$(CONFIG)/alarm_test: openssl_dep_error
+
+else
+
+
+
+$(BINDIR)/$(CONFIG)/alarm_test: $(ALARM_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
+	$(E) "[LD]      Linking $@"
+	$(Q) mkdir -p `dirname $@`
+	$(Q) $(LD) $(LDFLAGS) $(ALARM_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBS) $(LDLIBS_SECURE) -o $(BINDIR)/$(CONFIG)/alarm_test
+
+endif
+
+$(OBJDIR)/$(CONFIG)/test/core/surface/alarm_test.o:  $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
+
+deps_alarm_test: $(ALARM_TEST_OBJS:.o=.dep)
+
+ifneq ($(NO_SECURE),true)
+ifneq ($(NO_DEPS),true)
+-include $(ALARM_TEST_OBJS:.o=.dep)
+endif
+endif
+
+
 ALGORITHM_TEST_SRC = \
     test/core/compression/algorithm_test.c \
 
@@ -5873,14 +5779,14 @@
 
 
 
-$(BINDIR)/$(CONFIG)/bin_encoder_test: $(BIN_ENCODER_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
+$(BINDIR)/$(CONFIG)/bin_encoder_test: $(BIN_ENCODER_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a
 	$(E) "[LD]      Linking $@"
 	$(Q) mkdir -p `dirname $@`
-	$(Q) $(LD) $(LDFLAGS) $(BIN_ENCODER_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBS) $(LDLIBS_SECURE) -o $(BINDIR)/$(CONFIG)/bin_encoder_test
+	$(Q) $(LD) $(LDFLAGS) $(BIN_ENCODER_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LDLIBS) $(LDLIBS_SECURE) -o $(BINDIR)/$(CONFIG)/bin_encoder_test
 
 endif
 
-$(OBJDIR)/$(CONFIG)/test/core/transport/chttp2/bin_encoder_test.o:  $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
+$(OBJDIR)/$(CONFIG)/test/core/transport/chttp2/bin_encoder_test.o:  $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a
 
 deps_bin_encoder_test: $(BIN_ENCODER_TEST_OBJS:.o=.dep)
 
@@ -5891,6 +5797,38 @@
 endif
 
 
+CENSUS_CONTEXT_TEST_SRC = \
+    test/core/census/context_test.c \
+
+CENSUS_CONTEXT_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(CENSUS_CONTEXT_TEST_SRC))))
+ifeq ($(NO_SECURE),true)
+
+# You can't build secure targets if you don't have OpenSSL.
+
+$(BINDIR)/$(CONFIG)/census_context_test: openssl_dep_error
+
+else
+
+
+
+$(BINDIR)/$(CONFIG)/census_context_test: $(CENSUS_CONTEXT_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
+	$(E) "[LD]      Linking $@"
+	$(Q) mkdir -p `dirname $@`
+	$(Q) $(LD) $(LDFLAGS) $(CENSUS_CONTEXT_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBS) $(LDLIBS_SECURE) -o $(BINDIR)/$(CONFIG)/census_context_test
+
+endif
+
+$(OBJDIR)/$(CONFIG)/test/core/census/context_test.o:  $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
+
+deps_census_context_test: $(CENSUS_CONTEXT_TEST_OBJS:.o=.dep)
+
+ifneq ($(NO_SECURE),true)
+ifneq ($(NO_DEPS),true)
+-include $(CENSUS_CONTEXT_TEST_OBJS:.o=.dep)
+endif
+endif
+
+
 CHANNEL_CREATE_TEST_SRC = \
     test/core/surface/channel_create_test.c \
 
@@ -8355,38 +8293,6 @@
 endif
 
 
-TAG_SET_TEST_SRC = \
-    test/core/census/tag_set_test.c \
-
-TAG_SET_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(TAG_SET_TEST_SRC))))
-ifeq ($(NO_SECURE),true)
-
-# You can't build secure targets if you don't have OpenSSL.
-
-$(BINDIR)/$(CONFIG)/tag_set_test: openssl_dep_error
-
-else
-
-
-
-$(BINDIR)/$(CONFIG)/tag_set_test: $(TAG_SET_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
-	$(E) "[LD]      Linking $@"
-	$(Q) mkdir -p `dirname $@`
-	$(Q) $(LD) $(LDFLAGS) $(TAG_SET_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBS) $(LDLIBS_SECURE) -o $(BINDIR)/$(CONFIG)/tag_set_test
-
-endif
-
-$(OBJDIR)/$(CONFIG)/test/core/census/tag_set_test.o:  $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
-
-deps_tag_set_test: $(TAG_SET_TEST_OBJS:.o=.dep)
-
-ifneq ($(NO_SECURE),true)
-ifneq ($(NO_DEPS),true)
--include $(TAG_SET_TEST_OBJS:.o=.dep)
-endif
-endif
-
-
 TCP_CLIENT_POSIX_TEST_SRC = \
     test/core/iomgr/tcp_client_posix_test.c \
 
@@ -8835,6 +8741,49 @@
 endif
 
 
+ALARM_CPP_TEST_SRC = \
+    test/cpp/common/alarm_cpp_test.cc \
+
+ALARM_CPP_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(ALARM_CPP_TEST_SRC))))
+ifeq ($(NO_SECURE),true)
+
+# You can't build secure targets if you don't have OpenSSL.
+
+$(BINDIR)/$(CONFIG)/alarm_cpp_test: openssl_dep_error
+
+else
+
+
+
+
+ifeq ($(NO_PROTOBUF),true)
+
+# You can't build the protoc plugins or protobuf-enabled targets if you don't have protobuf 3.0.0+.
+
+$(BINDIR)/$(CONFIG)/alarm_cpp_test: protobuf_dep_error
+
+else
+
+$(BINDIR)/$(CONFIG)/alarm_cpp_test: $(PROTOBUF_DEP) $(ALARM_CPP_TEST_OBJS) $(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) $(ALARM_CPP_TEST_OBJS) $(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)/alarm_cpp_test
+
+endif
+
+endif
+
+$(OBJDIR)/$(CONFIG)/test/cpp/common/alarm_cpp_test.o:  $(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_alarm_cpp_test: $(ALARM_CPP_TEST_OBJS:.o=.dep)
+
+ifneq ($(NO_SECURE),true)
+ifneq ($(NO_DEPS),true)
+-include $(ALARM_CPP_TEST_OBJS:.o=.dep)
+endif
+endif
+
+
 ASYNC_END2END_TEST_SRC = \
     test/cpp/end2end/async_end2end_test.cc \
 
@@ -9721,6 +9670,49 @@
 endif
 
 
+HYBRID_END2END_TEST_SRC = \
+    test/cpp/end2end/hybrid_end2end_test.cc \
+
+HYBRID_END2END_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(HYBRID_END2END_TEST_SRC))))
+ifeq ($(NO_SECURE),true)
+
+# You can't build secure targets if you don't have OpenSSL.
+
+$(BINDIR)/$(CONFIG)/hybrid_end2end_test: openssl_dep_error
+
+else
+
+
+
+
+ifeq ($(NO_PROTOBUF),true)
+
+# You can't build the protoc plugins or protobuf-enabled targets if you don't have protobuf 3.0.0+.
+
+$(BINDIR)/$(CONFIG)/hybrid_end2end_test: protobuf_dep_error
+
+else
+
+$(BINDIR)/$(CONFIG)/hybrid_end2end_test: $(PROTOBUF_DEP) $(HYBRID_END2END_TEST_OBJS) $(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) $(HYBRID_END2END_TEST_OBJS) $(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)/hybrid_end2end_test
+
+endif
+
+endif
+
+$(OBJDIR)/$(CONFIG)/test/cpp/end2end/hybrid_end2end_test.o:  $(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_hybrid_end2end_test: $(HYBRID_END2END_TEST_OBJS:.o=.dep)
+
+ifneq ($(NO_SECURE),true)
+ifneq ($(NO_DEPS),true)
+-include $(HYBRID_END2END_TEST_OBJS:.o=.dep)
+endif
+endif
+
+
 ifeq ($(NO_SECURE),true)
 
 # You can't build secure targets if you don't have OpenSSL.
@@ -10807,7 +10799,7 @@
 $(OBJDIR)/$(CONFIG)/test/core/surface/public_headers_must_be_c89.o : test/core/surface/public_headers_must_be_c89.c
 	$(E) "[C]       Compiling $<"
 	$(Q) mkdir -p `dirname $@`
-	$(Q) $(CC) $(CFLAGS) $(CPPFLAGS) -std=c89 -pedantic -MMD -MF $(addsuffix .dep, $(basename $@)) -c -o $@ $<
+	$(Q) $(CC) $(CPPFLAGS) $(CFLAGS) -std=c89 -pedantic -MMD -MF $(addsuffix .dep, $(basename $@)) -c -o $@ $<
 
 deps_public_headers_must_be_c89: $(PUBLIC_HEADERS_MUST_BE_C89_OBJS:.o=.dep)
 
@@ -12960,6 +12952,7 @@
 test/core/security/oauth2_utils.c: $(OPENSSL_DEP)
 test/core/util/reconnect_server.c: $(OPENSSL_DEP)
 test/core/util/test_tcp_server.c: $(OPENSSL_DEP)
+test/cpp/end2end/test_service_impl.cc: $(OPENSSL_DEP)
 test/cpp/interop/client.cc: $(OPENSSL_DEP)
 test/cpp/interop/client_helper.cc: $(OPENSSL_DEP)
 test/cpp/interop/interop_client.cc: $(OPENSSL_DEP)
@@ -12968,6 +12961,7 @@
 test/cpp/qps/client_async.cc: $(OPENSSL_DEP)
 test/cpp/qps/client_sync.cc: $(OPENSSL_DEP)
 test/cpp/qps/driver.cc: $(OPENSSL_DEP)
+test/cpp/qps/limit_cores.cc: $(OPENSSL_DEP)
 test/cpp/qps/perf_db_client.cc: $(OPENSSL_DEP)
 test/cpp/qps/qps_worker.cc: $(OPENSSL_DEP)
 test/cpp/qps/report.cc: $(OPENSSL_DEP)
@@ -12975,6 +12969,7 @@
 test/cpp/qps/server_sync.cc: $(OPENSSL_DEP)
 test/cpp/qps/timer.cc: $(OPENSSL_DEP)
 test/cpp/util/benchmark_config.cc: $(OPENSSL_DEP)
+test/cpp/util/byte_buffer_proto_helper.cc: $(OPENSSL_DEP)
 test/cpp/util/cli_call.cc: $(OPENSSL_DEP)
 test/cpp/util/create_test_channel.cc: $(OPENSSL_DEP)
 test/cpp/util/string_ref_helper.cc: $(OPENSSL_DEP)
diff --git a/PYTHON-MANIFEST.in b/PYTHON-MANIFEST.in
index 2f5700d..3c46d61 100644
--- a/PYTHON-MANIFEST.in
+++ b/PYTHON-MANIFEST.in
@@ -5,6 +5,7 @@
 graft third_party/boringssl
 graft third_party/zlib
 include src/python/grpcio/commands.py
+include src/python/grpcio/grpc_version.py
 include src/python/grpcio/grpc_core_dependencies.py
 include src/python/grpcio/support.py
 include src/python/grpcio/README.rst
diff --git a/Rakefile b/Rakefile
index 079df67..f208a24 100755
--- a/Rakefile
+++ b/Rakefile
@@ -3,6 +3,9 @@
 require 'rspec/core/rake_task'
 require 'rubocop/rake_task'
 require 'bundler/gem_tasks'
+require 'fileutils'
+
+load 'tools/distrib/docker_for_windows.rb'
 
 # Add rubocop style checking tasks
 RuboCop::RakeTask.new(:rubocop) do |task|
@@ -10,11 +13,29 @@
   task.patterns = ['src/ruby/{lib,spec}/**/*.rb']
 end
 
+spec = Gem::Specification.load('grpc.gemspec')
+
+Gem::PackageTask.new(spec) do |pkg|
+end
+
 # Add the extension compiler task
-Rake::ExtensionTask.new 'grpc' do |ext|
+Rake::ExtensionTask.new('grpc_c', spec) do |ext|
   ext.source_pattern = '**/*.{c,h}'
   ext.ext_dir = File.join('src', 'ruby', 'ext', 'grpc')
   ext.lib_dir = File.join('src', 'ruby', 'lib', 'grpc')
+  ext.cross_compile = true
+  ext.cross_platform = [
+    'x86-mingw32', 'x64-mingw32',
+    'x86_64-linux', 'x86-linux',
+    'universal-darwin'
+  ]
+  ext.cross_compiling do |spec|
+    spec.files = %w( etc/roots.pem grpc_c.32.ruby grpc_c.64.ruby )
+    spec.files += Dir.glob('src/ruby/bin/**/*')
+    spec.files += Dir.glob('src/ruby/ext/**/*')
+    spec.files += Dir.glob('src/ruby/lib/**/*')
+    spec.files += Dir.glob('src/ruby/pb/**/*')
+  end
 end
 
 # Define the test suites
@@ -51,6 +72,44 @@
   end
 end
 
+desc 'Build the Windows gRPC DLLs for Ruby'
+task 'dlls' do
+  grpc_config = ENV['GRPC_CONFIG'] || 'opt'
+  verbose = ENV['V'] || '0'
+
+  env = 'CPPFLAGS="-D_WIN32_WINNT=0x600 -DUNICODE -D_UNICODE" '
+  env += 'LDFLAGS=-static '
+  env += 'SYSTEM=MINGW32 '
+  env += 'EMBED_ZLIB=true '
+  env += 'BUILDDIR=/tmp '
+  env += "V=#{verbose} "
+  out = '/tmp/libs/opt/grpc-0.dll'
+
+  w64 = { cross: 'x86_64-w64-mingw32', out: 'grpc_c.64.ruby' }
+  w32 = { cross: 'i686-w64-mingw32', out: 'grpc_c.32.ruby' }
+
+  [ w64, w32 ].each do |opt|
+    env_comp = "CC=#{opt[:cross]}-gcc "
+    env_comp += "LD=#{opt[:cross]}-gcc "
+    docker_for_windows "#{env} #{env_comp} make -j #{out} && #{opt[:cross]}-strip -x -S #{out} && cp #{out} #{opt[:out]}"
+  end
+
+end
+
+desc 'Build the native gem file under rake_compiler_dock'
+task 'gem:native' do
+  verbose = ENV['V'] || '0'
+
+  if RUBY_PLATFORM =~ /darwin/
+    FileUtils.touch 'grpc_c.32.ruby'
+    FileUtils.touch 'grpc_c.64.ruby'
+    system "rake cross native gem RUBY_CC_VERSION=2.3.0:2.2.2:2.1.5:2.0.0 V=#{verbose}"
+  else
+    Rake::Task['dlls'].execute
+    docker_for_windows "bundle && rake cross native gem RUBY_CC_VERSION=2.3.0:2.2.2:2.1.5:2.0.0 V=#{verbose}"
+  end
+end
+
 # Define dependencies between the suites.
 task 'suite:wrapper' => [:compile, :rubocop]
 task 'suite:idiomatic' => 'suite:wrapper'
diff --git a/binding.gyp b/binding.gyp
index b1c0214..3659bfc 100644
--- a/binding.gyp
+++ b/binding.gyp
@@ -37,29 +37,49 @@
 # Some of this file is built with the help of
 # https://n8.io/converting-a-c-library-to-gyp/
 {
-  'variables': {
-    'config': '<!(echo $CONFIG)'
-  },
-  # TODO: Finish windows support
   'target_defaults': {
-      # Empirically, Node only exports ALPN symbols if its major version is >0.
-      # io.js always reports versions >0 and always exports ALPN symbols.
-      # Therefore, Node's major version will be truthy if and only if it
-      # supports ALPN. The output of "node -v" is v[major].[minor].[patch],
-      # like "v4.1.1" in a recent version. We use cut to split by period and
-      # take the first field (resulting in "v[major]"), then use cut again
-      # to take all but the first character, removing the "v".
-    'defines': [
-      'TSI_OPENSSL_ALPN_SUPPORT=<!(node --version | cut -d. -f1 | cut -c2-)'
-    ],
     'include_dirs': [
       '.',
       'include'
     ],
     'conditions': [
       ['OS == "win"', {
-        "include_dirs": [ "third_party/boringssl/include" ]
-      }, {
+        "include_dirs": [
+          "third_party/boringssl/include",
+          "third_party/zlib"
+        ],
+        "defines": [
+          '_WIN32_WINNT=0x0600',
+          'WIN32_LEAN_AND_MEAN',
+          '_HAS_EXCEPTIONS=0',
+          'UNICODE',
+          '_UNICODE',
+          'NOMINMAX',
+          'OPENSSL_NO_ASM'
+        ],
+        "msvs_settings": {
+          'VCCLCompilerTool': {
+            'RuntimeLibrary': 1, # static debug
+          }
+        },
+        "libraries": [
+          "ws2_32"
+        ]
+      }, { # OS != "win"
+        'variables': {
+          'config': '<!(echo $CONFIG)',
+          # The output of "node --version" is "v[version]". We use cut to
+          # remove the first character.
+          'target%': '<!(node --version | cut -c2-)'
+        },
+          # Empirically, Node only exports ALPN symbols if its major version is >0.
+          # io.js always reports versions >0 and always exports ALPN symbols.
+          # Therefore, Node's major version will be truthy if and only if it
+          # supports ALPN. The target is "[major].[minor].[patch]". We split by
+          # periods and take the first field to get the major version.
+        'defines': [
+          'TSI_OPENSSL_ALPN_SUPPORT=<!(echo <(target) | cut -d. -f1)'
+        ],
         'include_dirs': [
           '<(node_root_dir)/deps/openssl/openssl/include',
           '<(node_root_dir)/deps/zlib'
@@ -93,6 +113,29 @@
   'conditions': [
     ['OS == "win"', {
       'targets': [
+        {
+          # IMPORTANT WINDOWS BUILD INFORMATION
+          # This library does not build on Windows without modifying the Node
+          # development packages that node-gyp downloads in order to build.
+          # Due to https://github.com/nodejs/node/issues/4932, the headers for
+          # BoringSSL conflict with the OpenSSL headers included by default
+          # when including the Node headers. The remedy for this is to remove
+          # the OpenSSL headers, from the downloaded Node development package,
+          # which is typically located in `.node-gyp` in your home directory.
+          'target_name': 'WINDOWS_BUILD_WARNING',
+          'actions': [
+            {
+              'action_name': 'WINDOWS_BUILD_WARNING',
+              'inputs': [
+                'package.json'
+              ],
+              'outputs': [
+                'ignore_this_part'
+              ],
+              'action': ['echo', 'IMPORTANT: Due to https://github.com/nodejs/node/issues/4932, to build this library on Windows, you must first remove <(node_root_dir)/include/node/openssl/']
+            }
+          ]
+        },
         # Only want to compile BoringSSL and zlib under Windows
         {
           'cflags': [
@@ -400,8 +443,7 @@
             'third_party/boringssl/ssl/t1_enc.c',
             'third_party/boringssl/ssl/t1_lib.c',
             'third_party/boringssl/ssl/tls_record.c',
-          ],
-          "include_dirs": [ "third_party/boringssl/include" ]
+          ]
         },
         {
           'cflags': [
@@ -430,8 +472,7 @@
             'third_party/zlib/trees.c',
             'third_party/zlib/uncompr.c',
             'third_party/zlib/zutil.c',
-          ],
-          "include_dirs": [ "third_party/boringssl/include" ]
+          ]
         },
       ]
     }]
@@ -479,6 +520,7 @@
         'src/core/support/string_posix.c',
         'src/core/support/string_win32.c',
         'src/core/support/subprocess_posix.c',
+        'src/core/support/subprocess_windows.c',
         'src/core/support/sync.c',
         'src/core/support/sync_posix.c',
         'src/core/support/sync_win32.c',
@@ -490,6 +532,7 @@
         'src/core/support/time_precise.c',
         'src/core/support/time_win32.c',
         'src/core/support/tls_pthread.c',
+        'src/core/support/wrap_memcpy.c',
       ],
       "conditions": [
         ['OS == "mac"', {
@@ -611,6 +654,7 @@
         'src/core/json/json_reader.c',
         'src/core/json/json_string.c',
         'src/core/json/json_writer.c',
+        'src/core/surface/alarm.c',
         'src/core/surface/api_trace.c',
         'src/core/surface/byte_buffer.c',
         'src/core/surface/byte_buffer_reader.c',
@@ -662,7 +706,7 @@
         'src/core/census/context.c',
         'src/core/census/initialize.c',
         'src/core/census/operation.c',
-        'src/core/census/tag_set.c',
+        'src/core/census/placeholders.c',
         'src/core/census/tracing.c',
       ],
       "conditions": [
@@ -694,7 +738,8 @@
           'xcode_settings': {
             'MACOSX_DEPLOYMENT_TARGET': '10.9',
             'OTHER_CFLAGS': [
-              '-stdlib=libc++'
+              '-stdlib=libc++',
+              '-std=c++11'
             ]
           }
         }],
@@ -703,6 +748,11 @@
             "boringssl",
             "z",
           ]
+        }],
+        ['OS=="linux"', {
+          'ldflags': [
+            '-Wl,-wrap,memcpy'
+          ]
         }]
       ],
       "target_name": "grpc_node",
diff --git a/build.yaml b/build.yaml
index 6cb861d..7f33ef3 100644
--- a/build.yaml
+++ b/build.yaml
@@ -2,28 +2,129 @@
 '#2': It is used among other things to generate all of our project files.
 '#3': Please refer to the templates directory for more information.
 settings:
-  '#': The public version number of the library.
-  version:
-    major: 0
-    minor: 13
-    micro: 0
-    build: 0
+  '#1': The public version number of the library.
+  '#2': Master always has a "-dev" suffix
+  '#3': Use "-preN" suffixes to identify pre-release versions
+  '#4': Per-language overrides are possible with (eg) ruby_version tag here
+  '#5': See the expand_version.py for all the quirks here
+  version: 0.14.0-dev
 filegroups:
 - name: census
   public_headers:
   - include/grpc/census.h
   headers:
   - src/core/census/aggregation.h
-  - src/core/census/context.h
   - src/core/census/rpc_metric_id.h
   src:
   - src/core/census/context.c
   - src/core/census/initialize.c
   - src/core/census/operation.c
-  - src/core/census/tag_set.c
+  - src/core/census/placeholders.c
   - src/core/census/tracing.c
+- name: gpr
+  public_headers:
+  - include/grpc/support/alloc.h
+  - include/grpc/support/atm.h
+  - include/grpc/support/atm_gcc_atomic.h
+  - include/grpc/support/atm_gcc_sync.h
+  - include/grpc/support/atm_win32.h
+  - include/grpc/support/avl.h
+  - include/grpc/support/cmdline.h
+  - include/grpc/support/cpu.h
+  - include/grpc/support/histogram.h
+  - include/grpc/support/host_port.h
+  - include/grpc/support/log.h
+  - include/grpc/support/log_win32.h
+  - include/grpc/support/port_platform.h
+  - include/grpc/support/slice.h
+  - include/grpc/support/slice_buffer.h
+  - include/grpc/support/string_util.h
+  - include/grpc/support/subprocess.h
+  - include/grpc/support/sync.h
+  - include/grpc/support/sync_generic.h
+  - include/grpc/support/sync_posix.h
+  - include/grpc/support/sync_win32.h
+  - include/grpc/support/thd.h
+  - include/grpc/support/time.h
+  - include/grpc/support/tls.h
+  - include/grpc/support/tls_gcc.h
+  - include/grpc/support/tls_msvc.h
+  - include/grpc/support/tls_pthread.h
+  - include/grpc/support/useful.h
+  headers:
+  - src/core/profiling/timers.h
+  - src/core/support/block_annotate.h
+  - src/core/support/env.h
+  - src/core/support/file.h
+  - src/core/support/murmur_hash.h
+  - src/core/support/stack_lockfree.h
+  - src/core/support/string.h
+  - src/core/support/string_win32.h
+  - src/core/support/thd_internal.h
+  - src/core/support/time_precise.h
+  src:
+  - src/core/profiling/basic_timers.c
+  - src/core/profiling/stap_timers.c
+  - src/core/support/alloc.c
+  - src/core/support/avl.c
+  - src/core/support/cmdline.c
+  - src/core/support/cpu_iphone.c
+  - src/core/support/cpu_linux.c
+  - src/core/support/cpu_posix.c
+  - src/core/support/cpu_windows.c
+  - src/core/support/env_linux.c
+  - src/core/support/env_posix.c
+  - src/core/support/env_win32.c
+  - src/core/support/file.c
+  - src/core/support/file_posix.c
+  - src/core/support/file_win32.c
+  - src/core/support/histogram.c
+  - src/core/support/host_port.c
+  - src/core/support/log.c
+  - src/core/support/log_android.c
+  - src/core/support/log_linux.c
+  - src/core/support/log_posix.c
+  - src/core/support/log_win32.c
+  - src/core/support/murmur_hash.c
+  - src/core/support/slice.c
+  - src/core/support/slice_buffer.c
+  - src/core/support/stack_lockfree.c
+  - src/core/support/string.c
+  - src/core/support/string_posix.c
+  - src/core/support/string_win32.c
+  - src/core/support/subprocess_posix.c
+  - src/core/support/subprocess_windows.c
+  - src/core/support/sync.c
+  - src/core/support/sync_posix.c
+  - src/core/support/sync_win32.c
+  - src/core/support/thd.c
+  - src/core/support/thd_posix.c
+  - src/core/support/thd_win32.c
+  - src/core/support/time.c
+  - src/core/support/time_posix.c
+  - src/core/support/time_precise.c
+  - src/core/support/time_win32.c
+  - src/core/support/tls_pthread.c
+  - src/core/support/wrap_memcpy.c
+- name: gpr_codegen
+  public_headers:
+  - include/grpc/impl/codegen/alloc.h
+  - include/grpc/impl/codegen/atm.h
+  - include/grpc/impl/codegen/atm_gcc_atomic.h
+  - include/grpc/impl/codegen/atm_gcc_sync.h
+  - include/grpc/impl/codegen/atm_win32.h
+  - include/grpc/impl/codegen/log.h
+  - include/grpc/impl/codegen/port_platform.h
+  - include/grpc/impl/codegen/slice.h
+  - include/grpc/impl/codegen/slice_buffer.h
+  - include/grpc/impl/codegen/sync.h
+  - include/grpc/impl/codegen/sync_generic.h
+  - include/grpc/impl/codegen/sync_posix.h
+  - include/grpc/impl/codegen/sync_win32.h
+  - include/grpc/impl/codegen/time.h
 - name: grpc++_base
   public_headers:
+  - include/grpc++/alarm.h
   - include/grpc++/channel.h
   - include/grpc++/client_context.h
   - include/grpc++/completion_queue.h
@@ -34,6 +135,7 @@
   - include/grpc++/impl/call.h
   - include/grpc++/impl/client_unary_call.h
   - include/grpc++/impl/grpc_library.h
+  - include/grpc++/impl/method_handler_impl.h
   - include/grpc++/impl/proto_utils.h
   - include/grpc++/impl/rpc_method.h
   - include/grpc++/impl/rpc_service_method.h
@@ -80,6 +182,7 @@
   - src/cpp/client/credentials.cc
   - src/cpp/client/generic_stub.cc
   - src/cpp/client/insecure_credentials.cc
+  - src/cpp/common/alarm.cc
   - src/cpp/common/call.cc
   - src/cpp/common/channel_arguments.cc
   - src/cpp/common/completion_queue.cc
@@ -99,6 +202,40 @@
   - src/cpp/util/status.cc
   - src/cpp/util/string_ref.cc
   - src/cpp/util/time.cc
+- name: grpc++_codegen
+  public_headers:
+  - include/grpc++/impl/codegen/async_stream.h
+  - include/grpc++/impl/codegen/async_unary_call.h
+  - include/grpc++/impl/codegen/call.h
+  - include/grpc++/impl/codegen/call_hook.h
+  - include/grpc++/impl/codegen/channel_interface.h
+  - include/grpc++/impl/codegen/client_context.h
+  - include/grpc++/impl/codegen/client_unary_call.h
+  - include/grpc++/impl/codegen/completion_queue.h
+  - include/grpc++/impl/codegen/completion_queue_tag.h
+  - include/grpc++/impl/codegen/config.h
+  - include/grpc++/impl/codegen/config_protobuf.h
+  - include/grpc++/impl/codegen/grpc_library.h
+  - include/grpc++/impl/codegen/method_handler_impl.h
+  - include/grpc++/impl/codegen/proto_utils.h
+  - include/grpc++/impl/codegen/rpc_method.h
+  - include/grpc++/impl/codegen/rpc_service_method.h
+  - include/grpc++/impl/codegen/security/auth_context.h
+  - include/grpc++/impl/codegen/serialization_traits.h
+  - include/grpc++/impl/codegen/server_context.h
+  - include/grpc++/impl/codegen/server_interface.h
+  - include/grpc++/impl/codegen/service_type.h
+  - include/grpc++/impl/codegen/status.h
+  - include/grpc++/impl/codegen/status_code_enum.h
+  - include/grpc++/impl/codegen/string_ref.h
+  - include/grpc++/impl/codegen/stub_options.h
+  - include/grpc++/impl/codegen/sync.h
+  - include/grpc++/impl/codegen/sync_cxx11.h
+  - include/grpc++/impl/codegen/sync_no_cxx11.h
+  - include/grpc++/impl/codegen/sync_stream.h
+  - include/grpc++/impl/codegen/time.h
+  src:
+  - src/cpp/codegen/grpc_library.cc
 - name: grpc_base
   public_headers:
   - include/grpc/byte_buffer.h
@@ -299,6 +436,7 @@
   - src/core/json/json_reader.c
   - src/core/json/json_string.c
   - src/core/json/json_writer.c
+  - src/core/surface/alarm.c
   - src/core/surface/api_trace.c
   - src/core/surface/byte_buffer.c
   - src/core/surface/byte_buffer_reader.c
@@ -347,6 +485,14 @@
   - src/core/transport/static_metadata.c
   - src/core/transport/transport.c
   - src/core/transport/transport_op_string.c
+- name: grpc_codegen
+  public_headers:
+  - include/grpc/impl/codegen/byte_buffer.h
+  - include/grpc/impl/codegen/compression_types.h
+  - include/grpc/impl/codegen/connectivity_state.h
+  - include/grpc/impl/codegen/grpc_types.h
+  - include/grpc/impl/codegen/propagation_bits.h
+  - include/grpc/impl/codegen/status.h
 - name: grpc_test_util_base
   headers:
   - test/core/end2end/cq_verifier.h
@@ -369,88 +515,9 @@
 - name: gpr
   build: all
   language: c
-  public_headers:
-  - include/grpc/support/alloc.h
-  - include/grpc/support/atm.h
-  - include/grpc/support/atm_gcc_atomic.h
-  - include/grpc/support/atm_gcc_sync.h
-  - include/grpc/support/atm_win32.h
-  - include/grpc/support/avl.h
-  - include/grpc/support/cmdline.h
-  - include/grpc/support/cpu.h
-  - include/grpc/support/histogram.h
-  - include/grpc/support/host_port.h
-  - include/grpc/support/log.h
-  - include/grpc/support/log_win32.h
-  - include/grpc/support/port_platform.h
-  - include/grpc/support/slice.h
-  - include/grpc/support/slice_buffer.h
-  - include/grpc/support/string_util.h
-  - include/grpc/support/subprocess.h
-  - include/grpc/support/sync.h
-  - include/grpc/support/sync_generic.h
-  - include/grpc/support/sync_posix.h
-  - include/grpc/support/sync_win32.h
-  - include/grpc/support/thd.h
-  - include/grpc/support/time.h
-  - include/grpc/support/tls.h
-  - include/grpc/support/tls_gcc.h
-  - include/grpc/support/tls_msvc.h
-  - include/grpc/support/tls_pthread.h
-  - include/grpc/support/useful.h
-  headers:
-  - src/core/profiling/timers.h
-  - src/core/support/block_annotate.h
-  - src/core/support/env.h
-  - src/core/support/file.h
-  - src/core/support/murmur_hash.h
-  - src/core/support/stack_lockfree.h
-  - src/core/support/string.h
-  - src/core/support/string_win32.h
-  - src/core/support/thd_internal.h
-  - src/core/support/time_precise.h
-  src:
-  - src/core/profiling/basic_timers.c
-  - src/core/profiling/stap_timers.c
-  - src/core/support/alloc.c
-  - src/core/support/avl.c
-  - src/core/support/cmdline.c
-  - src/core/support/cpu_iphone.c
-  - src/core/support/cpu_linux.c
-  - src/core/support/cpu_posix.c
-  - src/core/support/cpu_windows.c
-  - src/core/support/env_linux.c
-  - src/core/support/env_posix.c
-  - src/core/support/env_win32.c
-  - src/core/support/file.c
-  - src/core/support/file_posix.c
-  - src/core/support/file_win32.c
-  - src/core/support/histogram.c
-  - src/core/support/host_port.c
-  - src/core/support/log.c
-  - src/core/support/log_android.c
-  - src/core/support/log_linux.c
-  - src/core/support/log_posix.c
-  - src/core/support/log_win32.c
-  - src/core/support/murmur_hash.c
-  - src/core/support/slice.c
-  - src/core/support/slice_buffer.c
-  - src/core/support/stack_lockfree.c
-  - src/core/support/string.c
-  - src/core/support/string_posix.c
-  - src/core/support/string_win32.c
-  - src/core/support/subprocess_posix.c
-  - src/core/support/sync.c
-  - src/core/support/sync_posix.c
-  - src/core/support/sync_win32.c
-  - src/core/support/thd.c
-  - src/core/support/thd_posix.c
-  - src/core/support/thd_win32.c
-  - src/core/support/time.c
-  - src/core/support/time_posix.c
-  - src/core/support/time_precise.c
-  - src/core/support/time_win32.c
-  - src/core/support/tls_pthread.c
+  filegroups:
+  - gpr
+  - gpr_codegen
   secure: false
   vs_project_guid: '{B23D3D1A-9438-4EDA-BEB6-9A0A03D17792}'
 - name: gpr_test_util
@@ -509,8 +576,10 @@
   deps:
   - gpr
   baselib: true
+  deps_linkage: static
   dll: true
   filegroups:
+  - grpc_codegen
   - grpc_base
   - census
   secure: true
@@ -530,8 +599,8 @@
   - test/core/end2end/data/test_root_cert.c
   - test/core/security/oauth2_utils.c
   deps:
-  - gpr
   - gpr_test_util
+  - gpr
   - grpc
   filegroups:
   - grpc_test_util_base
@@ -555,9 +624,11 @@
   deps:
   - gpr
   baselib: true
+  deps_linkage: static
   dll: true
   filegroups:
   - grpc_base
+  - grpc_codegen
   - census
   secure: false
   vs_project_guid: '{46CEDFFF-9692-456A-AA24-38B5D6BCF4C5}'
@@ -618,12 +689,12 @@
   - src/cpp/common/secure_create_auth_context.cc
   - src/cpp/server/secure_server_credentials.cc
   deps:
-  - gpr
   - grpc
   baselib: true
   dll: true
   filegroups:
   - grpc++_base
+  - grpc++_codegen
   secure: check
   vs_project_guid: '{C187A093-A0FE-489D-A40A-6E33DE0F9FEB}'
 - name: grpc++_test_config
@@ -637,6 +708,8 @@
   build: private
   language: c++
   headers:
+  - test/cpp/end2end/test_service_impl.h
+  - test/cpp/util/byte_buffer_proto_helper.h
   - test/cpp/util/cli_call.h
   - test/cpp/util/create_test_channel.h
   - test/cpp/util/string_ref_helper.h
@@ -645,6 +718,8 @@
   - src/proto/grpc/testing/echo_messages.proto
   - src/proto/grpc/testing/echo.proto
   - src/proto/grpc/testing/duplicate/echo_duplicate.proto
+  - test/cpp/end2end/test_service_impl.cc
+  - test/cpp/util/byte_buffer_proto_helper.cc
   - test/cpp/util/cli_call.cc
   - test/cpp/util/create_test_channel.cc
   - test/cpp/util/string_ref_helper.cc
@@ -664,6 +739,7 @@
   dll: true
   filegroups:
   - grpc++_base
+  - grpc++_codegen
   secure: false
   vs_project_guid: '{6EE56155-DF7C-4F6E-BFC4-F6F776BEB211}'
 - name: grpc_plugin_support
@@ -692,6 +768,10 @@
   - src/compiler/python_generator.cc
   - src/compiler/ruby_generator.cc
   deps: []
+  filegroups:
+  - grpc++_codegen
+  - grpc_codegen
+  - gpr_codegen
   secure: false
   vs_project_guid: '{B6E81D84-2ACB-41B8-8781-493A944C7817}'
 - name: interop_client_helper
@@ -765,6 +845,7 @@
   - test/cpp/qps/driver.h
   - test/cpp/qps/histogram.h
   - test/cpp/qps/interarrival.h
+  - test/cpp/qps/limit_cores.h
   - test/cpp/qps/perf_db_client.h
   - test/cpp/qps/qps_worker.h
   - test/cpp/qps/report.h
@@ -782,6 +863,7 @@
   - test/cpp/qps/client_async.cc
   - test/cpp/qps/client_sync.cc
   - test/cpp/qps/driver.cc
+  - test/cpp/qps/limit_cores.cc
   - test/cpp/qps/perf_db_client.cc
   - test/cpp/qps/qps_worker.cc
   - test/cpp/qps/report.cc
@@ -801,6 +883,7 @@
   deps:
   - grpc
   - gpr
+  LDFLAGS: $(if $(subst Linux,,$(SYSTEM)),,-Wl$(comma)-wrap$(comma)memcpy)
   deps_linkage: static
   dll: only
   vs_config_type: DynamicLibrary
@@ -814,6 +897,16 @@
   - winsock
   - global
 targets:
+- name: alarm_test
+  build: test
+  language: c
+  src:
+  - test/core/surface/alarm_test.c
+  deps:
+  - grpc_test_util
+  - grpc
+  - gpr_test_util
+  - gpr
 - name: algorithm_test
   build: test
   language: c
@@ -850,6 +943,14 @@
   deps:
   - grpc_test_util
   - grpc
+- name: census_context_test
+  build: test
+  language: c
+  src:
+  - test/core/census/context_test.c
+  deps:
+  - grpc_test_util
+  - grpc
   - gpr_test_util
   - gpr
 - name: channel_create_test
@@ -1631,16 +1732,6 @@
   - mac
   - linux
   - posix
-- name: tag_set_test
-  build: test
-  language: c
-  src:
-  - test/core/census/tag_set_test.c
-  deps:
-  - grpc_test_util
-  - grpc
-  - gpr_test_util
-  - gpr
 - name: tcp_client_posix_test
   cpu_cost: 0.5
   build: test
@@ -1807,6 +1898,18 @@
   - mac
   - linux
   - posix
+- name: alarm_cpp_test
+  build: test
+  language: c++
+  src:
+  - test/cpp/common/alarm_cpp_test.cc
+  deps:
+  - grpc++_test_util
+  - grpc_test_util
+  - grpc++
+  - grpc
+  - gpr_test_util
+  - gpr
 - name: async_end2end_test
   build: test
   language: c++
@@ -2071,6 +2174,18 @@
   secure: false
   vs_config_type: Application
   vs_project_guid: '{069E9D05-B78B-4751-9252-D21EBAE7DE8E}'
+- name: hybrid_end2end_test
+  build: test
+  language: c++
+  src:
+  - test/cpp/end2end/hybrid_end2end_test.cc
+  deps:
+  - grpc++_test_util
+  - grpc_test_util
+  - grpc++
+  - grpc
+  - gpr_test_util
+  - gpr
 - name: interop_client
   build: test
   run: false
@@ -2495,9 +2610,9 @@
 configs:
   asan:
     CC: clang
-    CFLAGS: -O0 -fsanitize=address -fno-omit-frame-pointer -Wno-unused-command-line-argument
+    CPPFLAGS: -O0 -fsanitize=address -fno-omit-frame-pointer -Wno-unused-command-line-argument
+      -DGPR_NO_DIRECT_SYSCALLS
     CXX: clang++
-    CXXFLAGS: -O0 -fsanitize=address -fno-omit-frame-pointer -Wno-unused-command-line-argument
     LD: clang
     LDFLAGS: -fsanitize=address
     LDXX: clang++
@@ -2508,9 +2623,9 @@
     timeout_multiplier: 1.5
   asan-noleaks:
     CC: clang
-    CFLAGS: -O0 -fsanitize=address -fno-omit-frame-pointer -Wno-unused-command-line-argument
+    CPPFLAGS: -O0 -fsanitize=address -fno-omit-frame-pointer -Wno-unused-command-line-argument
+      -DGPR_NO_DIRECT_SYSCALLS
     CXX: clang++
-    CXXFLAGS: -O0 -fsanitize=address -fno-omit-frame-pointer -Wno-unused-command-line-argument
     LD: clang
     LDFLAGS: -fsanitize=address
     LDXX: clang++
@@ -2524,12 +2639,10 @@
   dbg:
     CPPFLAGS: -O0
     DEFINES: _DEBUG DEBUG
-    LDFLAGS: -rdynamic
   gcov:
     CC: gcc
-    CFLAGS: -O0 -fprofile-arcs -ftest-coverage -Wno-return-type
+    CPPFLAGS: -O0 -fprofile-arcs -ftest-coverage -Wno-return-type
     CXX: g++
-    CXXFLAGS: -O0 -fprofile-arcs -ftest-coverage -Wno-return-type
     DEFINES: _DEBUG DEBUG GPR_GCOV
     LD: gcc
     LDFLAGS: -fprofile-arcs -ftest-coverage -rdynamic
@@ -2548,20 +2661,17 @@
     valgrind: --tool=memcheck --leak-check=full
   msan:
     CC: clang
-    CFLAGS: -O0 -fsanitize=memory -fsanitize-memory-track-origins -fno-omit-frame-pointer
+    CPPFLAGS: -O0 -fsanitize=memory -fsanitize-memory-track-origins -fno-omit-frame-pointer
       -DGTEST_HAS_TR1_TUPLE=0 -DGTEST_USE_OWN_TR1_TUPLE=1 -Wno-unused-command-line-argument
-      -fPIE -pie
+      -fPIE -pie -DGPR_NO_DIRECT_SYSCALLS
     CXX: clang++
-    CXXFLAGS: -O0 -fsanitize=memory -fsanitize-memory-track-origins -fno-omit-frame-pointer
-      -DGTEST_HAS_TR1_TUPLE=0 -DGTEST_USE_OWN_TR1_TUPLE=1 -Wno-unused-command-line-argument
-      -fPIE -pie
     DEFINES: NDEBUG
     LD: clang
     LDFLAGS: -fsanitize=memory -DGTEST_HAS_TR1_TUPLE=0 -DGTEST_USE_OWN_TR1_TUPLE=1
       -fPIE -pie $(if $(JENKINS_BUILD),-Wl$(comma)-Ttext-segment=0x7e0000000000,)
     LDXX: clang++
     compile_the_world: true
-    timeout_multiplier: 1.5
+    timeout_multiplier: 2
   mutrace:
     CPPFLAGS: -O0
     DEFINES: _DEBUG DEBUG
@@ -2569,17 +2679,14 @@
   opt:
     CPPFLAGS: -O2
     DEFINES: NDEBUG
-    LDFLAGS: -rdynamic
   stapprof:
     CPPFLAGS: -O2 -DGRPC_STAP_PROFILER
     DEFINES: NDEBUG
   tsan:
     CC: clang
-    CFLAGS: -O0 -fsanitize=thread -fno-omit-frame-pointer -Wno-unused-command-line-argument
-      -fPIE -pie
+    CPPFLAGS: -O0 -fsanitize=thread -fno-omit-frame-pointer -Wno-unused-command-line-argument
+      -fPIE -pie -DGPR_NO_DIRECT_SYSCALLS
     CXX: clang++
-    CXXFLAGS: -O0 -fsanitize=thread -fno-omit-frame-pointer -Wno-unused-command-line-argument
-      -fPIE -pie
     LD: clang
     LDFLAGS: -fsanitize=thread -fPIE -pie $(if $(JENKINS_BUILD),-Wl$(comma)-Ttext-segment=0x7e0000000000,)
     LDXX: clang++
@@ -2589,15 +2696,26 @@
     timeout_multiplier: 2
   ubsan:
     CC: clang
-    CFLAGS: -O1 -fsanitize=undefined -fno-omit-frame-pointer -Wno-unused-command-line-argument
+    CPPFLAGS: -O1 -fsanitize=undefined -fno-omit-frame-pointer -Wno-unused-command-line-argument
     CXX: clang++
-    CXXFLAGS: -O1 -fsanitize=undefined -fno-omit-frame-pointer -Wno-unused-command-line-argument
     DEFINES: NDEBUG
     LD: clang
     LDFLAGS: -fsanitize=undefined
     LDXX: clang++
     compile_the_world: true
     timeout_multiplier: 1.5
+defaults:
+  boringssl:
+    CFLAGS: -Wno-sign-conversion -Wno-conversion -Wno-unused-value -Wno-unknown-pragmas
+      -Wno-implicit-function-declaration -Wno-unused-variable -Wno-sign-compare
+    CPPFLAGS: -Ithird_party/boringssl/include -fvisibility=hidden -DOPENSSL_NO_ASM
+      -D_GNU_SOURCE -DWIN32_LEAN_AND_MEAN -D_HAS_EXCEPTIONS=0 -DNOMINMAX
+  global:
+    CPPFLAGS: -g -Wall -Wextra -Werror -Wno-long-long -Wno-unused-parameter
+    LDFLAGS: -g
+  zlib:
+    CFLAGS: -Wno-sign-conversion -Wno-conversion -Wno-unused-value -Wno-implicit-function-declaration
+      $(W_NO_SHIFT_NEGATIVE_VALUE) -fvisibility=hidden
 node_modules:
 - deps:
   - grpc
@@ -2619,6 +2737,7 @@
   - src/node/src/client.js
   - src/node/src/common.js
   - src/node/src/credentials.js
+  - src/node/src/grpc_extension.js
   - src/node/src/metadata.js
   - src/node/src/server.js
   name: grpc_node
@@ -2639,3 +2758,9 @@
   - gpr
   - boringssl
   - z
+ruby_gem:
+  deps:
+  - grpc
+  - gpr
+  - boringssl
+  - z
diff --git a/doc/statuscodes.md b/doc/statuscodes.md
new file mode 100644
index 0000000..84258c8
--- /dev/null
+++ b/doc/statuscodes.md
@@ -0,0 +1,35 @@
+# Status codes and their use in gRPC
+
+gRPC uses a set of well defined status codes as part of the RPC API. All RPCs started at a client return  a `status` object composed of an integer `code` and a string `message`. The server-side can choose the status it returns for a given RPC.
+
+The gRPC client and server-side implementations may also generate and return `status` on their own when errors happen.  
+Only a subset of the pre-defined status codes are generated by the gRPC libraries. The following table lists these codes and summarizes the situations in which they are generated, either by the client or the server-side library implementation.
+
+| Case        | Code           | Generated at Client or Server  |
+| ------------- |:-------------| :-----:|
+| Client Application cancelled the request	| CANCELLED | Both |
+| Deadline expires before server returns status	| DEADLINE_EXCEEDED | Both |
+| Method not found at server	| UNIMPLEMENTED | Server|
+| Server shutting down	| UNAVAILABLE | Server|
+| Server side application throws an exception (or does something other than returning a Status code to terminate an RPC) |	UNKNOWN | Server|
+| No response received before Deadline expires. This may occur either when the client is unable to send the request to the server or when the server fails to respond in time. |	DEADLINE_EXCEEDED | Both|
+| Some data transmitted (e.g., request metadata written to TCP connection) before connection breaks |	UNAVAILABLE | Client |
+| Could not decompress, but compression algorithm supported (Client -> Server)	| INTERNAL | Server |
+| Could not decompress, but compression algorithm supported (Server -> Client)	| INTERNAL | Client |
+| Compression mechanism used by client not supported at server	| UNIMPLEMENTED | Server |
+| Server temporarily out of resources (e.g., Flow-control resource limits reached) |	RESOURCE_EXHAUSTED | Server|
+| Flow-control protocol violation |	INTERNAL | Both |
+| Error parsing returned status	| UNKNOWN | Client |
+| Incorrect Auth metadata ( Credentials failed to get metadata, Incompatible credentials set on channel and call, Invalid host set in `:authority` metadata, etc.) | UNAUTHENTICATED | Both |
+| Error parsing response proto	| INTERNAL | Client|
+| Error parsing request proto	| INTERNAL | Server|
+
+
+The following status codes are never generated by the library:
+- INVALID_ARGUMENT
+- NOT_FOUND
+- ALREADY_EXISTS
+- FAILED_PRECONDITION
+- ABORTED
+- OUT_OF_RANGE
+- DATA_LOSS
diff --git a/examples/cpp/helloworld/Makefile b/examples/cpp/helloworld/Makefile
index f2093af..b785612 100644
--- a/examples/cpp/helloworld/Makefile
+++ b/examples/cpp/helloworld/Makefile
@@ -1,5 +1,5 @@
 #
-# Copyright 2015, Google Inc.
+# Copyright 2015-2016, Google Inc.
 # All rights reserved.
 #
 # Redistribution and use in source and binary forms, with or without
@@ -32,7 +32,7 @@
 CXX = g++
 CPPFLAGS += -I/usr/local/include -pthread
 CXXFLAGS += -std=c++11
-LDFLAGS += -L/usr/local/lib -lgrpc++_unsecure -lgrpc -lgpr -lprotobuf -lpthread -ldl
+LDFLAGS += -L/usr/local/lib -lgrpc++_unsecure -lgrpc -lprotobuf -lpthread -ldl
 PROTOC = protoc
 GRPC_CPP_PLUGIN = grpc_cpp_plugin
 GRPC_CPP_PLUGIN_PATH ?= `which $(GRPC_CPP_PLUGIN)`
@@ -55,9 +55,11 @@
 greeter_async_server: helloworld.pb.o helloworld.grpc.pb.o greeter_async_server.o
 	$(CXX) $^ $(LDFLAGS) -o $@
 
+.PRECIOUS: %.grpc.pb.cc
 %.grpc.pb.cc: %.proto
 	$(PROTOC) -I $(PROTOS_PATH) --grpc_out=. --plugin=protoc-gen-grpc=$(GRPC_CPP_PLUGIN_PATH) $<
 
+.PRECIOUS: %.pb.cc
 %.pb.cc: %.proto
 	$(PROTOC) -I $(PROTOS_PATH) --cpp_out=. $<
 
@@ -92,7 +94,7 @@
 	@echo "Please install Google protocol buffers 3.0.0 and its compiler."
 	@echo "You can find it here:"
 	@echo
-	@echo "   https://github.com/google/protobuf/releases/tag/v3.0.0-alpha-1"
+	@echo "   https://github.com/google/protobuf/releases/tag/v3.0.0-beta-2"
 	@echo
 	@echo "Here is what I get when trying to evaluate your version of protoc:"
 	@echo
diff --git a/examples/cpp/helloworld/greeter_async_server.cc b/examples/cpp/helloworld/greeter_async_server.cc
index d06e7c7..c9b1a67 100644
--- a/examples/cpp/helloworld/greeter_async_server.cc
+++ b/examples/cpp/helloworld/greeter_async_server.cc
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -67,7 +67,7 @@
     builder.AddListeningPort(server_address, grpc::InsecureServerCredentials());
     // Register "service_" as the instance through which we'll communicate with
     // clients. In this case it corresponds to an *asynchronous* service.
-    builder.RegisterAsyncService(&service_);
+    builder.RegisterService(&service_);
     // Get hold of the completion queue used for the asynchronous communication
     // with the gRPC runtime.
     cq_ = builder.AddCompletionQueue();
diff --git a/examples/cpp/route_guide/Makefile b/examples/cpp/route_guide/Makefile
index b906177..3f8a598 100644
--- a/examples/cpp/route_guide/Makefile
+++ b/examples/cpp/route_guide/Makefile
@@ -1,5 +1,5 @@
 #
-# Copyright 2015, Google Inc.
+# Copyright 2015-2016, Google Inc.
 # All rights reserved.
 #
 # Redistribution and use in source and binary forms, with or without
@@ -32,7 +32,7 @@
 CXX = g++
 CPPFLAGS += -I/usr/local/include -pthread
 CXXFLAGS += -std=c++11
-LDFLAGS += -L/usr/local/lib -lgrpc++_unsecure -lgrpc -lgpr -lprotobuf -lpthread -ldl
+LDFLAGS += -L/usr/local/lib -lgrpc++_unsecure -lgrpc -lprotobuf -lpthread -ldl
 PROTOC = protoc
 GRPC_CPP_PLUGIN = grpc_cpp_plugin
 GRPC_CPP_PLUGIN_PATH ?= `which $(GRPC_CPP_PLUGIN)`
@@ -86,7 +86,7 @@
 	@echo "Please install Google protocol buffers 3.0.0 and its compiler."
 	@echo "You can find it here:"
 	@echo
-	@echo "   https://github.com/google/protobuf/releases/tag/v3.0.0-alpha-1"
+	@echo "   https://github.com/google/protobuf/releases/tag/v3.0.0-beta-2"
 	@echo
 	@echo "Here is what I get when trying to evaluate your version of protoc:"
 	@echo
diff --git a/examples/node/greeter_client.js b/examples/node/greeter_client.js
index e0b89bd..9b4b0a7 100644
--- a/examples/node/greeter_client.js
+++ b/examples/node/greeter_client.js
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -33,7 +33,7 @@
 
 var PROTO_PATH = __dirname + '/helloworld.proto';
 
-var grpc = require('../../');
+var grpc = require('grpc');
 var hello_proto = grpc.load(PROTO_PATH).helloworld;
 
 function main() {
diff --git a/examples/node/greeter_server.js b/examples/node/greeter_server.js
index 3600c8b..2712b3d 100644
--- a/examples/node/greeter_server.js
+++ b/examples/node/greeter_server.js
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -33,7 +33,7 @@
 
 var PROTO_PATH = __dirname + '/helloworld.proto';
 
-var grpc = require('../../');
+var grpc = require('grpc');
 var hello_proto = grpc.load(PROTO_PATH).helloworld;
 
 /**
diff --git a/examples/node/package.json b/examples/node/package.json
new file mode 100644
index 0000000..65c5789
--- /dev/null
+++ b/examples/node/package.json
@@ -0,0 +1,7 @@
+{
+  "name": "grpc-examples",
+  "version": "0.1.0",
+  "dependencies": {
+    "grpc": "0.12.0"
+  }
+}
diff --git a/examples/node/route_guide/route_guide_client.js b/examples/node/route_guide/route_guide_client.js
index edeca6f..e38a21f 100644
--- a/examples/node/route_guide/route_guide_client.js
+++ b/examples/node/route_guide/route_guide_client.js
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -30,13 +30,13 @@
  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  *
  */
- 
+
 var async = require('async');
 var fs = require('fs');
 var parseArgs = require('minimist');
 var path = require('path');
 var _ = require('lodash');
-var grpc = require('../../../');
+var grpc = require('grpc');
 var routeguide = grpc.load(__dirname + '/route_guide.proto').routeguide;
 var client = new routeguide.RouteGuide('localhost:50051',
                                        grpc.Credentials.createInsecure());
diff --git a/examples/node/route_guide/route_guide_server.js b/examples/node/route_guide/route_guide_server.js
index 2090a6a..06cf292 100644
--- a/examples/node/route_guide/route_guide_server.js
+++ b/examples/node/route_guide/route_guide_server.js
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -30,12 +30,12 @@
  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  *
  */
- 
+
 var fs = require('fs');
 var parseArgs = require('minimist');
 var path = require('path');
 var _ = require('lodash');
-var grpc = require('../../../');
+var grpc = require('grpc');
 var routeguide = grpc.load(__dirname + '/route_guide.proto').routeguide;
 
 var COORD_FACTOR = 1e7;
diff --git a/examples/objective-c/helloworld/main.m b/examples/objective-c/helloworld/main.m
index a62f836..bf35799 100644
--- a/examples/objective-c/helloworld/main.m
+++ b/examples/objective-c/helloworld/main.m
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -34,6 +34,7 @@
 #import <UIKit/UIKit.h>
 #import "AppDelegate.h"
 
+#import <GRPCClient/GRPCCall+ChannelArg.h>
 #import <GRPCClient/GRPCCall+Tests.h>
 #import <HelloWorld/Helloworld.pbrpc.h>
 
@@ -42,6 +43,7 @@
 int main(int argc, char * argv[]) {
   @autoreleasepool {
     [GRPCCall useInsecureConnectionsForHost:kHostAddress];
+    [GRPCCall setUserAgentPrefix:@"HelloWorld/1.0" forHost:kHostAddress];
 
     HLWGreeter *client = [[HLWGreeter alloc] initWithHost:kHostAddress];
 
diff --git a/examples/protos/helloworld.proto b/examples/protos/helloworld.proto
index 7d58870..e670503 100644
--- a/examples/protos/helloworld.proto
+++ b/examples/protos/helloworld.proto
@@ -1,4 +1,4 @@
-// Copyright 2015, Google Inc.
+// Copyright 2015-2016, Google Inc.
 // All rights reserved.
 //
 // Redistribution and use in source and binary forms, with or without
@@ -29,7 +29,9 @@
 
 syntax = "proto3";
 
-option java_package = "io.grpc.examples";
+option java_multiple_files = true;
+option java_package = "io.grpc.examples.helloworld";
+option java_outer_classname = "HelloWorldProto";
 option objc_class_prefix = "HLW";
 
 package helloworld;
diff --git a/examples/protos/route_guide.proto b/examples/protos/route_guide.proto
index 7a70040..b3553ee 100644
--- a/examples/protos/route_guide.proto
+++ b/examples/protos/route_guide.proto
@@ -1,4 +1,4 @@
-// Copyright 2015, Google Inc.
+// Copyright 2015-2016, Google Inc.
 // All rights reserved.
 //
 // Redistribution and use in source and binary forms, with or without
@@ -29,7 +29,9 @@
 
 syntax = "proto3";
 
-option java_package = "ex.grpc";
+option java_multiple_files = true;
+option java_package = "io.grpc.examples.routeguide";
+option java_outer_classname = "RouteGuideProto";
 option objc_class_prefix = "RTG";
 
 package routeguide;
diff --git a/examples/ruby/greeter_client.rb b/examples/ruby/greeter_client.rb
index e6cb4ba..2a24316 100755
--- a/examples/ruby/greeter_client.rb
+++ b/examples/ruby/greeter_client.rb
@@ -1,6 +1,6 @@
 #!/usr/bin/env ruby
 
-# Copyright 2015, Google Inc.
+# Copyright 2015-2016, Google Inc.
 # All rights reserved.
 #
 # Redistribution and use in source and binary forms, with or without
@@ -41,7 +41,7 @@
 require 'helloworld_services'
 
 def main
-  stub = Helloworld::Greeter::Stub.new('localhost:50051')
+  stub = Helloworld::Greeter::Stub.new('localhost:50051', :this_channel_is_insecure)
   user = ARGV.size > 0 ?  ARGV[0] : 'world'
   message = stub.say_hello(Helloworld::HelloRequest.new(name: user)).message
   p "Greeting: #{message}"
diff --git a/examples/ruby/route_guide/route_guide_client.rb b/examples/ruby/route_guide/route_guide_client.rb
index baef0e5..715a3c0 100755
--- a/examples/ruby/route_guide/route_guide_client.rb
+++ b/examples/ruby/route_guide/route_guide_client.rb
@@ -1,6 +1,6 @@
 #!/usr/bin/env ruby
 
-# Copyright 2015, Google Inc.
+# Copyright 2015-2016, Google Inc.
 # All rights reserved.
 #
 # Redistribution and use in source and binary forms, with or without
@@ -147,7 +147,7 @@
 end
 
 def main
-  stub = RouteGuide::Stub.new('localhost:50051')
+  stub = RouteGuide::Stub.new('localhost:50051', :this_channel_is_insecure)
   run_get_feature(stub)
   run_list_features(stub)
   run_route_chat(stub)
diff --git a/gRPC.podspec b/gRPC.podspec
index 18c05e2..5b4d24e 100644
--- a/gRPC.podspec
+++ b/gRPC.podspec
@@ -101,6 +101,20 @@
                       'include/grpc/support/tls_msvc.h',
                       'include/grpc/support/tls_pthread.h',
                       'include/grpc/support/useful.h',
+                      'include/grpc/impl/codegen/alloc.h',
+                      'include/grpc/impl/codegen/atm.h',
+                      'include/grpc/impl/codegen/atm_gcc_atomic.h',
+                      'include/grpc/impl/codegen/atm_gcc_sync.h',
+                      'include/grpc/impl/codegen/atm_win32.h',
+                      'include/grpc/impl/codegen/log.h',
+                      'include/grpc/impl/codegen/port_platform.h',
+                      'include/grpc/impl/codegen/slice.h',
+                      'include/grpc/impl/codegen/slice_buffer.h',
+                      'include/grpc/impl/codegen/sync.h',
+                      'include/grpc/impl/codegen/sync_generic.h',
+                      'include/grpc/impl/codegen/sync_posix.h',
+                      'include/grpc/impl/codegen/sync_win32.h',
+                      'include/grpc/impl/codegen/time.h',
                       'src/core/profiling/basic_timers.c',
                       'src/core/profiling/stap_timers.c',
                       'src/core/support/alloc.c',
@@ -131,6 +145,7 @@
                       'src/core/support/string_posix.c',
                       'src/core/support/string_win32.c',
                       'src/core/support/subprocess_posix.c',
+                      'src/core/support/subprocess_windows.c',
                       'src/core/support/sync.c',
                       'src/core/support/sync_posix.c',
                       'src/core/support/sync_win32.c',
@@ -142,6 +157,7 @@
                       'src/core/support/time_precise.c',
                       'src/core/support/time_win32.c',
                       'src/core/support/tls_pthread.c',
+                      'src/core/support/wrap_memcpy.c',
                       'src/core/security/auth_filters.h',
                       'src/core/security/base64.h',
                       'src/core/security/credentials.h',
@@ -270,9 +286,14 @@
                       'src/core/transport/transport.h',
                       'src/core/transport/transport_impl.h',
                       'src/core/census/aggregation.h',
-                      'src/core/census/context.h',
                       'src/core/census/rpc_metric_id.h',
                       'include/grpc/grpc_security.h',
+                      'include/grpc/impl/codegen/byte_buffer.h',
+                      'include/grpc/impl/codegen/compression_types.h',
+                      'include/grpc/impl/codegen/connectivity_state.h',
+                      'include/grpc/impl/codegen/grpc_types.h',
+                      'include/grpc/impl/codegen/propagation_bits.h',
+                      'include/grpc/impl/codegen/status.h',
                       'include/grpc/byte_buffer.h',
                       'include/grpc/byte_buffer_reader.h',
                       'include/grpc/compression.h',
@@ -378,6 +399,7 @@
                       'src/core/json/json_reader.c',
                       'src/core/json/json_string.c',
                       'src/core/json/json_writer.c',
+                      'src/core/surface/alarm.c',
                       'src/core/surface/api_trace.c',
                       'src/core/surface/byte_buffer.c',
                       'src/core/surface/byte_buffer_reader.c',
@@ -429,7 +451,7 @@
                       'src/core/census/context.c',
                       'src/core/census/initialize.c',
                       'src/core/census/operation.c',
-                      'src/core/census/tag_set.c',
+                      'src/core/census/placeholders.c',
                       'src/core/census/tracing.c'
 
     ss.private_header_files = 'src/core/profiling/timers.h',
@@ -570,7 +592,6 @@
                               'src/core/transport/transport.h',
                               'src/core/transport/transport_impl.h',
                               'src/core/census/aggregation.h',
-                              'src/core/census/context.h',
                               'src/core/census/rpc_metric_id.h'
 
     ss.header_mappings_dir = '.'
@@ -585,7 +606,7 @@
 
     ss.requires_arc = false
     ss.libraries = 'z'
-    ss.dependency 'BoringSSL', '~> 1.0'
+    ss.dependency 'BoringSSL', '~> 2.0'
 
     # ss.compiler_flags = '-GCC_WARN_INHIBIT_ALL_WARNINGS', '-w'
   end
diff --git a/grpc.def b/grpc.def
new file mode 100644
index 0000000..d37e687
--- /dev/null
+++ b/grpc.def
@@ -0,0 +1,259 @@
+EXPORTS
+    census_initialize
+    census_shutdown
+    census_supported
+    census_enabled
+    census_context_create
+    census_context_destroy
+    census_context_get_status
+    census_context_initialize_iterator
+    census_context_next_tag
+    census_context_get_tag
+    census_context_encode
+    census_context_decode
+    census_trace_mask
+    census_set_trace_mask
+    census_start_rpc_op_timestamp
+    census_start_client_rpc_op
+    census_set_rpc_client_peer
+    census_start_server_rpc_op
+    census_start_op
+    census_end_op
+    census_trace_print
+    census_trace_scan_start
+    census_get_trace_record
+    census_trace_scan_end
+    census_record_values
+    census_view_create
+    census_view_delete
+    census_view_metric
+    census_view_naggregations
+    census_view_tags
+    census_view_aggregrations
+    census_view_get_data
+    census_view_reset
+    grpc_compression_algorithm_parse
+    grpc_compression_algorithm_name
+    grpc_compression_algorithm_for_level
+    grpc_compression_options_init
+    grpc_compression_options_enable_algorithm
+    grpc_compression_options_disable_algorithm
+    grpc_compression_options_is_algorithm_enabled
+    grpc_metadata_array_init
+    grpc_metadata_array_destroy
+    grpc_call_details_init
+    grpc_call_details_destroy
+    grpc_register_plugin
+    grpc_init
+    grpc_shutdown
+    grpc_version_string
+    grpc_completion_queue_create
+    grpc_completion_queue_next
+    grpc_completion_queue_pluck
+    grpc_completion_queue_shutdown
+    grpc_completion_queue_destroy
+    grpc_alarm_create
+    grpc_alarm_cancel
+    grpc_alarm_destroy
+    grpc_channel_check_connectivity_state
+    grpc_channel_watch_connectivity_state
+    grpc_channel_create_call
+    grpc_channel_ping
+    grpc_channel_register_call
+    grpc_channel_create_registered_call
+    grpc_call_start_batch
+    grpc_call_get_peer
+    grpc_census_call_set_context
+    grpc_census_call_get_context
+    grpc_channel_get_target
+    grpc_insecure_channel_create
+    grpc_lame_client_channel_create
+    grpc_channel_destroy
+    grpc_call_cancel
+    grpc_call_cancel_with_status
+    grpc_call_destroy
+    grpc_server_request_call
+    grpc_server_register_method
+    grpc_server_request_registered_call
+    grpc_server_create
+    grpc_server_register_completion_queue
+    grpc_server_add_insecure_http2_port
+    grpc_server_start
+    grpc_server_shutdown_and_notify
+    grpc_server_cancel_all_calls
+    grpc_server_destroy
+    grpc_tracer_set_enabled
+    grpc_header_key_is_legal
+    grpc_header_nonbin_value_is_legal
+    grpc_is_binary_header
+    grpc_auth_property_iterator_next
+    grpc_auth_context_property_iterator
+    grpc_auth_context_peer_identity
+    grpc_auth_context_find_properties_by_name
+    grpc_auth_context_peer_identity_property_name
+    grpc_auth_context_peer_is_authenticated
+    grpc_call_auth_context
+    grpc_auth_context_release
+    grpc_auth_context_add_property
+    grpc_auth_context_add_cstring_property
+    grpc_auth_context_set_peer_identity_property_name
+    grpc_channel_credentials_release
+    grpc_google_default_credentials_create
+    grpc_ssl_credentials_create
+    grpc_call_credentials_release
+    grpc_composite_channel_credentials_create
+    grpc_composite_call_credentials_create
+    grpc_google_compute_engine_credentials_create
+    grpc_max_auth_token_lifetime
+    grpc_service_account_jwt_access_credentials_create
+    grpc_google_refresh_token_credentials_create
+    grpc_access_token_credentials_create
+    grpc_google_iam_credentials_create
+    grpc_metadata_credentials_create_from_plugin
+    grpc_secure_channel_create
+    grpc_server_credentials_release
+    grpc_ssl_server_credentials_create
+    grpc_server_add_secure_http2_port
+    grpc_call_set_credentials
+    grpc_server_credentials_set_auth_metadata_processor
+    gpr_malloc
+    gpr_free
+    gpr_realloc
+    gpr_malloc_aligned
+    gpr_free_aligned
+    gpr_set_allocation_functions
+    gpr_get_allocation_functions
+    grpc_raw_byte_buffer_create
+    grpc_raw_compressed_byte_buffer_create
+    grpc_byte_buffer_copy
+    grpc_byte_buffer_length
+    grpc_byte_buffer_destroy
+    grpc_byte_buffer_reader_init
+    grpc_byte_buffer_reader_destroy
+    grpc_byte_buffer_reader_next
+    grpc_byte_buffer_reader_readall
+    grpc_raw_byte_buffer_from_reader
+    gpr_log
+    gpr_log_message
+    gpr_set_log_function
+    gpr_slice_ref
+    gpr_slice_unref
+    gpr_slice_new
+    gpr_slice_new_with_len
+    gpr_slice_malloc
+    gpr_slice_from_copied_string
+    gpr_slice_from_copied_buffer
+    gpr_slice_from_static_string
+    gpr_slice_sub
+    gpr_slice_sub_no_ref
+    gpr_slice_split_tail
+    gpr_slice_split_head
+    gpr_empty_slice
+    gpr_slice_cmp
+    gpr_slice_str_cmp
+    gpr_slice_buffer_init
+    gpr_slice_buffer_destroy
+    gpr_slice_buffer_add
+    gpr_slice_buffer_add_indexed
+    gpr_slice_buffer_addn
+    gpr_slice_buffer_tiny_add
+    gpr_slice_buffer_pop
+    gpr_slice_buffer_reset_and_unref
+    gpr_slice_buffer_swap
+    gpr_slice_buffer_move_into
+    gpr_slice_buffer_trim_end
+    gpr_slice_buffer_move_first
+    gpr_slice_buffer_take_first
+    gpr_mu_init
+    gpr_mu_destroy
+    gpr_mu_lock
+    gpr_mu_unlock
+    gpr_mu_trylock
+    gpr_cv_init
+    gpr_cv_destroy
+    gpr_cv_wait
+    gpr_cv_signal
+    gpr_cv_broadcast
+    gpr_once_init
+    gpr_event_init
+    gpr_event_set
+    gpr_event_get
+    gpr_event_wait
+    gpr_ref_init
+    gpr_ref
+    gpr_refn
+    gpr_unref
+    gpr_stats_init
+    gpr_stats_inc
+    gpr_stats_read
+    gpr_time_0
+    gpr_inf_future
+    gpr_inf_past
+    gpr_time_init
+    gpr_now
+    gpr_convert_clock_type
+    gpr_time_cmp
+    gpr_time_max
+    gpr_time_min
+    gpr_time_add
+    gpr_time_sub
+    gpr_time_from_micros
+    gpr_time_from_nanos
+    gpr_time_from_millis
+    gpr_time_from_seconds
+    gpr_time_from_minutes
+    gpr_time_from_hours
+    gpr_time_to_millis
+    gpr_time_similar
+    gpr_sleep_until
+    gpr_timespec_to_micros
+    gpr_avl_create
+    gpr_avl_ref
+    gpr_avl_unref
+    gpr_avl_add
+    gpr_avl_remove
+    gpr_avl_get
+    gpr_cmdline_create
+    gpr_cmdline_add_int
+    gpr_cmdline_add_flag
+    gpr_cmdline_add_string
+    gpr_cmdline_on_extra_arg
+    gpr_cmdline_set_survive_failure
+    gpr_cmdline_parse
+    gpr_cmdline_destroy
+    gpr_cmdline_usage_string
+    gpr_cpu_num_cores
+    gpr_cpu_current_cpu
+    gpr_histogram_create
+    gpr_histogram_destroy
+    gpr_histogram_add
+    gpr_histogram_merge
+    gpr_histogram_percentile
+    gpr_histogram_mean
+    gpr_histogram_stddev
+    gpr_histogram_variance
+    gpr_histogram_maximum
+    gpr_histogram_minimum
+    gpr_histogram_count
+    gpr_histogram_sum
+    gpr_histogram_sum_of_squares
+    gpr_histogram_get_contents
+    gpr_histogram_merge_contents
+    gpr_join_host_port
+    gpr_split_host_port
+    gpr_format_message
+    gpr_strdup
+    gpr_asprintf
+    gpr_subprocess_binary_extension
+    gpr_subprocess_create
+    gpr_subprocess_destroy
+    gpr_subprocess_join
+    gpr_subprocess_interrupt
+    gpr_thd_new
+    gpr_thd_options_default
+    gpr_thd_options_set_detached
+    gpr_thd_options_set_joinable
+    gpr_thd_options_is_detached
+    gpr_thd_options_is_joinable
+    gpr_thd_currentid
+    gpr_thd_join
diff --git a/grpc.gemspec b/grpc.gemspec
index 47b66ae..9e4683f 100755
--- a/grpc.gemspec
+++ b/grpc.gemspec
@@ -14,9 +14,8 @@
   s.license       = 'BSD-3-Clause'
 
   s.required_ruby_version = '>= 2.0.0'
-  s.requirements << 'libgrpc ~> 0.11.0 needs to be installed'
 
-  s.files = %w( Rakefile Makefile )
+  s.files = %w( Makefile )
   s.files += %w( etc/roots.pem )
   s.files += Dir.glob('src/ruby/bin/**/*')
   s.files += Dir.glob('src/ruby/ext/**/*')
@@ -32,17 +31,18 @@
   s.require_paths = %w( src/ruby/bin src/ruby/lib src/ruby/pb )
   s.platform      = Gem::Platform::RUBY
 
-  s.add_dependency 'google-protobuf', '~> 3.0.0alpha.1.1'
-  s.add_dependency 'googleauth', '~> 0.5.1'
+  s.add_dependency 'google-protobuf', '~> 3.0.0.alpha.5.0.2'
+  s.add_dependency 'googleauth',      '~> 0.5.1'
 
-  s.add_development_dependency 'bundler', '~> 1.9'
-  s.add_development_dependency 'logging', '~> 2.0'
-  s.add_development_dependency 'simplecov', '~> 0.9'
-  s.add_development_dependency 'rake', '~> 10.4'
-  s.add_development_dependency 'rake-compiler', '~> 0.9'
-  s.add_development_dependency 'rspec', '~> 3.2'
-  s.add_development_dependency 'rubocop', '~> 0.30.0'
-  s.add_development_dependency 'signet', '~>0.7.0'
+  s.add_development_dependency 'bundler',            '~> 1.9'
+  s.add_development_dependency 'logging',            '~> 2.0'
+  s.add_development_dependency 'simplecov',          '~> 0.9'
+  s.add_development_dependency 'rake',               '~> 10.4'
+  s.add_development_dependency 'rake-compiler',      '~> 0.9'
+  s.add_development_dependency 'rake-compiler-dock', '~> 0.5.1'
+  s.add_development_dependency 'rspec',              '~> 3.2'
+  s.add_development_dependency 'rubocop',            '~> 0.30.0'
+  s.add_development_dependency 'signet',             '~> 0.7.0'
 
   s.extensions = %w(src/ruby/ext/grpc/extconf.rb)
 
@@ -74,6 +74,20 @@
   s.files += %w( include/grpc/support/tls_msvc.h )
   s.files += %w( include/grpc/support/tls_pthread.h )
   s.files += %w( include/grpc/support/useful.h )
+  s.files += %w( include/grpc/impl/codegen/alloc.h )
+  s.files += %w( include/grpc/impl/codegen/atm.h )
+  s.files += %w( include/grpc/impl/codegen/atm_gcc_atomic.h )
+  s.files += %w( include/grpc/impl/codegen/atm_gcc_sync.h )
+  s.files += %w( include/grpc/impl/codegen/atm_win32.h )
+  s.files += %w( include/grpc/impl/codegen/log.h )
+  s.files += %w( include/grpc/impl/codegen/port_platform.h )
+  s.files += %w( include/grpc/impl/codegen/slice.h )
+  s.files += %w( include/grpc/impl/codegen/slice_buffer.h )
+  s.files += %w( include/grpc/impl/codegen/sync.h )
+  s.files += %w( include/grpc/impl/codegen/sync_generic.h )
+  s.files += %w( include/grpc/impl/codegen/sync_posix.h )
+  s.files += %w( include/grpc/impl/codegen/sync_win32.h )
+  s.files += %w( include/grpc/impl/codegen/time.h )
   s.files += %w( src/core/profiling/timers.h )
   s.files += %w( src/core/support/block_annotate.h )
   s.files += %w( src/core/support/env.h )
@@ -114,6 +128,7 @@
   s.files += %w( src/core/support/string_posix.c )
   s.files += %w( src/core/support/string_win32.c )
   s.files += %w( src/core/support/subprocess_posix.c )
+  s.files += %w( src/core/support/subprocess_windows.c )
   s.files += %w( src/core/support/sync.c )
   s.files += %w( src/core/support/sync_posix.c )
   s.files += %w( src/core/support/sync_win32.c )
@@ -125,7 +140,14 @@
   s.files += %w( src/core/support/time_precise.c )
   s.files += %w( src/core/support/time_win32.c )
   s.files += %w( src/core/support/tls_pthread.c )
+  s.files += %w( src/core/support/wrap_memcpy.c )
   s.files += %w( include/grpc/grpc_security.h )
+  s.files += %w( include/grpc/impl/codegen/byte_buffer.h )
+  s.files += %w( include/grpc/impl/codegen/compression_types.h )
+  s.files += %w( include/grpc/impl/codegen/connectivity_state.h )
+  s.files += %w( include/grpc/impl/codegen/grpc_types.h )
+  s.files += %w( include/grpc/impl/codegen/propagation_bits.h )
+  s.files += %w( include/grpc/impl/codegen/status.h )
   s.files += %w( include/grpc/byte_buffer.h )
   s.files += %w( include/grpc/byte_buffer_reader.h )
   s.files += %w( include/grpc/compression.h )
@@ -260,7 +282,6 @@
   s.files += %w( src/core/transport/transport.h )
   s.files += %w( src/core/transport/transport_impl.h )
   s.files += %w( src/core/census/aggregation.h )
-  s.files += %w( src/core/census/context.h )
   s.files += %w( src/core/census/rpc_metric_id.h )
   s.files += %w( src/core/httpcli/httpcli_security_connector.c )
   s.files += %w( src/core/security/base64.c )
@@ -361,6 +382,7 @@
   s.files += %w( src/core/json/json_reader.c )
   s.files += %w( src/core/json/json_string.c )
   s.files += %w( src/core/json/json_writer.c )
+  s.files += %w( src/core/surface/alarm.c )
   s.files += %w( src/core/surface/api_trace.c )
   s.files += %w( src/core/surface/byte_buffer.c )
   s.files += %w( src/core/surface/byte_buffer_reader.c )
@@ -412,6 +434,433 @@
   s.files += %w( src/core/census/context.c )
   s.files += %w( src/core/census/initialize.c )
   s.files += %w( src/core/census/operation.c )
-  s.files += %w( src/core/census/tag_set.c )
+  s.files += %w( src/core/census/placeholders.c )
   s.files += %w( src/core/census/tracing.c )
+  s.files += %w( third_party/boringssl/crypto/aes/internal.h )
+  s.files += %w( third_party/boringssl/crypto/asn1/asn1_locl.h )
+  s.files += %w( third_party/boringssl/crypto/bio/internal.h )
+  s.files += %w( third_party/boringssl/crypto/bn/internal.h )
+  s.files += %w( third_party/boringssl/crypto/bn/rsaz_exp.h )
+  s.files += %w( third_party/boringssl/crypto/bytestring/internal.h )
+  s.files += %w( third_party/boringssl/crypto/cipher/internal.h )
+  s.files += %w( third_party/boringssl/crypto/conf/conf_def.h )
+  s.files += %w( third_party/boringssl/crypto/conf/internal.h )
+  s.files += %w( third_party/boringssl/crypto/des/internal.h )
+  s.files += %w( third_party/boringssl/crypto/dh/internal.h )
+  s.files += %w( third_party/boringssl/crypto/digest/internal.h )
+  s.files += %w( third_party/boringssl/crypto/digest/md32_common.h )
+  s.files += %w( third_party/boringssl/crypto/directory.h )
+  s.files += %w( third_party/boringssl/crypto/dsa/internal.h )
+  s.files += %w( third_party/boringssl/crypto/ec/internal.h )
+  s.files += %w( third_party/boringssl/crypto/ec/p256-x86_64-table.h )
+  s.files += %w( third_party/boringssl/crypto/evp/internal.h )
+  s.files += %w( third_party/boringssl/crypto/internal.h )
+  s.files += %w( third_party/boringssl/crypto/modes/internal.h )
+  s.files += %w( third_party/boringssl/crypto/obj/obj_dat.h )
+  s.files += %w( third_party/boringssl/crypto/obj/obj_xref.h )
+  s.files += %w( third_party/boringssl/crypto/pkcs8/internal.h )
+  s.files += %w( third_party/boringssl/crypto/rand/internal.h )
+  s.files += %w( third_party/boringssl/crypto/rsa/internal.h )
+  s.files += %w( third_party/boringssl/crypto/test/scoped_types.h )
+  s.files += %w( third_party/boringssl/crypto/test/test_util.h )
+  s.files += %w( third_party/boringssl/crypto/x509/charmap.h )
+  s.files += %w( third_party/boringssl/crypto/x509/vpm_int.h )
+  s.files += %w( third_party/boringssl/crypto/x509v3/ext_dat.h )
+  s.files += %w( third_party/boringssl/crypto/x509v3/pcy_int.h )
+  s.files += %w( third_party/boringssl/include/openssl/aead.h )
+  s.files += %w( third_party/boringssl/include/openssl/aes.h )
+  s.files += %w( third_party/boringssl/include/openssl/arm_arch.h )
+  s.files += %w( third_party/boringssl/include/openssl/asn1.h )
+  s.files += %w( third_party/boringssl/include/openssl/asn1_mac.h )
+  s.files += %w( third_party/boringssl/include/openssl/asn1t.h )
+  s.files += %w( third_party/boringssl/include/openssl/base.h )
+  s.files += %w( third_party/boringssl/include/openssl/base64.h )
+  s.files += %w( third_party/boringssl/include/openssl/bio.h )
+  s.files += %w( third_party/boringssl/include/openssl/blowfish.h )
+  s.files += %w( third_party/boringssl/include/openssl/bn.h )
+  s.files += %w( third_party/boringssl/include/openssl/buf.h )
+  s.files += %w( third_party/boringssl/include/openssl/buffer.h )
+  s.files += %w( third_party/boringssl/include/openssl/bytestring.h )
+  s.files += %w( third_party/boringssl/include/openssl/cast.h )
+  s.files += %w( third_party/boringssl/include/openssl/chacha.h )
+  s.files += %w( third_party/boringssl/include/openssl/cipher.h )
+  s.files += %w( third_party/boringssl/include/openssl/cmac.h )
+  s.files += %w( third_party/boringssl/include/openssl/conf.h )
+  s.files += %w( third_party/boringssl/include/openssl/cpu.h )
+  s.files += %w( third_party/boringssl/include/openssl/crypto.h )
+  s.files += %w( third_party/boringssl/include/openssl/curve25519.h )
+  s.files += %w( third_party/boringssl/include/openssl/des.h )
+  s.files += %w( third_party/boringssl/include/openssl/dh.h )
+  s.files += %w( third_party/boringssl/include/openssl/digest.h )
+  s.files += %w( third_party/boringssl/include/openssl/dsa.h )
+  s.files += %w( third_party/boringssl/include/openssl/dtls1.h )
+  s.files += %w( third_party/boringssl/include/openssl/ec.h )
+  s.files += %w( third_party/boringssl/include/openssl/ec_key.h )
+  s.files += %w( third_party/boringssl/include/openssl/ecdh.h )
+  s.files += %w( third_party/boringssl/include/openssl/ecdsa.h )
+  s.files += %w( third_party/boringssl/include/openssl/engine.h )
+  s.files += %w( third_party/boringssl/include/openssl/err.h )
+  s.files += %w( third_party/boringssl/include/openssl/evp.h )
+  s.files += %w( third_party/boringssl/include/openssl/ex_data.h )
+  s.files += %w( third_party/boringssl/include/openssl/hkdf.h )
+  s.files += %w( third_party/boringssl/include/openssl/hmac.h )
+  s.files += %w( third_party/boringssl/include/openssl/lhash.h )
+  s.files += %w( third_party/boringssl/include/openssl/lhash_macros.h )
+  s.files += %w( third_party/boringssl/include/openssl/md4.h )
+  s.files += %w( third_party/boringssl/include/openssl/md5.h )
+  s.files += %w( third_party/boringssl/include/openssl/mem.h )
+  s.files += %w( third_party/boringssl/include/openssl/obj.h )
+  s.files += %w( third_party/boringssl/include/openssl/obj_mac.h )
+  s.files += %w( third_party/boringssl/include/openssl/objects.h )
+  s.files += %w( third_party/boringssl/include/openssl/opensslfeatures.h )
+  s.files += %w( third_party/boringssl/include/openssl/opensslv.h )
+  s.files += %w( third_party/boringssl/include/openssl/ossl_typ.h )
+  s.files += %w( third_party/boringssl/include/openssl/pem.h )
+  s.files += %w( third_party/boringssl/include/openssl/pkcs12.h )
+  s.files += %w( third_party/boringssl/include/openssl/pkcs7.h )
+  s.files += %w( third_party/boringssl/include/openssl/pkcs8.h )
+  s.files += %w( third_party/boringssl/include/openssl/poly1305.h )
+  s.files += %w( third_party/boringssl/include/openssl/pqueue.h )
+  s.files += %w( third_party/boringssl/include/openssl/rand.h )
+  s.files += %w( third_party/boringssl/include/openssl/rc4.h )
+  s.files += %w( third_party/boringssl/include/openssl/rsa.h )
+  s.files += %w( third_party/boringssl/include/openssl/safestack.h )
+  s.files += %w( third_party/boringssl/include/openssl/sha.h )
+  s.files += %w( third_party/boringssl/include/openssl/srtp.h )
+  s.files += %w( third_party/boringssl/include/openssl/ssl.h )
+  s.files += %w( third_party/boringssl/include/openssl/ssl3.h )
+  s.files += %w( third_party/boringssl/include/openssl/stack.h )
+  s.files += %w( third_party/boringssl/include/openssl/stack_macros.h )
+  s.files += %w( third_party/boringssl/include/openssl/thread.h )
+  s.files += %w( third_party/boringssl/include/openssl/time_support.h )
+  s.files += %w( third_party/boringssl/include/openssl/tls1.h )
+  s.files += %w( third_party/boringssl/include/openssl/type_check.h )
+  s.files += %w( third_party/boringssl/include/openssl/x509.h )
+  s.files += %w( third_party/boringssl/include/openssl/x509_vfy.h )
+  s.files += %w( third_party/boringssl/include/openssl/x509v3.h )
+  s.files += %w( third_party/boringssl/ssl/internal.h )
+  s.files += %w( third_party/boringssl/ssl/test/async_bio.h )
+  s.files += %w( third_party/boringssl/ssl/test/packeted_bio.h )
+  s.files += %w( third_party/boringssl/ssl/test/scoped_types.h )
+  s.files += %w( third_party/boringssl/ssl/test/test_config.h )
+  s.files += %w( src/boringssl/err_data.c )
+  s.files += %w( third_party/boringssl/crypto/aes/aes.c )
+  s.files += %w( third_party/boringssl/crypto/aes/mode_wrappers.c )
+  s.files += %w( third_party/boringssl/crypto/asn1/a_bitstr.c )
+  s.files += %w( third_party/boringssl/crypto/asn1/a_bool.c )
+  s.files += %w( third_party/boringssl/crypto/asn1/a_bytes.c )
+  s.files += %w( third_party/boringssl/crypto/asn1/a_d2i_fp.c )
+  s.files += %w( third_party/boringssl/crypto/asn1/a_dup.c )
+  s.files += %w( third_party/boringssl/crypto/asn1/a_enum.c )
+  s.files += %w( third_party/boringssl/crypto/asn1/a_gentm.c )
+  s.files += %w( third_party/boringssl/crypto/asn1/a_i2d_fp.c )
+  s.files += %w( third_party/boringssl/crypto/asn1/a_int.c )
+  s.files += %w( third_party/boringssl/crypto/asn1/a_mbstr.c )
+  s.files += %w( third_party/boringssl/crypto/asn1/a_object.c )
+  s.files += %w( third_party/boringssl/crypto/asn1/a_octet.c )
+  s.files += %w( third_party/boringssl/crypto/asn1/a_print.c )
+  s.files += %w( third_party/boringssl/crypto/asn1/a_strnid.c )
+  s.files += %w( third_party/boringssl/crypto/asn1/a_time.c )
+  s.files += %w( third_party/boringssl/crypto/asn1/a_type.c )
+  s.files += %w( third_party/boringssl/crypto/asn1/a_utctm.c )
+  s.files += %w( third_party/boringssl/crypto/asn1/a_utf8.c )
+  s.files += %w( third_party/boringssl/crypto/asn1/asn1_lib.c )
+  s.files += %w( third_party/boringssl/crypto/asn1/asn1_par.c )
+  s.files += %w( third_party/boringssl/crypto/asn1/asn_pack.c )
+  s.files += %w( third_party/boringssl/crypto/asn1/bio_asn1.c )
+  s.files += %w( third_party/boringssl/crypto/asn1/bio_ndef.c )
+  s.files += %w( third_party/boringssl/crypto/asn1/f_enum.c )
+  s.files += %w( third_party/boringssl/crypto/asn1/f_int.c )
+  s.files += %w( third_party/boringssl/crypto/asn1/f_string.c )
+  s.files += %w( third_party/boringssl/crypto/asn1/t_bitst.c )
+  s.files += %w( third_party/boringssl/crypto/asn1/t_pkey.c )
+  s.files += %w( third_party/boringssl/crypto/asn1/tasn_dec.c )
+  s.files += %w( third_party/boringssl/crypto/asn1/tasn_enc.c )
+  s.files += %w( third_party/boringssl/crypto/asn1/tasn_fre.c )
+  s.files += %w( third_party/boringssl/crypto/asn1/tasn_new.c )
+  s.files += %w( third_party/boringssl/crypto/asn1/tasn_prn.c )
+  s.files += %w( third_party/boringssl/crypto/asn1/tasn_typ.c )
+  s.files += %w( third_party/boringssl/crypto/asn1/tasn_utl.c )
+  s.files += %w( third_party/boringssl/crypto/asn1/x_bignum.c )
+  s.files += %w( third_party/boringssl/crypto/asn1/x_long.c )
+  s.files += %w( third_party/boringssl/crypto/base64/base64.c )
+  s.files += %w( third_party/boringssl/crypto/bio/bio.c )
+  s.files += %w( third_party/boringssl/crypto/bio/bio_mem.c )
+  s.files += %w( third_party/boringssl/crypto/bio/buffer.c )
+  s.files += %w( third_party/boringssl/crypto/bio/connect.c )
+  s.files += %w( third_party/boringssl/crypto/bio/fd.c )
+  s.files += %w( third_party/boringssl/crypto/bio/file.c )
+  s.files += %w( third_party/boringssl/crypto/bio/hexdump.c )
+  s.files += %w( third_party/boringssl/crypto/bio/pair.c )
+  s.files += %w( third_party/boringssl/crypto/bio/printf.c )
+  s.files += %w( third_party/boringssl/crypto/bio/socket.c )
+  s.files += %w( third_party/boringssl/crypto/bio/socket_helper.c )
+  s.files += %w( third_party/boringssl/crypto/bn/add.c )
+  s.files += %w( third_party/boringssl/crypto/bn/asm/x86_64-gcc.c )
+  s.files += %w( third_party/boringssl/crypto/bn/bn.c )
+  s.files += %w( third_party/boringssl/crypto/bn/bn_asn1.c )
+  s.files += %w( third_party/boringssl/crypto/bn/cmp.c )
+  s.files += %w( third_party/boringssl/crypto/bn/convert.c )
+  s.files += %w( third_party/boringssl/crypto/bn/ctx.c )
+  s.files += %w( third_party/boringssl/crypto/bn/div.c )
+  s.files += %w( third_party/boringssl/crypto/bn/exponentiation.c )
+  s.files += %w( third_party/boringssl/crypto/bn/gcd.c )
+  s.files += %w( third_party/boringssl/crypto/bn/generic.c )
+  s.files += %w( third_party/boringssl/crypto/bn/kronecker.c )
+  s.files += %w( third_party/boringssl/crypto/bn/montgomery.c )
+  s.files += %w( third_party/boringssl/crypto/bn/mul.c )
+  s.files += %w( third_party/boringssl/crypto/bn/prime.c )
+  s.files += %w( third_party/boringssl/crypto/bn/random.c )
+  s.files += %w( third_party/boringssl/crypto/bn/rsaz_exp.c )
+  s.files += %w( third_party/boringssl/crypto/bn/shift.c )
+  s.files += %w( third_party/boringssl/crypto/bn/sqrt.c )
+  s.files += %w( third_party/boringssl/crypto/buf/buf.c )
+  s.files += %w( third_party/boringssl/crypto/bytestring/ber.c )
+  s.files += %w( third_party/boringssl/crypto/bytestring/cbb.c )
+  s.files += %w( third_party/boringssl/crypto/bytestring/cbs.c )
+  s.files += %w( third_party/boringssl/crypto/chacha/chacha_generic.c )
+  s.files += %w( third_party/boringssl/crypto/chacha/chacha_vec.c )
+  s.files += %w( third_party/boringssl/crypto/cipher/aead.c )
+  s.files += %w( third_party/boringssl/crypto/cipher/cipher.c )
+  s.files += %w( third_party/boringssl/crypto/cipher/derive_key.c )
+  s.files += %w( third_party/boringssl/crypto/cipher/e_aes.c )
+  s.files += %w( third_party/boringssl/crypto/cipher/e_chacha20poly1305.c )
+  s.files += %w( third_party/boringssl/crypto/cipher/e_des.c )
+  s.files += %w( third_party/boringssl/crypto/cipher/e_null.c )
+  s.files += %w( third_party/boringssl/crypto/cipher/e_rc2.c )
+  s.files += %w( third_party/boringssl/crypto/cipher/e_rc4.c )
+  s.files += %w( third_party/boringssl/crypto/cipher/e_ssl3.c )
+  s.files += %w( third_party/boringssl/crypto/cipher/e_tls.c )
+  s.files += %w( third_party/boringssl/crypto/cipher/tls_cbc.c )
+  s.files += %w( third_party/boringssl/crypto/cmac/cmac.c )
+  s.files += %w( third_party/boringssl/crypto/conf/conf.c )
+  s.files += %w( third_party/boringssl/crypto/cpu-arm.c )
+  s.files += %w( third_party/boringssl/crypto/cpu-intel.c )
+  s.files += %w( third_party/boringssl/crypto/crypto.c )
+  s.files += %w( third_party/boringssl/crypto/curve25519/curve25519.c )
+  s.files += %w( third_party/boringssl/crypto/des/des.c )
+  s.files += %w( third_party/boringssl/crypto/dh/check.c )
+  s.files += %w( third_party/boringssl/crypto/dh/dh.c )
+  s.files += %w( third_party/boringssl/crypto/dh/dh_asn1.c )
+  s.files += %w( third_party/boringssl/crypto/dh/params.c )
+  s.files += %w( third_party/boringssl/crypto/digest/digest.c )
+  s.files += %w( third_party/boringssl/crypto/digest/digests.c )
+  s.files += %w( third_party/boringssl/crypto/directory_posix.c )
+  s.files += %w( third_party/boringssl/crypto/directory_win.c )
+  s.files += %w( third_party/boringssl/crypto/dsa/dsa.c )
+  s.files += %w( third_party/boringssl/crypto/dsa/dsa_asn1.c )
+  s.files += %w( third_party/boringssl/crypto/ec/ec.c )
+  s.files += %w( third_party/boringssl/crypto/ec/ec_asn1.c )
+  s.files += %w( third_party/boringssl/crypto/ec/ec_key.c )
+  s.files += %w( third_party/boringssl/crypto/ec/ec_montgomery.c )
+  s.files += %w( third_party/boringssl/crypto/ec/oct.c )
+  s.files += %w( third_party/boringssl/crypto/ec/p224-64.c )
+  s.files += %w( third_party/boringssl/crypto/ec/p256-64.c )
+  s.files += %w( third_party/boringssl/crypto/ec/p256-x86_64.c )
+  s.files += %w( third_party/boringssl/crypto/ec/simple.c )
+  s.files += %w( third_party/boringssl/crypto/ec/util-64.c )
+  s.files += %w( third_party/boringssl/crypto/ec/wnaf.c )
+  s.files += %w( third_party/boringssl/crypto/ecdh/ecdh.c )
+  s.files += %w( third_party/boringssl/crypto/ecdsa/ecdsa.c )
+  s.files += %w( third_party/boringssl/crypto/ecdsa/ecdsa_asn1.c )
+  s.files += %w( third_party/boringssl/crypto/engine/engine.c )
+  s.files += %w( third_party/boringssl/crypto/err/err.c )
+  s.files += %w( third_party/boringssl/crypto/evp/algorithm.c )
+  s.files += %w( third_party/boringssl/crypto/evp/digestsign.c )
+  s.files += %w( third_party/boringssl/crypto/evp/evp.c )
+  s.files += %w( third_party/boringssl/crypto/evp/evp_asn1.c )
+  s.files += %w( third_party/boringssl/crypto/evp/evp_ctx.c )
+  s.files += %w( third_party/boringssl/crypto/evp/p_dsa_asn1.c )
+  s.files += %w( third_party/boringssl/crypto/evp/p_ec.c )
+  s.files += %w( third_party/boringssl/crypto/evp/p_ec_asn1.c )
+  s.files += %w( third_party/boringssl/crypto/evp/p_rsa.c )
+  s.files += %w( third_party/boringssl/crypto/evp/p_rsa_asn1.c )
+  s.files += %w( third_party/boringssl/crypto/evp/pbkdf.c )
+  s.files += %w( third_party/boringssl/crypto/evp/sign.c )
+  s.files += %w( third_party/boringssl/crypto/ex_data.c )
+  s.files += %w( third_party/boringssl/crypto/hkdf/hkdf.c )
+  s.files += %w( third_party/boringssl/crypto/hmac/hmac.c )
+  s.files += %w( third_party/boringssl/crypto/lhash/lhash.c )
+  s.files += %w( third_party/boringssl/crypto/md4/md4.c )
+  s.files += %w( third_party/boringssl/crypto/md5/md5.c )
+  s.files += %w( third_party/boringssl/crypto/mem.c )
+  s.files += %w( third_party/boringssl/crypto/modes/cbc.c )
+  s.files += %w( third_party/boringssl/crypto/modes/cfb.c )
+  s.files += %w( third_party/boringssl/crypto/modes/ctr.c )
+  s.files += %w( third_party/boringssl/crypto/modes/gcm.c )
+  s.files += %w( third_party/boringssl/crypto/modes/ofb.c )
+  s.files += %w( third_party/boringssl/crypto/obj/obj.c )
+  s.files += %w( third_party/boringssl/crypto/obj/obj_xref.c )
+  s.files += %w( third_party/boringssl/crypto/pem/pem_all.c )
+  s.files += %w( third_party/boringssl/crypto/pem/pem_info.c )
+  s.files += %w( third_party/boringssl/crypto/pem/pem_lib.c )
+  s.files += %w( third_party/boringssl/crypto/pem/pem_oth.c )
+  s.files += %w( third_party/boringssl/crypto/pem/pem_pk8.c )
+  s.files += %w( third_party/boringssl/crypto/pem/pem_pkey.c )
+  s.files += %w( third_party/boringssl/crypto/pem/pem_x509.c )
+  s.files += %w( third_party/boringssl/crypto/pem/pem_xaux.c )
+  s.files += %w( third_party/boringssl/crypto/pkcs8/p5_pbe.c )
+  s.files += %w( third_party/boringssl/crypto/pkcs8/p5_pbev2.c )
+  s.files += %w( third_party/boringssl/crypto/pkcs8/p8_pkey.c )
+  s.files += %w( third_party/boringssl/crypto/pkcs8/pkcs8.c )
+  s.files += %w( third_party/boringssl/crypto/poly1305/poly1305.c )
+  s.files += %w( third_party/boringssl/crypto/poly1305/poly1305_arm.c )
+  s.files += %w( third_party/boringssl/crypto/poly1305/poly1305_vec.c )
+  s.files += %w( third_party/boringssl/crypto/rand/rand.c )
+  s.files += %w( third_party/boringssl/crypto/rand/urandom.c )
+  s.files += %w( third_party/boringssl/crypto/rand/windows.c )
+  s.files += %w( third_party/boringssl/crypto/rc4/rc4.c )
+  s.files += %w( third_party/boringssl/crypto/refcount_c11.c )
+  s.files += %w( third_party/boringssl/crypto/refcount_lock.c )
+  s.files += %w( third_party/boringssl/crypto/rsa/blinding.c )
+  s.files += %w( third_party/boringssl/crypto/rsa/padding.c )
+  s.files += %w( third_party/boringssl/crypto/rsa/rsa.c )
+  s.files += %w( third_party/boringssl/crypto/rsa/rsa_asn1.c )
+  s.files += %w( third_party/boringssl/crypto/rsa/rsa_impl.c )
+  s.files += %w( third_party/boringssl/crypto/sha/sha1.c )
+  s.files += %w( third_party/boringssl/crypto/sha/sha256.c )
+  s.files += %w( third_party/boringssl/crypto/sha/sha512.c )
+  s.files += %w( third_party/boringssl/crypto/stack/stack.c )
+  s.files += %w( third_party/boringssl/crypto/thread.c )
+  s.files += %w( third_party/boringssl/crypto/thread_none.c )
+  s.files += %w( third_party/boringssl/crypto/thread_pthread.c )
+  s.files += %w( third_party/boringssl/crypto/thread_win.c )
+  s.files += %w( third_party/boringssl/crypto/time_support.c )
+  s.files += %w( third_party/boringssl/crypto/x509/a_digest.c )
+  s.files += %w( third_party/boringssl/crypto/x509/a_sign.c )
+  s.files += %w( third_party/boringssl/crypto/x509/a_strex.c )
+  s.files += %w( third_party/boringssl/crypto/x509/a_verify.c )
+  s.files += %w( third_party/boringssl/crypto/x509/asn1_gen.c )
+  s.files += %w( third_party/boringssl/crypto/x509/by_dir.c )
+  s.files += %w( third_party/boringssl/crypto/x509/by_file.c )
+  s.files += %w( third_party/boringssl/crypto/x509/i2d_pr.c )
+  s.files += %w( third_party/boringssl/crypto/x509/pkcs7.c )
+  s.files += %w( third_party/boringssl/crypto/x509/t_crl.c )
+  s.files += %w( third_party/boringssl/crypto/x509/t_req.c )
+  s.files += %w( third_party/boringssl/crypto/x509/t_x509.c )
+  s.files += %w( third_party/boringssl/crypto/x509/t_x509a.c )
+  s.files += %w( third_party/boringssl/crypto/x509/x509.c )
+  s.files += %w( third_party/boringssl/crypto/x509/x509_att.c )
+  s.files += %w( third_party/boringssl/crypto/x509/x509_cmp.c )
+  s.files += %w( third_party/boringssl/crypto/x509/x509_d2.c )
+  s.files += %w( third_party/boringssl/crypto/x509/x509_def.c )
+  s.files += %w( third_party/boringssl/crypto/x509/x509_ext.c )
+  s.files += %w( third_party/boringssl/crypto/x509/x509_lu.c )
+  s.files += %w( third_party/boringssl/crypto/x509/x509_obj.c )
+  s.files += %w( third_party/boringssl/crypto/x509/x509_r2x.c )
+  s.files += %w( third_party/boringssl/crypto/x509/x509_req.c )
+  s.files += %w( third_party/boringssl/crypto/x509/x509_set.c )
+  s.files += %w( third_party/boringssl/crypto/x509/x509_trs.c )
+  s.files += %w( third_party/boringssl/crypto/x509/x509_txt.c )
+  s.files += %w( third_party/boringssl/crypto/x509/x509_v3.c )
+  s.files += %w( third_party/boringssl/crypto/x509/x509_vfy.c )
+  s.files += %w( third_party/boringssl/crypto/x509/x509_vpm.c )
+  s.files += %w( third_party/boringssl/crypto/x509/x509cset.c )
+  s.files += %w( third_party/boringssl/crypto/x509/x509name.c )
+  s.files += %w( third_party/boringssl/crypto/x509/x509rset.c )
+  s.files += %w( third_party/boringssl/crypto/x509/x509spki.c )
+  s.files += %w( third_party/boringssl/crypto/x509/x509type.c )
+  s.files += %w( third_party/boringssl/crypto/x509/x_algor.c )
+  s.files += %w( third_party/boringssl/crypto/x509/x_all.c )
+  s.files += %w( third_party/boringssl/crypto/x509/x_attrib.c )
+  s.files += %w( third_party/boringssl/crypto/x509/x_crl.c )
+  s.files += %w( third_party/boringssl/crypto/x509/x_exten.c )
+  s.files += %w( third_party/boringssl/crypto/x509/x_info.c )
+  s.files += %w( third_party/boringssl/crypto/x509/x_name.c )
+  s.files += %w( third_party/boringssl/crypto/x509/x_pkey.c )
+  s.files += %w( third_party/boringssl/crypto/x509/x_pubkey.c )
+  s.files += %w( third_party/boringssl/crypto/x509/x_req.c )
+  s.files += %w( third_party/boringssl/crypto/x509/x_sig.c )
+  s.files += %w( third_party/boringssl/crypto/x509/x_spki.c )
+  s.files += %w( third_party/boringssl/crypto/x509/x_val.c )
+  s.files += %w( third_party/boringssl/crypto/x509/x_x509.c )
+  s.files += %w( third_party/boringssl/crypto/x509/x_x509a.c )
+  s.files += %w( third_party/boringssl/crypto/x509v3/pcy_cache.c )
+  s.files += %w( third_party/boringssl/crypto/x509v3/pcy_data.c )
+  s.files += %w( third_party/boringssl/crypto/x509v3/pcy_lib.c )
+  s.files += %w( third_party/boringssl/crypto/x509v3/pcy_map.c )
+  s.files += %w( third_party/boringssl/crypto/x509v3/pcy_node.c )
+  s.files += %w( third_party/boringssl/crypto/x509v3/pcy_tree.c )
+  s.files += %w( third_party/boringssl/crypto/x509v3/v3_akey.c )
+  s.files += %w( third_party/boringssl/crypto/x509v3/v3_akeya.c )
+  s.files += %w( third_party/boringssl/crypto/x509v3/v3_alt.c )
+  s.files += %w( third_party/boringssl/crypto/x509v3/v3_bcons.c )
+  s.files += %w( third_party/boringssl/crypto/x509v3/v3_bitst.c )
+  s.files += %w( third_party/boringssl/crypto/x509v3/v3_conf.c )
+  s.files += %w( third_party/boringssl/crypto/x509v3/v3_cpols.c )
+  s.files += %w( third_party/boringssl/crypto/x509v3/v3_crld.c )
+  s.files += %w( third_party/boringssl/crypto/x509v3/v3_enum.c )
+  s.files += %w( third_party/boringssl/crypto/x509v3/v3_extku.c )
+  s.files += %w( third_party/boringssl/crypto/x509v3/v3_genn.c )
+  s.files += %w( third_party/boringssl/crypto/x509v3/v3_ia5.c )
+  s.files += %w( third_party/boringssl/crypto/x509v3/v3_info.c )
+  s.files += %w( third_party/boringssl/crypto/x509v3/v3_int.c )
+  s.files += %w( third_party/boringssl/crypto/x509v3/v3_lib.c )
+  s.files += %w( third_party/boringssl/crypto/x509v3/v3_ncons.c )
+  s.files += %w( third_party/boringssl/crypto/x509v3/v3_pci.c )
+  s.files += %w( third_party/boringssl/crypto/x509v3/v3_pcia.c )
+  s.files += %w( third_party/boringssl/crypto/x509v3/v3_pcons.c )
+  s.files += %w( third_party/boringssl/crypto/x509v3/v3_pku.c )
+  s.files += %w( third_party/boringssl/crypto/x509v3/v3_pmaps.c )
+  s.files += %w( third_party/boringssl/crypto/x509v3/v3_prn.c )
+  s.files += %w( third_party/boringssl/crypto/x509v3/v3_purp.c )
+  s.files += %w( third_party/boringssl/crypto/x509v3/v3_skey.c )
+  s.files += %w( third_party/boringssl/crypto/x509v3/v3_sxnet.c )
+  s.files += %w( third_party/boringssl/crypto/x509v3/v3_utl.c )
+  s.files += %w( third_party/boringssl/ssl/custom_extensions.c )
+  s.files += %w( third_party/boringssl/ssl/d1_both.c )
+  s.files += %w( third_party/boringssl/ssl/d1_clnt.c )
+  s.files += %w( third_party/boringssl/ssl/d1_lib.c )
+  s.files += %w( third_party/boringssl/ssl/d1_meth.c )
+  s.files += %w( third_party/boringssl/ssl/d1_pkt.c )
+  s.files += %w( third_party/boringssl/ssl/d1_srtp.c )
+  s.files += %w( third_party/boringssl/ssl/d1_srvr.c )
+  s.files += %w( third_party/boringssl/ssl/dtls_record.c )
+  s.files += %w( third_party/boringssl/ssl/pqueue/pqueue.c )
+  s.files += %w( third_party/boringssl/ssl/s3_both.c )
+  s.files += %w( third_party/boringssl/ssl/s3_clnt.c )
+  s.files += %w( third_party/boringssl/ssl/s3_enc.c )
+  s.files += %w( third_party/boringssl/ssl/s3_lib.c )
+  s.files += %w( third_party/boringssl/ssl/s3_meth.c )
+  s.files += %w( third_party/boringssl/ssl/s3_pkt.c )
+  s.files += %w( third_party/boringssl/ssl/s3_srvr.c )
+  s.files += %w( third_party/boringssl/ssl/ssl_aead_ctx.c )
+  s.files += %w( third_party/boringssl/ssl/ssl_asn1.c )
+  s.files += %w( third_party/boringssl/ssl/ssl_buffer.c )
+  s.files += %w( third_party/boringssl/ssl/ssl_cert.c )
+  s.files += %w( third_party/boringssl/ssl/ssl_cipher.c )
+  s.files += %w( third_party/boringssl/ssl/ssl_file.c )
+  s.files += %w( third_party/boringssl/ssl/ssl_lib.c )
+  s.files += %w( third_party/boringssl/ssl/ssl_rsa.c )
+  s.files += %w( third_party/boringssl/ssl/ssl_session.c )
+  s.files += %w( third_party/boringssl/ssl/ssl_stat.c )
+  s.files += %w( third_party/boringssl/ssl/t1_enc.c )
+  s.files += %w( third_party/boringssl/ssl/t1_lib.c )
+  s.files += %w( third_party/boringssl/ssl/tls_record.c )
+  s.files += %w( third_party/zlib/crc32.h )
+  s.files += %w( third_party/zlib/deflate.h )
+  s.files += %w( third_party/zlib/gzguts.h )
+  s.files += %w( third_party/zlib/inffast.h )
+  s.files += %w( third_party/zlib/inffixed.h )
+  s.files += %w( third_party/zlib/inflate.h )
+  s.files += %w( third_party/zlib/inftrees.h )
+  s.files += %w( third_party/zlib/trees.h )
+  s.files += %w( third_party/zlib/zconf.h )
+  s.files += %w( third_party/zlib/zlib.h )
+  s.files += %w( third_party/zlib/zutil.h )
+  s.files += %w( third_party/zlib/adler32.c )
+  s.files += %w( third_party/zlib/compress.c )
+  s.files += %w( third_party/zlib/crc32.c )
+  s.files += %w( third_party/zlib/deflate.c )
+  s.files += %w( third_party/zlib/gzclose.c )
+  s.files += %w( third_party/zlib/gzlib.c )
+  s.files += %w( third_party/zlib/gzread.c )
+  s.files += %w( third_party/zlib/gzwrite.c )
+  s.files += %w( third_party/zlib/infback.c )
+  s.files += %w( third_party/zlib/inffast.c )
+  s.files += %w( third_party/zlib/inflate.c )
+  s.files += %w( third_party/zlib/inftrees.c )
+  s.files += %w( third_party/zlib/trees.c )
+  s.files += %w( third_party/zlib/uncompr.c )
+  s.files += %w( third_party/zlib/zutil.c )
 end
diff --git a/include/grpc++/alarm.h b/include/grpc++/alarm.h
index 957d11c..9979c34 100644
--- a/include/grpc++/alarm.h
+++ b/include/grpc++/alarm.h
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -36,14 +36,18 @@
 #ifndef GRPCXX_ALARM_H
 #define GRPCXX_ALARM_H
 
-#include <grpc++/completion_queue.h>
-#include <grpc++/impl/grpc_library.h>
-#include <grpc++/support/time.h>
+#include <grpc++/impl/codegen/completion_queue_tag.h>
+#include <grpc++/impl/codegen/grpc_library.h>
+#include <grpc++/impl/codegen/time.h>
+
+struct grpc_alarm;
 
 namespace grpc {
 
+class CompletionQueue;
+
 /// A thin wrapper around \a grpc_alarm (see / \a / src/core/surface/alarm.h).
-class Alarm : public GrpcLibrary {
+class Alarm : private GrpcLibrary {
  public:
   /// Create a completion queue alarm instance associated to \a cq.
   ///
@@ -60,6 +64,19 @@
   void Cancel();
 
  private:
+  class AlarmEntry : public CompletionQueueTag {
+   public:
+    AlarmEntry(void* tag) : tag_(tag) {}
+    bool FinalizeResult(void** tag, bool* status) GRPC_OVERRIDE {
+      *tag = tag_;
+      return true;
+    }
+
+   private:
+    void* tag_;
+  };
+
+  AlarmEntry tag_;
   grpc_alarm* const alarm_;  // owned
 };
 
diff --git a/include/grpc++/channel.h b/include/grpc++/channel.h
index 541be13..80547f7 100644
--- a/include/grpc++/channel.h
+++ b/include/grpc++/channel.h
@@ -36,99 +36,48 @@
 
 #include <memory>
 
-#include <grpc/grpc.h>
 #include <grpc++/impl/call.h>
-#include <grpc++/impl/grpc_library.h>
-#include <grpc++/support/config.h>
+#include <grpc++/impl/codegen/channel_interface.h>
+#include <grpc++/impl/codegen/config.h>
+#include <grpc++/impl/codegen/grpc_library.h>
+#include <grpc/grpc.h>
 
 struct grpc_channel;
 
 namespace grpc {
-class CallOpSetInterface;
-class ChannelArguments;
-class CompletionQueue;
-class ChannelCredentials;
-class SecureChannelCredentials;
-
-template <class R>
-class ClientReader;
-template <class W>
-class ClientWriter;
-template <class W, class R>
-class ClientReaderWriter;
-template <class R>
-class ClientAsyncReader;
-template <class W>
-class ClientAsyncWriter;
-template <class W, class R>
-class ClientAsyncReaderWriter;
-template <class R>
-class ClientAsyncResponseReader;
-
 /// Channels represent a connection to an endpoint. Created by \a CreateChannel.
-class Channel GRPC_FINAL : public GrpcLibrary,
+class Channel GRPC_FINAL : public ChannelInterface,
                            public CallHook,
-                           public std::enable_shared_from_this<Channel> {
+                           public std::enable_shared_from_this<Channel>,
+                           private GrpcLibrary {
  public:
   ~Channel();
 
   /// Get the current channel state. If the channel is in IDLE and
   /// \a try_to_connect is set to true, try to connect.
-  grpc_connectivity_state GetState(bool try_to_connect);
-
-  /// Return the \a tag on \a cq when the channel state is changed or \a
-  /// deadline expires. \a GetState needs to called to get the current state.
-  template <typename T>
-  void NotifyOnStateChange(grpc_connectivity_state last_observed, T deadline,
-                           CompletionQueue* cq, void* tag) {
-    TimePoint<T> deadline_tp(deadline);
-    NotifyOnStateChangeImpl(last_observed, deadline_tp.raw_time(), cq, tag);
-  }
-
-  /// Blocking wait for channel state change or \a deadline expiration.
-  /// \a GetState needs to called to get the current state.
-  template <typename T>
-  bool WaitForStateChange(grpc_connectivity_state last_observed, T deadline) {
-    TimePoint<T> deadline_tp(deadline);
-    return WaitForStateChangeImpl(last_observed, deadline_tp.raw_time());
-  }
+  grpc_connectivity_state GetState(bool try_to_connect) GRPC_OVERRIDE;
 
  private:
-  template <class R>
-  friend class ::grpc::ClientReader;
-  template <class W>
-  friend class ::grpc::ClientWriter;
-  template <class W, class R>
-  friend class ::grpc::ClientReaderWriter;
-  template <class R>
-  friend class ::grpc::ClientAsyncReader;
-  template <class W>
-  friend class ::grpc::ClientAsyncWriter;
-  template <class W, class R>
-  friend class ::grpc::ClientAsyncReaderWriter;
-  template <class R>
-  friend class ::grpc::ClientAsyncResponseReader;
   template <class InputMessage, class OutputMessage>
-  friend Status BlockingUnaryCall(Channel* channel, const RpcMethod& method,
+  friend Status BlockingUnaryCall(ChannelInterface* channel,
+                                  const RpcMethod& method,
                                   ClientContext* context,
                                   const InputMessage& request,
                                   OutputMessage* result);
-  friend class ::grpc::RpcMethod;
   friend std::shared_ptr<Channel> CreateChannelInternal(
       const grpc::string& host, grpc_channel* c_channel);
-
   Channel(const grpc::string& host, grpc_channel* c_channel);
 
   Call CreateCall(const RpcMethod& method, ClientContext* context,
-                  CompletionQueue* cq);
-  void PerformOpsOnCall(CallOpSetInterface* ops, Call* call);
-  void* RegisterMethod(const char* method);
+                  CompletionQueue* cq) GRPC_OVERRIDE;
+  void PerformOpsOnCall(CallOpSetInterface* ops, Call* call) GRPC_OVERRIDE;
+  void* RegisterMethod(const char* method) GRPC_OVERRIDE;
 
   void NotifyOnStateChangeImpl(grpc_connectivity_state last_observed,
                                gpr_timespec deadline, CompletionQueue* cq,
-                               void* tag);
+                               void* tag) GRPC_OVERRIDE;
   bool WaitForStateChangeImpl(grpc_connectivity_state last_observed,
-                              gpr_timespec deadline);
+                              gpr_timespec deadline) GRPC_OVERRIDE;
 
   const grpc::string host_;
   grpc_channel* const c_channel_;  // owned
diff --git a/include/grpc++/client_context.h b/include/grpc++/client_context.h
index 4e8776e..3fbe6d1 100644
--- a/include/grpc++/client_context.h
+++ b/include/grpc++/client_context.h
@@ -49,303 +49,6 @@
 #ifndef GRPCXX_CLIENT_CONTEXT_H
 #define GRPCXX_CLIENT_CONTEXT_H
 
-#include <map>
-#include <memory>
-#include <string>
-
-#include <grpc++/impl/sync.h>
-#include <grpc++/security/auth_context.h>
-#include <grpc++/support/config.h>
-#include <grpc++/support/status.h>
-#include <grpc++/support/string_ref.h>
-#include <grpc++/support/time.h>
-#include <grpc/compression.h>
-#include <grpc/grpc.h>
-#include <grpc/support/log.h>
-#include <grpc/support/time.h>
-
-struct census_context;
-
-namespace grpc {
-
-class Channel;
-class CompletionQueue;
-class CallCredentials;
-class RpcMethod;
-template <class R>
-class ClientReader;
-template <class W>
-class ClientWriter;
-template <class W, class R>
-class ClientReaderWriter;
-template <class R>
-class ClientAsyncReader;
-template <class W>
-class ClientAsyncWriter;
-template <class W, class R>
-class ClientAsyncReaderWriter;
-template <class R>
-class ClientAsyncResponseReader;
-class ServerContext;
-
-/// Options for \a ClientContext::FromServerContext specifying which traits from
-/// the \a ServerContext to propagate (copy) from it into a new \a
-/// ClientContext.
-///
-/// \see ClientContext::FromServerContext
-class PropagationOptions {
- public:
-  PropagationOptions() : propagate_(GRPC_PROPAGATE_DEFAULTS) {}
-
-  PropagationOptions& enable_deadline_propagation() {
-    propagate_ |= GRPC_PROPAGATE_DEADLINE;
-    return *this;
-  }
-
-  PropagationOptions& disable_deadline_propagation() {
-    propagate_ &= ~GRPC_PROPAGATE_DEADLINE;
-    return *this;
-  }
-
-  PropagationOptions& enable_census_stats_propagation() {
-    propagate_ |= GRPC_PROPAGATE_CENSUS_STATS_CONTEXT;
-    return *this;
-  }
-
-  PropagationOptions& disable_census_stats_propagation() {
-    propagate_ &= ~GRPC_PROPAGATE_CENSUS_STATS_CONTEXT;
-    return *this;
-  }
-
-  PropagationOptions& enable_census_tracing_propagation() {
-    propagate_ |= GRPC_PROPAGATE_CENSUS_TRACING_CONTEXT;
-    return *this;
-  }
-
-  PropagationOptions& disable_census_tracing_propagation() {
-    propagate_ &= ~GRPC_PROPAGATE_CENSUS_TRACING_CONTEXT;
-    return *this;
-  }
-
-  PropagationOptions& enable_cancellation_propagation() {
-    propagate_ |= GRPC_PROPAGATE_CANCELLATION;
-    return *this;
-  }
-
-  PropagationOptions& disable_cancellation_propagation() {
-    propagate_ &= ~GRPC_PROPAGATE_CANCELLATION;
-    return *this;
-  }
-
-  uint32_t c_bitmask() const { return propagate_; }
-
- private:
-  uint32_t propagate_;
-};
-
-namespace testing {
-class InteropClientContextInspector;
-}  // namespace testing
-
-class ClientContext {
- public:
-  ClientContext();
-  ~ClientContext();
-
-  /// Create a new \a ClientContext as a child of an incoming server call,
-  /// according to \a options (\see PropagationOptions).
-  ///
-  /// \param server_context The source server context to use as the basis for
-  /// constructing the client context.
-  /// \param options The options controlling what to copy from the \a
-  /// server_context.
-  ///
-  /// \return A newly constructed \a ClientContext instance based on \a
-  /// server_context, with traits propagated (copied) according to \a options.
-  static std::unique_ptr<ClientContext> FromServerContext(
-      const ServerContext& server_context,
-      PropagationOptions options = PropagationOptions());
-
-  /// Add the (\a meta_key, \a meta_value) pair to the metadata associated with
-  /// a client call. These are made available at the server side by the \a
-  /// grpc::ServerContext::client_metadata() method.
-  ///
-  /// \warning This method should only be called before invoking the rpc.
-  ///
-  /// \param meta_key The metadata key. If \a meta_value is binary data, it must
-  /// end in "-bin".
-  /// \param meta_value The metadata value. If its value is binary, it must be
-  /// base64-encoding (see https://tools.ietf.org/html/rfc4648#section-4) and \a
-  /// meta_key must end in "-bin".
-  void AddMetadata(const grpc::string& meta_key,
-                   const grpc::string& meta_value);
-
-  /// Return a collection of initial metadata key-value pairs. Note that keys
-  /// may happen more than once (ie, a \a std::multimap is returned).
-  ///
-  /// \warning This method should only be called after initial metadata has been
-  /// received. For streaming calls, see \a
-  /// ClientReaderInterface::WaitForInitialMetadata().
-  ///
-  /// \return A multimap of initial metadata key-value pairs from the server.
-  const std::multimap<grpc::string_ref, grpc::string_ref>&
-  GetServerInitialMetadata() {
-    GPR_ASSERT(initial_metadata_received_);
-    return recv_initial_metadata_;
-  }
-
-  /// Return a collection of trailing metadata key-value pairs. Note that keys
-  /// may happen more than once (ie, a \a std::multimap is returned).
-  ///
-  /// \warning This method is only callable once the stream has finished.
-  ///
-  /// \return A multimap of metadata trailing key-value pairs from the server.
-  const std::multimap<grpc::string_ref, grpc::string_ref>&
-  GetServerTrailingMetadata() {
-    // TODO(yangg) check finished
-    return trailing_metadata_;
-  }
-
-  /// Set the deadline for the client call.
-  ///
-  /// \warning This method should only be called before invoking the rpc.
-  ///
-  /// \param deadline the deadline for the client call. Units are determined by
-  /// the type used.
-  template <typename T>
-  void set_deadline(const T& deadline) {
-    TimePoint<T> deadline_tp(deadline);
-    deadline_ = deadline_tp.raw_time();
-  }
-
-#ifndef GRPC_CXX0X_NO_CHRONO
-  /// Return the deadline for the client call.
-  std::chrono::system_clock::time_point deadline() {
-    return Timespec2Timepoint(deadline_);
-  }
-#endif  // !GRPC_CXX0X_NO_CHRONO
-
-  /// Return a \a gpr_timespec representation of the client call's deadline.
-  gpr_timespec raw_deadline() { return deadline_; }
-
-  /// Set the per call authority header (see
-  /// https://tools.ietf.org/html/rfc7540#section-8.1.2.3).
-  void set_authority(const grpc::string& authority) { authority_ = authority; }
-
-  /// Return the authentication context for this client call.
-  ///
-  /// \see grpc::AuthContext.
-  std::shared_ptr<const AuthContext> auth_context() const;
-
-  /// Set credentials for the client call.
-  ///
-  /// A credentials object encapsulates all the state needed by a client to
-  /// authenticate with a server and make various assertions, e.g., about the
-  /// client’s identity, role, or whether it is authorized to make a particular
-  /// call.
-  ///
-  /// \see  http://www.grpc.io/docs/guides/auth.html
-  void set_credentials(const std::shared_ptr<CallCredentials>& creds) {
-    creds_ = creds;
-  }
-
-  /// Return the compression algorithm to be used by the client call.
-  grpc_compression_algorithm compression_algorithm() const {
-    return compression_algorithm_;
-  }
-
-  /// Set \a algorithm to be the compression algorithm used for the client call.
-  ///
-  /// \param algorith The compression algorithm used for the client call.
-  void set_compression_algorithm(grpc_compression_algorithm algorithm);
-
-  /// Return the peer uri in a string.
-  ///
-  /// \warning This value is never authenticated or subject to any security
-  /// related code. It must not be used for any authentication related
-  /// functionality. Instead, use auth_context.
-  ///
-  /// \return The call's peer URI.
-  grpc::string peer() const;
-
-  /// Get and set census context.
-  void set_census_context(struct census_context* ccp) { census_context_ = ccp; }
-  struct census_context* census_context() const {
-    return census_context_;
-  }
-
-  /// Send a best-effort out-of-band cancel. The call could be in any stage.
-  /// e.g. if it is already finished, it may still return success.
-  ///
-  /// There is no guarantee the call will be cancelled.
-  void TryCancel();
-
-  /// Global Callbacks
-  ///
-  /// Can be set exactly once per application to install hooks whenever
-  /// a client context is constructed and destructed.
-  class GlobalCallbacks {
-   public:
-    virtual ~GlobalCallbacks() {}
-    virtual void DefaultConstructor(ClientContext* context) = 0;
-    virtual void Destructor(ClientContext* context) = 0;
-  };
-  static void SetGlobalCallbacks(GlobalCallbacks* callbacks);
-
- private:
-  // Disallow copy and assign.
-  ClientContext(const ClientContext&);
-  ClientContext& operator=(const ClientContext&);
-
-  friend class ::grpc::testing::InteropClientContextInspector;
-  friend class CallOpClientRecvStatus;
-  friend class CallOpRecvInitialMetadata;
-  friend class Channel;
-  template <class R>
-  friend class ::grpc::ClientReader;
-  template <class W>
-  friend class ::grpc::ClientWriter;
-  template <class W, class R>
-  friend class ::grpc::ClientReaderWriter;
-  template <class R>
-  friend class ::grpc::ClientAsyncReader;
-  template <class W>
-  friend class ::grpc::ClientAsyncWriter;
-  template <class W, class R>
-  friend class ::grpc::ClientAsyncReaderWriter;
-  template <class R>
-  friend class ::grpc::ClientAsyncResponseReader;
-  template <class InputMessage, class OutputMessage>
-  friend Status BlockingUnaryCall(Channel* channel, const RpcMethod& method,
-                                  ClientContext* context,
-                                  const InputMessage& request,
-                                  OutputMessage* result);
-
-  grpc_call* call() { return call_; }
-  void set_call(grpc_call* call, const std::shared_ptr<Channel>& channel);
-
-  grpc::string authority() { return authority_; }
-
-  bool initial_metadata_received_;
-  std::shared_ptr<Channel> channel_;
-  grpc::mutex mu_;
-  grpc_call* call_;
-  bool call_canceled_;
-  gpr_timespec deadline_;
-  grpc::string authority_;
-  std::shared_ptr<CallCredentials> creds_;
-  mutable std::shared_ptr<const AuthContext> auth_context_;
-  struct census_context* census_context_;
-  std::multimap<grpc::string, grpc::string> send_initial_metadata_;
-  std::multimap<grpc::string_ref, grpc::string_ref> recv_initial_metadata_;
-  std::multimap<grpc::string_ref, grpc::string_ref> trailing_metadata_;
-
-  grpc_call* propagate_from_call_;
-  PropagationOptions propagation_options_;
-
-  grpc_compression_algorithm compression_algorithm_;
-};
-
-}  // namespace grpc
+#include <grpc++/impl/codegen/client_context.h>
 
 #endif  // GRPCXX_CLIENT_CONTEXT_H
diff --git a/include/grpc++/completion_queue.h b/include/grpc++/completion_queue.h
index 5c2bc20..f53f5ee 100644
--- a/include/grpc++/completion_queue.h
+++ b/include/grpc++/completion_queue.h
@@ -31,182 +31,9 @@
  *
  */
 
-/// A completion queue implements a concurrent producer-consumer queue, with two
-/// main methods, \a Next and \a AsyncNext.
 #ifndef GRPCXX_COMPLETION_QUEUE_H
 #define GRPCXX_COMPLETION_QUEUE_H
 
-#include <grpc/support/time.h>
-#include <grpc++/impl/grpc_library.h>
-#include <grpc++/support/status.h>
-#include <grpc++/support/time.h>
-
-struct grpc_completion_queue;
-
-namespace grpc {
-
-template <class R>
-class ClientReader;
-template <class W>
-class ClientWriter;
-template <class W, class R>
-class ClientReaderWriter;
-template <class R>
-class ServerReader;
-template <class W>
-class ServerWriter;
-template <class W, class R>
-class ServerReaderWriter;
-template <class ServiceType, class RequestType, class ResponseType>
-class RpcMethodHandler;
-template <class ServiceType, class RequestType, class ResponseType>
-class ClientStreamingHandler;
-template <class ServiceType, class RequestType, class ResponseType>
-class ServerStreamingHandler;
-template <class ServiceType, class RequestType, class ResponseType>
-class BidiStreamingHandler;
-class UnknownMethodHandler;
-
-class Channel;
-class ClientContext;
-class CompletionQueueTag;
-class CompletionQueue;
-class RpcMethod;
-class Server;
-class ServerBuilder;
-class ServerContext;
-
-/// A thin wrapper around \a grpc_completion_queue (see / \a
-/// src/core/surface/completion_queue.h).
-class CompletionQueue : public GrpcLibrary {
- public:
-  /// Default constructor. Implicitly creates a \a grpc_completion_queue
-  /// instance.
-  CompletionQueue();
-
-  /// Wrap \a take, taking ownership of the instance.
-  ///
-  /// \param take The completion queue instance to wrap. Ownership is taken.
-  explicit CompletionQueue(grpc_completion_queue* take);
-
-  /// Destructor. Destroys the owned wrapped completion queue / instance.
-  ~CompletionQueue() GRPC_OVERRIDE;
-
-  /// Tri-state return for AsyncNext: SHUTDOWN, GOT_EVENT, TIMEOUT.
-  enum NextStatus {
-    SHUTDOWN,   ///< The completion queue has been shutdown.
-    GOT_EVENT,  ///< Got a new event; \a tag will be filled in with its
-                ///< associated value; \a ok indicating its success.
-    TIMEOUT     ///< deadline was reached.
-  };
-
-  /// Read from the queue, blocking up to \a deadline (or the queue's shutdown).
-  /// Both \a tag and \a ok are updated upon success (if an event is available
-  /// within the \a deadline).  A \a tag points to an arbitrary location usually
-  /// employed to uniquely identify an event.
-  ///
-  /// \param tag[out] Upon sucess, updated to point to the event's tag.
-  /// \param ok[out] Upon sucess, true if read a regular event, false otherwise.
-  /// \param deadline[in] How long to block in wait for an event.
-  ///
-  /// \return The type of event read.
-  template <typename T>
-  NextStatus AsyncNext(void** tag, bool* ok, const T& deadline) {
-    TimePoint<T> deadline_tp(deadline);
-    return AsyncNextInternal(tag, ok, deadline_tp.raw_time());
-  }
-
-  /// Read from the queue, blocking until an event is available or the queue is
-  /// shutting down.
-  ///
-  /// \param tag[out] Updated to point to the read event's tag.
-  /// \param ok[out] true if read a regular event, false otherwise.
-  ///
-  /// \return true if read a regular event, false if the queue is shutting down.
-  bool Next(void** tag, bool* ok) {
-    return (AsyncNextInternal(tag, ok, gpr_inf_future(GPR_CLOCK_REALTIME)) !=
-            SHUTDOWN);
-  }
-
-  /// Request the shutdown of the queue.
-  ///
-  /// \warning This method must be called at some point. Once invoked, \a Next
-  /// will start to return false and \a AsyncNext will return \a
-  /// NextStatus::SHUTDOWN. Only once either one of these methods does that
-  /// (that is, once the queue has been \em drained) can an instance of this
-  /// class be destroyed.
-  void Shutdown();
-
-  /// Returns a \em raw pointer to the underlying \a grpc_completion_queue
-  /// instance.
-  ///
-  /// \warning Remember that the returned instance is owned. No transfer of
-  /// owership is performed.
-  grpc_completion_queue* cq() { return cq_; }
-
- private:
-  // Friend synchronous wrappers so that they can access Pluck(), which is
-  // a semi-private API geared towards the synchronous implementation.
-  template <class R>
-  friend class ::grpc::ClientReader;
-  template <class W>
-  friend class ::grpc::ClientWriter;
-  template <class W, class R>
-  friend class ::grpc::ClientReaderWriter;
-  template <class R>
-  friend class ::grpc::ServerReader;
-  template <class W>
-  friend class ::grpc::ServerWriter;
-  template <class W, class R>
-  friend class ::grpc::ServerReaderWriter;
-  template <class ServiceType, class RequestType, class ResponseType>
-  friend class RpcMethodHandler;
-  template <class ServiceType, class RequestType, class ResponseType>
-  friend class ClientStreamingHandler;
-  template <class ServiceType, class RequestType, class ResponseType>
-  friend class ServerStreamingHandler;
-  template <class ServiceType, class RequestType, class ResponseType>
-  friend class BidiStreamingHandler;
-  friend class UnknownMethodHandler;
-  friend class ::grpc::Server;
-  friend class ::grpc::ServerContext;
-  template <class InputMessage, class OutputMessage>
-  friend Status BlockingUnaryCall(Channel* channel, const RpcMethod& method,
-                                  ClientContext* context,
-                                  const InputMessage& request,
-                                  OutputMessage* result);
-
-  NextStatus AsyncNextInternal(void** tag, bool* ok, gpr_timespec deadline);
-
-  /// Wraps \a grpc_completion_queue_pluck.
-  /// \warning Must not be mixed with calls to \a Next.
-  bool Pluck(CompletionQueueTag* tag);
-
-  /// Performs a single polling pluck on \a tag.
-  void TryPluck(CompletionQueueTag* tag);
-
-  grpc_completion_queue* cq_;  // owned
-};
-
-/// An interface allowing implementors to process and filter event tags.
-class CompletionQueueTag {
- public:
-  virtual ~CompletionQueueTag() {}
-  // Called prior to returning from Next(), return value is the status of the
-  // operation (return status is the default thing to do). If this function
-  // returns false, the tag is dropped and not returned from the completion
-  // queue
-  virtual bool FinalizeResult(void** tag, bool* status) = 0;
-};
-
-/// A specific type of completion queue used by the processing of notifications
-/// by servers. Instantiated by \a ServerBuilder.
-class ServerCompletionQueue : public CompletionQueue {
- private:
-  friend class ServerBuilder;
-  ServerCompletionQueue() {}
-};
-
-}  // namespace grpc
+#include <grpc++/impl/codegen/completion_queue.h>
 
 #endif  // GRPCXX_COMPLETION_QUEUE_H
diff --git a/include/grpc++/generic/async_generic_service.h b/include/grpc++/generic/async_generic_service.h
index 57a2696..9ae8391 100644
--- a/include/grpc++/generic/async_generic_service.h
+++ b/include/grpc++/generic/async_generic_service.h
@@ -51,6 +51,7 @@
 
  private:
   friend class Server;
+  friend class ServerInterface;
 
   grpc::string method_;
   grpc::string host_;
@@ -58,11 +59,7 @@
 
 class AsyncGenericService GRPC_FINAL {
  public:
-  // TODO(yangg) Once we can add multiple completion queues to the server
-  // in c core, add a CompletionQueue* argument to the ctor here.
-  // TODO(yangg) support methods list.
   AsyncGenericService() : server_(nullptr) {}
-  AsyncGenericService(const grpc::string& methods) : server_(nullptr) {}
 
   void RequestCall(GenericServerContext* ctx,
                    GenericServerAsyncReaderWriter* reader_writer,
diff --git a/include/grpc++/generic/generic_stub.h b/include/grpc++/generic/generic_stub.h
index 1bb7900..5ac0371 100644
--- a/include/grpc++/generic/generic_stub.h
+++ b/include/grpc++/generic/generic_stub.h
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -47,7 +47,8 @@
 // by name.
 class GenericStub GRPC_FINAL {
  public:
-  explicit GenericStub(std::shared_ptr<Channel> channel) : channel_(channel) {}
+  explicit GenericStub(std::shared_ptr<ChannelInterface> channel)
+      : channel_(channel) {}
 
   // begin a call to a named method
   std::unique_ptr<GenericClientAsyncReaderWriter> Call(
@@ -55,7 +56,7 @@
       void* tag);
 
  private:
-  std::shared_ptr<Channel> channel_;
+  std::shared_ptr<ChannelInterface> channel_;
 };
 
 }  // namespace grpc
diff --git a/include/grpc++/impl/call.h b/include/grpc++/impl/call.h
index cb7856b..64b6563 100644
--- a/include/grpc++/impl/call.h
+++ b/include/grpc++/impl/call.h
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -34,549 +34,6 @@
 #ifndef GRPCXX_IMPL_CALL_H
 #define GRPCXX_IMPL_CALL_H
 
-#include <functional>
-#include <memory>
-#include <map>
-#include <cstring>
-
-#include <grpc/support/alloc.h>
-#include <grpc++/client_context.h>
-#include <grpc++/completion_queue.h>
-#include <grpc++/impl/serialization_traits.h>
-#include <grpc++/support/config.h>
-#include <grpc++/support/status.h>
-
-struct grpc_call;
-struct grpc_op;
-
-namespace grpc {
-
-class ByteBuffer;
-class Call;
-
-void FillMetadataMap(
-    grpc_metadata_array* arr,
-    std::multimap<grpc::string_ref, grpc::string_ref>* metadata);
-grpc_metadata* FillMetadataArray(
-    const std::multimap<grpc::string, grpc::string>& metadata);
-
-/// Per-message write options.
-class WriteOptions {
- public:
-  WriteOptions() : flags_(0) {}
-  WriteOptions(const WriteOptions& other) : flags_(other.flags_) {}
-
-  /// Clear all flags.
-  inline void Clear() { flags_ = 0; }
-
-  /// Returns raw flags bitset.
-  inline uint32_t flags() const { return flags_; }
-
-  /// Sets flag for the disabling of compression for the next message write.
-  ///
-  /// \sa GRPC_WRITE_NO_COMPRESS
-  inline WriteOptions& set_no_compression() {
-    SetBit(GRPC_WRITE_NO_COMPRESS);
-    return *this;
-  }
-
-  /// Clears flag for the disabling of compression for the next message write.
-  ///
-  /// \sa GRPC_WRITE_NO_COMPRESS
-  inline WriteOptions& clear_no_compression() {
-    ClearBit(GRPC_WRITE_NO_COMPRESS);
-    return *this;
-  }
-
-  /// Get value for the flag indicating whether compression for the next
-  /// message write is forcefully disabled.
-  ///
-  /// \sa GRPC_WRITE_NO_COMPRESS
-  inline bool get_no_compression() const {
-    return GetBit(GRPC_WRITE_NO_COMPRESS);
-  }
-
-  /// Sets flag indicating that the write may be buffered and need not go out on
-  /// the wire immediately.
-  ///
-  /// \sa GRPC_WRITE_BUFFER_HINT
-  inline WriteOptions& set_buffer_hint() {
-    SetBit(GRPC_WRITE_BUFFER_HINT);
-    return *this;
-  }
-
-  /// Clears flag indicating that the write may be buffered and need not go out
-  /// on the wire immediately.
-  ///
-  /// \sa GRPC_WRITE_BUFFER_HINT
-  inline WriteOptions& clear_buffer_hint() {
-    ClearBit(GRPC_WRITE_BUFFER_HINT);
-    return *this;
-  }
-
-  /// Get value for the flag indicating that the write may be buffered and need
-  /// not go out on the wire immediately.
-  ///
-  /// \sa GRPC_WRITE_BUFFER_HINT
-  inline bool get_buffer_hint() const { return GetBit(GRPC_WRITE_BUFFER_HINT); }
-
-  WriteOptions& operator=(const WriteOptions& rhs) {
-    flags_ = rhs.flags_;
-    return *this;
-  }
-
- private:
-  void SetBit(const uint32_t mask) { flags_ |= mask; }
-
-  void ClearBit(const uint32_t mask) { flags_ &= ~mask; }
-
-  bool GetBit(const uint32_t mask) const { return (flags_ & mask) != 0; }
-
-  uint32_t flags_;
-};
-
-/// Default argument for CallOpSet. I is unused by the class, but can be
-/// used for generating multiple names for the same thing.
-template <int I>
-class CallNoOp {
- protected:
-  void AddOp(grpc_op* ops, size_t* nops) {}
-  void FinishOp(bool* status, int max_message_size) {}
-};
-
-class CallOpSendInitialMetadata {
- public:
-  CallOpSendInitialMetadata() : send_(false) {}
-
-  void SendInitialMetadata(
-      const std::multimap<grpc::string, grpc::string>& metadata) {
-    send_ = true;
-    initial_metadata_count_ = metadata.size();
-    initial_metadata_ = FillMetadataArray(metadata);
-  }
-
- protected:
-  void AddOp(grpc_op* ops, size_t* nops) {
-    if (!send_) return;
-    grpc_op* op = &ops[(*nops)++];
-    op->op = GRPC_OP_SEND_INITIAL_METADATA;
-    op->flags = 0;
-    op->reserved = NULL;
-    op->data.send_initial_metadata.count = initial_metadata_count_;
-    op->data.send_initial_metadata.metadata = initial_metadata_;
-  }
-  void FinishOp(bool* status, int max_message_size) {
-    if (!send_) return;
-    gpr_free(initial_metadata_);
-    send_ = false;
-  }
-
-  bool send_;
-  size_t initial_metadata_count_;
-  grpc_metadata* initial_metadata_;
-};
-
-class CallOpSendMessage {
- public:
-  CallOpSendMessage() : send_buf_(nullptr), own_buf_(false) {}
-
-  /// Send \a message using \a options for the write. The \a options are cleared
-  /// after use.
-  template <class M>
-  Status SendMessage(const M& message,
-                     const WriteOptions& options) GRPC_MUST_USE_RESULT;
-
-  template <class M>
-  Status SendMessage(const M& message) GRPC_MUST_USE_RESULT;
-
- protected:
-  void AddOp(grpc_op* ops, size_t* nops) {
-    if (send_buf_ == nullptr) return;
-    grpc_op* op = &ops[(*nops)++];
-    op->op = GRPC_OP_SEND_MESSAGE;
-    op->flags = write_options_.flags();
-    op->reserved = NULL;
-    op->data.send_message = send_buf_;
-    // Flags are per-message: clear them after use.
-    write_options_.Clear();
-  }
-  void FinishOp(bool* status, int max_message_size) {
-    if (own_buf_) grpc_byte_buffer_destroy(send_buf_);
-    send_buf_ = nullptr;
-  }
-
- private:
-  grpc_byte_buffer* send_buf_;
-  WriteOptions write_options_;
-  bool own_buf_;
-};
-
-template <class M>
-Status CallOpSendMessage::SendMessage(const M& message,
-                                      const WriteOptions& options) {
-  write_options_ = options;
-  return SerializationTraits<M>::Serialize(message, &send_buf_, &own_buf_);
-}
-
-template <class M>
-Status CallOpSendMessage::SendMessage(const M& message) {
-  return SendMessage(message, WriteOptions());
-}
-
-template <class R>
-class CallOpRecvMessage {
- public:
-  CallOpRecvMessage() : got_message(false), message_(nullptr) {}
-
-  void RecvMessage(R* message) { message_ = message; }
-
-  bool got_message;
-
- protected:
-  void AddOp(grpc_op* ops, size_t* nops) {
-    if (message_ == nullptr) return;
-    grpc_op* op = &ops[(*nops)++];
-    op->op = GRPC_OP_RECV_MESSAGE;
-    op->flags = 0;
-    op->reserved = NULL;
-    op->data.recv_message = &recv_buf_;
-  }
-
-  void FinishOp(bool* status, int max_message_size) {
-    if (message_ == nullptr) return;
-    if (recv_buf_) {
-      if (*status) {
-        got_message = true;
-        *status = SerializationTraits<R>::Deserialize(recv_buf_, message_,
-                                                      max_message_size).ok();
-      } else {
-        got_message = false;
-        grpc_byte_buffer_destroy(recv_buf_);
-      }
-    } else {
-      got_message = false;
-      *status = false;
-    }
-    message_ = nullptr;
-  }
-
- private:
-  R* message_;
-  grpc_byte_buffer* recv_buf_;
-};
-
-namespace CallOpGenericRecvMessageHelper {
-class DeserializeFunc {
- public:
-  virtual Status Deserialize(grpc_byte_buffer* buf, int max_message_size) = 0;
-};
-
-template <class R>
-class DeserializeFuncType GRPC_FINAL : public DeserializeFunc {
- public:
-  DeserializeFuncType(R* message) : message_(message) {}
-  Status Deserialize(grpc_byte_buffer* buf,
-                     int max_message_size) GRPC_OVERRIDE {
-    return SerializationTraits<R>::Deserialize(buf, message_, max_message_size);
-  }
-
- private:
-  R* message_;  // Not a managed pointer because management is external to this
-};
-}  // namespace CallOpGenericRecvMessageHelper
-
-class CallOpGenericRecvMessage {
- public:
-  CallOpGenericRecvMessage() : got_message(false) {}
-
-  template <class R>
-  void RecvMessage(R* message) {
-    deserialize_.reset(
-        new CallOpGenericRecvMessageHelper::DeserializeFuncType<R>(message));
-  }
-
-  bool got_message;
-
- protected:
-  void AddOp(grpc_op* ops, size_t* nops) {
-    if (!deserialize_) return;
-    grpc_op* op = &ops[(*nops)++];
-    op->op = GRPC_OP_RECV_MESSAGE;
-    op->flags = 0;
-    op->reserved = NULL;
-    op->data.recv_message = &recv_buf_;
-  }
-
-  void FinishOp(bool* status, int max_message_size) {
-    if (!deserialize_) return;
-    if (recv_buf_) {
-      if (*status) {
-        got_message = true;
-        *status = deserialize_->Deserialize(recv_buf_, max_message_size).ok();
-      } else {
-        got_message = false;
-        grpc_byte_buffer_destroy(recv_buf_);
-      }
-    } else {
-      got_message = false;
-      *status = false;
-    }
-    deserialize_.reset();
-  }
-
- private:
-  std::unique_ptr<CallOpGenericRecvMessageHelper::DeserializeFunc> deserialize_;
-  grpc_byte_buffer* recv_buf_;
-};
-
-class CallOpClientSendClose {
- public:
-  CallOpClientSendClose() : send_(false) {}
-
-  void ClientSendClose() { send_ = true; }
-
- protected:
-  void AddOp(grpc_op* ops, size_t* nops) {
-    if (!send_) return;
-    grpc_op* op = &ops[(*nops)++];
-    op->op = GRPC_OP_SEND_CLOSE_FROM_CLIENT;
-    op->flags = 0;
-    op->reserved = NULL;
-  }
-  void FinishOp(bool* status, int max_message_size) { send_ = false; }
-
- private:
-  bool send_;
-};
-
-class CallOpServerSendStatus {
- public:
-  CallOpServerSendStatus() : send_status_available_(false) {}
-
-  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_status_available_ = true;
-    send_status_code_ = static_cast<grpc_status_code>(status.error_code());
-    send_status_details_ = status.error_message();
-  }
-
- protected:
-  void AddOp(grpc_op* ops, size_t* nops) {
-    if (!send_status_available_) return;
-    grpc_op* op = &ops[(*nops)++];
-    op->op = GRPC_OP_SEND_STATUS_FROM_SERVER;
-    op->data.send_status_from_server.trailing_metadata_count =
-        trailing_metadata_count_;
-    op->data.send_status_from_server.trailing_metadata = trailing_metadata_;
-    op->data.send_status_from_server.status = send_status_code_;
-    op->data.send_status_from_server.status_details =
-        send_status_details_.empty() ? nullptr : send_status_details_.c_str();
-    op->flags = 0;
-    op->reserved = NULL;
-  }
-
-  void FinishOp(bool* status, int max_message_size) {
-    if (!send_status_available_) return;
-    gpr_free(trailing_metadata_);
-    send_status_available_ = false;
-  }
-
- private:
-  bool send_status_available_;
-  grpc_status_code send_status_code_;
-  grpc::string send_status_details_;
-  size_t trailing_metadata_count_;
-  grpc_metadata* trailing_metadata_;
-};
-
-class CallOpRecvInitialMetadata {
- public:
-  CallOpRecvInitialMetadata() : recv_initial_metadata_(nullptr) {}
-
-  void RecvInitialMetadata(ClientContext* context) {
-    context->initial_metadata_received_ = true;
-    recv_initial_metadata_ = &context->recv_initial_metadata_;
-  }
-
- protected:
-  void AddOp(grpc_op* ops, size_t* nops) {
-    if (!recv_initial_metadata_) return;
-    memset(&recv_initial_metadata_arr_, 0, sizeof(recv_initial_metadata_arr_));
-    grpc_op* op = &ops[(*nops)++];
-    op->op = GRPC_OP_RECV_INITIAL_METADATA;
-    op->data.recv_initial_metadata = &recv_initial_metadata_arr_;
-    op->flags = 0;
-    op->reserved = NULL;
-  }
-  void FinishOp(bool* status, int max_message_size) {
-    if (recv_initial_metadata_ == nullptr) return;
-    FillMetadataMap(&recv_initial_metadata_arr_, recv_initial_metadata_);
-    recv_initial_metadata_ = nullptr;
-  }
-
- private:
-  std::multimap<grpc::string_ref, grpc::string_ref>* recv_initial_metadata_;
-  grpc_metadata_array recv_initial_metadata_arr_;
-};
-
-class CallOpClientRecvStatus {
- public:
-  CallOpClientRecvStatus() : recv_status_(nullptr) {}
-
-  void ClientRecvStatus(ClientContext* context, Status* status) {
-    recv_trailing_metadata_ = &context->trailing_metadata_;
-    recv_status_ = status;
-  }
-
- protected:
-  void AddOp(grpc_op* ops, size_t* nops) {
-    if (recv_status_ == nullptr) return;
-    memset(&recv_trailing_metadata_arr_, 0,
-           sizeof(recv_trailing_metadata_arr_));
-    status_details_ = nullptr;
-    status_details_capacity_ = 0;
-    grpc_op* op = &ops[(*nops)++];
-    op->op = GRPC_OP_RECV_STATUS_ON_CLIENT;
-    op->data.recv_status_on_client.trailing_metadata =
-        &recv_trailing_metadata_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_capacity =
-        &status_details_capacity_;
-    op->flags = 0;
-    op->reserved = NULL;
-  }
-
-  void FinishOp(bool* status, int max_message_size) {
-    if (recv_status_ == nullptr) return;
-    FillMetadataMap(&recv_trailing_metadata_arr_, recv_trailing_metadata_);
-    *recv_status_ = Status(
-        static_cast<StatusCode>(status_code_),
-        status_details_ ? grpc::string(status_details_) : grpc::string());
-    gpr_free(status_details_);
-    recv_status_ = nullptr;
-  }
-
- private:
-  std::multimap<grpc::string_ref, grpc::string_ref>* recv_trailing_metadata_;
-  Status* recv_status_;
-  grpc_metadata_array recv_trailing_metadata_arr_;
-  grpc_status_code status_code_;
-  char* status_details_;
-  size_t status_details_capacity_;
-};
-
-/// An abstract collection of call ops, used to generate the
-/// grpc_call_op structure to pass down to the lower layers,
-/// and as it is-a CompletionQueueTag, also massages the final
-/// completion into the correct form for consumption in the C++
-/// API.
-class CallOpSetInterface : public CompletionQueueTag {
- public:
-  CallOpSetInterface() : max_message_size_(0) {}
-  /// Fills in grpc_op, starting from ops[*nops] and moving
-  /// upwards.
-  virtual void FillOps(grpc_op* ops, size_t* nops) = 0;
-
-  void set_max_message_size(int max_message_size) {
-    max_message_size_ = max_message_size;
-  }
-
- protected:
-  int max_message_size_;
-};
-
-/// Primary implementaiton of CallOpSetInterface.
-/// Since we cannot use variadic templates, we declare slots up to
-/// the maximum count of ops we'll need in a set. We leverage the
-/// empty base class optimization to slim this class (especially
-/// when there are many unused slots used). To avoid duplicate base classes,
-/// the template parmeter for CallNoOp is varied by argument position.
-template <class Op1 = CallNoOp<1>, class Op2 = CallNoOp<2>,
-          class Op3 = CallNoOp<3>, class Op4 = CallNoOp<4>,
-          class Op5 = CallNoOp<5>, class Op6 = CallNoOp<6>>
-class CallOpSet : public CallOpSetInterface,
-                  public Op1,
-                  public Op2,
-                  public Op3,
-                  public Op4,
-                  public Op5,
-                  public Op6 {
- public:
-  CallOpSet() : return_tag_(this) {}
-  void FillOps(grpc_op* ops, size_t* nops) GRPC_OVERRIDE {
-    this->Op1::AddOp(ops, nops);
-    this->Op2::AddOp(ops, nops);
-    this->Op3::AddOp(ops, nops);
-    this->Op4::AddOp(ops, nops);
-    this->Op5::AddOp(ops, nops);
-    this->Op6::AddOp(ops, nops);
-  }
-
-  bool FinalizeResult(void** tag, bool* status) GRPC_OVERRIDE {
-    this->Op1::FinishOp(status, max_message_size_);
-    this->Op2::FinishOp(status, max_message_size_);
-    this->Op3::FinishOp(status, max_message_size_);
-    this->Op4::FinishOp(status, max_message_size_);
-    this->Op5::FinishOp(status, max_message_size_);
-    this->Op6::FinishOp(status, max_message_size_);
-    *tag = return_tag_;
-    return true;
-  }
-
-  void set_output_tag(void* return_tag) { return_tag_ = return_tag; }
-
- private:
-  void* return_tag_;
-};
-
-/// A CallOpSet that does not post completions to the completion queue.
-///
-/// Allows hiding some completions that the C core must generate from
-/// C++ users.
-template <class Op1 = CallNoOp<1>, class Op2 = CallNoOp<2>,
-          class Op3 = CallNoOp<3>, class Op4 = CallNoOp<4>,
-          class Op5 = CallNoOp<5>, class Op6 = CallNoOp<6>>
-class SneakyCallOpSet : public CallOpSet<Op1, Op2, Op3, Op4, Op5, Op6> {
- public:
-  bool FinalizeResult(void** tag, bool* status) GRPC_OVERRIDE {
-    typedef CallOpSet<Op1, Op2, Op3, Op4, Op5, Op6> Base;
-    return Base::FinalizeResult(tag, status) && false;
-  }
-};
-
-// Channel and Server implement this to allow them to hook performing ops
-class CallHook {
- public:
-  virtual ~CallHook() {}
-  virtual void PerformOpsOnCall(CallOpSetInterface* ops, Call* call) = 0;
-};
-
-// Straightforward wrapping of the C call object
-class Call GRPC_FINAL {
- public:
-  /* call is owned by the caller */
-  Call(grpc_call* call, CallHook* call_hook_, CompletionQueue* cq);
-  Call(grpc_call* call, CallHook* call_hook_, CompletionQueue* cq,
-       int max_message_size);
-
-  void PerformOps(CallOpSetInterface* ops);
-
-  grpc_call* call() { return call_; }
-  CompletionQueue* cq() { return cq_; }
-
-  int max_message_size() { return max_message_size_; }
-
- private:
-  CallHook* call_hook_;
-  CompletionQueue* cq_;
-  grpc_call* call_;
-  int max_message_size_;
-};
-
-}  // namespace grpc
+#include <grpc++/impl/codegen/call.h>
 
 #endif  // GRPCXX_IMPL_CALL_H
diff --git a/include/grpc++/impl/client_unary_call.h b/include/grpc++/impl/client_unary_call.h
index 4cdc800..abe321e 100644
--- a/include/grpc++/impl/client_unary_call.h
+++ b/include/grpc++/impl/client_unary_call.h
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -34,41 +34,6 @@
 #ifndef GRPCXX_IMPL_CLIENT_UNARY_CALL_H
 #define GRPCXX_IMPL_CLIENT_UNARY_CALL_H
 
-#include <grpc++/impl/call.h>
-#include <grpc++/support/config.h>
-#include <grpc++/support/status.h>
-
-namespace grpc {
-
-class Channel;
-class ClientContext;
-class CompletionQueue;
-class RpcMethod;
-
-// Wrapper that performs a blocking unary call
-template <class InputMessage, class OutputMessage>
-Status BlockingUnaryCall(Channel* channel, const RpcMethod& method,
-                         ClientContext* context, const InputMessage& request,
-                         OutputMessage* result) {
-  CompletionQueue cq;
-  Call call(channel->CreateCall(method, context, &cq));
-  CallOpSet<CallOpSendInitialMetadata, CallOpSendMessage,
-            CallOpRecvInitialMetadata, CallOpRecvMessage<OutputMessage>,
-            CallOpClientSendClose, CallOpClientRecvStatus> ops;
-  Status status = ops.SendMessage(request);
-  if (!status.ok()) {
-    return status;
-  }
-  ops.SendInitialMetadata(context->send_initial_metadata_);
-  ops.RecvInitialMetadata(context);
-  ops.RecvMessage(result);
-  ops.ClientSendClose();
-  ops.ClientRecvStatus(context, &status);
-  call.PerformOps(&ops);
-  GPR_ASSERT((cq.Pluck(&ops) && ops.got_message) || !status.ok());
-  return status;
-}
-
-}  // namespace grpc
+#include <grpc++/impl/codegen/client_unary_call.h>
 
 #endif  // GRPCXX_IMPL_CLIENT_UNARY_CALL_H
diff --git a/include/grpc++/impl/codegen/async_stream.h b/include/grpc++/impl/codegen/async_stream.h
new file mode 100644
index 0000000..b041048
--- /dev/null
+++ b/include/grpc++/impl/codegen/async_stream.h
@@ -0,0 +1,462 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef GRPCXX_IMPL_CODEGEN_ASYNC_STREAM_H
+#define GRPCXX_IMPL_CODEGEN_ASYNC_STREAM_H
+
+#include <grpc++/impl/codegen/channel_interface.h>
+#include <grpc++/impl/codegen/call.h>
+#include <grpc++/impl/codegen/service_type.h>
+#include <grpc++/impl/codegen/server_context.h>
+#include <grpc++/impl/codegen/status.h>
+
+namespace grpc {
+
+class CompletionQueue;
+
+/// Common interface for all client side asynchronous streaming.
+class ClientAsyncStreamingInterface {
+ public:
+  virtual ~ClientAsyncStreamingInterface() {}
+
+  /// Request notification of the reading of the initial metadata. Completion
+  /// will be notified by \a tag on the associated completion queue.
+  ///
+  /// \param[in] tag Tag identifying this request.
+  virtual void ReadInitialMetadata(void* tag) = 0;
+
+  /// Request notification completion.
+  ///
+  /// \param[out] status To be updated with the operation status.
+  /// \param[in] tag Tag identifying this request.
+  virtual void Finish(Status* status, void* tag) = 0;
+};
+
+/// An interface that yields a sequence of messages of type \a R.
+template <class R>
+class AsyncReaderInterface {
+ public:
+  virtual ~AsyncReaderInterface() {}
+
+  /// Read a message of type \a R into \a msg. Completion will be notified by \a
+  /// tag on the associated completion queue.
+  ///
+  /// \param[out] msg Where to eventually store the read message.
+  /// \param[in] tag The tag identifying the operation.
+  virtual void Read(R* msg, void* tag) = 0;
+};
+
+/// An interface that can be fed a sequence of messages of type \a W.
+template <class W>
+class AsyncWriterInterface {
+ public:
+  virtual ~AsyncWriterInterface() {}
+
+  /// Request the writing of \a msg with identifying tag \a tag.
+  ///
+  /// Only one write may be outstanding at any given time. This means that
+  /// after calling Write, one must wait to receive \a tag from the completion
+  /// queue BEFORE calling Write again.
+  ///
+  /// \param[in] msg The message to be written.
+  /// \param[in] tag The tag identifying the operation.
+  virtual void Write(const W& msg, void* tag) = 0;
+};
+
+template <class R>
+class ClientAsyncReaderInterface : public ClientAsyncStreamingInterface,
+                                   public AsyncReaderInterface<R> {};
+
+template <class R>
+class ClientAsyncReader GRPC_FINAL : public ClientAsyncReaderInterface<R> {
+ public:
+  /// Create a stream and write the first request out.
+  template <class W>
+  ClientAsyncReader(ChannelInterface* channel, CompletionQueue* cq,
+                    const RpcMethod& method, ClientContext* context,
+                    const W& request, void* tag)
+      : context_(context), call_(channel->CreateCall(method, context, cq)) {
+    init_ops_.set_output_tag(tag);
+    init_ops_.SendInitialMetadata(context->send_initial_metadata_);
+    // TODO(ctiller): don't assert
+    GPR_ASSERT(init_ops_.SendMessage(request).ok());
+    init_ops_.ClientSendClose();
+    call_.PerformOps(&init_ops_);
+  }
+
+  void ReadInitialMetadata(void* tag) GRPC_OVERRIDE {
+    GPR_ASSERT(!context_->initial_metadata_received_);
+
+    meta_ops_.set_output_tag(tag);
+    meta_ops_.RecvInitialMetadata(context_);
+    call_.PerformOps(&meta_ops_);
+  }
+
+  void Read(R* msg, void* tag) GRPC_OVERRIDE {
+    read_ops_.set_output_tag(tag);
+    if (!context_->initial_metadata_received_) {
+      read_ops_.RecvInitialMetadata(context_);
+    }
+    read_ops_.RecvMessage(msg);
+    call_.PerformOps(&read_ops_);
+  }
+
+  void Finish(Status* status, void* tag) GRPC_OVERRIDE {
+    finish_ops_.set_output_tag(tag);
+    if (!context_->initial_metadata_received_) {
+      finish_ops_.RecvInitialMetadata(context_);
+    }
+    finish_ops_.ClientRecvStatus(context_, status);
+    call_.PerformOps(&finish_ops_);
+  }
+
+ private:
+  ClientContext* context_;
+  Call call_;
+  CallOpSet<CallOpSendInitialMetadata, CallOpSendMessage, CallOpClientSendClose>
+      init_ops_;
+  CallOpSet<CallOpRecvInitialMetadata> meta_ops_;
+  CallOpSet<CallOpRecvInitialMetadata, CallOpRecvMessage<R>> read_ops_;
+  CallOpSet<CallOpRecvInitialMetadata, CallOpClientRecvStatus> finish_ops_;
+};
+
+/// Common interface for client side asynchronous writing.
+template <class W>
+class ClientAsyncWriterInterface : public ClientAsyncStreamingInterface,
+                                   public AsyncWriterInterface<W> {
+ public:
+  /// Signal the client is done with the writes.
+  ///
+  /// \param[in] tag The tag identifying the operation.
+  virtual void WritesDone(void* tag) = 0;
+};
+
+template <class W>
+class ClientAsyncWriter GRPC_FINAL : public ClientAsyncWriterInterface<W> {
+ public:
+  template <class R>
+  ClientAsyncWriter(ChannelInterface* channel, CompletionQueue* cq,
+                    const RpcMethod& method, ClientContext* context,
+                    R* response, void* tag)
+      : context_(context), call_(channel->CreateCall(method, context, cq)) {
+    finish_ops_.RecvMessage(response);
+
+    init_ops_.set_output_tag(tag);
+    init_ops_.SendInitialMetadata(context->send_initial_metadata_);
+    call_.PerformOps(&init_ops_);
+  }
+
+  void ReadInitialMetadata(void* tag) GRPC_OVERRIDE {
+    GPR_ASSERT(!context_->initial_metadata_received_);
+
+    meta_ops_.set_output_tag(tag);
+    meta_ops_.RecvInitialMetadata(context_);
+    call_.PerformOps(&meta_ops_);
+  }
+
+  void Write(const W& msg, void* tag) GRPC_OVERRIDE {
+    write_ops_.set_output_tag(tag);
+    // TODO(ctiller): don't assert
+    GPR_ASSERT(write_ops_.SendMessage(msg).ok());
+    call_.PerformOps(&write_ops_);
+  }
+
+  void WritesDone(void* tag) GRPC_OVERRIDE {
+    writes_done_ops_.set_output_tag(tag);
+    writes_done_ops_.ClientSendClose();
+    call_.PerformOps(&writes_done_ops_);
+  }
+
+  void Finish(Status* status, void* tag) GRPC_OVERRIDE {
+    finish_ops_.set_output_tag(tag);
+    if (!context_->initial_metadata_received_) {
+      finish_ops_.RecvInitialMetadata(context_);
+    }
+    finish_ops_.ClientRecvStatus(context_, status);
+    call_.PerformOps(&finish_ops_);
+  }
+
+ private:
+  ClientContext* context_;
+  Call call_;
+  CallOpSet<CallOpSendInitialMetadata> init_ops_;
+  CallOpSet<CallOpRecvInitialMetadata> meta_ops_;
+  CallOpSet<CallOpSendMessage> write_ops_;
+  CallOpSet<CallOpClientSendClose> writes_done_ops_;
+  CallOpSet<CallOpRecvInitialMetadata, CallOpGenericRecvMessage,
+            CallOpClientRecvStatus> finish_ops_;
+};
+
+/// Client-side interface for asynchronous bi-directional streaming.
+template <class W, class R>
+class ClientAsyncReaderWriterInterface : public ClientAsyncStreamingInterface,
+                                         public AsyncWriterInterface<W>,
+                                         public AsyncReaderInterface<R> {
+ public:
+  /// Signal the client is done with the writes.
+  ///
+  /// \param[in] tag The tag identifying the operation.
+  virtual void WritesDone(void* tag) = 0;
+};
+
+template <class W, class R>
+class ClientAsyncReaderWriter GRPC_FINAL
+    : public ClientAsyncReaderWriterInterface<W, R> {
+ public:
+  ClientAsyncReaderWriter(ChannelInterface* channel, CompletionQueue* cq,
+                          const RpcMethod& method, ClientContext* context,
+                          void* tag)
+      : context_(context), call_(channel->CreateCall(method, context, cq)) {
+    init_ops_.set_output_tag(tag);
+    init_ops_.SendInitialMetadata(context->send_initial_metadata_);
+    call_.PerformOps(&init_ops_);
+  }
+
+  void ReadInitialMetadata(void* tag) GRPC_OVERRIDE {
+    GPR_ASSERT(!context_->initial_metadata_received_);
+
+    meta_ops_.set_output_tag(tag);
+    meta_ops_.RecvInitialMetadata(context_);
+    call_.PerformOps(&meta_ops_);
+  }
+
+  void Read(R* msg, void* tag) GRPC_OVERRIDE {
+    read_ops_.set_output_tag(tag);
+    if (!context_->initial_metadata_received_) {
+      read_ops_.RecvInitialMetadata(context_);
+    }
+    read_ops_.RecvMessage(msg);
+    call_.PerformOps(&read_ops_);
+  }
+
+  void Write(const W& msg, void* tag) GRPC_OVERRIDE {
+    write_ops_.set_output_tag(tag);
+    // TODO(ctiller): don't assert
+    GPR_ASSERT(write_ops_.SendMessage(msg).ok());
+    call_.PerformOps(&write_ops_);
+  }
+
+  void WritesDone(void* tag) GRPC_OVERRIDE {
+    writes_done_ops_.set_output_tag(tag);
+    writes_done_ops_.ClientSendClose();
+    call_.PerformOps(&writes_done_ops_);
+  }
+
+  void Finish(Status* status, void* tag) GRPC_OVERRIDE {
+    finish_ops_.set_output_tag(tag);
+    if (!context_->initial_metadata_received_) {
+      finish_ops_.RecvInitialMetadata(context_);
+    }
+    finish_ops_.ClientRecvStatus(context_, status);
+    call_.PerformOps(&finish_ops_);
+  }
+
+ private:
+  ClientContext* context_;
+  Call call_;
+  CallOpSet<CallOpSendInitialMetadata> init_ops_;
+  CallOpSet<CallOpRecvInitialMetadata> meta_ops_;
+  CallOpSet<CallOpRecvInitialMetadata, CallOpRecvMessage<R>> read_ops_;
+  CallOpSet<CallOpSendMessage> write_ops_;
+  CallOpSet<CallOpClientSendClose> writes_done_ops_;
+  CallOpSet<CallOpRecvInitialMetadata, CallOpClientRecvStatus> finish_ops_;
+};
+
+template <class W, class R>
+class ServerAsyncReader GRPC_FINAL : public ServerAsyncStreamingInterface,
+                                     public AsyncReaderInterface<R> {
+ public:
+  explicit ServerAsyncReader(ServerContext* ctx)
+      : call_(nullptr, nullptr, nullptr), ctx_(ctx) {}
+
+  void SendInitialMetadata(void* tag) GRPC_OVERRIDE {
+    GPR_ASSERT(!ctx_->sent_initial_metadata_);
+
+    meta_ops_.set_output_tag(tag);
+    meta_ops_.SendInitialMetadata(ctx_->initial_metadata_);
+    ctx_->sent_initial_metadata_ = true;
+    call_.PerformOps(&meta_ops_);
+  }
+
+  void Read(R* msg, void* tag) GRPC_OVERRIDE {
+    read_ops_.set_output_tag(tag);
+    read_ops_.RecvMessage(msg);
+    call_.PerformOps(&read_ops_);
+  }
+
+  void Finish(const W& msg, const Status& status, void* tag) {
+    finish_ops_.set_output_tag(tag);
+    if (!ctx_->sent_initial_metadata_) {
+      finish_ops_.SendInitialMetadata(ctx_->initial_metadata_);
+      ctx_->sent_initial_metadata_ = true;
+    }
+    // The response is dropped if the status is not OK.
+    if (status.ok()) {
+      finish_ops_.ServerSendStatus(ctx_->trailing_metadata_,
+                                   finish_ops_.SendMessage(msg));
+    } else {
+      finish_ops_.ServerSendStatus(ctx_->trailing_metadata_, status);
+    }
+    call_.PerformOps(&finish_ops_);
+  }
+
+  void FinishWithError(const Status& status, void* tag) {
+    GPR_ASSERT(!status.ok());
+    finish_ops_.set_output_tag(tag);
+    if (!ctx_->sent_initial_metadata_) {
+      finish_ops_.SendInitialMetadata(ctx_->initial_metadata_);
+      ctx_->sent_initial_metadata_ = true;
+    }
+    finish_ops_.ServerSendStatus(ctx_->trailing_metadata_, status);
+    call_.PerformOps(&finish_ops_);
+  }
+
+ private:
+  void BindCall(Call* call) GRPC_OVERRIDE { call_ = *call; }
+
+  Call call_;
+  ServerContext* ctx_;
+  CallOpSet<CallOpSendInitialMetadata> meta_ops_;
+  CallOpSet<CallOpRecvMessage<R>> read_ops_;
+  CallOpSet<CallOpSendInitialMetadata, CallOpSendMessage,
+            CallOpServerSendStatus> finish_ops_;
+};
+
+template <class W>
+class ServerAsyncWriter GRPC_FINAL : public ServerAsyncStreamingInterface,
+                                     public AsyncWriterInterface<W> {
+ public:
+  explicit ServerAsyncWriter(ServerContext* ctx)
+      : call_(nullptr, nullptr, nullptr), ctx_(ctx) {}
+
+  void SendInitialMetadata(void* tag) GRPC_OVERRIDE {
+    GPR_ASSERT(!ctx_->sent_initial_metadata_);
+
+    meta_ops_.set_output_tag(tag);
+    meta_ops_.SendInitialMetadata(ctx_->initial_metadata_);
+    ctx_->sent_initial_metadata_ = true;
+    call_.PerformOps(&meta_ops_);
+  }
+
+  void Write(const W& msg, void* tag) GRPC_OVERRIDE {
+    write_ops_.set_output_tag(tag);
+    if (!ctx_->sent_initial_metadata_) {
+      write_ops_.SendInitialMetadata(ctx_->initial_metadata_);
+      ctx_->sent_initial_metadata_ = true;
+    }
+    // TODO(ctiller): don't assert
+    GPR_ASSERT(write_ops_.SendMessage(msg).ok());
+    call_.PerformOps(&write_ops_);
+  }
+
+  void Finish(const Status& status, void* tag) {
+    finish_ops_.set_output_tag(tag);
+    if (!ctx_->sent_initial_metadata_) {
+      finish_ops_.SendInitialMetadata(ctx_->initial_metadata_);
+      ctx_->sent_initial_metadata_ = true;
+    }
+    finish_ops_.ServerSendStatus(ctx_->trailing_metadata_, status);
+    call_.PerformOps(&finish_ops_);
+  }
+
+ private:
+  void BindCall(Call* call) GRPC_OVERRIDE { call_ = *call; }
+
+  Call call_;
+  ServerContext* ctx_;
+  CallOpSet<CallOpSendInitialMetadata> meta_ops_;
+  CallOpSet<CallOpSendInitialMetadata, CallOpSendMessage> write_ops_;
+  CallOpSet<CallOpSendInitialMetadata, CallOpServerSendStatus> finish_ops_;
+};
+
+/// Server-side interface for asynchronous bi-directional streaming.
+template <class W, class R>
+class ServerAsyncReaderWriter GRPC_FINAL : public ServerAsyncStreamingInterface,
+                                           public AsyncWriterInterface<W>,
+                                           public AsyncReaderInterface<R> {
+ public:
+  explicit ServerAsyncReaderWriter(ServerContext* ctx)
+      : call_(nullptr, nullptr, nullptr), ctx_(ctx) {}
+
+  void SendInitialMetadata(void* tag) GRPC_OVERRIDE {
+    GPR_ASSERT(!ctx_->sent_initial_metadata_);
+
+    meta_ops_.set_output_tag(tag);
+    meta_ops_.SendInitialMetadata(ctx_->initial_metadata_);
+    ctx_->sent_initial_metadata_ = true;
+    call_.PerformOps(&meta_ops_);
+  }
+
+  void Read(R* msg, void* tag) GRPC_OVERRIDE {
+    read_ops_.set_output_tag(tag);
+    read_ops_.RecvMessage(msg);
+    call_.PerformOps(&read_ops_);
+  }
+
+  void Write(const W& msg, void* tag) GRPC_OVERRIDE {
+    write_ops_.set_output_tag(tag);
+    if (!ctx_->sent_initial_metadata_) {
+      write_ops_.SendInitialMetadata(ctx_->initial_metadata_);
+      ctx_->sent_initial_metadata_ = true;
+    }
+    // TODO(ctiller): don't assert
+    GPR_ASSERT(write_ops_.SendMessage(msg).ok());
+    call_.PerformOps(&write_ops_);
+  }
+
+  void Finish(const Status& status, void* tag) {
+    finish_ops_.set_output_tag(tag);
+    if (!ctx_->sent_initial_metadata_) {
+      finish_ops_.SendInitialMetadata(ctx_->initial_metadata_);
+      ctx_->sent_initial_metadata_ = true;
+    }
+    finish_ops_.ServerSendStatus(ctx_->trailing_metadata_, status);
+    call_.PerformOps(&finish_ops_);
+  }
+
+ private:
+  friend class ::grpc::Server;
+
+  void BindCall(Call* call) GRPC_OVERRIDE { call_ = *call; }
+
+  Call call_;
+  ServerContext* ctx_;
+  CallOpSet<CallOpSendInitialMetadata> meta_ops_;
+  CallOpSet<CallOpRecvMessage<R>> read_ops_;
+  CallOpSet<CallOpSendInitialMetadata, CallOpSendMessage> write_ops_;
+  CallOpSet<CallOpSendInitialMetadata, CallOpServerSendStatus> finish_ops_;
+};
+
+}  // namespace grpc
+
+#endif  // GRPCXX_IMPL_CODEGEN_ASYNC_STREAM_H
diff --git a/include/grpc++/impl/codegen/async_unary_call.h b/include/grpc++/impl/codegen/async_unary_call.h
new file mode 100644
index 0000000..f3c75dc
--- /dev/null
+++ b/include/grpc++/impl/codegen/async_unary_call.h
@@ -0,0 +1,166 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef GRPCXX_IMPL_CODEGEN_ASYNC_UNARY_CALL_H
+#define GRPCXX_IMPL_CODEGEN_ASYNC_UNARY_CALL_H
+
+#include <grpc++/impl/codegen/call.h>
+#include <grpc++/impl/codegen/channel_interface.h>
+#include <grpc++/impl/codegen/client_context.h>
+#include <grpc++/impl/codegen/server_context.h>
+#include <grpc++/impl/codegen/service_type.h>
+#include <grpc++/impl/codegen/status.h>
+#include <grpc/impl/codegen/log.h>
+
+namespace grpc {
+
+class CompletionQueue;
+
+template <class R>
+class ClientAsyncResponseReaderInterface {
+ public:
+  virtual ~ClientAsyncResponseReaderInterface() {}
+  virtual void ReadInitialMetadata(void* tag) = 0;
+  virtual void Finish(R* msg, Status* status, void* tag) = 0;
+};
+
+template <class R>
+class ClientAsyncResponseReader GRPC_FINAL
+    : public ClientAsyncResponseReaderInterface<R> {
+ public:
+  template <class W>
+  ClientAsyncResponseReader(ChannelInterface* channel, CompletionQueue* cq,
+                            const RpcMethod& method, ClientContext* context,
+                            const W& request)
+      : context_(context),
+        call_(channel->CreateCall(method, context, cq)),
+        collection_(new CallOpSetCollection) {
+    collection_->init_buf_.SetCollection(collection_);
+    collection_->init_buf_.SendInitialMetadata(context->send_initial_metadata_);
+    // TODO(ctiller): don't assert
+    GPR_ASSERT(collection_->init_buf_.SendMessage(request).ok());
+    collection_->init_buf_.ClientSendClose();
+    call_.PerformOps(&collection_->init_buf_);
+  }
+
+  void ReadInitialMetadata(void* tag) {
+    GPR_ASSERT(!context_->initial_metadata_received_);
+
+    collection_->meta_buf_.SetCollection(collection_);
+    collection_->meta_buf_.set_output_tag(tag);
+    collection_->meta_buf_.RecvInitialMetadata(context_);
+    call_.PerformOps(&collection_->meta_buf_);
+  }
+
+  void Finish(R* msg, Status* status, void* tag) {
+    collection_->finish_buf_.SetCollection(collection_);
+    collection_->finish_buf_.set_output_tag(tag);
+    if (!context_->initial_metadata_received_) {
+      collection_->finish_buf_.RecvInitialMetadata(context_);
+    }
+    collection_->finish_buf_.RecvMessage(msg);
+    collection_->finish_buf_.ClientRecvStatus(context_, status);
+    call_.PerformOps(&collection_->finish_buf_);
+  }
+
+ private:
+  ClientContext* context_;
+  Call call_;
+
+  class CallOpSetCollection : public CallOpSetCollectionInterface {
+   public:
+    SneakyCallOpSet<CallOpSendInitialMetadata, CallOpSendMessage,
+                    CallOpClientSendClose> init_buf_;
+    CallOpSet<CallOpRecvInitialMetadata> meta_buf_;
+    CallOpSet<CallOpRecvInitialMetadata, CallOpRecvMessage<R>,
+              CallOpClientRecvStatus> finish_buf_;
+  };
+  std::shared_ptr<CallOpSetCollection> collection_;
+};
+
+template <class W>
+class ServerAsyncResponseWriter GRPC_FINAL
+    : public ServerAsyncStreamingInterface {
+ public:
+  explicit ServerAsyncResponseWriter(ServerContext* ctx)
+      : call_(nullptr, nullptr, nullptr), ctx_(ctx) {}
+
+  void SendInitialMetadata(void* tag) GRPC_OVERRIDE {
+    GPR_ASSERT(!ctx_->sent_initial_metadata_);
+
+    meta_buf_.set_output_tag(tag);
+    meta_buf_.SendInitialMetadata(ctx_->initial_metadata_);
+    ctx_->sent_initial_metadata_ = true;
+    call_.PerformOps(&meta_buf_);
+  }
+
+  void Finish(const W& msg, const Status& status, void* tag) {
+    finish_buf_.set_output_tag(tag);
+    if (!ctx_->sent_initial_metadata_) {
+      finish_buf_.SendInitialMetadata(ctx_->initial_metadata_);
+      ctx_->sent_initial_metadata_ = true;
+    }
+    // The response is dropped if the status is not OK.
+    if (status.ok()) {
+      finish_buf_.ServerSendStatus(ctx_->trailing_metadata_,
+                                   finish_buf_.SendMessage(msg));
+    } else {
+      finish_buf_.ServerSendStatus(ctx_->trailing_metadata_, status);
+    }
+    call_.PerformOps(&finish_buf_);
+  }
+
+  void FinishWithError(const Status& status, void* tag) {
+    GPR_ASSERT(!status.ok());
+    finish_buf_.set_output_tag(tag);
+    if (!ctx_->sent_initial_metadata_) {
+      finish_buf_.SendInitialMetadata(ctx_->initial_metadata_);
+      ctx_->sent_initial_metadata_ = true;
+    }
+    finish_buf_.ServerSendStatus(ctx_->trailing_metadata_, status);
+    call_.PerformOps(&finish_buf_);
+  }
+
+ private:
+  void BindCall(Call* call) GRPC_OVERRIDE { call_ = *call; }
+
+  Call call_;
+  ServerContext* ctx_;
+  CallOpSet<CallOpSendInitialMetadata> meta_buf_;
+  CallOpSet<CallOpSendInitialMetadata, CallOpSendMessage,
+            CallOpServerSendStatus> finish_buf_;
+};
+
+}  // namespace grpc
+
+#endif  // GRPCXX_IMPL_CODEGEN_ASYNC_UNARY_CALL_H
diff --git a/include/grpc++/impl/codegen/call.h b/include/grpc++/impl/codegen/call.h
new file mode 100644
index 0000000..e65349d
--- /dev/null
+++ b/include/grpc++/impl/codegen/call.h
@@ -0,0 +1,596 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef GRPCXX_IMPL_CODEGEN_CALL_H
+#define GRPCXX_IMPL_CODEGEN_CALL_H
+
+#include <functional>
+#include <memory>
+#include <map>
+#include <cstring>
+
+#include <grpc/impl/codegen/alloc.h>
+#include <grpc/impl/codegen/grpc_types.h>
+#include <grpc++/impl/codegen/client_context.h>
+#include <grpc++/impl/codegen/call_hook.h>
+#include <grpc++/impl/codegen/completion_queue_tag.h>
+#include <grpc++/impl/codegen/serialization_traits.h>
+#include <grpc++/impl/codegen/config.h>
+#include <grpc++/impl/codegen/status.h>
+
+struct grpc_byte_buffer;
+
+namespace grpc {
+
+class ByteBuffer;
+class Call;
+class CallHook;
+class CompletionQueue;
+
+void FillMetadataMap(
+    grpc_metadata_array* arr,
+    std::multimap<grpc::string_ref, grpc::string_ref>* metadata);
+grpc_metadata* FillMetadataArray(
+    const std::multimap<grpc::string, grpc::string>& metadata);
+
+/// Per-message write options.
+class WriteOptions {
+ public:
+  WriteOptions() : flags_(0) {}
+  WriteOptions(const WriteOptions& other) : flags_(other.flags_) {}
+
+  /// Clear all flags.
+  inline void Clear() { flags_ = 0; }
+
+  /// Returns raw flags bitset.
+  inline uint32_t flags() const { return flags_; }
+
+  /// Sets flag for the disabling of compression for the next message write.
+  ///
+  /// \sa GRPC_WRITE_NO_COMPRESS
+  inline WriteOptions& set_no_compression() {
+    SetBit(GRPC_WRITE_NO_COMPRESS);
+    return *this;
+  }
+
+  /// Clears flag for the disabling of compression for the next message write.
+  ///
+  /// \sa GRPC_WRITE_NO_COMPRESS
+  inline WriteOptions& clear_no_compression() {
+    ClearBit(GRPC_WRITE_NO_COMPRESS);
+    return *this;
+  }
+
+  /// Get value for the flag indicating whether compression for the next
+  /// message write is forcefully disabled.
+  ///
+  /// \sa GRPC_WRITE_NO_COMPRESS
+  inline bool get_no_compression() const {
+    return GetBit(GRPC_WRITE_NO_COMPRESS);
+  }
+
+  /// Sets flag indicating that the write may be buffered and need not go out on
+  /// the wire immediately.
+  ///
+  /// \sa GRPC_WRITE_BUFFER_HINT
+  inline WriteOptions& set_buffer_hint() {
+    SetBit(GRPC_WRITE_BUFFER_HINT);
+    return *this;
+  }
+
+  /// Clears flag indicating that the write may be buffered and need not go out
+  /// on the wire immediately.
+  ///
+  /// \sa GRPC_WRITE_BUFFER_HINT
+  inline WriteOptions& clear_buffer_hint() {
+    ClearBit(GRPC_WRITE_BUFFER_HINT);
+    return *this;
+  }
+
+  /// Get value for the flag indicating that the write may be buffered and need
+  /// not go out on the wire immediately.
+  ///
+  /// \sa GRPC_WRITE_BUFFER_HINT
+  inline bool get_buffer_hint() const { return GetBit(GRPC_WRITE_BUFFER_HINT); }
+
+  WriteOptions& operator=(const WriteOptions& rhs) {
+    flags_ = rhs.flags_;
+    return *this;
+  }
+
+ private:
+  void SetBit(const uint32_t mask) { flags_ |= mask; }
+
+  void ClearBit(const uint32_t mask) { flags_ &= ~mask; }
+
+  bool GetBit(const uint32_t mask) const { return (flags_ & mask) != 0; }
+
+  uint32_t flags_;
+};
+
+/// Default argument for CallOpSet. I is unused by the class, but can be
+/// used for generating multiple names for the same thing.
+template <int I>
+class CallNoOp {
+ protected:
+  void AddOp(grpc_op* ops, size_t* nops) {}
+  void FinishOp(bool* status, int max_message_size) {}
+};
+
+class CallOpSendInitialMetadata {
+ public:
+  CallOpSendInitialMetadata() : send_(false) {}
+
+  void SendInitialMetadata(
+      const std::multimap<grpc::string, grpc::string>& metadata) {
+    send_ = true;
+    initial_metadata_count_ = metadata.size();
+    initial_metadata_ = FillMetadataArray(metadata);
+  }
+
+ protected:
+  void AddOp(grpc_op* ops, size_t* nops) {
+    if (!send_) return;
+    grpc_op* op = &ops[(*nops)++];
+    op->op = GRPC_OP_SEND_INITIAL_METADATA;
+    op->flags = 0;
+    op->reserved = NULL;
+    op->data.send_initial_metadata.count = initial_metadata_count_;
+    op->data.send_initial_metadata.metadata = initial_metadata_;
+  }
+  void FinishOp(bool* status, int max_message_size) {
+    if (!send_) return;
+    gpr_free(initial_metadata_);
+    send_ = false;
+  }
+
+  bool send_;
+  size_t initial_metadata_count_;
+  grpc_metadata* initial_metadata_;
+};
+
+class CallOpSendMessage {
+ public:
+  CallOpSendMessage() : send_buf_(nullptr), own_buf_(false) {}
+
+  /// Send \a message using \a options for the write. The \a options are cleared
+  /// after use.
+  template <class M>
+  Status SendMessage(const M& message,
+                     const WriteOptions& options) GRPC_MUST_USE_RESULT;
+
+  template <class M>
+  Status SendMessage(const M& message) GRPC_MUST_USE_RESULT;
+
+ protected:
+  void AddOp(grpc_op* ops, size_t* nops) {
+    if (send_buf_ == nullptr) return;
+    grpc_op* op = &ops[(*nops)++];
+    op->op = GRPC_OP_SEND_MESSAGE;
+    op->flags = write_options_.flags();
+    op->reserved = NULL;
+    op->data.send_message = send_buf_;
+    // Flags are per-message: clear them after use.
+    write_options_.Clear();
+  }
+  void FinishOp(bool* status, int max_message_size) {
+    if (own_buf_) grpc_byte_buffer_destroy(send_buf_);
+    send_buf_ = nullptr;
+  }
+
+ private:
+  grpc_byte_buffer* send_buf_;
+  WriteOptions write_options_;
+  bool own_buf_;
+};
+
+template <class M>
+Status CallOpSendMessage::SendMessage(const M& message,
+                                      const WriteOptions& options) {
+  write_options_ = options;
+  return SerializationTraits<M>::Serialize(message, &send_buf_, &own_buf_);
+}
+
+template <class M>
+Status CallOpSendMessage::SendMessage(const M& message) {
+  return SendMessage(message, WriteOptions());
+}
+
+template <class R>
+class CallOpRecvMessage {
+ public:
+  CallOpRecvMessage() : got_message(false), message_(nullptr) {}
+
+  void RecvMessage(R* message) { message_ = message; }
+
+  bool got_message;
+
+ protected:
+  void AddOp(grpc_op* ops, size_t* nops) {
+    if (message_ == nullptr) return;
+    grpc_op* op = &ops[(*nops)++];
+    op->op = GRPC_OP_RECV_MESSAGE;
+    op->flags = 0;
+    op->reserved = NULL;
+    op->data.recv_message = &recv_buf_;
+  }
+
+  void FinishOp(bool* status, int max_message_size) {
+    if (message_ == nullptr) return;
+    if (recv_buf_) {
+      if (*status) {
+        got_message = true;
+        *status = SerializationTraits<R>::Deserialize(recv_buf_, message_,
+                                                      max_message_size).ok();
+      } else {
+        got_message = false;
+        grpc_byte_buffer_destroy(recv_buf_);
+      }
+    } else {
+      got_message = false;
+      *status = false;
+    }
+    message_ = nullptr;
+  }
+
+ private:
+  R* message_;
+  grpc_byte_buffer* recv_buf_;
+};
+
+namespace CallOpGenericRecvMessageHelper {
+class DeserializeFunc {
+ public:
+  virtual Status Deserialize(grpc_byte_buffer* buf, int max_message_size) = 0;
+};
+
+template <class R>
+class DeserializeFuncType GRPC_FINAL : public DeserializeFunc {
+ public:
+  DeserializeFuncType(R* message) : message_(message) {}
+  Status Deserialize(grpc_byte_buffer* buf,
+                     int max_message_size) GRPC_OVERRIDE {
+    return SerializationTraits<R>::Deserialize(buf, message_, max_message_size);
+  }
+
+ private:
+  R* message_;  // Not a managed pointer because management is external to this
+};
+}  // namespace CallOpGenericRecvMessageHelper
+
+class CallOpGenericRecvMessage {
+ public:
+  CallOpGenericRecvMessage() : got_message(false) {}
+
+  template <class R>
+  void RecvMessage(R* message) {
+    deserialize_.reset(
+        new CallOpGenericRecvMessageHelper::DeserializeFuncType<R>(message));
+  }
+
+  bool got_message;
+
+ protected:
+  void AddOp(grpc_op* ops, size_t* nops) {
+    if (!deserialize_) return;
+    grpc_op* op = &ops[(*nops)++];
+    op->op = GRPC_OP_RECV_MESSAGE;
+    op->flags = 0;
+    op->reserved = NULL;
+    op->data.recv_message = &recv_buf_;
+  }
+
+  void FinishOp(bool* status, int max_message_size) {
+    if (!deserialize_) return;
+    if (recv_buf_) {
+      if (*status) {
+        got_message = true;
+        *status = deserialize_->Deserialize(recv_buf_, max_message_size).ok();
+      } else {
+        got_message = false;
+        grpc_byte_buffer_destroy(recv_buf_);
+      }
+    } else {
+      got_message = false;
+      *status = false;
+    }
+    deserialize_.reset();
+  }
+
+ private:
+  std::unique_ptr<CallOpGenericRecvMessageHelper::DeserializeFunc> deserialize_;
+  grpc_byte_buffer* recv_buf_;
+};
+
+class CallOpClientSendClose {
+ public:
+  CallOpClientSendClose() : send_(false) {}
+
+  void ClientSendClose() { send_ = true; }
+
+ protected:
+  void AddOp(grpc_op* ops, size_t* nops) {
+    if (!send_) return;
+    grpc_op* op = &ops[(*nops)++];
+    op->op = GRPC_OP_SEND_CLOSE_FROM_CLIENT;
+    op->flags = 0;
+    op->reserved = NULL;
+  }
+  void FinishOp(bool* status, int max_message_size) { send_ = false; }
+
+ private:
+  bool send_;
+};
+
+class CallOpServerSendStatus {
+ public:
+  CallOpServerSendStatus() : send_status_available_(false) {}
+
+  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_status_available_ = true;
+    send_status_code_ = static_cast<grpc_status_code>(status.error_code());
+    send_status_details_ = status.error_message();
+  }
+
+ protected:
+  void AddOp(grpc_op* ops, size_t* nops) {
+    if (!send_status_available_) return;
+    grpc_op* op = &ops[(*nops)++];
+    op->op = GRPC_OP_SEND_STATUS_FROM_SERVER;
+    op->data.send_status_from_server.trailing_metadata_count =
+        trailing_metadata_count_;
+    op->data.send_status_from_server.trailing_metadata = trailing_metadata_;
+    op->data.send_status_from_server.status = send_status_code_;
+    op->data.send_status_from_server.status_details =
+        send_status_details_.empty() ? nullptr : send_status_details_.c_str();
+    op->flags = 0;
+    op->reserved = NULL;
+  }
+
+  void FinishOp(bool* status, int max_message_size) {
+    if (!send_status_available_) return;
+    gpr_free(trailing_metadata_);
+    send_status_available_ = false;
+  }
+
+ private:
+  bool send_status_available_;
+  grpc_status_code send_status_code_;
+  grpc::string send_status_details_;
+  size_t trailing_metadata_count_;
+  grpc_metadata* trailing_metadata_;
+};
+
+class CallOpRecvInitialMetadata {
+ public:
+  CallOpRecvInitialMetadata() : recv_initial_metadata_(nullptr) {}
+
+  void RecvInitialMetadata(ClientContext* context) {
+    context->initial_metadata_received_ = true;
+    recv_initial_metadata_ = &context->recv_initial_metadata_;
+  }
+
+ protected:
+  void AddOp(grpc_op* ops, size_t* nops) {
+    if (!recv_initial_metadata_) return;
+    memset(&recv_initial_metadata_arr_, 0, sizeof(recv_initial_metadata_arr_));
+    grpc_op* op = &ops[(*nops)++];
+    op->op = GRPC_OP_RECV_INITIAL_METADATA;
+    op->data.recv_initial_metadata = &recv_initial_metadata_arr_;
+    op->flags = 0;
+    op->reserved = NULL;
+  }
+  void FinishOp(bool* status, int max_message_size) {
+    if (recv_initial_metadata_ == nullptr) return;
+    FillMetadataMap(&recv_initial_metadata_arr_, recv_initial_metadata_);
+    recv_initial_metadata_ = nullptr;
+  }
+
+ private:
+  std::multimap<grpc::string_ref, grpc::string_ref>* recv_initial_metadata_;
+  grpc_metadata_array recv_initial_metadata_arr_;
+};
+
+class CallOpClientRecvStatus {
+ public:
+  CallOpClientRecvStatus() : recv_status_(nullptr) {}
+
+  void ClientRecvStatus(ClientContext* context, Status* status) {
+    recv_trailing_metadata_ = &context->trailing_metadata_;
+    recv_status_ = status;
+  }
+
+ protected:
+  void AddOp(grpc_op* ops, size_t* nops) {
+    if (recv_status_ == nullptr) return;
+    memset(&recv_trailing_metadata_arr_, 0,
+           sizeof(recv_trailing_metadata_arr_));
+    status_details_ = nullptr;
+    status_details_capacity_ = 0;
+    grpc_op* op = &ops[(*nops)++];
+    op->op = GRPC_OP_RECV_STATUS_ON_CLIENT;
+    op->data.recv_status_on_client.trailing_metadata =
+        &recv_trailing_metadata_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_capacity =
+        &status_details_capacity_;
+    op->flags = 0;
+    op->reserved = NULL;
+  }
+
+  void FinishOp(bool* status, int max_message_size) {
+    if (recv_status_ == nullptr) return;
+    FillMetadataMap(&recv_trailing_metadata_arr_, recv_trailing_metadata_);
+    *recv_status_ = Status(
+        static_cast<StatusCode>(status_code_),
+        status_details_ ? grpc::string(status_details_) : grpc::string());
+    gpr_free(status_details_);
+    recv_status_ = nullptr;
+  }
+
+ private:
+  std::multimap<grpc::string_ref, grpc::string_ref>* recv_trailing_metadata_;
+  Status* recv_status_;
+  grpc_metadata_array recv_trailing_metadata_arr_;
+  grpc_status_code status_code_;
+  char* status_details_;
+  size_t status_details_capacity_;
+};
+
+/// An abstract collection of CallOpSet's, to be used whenever
+/// CallOpSet objects must be thought of as a group. Each member
+/// of the group should have a shared_ptr back to the collection,
+/// as will the object that instantiates the collection, allowing
+/// for automatic ref-counting. In practice, any actual use should
+/// derive from this base class. This is specifically necessary if
+/// some of the CallOpSet's in the collection are "Sneaky" and don't
+/// report back to the C++ layer CQ operations
+class CallOpSetCollectionInterface
+    : public std::enable_shared_from_this<CallOpSetCollectionInterface> {};
+
+/// An abstract collection of call ops, used to generate the
+/// grpc_call_op structure to pass down to the lower layers,
+/// and as it is-a CompletionQueueTag, also massages the final
+/// completion into the correct form for consumption in the C++
+/// API.
+class CallOpSetInterface : public CompletionQueueTag {
+ public:
+  CallOpSetInterface() : max_message_size_(0) {}
+  /// Fills in grpc_op, starting from ops[*nops] and moving
+  /// upwards.
+  virtual void FillOps(grpc_op* ops, size_t* nops) = 0;
+
+  void set_max_message_size(int max_message_size) {
+    max_message_size_ = max_message_size;
+  }
+
+  /// Mark this as belonging to a collection if needed
+  void SetCollection(std::shared_ptr<CallOpSetCollectionInterface> collection) {
+    collection_ = collection;
+  }
+
+ protected:
+  int max_message_size_;
+  std::shared_ptr<CallOpSetCollectionInterface> collection_;
+};
+
+/// Primary implementaiton of CallOpSetInterface.
+/// Since we cannot use variadic templates, we declare slots up to
+/// the maximum count of ops we'll need in a set. We leverage the
+/// empty base class optimization to slim this class (especially
+/// when there are many unused slots used). To avoid duplicate base classes,
+/// the template parmeter for CallNoOp is varied by argument position.
+template <class Op1 = CallNoOp<1>, class Op2 = CallNoOp<2>,
+          class Op3 = CallNoOp<3>, class Op4 = CallNoOp<4>,
+          class Op5 = CallNoOp<5>, class Op6 = CallNoOp<6>>
+class CallOpSet : public CallOpSetInterface,
+                  public Op1,
+                  public Op2,
+                  public Op3,
+                  public Op4,
+                  public Op5,
+                  public Op6 {
+ public:
+  CallOpSet() : return_tag_(this) {}
+  void FillOps(grpc_op* ops, size_t* nops) GRPC_OVERRIDE {
+    this->Op1::AddOp(ops, nops);
+    this->Op2::AddOp(ops, nops);
+    this->Op3::AddOp(ops, nops);
+    this->Op4::AddOp(ops, nops);
+    this->Op5::AddOp(ops, nops);
+    this->Op6::AddOp(ops, nops);
+  }
+
+  bool FinalizeResult(void** tag, bool* status) GRPC_OVERRIDE {
+    this->Op1::FinishOp(status, max_message_size_);
+    this->Op2::FinishOp(status, max_message_size_);
+    this->Op3::FinishOp(status, max_message_size_);
+    this->Op4::FinishOp(status, max_message_size_);
+    this->Op5::FinishOp(status, max_message_size_);
+    this->Op6::FinishOp(status, max_message_size_);
+    *tag = return_tag_;
+    collection_.reset();  // drop the ref at this point
+    return true;
+  }
+
+  void set_output_tag(void* return_tag) { return_tag_ = return_tag; }
+
+ private:
+  void* return_tag_;
+};
+
+/// A CallOpSet that does not post completions to the completion queue.
+///
+/// Allows hiding some completions that the C core must generate from
+/// C++ users.
+template <class Op1 = CallNoOp<1>, class Op2 = CallNoOp<2>,
+          class Op3 = CallNoOp<3>, class Op4 = CallNoOp<4>,
+          class Op5 = CallNoOp<5>, class Op6 = CallNoOp<6>>
+class SneakyCallOpSet : public CallOpSet<Op1, Op2, Op3, Op4, Op5, Op6> {
+ public:
+  bool FinalizeResult(void** tag, bool* status) GRPC_OVERRIDE {
+    typedef CallOpSet<Op1, Op2, Op3, Op4, Op5, Op6> Base;
+    return Base::FinalizeResult(tag, status) && false;
+  }
+};
+
+// Straightforward wrapping of the C call object
+class Call GRPC_FINAL {
+ public:
+  /* call is owned by the caller */
+  Call(grpc_call* call, CallHook* call_hook_, CompletionQueue* cq);
+  Call(grpc_call* call, CallHook* call_hook_, CompletionQueue* cq,
+       int max_message_size);
+
+  void PerformOps(CallOpSetInterface* ops);
+
+  grpc_call* call() { return call_; }
+  CompletionQueue* cq() { return cq_; }
+
+  int max_message_size() { return max_message_size_; }
+
+ private:
+  CallHook* call_hook_;
+  CompletionQueue* cq_;
+  grpc_call* call_;
+  int max_message_size_;
+};
+
+}  // namespace grpc
+
+#endif  // GRPCXX_IMPL_CODEGEN_CALL_H
diff --git a/src/objective-c/GRPCClient/private/GRPCUnsecuredChannel.h b/include/grpc++/impl/codegen/call_hook.h
similarity index 76%
copy from src/objective-c/GRPCClient/private/GRPCUnsecuredChannel.h
copy to include/grpc++/impl/codegen/call_hook.h
index 8528be4..0b60272 100644
--- a/src/objective-c/GRPCClient/private/GRPCUnsecuredChannel.h
+++ b/include/grpc++/impl/codegen/call_hook.h
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -31,8 +31,21 @@
  *
  */
 
-#import "GRPCChannel.h"
+#ifndef GRPCXX_IMPL_CODEGEN_CALL_HOOK_H
+#define GRPCXX_IMPL_CODEGEN_CALL_HOOK_H
 
-@interface GRPCUnsecuredChannel : GRPCChannel
-- (instancetype)initWithHost:(NSString *)host NS_DESIGNATED_INITIALIZER;
-@end
+namespace grpc {
+
+class CallOpSetInterface;
+class Call;
+
+/// Channel and Server implement this to allow them to hook performing ops
+class CallHook {
+ public:
+  virtual ~CallHook() {}
+  virtual void PerformOpsOnCall(CallOpSetInterface* ops, Call* call) = 0;
+};
+
+}  // namespace grpc
+
+#endif  // GRPCXX_IMPL_CODEGEN_CALL_HOOK_H
diff --git a/include/grpc++/impl/codegen/channel_interface.h b/include/grpc++/impl/codegen/channel_interface.h
new file mode 100644
index 0000000..6fcd5c3
--- /dev/null
+++ b/include/grpc++/impl/codegen/channel_interface.h
@@ -0,0 +1,123 @@
+/*
+ *
+ * Copyright 2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef GRPCXX_IMPL_CODEGEN_CHANNEL_INTERFACE_H
+#define GRPCXX_IMPL_CODEGEN_CHANNEL_INTERFACE_H
+
+#include <grpc++/impl/codegen/status.h>
+#include <grpc++/impl/codegen/time.h>
+#include <grpc/impl/codegen/connectivity_state.h>
+
+namespace grpc {
+class Call;
+class ClientContext;
+class RpcMethod;
+class CallOpSetInterface;
+class CompletionQueue;
+
+template <class R>
+class ClientReader;
+template <class W>
+class ClientWriter;
+template <class W, class R>
+class ClientReaderWriter;
+template <class R>
+class ClientAsyncReader;
+template <class W>
+class ClientAsyncWriter;
+template <class W, class R>
+class ClientAsyncReaderWriter;
+template <class R>
+class ClientAsyncResponseReader;
+
+/// Codegen interface for \a grpc::Channel.
+class ChannelInterface {
+ public:
+  virtual ~ChannelInterface() {}
+  /// Get the current channel state. If the channel is in IDLE and
+  /// \a try_to_connect is set to true, try to connect.
+  virtual grpc_connectivity_state GetState(bool try_to_connect) = 0;
+
+  /// Return the \a tag on \a cq when the channel state is changed or \a
+  /// deadline expires. \a GetState needs to called to get the current state.
+  template <typename T>
+  void NotifyOnStateChange(grpc_connectivity_state last_observed, T deadline,
+                           CompletionQueue* cq, void* tag) {
+    TimePoint<T> deadline_tp(deadline);
+    NotifyOnStateChangeImpl(last_observed, deadline_tp.raw_time(), cq, tag);
+  }
+
+  /// Blocking wait for channel state change or \a deadline expiration.
+  /// \a GetState needs to called to get the current state.
+  template <typename T>
+  bool WaitForStateChange(grpc_connectivity_state last_observed, T deadline) {
+    TimePoint<T> deadline_tp(deadline);
+    return WaitForStateChangeImpl(last_observed, deadline_tp.raw_time());
+  }
+
+ private:
+  template <class R>
+  friend class ::grpc::ClientReader;
+  template <class W>
+  friend class ::grpc::ClientWriter;
+  template <class W, class R>
+  friend class ::grpc::ClientReaderWriter;
+  template <class R>
+  friend class ::grpc::ClientAsyncReader;
+  template <class W>
+  friend class ::grpc::ClientAsyncWriter;
+  template <class W, class R>
+  friend class ::grpc::ClientAsyncReaderWriter;
+  template <class R>
+  friend class ::grpc::ClientAsyncResponseReader;
+  template <class InputMessage, class OutputMessage>
+  friend Status BlockingUnaryCall(ChannelInterface* channel,
+                                  const RpcMethod& method,
+                                  ClientContext* context,
+                                  const InputMessage& request,
+                                  OutputMessage* result);
+  friend class ::grpc::RpcMethod;
+  virtual Call CreateCall(const RpcMethod& method, ClientContext* context,
+                          CompletionQueue* cq) = 0;
+  virtual void PerformOpsOnCall(CallOpSetInterface* ops, Call* call) = 0;
+  virtual void* RegisterMethod(const char* method) = 0;
+  virtual void NotifyOnStateChangeImpl(grpc_connectivity_state last_observed,
+                                       gpr_timespec deadline,
+                                       CompletionQueue* cq, void* tag) = 0;
+  virtual bool WaitForStateChangeImpl(grpc_connectivity_state last_observed,
+                                      gpr_timespec deadline) = 0;
+};
+
+}  // namespace grpc
+
+#endif  // GRPCXX_IMPL_CODEGEN_CHANNEL_INTERFACE_H
diff --git a/include/grpc++/impl/codegen/client_context.h b/include/grpc++/impl/codegen/client_context.h
new file mode 100644
index 0000000..db2afe9
--- /dev/null
+++ b/include/grpc++/impl/codegen/client_context.h
@@ -0,0 +1,354 @@
+/*
+ *
+ * Copyright 2015-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.
+ *
+ */
+
+/// A ClientContext allows the person implementing a service client to:
+///
+/// - Add custom metadata key-value pairs that will propagated to the server
+/// side.
+/// - Control call settings such as compression and authentication.
+/// - Initial and trailing metadata coming from the server.
+/// - Get performance metrics (ie, census).
+///
+/// Context settings are only relevant to the call they are invoked with, that
+/// is to say, they aren't sticky. Some of these settings, such as the
+/// compression options, can be made persistant at channel construction time
+/// (see \a grpc::CreateCustomChannel).
+///
+/// \warning ClientContext instances should \em not be reused across rpcs.
+
+#ifndef GRPCXX_IMPL_CODEGEN_CLIENT_CONTEXT_H
+#define GRPCXX_IMPL_CODEGEN_CLIENT_CONTEXT_H
+
+#include <map>
+#include <memory>
+#include <string>
+
+#include <grpc++/impl/codegen/config.h>
+#include <grpc++/impl/codegen/security/auth_context.h>
+#include <grpc++/impl/codegen/status.h>
+#include <grpc++/impl/codegen/string_ref.h>
+#include <grpc++/impl/codegen/sync.h>
+#include <grpc++/impl/codegen/time.h>
+#include <grpc/impl/codegen/compression_types.h>
+#include <grpc/impl/codegen/log.h>
+#include <grpc/impl/codegen/propagation_bits.h>
+#include <grpc/impl/codegen/time.h>
+
+struct census_context;
+struct grpc_call;
+
+namespace grpc {
+
+class Channel;
+class ChannelInterface;
+class CompletionQueue;
+class CallCredentials;
+class RpcMethod;
+template <class R>
+class ClientReader;
+template <class W>
+class ClientWriter;
+template <class W, class R>
+class ClientReaderWriter;
+template <class R>
+class ClientAsyncReader;
+template <class W>
+class ClientAsyncWriter;
+template <class W, class R>
+class ClientAsyncReaderWriter;
+template <class R>
+class ClientAsyncResponseReader;
+class ServerContext;
+
+/// Options for \a ClientContext::FromServerContext specifying which traits from
+/// the \a ServerContext to propagate (copy) from it into a new \a
+/// ClientContext.
+///
+/// \see ClientContext::FromServerContext
+class PropagationOptions {
+ public:
+  PropagationOptions() : propagate_(GRPC_PROPAGATE_DEFAULTS) {}
+
+  PropagationOptions& enable_deadline_propagation() {
+    propagate_ |= GRPC_PROPAGATE_DEADLINE;
+    return *this;
+  }
+
+  PropagationOptions& disable_deadline_propagation() {
+    propagate_ &= ~GRPC_PROPAGATE_DEADLINE;
+    return *this;
+  }
+
+  PropagationOptions& enable_census_stats_propagation() {
+    propagate_ |= GRPC_PROPAGATE_CENSUS_STATS_CONTEXT;
+    return *this;
+  }
+
+  PropagationOptions& disable_census_stats_propagation() {
+    propagate_ &= ~GRPC_PROPAGATE_CENSUS_STATS_CONTEXT;
+    return *this;
+  }
+
+  PropagationOptions& enable_census_tracing_propagation() {
+    propagate_ |= GRPC_PROPAGATE_CENSUS_TRACING_CONTEXT;
+    return *this;
+  }
+
+  PropagationOptions& disable_census_tracing_propagation() {
+    propagate_ &= ~GRPC_PROPAGATE_CENSUS_TRACING_CONTEXT;
+    return *this;
+  }
+
+  PropagationOptions& enable_cancellation_propagation() {
+    propagate_ |= GRPC_PROPAGATE_CANCELLATION;
+    return *this;
+  }
+
+  PropagationOptions& disable_cancellation_propagation() {
+    propagate_ &= ~GRPC_PROPAGATE_CANCELLATION;
+    return *this;
+  }
+
+  uint32_t c_bitmask() const { return propagate_; }
+
+ private:
+  uint32_t propagate_;
+};
+
+namespace testing {
+class InteropClientContextInspector;
+}  // namespace testing
+
+class ClientContext {
+ public:
+  ClientContext();
+  ~ClientContext();
+
+  /// Create a new \a ClientContext as a child of an incoming server call,
+  /// according to \a options (\see PropagationOptions).
+  ///
+  /// \param server_context The source server context to use as the basis for
+  /// constructing the client context.
+  /// \param options The options controlling what to copy from the \a
+  /// server_context.
+  ///
+  /// \return A newly constructed \a ClientContext instance based on \a
+  /// server_context, with traits propagated (copied) according to \a options.
+  static std::unique_ptr<ClientContext> FromServerContext(
+      const ServerContext& server_context,
+      PropagationOptions options = PropagationOptions());
+
+  /// Add the (\a meta_key, \a meta_value) pair to the metadata associated with
+  /// a client call. These are made available at the server side by the \a
+  /// grpc::ServerContext::client_metadata() method.
+  ///
+  /// \warning This method should only be called before invoking the rpc.
+  ///
+  /// \param meta_key The metadata key. If \a meta_value is binary data, it must
+  /// end in "-bin".
+  /// \param meta_value The metadata value. If its value is binary, it must be
+  /// base64-encoding (see https://tools.ietf.org/html/rfc4648#section-4) and \a
+  /// meta_key must end in "-bin".
+  void AddMetadata(const grpc::string& meta_key,
+                   const grpc::string& meta_value);
+
+  /// Return a collection of initial metadata key-value pairs. Note that keys
+  /// may happen more than once (ie, a \a std::multimap is returned).
+  ///
+  /// \warning This method should only be called after initial metadata has been
+  /// received. For streaming calls, see \a
+  /// ClientReaderInterface::WaitForInitialMetadata().
+  ///
+  /// \return A multimap of initial metadata key-value pairs from the server.
+  const std::multimap<grpc::string_ref, grpc::string_ref>&
+  GetServerInitialMetadata() {
+    GPR_ASSERT(initial_metadata_received_);
+    return recv_initial_metadata_;
+  }
+
+  /// Return a collection of trailing metadata key-value pairs. Note that keys
+  /// may happen more than once (ie, a \a std::multimap is returned).
+  ///
+  /// \warning This method is only callable once the stream has finished.
+  ///
+  /// \return A multimap of metadata trailing key-value pairs from the server.
+  const std::multimap<grpc::string_ref, grpc::string_ref>&
+  GetServerTrailingMetadata() {
+    // TODO(yangg) check finished
+    return trailing_metadata_;
+  }
+
+  /// Set the deadline for the client call.
+  ///
+  /// \warning This method should only be called before invoking the rpc.
+  ///
+  /// \param deadline the deadline for the client call. Units are determined by
+  /// the type used.
+  template <typename T>
+  void set_deadline(const T& deadline) {
+    TimePoint<T> deadline_tp(deadline);
+    deadline_ = deadline_tp.raw_time();
+  }
+
+#ifndef GRPC_CXX0X_NO_CHRONO
+  /// Return the deadline for the client call.
+  std::chrono::system_clock::time_point deadline() {
+    return Timespec2Timepoint(deadline_);
+  }
+#endif  // !GRPC_CXX0X_NO_CHRONO
+
+  /// Return a \a gpr_timespec representation of the client call's deadline.
+  gpr_timespec raw_deadline() { return deadline_; }
+
+  /// Set the per call authority header (see
+  /// https://tools.ietf.org/html/rfc7540#section-8.1.2.3).
+  void set_authority(const grpc::string& authority) { authority_ = authority; }
+
+  /// Return the authentication context for this client call.
+  ///
+  /// \see grpc::AuthContext.
+  std::shared_ptr<const AuthContext> auth_context() const;
+
+  /// Set credentials for the client call.
+  ///
+  /// A credentials object encapsulates all the state needed by a client to
+  /// authenticate with a server and make various assertions, e.g., about the
+  /// client’s identity, role, or whether it is authorized to make a particular
+  /// call.
+  ///
+  /// \see  http://www.grpc.io/docs/guides/auth.html
+  void set_credentials(const std::shared_ptr<CallCredentials>& creds) {
+    creds_ = creds;
+  }
+
+  /// Return the compression algorithm to be used by the client call.
+  grpc_compression_algorithm compression_algorithm() const {
+    return compression_algorithm_;
+  }
+
+  /// Set \a algorithm to be the compression algorithm used for the client call.
+  ///
+  /// \param algorith The compression algorithm used for the client call.
+  void set_compression_algorithm(grpc_compression_algorithm algorithm);
+
+  /// Return the peer uri in a string.
+  ///
+  /// \warning This value is never authenticated or subject to any security
+  /// related code. It must not be used for any authentication related
+  /// functionality. Instead, use auth_context.
+  ///
+  /// \return The call's peer URI.
+  grpc::string peer() const;
+
+  /// Get and set census context.
+  void set_census_context(struct census_context* ccp) { census_context_ = ccp; }
+  struct census_context* census_context() const {
+    return census_context_;
+  }
+
+  /// Send a best-effort out-of-band cancel. The call could be in any stage.
+  /// e.g. if it is already finished, it may still return success.
+  ///
+  /// There is no guarantee the call will be cancelled.
+  void TryCancel();
+
+  /// Global Callbacks
+  ///
+  /// Can be set exactly once per application to install hooks whenever
+  /// a client context is constructed and destructed.
+  class GlobalCallbacks {
+   public:
+    virtual ~GlobalCallbacks() {}
+    virtual void DefaultConstructor(ClientContext* context) = 0;
+    virtual void Destructor(ClientContext* context) = 0;
+  };
+  static void SetGlobalCallbacks(GlobalCallbacks* callbacks);
+
+ private:
+  // Disallow copy and assign.
+  ClientContext(const ClientContext&);
+  ClientContext& operator=(const ClientContext&);
+
+  friend class ::grpc::testing::InteropClientContextInspector;
+  friend class CallOpClientRecvStatus;
+  friend class CallOpRecvInitialMetadata;
+  friend class Channel;
+  template <class R>
+  friend class ::grpc::ClientReader;
+  template <class W>
+  friend class ::grpc::ClientWriter;
+  template <class W, class R>
+  friend class ::grpc::ClientReaderWriter;
+  template <class R>
+  friend class ::grpc::ClientAsyncReader;
+  template <class W>
+  friend class ::grpc::ClientAsyncWriter;
+  template <class W, class R>
+  friend class ::grpc::ClientAsyncReaderWriter;
+  template <class R>
+  friend class ::grpc::ClientAsyncResponseReader;
+  template <class InputMessage, class OutputMessage>
+  friend Status BlockingUnaryCall(ChannelInterface* channel,
+                                  const RpcMethod& method,
+                                  ClientContext* context,
+                                  const InputMessage& request,
+                                  OutputMessage* result);
+
+  grpc_call* call() { return call_; }
+  void set_call(grpc_call* call, const std::shared_ptr<Channel>& channel);
+
+  grpc::string authority() { return authority_; }
+
+  bool initial_metadata_received_;
+  std::shared_ptr<Channel> channel_;
+  grpc::mutex mu_;
+  grpc_call* call_;
+  bool call_canceled_;
+  gpr_timespec deadline_;
+  grpc::string authority_;
+  std::shared_ptr<CallCredentials> creds_;
+  mutable std::shared_ptr<const AuthContext> auth_context_;
+  struct census_context* census_context_;
+  std::multimap<grpc::string, grpc::string> send_initial_metadata_;
+  std::multimap<grpc::string_ref, grpc::string_ref> recv_initial_metadata_;
+  std::multimap<grpc::string_ref, grpc::string_ref> trailing_metadata_;
+
+  grpc_call* propagate_from_call_;
+  PropagationOptions propagation_options_;
+
+  grpc_compression_algorithm compression_algorithm_;
+};
+
+}  // namespace grpc
+
+#endif  // GRPCXX_IMPL_CODEGEN_CLIENT_CONTEXT_H
diff --git a/include/grpc++/impl/codegen/client_unary_call.h b/include/grpc++/impl/codegen/client_unary_call.h
new file mode 100644
index 0000000..0134dec
--- /dev/null
+++ b/include/grpc++/impl/codegen/client_unary_call.h
@@ -0,0 +1,75 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef GRPCXX_IMPL_CODEGEN_CLIENT_UNARY_CALL_H
+#define GRPCXX_IMPL_CODEGEN_CLIENT_UNARY_CALL_H
+
+#include <grpc++/impl/codegen/call.h>
+#include <grpc++/impl/codegen/channel_interface.h>
+#include <grpc++/impl/codegen/config.h>
+#include <grpc++/impl/codegen/status.h>
+
+namespace grpc {
+
+class Channel;
+class ClientContext;
+class CompletionQueue;
+class RpcMethod;
+
+// Wrapper that performs a blocking unary call
+template <class InputMessage, class OutputMessage>
+Status BlockingUnaryCall(ChannelInterface* channel, const RpcMethod& method,
+                         ClientContext* context, const InputMessage& request,
+                         OutputMessage* result) {
+  CompletionQueue cq;
+  Call call(channel->CreateCall(method, context, &cq));
+  CallOpSet<CallOpSendInitialMetadata, CallOpSendMessage,
+            CallOpRecvInitialMetadata, CallOpRecvMessage<OutputMessage>,
+            CallOpClientSendClose, CallOpClientRecvStatus> ops;
+  Status status = ops.SendMessage(request);
+  if (!status.ok()) {
+    return status;
+  }
+  ops.SendInitialMetadata(context->send_initial_metadata_);
+  ops.RecvInitialMetadata(context);
+  ops.RecvMessage(result);
+  ops.ClientSendClose();
+  ops.ClientRecvStatus(context, &status);
+  call.PerformOps(&ops);
+  GPR_ASSERT((cq.Pluck(&ops) && ops.got_message) || !status.ok());
+  return status;
+}
+
+}  // namespace grpc
+
+#endif  // GRPCXX_IMPL_CODEGEN_CLIENT_UNARY_CALL_H
diff --git a/include/grpc++/impl/codegen/completion_queue.h b/include/grpc++/impl/codegen/completion_queue.h
new file mode 100644
index 0000000..102831e
--- /dev/null
+++ b/include/grpc++/impl/codegen/completion_queue.h
@@ -0,0 +1,202 @@
+/*
+ *
+ * Copyright 2015-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.
+ *
+ */
+
+/// A completion queue implements a concurrent producer-consumer queue, with two
+/// main methods, \a Next and \a AsyncNext.
+#ifndef GRPCXX_IMPL_CODEGEN_COMPLETION_QUEUE_H
+#define GRPCXX_IMPL_CODEGEN_COMPLETION_QUEUE_H
+
+#include <grpc++/impl/codegen/grpc_library.h>
+#include <grpc++/impl/codegen/status.h>
+#include <grpc++/impl/codegen/time.h>
+
+struct grpc_completion_queue;
+
+namespace grpc {
+
+template <class R>
+class ClientReader;
+template <class W>
+class ClientWriter;
+template <class W, class R>
+class ClientReaderWriter;
+template <class R>
+class ServerReader;
+template <class W>
+class ServerWriter;
+template <class W, class R>
+class ServerReaderWriter;
+template <class ServiceType, class RequestType, class ResponseType>
+class RpcMethodHandler;
+template <class ServiceType, class RequestType, class ResponseType>
+class ClientStreamingHandler;
+template <class ServiceType, class RequestType, class ResponseType>
+class ServerStreamingHandler;
+template <class ServiceType, class RequestType, class ResponseType>
+class BidiStreamingHandler;
+class UnknownMethodHandler;
+
+class Channel;
+class ChannelInterface;
+class ClientContext;
+class CompletionQueueTag;
+class CompletionQueue;
+class RpcMethod;
+class Server;
+class ServerBuilder;
+class ServerContext;
+
+/// A thin wrapper around \a grpc_completion_queue (see / \a
+/// src/core/surface/completion_queue.h).
+class CompletionQueue : private GrpcLibrary {
+ public:
+  /// Default constructor. Implicitly creates a \a grpc_completion_queue
+  /// instance.
+  CompletionQueue();
+
+  /// Wrap \a take, taking ownership of the instance.
+  ///
+  /// \param take The completion queue instance to wrap. Ownership is taken.
+  explicit CompletionQueue(grpc_completion_queue* take);
+
+  /// Destructor. Destroys the owned wrapped completion queue / instance.
+  ~CompletionQueue();
+
+  /// Tri-state return for AsyncNext: SHUTDOWN, GOT_EVENT, TIMEOUT.
+  enum NextStatus {
+    SHUTDOWN,   ///< The completion queue has been shutdown.
+    GOT_EVENT,  ///< Got a new event; \a tag will be filled in with its
+                ///< associated value; \a ok indicating its success.
+    TIMEOUT     ///< deadline was reached.
+  };
+
+  /// Read from the queue, blocking up to \a deadline (or the queue's shutdown).
+  /// Both \a tag and \a ok are updated upon success (if an event is available
+  /// within the \a deadline).  A \a tag points to an arbitrary location usually
+  /// employed to uniquely identify an event.
+  ///
+  /// \param tag[out] Upon sucess, updated to point to the event's tag.
+  /// \param ok[out] Upon sucess, true if read a regular event, false otherwise.
+  /// \param deadline[in] How long to block in wait for an event.
+  ///
+  /// \return The type of event read.
+  template <typename T>
+  NextStatus AsyncNext(void** tag, bool* ok, const T& deadline) {
+    TimePoint<T> deadline_tp(deadline);
+    return AsyncNextInternal(tag, ok, deadline_tp.raw_time());
+  }
+
+  /// Read from the queue, blocking until an event is available or the queue is
+  /// shutting down.
+  ///
+  /// \param tag[out] Updated to point to the read event's tag.
+  /// \param ok[out] true if read a regular event, false otherwise.
+  ///
+  /// \return true if read a regular event, false if the queue is shutting down.
+  bool Next(void** tag, bool* ok) {
+    return (AsyncNextInternal(tag, ok, gpr_inf_future(GPR_CLOCK_REALTIME)) !=
+            SHUTDOWN);
+  }
+
+  /// Request the shutdown of the queue.
+  ///
+  /// \warning This method must be called at some point. Once invoked, \a Next
+  /// will start to return false and \a AsyncNext will return \a
+  /// NextStatus::SHUTDOWN. Only once either one of these methods does that
+  /// (that is, once the queue has been \em drained) can an instance of this
+  /// class be destroyed.
+  void Shutdown();
+
+  /// Returns a \em raw pointer to the underlying \a grpc_completion_queue
+  /// instance.
+  ///
+  /// \warning Remember that the returned instance is owned. No transfer of
+  /// owership is performed.
+  grpc_completion_queue* cq() { return cq_; }
+
+ private:
+  // Friend synchronous wrappers so that they can access Pluck(), which is
+  // a semi-private API geared towards the synchronous implementation.
+  template <class R>
+  friend class ::grpc::ClientReader;
+  template <class W>
+  friend class ::grpc::ClientWriter;
+  template <class W, class R>
+  friend class ::grpc::ClientReaderWriter;
+  template <class R>
+  friend class ::grpc::ServerReader;
+  template <class W>
+  friend class ::grpc::ServerWriter;
+  template <class W, class R>
+  friend class ::grpc::ServerReaderWriter;
+  template <class ServiceType, class RequestType, class ResponseType>
+  friend class RpcMethodHandler;
+  template <class ServiceType, class RequestType, class ResponseType>
+  friend class ClientStreamingHandler;
+  template <class ServiceType, class RequestType, class ResponseType>
+  friend class ServerStreamingHandler;
+  template <class ServiceType, class RequestType, class ResponseType>
+  friend class BidiStreamingHandler;
+  friend class UnknownMethodHandler;
+  friend class ::grpc::Server;
+  friend class ::grpc::ServerContext;
+  template <class InputMessage, class OutputMessage>
+  friend Status BlockingUnaryCall(ChannelInterface* channel,
+                                  const RpcMethod& method,
+                                  ClientContext* context,
+                                  const InputMessage& request,
+                                  OutputMessage* result);
+
+  NextStatus AsyncNextInternal(void** tag, bool* ok, gpr_timespec deadline);
+
+  /// Wraps \a grpc_completion_queue_pluck.
+  /// \warning Must not be mixed with calls to \a Next.
+  bool Pluck(CompletionQueueTag* tag);
+
+  /// Performs a single polling pluck on \a tag.
+  void TryPluck(CompletionQueueTag* tag);
+
+  grpc_completion_queue* cq_;  // owned
+};
+
+/// A specific type of completion queue used by the processing of notifications
+/// by servers. Instantiated by \a ServerBuilder.
+class ServerCompletionQueue : public CompletionQueue {
+ private:
+  friend class ServerBuilder;
+  ServerCompletionQueue() {}
+};
+
+}  // namespace grpc
+
+#endif  // GRPCXX_IMPL_CODEGEN_COMPLETION_QUEUE_H
diff --git a/src/core/census/context.h b/include/grpc++/impl/codegen/completion_queue_tag.h
similarity index 70%
rename from src/core/census/context.h
rename to include/grpc++/impl/codegen/completion_queue_tag.h
index 700bcf8..8be2ac3 100644
--- a/src/core/census/context.h
+++ b/include/grpc++/impl/codegen/completion_queue_tag.h
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -31,17 +31,22 @@
  *
  */
 
-#ifndef GRPC_INTERNAL_CORE_CENSUS_CONTEXT_H
-#define GRPC_INTERNAL_CORE_CENSUS_CONTEXT_H
+#ifndef GRPCXX_COMPLETION_QUEUE_TAG_H
+#define GRPCXX_COMPLETION_QUEUE_TAG_H
 
-#include <grpc/census.h>
+namespace grpc {
 
-#define GRPC_CENSUS_MAX_ON_THE_WIRE_TAG_BYTES 2048
-
-/* census_context is the in-memory representation of information needed to
- * maintain tracing, RPC statistics and resource usage information. */
-struct census_context {
-  census_tag_set *tags; /* Opaque data structure for census tags. */
+/// An interface allowing implementors to process and filter event tags.
+class CompletionQueueTag {
+ public:
+  virtual ~CompletionQueueTag() {}
+  // Called prior to returning from Next(), return value is the status of the
+  // operation (return status is the default thing to do). If this function
+  // returns false, the tag is dropped and not returned from the completion
+  // queue
+  virtual bool FinalizeResult(void** tag, bool* status) = 0;
 };
 
-#endif /* GRPC_INTERNAL_CORE_CENSUS_CONTEXT_H */
+}  // namespace grpc
+
+#endif  // GRPCXX_COMPLETION_QUEUE_TAG_H
diff --git a/include/grpc++/impl/codegen/config.h b/include/grpc++/impl/codegen/config.h
new file mode 100644
index 0000000..d782d5f
--- /dev/null
+++ b/include/grpc++/impl/codegen/config.h
@@ -0,0 +1,116 @@
+/*
+ *
+ * Copyright 2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef GRPCXX_IMPL_CODEGEN_CONFIG_H
+#define GRPCXX_IMPL_CODEGEN_CONFIG_H
+
+#if !defined(GRPC_NO_AUTODETECT_PLATFORM)
+
+#ifdef _MSC_VER
+// Visual Studio 2010 is 1600.
+#if _MSC_VER < 1600
+#error "gRPC is only supported with Visual Studio starting at 2010"
+// Visual Studio 2013 is 1800.
+#elif _MSC_VER < 1800
+#define GRPC_CXX0X_NO_FINAL 1
+#define GRPC_CXX0X_NO_OVERRIDE 1
+#define GRPC_CXX0X_NO_CHRONO 1
+#define GRPC_CXX0X_NO_THREAD 1
+#endif
+#endif  // Visual Studio
+
+#ifndef __clang__
+#ifdef __GNUC__
+// nullptr was added in gcc 4.6
+#if (__GNUC__ * 100 + __GNUC_MINOR__ < 406)
+#define GRPC_CXX0X_NO_NULLPTR 1
+#endif
+// final and override were added in gcc 4.7
+#if (__GNUC__ * 100 + __GNUC_MINOR__ < 407)
+#define GRPC_CXX0X_NO_FINAL 1
+#define GRPC_CXX0X_NO_OVERRIDE 1
+#endif
+#endif
+#endif
+
+#endif
+
+#ifdef GRPC_CXX0X_NO_FINAL
+#define GRPC_FINAL
+#else
+#define GRPC_FINAL final
+#endif
+
+#ifdef GRPC_CXX0X_NO_OVERRIDE
+#define GRPC_OVERRIDE
+#else
+#define GRPC_OVERRIDE override
+#endif
+
+#ifdef GRPC_CXX0X_NO_NULLPTR
+#include <memory>
+namespace grpc {
+const class {
+ public:
+  template <class T>
+  operator T *() const {
+    return static_cast<T *>(0);
+  }
+  template <class T>
+  operator std::unique_ptr<T>() const {
+    return std::unique_ptr<T>(static_cast<T *>(0));
+  }
+  template <class T>
+  operator std::shared_ptr<T>() const {
+    return std::shared_ptr<T>(static_cast<T *>(0));
+  }
+  operator bool() const { return false; }
+
+ private:
+  void operator&() const = delete;
+} nullptr = {};
+}
+#endif
+
+#ifndef GRPC_CUSTOM_STRING
+#include <string>
+#define GRPC_CUSTOM_STRING std::string
+#endif
+
+namespace grpc {
+
+typedef GRPC_CUSTOM_STRING string;
+
+}  // namespace grpc
+
+#endif  // GRPCXX_IMPL_CODEGEN_CONFIG_H
diff --git a/include/grpc++/impl/codegen/config_protobuf.h b/include/grpc++/impl/codegen/config_protobuf.h
new file mode 100644
index 0000000..3b9f05c
--- /dev/null
+++ b/include/grpc++/impl/codegen/config_protobuf.h
@@ -0,0 +1,72 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef GRPCXX_IMPL_CODEGEN_CONFIG_PROTOBUF_H
+#define GRPCXX_IMPL_CODEGEN_CONFIG_PROTOBUF_H
+
+#ifndef GRPC_CUSTOM_PROTOBUF_INT64
+#include <google/protobuf/stubs/common.h>
+#define GRPC_CUSTOM_PROTOBUF_INT64 ::google::protobuf::int64
+#endif
+
+#ifndef GRPC_CUSTOM_MESSAGE
+#include <google/protobuf/message.h>
+#define GRPC_CUSTOM_MESSAGE ::google::protobuf::Message
+#endif
+
+#ifndef GRPC_CUSTOM_ZEROCOPYOUTPUTSTREAM
+#include <google/protobuf/io/coded_stream.h>
+#include <google/protobuf/io/zero_copy_stream.h>
+#define GRPC_CUSTOM_ZEROCOPYOUTPUTSTREAM \
+  ::google::protobuf::io::ZeroCopyOutputStream
+#define GRPC_CUSTOM_ZEROCOPYINPUTSTREAM \
+  ::google::protobuf::io::ZeroCopyInputStream
+#define GRPC_CUSTOM_CODEDINPUTSTREAM ::google::protobuf::io::CodedInputStream
+#endif
+
+namespace grpc {
+namespace protobuf {
+
+typedef GRPC_CUSTOM_MESSAGE Message;
+typedef GRPC_CUSTOM_PROTOBUF_INT64 int64;
+
+namespace io {
+typedef GRPC_CUSTOM_ZEROCOPYOUTPUTSTREAM ZeroCopyOutputStream;
+typedef GRPC_CUSTOM_ZEROCOPYINPUTSTREAM ZeroCopyInputStream;
+typedef GRPC_CUSTOM_CODEDINPUTSTREAM CodedInputStream;
+}  // namespace io
+
+}  // namespace protobuf
+}  // namespace grpc
+
+#endif  // GRPCXX_IMPL_CODEGEN_CONFIG_PROTOBUF_H
diff --git a/src/objective-c/GRPCClient/private/GRPCUnsecuredChannel.h b/include/grpc++/impl/codegen/grpc_library.h
similarity index 66%
copy from src/objective-c/GRPCClient/private/GRPCUnsecuredChannel.h
copy to include/grpc++/impl/codegen/grpc_library.h
index 8528be4..eb7152a 100644
--- a/src/objective-c/GRPCClient/private/GRPCUnsecuredChannel.h
+++ b/include/grpc++/impl/codegen/grpc_library.h
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -31,8 +31,37 @@
  *
  */
 
-#import "GRPCChannel.h"
+#ifndef GRPCXX_IMPL_CODEGEN_GRPC_LIBRARY_H
+#define GRPCXX_IMPL_CODEGEN_GRPC_LIBRARY_H
 
-@interface GRPCUnsecuredChannel : GRPCChannel
-- (instancetype)initWithHost:(NSString *)host NS_DESIGNATED_INITIALIZER;
-@end
+#include <grpc/impl/codegen/log.h>
+
+namespace grpc {
+
+class GrpcLibraryInterface {
+ public:
+  virtual void init() = 0;
+  virtual void shutdown() = 0;
+};
+
+extern GrpcLibraryInterface* g_glip;
+
+class GrpcLibrary {
+ public:
+  GrpcLibrary() {
+    GPR_ASSERT(g_glip &&
+               "gRPC library not initialized. See "
+               "grpc::internal::GrpcLibraryInitializer.");
+    g_glip->init();
+  }
+  virtual ~GrpcLibrary() {
+    GPR_ASSERT(g_glip &&
+               "gRPC library not initialized. See "
+               "grpc::internal::GrpcLibraryInitializer.");
+    g_glip->shutdown();
+  }
+};
+
+}  // namespace grpc
+
+#endif  // GRPCXX_IMPL_GRPC_LIBRARY_H
diff --git a/include/grpc++/impl/codegen/method_handler_impl.h b/include/grpc++/impl/codegen/method_handler_impl.h
new file mode 100644
index 0000000..1bf9bf0
--- /dev/null
+++ b/include/grpc++/impl/codegen/method_handler_impl.h
@@ -0,0 +1,203 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef GRPCXX_IMPL_CODEGEN_METHOD_HANDLER_IMPL_H
+#define GRPCXX_IMPL_CODEGEN_METHOD_HANDLER_IMPL_H
+
+#include <grpc++/impl/codegen/rpc_service_method.h>
+#include <grpc++/impl/codegen/sync_stream.h>
+
+namespace grpc {
+
+// A wrapper class of an application provided rpc method handler.
+template <class ServiceType, class RequestType, class ResponseType>
+class RpcMethodHandler : public MethodHandler {
+ public:
+  RpcMethodHandler(
+      std::function<Status(ServiceType*, ServerContext*, const RequestType*,
+                           ResponseType*)> func,
+      ServiceType* service)
+      : func_(func), service_(service) {}
+
+  void RunHandler(const HandlerParameter& param) GRPC_FINAL {
+    RequestType req;
+    Status status = SerializationTraits<RequestType>::Deserialize(
+        param.request, &req, param.max_message_size);
+    ResponseType rsp;
+    if (status.ok()) {
+      status = func_(service_, param.server_context, &req, &rsp);
+    }
+
+    GPR_ASSERT(!param.server_context->sent_initial_metadata_);
+    CallOpSet<CallOpSendInitialMetadata, CallOpSendMessage,
+              CallOpServerSendStatus> ops;
+    ops.SendInitialMetadata(param.server_context->initial_metadata_);
+    if (status.ok()) {
+      status = ops.SendMessage(rsp);
+    }
+    ops.ServerSendStatus(param.server_context->trailing_metadata_, status);
+    param.call->PerformOps(&ops);
+    param.call->cq()->Pluck(&ops);
+  }
+
+ private:
+  // Application provided rpc handler function.
+  std::function<Status(ServiceType*, ServerContext*, const RequestType*,
+                       ResponseType*)> func_;
+  // The class the above handler function lives in.
+  ServiceType* service_;
+};
+
+// A wrapper class of an application provided client streaming handler.
+template <class ServiceType, class RequestType, class ResponseType>
+class ClientStreamingHandler : public MethodHandler {
+ public:
+  ClientStreamingHandler(
+      std::function<Status(ServiceType*, ServerContext*,
+                           ServerReader<RequestType>*, ResponseType*)> func,
+      ServiceType* service)
+      : func_(func), service_(service) {}
+
+  void RunHandler(const HandlerParameter& param) GRPC_FINAL {
+    ServerReader<RequestType> reader(param.call, param.server_context);
+    ResponseType rsp;
+    Status status = func_(service_, param.server_context, &reader, &rsp);
+
+    GPR_ASSERT(!param.server_context->sent_initial_metadata_);
+    CallOpSet<CallOpSendInitialMetadata, CallOpSendMessage,
+              CallOpServerSendStatus> ops;
+    ops.SendInitialMetadata(param.server_context->initial_metadata_);
+    if (status.ok()) {
+      status = ops.SendMessage(rsp);
+    }
+    ops.ServerSendStatus(param.server_context->trailing_metadata_, status);
+    param.call->PerformOps(&ops);
+    param.call->cq()->Pluck(&ops);
+  }
+
+ private:
+  std::function<Status(ServiceType*, ServerContext*, ServerReader<RequestType>*,
+                       ResponseType*)> func_;
+  ServiceType* service_;
+};
+
+// A wrapper class of an application provided server streaming handler.
+template <class ServiceType, class RequestType, class ResponseType>
+class ServerStreamingHandler : public MethodHandler {
+ public:
+  ServerStreamingHandler(
+      std::function<Status(ServiceType*, ServerContext*, const RequestType*,
+                           ServerWriter<ResponseType>*)> func,
+      ServiceType* service)
+      : func_(func), service_(service) {}
+
+  void RunHandler(const HandlerParameter& param) GRPC_FINAL {
+    RequestType req;
+    Status status = SerializationTraits<RequestType>::Deserialize(
+        param.request, &req, param.max_message_size);
+
+    if (status.ok()) {
+      ServerWriter<ResponseType> writer(param.call, param.server_context);
+      status = func_(service_, param.server_context, &req, &writer);
+    }
+
+    CallOpSet<CallOpSendInitialMetadata, CallOpServerSendStatus> ops;
+    if (!param.server_context->sent_initial_metadata_) {
+      ops.SendInitialMetadata(param.server_context->initial_metadata_);
+    }
+    ops.ServerSendStatus(param.server_context->trailing_metadata_, status);
+    param.call->PerformOps(&ops);
+    param.call->cq()->Pluck(&ops);
+  }
+
+ private:
+  std::function<Status(ServiceType*, ServerContext*, const RequestType*,
+                       ServerWriter<ResponseType>*)> func_;
+  ServiceType* service_;
+};
+
+// A wrapper class of an application provided bidi-streaming handler.
+template <class ServiceType, class RequestType, class ResponseType>
+class BidiStreamingHandler : public MethodHandler {
+ public:
+  BidiStreamingHandler(
+      std::function<Status(ServiceType*, ServerContext*,
+                           ServerReaderWriter<ResponseType, RequestType>*)>
+          func,
+      ServiceType* service)
+      : func_(func), service_(service) {}
+
+  void RunHandler(const HandlerParameter& param) GRPC_FINAL {
+    ServerReaderWriter<ResponseType, RequestType> stream(param.call,
+                                                         param.server_context);
+    Status status = func_(service_, param.server_context, &stream);
+
+    CallOpSet<CallOpSendInitialMetadata, CallOpServerSendStatus> ops;
+    if (!param.server_context->sent_initial_metadata_) {
+      ops.SendInitialMetadata(param.server_context->initial_metadata_);
+    }
+    ops.ServerSendStatus(param.server_context->trailing_metadata_, status);
+    param.call->PerformOps(&ops);
+    param.call->cq()->Pluck(&ops);
+  }
+
+ private:
+  std::function<Status(ServiceType*, ServerContext*,
+                       ServerReaderWriter<ResponseType, RequestType>*)> func_;
+  ServiceType* service_;
+};
+
+// Handle unknown method by returning UNIMPLEMENTED error.
+class UnknownMethodHandler : public MethodHandler {
+ public:
+  template <class T>
+  static void FillOps(ServerContext* context, T* ops) {
+    Status status(StatusCode::UNIMPLEMENTED, "");
+    if (!context->sent_initial_metadata_) {
+      ops->SendInitialMetadata(context->initial_metadata_);
+      context->sent_initial_metadata_ = true;
+    }
+    ops->ServerSendStatus(context->trailing_metadata_, status);
+  }
+
+  void RunHandler(const HandlerParameter& param) GRPC_FINAL {
+    CallOpSet<CallOpSendInitialMetadata, CallOpServerSendStatus> ops;
+    FillOps(param.server_context, &ops);
+    param.call->PerformOps(&ops);
+    param.call->cq()->Pluck(&ops);
+  }
+};
+
+}  // namespace grpc
+
+#endif  // GRPCXX_IMPL_CODEGEN_METHOD_HANDLER_IMPL_H
diff --git a/include/grpc++/impl/codegen/proto_utils.h b/include/grpc++/impl/codegen/proto_utils.h
new file mode 100644
index 0000000..ce17710
--- /dev/null
+++ b/include/grpc++/impl/codegen/proto_utils.h
@@ -0,0 +1,76 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef GRPCXX_IMPL_CODEGEN_PROTO_UTILS_H
+#define GRPCXX_IMPL_CODEGEN_PROTO_UTILS_H
+
+#include <type_traits>
+
+#include <grpc/impl/codegen/byte_buffer.h>
+#include <grpc++/impl/codegen/serialization_traits.h>
+#include <grpc++/impl/codegen/config_protobuf.h>
+#include <grpc++/impl/codegen/status.h>
+
+namespace grpc {
+
+// Serialize the msg into a buffer created inside the function. The caller
+// should destroy the returned buffer when done with it. If serialization fails,
+// false is returned and buffer is left unchanged.
+Status SerializeProto(const grpc::protobuf::Message& msg,
+                      grpc_byte_buffer** buffer);
+
+// The caller keeps ownership of buffer and msg.
+Status DeserializeProto(grpc_byte_buffer* buffer, grpc::protobuf::Message* msg,
+                        int max_message_size);
+
+template <class T>
+class SerializationTraits<T, typename std::enable_if<std::is_base_of<
+                                 grpc::protobuf::Message, T>::value>::type> {
+ public:
+  static Status Serialize(const grpc::protobuf::Message& msg,
+                          grpc_byte_buffer** buffer, bool* own_buffer) {
+    *own_buffer = true;
+    return SerializeProto(msg, buffer);
+  }
+  static Status Deserialize(grpc_byte_buffer* buffer,
+                            grpc::protobuf::Message* msg,
+                            int max_message_size) {
+    auto status = DeserializeProto(buffer, msg, max_message_size);
+    grpc_byte_buffer_destroy(buffer);
+    return status;
+  }
+};
+
+}  // namespace grpc
+
+#endif  // GRPCXX_IMPL_CODEGEN_PROTO_UTILS_H
diff --git a/include/grpc++/impl/codegen/rpc_method.h b/include/grpc++/impl/codegen/rpc_method.h
new file mode 100644
index 0000000..85d5c1c
--- /dev/null
+++ b/include/grpc++/impl/codegen/rpc_method.h
@@ -0,0 +1,73 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef GRPCXX_IMPL_CODEGEN_RPC_METHOD_H
+#define GRPCXX_IMPL_CODEGEN_RPC_METHOD_H
+
+#include <memory>
+
+#include <grpc++/impl/codegen/channel_interface.h>
+
+namespace grpc {
+
+class RpcMethod {
+ public:
+  enum RpcType {
+    NORMAL_RPC = 0,
+    CLIENT_STREAMING,  // request streaming
+    SERVER_STREAMING,  // response streaming
+    BIDI_STREAMING
+  };
+
+  RpcMethod(const char* name, RpcType type)
+      : name_(name), method_type_(type), channel_tag_(NULL) {}
+
+  RpcMethod(const char* name, RpcType type,
+            const std::shared_ptr<ChannelInterface>& channel)
+      : name_(name),
+        method_type_(type),
+        channel_tag_(channel->RegisterMethod(name)) {}
+
+  const char* name() const { return name_; }
+  RpcType method_type() const { return method_type_; }
+  void* channel_tag() const { return channel_tag_; }
+
+ private:
+  const char* const name_;
+  const RpcType method_type_;
+  void* const channel_tag_;
+};
+
+}  // namespace grpc
+
+#endif  // GRPCXX_IMPL_CODEGEN_RPC_METHOD_H
diff --git a/include/grpc++/impl/codegen/rpc_service_method.h b/include/grpc++/impl/codegen/rpc_service_method.h
new file mode 100644
index 0000000..6256301
--- /dev/null
+++ b/include/grpc++/impl/codegen/rpc_service_method.h
@@ -0,0 +1,93 @@
+/*
+ *
+ * Copyright 2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef GRPCXX_IMPL_CODEGEN_RPC_SERVICE_METHOD_H
+#define GRPCXX_IMPL_CODEGEN_RPC_SERVICE_METHOD_H
+
+#include <climits>
+#include <functional>
+#include <map>
+#include <memory>
+#include <vector>
+
+#include <grpc/impl/codegen/byte_buffer.h>
+#include <grpc++/impl/codegen/config.h>
+#include <grpc++/impl/codegen/rpc_method.h>
+#include <grpc++/impl/codegen/status.h>
+
+namespace grpc {
+class ServerContext;
+class StreamContextInterface;
+
+// Base class for running an RPC handler.
+class MethodHandler {
+ public:
+  virtual ~MethodHandler() {}
+  struct HandlerParameter {
+    HandlerParameter(Call* c, ServerContext* context, grpc_byte_buffer* req,
+                     int max_size)
+        : call(c),
+          server_context(context),
+          request(req),
+          max_message_size(max_size) {}
+    Call* call;
+    ServerContext* server_context;
+    // Handler required to grpc_byte_buffer_destroy this
+    grpc_byte_buffer* request;
+    int max_message_size;
+  };
+  virtual void RunHandler(const HandlerParameter& param) = 0;
+};
+
+// Server side rpc method class
+class RpcServiceMethod : public RpcMethod {
+ public:
+  // Takes ownership of the handler
+  RpcServiceMethod(const char* name, RpcMethod::RpcType type,
+                   MethodHandler* handler)
+      : RpcMethod(name, type), server_tag_(nullptr), handler_(handler) {}
+
+  void set_server_tag(void* tag) { server_tag_ = tag; }
+  void* server_tag() const { return server_tag_; }
+  // if MethodHandler is nullptr, then this is an async method
+  MethodHandler* handler() const { return handler_.get(); }
+  void ResetHandler() { handler_.reset(); }
+
+ private:
+  void* server_tag_;
+  std::unique_ptr<MethodHandler> handler_;
+};
+
+}  // namespace grpc
+
+#endif  // GRPCXX_IMPL_CODEGEN_RPC_SERVICE_METHOD_H
diff --git a/include/grpc++/impl/codegen/security/auth_context.h b/include/grpc++/impl/codegen/security/auth_context.h
new file mode 100644
index 0000000..7544430
--- /dev/null
+++ b/include/grpc++/impl/codegen/security/auth_context.h
@@ -0,0 +1,110 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef GRPCXX_IMPL_CODEGEN_SECURITY_AUTH_CONTEXT_H
+#define GRPCXX_IMPL_CODEGEN_SECURITY_AUTH_CONTEXT_H
+
+#include <iterator>
+#include <vector>
+
+#include <grpc++/impl/codegen/config.h>
+#include <grpc++/impl/codegen/string_ref.h>
+
+struct grpc_auth_context;
+struct grpc_auth_property;
+struct grpc_auth_property_iterator;
+
+namespace grpc {
+class SecureAuthContext;
+
+typedef std::pair<grpc::string_ref, grpc::string_ref> AuthProperty;
+
+class AuthPropertyIterator
+    : public std::iterator<std::input_iterator_tag, const AuthProperty> {
+ public:
+  ~AuthPropertyIterator();
+  AuthPropertyIterator& operator++();
+  AuthPropertyIterator operator++(int);
+  bool operator==(const AuthPropertyIterator& rhs) const;
+  bool operator!=(const AuthPropertyIterator& rhs) const;
+  const AuthProperty operator*();
+
+ protected:
+  AuthPropertyIterator();
+  AuthPropertyIterator(const grpc_auth_property* property,
+                       const grpc_auth_property_iterator* iter);
+
+ private:
+  friend class SecureAuthContext;
+  const grpc_auth_property* property_;
+  // The following items form a grpc_auth_property_iterator.
+  const grpc_auth_context* ctx_;
+  size_t index_;
+  const char* name_;
+};
+
+/// Class encapsulating the Authentication Information.
+///
+/// It includes the secure identity of the peer, the type of secure transport
+/// used as well as any other properties required by the authorization layer.
+class AuthContext {
+ public:
+  virtual ~AuthContext() {}
+
+  /// Returns true if the peer is authenticated.
+  virtual bool IsPeerAuthenticated() const = 0;
+
+  /// A peer identity.
+  ///
+  /// It is, in general, comprised of one or more properties (in which case they
+  /// have the same name).
+  virtual std::vector<grpc::string_ref> GetPeerIdentity() const = 0;
+  virtual grpc::string GetPeerIdentityPropertyName() const = 0;
+
+  /// Returns all the property values with the given name.
+  virtual std::vector<grpc::string_ref> FindPropertyValues(
+      const grpc::string& name) const = 0;
+
+  /// Iteration over all the properties.
+  virtual AuthPropertyIterator begin() const = 0;
+  virtual AuthPropertyIterator end() const = 0;
+
+  // Mutation functions: should only be used by an AuthMetadataProcessor.
+  virtual void AddProperty(const grpc::string& key,
+                           const grpc::string_ref& value) = 0;
+  virtual bool SetPeerIdentityPropertyName(const grpc::string& name) = 0;
+};
+
+}  // namespace grpc
+
+#endif  // GRPCXX_IMPL_CODEGEN_SECURITY_AUTH_CONTEXT_H
diff --git a/include/grpc++/impl/codegen/serialization_traits.h b/include/grpc++/impl/codegen/serialization_traits.h
new file mode 100644
index 0000000..83c3b64
--- /dev/null
+++ b/include/grpc++/impl/codegen/serialization_traits.h
@@ -0,0 +1,68 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef GRPCXX_IMPL_CODEGEN_SERIALIZATION_TRAITS_H
+#define GRPCXX_IMPL_CODEGEN_SERIALIZATION_TRAITS_H
+
+namespace grpc {
+
+/// Defines how to serialize and deserialize some type.
+///
+/// Used for hooking different message serialization API's into GRPC.
+/// Each SerializationTraits implementation must provide the following
+/// functions:
+///   static Status Serialize(const Message& msg,
+///                           grpc_byte_buffer** buffer,
+//                            bool* own_buffer);
+///   static Status Deserialize(grpc_byte_buffer* buffer,
+///                             Message* msg,
+///                             int max_message_size);
+///
+/// Serialize is required to convert message to a grpc_byte_buffer, and
+/// to store a pointer to that byte buffer at *buffer. *own_buffer should
+/// be set to true if the caller owns said byte buffer, or false if
+/// ownership is retained elsewhere.
+///
+/// Deserialize is required to convert buffer into the message stored at
+/// msg. max_message_size is passed in as a bound on the maximum number of
+/// message bytes Deserialize should accept.
+///
+/// Both functions return a Status, allowing them to explain what went
+/// wrong if required.
+template <class Message,
+          class UnusedButHereForPartialTemplateSpecialization = void>
+class SerializationTraits;
+
+}  // namespace grpc
+
+#endif  // GRPCXX_IMPL_CODEGEN_SERIALIZATION_TRAITS_H
diff --git a/include/grpc++/impl/codegen/server_context.h b/include/grpc++/impl/codegen/server_context.h
new file mode 100644
index 0000000..ad08b82
--- /dev/null
+++ b/include/grpc++/impl/codegen/server_context.h
@@ -0,0 +1,214 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef GRPCXX_IMPL_CODEGEN_SERVER_CONTEXT_H
+#define GRPCXX_IMPL_CODEGEN_SERVER_CONTEXT_H
+
+#include <map>
+#include <memory>
+
+#include <grpc/impl/codegen/compression_types.h>
+#include <grpc/impl/codegen/time.h>
+#include <grpc++/impl/codegen/security/auth_context.h>
+#include <grpc++/impl/codegen/config.h>
+#include <grpc++/impl/codegen/string_ref.h>
+#include <grpc++/impl/codegen/time.h>
+
+struct gpr_timespec;
+struct grpc_metadata;
+struct grpc_call;
+struct census_context;
+
+namespace grpc {
+
+class ClientContext;
+template <class W, class R>
+class ServerAsyncReader;
+template <class W>
+class ServerAsyncWriter;
+template <class W>
+class ServerAsyncResponseWriter;
+template <class W, class R>
+class ServerAsyncReaderWriter;
+template <class R>
+class ServerReader;
+template <class W>
+class ServerWriter;
+template <class W, class R>
+class ServerReaderWriter;
+template <class ServiceType, class RequestType, class ResponseType>
+class RpcMethodHandler;
+template <class ServiceType, class RequestType, class ResponseType>
+class ClientStreamingHandler;
+template <class ServiceType, class RequestType, class ResponseType>
+class ServerStreamingHandler;
+template <class ServiceType, class RequestType, class ResponseType>
+class BidiStreamingHandler;
+class UnknownMethodHandler;
+
+class Call;
+class CallOpBuffer;
+class CompletionQueue;
+class Server;
+class ServerInterface;
+
+namespace testing {
+class InteropServerContextInspector;
+}  // namespace testing
+
+// Interface of server side rpc context.
+class ServerContext {
+ public:
+  ServerContext();  // for async calls
+  ~ServerContext();
+
+#ifndef GRPC_CXX0X_NO_CHRONO
+  std::chrono::system_clock::time_point deadline() {
+    return Timespec2Timepoint(deadline_);
+  }
+#endif  // !GRPC_CXX0X_NO_CHRONO
+
+  gpr_timespec raw_deadline() { return deadline_; }
+
+  void AddInitialMetadata(const grpc::string& key, const grpc::string& value);
+  void AddTrailingMetadata(const grpc::string& key, const grpc::string& value);
+
+  bool IsCancelled() const;
+
+  // Cancel the Call from the server. This is a best-effort API and depending on
+  // when it is called, the RPC may still appear successful to the client.
+  // For example, if TryCancel() is called on a separate thread, it might race
+  // with the server handler which might return success to the client before
+  // TryCancel() was even started by the thread.
+  //
+  // It is the caller's responsibility to prevent such races and ensure that if
+  // TryCancel() is called, the serverhandler must return Status::CANCELLED. The
+  // only exception is that if the serverhandler is already returning an error
+  // status code, it is ok to not return Status::CANCELLED even if TryCancel()
+  // was called.
+  void TryCancel() const;
+
+  const std::multimap<grpc::string_ref, grpc::string_ref>& client_metadata() {
+    return client_metadata_;
+  }
+
+  grpc_compression_level compression_level() const {
+    return compression_level_;
+  }
+  void set_compression_level(grpc_compression_level level);
+
+  grpc_compression_algorithm compression_algorithm() const {
+    return compression_algorithm_;
+  }
+  void set_compression_algorithm(grpc_compression_algorithm algorithm);
+
+  std::shared_ptr<const AuthContext> auth_context() const;
+
+  // Return the peer uri in a string.
+  // WARNING: this value is never authenticated or subject to any security
+  // related code. It must not be used for any authentication related
+  // functionality. Instead, use auth_context.
+  grpc::string peer() const;
+
+  const struct census_context* census_context() const;
+
+  // Async only. Has to be called before the rpc starts.
+  // Returns the tag in completion queue when the rpc finishes.
+  // IsCancelled() can then be called to check whether the rpc was cancelled.
+  void AsyncNotifyWhenDone(void* tag) {
+    has_notify_when_done_tag_ = true;
+    async_notify_when_done_tag_ = tag;
+  }
+
+ private:
+  friend class ::grpc::testing::InteropServerContextInspector;
+  friend class ::grpc::ServerInterface;
+  friend class ::grpc::Server;
+  template <class W, class R>
+  friend class ::grpc::ServerAsyncReader;
+  template <class W>
+  friend class ::grpc::ServerAsyncWriter;
+  template <class W>
+  friend class ::grpc::ServerAsyncResponseWriter;
+  template <class W, class R>
+  friend class ::grpc::ServerAsyncReaderWriter;
+  template <class R>
+  friend class ::grpc::ServerReader;
+  template <class W>
+  friend class ::grpc::ServerWriter;
+  template <class W, class R>
+  friend class ::grpc::ServerReaderWriter;
+  template <class ServiceType, class RequestType, class ResponseType>
+  friend class RpcMethodHandler;
+  template <class ServiceType, class RequestType, class ResponseType>
+  friend class ClientStreamingHandler;
+  template <class ServiceType, class RequestType, class ResponseType>
+  friend class ServerStreamingHandler;
+  template <class ServiceType, class RequestType, class ResponseType>
+  friend class BidiStreamingHandler;
+  friend class UnknownMethodHandler;
+  friend class ::grpc::ClientContext;
+
+  // Prevent copying.
+  ServerContext(const ServerContext&);
+  ServerContext& operator=(const ServerContext&);
+
+  class CompletionOp;
+
+  void BeginCompletionOp(Call* call);
+
+  ServerContext(gpr_timespec deadline, grpc_metadata* metadata,
+                size_t metadata_count);
+
+  void set_call(grpc_call* call);
+
+  CompletionOp* completion_op_;
+  bool has_notify_when_done_tag_;
+  void* async_notify_when_done_tag_;
+
+  gpr_timespec deadline_;
+  grpc_call* call_;
+  CompletionQueue* cq_;
+  bool sent_initial_metadata_;
+  mutable std::shared_ptr<const AuthContext> auth_context_;
+  std::multimap<grpc::string_ref, grpc::string_ref> client_metadata_;
+  std::multimap<grpc::string, grpc::string> initial_metadata_;
+  std::multimap<grpc::string, grpc::string> trailing_metadata_;
+
+  grpc_compression_level compression_level_;
+  grpc_compression_algorithm compression_algorithm_;
+};
+
+}  // namespace grpc
+
+#endif  // GRPCXX_IMPL_CODEGEN_SERVER_CONTEXT_H
diff --git a/include/grpc++/impl/codegen/server_interface.h b/include/grpc++/impl/codegen/server_interface.h
new file mode 100644
index 0000000..f934619
--- /dev/null
+++ b/include/grpc++/impl/codegen/server_interface.h
@@ -0,0 +1,253 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef GRPCXX_IMPL_CODEGEN_SERVER_INTERFACE_H
+#define GRPCXX_IMPL_CODEGEN_SERVER_INTERFACE_H
+
+#include <grpc/impl/codegen/grpc_types.h>
+#include <grpc++/impl/codegen/call_hook.h>
+#include <grpc++/impl/codegen/completion_queue_tag.h>
+#include <grpc++/impl/codegen/rpc_service_method.h>
+
+namespace grpc {
+
+class AsyncGenericService;
+class GenericServerContext;
+class RpcService;
+class ServerAsyncStreamingInterface;
+class ServerCompletionQueue;
+class ServerContext;
+class ServerCredentials;
+class Service;
+class ThreadPoolInterface;
+
+/// Models a gRPC server.
+///
+/// Servers are configured and started via \a grpc::ServerBuilder.
+class ServerInterface : public CallHook {
+ public:
+  virtual ~ServerInterface() {}
+
+  /// Shutdown the server, blocking until all rpc processing finishes.
+  /// Forcefully terminate pending calls after \a deadline expires.
+  ///
+  /// \param deadline How long to wait until pending rpcs are forcefully
+  /// terminated.
+  template <class T>
+  void Shutdown(const T& deadline) {
+    ShutdownInternal(TimePoint<T>(deadline).raw_time());
+  }
+
+  /// Shutdown the server, waiting for all rpc processing to finish.
+  void Shutdown() { ShutdownInternal(gpr_inf_future(GPR_CLOCK_MONOTONIC)); }
+
+  /// Block waiting for all work to complete.
+  ///
+  /// \warning The server must be either shutting down or some other thread must
+  /// call \a Shutdown for this function to ever return.
+  virtual void Wait() = 0;
+
+ protected:
+  friend class Service;
+
+  /// Register a service. This call does not take ownership of the service.
+  /// The service must exist for the lifetime of the Server instance.
+  virtual bool RegisterService(const grpc::string* host, Service* service) = 0;
+
+  /// Register a generic service. This call does not take ownership of the
+  /// service. The service must exist for the lifetime of the Server instance.
+  virtual void RegisterAsyncGenericService(AsyncGenericService* service) = 0;
+
+  /// Tries to bind \a server to the given \a addr.
+  ///
+  /// It can be invoked multiple times.
+  ///
+  /// \param addr The address to try to bind to the server (eg, localhost:1234,
+  /// 192.168.1.1:31416, [::1]:27182, etc.).
+  /// \params creds The credentials associated with the server.
+  ///
+  /// \return bound port number on sucess, 0 on failure.
+  ///
+  /// \warning It's an error to call this method on an already started server.
+  virtual int AddListeningPort(const grpc::string& addr,
+                               ServerCredentials* creds) = 0;
+
+  /// Start the server.
+  ///
+  /// \param cqs Completion queues for handling asynchronous services. The
+  /// caller is required to keep all completion queues live until the server is
+  /// destroyed.
+  /// \param num_cqs How many completion queues does \a cqs hold.
+  ///
+  /// \return true on a successful shutdown.
+  virtual bool Start(ServerCompletionQueue** cqs, size_t num_cqs) = 0;
+
+  /// Process one or more incoming calls.
+  virtual void RunRpc() = 0;
+
+  /// Schedule \a RunRpc to run in the threadpool.
+  virtual void ScheduleCallback() = 0;
+
+  virtual void ShutdownInternal(gpr_timespec deadline) = 0;
+
+  virtual int max_message_size() const = 0;
+
+  virtual grpc_server* server() = 0;
+
+  virtual void PerformOpsOnCall(CallOpSetInterface* ops, Call* call) = 0;
+
+  class BaseAsyncRequest : public CompletionQueueTag {
+   public:
+    BaseAsyncRequest(ServerInterface* server, ServerContext* context,
+                     ServerAsyncStreamingInterface* stream,
+                     CompletionQueue* call_cq, void* tag,
+                     bool delete_on_finalize);
+    virtual ~BaseAsyncRequest() {}
+
+    bool FinalizeResult(void** tag, bool* status) GRPC_OVERRIDE;
+
+   protected:
+    ServerInterface* const server_;
+    ServerContext* const context_;
+    ServerAsyncStreamingInterface* const stream_;
+    CompletionQueue* const call_cq_;
+    void* const tag_;
+    const bool delete_on_finalize_;
+    grpc_call* call_;
+    grpc_metadata_array initial_metadata_array_;
+  };
+
+  class RegisteredAsyncRequest : public BaseAsyncRequest {
+   public:
+    RegisteredAsyncRequest(ServerInterface* server, ServerContext* context,
+                           ServerAsyncStreamingInterface* stream,
+                           CompletionQueue* call_cq, void* tag);
+
+    // uses BaseAsyncRequest::FinalizeResult
+
+   protected:
+    void IssueRequest(void* registered_method, grpc_byte_buffer** payload,
+                      ServerCompletionQueue* notification_cq);
+  };
+
+  class NoPayloadAsyncRequest GRPC_FINAL : public RegisteredAsyncRequest {
+   public:
+    NoPayloadAsyncRequest(void* registered_method, ServerInterface* server,
+                          ServerContext* context,
+                          ServerAsyncStreamingInterface* stream,
+                          CompletionQueue* call_cq,
+                          ServerCompletionQueue* notification_cq, void* tag)
+        : RegisteredAsyncRequest(server, context, stream, call_cq, tag) {
+      IssueRequest(registered_method, nullptr, notification_cq);
+    }
+
+    // uses RegisteredAsyncRequest::FinalizeResult
+  };
+
+  template <class Message>
+  class PayloadAsyncRequest GRPC_FINAL : public RegisteredAsyncRequest {
+   public:
+    PayloadAsyncRequest(void* registered_method, ServerInterface* server,
+                        ServerContext* context,
+                        ServerAsyncStreamingInterface* stream,
+                        CompletionQueue* call_cq,
+                        ServerCompletionQueue* notification_cq, void* tag,
+                        Message* request)
+        : RegisteredAsyncRequest(server, context, stream, call_cq, tag),
+          request_(request) {
+      IssueRequest(registered_method, &payload_, notification_cq);
+    }
+
+    bool FinalizeResult(void** tag, bool* status) GRPC_OVERRIDE {
+      bool serialization_status =
+          *status && payload_ &&
+          SerializationTraits<Message>::Deserialize(
+              payload_, request_, server_->max_message_size()).ok();
+      bool ret = RegisteredAsyncRequest::FinalizeResult(tag, status);
+      *status = serialization_status&&* status;
+      return ret;
+    }
+
+   private:
+    grpc_byte_buffer* payload_;
+    Message* const request_;
+  };
+
+  class GenericAsyncRequest : public BaseAsyncRequest {
+   public:
+    GenericAsyncRequest(ServerInterface* server, GenericServerContext* context,
+                        ServerAsyncStreamingInterface* stream,
+                        CompletionQueue* call_cq,
+                        ServerCompletionQueue* notification_cq, void* tag,
+                        bool delete_on_finalize);
+
+    bool FinalizeResult(void** tag, bool* status) GRPC_OVERRIDE;
+
+   private:
+    grpc_call_details call_details_;
+  };
+
+  template <class Message>
+  void RequestAsyncCall(RpcServiceMethod* method, ServerContext* context,
+                        ServerAsyncStreamingInterface* stream,
+                        CompletionQueue* call_cq,
+                        ServerCompletionQueue* notification_cq, void* tag,
+                        Message* message) {
+    GPR_ASSERT(method);
+    new PayloadAsyncRequest<Message>(method->server_tag(), this, context,
+                                     stream, call_cq, notification_cq, tag,
+                                     message);
+  }
+
+  void RequestAsyncCall(RpcServiceMethod* method, ServerContext* context,
+                        ServerAsyncStreamingInterface* stream,
+                        CompletionQueue* call_cq,
+                        ServerCompletionQueue* notification_cq, void* tag) {
+    GPR_ASSERT(method);
+    new NoPayloadAsyncRequest(method->server_tag(), this, context, stream,
+                              call_cq, notification_cq, tag);
+  }
+
+  void RequestAsyncGenericCall(GenericServerContext* context,
+                               ServerAsyncStreamingInterface* stream,
+                               CompletionQueue* call_cq,
+                               ServerCompletionQueue* notification_cq,
+                               void* tag) {
+    new GenericAsyncRequest(this, context, stream, call_cq, notification_cq,
+                            tag, true);
+  }
+};
+
+}  // namespace grpc
+
+#endif  // GRPCXX_IMPL_CODEGEN_SERVER_INTERFACE_H
diff --git a/include/grpc++/impl/codegen/service_type.h b/include/grpc++/impl/codegen/service_type.h
new file mode 100644
index 0000000..deb91a4
--- /dev/null
+++ b/include/grpc++/impl/codegen/service_type.h
@@ -0,0 +1,161 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef GRPCXX_IMPL_CODEGEN_SERVICE_TYPE_H
+#define GRPCXX_IMPL_CODEGEN_SERVICE_TYPE_H
+
+#include <grpc++/impl/codegen/config.h>
+#include <grpc++/impl/codegen/rpc_service_method.h>
+#include <grpc++/impl/codegen/serialization_traits.h>
+#include <grpc++/impl/codegen/server_interface.h>
+#include <grpc++/impl/codegen/status.h>
+
+namespace grpc {
+
+class Call;
+class CompletionQueue;
+class Server;
+class ServerInterface;
+class ServerCompletionQueue;
+class ServerContext;
+
+class ServerAsyncStreamingInterface {
+ public:
+  virtual ~ServerAsyncStreamingInterface() {}
+
+  virtual void SendInitialMetadata(void* tag) = 0;
+
+ private:
+  friend class ServerInterface;
+  virtual void BindCall(Call* call) = 0;
+};
+
+class Service {
+ public:
+  Service() : server_(nullptr) {}
+  virtual ~Service() {}
+
+  bool has_async_methods() const {
+    for (auto it = methods_.begin(); it != methods_.end(); ++it) {
+      if (*it && (*it)->handler() == nullptr) {
+        return true;
+      }
+    }
+    return false;
+  }
+
+  bool has_synchronous_methods() const {
+    for (auto it = methods_.begin(); it != methods_.end(); ++it) {
+      if (*it && (*it)->handler() != nullptr) {
+        return true;
+      }
+    }
+    return false;
+  }
+
+  bool has_generic_methods() const {
+    for (auto it = methods_.begin(); it != methods_.end(); ++it) {
+      if (it->get() == nullptr) {
+        return true;
+      }
+    }
+    return false;
+  }
+
+ protected:
+  template <class Message>
+  void RequestAsyncUnary(int index, ServerContext* context, Message* request,
+                         ServerAsyncStreamingInterface* stream,
+                         CompletionQueue* call_cq,
+                         ServerCompletionQueue* notification_cq, void* tag) {
+    server_->RequestAsyncCall(methods_[index].get(), context, stream, call_cq,
+                              notification_cq, tag, request);
+  }
+  void RequestAsyncClientStreaming(int index, ServerContext* context,
+                                   ServerAsyncStreamingInterface* stream,
+                                   CompletionQueue* call_cq,
+                                   ServerCompletionQueue* notification_cq,
+                                   void* tag) {
+    server_->RequestAsyncCall(methods_[index].get(), context, stream, call_cq,
+                              notification_cq, tag);
+  }
+  template <class Message>
+  void RequestAsyncServerStreaming(int index, ServerContext* context,
+                                   Message* request,
+                                   ServerAsyncStreamingInterface* stream,
+                                   CompletionQueue* call_cq,
+                                   ServerCompletionQueue* notification_cq,
+                                   void* tag) {
+    server_->RequestAsyncCall(methods_[index].get(), context, stream, call_cq,
+                              notification_cq, tag, request);
+  }
+  void RequestAsyncBidiStreaming(int index, ServerContext* context,
+                                 ServerAsyncStreamingInterface* stream,
+                                 CompletionQueue* call_cq,
+                                 ServerCompletionQueue* notification_cq,
+                                 void* tag) {
+    server_->RequestAsyncCall(methods_[index].get(), context, stream, call_cq,
+                              notification_cq, tag);
+  }
+
+  void AddMethod(RpcServiceMethod* method) { methods_.emplace_back(method); }
+
+  void MarkMethodAsync(int index) {
+    if (methods_[index].get() == nullptr) {
+      gpr_log(GPR_ERROR,
+              "Cannot mark the method as 'async' because it has already been "
+              "marked as 'generic'.");
+      return;
+    }
+    methods_[index]->ResetHandler();
+  }
+
+  void MarkMethodGeneric(int index) {
+    if (methods_[index]->handler() == nullptr) {
+      gpr_log(GPR_ERROR,
+              "Cannot mark the method as 'generic' because it has already been "
+              "marked as 'async'.");
+    }
+    methods_[index].reset();
+  }
+
+ private:
+  friend class Server;
+  friend class ServerInterface;
+  ServerInterface* server_;
+  std::vector<std::unique_ptr<RpcServiceMethod>> methods_;
+};
+
+}  // namespace grpc
+
+#endif  // GRPCXX_IMPL_CODEGEN_SERVICE_TYPE_H
diff --git a/include/grpc++/impl/codegen/status.h b/include/grpc++/impl/codegen/status.h
new file mode 100644
index 0000000..a509d31
--- /dev/null
+++ b/include/grpc++/impl/codegen/status.h
@@ -0,0 +1,76 @@
+/*
+ *
+ * Copyright 2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef GRPCXX_IMPL_CODEGEN_STATUS_H
+#define GRPCXX_IMPL_CODEGEN_STATUS_H
+
+#include <grpc++/impl/codegen/config.h>
+#include <grpc++/impl/codegen/status_code_enum.h>
+
+namespace grpc {
+
+/// Did it work? If it didn't, why?
+///
+/// See \a grpc::StatusCode for details on the available code and their meaning.
+class Status {
+ public:
+  /// 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) {}
+
+  // Pre-defined special status objects.
+  /// An OK pre-defined instance.
+  static const Status& OK;
+  /// A CANCELLED pre-defined instance.
+  static const Status& CANCELLED;
+
+  /// 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_; }
+
+  /// Is the status OK?
+  bool ok() const { return code_ == StatusCode::OK; }
+
+ private:
+  StatusCode code_;
+  grpc::string details_;
+};
+
+}  // namespace grpc
+
+#endif  // GRPCXX_IMPL_CODEGEN_STATUS_H
diff --git a/include/grpc++/impl/codegen/status_code_enum.h b/include/grpc++/impl/codegen/status_code_enum.h
new file mode 100644
index 0000000..9a90a18
--- /dev/null
+++ b/include/grpc++/impl/codegen/status_code_enum.h
@@ -0,0 +1,152 @@
+/*
+ *
+ * Copyright 2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef GRPCXX_IMPL_CODEGEN_STATUS_CODE_ENUM_H
+#define GRPCXX_IMPL_CODEGEN_STATUS_CODE_ENUM_H
+
+namespace grpc {
+
+enum StatusCode {
+  /// Not an error; returned on success.
+  OK = 0,
+
+  /// The operation was cancelled (typically by the caller).
+  CANCELLED = 1,
+
+  /// Unknown error. An example of where this error may be returned is if a
+  /// Status value received from another address space belongs to an error-space
+  /// that is not known in this address space. Also errors raised by APIs that
+  /// do not return enough error information may be converted to this error.
+  UNKNOWN = 2,
+
+  /// Client specified an invalid argument. Note that this differs from
+  /// FAILED_PRECONDITION. INVALID_ARGUMENT indicates arguments that are
+  /// problematic regardless of the state of the system (e.g., a malformed file
+  /// name).
+  INVALID_ARGUMENT = 3,
+
+  /// Deadline expired before operation could complete. For operations that
+  /// change the state of the system, this error may be returned even if the
+  /// operation has completed successfully. For example, a successful response
+  /// from a server could have been delayed long enough for the deadline to
+  /// expire.
+  DEADLINE_EXCEEDED = 4,
+
+  /// Some requested entity (e.g., file or directory) was not found.
+  NOT_FOUND = 5,
+
+  /// Some entity that we attempted to create (e.g., file or directory) already
+  /// exists.
+  ALREADY_EXISTS = 6,
+
+  /// The caller does not have permission to execute the specified operation.
+  /// PERMISSION_DENIED must not be used for rejections caused by exhausting
+  /// some resource (use RESOURCE_EXHAUSTED instead for those errors).
+  /// PERMISSION_DENIED must not be used if the caller can not be identified
+  /// (use UNAUTHENTICATED instead for those errors).
+  PERMISSION_DENIED = 7,
+
+  /// The request does not have valid authentication credentials for the
+  /// operation.
+  UNAUTHENTICATED = 16,
+
+  /// Some resource has been exhausted, perhaps a per-user quota, or perhaps the
+  /// entire file system is out of space.
+  RESOURCE_EXHAUSTED = 8,
+
+  /// Operation was rejected because the system is not in a state required for
+  /// the operation's execution. For example, directory to be deleted may be
+  /// non-empty, an rmdir operation is applied to a non-directory, etc.
+  ///
+  /// A litmus test that may help a service implementor in deciding
+  /// between FAILED_PRECONDITION, ABORTED, and UNAVAILABLE:
+  ///  (a) Use UNAVAILABLE if the client can retry just the failing call.
+  ///  (b) Use ABORTED if the client should retry at a higher-level
+  ///      (e.g., restarting a read-modify-write sequence).
+  ///  (c) Use FAILED_PRECONDITION if the client should not retry until
+  ///      the system state has been explicitly fixed. E.g., if an "rmdir"
+  ///      fails because the directory is non-empty, FAILED_PRECONDITION
+  ///      should be returned since the client should not retry unless
+  ///      they have first fixed up the directory by deleting files from it.
+  ///  (d) Use FAILED_PRECONDITION if the client performs conditional
+  ///      REST Get/Update/Delete on a resource and the resource on the
+  ///      server does not match the condition. E.g., conflicting
+  ///      read-modify-write on the same resource.
+  FAILED_PRECONDITION = 9,
+
+  /// The operation was aborted, typically due to a concurrency issue like
+  /// sequencer check failures, transaction aborts, etc.
+  ///
+  /// See litmus test above for deciding between FAILED_PRECONDITION, ABORTED,
+  /// and UNAVAILABLE.
+  ABORTED = 10,
+
+  /// Operation was attempted past the valid range. E.g., seeking or reading
+  /// past end of file.
+  ///
+  /// Unlike INVALID_ARGUMENT, this error indicates a problem that may be fixed
+  /// if the system state changes. For example, a 32-bit file system will
+  /// generate INVALID_ARGUMENT if asked to read at an offset that is not in the
+  /// range [0,2^32-1], but it will generate OUT_OF_RANGE if asked to read from
+  /// an offset past the current file size.
+  ///
+  /// There is a fair bit of overlap between FAILED_PRECONDITION and
+  /// OUT_OF_RANGE. We recommend using OUT_OF_RANGE (the more specific error)
+  /// when it applies so that callers who are iterating through a space can
+  /// easily look for an OUT_OF_RANGE error to detect when they are done.
+  OUT_OF_RANGE = 11,
+
+  /// Operation is not implemented or not supported/enabled in this service.
+  UNIMPLEMENTED = 12,
+
+  /// Internal errors. Means some invariants expected by underlying System has
+  /// been broken. If you see one of these errors, Something is very broken.
+  INTERNAL = 13,
+
+  /// The service is currently unavailable. This is a most likely a transient
+  /// condition and may be corrected by retrying with a backoff.
+  ///
+  /// See litmus test above for deciding between FAILED_PRECONDITION, ABORTED,
+  /// and UNAVAILABLE.
+  UNAVAILABLE = 14,
+
+  /// Unrecoverable data loss or corruption.
+  DATA_LOSS = 15,
+
+  /// Force users to include a default branch:
+  DO_NOT_USE = -1
+};
+
+}  // namespace grpc
+
+#endif  // GRPCXX_IMPL_CODEGEN_STATUS_CODE_ENUM_H
diff --git a/include/grpc++/impl/codegen/string_ref.h b/include/grpc++/impl/codegen/string_ref.h
new file mode 100644
index 0000000..e3af37e
--- /dev/null
+++ b/include/grpc++/impl/codegen/string_ref.h
@@ -0,0 +1,123 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef GRPCXX_IMPL_CODEGEN_STRING_REF_H
+#define GRPCXX_IMPL_CODEGEN_STRING_REF_H
+
+#include <iterator>
+#include <iosfwd>
+
+#include <grpc++/impl/codegen/config.h>
+
+namespace grpc {
+
+/// This class is a non owning reference to a string.
+///
+/// It should be a strict subset of the upcoming std::string_ref.
+///
+/// \see http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3442.html
+///
+/// The constexpr is dropped or replaced with const for legacy compiler
+/// compatibility.
+class string_ref {
+ public:
+  // types
+  typedef const char* const_iterator;
+  typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
+
+  // constants
+  const static size_t npos;
+
+  // construct/copy.
+  string_ref() : data_(nullptr), length_(0) {}
+  string_ref(const string_ref& other)
+      : data_(other.data_), length_(other.length_) {}
+  string_ref& operator=(const string_ref& rhs);
+  string_ref(const char* s);
+  string_ref(const char* s, size_t l) : data_(s), length_(l) {}
+  string_ref(const grpc::string& s) : data_(s.data()), length_(s.length()) {}
+
+  // iterators
+  const_iterator begin() const { return data_; }
+  const_iterator end() const { return data_ + length_; }
+  const_iterator cbegin() const { return data_; }
+  const_iterator cend() const { return data_ + length_; }
+  const_reverse_iterator rbegin() const {
+    return const_reverse_iterator(end());
+  }
+  const_reverse_iterator rend() const {
+    return const_reverse_iterator(begin());
+  }
+  const_reverse_iterator crbegin() const {
+    return const_reverse_iterator(end());
+  }
+  const_reverse_iterator crend() const {
+    return const_reverse_iterator(begin());
+  }
+
+  // capacity
+  size_t size() const { return length_; }
+  size_t length() const { return length_; }
+  size_t max_size() const { return length_; }
+  bool empty() const { return length_ == 0; }
+
+  // element access
+  const char* data() const { return data_; }
+
+  // string operations
+  int compare(string_ref x) const;
+  bool starts_with(string_ref x) const;
+  bool ends_with(string_ref x) const;
+  size_t find(string_ref s) const;
+  size_t find(char c) const;
+
+  string_ref substr(size_t pos, size_t n = npos) const;
+
+ private:
+  const char* data_;
+  size_t length_;
+};
+
+// Comparison operators
+bool operator==(string_ref x, string_ref y);
+bool operator!=(string_ref x, string_ref y);
+bool operator<(string_ref x, string_ref y);
+bool operator>(string_ref x, string_ref y);
+bool operator<=(string_ref x, string_ref y);
+bool operator>=(string_ref x, string_ref y);
+
+std::ostream& operator<<(std::ostream& stream, const string_ref& string);
+
+}  // namespace grpc
+
+#endif  // GRPCXX_IMPL_CODEGEN_STRING_REF_H
diff --git a/src/objective-c/GRPCClient/private/GRPCUnsecuredChannel.h b/include/grpc++/impl/codegen/stub_options.h
similarity index 86%
copy from src/objective-c/GRPCClient/private/GRPCUnsecuredChannel.h
copy to include/grpc++/impl/codegen/stub_options.h
index 8528be4..3912ae2 100644
--- a/src/objective-c/GRPCClient/private/GRPCUnsecuredChannel.h
+++ b/include/grpc++/impl/codegen/stub_options.h
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -31,8 +31,13 @@
  *
  */
 
-#import "GRPCChannel.h"
+#ifndef GRPCXX_IMPL_CODEGEN_STUB_OPTIONS_H
+#define GRPCXX_IMPL_CODEGEN_STUB_OPTIONS_H
 
-@interface GRPCUnsecuredChannel : GRPCChannel
-- (instancetype)initWithHost:(NSString *)host NS_DESIGNATED_INITIALIZER;
-@end
+namespace grpc {
+
+class StubOptions {};
+
+}  // namespace grpc
+
+#endif  // GRPCXX_IMPL_CODEGEN_STUB_OPTIONS_H
diff --git a/src/objective-c/GRPCClient/private/GRPCUnsecuredChannel.h b/include/grpc++/impl/codegen/sync.h
similarity index 82%
copy from src/objective-c/GRPCClient/private/GRPCUnsecuredChannel.h
copy to include/grpc++/impl/codegen/sync.h
index 8528be4..375af15 100644
--- a/src/objective-c/GRPCClient/private/GRPCUnsecuredChannel.h
+++ b/include/grpc++/impl/codegen/sync.h
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -31,8 +31,15 @@
  *
  */
 
-#import "GRPCChannel.h"
+#ifndef GRPCXX_IMPL_CODEGEN_SYNC_H
+#define GRPCXX_IMPL_CODEGEN_SYNC_H
 
-@interface GRPCUnsecuredChannel : GRPCChannel
-- (instancetype)initWithHost:(NSString *)host NS_DESIGNATED_INITIALIZER;
-@end
+#include <grpc++/impl/codegen/config.h>
+
+#ifdef GRPC_CXX0X_NO_THREAD
+#include <grpc++/impl/codegen/sync_no_cxx11.h>
+#else
+#include <grpc++/impl/codegen/sync_cxx11.h>
+#endif
+
+#endif  // GRPCXX_IMPL_CODEGEN_SYNC_H
diff --git a/src/objective-c/GRPCClient/private/GRPCUnsecuredChannel.h b/include/grpc++/impl/codegen/sync_cxx11.h
similarity index 80%
copy from src/objective-c/GRPCClient/private/GRPCUnsecuredChannel.h
copy to include/grpc++/impl/codegen/sync_cxx11.h
index 8528be4..4910547 100644
--- a/src/objective-c/GRPCClient/private/GRPCUnsecuredChannel.h
+++ b/include/grpc++/impl/codegen/sync_cxx11.h
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -31,8 +31,19 @@
  *
  */
 
-#import "GRPCChannel.h"
+#ifndef GRPCXX_IMPL_CODEGEN_SYNC_CXX11_H
+#define GRPCXX_IMPL_CODEGEN_SYNC_CXX11_H
 
-@interface GRPCUnsecuredChannel : GRPCChannel
-- (instancetype)initWithHost:(NSString *)host NS_DESIGNATED_INITIALIZER;
-@end
+#include <condition_variable>
+#include <mutex>
+
+namespace grpc {
+
+using std::condition_variable;
+using std::mutex;
+using std::lock_guard;
+using std::unique_lock;
+
+}  // namespace grpc
+
+#endif  // GRPCXX_IMPL_CODEGEN_SYNC_CXX11_H
diff --git a/include/grpc++/impl/codegen/sync_no_cxx11.h b/include/grpc++/impl/codegen/sync_no_cxx11.h
new file mode 100644
index 0000000..8dea847
--- /dev/null
+++ b/include/grpc++/impl/codegen/sync_no_cxx11.h
@@ -0,0 +1,105 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef GRPCXX_IMPL_CODEGEN_SYNC_NO_CXX11_H
+#define GRPCXX_IMPL_CODEGEN_SYNC_NO_CXX11_H
+
+#include <grpc/impl/codegen/sync.h>
+
+namespace grpc {
+
+template <class mutex>
+class lock_guard;
+class condition_variable;
+
+class mutex {
+ public:
+  mutex() { gpr_mu_init(&mu_); }
+  ~mutex() { gpr_mu_destroy(&mu_); }
+
+ private:
+  ::gpr_mu mu_;
+  template <class mutex>
+  friend class lock_guard;
+  friend class condition_variable;
+};
+
+template <class mutex>
+class lock_guard {
+ public:
+  lock_guard(mutex &mu) : mu_(mu), locked(true) { gpr_mu_lock(&mu.mu_); }
+  ~lock_guard() { unlock_internal(); }
+
+ protected:
+  void lock_internal() {
+    if (!locked) gpr_mu_lock(&mu_.mu_);
+    locked = true;
+  }
+  void unlock_internal() {
+    if (locked) gpr_mu_unlock(&mu_.mu_);
+    locked = false;
+  }
+
+ private:
+  mutex &mu_;
+  bool locked;
+  friend class condition_variable;
+};
+
+template <class mutex>
+class unique_lock : public lock_guard<mutex> {
+ public:
+  unique_lock(mutex &mu) : lock_guard<mutex>(mu) {}
+  void lock() { this->lock_internal(); }
+  void unlock() { this->unlock_internal(); }
+};
+
+class condition_variable {
+ public:
+  condition_variable() { gpr_cv_init(&cv_); }
+  ~condition_variable() { gpr_cv_destroy(&cv_); }
+  void wait(lock_guard<mutex> &mu) {
+    mu.locked = false;
+    gpr_cv_wait(&cv_, &mu.mu_.mu_, gpr_inf_future(GPR_CLOCK_REALTIME));
+    mu.locked = true;
+  }
+  void notify_one() { gpr_cv_signal(&cv_); }
+  void notify_all() { gpr_cv_broadcast(&cv_); }
+
+ private:
+  gpr_cv cv_;
+};
+
+}  // namespace grpc
+
+#endif  // GRPCXX_IMPL_CODEGEN_SYNC_NO_CXX11_H
diff --git a/include/grpc++/impl/codegen/sync_stream.h b/include/grpc++/impl/codegen/sync_stream.h
new file mode 100644
index 0000000..9ae48bd
--- /dev/null
+++ b/include/grpc++/impl/codegen/sync_stream.h
@@ -0,0 +1,431 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef GRPCXX_IMPL_CODEGEN_SYNC_STREAM_H
+#define GRPCXX_IMPL_CODEGEN_SYNC_STREAM_H
+
+#include <grpc++/impl/codegen/call.h>
+#include <grpc++/impl/codegen/channel_interface.h>
+#include <grpc++/impl/codegen/client_context.h>
+#include <grpc++/impl/codegen/completion_queue.h>
+#include <grpc++/impl/codegen/server_context.h>
+#include <grpc++/impl/codegen/service_type.h>
+#include <grpc++/impl/codegen/status.h>
+#include <grpc/impl/codegen/log.h>
+
+namespace grpc {
+
+/// Common interface for all synchronous client side streaming.
+class ClientStreamingInterface {
+ public:
+  virtual ~ClientStreamingInterface() {}
+
+  /// Wait until the stream finishes, and return the final status. When the
+  /// client side declares it has no more message to send, either implicitly or
+  /// by calling \a WritesDone(), it needs to make sure there is no more message
+  /// to be received from the server, either implicitly or by getting a false
+  /// from a \a Read().
+  ///
+  /// This function will return either:
+  /// - when all incoming messages have been read and the server has returned
+  ///   status.
+  /// - OR when the server has returned a non-OK status.
+  virtual Status Finish() = 0;
+};
+
+/// An interface that yields a sequence of messages of type \a R.
+template <class R>
+class ReaderInterface {
+ public:
+  virtual ~ReaderInterface() {}
+
+  /// Blocking read a message and parse to \a msg. Returns \a true on success.
+  ///
+  /// \param[out] msg The read message.
+  ///
+  /// \return \a false when there will be no more incoming messages, either
+  /// because the other side has called \a WritesDone() or the stream has failed
+  /// (or been cancelled).
+  virtual bool Read(R* msg) = 0;
+};
+
+/// An interface that can be fed a sequence of messages of type \a W.
+template <class W>
+class WriterInterface {
+ public:
+  virtual ~WriterInterface() {}
+
+  /// Blocking write \a msg to the stream with options.
+  ///
+  /// \param msg The message to be written to the stream.
+  /// \param options Options affecting the write operation.
+  ///
+  /// \return \a true on success, \a false when the stream has been closed.
+  virtual bool Write(const W& msg, const WriteOptions& options) = 0;
+
+  /// Blocking write \a msg to the stream with default options.
+  ///
+  /// \param msg The message to be written to the stream.
+  ///
+  /// \return \a true on success, \a false when the stream has been closed.
+  inline bool Write(const W& msg) { return Write(msg, WriteOptions()); }
+};
+
+/// Client-side interface for streaming reads of message of type \a R.
+template <class R>
+class ClientReaderInterface : public ClientStreamingInterface,
+                              public ReaderInterface<R> {
+ public:
+  /// Blocking wait for initial metadata from server. The received metadata
+  /// can only be accessed after this call returns. Should only be called before
+  /// the first read. Calling this method is optional, and if it is not called
+  /// the metadata will be available in ClientContext after the first read.
+  virtual void WaitForInitialMetadata() = 0;
+};
+
+template <class R>
+class ClientReader GRPC_FINAL : public ClientReaderInterface<R> {
+ public:
+  /// Blocking create a stream and write the first request out.
+  template <class W>
+  ClientReader(ChannelInterface* channel, const RpcMethod& method,
+               ClientContext* context, const W& request)
+      : context_(context), call_(channel->CreateCall(method, context, &cq_)) {
+    CallOpSet<CallOpSendInitialMetadata, CallOpSendMessage,
+              CallOpClientSendClose> ops;
+    ops.SendInitialMetadata(context->send_initial_metadata_);
+    // TODO(ctiller): don't assert
+    GPR_ASSERT(ops.SendMessage(request).ok());
+    ops.ClientSendClose();
+    call_.PerformOps(&ops);
+    cq_.Pluck(&ops);
+  }
+
+  void WaitForInitialMetadata() GRPC_OVERRIDE {
+    GPR_ASSERT(!context_->initial_metadata_received_);
+
+    CallOpSet<CallOpRecvInitialMetadata> ops;
+    ops.RecvInitialMetadata(context_);
+    call_.PerformOps(&ops);
+    cq_.Pluck(&ops);  /// status ignored
+  }
+
+  bool Read(R* msg) GRPC_OVERRIDE {
+    CallOpSet<CallOpRecvInitialMetadata, CallOpRecvMessage<R>> ops;
+    if (!context_->initial_metadata_received_) {
+      ops.RecvInitialMetadata(context_);
+    }
+    ops.RecvMessage(msg);
+    call_.PerformOps(&ops);
+    return cq_.Pluck(&ops) && ops.got_message;
+  }
+
+  Status Finish() GRPC_OVERRIDE {
+    CallOpSet<CallOpClientRecvStatus> ops;
+    Status status;
+    ops.ClientRecvStatus(context_, &status);
+    call_.PerformOps(&ops);
+    GPR_ASSERT(cq_.Pluck(&ops));
+    return status;
+  }
+
+ private:
+  ClientContext* context_;
+  CompletionQueue cq_;
+  Call call_;
+};
+
+/// Client-side interface for streaming writes of message of type \a W.
+template <class W>
+class ClientWriterInterface : public ClientStreamingInterface,
+                              public WriterInterface<W> {
+ public:
+  /// Half close writing from the client.
+  /// Block until writes are completed.
+  ///
+  /// \return Whether the writes were successful.
+  virtual bool WritesDone() = 0;
+};
+
+template <class W>
+class ClientWriter : public ClientWriterInterface<W> {
+ public:
+  /// Blocking create a stream.
+  template <class R>
+  ClientWriter(ChannelInterface* channel, const RpcMethod& method,
+               ClientContext* context, R* response)
+      : context_(context), call_(channel->CreateCall(method, context, &cq_)) {
+    finish_ops_.RecvMessage(response);
+
+    CallOpSet<CallOpSendInitialMetadata> ops;
+    ops.SendInitialMetadata(context->send_initial_metadata_);
+    call_.PerformOps(&ops);
+    cq_.Pluck(&ops);
+  }
+
+  void WaitForInitialMetadata() {
+    GPR_ASSERT(!context_->initial_metadata_received_);
+
+    CallOpSet<CallOpRecvInitialMetadata> ops;
+    ops.RecvInitialMetadata(context_);
+    call_.PerformOps(&ops);
+    cq_.Pluck(&ops);  // status ignored
+  }
+
+  using WriterInterface<W>::Write;
+  bool Write(const W& msg, const WriteOptions& options) GRPC_OVERRIDE {
+    CallOpSet<CallOpSendMessage> ops;
+    if (!ops.SendMessage(msg, options).ok()) {
+      return false;
+    }
+    call_.PerformOps(&ops);
+    return cq_.Pluck(&ops);
+  }
+
+  bool WritesDone() GRPC_OVERRIDE {
+    CallOpSet<CallOpClientSendClose> ops;
+    ops.ClientSendClose();
+    call_.PerformOps(&ops);
+    return cq_.Pluck(&ops);
+  }
+
+  /// Read the final response and wait for the final status.
+  Status Finish() GRPC_OVERRIDE {
+    Status status;
+    if (!context_->initial_metadata_received_) {
+      finish_ops_.RecvInitialMetadata(context_);
+    }
+    finish_ops_.ClientRecvStatus(context_, &status);
+    call_.PerformOps(&finish_ops_);
+    GPR_ASSERT(cq_.Pluck(&finish_ops_));
+    return status;
+  }
+
+ private:
+  ClientContext* context_;
+  CallOpSet<CallOpRecvInitialMetadata, CallOpGenericRecvMessage,
+            CallOpClientRecvStatus> finish_ops_;
+  CompletionQueue cq_;
+  Call call_;
+};
+
+/// Client-side interface for bi-directional streaming.
+template <class W, class R>
+class ClientReaderWriterInterface : public ClientStreamingInterface,
+                                    public WriterInterface<W>,
+                                    public ReaderInterface<R> {
+ public:
+  /// Blocking wait for initial metadata from server. The received metadata
+  /// can only be accessed after this call returns. Should only be called before
+  /// the first read. Calling this method is optional, and if it is not called
+  /// the metadata will be available in ClientContext after the first read.
+  virtual void WaitForInitialMetadata() = 0;
+
+  /// Block until writes are completed.
+  ///
+  /// \return Whether the writes were successful.
+  virtual bool WritesDone() = 0;
+};
+
+template <class W, class R>
+class ClientReaderWriter GRPC_FINAL : public ClientReaderWriterInterface<W, R> {
+ public:
+  /// Blocking create a stream.
+  ClientReaderWriter(ChannelInterface* channel, const RpcMethod& method,
+                     ClientContext* context)
+      : context_(context), call_(channel->CreateCall(method, context, &cq_)) {
+    CallOpSet<CallOpSendInitialMetadata> ops;
+    ops.SendInitialMetadata(context->send_initial_metadata_);
+    call_.PerformOps(&ops);
+    cq_.Pluck(&ops);
+  }
+
+  void WaitForInitialMetadata() GRPC_OVERRIDE {
+    GPR_ASSERT(!context_->initial_metadata_received_);
+
+    CallOpSet<CallOpRecvInitialMetadata> ops;
+    ops.RecvInitialMetadata(context_);
+    call_.PerformOps(&ops);
+    cq_.Pluck(&ops);  // status ignored
+  }
+
+  bool Read(R* msg) GRPC_OVERRIDE {
+    CallOpSet<CallOpRecvInitialMetadata, CallOpRecvMessage<R>> ops;
+    if (!context_->initial_metadata_received_) {
+      ops.RecvInitialMetadata(context_);
+    }
+    ops.RecvMessage(msg);
+    call_.PerformOps(&ops);
+    return cq_.Pluck(&ops) && ops.got_message;
+  }
+
+  using WriterInterface<W>::Write;
+  bool Write(const W& msg, const WriteOptions& options) GRPC_OVERRIDE {
+    CallOpSet<CallOpSendMessage> ops;
+    if (!ops.SendMessage(msg, options).ok()) return false;
+    call_.PerformOps(&ops);
+    return cq_.Pluck(&ops);
+  }
+
+  bool WritesDone() GRPC_OVERRIDE {
+    CallOpSet<CallOpClientSendClose> ops;
+    ops.ClientSendClose();
+    call_.PerformOps(&ops);
+    return cq_.Pluck(&ops);
+  }
+
+  Status Finish() GRPC_OVERRIDE {
+    CallOpSet<CallOpRecvInitialMetadata, CallOpClientRecvStatus> ops;
+    if (!context_->initial_metadata_received_) {
+      ops.RecvInitialMetadata(context_);
+    }
+    Status status;
+    ops.ClientRecvStatus(context_, &status);
+    call_.PerformOps(&ops);
+    GPR_ASSERT(cq_.Pluck(&ops));
+    return status;
+  }
+
+ private:
+  ClientContext* context_;
+  CompletionQueue cq_;
+  Call call_;
+};
+
+template <class R>
+class ServerReader GRPC_FINAL : public ReaderInterface<R> {
+ public:
+  ServerReader(Call* call, ServerContext* ctx) : call_(call), ctx_(ctx) {}
+
+  void SendInitialMetadata() {
+    GPR_ASSERT(!ctx_->sent_initial_metadata_);
+
+    CallOpSet<CallOpSendInitialMetadata> ops;
+    ops.SendInitialMetadata(ctx_->initial_metadata_);
+    ctx_->sent_initial_metadata_ = true;
+    call_->PerformOps(&ops);
+    call_->cq()->Pluck(&ops);
+  }
+
+  bool Read(R* msg) GRPC_OVERRIDE {
+    CallOpSet<CallOpRecvMessage<R>> ops;
+    ops.RecvMessage(msg);
+    call_->PerformOps(&ops);
+    return call_->cq()->Pluck(&ops) && ops.got_message;
+  }
+
+ private:
+  Call* const call_;
+  ServerContext* const ctx_;
+};
+
+template <class W>
+class ServerWriter GRPC_FINAL : public WriterInterface<W> {
+ public:
+  ServerWriter(Call* call, ServerContext* ctx) : call_(call), ctx_(ctx) {}
+
+  void SendInitialMetadata() {
+    GPR_ASSERT(!ctx_->sent_initial_metadata_);
+
+    CallOpSet<CallOpSendInitialMetadata> ops;
+    ops.SendInitialMetadata(ctx_->initial_metadata_);
+    ctx_->sent_initial_metadata_ = true;
+    call_->PerformOps(&ops);
+    call_->cq()->Pluck(&ops);
+  }
+
+  using WriterInterface<W>::Write;
+  bool Write(const W& msg, const WriteOptions& options) GRPC_OVERRIDE {
+    CallOpSet<CallOpSendInitialMetadata, CallOpSendMessage> ops;
+    if (!ops.SendMessage(msg, options).ok()) {
+      return false;
+    }
+    if (!ctx_->sent_initial_metadata_) {
+      ops.SendInitialMetadata(ctx_->initial_metadata_);
+      ctx_->sent_initial_metadata_ = true;
+    }
+    call_->PerformOps(&ops);
+    return call_->cq()->Pluck(&ops);
+  }
+
+ private:
+  Call* const call_;
+  ServerContext* const ctx_;
+};
+
+/// Server-side interface for bi-directional streaming.
+template <class W, class R>
+class ServerReaderWriter GRPC_FINAL : public WriterInterface<W>,
+                                      public ReaderInterface<R> {
+ public:
+  ServerReaderWriter(Call* call, ServerContext* ctx) : call_(call), ctx_(ctx) {}
+
+  void SendInitialMetadata() {
+    GPR_ASSERT(!ctx_->sent_initial_metadata_);
+
+    CallOpSet<CallOpSendInitialMetadata> ops;
+    ops.SendInitialMetadata(ctx_->initial_metadata_);
+    ctx_->sent_initial_metadata_ = true;
+    call_->PerformOps(&ops);
+    call_->cq()->Pluck(&ops);
+  }
+
+  bool Read(R* msg) GRPC_OVERRIDE {
+    CallOpSet<CallOpRecvMessage<R>> ops;
+    ops.RecvMessage(msg);
+    call_->PerformOps(&ops);
+    return call_->cq()->Pluck(&ops) && ops.got_message;
+  }
+
+  using WriterInterface<W>::Write;
+  bool Write(const W& msg, const WriteOptions& options) GRPC_OVERRIDE {
+    CallOpSet<CallOpSendInitialMetadata, CallOpSendMessage> ops;
+    if (!ops.SendMessage(msg, options).ok()) {
+      return false;
+    }
+    if (!ctx_->sent_initial_metadata_) {
+      ops.SendInitialMetadata(ctx_->initial_metadata_);
+      ctx_->sent_initial_metadata_ = true;
+    }
+    call_->PerformOps(&ops);
+    return call_->cq()->Pluck(&ops);
+  }
+
+ private:
+  Call* const call_;
+  ServerContext* const ctx_;
+};
+
+}  // namespace grpc
+
+#endif  // GRPCXX_IMPL_CODEGEN_SYNC_STREAM_H
diff --git a/include/grpc++/impl/codegen/time.h b/include/grpc++/impl/codegen/time.h
new file mode 100644
index 0000000..bed7423
--- /dev/null
+++ b/include/grpc++/impl/codegen/time.h
@@ -0,0 +1,111 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef GRPCXX_IMPL_CODEGEN_TIME_H
+#define GRPCXX_IMPL_CODEGEN_TIME_H
+
+#include <grpc++/impl/codegen/config.h>
+#include <grpc/impl/codegen/time.h>
+
+namespace grpc {
+
+/* If you are trying to use CompletionQueue::AsyncNext with a time class that
+   isn't either gpr_timespec or std::chrono::system_clock::time_point, you
+   will most likely be looking at this comment as your compiler will have
+   fired an error below. In order to fix this issue, you have two potential
+   solutions:
+
+     1. Use gpr_timespec or std::chrono::system_clock::time_point instead
+     2. Specialize the TimePoint class with whichever time class that you
+        want to use here. See below for two examples of how to do this.
+ */
+
+template <typename T>
+class TimePoint {
+ public:
+  TimePoint(const T& time) { you_need_a_specialization_of_TimePoint(); }
+  gpr_timespec raw_time() {
+    gpr_timespec t;
+    return t;
+  }
+
+ private:
+  void you_need_a_specialization_of_TimePoint();
+};
+
+template <>
+class TimePoint<gpr_timespec> {
+ public:
+  TimePoint(const gpr_timespec& time) : time_(time) {}
+  gpr_timespec raw_time() { return time_; }
+
+ private:
+  gpr_timespec time_;
+};
+
+}  // namespace grpc
+
+#ifndef GRPC_CXX0X_NO_CHRONO
+
+#include <chrono>
+
+#include <grpc/impl/codegen/time.h>
+
+namespace grpc {
+
+// from and to should be absolute time.
+void Timepoint2Timespec(const std::chrono::system_clock::time_point& from,
+                        gpr_timespec* to);
+void TimepointHR2Timespec(
+    const std::chrono::high_resolution_clock::time_point& from,
+    gpr_timespec* to);
+
+std::chrono::system_clock::time_point Timespec2Timepoint(gpr_timespec t);
+
+template <>
+class TimePoint<std::chrono::system_clock::time_point> {
+ public:
+  TimePoint(const std::chrono::system_clock::time_point& time) {
+    Timepoint2Timespec(time, &time_);
+  }
+  gpr_timespec raw_time() const { return time_; }
+
+ private:
+  gpr_timespec time_;
+};
+
+}  // namespace grpc
+
+#endif  // !GRPC_CXX0X_NO_CHRONO
+
+#endif  // GRPCXX_IMPL_CODEGEN_TIME_H
diff --git a/include/grpc++/impl/grpc_library.h b/include/grpc++/impl/grpc_library.h
index ce42114..e8a075f 100644
--- a/include/grpc++/impl/grpc_library.h
+++ b/include/grpc++/impl/grpc_library.h
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -34,16 +34,34 @@
 #ifndef GRPCXX_IMPL_GRPC_LIBRARY_H
 #define GRPCXX_IMPL_GRPC_LIBRARY_H
 
+#include <iostream>
+
+#include <grpc++/impl/codegen/config.h>
+#include <grpc++/impl/codegen/grpc_library.h>
 #include <grpc/grpc.h>
 
 namespace grpc {
 
-class GrpcLibrary {
+namespace internal {
+class GrpcLibrary GRPC_FINAL : public GrpcLibraryInterface {
  public:
-  GrpcLibrary() { grpc_init(); }
-  virtual ~GrpcLibrary() { grpc_shutdown(); }
+  void init() GRPC_OVERRIDE { grpc_init(); }
+
+  void shutdown() GRPC_OVERRIDE { grpc_shutdown(); }
 };
 
+static GrpcLibrary g_gli;
+
+class GrpcLibraryInitializer GRPC_FINAL {
+ public:
+  GrpcLibraryInitializer() { grpc::g_glip = &g_gli; }
+
+  /// A no-op method to force the linker to reference this class, which will
+  /// take care of initializing and shutting down the gRPC runtime.
+  int summon() { return 0; }
+};
+
+}  // namespace internal
 }  // namespace grpc
 
 #endif  // GRPCXX_IMPL_GRPC_LIBRARY_H
diff --git a/src/objective-c/GRPCClient/private/GRPCUnsecuredChannel.h b/include/grpc++/impl/method_handler_impl.h
similarity index 86%
copy from src/objective-c/GRPCClient/private/GRPCUnsecuredChannel.h
copy to include/grpc++/impl/method_handler_impl.h
index 8528be4..305fd28 100644
--- a/src/objective-c/GRPCClient/private/GRPCUnsecuredChannel.h
+++ b/include/grpc++/impl/method_handler_impl.h
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -31,8 +31,9 @@
  *
  */
 
-#import "GRPCChannel.h"
+#ifndef GRPCXX_IMPL_METHOD_HANDLER_IMPL_H
+#define GRPCXX_IMPL_METHOD_HANDLER_IMPL_H
 
-@interface GRPCUnsecuredChannel : GRPCChannel
-- (instancetype)initWithHost:(NSString *)host NS_DESIGNATED_INITIALIZER;
-@end
+#include <grpc++/impl/codegen/method_handler_impl.h>
+
+#endif  // GRPCXX_IMPL_METHOD_HANDLER_IMPL_H
diff --git a/include/grpc++/impl/proto_utils.h b/include/grpc++/impl/proto_utils.h
index 283e334..9124001 100644
--- a/include/grpc++/impl/proto_utils.h
+++ b/include/grpc++/impl/proto_utils.h
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -34,43 +34,6 @@
 #ifndef GRPC_INTERNAL_CPP_PROTO_PROTO_UTILS_H
 #define GRPC_INTERNAL_CPP_PROTO_PROTO_UTILS_H
 
-#include <type_traits>
-
-#include <grpc/grpc.h>
-#include <grpc++/impl/serialization_traits.h>
-#include <grpc++/support/config_protobuf.h>
-#include <grpc++/support/status.h>
-
-namespace grpc {
-
-// Serialize the msg into a buffer created inside the function. The caller
-// should destroy the returned buffer when done with it. If serialization fails,
-// false is returned and buffer is left unchanged.
-Status SerializeProto(const grpc::protobuf::Message& msg,
-                      grpc_byte_buffer** buffer);
-
-// The caller keeps ownership of buffer and msg.
-Status DeserializeProto(grpc_byte_buffer* buffer, grpc::protobuf::Message* msg,
-                        int max_message_size);
-
-template <class T>
-class SerializationTraits<T, typename std::enable_if<std::is_base_of<
-                                 grpc::protobuf::Message, T>::value>::type> {
- public:
-  static Status Serialize(const grpc::protobuf::Message& msg,
-                          grpc_byte_buffer** buffer, bool* own_buffer) {
-    *own_buffer = true;
-    return SerializeProto(msg, buffer);
-  }
-  static Status Deserialize(grpc_byte_buffer* buffer,
-                            grpc::protobuf::Message* msg,
-                            int max_message_size) {
-    auto status = DeserializeProto(buffer, msg, max_message_size);
-    grpc_byte_buffer_destroy(buffer);
-    return status;
-  }
-};
-
-}  // namespace grpc
+#include <grpc++/impl/codegen/proto_utils.h>
 
 #endif  // GRPC_INTERNAL_CPP_PROTO_PROTO_UTILS_H
diff --git a/include/grpc++/impl/rpc_method.h b/include/grpc++/impl/rpc_method.h
index 9800268..8b5d1a3 100644
--- a/include/grpc++/impl/rpc_method.h
+++ b/include/grpc++/impl/rpc_method.h
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -34,40 +34,6 @@
 #ifndef GRPCXX_IMPL_RPC_METHOD_H
 #define GRPCXX_IMPL_RPC_METHOD_H
 
-#include <memory>
-
-#include <grpc++/channel.h>
-
-namespace grpc {
-
-class RpcMethod {
- public:
-  enum RpcType {
-    NORMAL_RPC = 0,
-    CLIENT_STREAMING,  // request streaming
-    SERVER_STREAMING,  // response streaming
-    BIDI_STREAMING
-  };
-
-  RpcMethod(const char* name, RpcType type)
-      : name_(name), method_type_(type), channel_tag_(NULL) {}
-
-  RpcMethod(const char* name, RpcType type,
-            const std::shared_ptr<Channel>& channel)
-      : name_(name),
-        method_type_(type),
-        channel_tag_(channel->RegisterMethod(name)) {}
-
-  const char* name() const { return name_; }
-  RpcType method_type() const { return method_type_; }
-  void* channel_tag() const { return channel_tag_; }
-
- private:
-  const char* const name_;
-  const RpcType method_type_;
-  void* const channel_tag_;
-};
-
-}  // namespace grpc
+#include <grpc++/impl/codegen/rpc_method.h>
 
 #endif  // GRPCXX_IMPL_RPC_METHOD_H
diff --git a/include/grpc++/impl/rpc_service_method.h b/include/grpc++/impl/rpc_service_method.h
index b203c8f..101e6a6 100644
--- a/include/grpc++/impl/rpc_service_method.h
+++ b/include/grpc++/impl/rpc_service_method.h
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -34,234 +34,6 @@
 #ifndef GRPCXX_IMPL_RPC_SERVICE_METHOD_H
 #define GRPCXX_IMPL_RPC_SERVICE_METHOD_H
 
-#include <climits>
-#include <functional>
-#include <map>
-#include <memory>
-#include <vector>
-
-#include <grpc++/impl/rpc_method.h>
-#include <grpc++/support/config.h>
-#include <grpc++/support/status.h>
-#include <grpc++/support/sync_stream.h>
-
-namespace grpc {
-class ServerContext;
-class StreamContextInterface;
-
-// TODO(rocking): we might need to split this file into multiple ones.
-
-// Base class for running an RPC handler.
-class MethodHandler {
- public:
-  virtual ~MethodHandler() {}
-  struct HandlerParameter {
-    HandlerParameter(Call* c, ServerContext* context, grpc_byte_buffer* req,
-                     int max_size)
-        : call(c),
-          server_context(context),
-          request(req),
-          max_message_size(max_size) {}
-    Call* call;
-    ServerContext* server_context;
-    // Handler required to grpc_byte_buffer_destroy this
-    grpc_byte_buffer* request;
-    int max_message_size;
-  };
-  virtual void RunHandler(const HandlerParameter& param) = 0;
-};
-
-// A wrapper class of an application provided rpc method handler.
-template <class ServiceType, class RequestType, class ResponseType>
-class RpcMethodHandler : public MethodHandler {
- public:
-  RpcMethodHandler(
-      std::function<Status(ServiceType*, ServerContext*, const RequestType*,
-                           ResponseType*)> func,
-      ServiceType* service)
-      : func_(func), service_(service) {}
-
-  void RunHandler(const HandlerParameter& param) GRPC_FINAL {
-    RequestType req;
-    Status status = SerializationTraits<RequestType>::Deserialize(
-        param.request, &req, param.max_message_size);
-    ResponseType rsp;
-    if (status.ok()) {
-      status = func_(service_, param.server_context, &req, &rsp);
-    }
-
-    GPR_ASSERT(!param.server_context->sent_initial_metadata_);
-    CallOpSet<CallOpSendInitialMetadata, CallOpSendMessage,
-              CallOpServerSendStatus> ops;
-    ops.SendInitialMetadata(param.server_context->initial_metadata_);
-    if (status.ok()) {
-      status = ops.SendMessage(rsp);
-    }
-    ops.ServerSendStatus(param.server_context->trailing_metadata_, status);
-    param.call->PerformOps(&ops);
-    param.call->cq()->Pluck(&ops);
-  }
-
- private:
-  // Application provided rpc handler function.
-  std::function<Status(ServiceType*, ServerContext*, const RequestType*,
-                       ResponseType*)> func_;
-  // The class the above handler function lives in.
-  ServiceType* service_;
-};
-
-// A wrapper class of an application provided client streaming handler.
-template <class ServiceType, class RequestType, class ResponseType>
-class ClientStreamingHandler : public MethodHandler {
- public:
-  ClientStreamingHandler(
-      std::function<Status(ServiceType*, ServerContext*,
-                           ServerReader<RequestType>*, ResponseType*)> func,
-      ServiceType* service)
-      : func_(func), service_(service) {}
-
-  void RunHandler(const HandlerParameter& param) GRPC_FINAL {
-    ServerReader<RequestType> reader(param.call, param.server_context);
-    ResponseType rsp;
-    Status status = func_(service_, param.server_context, &reader, &rsp);
-
-    GPR_ASSERT(!param.server_context->sent_initial_metadata_);
-    CallOpSet<CallOpSendInitialMetadata, CallOpSendMessage,
-              CallOpServerSendStatus> ops;
-    ops.SendInitialMetadata(param.server_context->initial_metadata_);
-    if (status.ok()) {
-      status = ops.SendMessage(rsp);
-    }
-    ops.ServerSendStatus(param.server_context->trailing_metadata_, status);
-    param.call->PerformOps(&ops);
-    param.call->cq()->Pluck(&ops);
-  }
-
- private:
-  std::function<Status(ServiceType*, ServerContext*, ServerReader<RequestType>*,
-                       ResponseType*)> func_;
-  ServiceType* service_;
-};
-
-// A wrapper class of an application provided server streaming handler.
-template <class ServiceType, class RequestType, class ResponseType>
-class ServerStreamingHandler : public MethodHandler {
- public:
-  ServerStreamingHandler(
-      std::function<Status(ServiceType*, ServerContext*, const RequestType*,
-                           ServerWriter<ResponseType>*)> func,
-      ServiceType* service)
-      : func_(func), service_(service) {}
-
-  void RunHandler(const HandlerParameter& param) GRPC_FINAL {
-    RequestType req;
-    Status status = SerializationTraits<RequestType>::Deserialize(
-        param.request, &req, param.max_message_size);
-
-    if (status.ok()) {
-      ServerWriter<ResponseType> writer(param.call, param.server_context);
-      status = func_(service_, param.server_context, &req, &writer);
-    }
-
-    CallOpSet<CallOpSendInitialMetadata, CallOpServerSendStatus> ops;
-    if (!param.server_context->sent_initial_metadata_) {
-      ops.SendInitialMetadata(param.server_context->initial_metadata_);
-    }
-    ops.ServerSendStatus(param.server_context->trailing_metadata_, status);
-    param.call->PerformOps(&ops);
-    param.call->cq()->Pluck(&ops);
-  }
-
- private:
-  std::function<Status(ServiceType*, ServerContext*, const RequestType*,
-                       ServerWriter<ResponseType>*)> func_;
-  ServiceType* service_;
-};
-
-// A wrapper class of an application provided bidi-streaming handler.
-template <class ServiceType, class RequestType, class ResponseType>
-class BidiStreamingHandler : public MethodHandler {
- public:
-  BidiStreamingHandler(
-      std::function<Status(ServiceType*, ServerContext*,
-                           ServerReaderWriter<ResponseType, RequestType>*)>
-          func,
-      ServiceType* service)
-      : func_(func), service_(service) {}
-
-  void RunHandler(const HandlerParameter& param) GRPC_FINAL {
-    ServerReaderWriter<ResponseType, RequestType> stream(param.call,
-                                                         param.server_context);
-    Status status = func_(service_, param.server_context, &stream);
-
-    CallOpSet<CallOpSendInitialMetadata, CallOpServerSendStatus> ops;
-    if (!param.server_context->sent_initial_metadata_) {
-      ops.SendInitialMetadata(param.server_context->initial_metadata_);
-    }
-    ops.ServerSendStatus(param.server_context->trailing_metadata_, status);
-    param.call->PerformOps(&ops);
-    param.call->cq()->Pluck(&ops);
-  }
-
- private:
-  std::function<Status(ServiceType*, ServerContext*,
-                       ServerReaderWriter<ResponseType, RequestType>*)> func_;
-  ServiceType* service_;
-};
-
-// Handle unknown method by returning UNIMPLEMENTED error.
-class UnknownMethodHandler : public MethodHandler {
- public:
-  template <class T>
-  static void FillOps(ServerContext* context, T* ops) {
-    Status status(StatusCode::UNIMPLEMENTED, "");
-    if (!context->sent_initial_metadata_) {
-      ops->SendInitialMetadata(context->initial_metadata_);
-      context->sent_initial_metadata_ = true;
-    }
-    ops->ServerSendStatus(context->trailing_metadata_, status);
-  }
-
-  void RunHandler(const HandlerParameter& param) GRPC_FINAL {
-    CallOpSet<CallOpSendInitialMetadata, CallOpServerSendStatus> ops;
-    FillOps(param.server_context, &ops);
-    param.call->PerformOps(&ops);
-    param.call->cq()->Pluck(&ops);
-  }
-};
-
-// Server side rpc method class
-class RpcServiceMethod : public RpcMethod {
- public:
-  // Takes ownership of the handler
-  RpcServiceMethod(const char* name, RpcMethod::RpcType type,
-                   MethodHandler* handler)
-      : RpcMethod(name, type), handler_(handler) {}
-
-  MethodHandler* handler() { return handler_.get(); }
-
- private:
-  std::unique_ptr<MethodHandler> handler_;
-};
-
-// This class contains all the method information for an rpc service. It is
-// used for registering a service on a grpc server.
-class RpcService {
- public:
-  // Takes ownership.
-  void AddMethod(RpcServiceMethod* method) { methods_.emplace_back(method); }
-
-  RpcServiceMethod* GetMethod(int i) { return methods_[i].get(); }
-  int GetMethodCount() const {
-    // On win x64, int is only 32bit
-    GPR_ASSERT(methods_.size() <= INT_MAX);
-    return (int)methods_.size();
-  }
-
- private:
-  std::vector<std::unique_ptr<RpcServiceMethod>> methods_;
-};
-
-}  // namespace grpc
+#include <grpc++/impl/codegen/rpc_service_method.h>
 
 #endif  // GRPCXX_IMPL_RPC_SERVICE_METHOD_H
diff --git a/include/grpc++/impl/serialization_traits.h b/include/grpc++/impl/serialization_traits.h
index 3ea66a3..fad4398 100644
--- a/include/grpc++/impl/serialization_traits.h
+++ b/include/grpc++/impl/serialization_traits.h
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -34,35 +34,6 @@
 #ifndef GRPCXX_IMPL_SERIALIZATION_TRAITS_H
 #define GRPCXX_IMPL_SERIALIZATION_TRAITS_H
 
-namespace grpc {
-
-/// Defines how to serialize and deserialize some type.
-///
-/// Used for hooking different message serialization API's into GRPC.
-/// Each SerializationTraits implementation must provide the following
-/// functions:
-///   static Status Serialize(const Message& msg,
-///                           grpc_byte_buffer** buffer,
-//                            bool* own_buffer);
-///   static Status Deserialize(grpc_byte_buffer* buffer,
-///                             Message* msg,
-///                             int max_message_size);
-///
-/// Serialize is required to convert message to a grpc_byte_buffer, and
-/// to store a pointer to that byte buffer at *buffer. *own_buffer should
-/// be set to true if the caller owns said byte buffer, or false if
-/// ownership is retained elsewhere.
-///
-/// Deserialize is required to convert buffer into the message stored at
-/// msg. max_message_size is passed in as a bound on the maximum number of
-/// message bytes Deserialize should accept.
-///
-/// Both functions return a Status, allowing them to explain what went
-/// wrong if required.
-template <class Message,
-          class UnusedButHereForPartialTemplateSpecialization = void>
-class SerializationTraits;
-
-}  // namespace grpc
+#include <grpc++/impl/codegen/serialization_traits.h>
 
 #endif  // GRPCXX_IMPL_SERIALIZATION_TRAITS_H
diff --git a/include/grpc++/impl/service_type.h b/include/grpc++/impl/service_type.h
index 3b6ac1d..b33fbec 100644
--- a/include/grpc++/impl/service_type.h
+++ b/include/grpc++/impl/service_type.h
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -34,90 +34,6 @@
 #ifndef GRPCXX_IMPL_SERVICE_TYPE_H
 #define GRPCXX_IMPL_SERVICE_TYPE_H
 
-#include <grpc++/impl/serialization_traits.h>
-#include <grpc++/server.h>
-#include <grpc++/support/config.h>
-#include <grpc++/support/status.h>
-
-namespace grpc {
-
-class Call;
-class CompletionQueue;
-class RpcService;
-class Server;
-class ServerCompletionQueue;
-class ServerContext;
-
-class SynchronousService {
- public:
-  virtual ~SynchronousService() {}
-  virtual RpcService* service() = 0;
-};
-
-class ServerAsyncStreamingInterface {
- public:
-  virtual ~ServerAsyncStreamingInterface() {}
-
-  virtual void SendInitialMetadata(void* tag) = 0;
-
- private:
-  friend class Server;
-  virtual void BindCall(Call* call) = 0;
-};
-
-class AsynchronousService {
- public:
-  AsynchronousService(const char** method_names, size_t method_count)
-      : server_(nullptr),
-        method_names_(method_names),
-        method_count_(method_count),
-        request_args_(nullptr) {}
-
-  ~AsynchronousService() { delete[] request_args_; }
-
- protected:
-  template <class Message>
-  void RequestAsyncUnary(int index, ServerContext* context, Message* request,
-                         ServerAsyncStreamingInterface* stream,
-                         CompletionQueue* call_cq,
-                         ServerCompletionQueue* notification_cq, void* tag) {
-    server_->RequestAsyncCall(request_args_[index], context, stream, call_cq,
-                              notification_cq, tag, request);
-  }
-  void RequestClientStreaming(int index, ServerContext* context,
-                              ServerAsyncStreamingInterface* stream,
-                              CompletionQueue* call_cq,
-                              ServerCompletionQueue* notification_cq,
-                              void* tag) {
-    server_->RequestAsyncCall(request_args_[index], context, stream, call_cq,
-                              notification_cq, tag);
-  }
-  template <class Message>
-  void RequestServerStreaming(int index, ServerContext* context,
-                              Message* request,
-                              ServerAsyncStreamingInterface* stream,
-                              CompletionQueue* call_cq,
-                              ServerCompletionQueue* notification_cq,
-                              void* tag) {
-    server_->RequestAsyncCall(request_args_[index], context, stream, call_cq,
-                              notification_cq, tag, request);
-  }
-  void RequestBidiStreaming(int index, ServerContext* context,
-                            ServerAsyncStreamingInterface* stream,
-                            CompletionQueue* call_cq,
-                            ServerCompletionQueue* notification_cq, void* tag) {
-    server_->RequestAsyncCall(request_args_[index], context, stream, call_cq,
-                              notification_cq, tag);
-  }
-
- private:
-  friend class Server;
-  Server* server_;
-  const char** const method_names_;
-  size_t method_count_;
-  void** request_args_;
-};
-
-}  // namespace grpc
+#include <grpc++/impl/codegen/service_type.h>
 
 #endif  // GRPCXX_IMPL_SERVICE_TYPE_H
diff --git a/include/grpc++/impl/sync.h b/include/grpc++/impl/sync.h
index 999c430..8241390 100644
--- a/include/grpc++/impl/sync.h
+++ b/include/grpc++/impl/sync.h
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -34,12 +34,6 @@
 #ifndef GRPCXX_IMPL_SYNC_H
 #define GRPCXX_IMPL_SYNC_H
 
-#include <grpc++/support/config.h>
-
-#ifdef GRPC_CXX0X_NO_THREAD
-#include <grpc++/impl/sync_no_cxx11.h>
-#else
-#include <grpc++/impl/sync_cxx11.h>
-#endif
+#include <grpc++/impl/codegen/sync.h>
 
 #endif  // GRPCXX_IMPL_SYNC_H
diff --git a/include/grpc++/impl/sync_cxx11.h b/include/grpc++/impl/sync_cxx11.h
index 4e6f1da..22997a1 100644
--- a/include/grpc++/impl/sync_cxx11.h
+++ b/include/grpc++/impl/sync_cxx11.h
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -34,16 +34,6 @@
 #ifndef GRPCXX_IMPL_SYNC_CXX11_H
 #define GRPCXX_IMPL_SYNC_CXX11_H
 
-#include <condition_variable>
-#include <mutex>
-
-namespace grpc {
-
-using std::condition_variable;
-using std::mutex;
-using std::lock_guard;
-using std::unique_lock;
-
-}  // namespace grpc
+#include <grpc++/impl/codegen/sync_cxx11.h>
 
 #endif  // GRPCXX_IMPL_SYNC_CXX11_H
diff --git a/include/grpc++/impl/sync_no_cxx11.h b/include/grpc++/impl/sync_no_cxx11.h
index 120a031..def800d 100644
--- a/include/grpc++/impl/sync_no_cxx11.h
+++ b/include/grpc++/impl/sync_no_cxx11.h
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -34,72 +34,6 @@
 #ifndef GRPCXX_IMPL_SYNC_NO_CXX11_H
 #define GRPCXX_IMPL_SYNC_NO_CXX11_H
 
-#include <grpc/support/sync.h>
-
-namespace grpc {
-
-template <class mutex>
-class lock_guard;
-class condition_variable;
-
-class mutex {
- public:
-  mutex() { gpr_mu_init(&mu_); }
-  ~mutex() { gpr_mu_destroy(&mu_); }
-
- private:
-  ::gpr_mu mu_;
-  template <class mutex>
-  friend class lock_guard;
-  friend class condition_variable;
-};
-
-template <class mutex>
-class lock_guard {
- public:
-  lock_guard(mutex &mu) : mu_(mu), locked(true) { gpr_mu_lock(&mu.mu_); }
-  ~lock_guard() { unlock_internal(); }
-
- protected:
-  void lock_internal() {
-    if (!locked) gpr_mu_lock(&mu_.mu_);
-    locked = true;
-  }
-  void unlock_internal() {
-    if (locked) gpr_mu_unlock(&mu_.mu_);
-    locked = false;
-  }
-
- private:
-  mutex &mu_;
-  bool locked;
-  friend class condition_variable;
-};
-
-template <class mutex>
-class unique_lock : public lock_guard<mutex> {
- public:
-  unique_lock(mutex &mu) : lock_guard<mutex>(mu) {}
-  void lock() { this->lock_internal(); }
-  void unlock() { this->unlock_internal(); }
-};
-
-class condition_variable {
- public:
-  condition_variable() { gpr_cv_init(&cv_); }
-  ~condition_variable() { gpr_cv_destroy(&cv_); }
-  void wait(lock_guard<mutex> &mu) {
-    mu.locked = false;
-    gpr_cv_wait(&cv_, &mu.mu_.mu_, gpr_inf_future(GPR_CLOCK_REALTIME));
-    mu.locked = true;
-  }
-  void notify_one() { gpr_cv_signal(&cv_); }
-  void notify_all() { gpr_cv_broadcast(&cv_); }
-
- private:
-  gpr_cv cv_;
-};
-
-}  // namespace grpc
+#include <grpc++/impl/codegen/sync_no_cxx11.h>
 
 #endif  // GRPCXX_IMPL_SYNC_NO_CXX11_H
diff --git a/include/grpc++/security/auth_context.h b/include/grpc++/security/auth_context.h
index b924ec9..bca8fa7 100644
--- a/include/grpc++/security/auth_context.h
+++ b/include/grpc++/security/auth_context.h
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -34,77 +34,6 @@
 #ifndef GRPCXX_SUPPORT_AUTH_CONTEXT_H
 #define GRPCXX_SUPPORT_AUTH_CONTEXT_H
 
-#include <iterator>
-#include <vector>
-
-#include <grpc++/support/config.h>
-#include <grpc++/support/string_ref.h>
-
-struct grpc_auth_context;
-struct grpc_auth_property;
-struct grpc_auth_property_iterator;
-
-namespace grpc {
-class SecureAuthContext;
-
-typedef std::pair<grpc::string_ref, grpc::string_ref> AuthProperty;
-
-class AuthPropertyIterator
-    : public std::iterator<std::input_iterator_tag, const AuthProperty> {
- public:
-  ~AuthPropertyIterator();
-  AuthPropertyIterator& operator++();
-  AuthPropertyIterator operator++(int);
-  bool operator==(const AuthPropertyIterator& rhs) const;
-  bool operator!=(const AuthPropertyIterator& rhs) const;
-  const AuthProperty operator*();
-
- protected:
-  AuthPropertyIterator();
-  AuthPropertyIterator(const grpc_auth_property* property,
-                       const grpc_auth_property_iterator* iter);
-
- private:
-  friend class SecureAuthContext;
-  const grpc_auth_property* property_;
-  // The following items form a grpc_auth_property_iterator.
-  const grpc_auth_context* ctx_;
-  size_t index_;
-  const char* name_;
-};
-
-/// Class encapsulating the Authentication Information.
-///
-/// It includes the secure identity of the peer, the type of secure transport
-/// used as well as any other properties required by the authorization layer.
-class AuthContext {
- public:
-  virtual ~AuthContext() {}
-
-  /// Returns true if the peer is authenticated.
-  virtual bool IsPeerAuthenticated() const = 0;
-
-  /// A peer identity.
-  ///
-  /// It is, in general, comprised of one or more properties (in which case they
-  /// have the same name).
-  virtual std::vector<grpc::string_ref> GetPeerIdentity() const = 0;
-  virtual grpc::string GetPeerIdentityPropertyName() const = 0;
-
-  /// Returns all the property values with the given name.
-  virtual std::vector<grpc::string_ref> FindPropertyValues(
-      const grpc::string& name) const = 0;
-
-  /// Iteration over all the properties.
-  virtual AuthPropertyIterator begin() const = 0;
-  virtual AuthPropertyIterator end() const = 0;
-
-  // Mutation functions: should only be used by an AuthMetadataProcessor.
-  virtual void AddProperty(const grpc::string& key,
-                           const grpc::string_ref& value) = 0;
-  virtual bool SetPeerIdentityPropertyName(const grpc::string& name) = 0;
-};
-
-}  // namespace grpc
+#include <grpc++/impl/codegen/security/auth_context.h>
 
 #endif  // GRPCXX_SUPPORT_AUTH_CONTEXT_H
diff --git a/include/grpc++/security/credentials.h b/include/grpc++/security/credentials.h
index 75945fd..e0806c0 100644
--- a/include/grpc++/security/credentials.h
+++ b/include/grpc++/security/credentials.h
@@ -37,12 +37,13 @@
 #include <map>
 #include <memory>
 
-#include <grpc++/impl/grpc_library.h>
+#include <grpc++/impl/codegen/grpc_library.h>
 #include <grpc++/security/auth_context.h>
-#include <grpc++/support/config.h>
 #include <grpc++/support/status.h>
 #include <grpc++/support/string_ref.h>
 
+struct grpc_call;
+
 namespace grpc {
 class ChannelArguments;
 class Channel;
@@ -56,9 +57,10 @@
 /// for all the calls on that channel.
 ///
 /// \see http://www.grpc.io/docs/guides/auth.html
-class ChannelCredentials : public GrpcLibrary {
+class ChannelCredentials : private GrpcLibrary {
  public:
-  ~ChannelCredentials() GRPC_OVERRIDE;
+  ChannelCredentials();
+  ~ChannelCredentials();
 
  protected:
   friend std::shared_ptr<ChannelCredentials> CompositeChannelCredentials(
@@ -81,9 +83,10 @@
 /// authenticate with a server for a given call on a channel.
 ///
 /// \see http://www.grpc.io/docs/guides/auth.html
-class CallCredentials : public GrpcLibrary {
+class CallCredentials : private GrpcLibrary {
  public:
-  ~CallCredentials() GRPC_OVERRIDE;
+  CallCredentials();
+  ~CallCredentials();
 
   /// Apply this instance's credentials to \a call.
   virtual bool ApplyToCall(grpc_call* call) = 0;
diff --git a/include/grpc++/server.h b/include/grpc++/server.h
index f24ed33..2a71073 100644
--- a/include/grpc++/server.h
+++ b/include/grpc++/server.h
@@ -39,7 +39,9 @@
 
 #include <grpc++/completion_queue.h>
 #include <grpc++/impl/call.h>
-#include <grpc++/impl/grpc_library.h>
+#include <grpc++/impl/codegen/grpc_library.h>
+#include <grpc++/impl/codegen/server_interface.h>
+#include <grpc++/impl/rpc_service_method.h>
 #include <grpc++/impl/sync.h>
 #include <grpc++/security/server_credentials.h>
 #include <grpc++/support/channel_arguments.h>
@@ -51,11 +53,8 @@
 
 namespace grpc {
 
-class AsynchronousService;
 class GenericServerContext;
 class AsyncGenericService;
-class RpcService;
-class RpcServiceMethod;
 class ServerAsyncStreamingInterface;
 class ServerContext;
 class ThreadPoolInterface;
@@ -63,28 +62,15 @@
 /// Models a gRPC server.
 ///
 /// Servers are configured and started via \a grpc::ServerBuilder.
-class Server GRPC_FINAL : public GrpcLibrary, private CallHook {
+class Server GRPC_FINAL : public ServerInterface, private GrpcLibrary {
  public:
   ~Server();
 
-  /// Shutdown the server, blocking until all rpc processing finishes.
-  /// Forcefully terminate pending calls after \a deadline expires.
-  ///
-  /// \param deadline How long to wait until pending rpcs are forcefully
-  /// terminated.
-  template <class T>
-  void Shutdown(const T& deadline) {
-    ShutdownInternal(TimePoint<T>(deadline).raw_time());
-  }
-
-  /// Shutdown the server, waiting for all rpc processing to finish.
-  void Shutdown() { ShutdownInternal(gpr_inf_future(GPR_CLOCK_MONOTONIC)); }
-
   /// Block waiting for all work to complete.
   ///
   /// \warning The server must be either shutting down or some other thread must
   /// call \a Shutdown for this function to ever return.
-  void Wait();
+  void Wait() GRPC_OVERRIDE;
 
   /// Global Callbacks
   ///
@@ -105,13 +91,16 @@
 
  private:
   friend class AsyncGenericService;
-  friend class AsynchronousService;
   friend class ServerBuilder;
 
   class SyncRequest;
   class AsyncRequest;
   class ShutdownRequest;
 
+  class UnimplementedAsyncRequestContext;
+  class UnimplementedAsyncRequest;
+  class UnimplementedAsyncResponse;
+
   /// Server constructors. To be used by \a ServerBuilder only.
   ///
   /// \param thread_pool The threadpool instance to use for call processing.
@@ -123,16 +112,12 @@
 
   /// Register a service. This call does not take ownership of the service.
   /// The service must exist for the lifetime of the Server instance.
-  bool RegisterService(const grpc::string* host, RpcService* service);
-
-  /// Register an asynchronous service. This call does not take ownership of the
-  /// service. The service must exist for the lifetime of the Server instance.
-  bool RegisterAsyncService(const grpc::string* host,
-                            AsynchronousService* service);
+  bool RegisterService(const grpc::string* host,
+                       Service* service) GRPC_OVERRIDE;
 
   /// Register a generic service. This call does not take ownership of the
   /// service. The service must exist for the lifetime of the Server instance.
-  void RegisterAsyncGenericService(AsyncGenericService* service);
+  void RegisterAsyncGenericService(AsyncGenericService* service) GRPC_OVERRIDE;
 
   /// Tries to bind \a server to the given \a addr.
   ///
@@ -145,7 +130,8 @@
   /// \return bound port number on sucess, 0 on failure.
   ///
   /// \warning It's an error to call this method on an already started server.
-  int AddListeningPort(const grpc::string& addr, ServerCredentials* creds);
+  int AddListeningPort(const grpc::string& addr,
+                       ServerCredentials* creds) GRPC_OVERRIDE;
 
   /// Start the server.
   ///
@@ -155,141 +141,21 @@
   /// \param num_cqs How many completion queues does \a cqs hold.
   ///
   /// \return true on a successful shutdown.
-  bool Start(ServerCompletionQueue** cqs, size_t num_cqs);
-
-  void HandleQueueClosed();
+  bool Start(ServerCompletionQueue** cqs, size_t num_cqs) GRPC_OVERRIDE;
 
   /// Process one or more incoming calls.
-  void RunRpc();
+  void RunRpc() GRPC_OVERRIDE;
 
   /// Schedule \a RunRpc to run in the threadpool.
-  void ScheduleCallback();
+  void ScheduleCallback() GRPC_OVERRIDE;
 
   void PerformOpsOnCall(CallOpSetInterface* ops, Call* call) GRPC_OVERRIDE;
 
-  void ShutdownInternal(gpr_timespec deadline);
+  void ShutdownInternal(gpr_timespec deadline) GRPC_OVERRIDE;
 
-  class BaseAsyncRequest : public CompletionQueueTag {
-   public:
-    BaseAsyncRequest(Server* server, ServerContext* context,
-                     ServerAsyncStreamingInterface* stream,
-                     CompletionQueue* call_cq, void* tag,
-                     bool delete_on_finalize);
-    virtual ~BaseAsyncRequest();
+  int max_message_size() const GRPC_OVERRIDE { return max_message_size_; };
 
-    bool FinalizeResult(void** tag, bool* status) GRPC_OVERRIDE;
-
-   protected:
-    Server* const server_;
-    ServerContext* const context_;
-    ServerAsyncStreamingInterface* const stream_;
-    CompletionQueue* const call_cq_;
-    void* const tag_;
-    const bool delete_on_finalize_;
-    grpc_call* call_;
-    grpc_metadata_array initial_metadata_array_;
-  };
-
-  class RegisteredAsyncRequest : public BaseAsyncRequest {
-   public:
-    RegisteredAsyncRequest(Server* server, ServerContext* context,
-                           ServerAsyncStreamingInterface* stream,
-                           CompletionQueue* call_cq, void* tag);
-
-    // uses BaseAsyncRequest::FinalizeResult
-
-   protected:
-    void IssueRequest(void* registered_method, grpc_byte_buffer** payload,
-                      ServerCompletionQueue* notification_cq);
-  };
-
-  class NoPayloadAsyncRequest GRPC_FINAL : public RegisteredAsyncRequest {
-   public:
-    NoPayloadAsyncRequest(void* registered_method, Server* server,
-                          ServerContext* context,
-                          ServerAsyncStreamingInterface* stream,
-                          CompletionQueue* call_cq,
-                          ServerCompletionQueue* notification_cq, void* tag)
-        : RegisteredAsyncRequest(server, context, stream, call_cq, tag) {
-      IssueRequest(registered_method, nullptr, notification_cq);
-    }
-
-    // uses RegisteredAsyncRequest::FinalizeResult
-  };
-
-  template <class Message>
-  class PayloadAsyncRequest GRPC_FINAL : public RegisteredAsyncRequest {
-   public:
-    PayloadAsyncRequest(void* registered_method, Server* server,
-                        ServerContext* context,
-                        ServerAsyncStreamingInterface* stream,
-                        CompletionQueue* call_cq,
-                        ServerCompletionQueue* notification_cq, void* tag,
-                        Message* request)
-        : RegisteredAsyncRequest(server, context, stream, call_cq, tag),
-          request_(request) {
-      IssueRequest(registered_method, &payload_, notification_cq);
-    }
-
-    bool FinalizeResult(void** tag, bool* status) GRPC_OVERRIDE {
-      bool serialization_status =
-          *status && payload_ &&
-          SerializationTraits<Message>::Deserialize(
-              payload_, request_, server_->max_message_size_).ok();
-      bool ret = RegisteredAsyncRequest::FinalizeResult(tag, status);
-      *status = serialization_status&&* status;
-      return ret;
-    }
-
-   private:
-    grpc_byte_buffer* payload_;
-    Message* const request_;
-  };
-
-  class GenericAsyncRequest : public BaseAsyncRequest {
-   public:
-    GenericAsyncRequest(Server* server, GenericServerContext* context,
-                        ServerAsyncStreamingInterface* stream,
-                        CompletionQueue* call_cq,
-                        ServerCompletionQueue* notification_cq, void* tag,
-                        bool delete_on_finalize);
-
-    bool FinalizeResult(void** tag, bool* status) GRPC_OVERRIDE;
-
-   private:
-    grpc_call_details call_details_;
-  };
-
-  class UnimplementedAsyncRequestContext;
-  class UnimplementedAsyncRequest;
-  class UnimplementedAsyncResponse;
-
-  template <class Message>
-  void RequestAsyncCall(void* registered_method, ServerContext* context,
-                        ServerAsyncStreamingInterface* stream,
-                        CompletionQueue* call_cq,
-                        ServerCompletionQueue* notification_cq, void* tag,
-                        Message* message) {
-    new PayloadAsyncRequest<Message>(registered_method, this, context, stream,
-                                     call_cq, notification_cq, tag, message);
-  }
-
-  void RequestAsyncCall(void* registered_method, ServerContext* context,
-                        ServerAsyncStreamingInterface* stream,
-                        CompletionQueue* call_cq,
-                        ServerCompletionQueue* notification_cq, void* tag) {
-    new NoPayloadAsyncRequest(registered_method, this, context, stream, call_cq,
-                              notification_cq, tag);
-  }
-
-  void RequestAsyncGenericCall(GenericServerContext* context,
-                               ServerAsyncStreamingInterface* stream,
-                               CompletionQueue* call_cq,
-                               ServerCompletionQueue* notification_cq,
-                               void* tag) {
-    new GenericAsyncRequest(this, context, stream, call_cq, notification_cq,
-                            tag, true);
-  }
+  grpc_server* server() GRPC_OVERRIDE { return server_; };
 
   const int max_message_size_;
 
diff --git a/include/grpc++/server_builder.h b/include/grpc++/server_builder.h
index b324deb..73bcfb6 100644
--- a/include/grpc++/server_builder.h
+++ b/include/grpc++/server_builder.h
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -44,14 +44,12 @@
 namespace grpc {
 
 class AsyncGenericService;
-class AsynchronousService;
 class CompletionQueue;
 class RpcService;
 class Server;
 class ServerCompletionQueue;
 class ServerCredentials;
-class SynchronousService;
-class ThreadPoolInterface;
+class Service;
 
 /// A builder class for the creation and startup of \a grpc::Server instances.
 class ServerBuilder {
@@ -62,14 +60,7 @@
   /// The service must exist for the lifetime of the \a Server instance returned
   /// by \a BuildAndStart().
   /// Matches requests with any :authority
-  void RegisterService(SynchronousService* service);
-
-  /// Register an asynchronous service.
-  /// This call does not take ownership of the service or completion queue.
-  /// The service and completion queuemust exist for the lifetime of the \a
-  /// Server instance returned by \a BuildAndStart().
-  /// Matches requests with any :authority
-  void RegisterAsyncService(AsynchronousService* service);
+  void RegisterService(Service* service);
 
   /// Register a generic service.
   /// Matches requests with any :authority
@@ -79,15 +70,7 @@
   /// The service must exist for the lifetime of the \a Server instance returned
   /// by BuildAndStart().
   /// Only matches requests with :authority \a host
-  void RegisterService(const grpc::string& host, SynchronousService* service);
-
-  /// Register an asynchronous service.
-  /// This call does not take ownership of the service or completion queue.
-  /// The service and completion queuemust exist for the lifetime of the \a
-  /// Server instance returned by \a BuildAndStart().
-  /// Only matches requests with :authority equal to \a host
-  void RegisterAsyncService(const grpc::string& host,
-                            AsynchronousService* service);
+  void RegisterService(const grpc::string& host, Service* service);
 
   /// Set max message size in bytes.
   void SetMaxMessageSize(int max_message_size) {
@@ -132,26 +115,22 @@
   };
 
   typedef std::unique_ptr<grpc::string> HostString;
-  template <class T>
   struct NamedService {
-    explicit NamedService(T* s) : service(s) {}
-    NamedService(const grpc::string& h, T* s)
+    explicit NamedService(Service* s) : service(s) {}
+    NamedService(const grpc::string& h, Service* s)
         : host(new grpc::string(h)), service(s) {}
     HostString host;
-    T* service;
+    Service* service;
   };
 
   int max_message_size_;
   grpc_compression_options compression_options_;
   std::vector<std::unique_ptr<ServerBuilderOption>> options_;
-  std::vector<std::unique_ptr<NamedService<RpcService>>> services_;
-  std::vector<std::unique_ptr<NamedService<AsynchronousService>>>
-      async_services_;
+  std::vector<std::unique_ptr<NamedService>> services_;
   std::vector<Port> ports_;
   std::vector<ServerCompletionQueue*> cqs_;
   std::shared_ptr<ServerCredentials> creds_;
   AsyncGenericService* generic_service_;
-  ThreadPoolInterface* thread_pool_;
 };
 
 }  // namespace grpc
diff --git a/include/grpc++/server_context.h b/include/grpc++/server_context.h
index 8ba7348..214188a 100644
--- a/include/grpc++/server_context.h
+++ b/include/grpc++/server_context.h
@@ -34,166 +34,6 @@
 #ifndef GRPCXX_SERVER_CONTEXT_H
 #define GRPCXX_SERVER_CONTEXT_H
 
-#include <map>
-#include <memory>
-
-#include <grpc/compression.h>
-#include <grpc/support/time.h>
-#include <grpc++/security/auth_context.h>
-#include <grpc++/support/config.h>
-#include <grpc++/support/string_ref.h>
-#include <grpc++/support/time.h>
-
-struct gpr_timespec;
-struct grpc_metadata;
-struct grpc_call;
-struct census_context;
-
-namespace grpc {
-
-class ClientContext;
-template <class W, class R>
-class ServerAsyncReader;
-template <class W>
-class ServerAsyncWriter;
-template <class W>
-class ServerAsyncResponseWriter;
-template <class W, class R>
-class ServerAsyncReaderWriter;
-template <class R>
-class ServerReader;
-template <class W>
-class ServerWriter;
-template <class W, class R>
-class ServerReaderWriter;
-template <class ServiceType, class RequestType, class ResponseType>
-class RpcMethodHandler;
-template <class ServiceType, class RequestType, class ResponseType>
-class ClientStreamingHandler;
-template <class ServiceType, class RequestType, class ResponseType>
-class ServerStreamingHandler;
-template <class ServiceType, class RequestType, class ResponseType>
-class BidiStreamingHandler;
-class UnknownMethodHandler;
-
-class Call;
-class CallOpBuffer;
-class CompletionQueue;
-class Server;
-
-namespace testing {
-class InteropServerContextInspector;
-}  // namespace testing
-
-// Interface of server side rpc context.
-class ServerContext {
- public:
-  ServerContext();  // for async calls
-  ~ServerContext();
-
-#ifndef GRPC_CXX0X_NO_CHRONO
-  std::chrono::system_clock::time_point deadline() {
-    return Timespec2Timepoint(deadline_);
-  }
-#endif  // !GRPC_CXX0X_NO_CHRONO
-
-  gpr_timespec raw_deadline() { return deadline_; }
-
-  void AddInitialMetadata(const grpc::string& key, const grpc::string& value);
-  void AddTrailingMetadata(const grpc::string& key, const grpc::string& value);
-
-  bool IsCancelled() const;
-
-  const std::multimap<grpc::string_ref, grpc::string_ref>& client_metadata() {
-    return client_metadata_;
-  }
-
-  grpc_compression_level compression_level() const {
-    return compression_level_;
-  }
-  void set_compression_level(grpc_compression_level level);
-
-  grpc_compression_algorithm compression_algorithm() const {
-    return compression_algorithm_;
-  }
-  void set_compression_algorithm(grpc_compression_algorithm algorithm);
-
-  std::shared_ptr<const AuthContext> auth_context() const;
-
-  // Return the peer uri in a string.
-  // WARNING: this value is never authenticated or subject to any security
-  // related code. It must not be used for any authentication related
-  // functionality. Instead, use auth_context.
-  grpc::string peer() const;
-
-  const struct census_context* census_context() const;
-
-  // Async only. Has to be called before the rpc starts.
-  // Returns the tag in completion queue when the rpc finishes.
-  // IsCancelled() can then be called to check whether the rpc was cancelled.
-  void AsyncNotifyWhenDone(void* tag) {
-    has_notify_when_done_tag_ = true;
-    async_notify_when_done_tag_ = tag;
-  }
-
- private:
-  friend class ::grpc::testing::InteropServerContextInspector;
-  friend class ::grpc::Server;
-  template <class W, class R>
-  friend class ::grpc::ServerAsyncReader;
-  template <class W>
-  friend class ::grpc::ServerAsyncWriter;
-  template <class W>
-  friend class ::grpc::ServerAsyncResponseWriter;
-  template <class W, class R>
-  friend class ::grpc::ServerAsyncReaderWriter;
-  template <class R>
-  friend class ::grpc::ServerReader;
-  template <class W>
-  friend class ::grpc::ServerWriter;
-  template <class W, class R>
-  friend class ::grpc::ServerReaderWriter;
-  template <class ServiceType, class RequestType, class ResponseType>
-  friend class RpcMethodHandler;
-  template <class ServiceType, class RequestType, class ResponseType>
-  friend class ClientStreamingHandler;
-  template <class ServiceType, class RequestType, class ResponseType>
-  friend class ServerStreamingHandler;
-  template <class ServiceType, class RequestType, class ResponseType>
-  friend class BidiStreamingHandler;
-  friend class UnknownMethodHandler;
-  friend class ::grpc::ClientContext;
-
-  // Prevent copying.
-  ServerContext(const ServerContext&);
-  ServerContext& operator=(const ServerContext&);
-
-  class CompletionOp;
-
-  void BeginCompletionOp(Call* call);
-
-  ServerContext(gpr_timespec deadline, grpc_metadata* metadata,
-                size_t metadata_count);
-
-  void set_call(grpc_call* call);
-
-  CompletionOp* completion_op_;
-  bool has_notify_when_done_tag_;
-  void* async_notify_when_done_tag_;
-
-  gpr_timespec deadline_;
-  grpc_call* call_;
-  CompletionQueue* cq_;
-  bool sent_initial_metadata_;
-  mutable std::shared_ptr<const AuthContext> auth_context_;
-  std::multimap<grpc::string_ref, grpc::string_ref> client_metadata_;
-  std::multimap<grpc::string, grpc::string> initial_metadata_;
-  std::multimap<grpc::string, grpc::string> trailing_metadata_;
-
-  grpc_compression_level compression_level_;
-  grpc_compression_algorithm compression_algorithm_;
-};
-
-}  // namespace grpc
+#include <grpc++/impl/codegen/server_context.h>
 
 #endif  // GRPCXX_SERVER_CONTEXT_H
diff --git a/include/grpc++/support/async_stream.h b/include/grpc++/support/async_stream.h
index 0c96352..88147ea 100644
--- a/include/grpc++/support/async_stream.h
+++ b/include/grpc++/support/async_stream.h
@@ -34,430 +34,6 @@
 #ifndef GRPCXX_SUPPORT_ASYNC_STREAM_H
 #define GRPCXX_SUPPORT_ASYNC_STREAM_H
 
-#include <grpc/support/log.h>
-#include <grpc++/channel.h>
-#include <grpc++/client_context.h>
-#include <grpc++/completion_queue.h>
-#include <grpc++/impl/call.h>
-#include <grpc++/impl/service_type.h>
-#include <grpc++/server_context.h>
-#include <grpc++/support/status.h>
-
-namespace grpc {
-
-/// Common interface for all client side asynchronous streaming.
-class ClientAsyncStreamingInterface {
- public:
-  virtual ~ClientAsyncStreamingInterface() {}
-
-  /// Request notification of the reading of the initial metadata. Completion
-  /// will be notified by \a tag on the associated completion queue.
-  ///
-  /// \param[in] tag Tag identifying this request.
-  virtual void ReadInitialMetadata(void* tag) = 0;
-
-  /// Request notification completion.
-  ///
-  /// \param[out] status To be updated with the operation status.
-  /// \param[in] tag Tag identifying this request.
-  virtual void Finish(Status* status, void* tag) = 0;
-};
-
-/// An interface that yields a sequence of messages of type \a R.
-template <class R>
-class AsyncReaderInterface {
- public:
-  virtual ~AsyncReaderInterface() {}
-
-  /// Read a message of type \a R into \a msg. Completion will be notified by \a
-  /// tag on the associated completion queue.
-  ///
-  /// \param[out] msg Where to eventually store the read message.
-  /// \param[in] tag The tag identifying the operation.
-  virtual void Read(R* msg, void* tag) = 0;
-};
-
-/// An interface that can be fed a sequence of messages of type \a W.
-template <class W>
-class AsyncWriterInterface {
- public:
-  virtual ~AsyncWriterInterface() {}
-
-  /// Request the writing of \a msg with identifying tag \a tag.
-  ///
-  /// Only one write may be outstanding at any given time. This means that
-  /// after calling Write, one must wait to receive \a tag from the completion
-  /// queue BEFORE calling Write again.
-  ///
-  /// \param[in] msg The message to be written.
-  /// \param[in] tag The tag identifying the operation.
-  virtual void Write(const W& msg, void* tag) = 0;
-};
-
-template <class R>
-class ClientAsyncReaderInterface : public ClientAsyncStreamingInterface,
-                                   public AsyncReaderInterface<R> {};
-
-template <class R>
-class ClientAsyncReader GRPC_FINAL : public ClientAsyncReaderInterface<R> {
- public:
-  /// Create a stream and write the first request out.
-  template <class W>
-  ClientAsyncReader(Channel* channel, CompletionQueue* cq,
-                    const RpcMethod& method, ClientContext* context,
-                    const W& request, void* tag)
-      : context_(context), call_(channel->CreateCall(method, context, cq)) {
-    init_ops_.set_output_tag(tag);
-    init_ops_.SendInitialMetadata(context->send_initial_metadata_);
-    // TODO(ctiller): don't assert
-    GPR_ASSERT(init_ops_.SendMessage(request).ok());
-    init_ops_.ClientSendClose();
-    call_.PerformOps(&init_ops_);
-  }
-
-  void ReadInitialMetadata(void* tag) GRPC_OVERRIDE {
-    GPR_ASSERT(!context_->initial_metadata_received_);
-
-    meta_ops_.set_output_tag(tag);
-    meta_ops_.RecvInitialMetadata(context_);
-    call_.PerformOps(&meta_ops_);
-  }
-
-  void Read(R* msg, void* tag) GRPC_OVERRIDE {
-    read_ops_.set_output_tag(tag);
-    if (!context_->initial_metadata_received_) {
-      read_ops_.RecvInitialMetadata(context_);
-    }
-    read_ops_.RecvMessage(msg);
-    call_.PerformOps(&read_ops_);
-  }
-
-  void Finish(Status* status, void* tag) GRPC_OVERRIDE {
-    finish_ops_.set_output_tag(tag);
-    if (!context_->initial_metadata_received_) {
-      finish_ops_.RecvInitialMetadata(context_);
-    }
-    finish_ops_.ClientRecvStatus(context_, status);
-    call_.PerformOps(&finish_ops_);
-  }
-
- private:
-  ClientContext* context_;
-  Call call_;
-  CallOpSet<CallOpSendInitialMetadata, CallOpSendMessage, CallOpClientSendClose>
-      init_ops_;
-  CallOpSet<CallOpRecvInitialMetadata> meta_ops_;
-  CallOpSet<CallOpRecvInitialMetadata, CallOpRecvMessage<R>> read_ops_;
-  CallOpSet<CallOpRecvInitialMetadata, CallOpClientRecvStatus> finish_ops_;
-};
-
-/// Common interface for client side asynchronous writing.
-template <class W>
-class ClientAsyncWriterInterface : public ClientAsyncStreamingInterface,
-                                   public AsyncWriterInterface<W> {
- public:
-  /// Signal the client is done with the writes.
-  ///
-  /// \param[in] tag The tag identifying the operation.
-  virtual void WritesDone(void* tag) = 0;
-};
-
-template <class W>
-class ClientAsyncWriter GRPC_FINAL : public ClientAsyncWriterInterface<W> {
- public:
-  template <class R>
-  ClientAsyncWriter(Channel* channel, CompletionQueue* cq,
-                    const RpcMethod& method, ClientContext* context,
-                    R* response, void* tag)
-      : context_(context), call_(channel->CreateCall(method, context, cq)) {
-    finish_ops_.RecvMessage(response);
-
-    init_ops_.set_output_tag(tag);
-    init_ops_.SendInitialMetadata(context->send_initial_metadata_);
-    call_.PerformOps(&init_ops_);
-  }
-
-  void ReadInitialMetadata(void* tag) GRPC_OVERRIDE {
-    GPR_ASSERT(!context_->initial_metadata_received_);
-
-    meta_ops_.set_output_tag(tag);
-    meta_ops_.RecvInitialMetadata(context_);
-    call_.PerformOps(&meta_ops_);
-  }
-
-  void Write(const W& msg, void* tag) GRPC_OVERRIDE {
-    write_ops_.set_output_tag(tag);
-    // TODO(ctiller): don't assert
-    GPR_ASSERT(write_ops_.SendMessage(msg).ok());
-    call_.PerformOps(&write_ops_);
-  }
-
-  void WritesDone(void* tag) GRPC_OVERRIDE {
-    writes_done_ops_.set_output_tag(tag);
-    writes_done_ops_.ClientSendClose();
-    call_.PerformOps(&writes_done_ops_);
-  }
-
-  void Finish(Status* status, void* tag) GRPC_OVERRIDE {
-    finish_ops_.set_output_tag(tag);
-    if (!context_->initial_metadata_received_) {
-      finish_ops_.RecvInitialMetadata(context_);
-    }
-    finish_ops_.ClientRecvStatus(context_, status);
-    call_.PerformOps(&finish_ops_);
-  }
-
- private:
-  ClientContext* context_;
-  Call call_;
-  CallOpSet<CallOpSendInitialMetadata> init_ops_;
-  CallOpSet<CallOpRecvInitialMetadata> meta_ops_;
-  CallOpSet<CallOpSendMessage> write_ops_;
-  CallOpSet<CallOpClientSendClose> writes_done_ops_;
-  CallOpSet<CallOpRecvInitialMetadata, CallOpGenericRecvMessage,
-            CallOpClientRecvStatus> finish_ops_;
-};
-
-/// Client-side interface for asynchronous bi-directional streaming.
-template <class W, class R>
-class ClientAsyncReaderWriterInterface : public ClientAsyncStreamingInterface,
-                                         public AsyncWriterInterface<W>,
-                                         public AsyncReaderInterface<R> {
- public:
-  /// Signal the client is done with the writes.
-  ///
-  /// \param[in] tag The tag identifying the operation.
-  virtual void WritesDone(void* tag) = 0;
-};
-
-template <class W, class R>
-class ClientAsyncReaderWriter GRPC_FINAL
-    : public ClientAsyncReaderWriterInterface<W, R> {
- public:
-  ClientAsyncReaderWriter(Channel* channel, CompletionQueue* cq,
-                          const RpcMethod& method, ClientContext* context,
-                          void* tag)
-      : context_(context), call_(channel->CreateCall(method, context, cq)) {
-    init_ops_.set_output_tag(tag);
-    init_ops_.SendInitialMetadata(context->send_initial_metadata_);
-    call_.PerformOps(&init_ops_);
-  }
-
-  void ReadInitialMetadata(void* tag) GRPC_OVERRIDE {
-    GPR_ASSERT(!context_->initial_metadata_received_);
-
-    meta_ops_.set_output_tag(tag);
-    meta_ops_.RecvInitialMetadata(context_);
-    call_.PerformOps(&meta_ops_);
-  }
-
-  void Read(R* msg, void* tag) GRPC_OVERRIDE {
-    read_ops_.set_output_tag(tag);
-    if (!context_->initial_metadata_received_) {
-      read_ops_.RecvInitialMetadata(context_);
-    }
-    read_ops_.RecvMessage(msg);
-    call_.PerformOps(&read_ops_);
-  }
-
-  void Write(const W& msg, void* tag) GRPC_OVERRIDE {
-    write_ops_.set_output_tag(tag);
-    // TODO(ctiller): don't assert
-    GPR_ASSERT(write_ops_.SendMessage(msg).ok());
-    call_.PerformOps(&write_ops_);
-  }
-
-  void WritesDone(void* tag) GRPC_OVERRIDE {
-    writes_done_ops_.set_output_tag(tag);
-    writes_done_ops_.ClientSendClose();
-    call_.PerformOps(&writes_done_ops_);
-  }
-
-  void Finish(Status* status, void* tag) GRPC_OVERRIDE {
-    finish_ops_.set_output_tag(tag);
-    if (!context_->initial_metadata_received_) {
-      finish_ops_.RecvInitialMetadata(context_);
-    }
-    finish_ops_.ClientRecvStatus(context_, status);
-    call_.PerformOps(&finish_ops_);
-  }
-
- private:
-  ClientContext* context_;
-  Call call_;
-  CallOpSet<CallOpSendInitialMetadata> init_ops_;
-  CallOpSet<CallOpRecvInitialMetadata> meta_ops_;
-  CallOpSet<CallOpRecvInitialMetadata, CallOpRecvMessage<R>> read_ops_;
-  CallOpSet<CallOpSendMessage> write_ops_;
-  CallOpSet<CallOpClientSendClose> writes_done_ops_;
-  CallOpSet<CallOpRecvInitialMetadata, CallOpClientRecvStatus> finish_ops_;
-};
-
-template <class W, class R>
-class ServerAsyncReader GRPC_FINAL : public ServerAsyncStreamingInterface,
-                                     public AsyncReaderInterface<R> {
- public:
-  explicit ServerAsyncReader(ServerContext* ctx)
-      : call_(nullptr, nullptr, nullptr), ctx_(ctx) {}
-
-  void SendInitialMetadata(void* tag) GRPC_OVERRIDE {
-    GPR_ASSERT(!ctx_->sent_initial_metadata_);
-
-    meta_ops_.set_output_tag(tag);
-    meta_ops_.SendInitialMetadata(ctx_->initial_metadata_);
-    ctx_->sent_initial_metadata_ = true;
-    call_.PerformOps(&meta_ops_);
-  }
-
-  void Read(R* msg, void* tag) GRPC_OVERRIDE {
-    read_ops_.set_output_tag(tag);
-    read_ops_.RecvMessage(msg);
-    call_.PerformOps(&read_ops_);
-  }
-
-  void Finish(const W& msg, const Status& status, void* tag) {
-    finish_ops_.set_output_tag(tag);
-    if (!ctx_->sent_initial_metadata_) {
-      finish_ops_.SendInitialMetadata(ctx_->initial_metadata_);
-      ctx_->sent_initial_metadata_ = true;
-    }
-    // The response is dropped if the status is not OK.
-    if (status.ok()) {
-      finish_ops_.ServerSendStatus(ctx_->trailing_metadata_,
-                                   finish_ops_.SendMessage(msg));
-    } else {
-      finish_ops_.ServerSendStatus(ctx_->trailing_metadata_, status);
-    }
-    call_.PerformOps(&finish_ops_);
-  }
-
-  void FinishWithError(const Status& status, void* tag) {
-    GPR_ASSERT(!status.ok());
-    finish_ops_.set_output_tag(tag);
-    if (!ctx_->sent_initial_metadata_) {
-      finish_ops_.SendInitialMetadata(ctx_->initial_metadata_);
-      ctx_->sent_initial_metadata_ = true;
-    }
-    finish_ops_.ServerSendStatus(ctx_->trailing_metadata_, status);
-    call_.PerformOps(&finish_ops_);
-  }
-
- private:
-  void BindCall(Call* call) GRPC_OVERRIDE { call_ = *call; }
-
-  Call call_;
-  ServerContext* ctx_;
-  CallOpSet<CallOpSendInitialMetadata> meta_ops_;
-  CallOpSet<CallOpRecvMessage<R>> read_ops_;
-  CallOpSet<CallOpSendInitialMetadata, CallOpSendMessage,
-            CallOpServerSendStatus> finish_ops_;
-};
-
-template <class W>
-class ServerAsyncWriter GRPC_FINAL : public ServerAsyncStreamingInterface,
-                                     public AsyncWriterInterface<W> {
- public:
-  explicit ServerAsyncWriter(ServerContext* ctx)
-      : call_(nullptr, nullptr, nullptr), ctx_(ctx) {}
-
-  void SendInitialMetadata(void* tag) GRPC_OVERRIDE {
-    GPR_ASSERT(!ctx_->sent_initial_metadata_);
-
-    meta_ops_.set_output_tag(tag);
-    meta_ops_.SendInitialMetadata(ctx_->initial_metadata_);
-    ctx_->sent_initial_metadata_ = true;
-    call_.PerformOps(&meta_ops_);
-  }
-
-  void Write(const W& msg, void* tag) GRPC_OVERRIDE {
-    write_ops_.set_output_tag(tag);
-    if (!ctx_->sent_initial_metadata_) {
-      write_ops_.SendInitialMetadata(ctx_->initial_metadata_);
-      ctx_->sent_initial_metadata_ = true;
-    }
-    // TODO(ctiller): don't assert
-    GPR_ASSERT(write_ops_.SendMessage(msg).ok());
-    call_.PerformOps(&write_ops_);
-  }
-
-  void Finish(const Status& status, void* tag) {
-    finish_ops_.set_output_tag(tag);
-    if (!ctx_->sent_initial_metadata_) {
-      finish_ops_.SendInitialMetadata(ctx_->initial_metadata_);
-      ctx_->sent_initial_metadata_ = true;
-    }
-    finish_ops_.ServerSendStatus(ctx_->trailing_metadata_, status);
-    call_.PerformOps(&finish_ops_);
-  }
-
- private:
-  void BindCall(Call* call) GRPC_OVERRIDE { call_ = *call; }
-
-  Call call_;
-  ServerContext* ctx_;
-  CallOpSet<CallOpSendInitialMetadata> meta_ops_;
-  CallOpSet<CallOpSendInitialMetadata, CallOpSendMessage> write_ops_;
-  CallOpSet<CallOpSendInitialMetadata, CallOpServerSendStatus> finish_ops_;
-};
-
-/// Server-side interface for asynchronous bi-directional streaming.
-template <class W, class R>
-class ServerAsyncReaderWriter GRPC_FINAL : public ServerAsyncStreamingInterface,
-                                           public AsyncWriterInterface<W>,
-                                           public AsyncReaderInterface<R> {
- public:
-  explicit ServerAsyncReaderWriter(ServerContext* ctx)
-      : call_(nullptr, nullptr, nullptr), ctx_(ctx) {}
-
-  void SendInitialMetadata(void* tag) GRPC_OVERRIDE {
-    GPR_ASSERT(!ctx_->sent_initial_metadata_);
-
-    meta_ops_.set_output_tag(tag);
-    meta_ops_.SendInitialMetadata(ctx_->initial_metadata_);
-    ctx_->sent_initial_metadata_ = true;
-    call_.PerformOps(&meta_ops_);
-  }
-
-  void Read(R* msg, void* tag) GRPC_OVERRIDE {
-    read_ops_.set_output_tag(tag);
-    read_ops_.RecvMessage(msg);
-    call_.PerformOps(&read_ops_);
-  }
-
-  void Write(const W& msg, void* tag) GRPC_OVERRIDE {
-    write_ops_.set_output_tag(tag);
-    if (!ctx_->sent_initial_metadata_) {
-      write_ops_.SendInitialMetadata(ctx_->initial_metadata_);
-      ctx_->sent_initial_metadata_ = true;
-    }
-    // TODO(ctiller): don't assert
-    GPR_ASSERT(write_ops_.SendMessage(msg).ok());
-    call_.PerformOps(&write_ops_);
-  }
-
-  void Finish(const Status& status, void* tag) {
-    finish_ops_.set_output_tag(tag);
-    if (!ctx_->sent_initial_metadata_) {
-      finish_ops_.SendInitialMetadata(ctx_->initial_metadata_);
-      ctx_->sent_initial_metadata_ = true;
-    }
-    finish_ops_.ServerSendStatus(ctx_->trailing_metadata_, status);
-    call_.PerformOps(&finish_ops_);
-  }
-
- private:
-  friend class ::grpc::Server;
-
-  void BindCall(Call* call) GRPC_OVERRIDE { call_ = *call; }
-
-  Call call_;
-  ServerContext* ctx_;
-  CallOpSet<CallOpSendInitialMetadata> meta_ops_;
-  CallOpSet<CallOpRecvMessage<R>> read_ops_;
-  CallOpSet<CallOpSendInitialMetadata, CallOpSendMessage> write_ops_;
-  CallOpSet<CallOpSendInitialMetadata, CallOpServerSendStatus> finish_ops_;
-};
-
-}  // namespace grpc
+#include <grpc++/impl/codegen/async_stream.h>
 
 #endif  // GRPCXX_SUPPORT_ASYNC_STREAM_H
diff --git a/include/grpc++/support/async_unary_call.h b/include/grpc++/support/async_unary_call.h
index 0f4ad26..6d74328 100644
--- a/include/grpc++/support/async_unary_call.h
+++ b/include/grpc++/support/async_unary_call.h
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -34,122 +34,6 @@
 #ifndef GRPCXX_SUPPORT_ASYNC_UNARY_CALL_H
 #define GRPCXX_SUPPORT_ASYNC_UNARY_CALL_H
 
-#include <grpc/support/log.h>
-#include <grpc++/channel.h>
-#include <grpc++/client_context.h>
-#include <grpc++/completion_queue.h>
-#include <grpc++/server_context.h>
-#include <grpc++/impl/call.h>
-#include <grpc++/impl/service_type.h>
-#include <grpc++/support/status.h>
-
-namespace grpc {
-
-template <class R>
-class ClientAsyncResponseReaderInterface {
- public:
-  virtual ~ClientAsyncResponseReaderInterface() {}
-  virtual void ReadInitialMetadata(void* tag) = 0;
-  virtual void Finish(R* msg, Status* status, void* tag) = 0;
-};
-
-template <class R>
-class ClientAsyncResponseReader GRPC_FINAL
-    : public ClientAsyncResponseReaderInterface<R> {
- public:
-  template <class W>
-  ClientAsyncResponseReader(Channel* channel, CompletionQueue* cq,
-                            const RpcMethod& method, ClientContext* context,
-                            const W& request)
-      : context_(context), call_(channel->CreateCall(method, context, cq)) {
-    init_buf_.SendInitialMetadata(context->send_initial_metadata_);
-    // TODO(ctiller): don't assert
-    GPR_ASSERT(init_buf_.SendMessage(request).ok());
-    init_buf_.ClientSendClose();
-    call_.PerformOps(&init_buf_);
-  }
-
-  void ReadInitialMetadata(void* tag) {
-    GPR_ASSERT(!context_->initial_metadata_received_);
-
-    meta_buf_.set_output_tag(tag);
-    meta_buf_.RecvInitialMetadata(context_);
-    call_.PerformOps(&meta_buf_);
-  }
-
-  void Finish(R* msg, Status* status, void* tag) {
-    finish_buf_.set_output_tag(tag);
-    if (!context_->initial_metadata_received_) {
-      finish_buf_.RecvInitialMetadata(context_);
-    }
-    finish_buf_.RecvMessage(msg);
-    finish_buf_.ClientRecvStatus(context_, status);
-    call_.PerformOps(&finish_buf_);
-  }
-
- private:
-  ClientContext* context_;
-  Call call_;
-  SneakyCallOpSet<CallOpSendInitialMetadata, CallOpSendMessage,
-                  CallOpClientSendClose> init_buf_;
-  CallOpSet<CallOpRecvInitialMetadata> meta_buf_;
-  CallOpSet<CallOpRecvInitialMetadata, CallOpRecvMessage<R>,
-            CallOpClientRecvStatus> finish_buf_;
-};
-
-template <class W>
-class ServerAsyncResponseWriter GRPC_FINAL
-    : public ServerAsyncStreamingInterface {
- public:
-  explicit ServerAsyncResponseWriter(ServerContext* ctx)
-      : call_(nullptr, nullptr, nullptr), ctx_(ctx) {}
-
-  void SendInitialMetadata(void* tag) GRPC_OVERRIDE {
-    GPR_ASSERT(!ctx_->sent_initial_metadata_);
-
-    meta_buf_.set_output_tag(tag);
-    meta_buf_.SendInitialMetadata(ctx_->initial_metadata_);
-    ctx_->sent_initial_metadata_ = true;
-    call_.PerformOps(&meta_buf_);
-  }
-
-  void Finish(const W& msg, const Status& status, void* tag) {
-    finish_buf_.set_output_tag(tag);
-    if (!ctx_->sent_initial_metadata_) {
-      finish_buf_.SendInitialMetadata(ctx_->initial_metadata_);
-      ctx_->sent_initial_metadata_ = true;
-    }
-    // The response is dropped if the status is not OK.
-    if (status.ok()) {
-      finish_buf_.ServerSendStatus(ctx_->trailing_metadata_,
-                                   finish_buf_.SendMessage(msg));
-    } else {
-      finish_buf_.ServerSendStatus(ctx_->trailing_metadata_, status);
-    }
-    call_.PerformOps(&finish_buf_);
-  }
-
-  void FinishWithError(const Status& status, void* tag) {
-    GPR_ASSERT(!status.ok());
-    finish_buf_.set_output_tag(tag);
-    if (!ctx_->sent_initial_metadata_) {
-      finish_buf_.SendInitialMetadata(ctx_->initial_metadata_);
-      ctx_->sent_initial_metadata_ = true;
-    }
-    finish_buf_.ServerSendStatus(ctx_->trailing_metadata_, status);
-    call_.PerformOps(&finish_buf_);
-  }
-
- private:
-  void BindCall(Call* call) GRPC_OVERRIDE { call_ = *call; }
-
-  Call call_;
-  ServerContext* ctx_;
-  CallOpSet<CallOpSendInitialMetadata> meta_buf_;
-  CallOpSet<CallOpSendInitialMetadata, CallOpSendMessage,
-            CallOpServerSendStatus> finish_buf_;
-};
-
-}  // namespace grpc
+#include <grpc++/impl/codegen/async_unary_call.h>
 
 #endif  // GRPCXX_SUPPORT_ASYNC_UNARY_CALL_H
diff --git a/include/grpc++/support/config.h b/include/grpc++/support/config.h
index 836bd47..be8c89c 100644
--- a/include/grpc++/support/config.h
+++ b/include/grpc++/support/config.h
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -34,83 +34,6 @@
 #ifndef GRPCXX_SUPPORT_CONFIG_H
 #define GRPCXX_SUPPORT_CONFIG_H
 
-#if !defined(GRPC_NO_AUTODETECT_PLATFORM)
-
-#ifdef _MSC_VER
-// Visual Studio 2010 is 1600.
-#if _MSC_VER < 1600
-#error "gRPC is only supported with Visual Studio starting at 2010"
-// Visual Studio 2013 is 1800.
-#elif _MSC_VER < 1800
-#define GRPC_CXX0X_NO_FINAL 1
-#define GRPC_CXX0X_NO_OVERRIDE 1
-#define GRPC_CXX0X_NO_CHRONO 1
-#define GRPC_CXX0X_NO_THREAD 1
-#endif
-#endif  // Visual Studio
-
-#ifndef __clang__
-#ifdef __GNUC__
-// nullptr was added in gcc 4.6
-#if (__GNUC__ * 100 + __GNUC_MINOR__ < 406)
-#define GRPC_CXX0X_NO_NULLPTR 1
-#endif
-// final and override were added in gcc 4.7
-#if (__GNUC__ * 100 + __GNUC_MINOR__ < 407)
-#define GRPC_CXX0X_NO_FINAL 1
-#define GRPC_CXX0X_NO_OVERRIDE 1
-#endif
-#endif
-#endif
-
-#endif
-
-#ifdef GRPC_CXX0X_NO_FINAL
-#define GRPC_FINAL
-#else
-#define GRPC_FINAL final
-#endif
-
-#ifdef GRPC_CXX0X_NO_OVERRIDE
-#define GRPC_OVERRIDE
-#else
-#define GRPC_OVERRIDE override
-#endif
-
-#ifdef GRPC_CXX0X_NO_NULLPTR
-#include <memory>
-namespace grpc {
-const class {
- public:
-  template <class T>
-  operator T *() const {
-    return static_cast<T *>(0);
-  }
-  template <class T>
-  operator std::unique_ptr<T>() const {
-    return std::unique_ptr<T>(static_cast<T *>(0));
-  }
-  template <class T>
-  operator std::shared_ptr<T>() const {
-    return std::shared_ptr<T>(static_cast<T *>(0));
-  }
-  operator bool() const { return false; }
-
- private:
-  void operator&() const = delete;
-} nullptr = {};
-}
-#endif
-
-#ifndef GRPC_CUSTOM_STRING
-#include <string>
-#define GRPC_CUSTOM_STRING std::string
-#endif
-
-namespace grpc {
-
-typedef GRPC_CUSTOM_STRING string;
-
-}  // namespace grpc
+#include <grpc++/impl/codegen/config.h>
 
 #endif  // GRPCXX_SUPPORT_CONFIG_H
diff --git a/include/grpc++/support/config_protobuf.h b/include/grpc++/support/config_protobuf.h
index 8235590..0b466e8 100644
--- a/include/grpc++/support/config_protobuf.h
+++ b/include/grpc++/support/config_protobuf.h
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -34,39 +34,6 @@
 #ifndef GRPCXX_SUPPORT_CONFIG_PROTOBUF_H
 #define GRPCXX_SUPPORT_CONFIG_PROTOBUF_H
 
-#ifndef GRPC_CUSTOM_PROTOBUF_INT64
-#include <google/protobuf/stubs/common.h>
-#define GRPC_CUSTOM_PROTOBUF_INT64 ::google::protobuf::int64
-#endif
-
-#ifndef GRPC_CUSTOM_MESSAGE
-#include <google/protobuf/message.h>
-#define GRPC_CUSTOM_MESSAGE ::google::protobuf::Message
-#endif
-
-#ifndef GRPC_CUSTOM_ZEROCOPYOUTPUTSTREAM
-#include <google/protobuf/io/coded_stream.h>
-#include <google/protobuf/io/zero_copy_stream.h>
-#define GRPC_CUSTOM_ZEROCOPYOUTPUTSTREAM \
-  ::google::protobuf::io::ZeroCopyOutputStream
-#define GRPC_CUSTOM_ZEROCOPYINPUTSTREAM \
-  ::google::protobuf::io::ZeroCopyInputStream
-#define GRPC_CUSTOM_CODEDINPUTSTREAM ::google::protobuf::io::CodedInputStream
-#endif
-
-namespace grpc {
-namespace protobuf {
-
-typedef GRPC_CUSTOM_MESSAGE Message;
-typedef GRPC_CUSTOM_PROTOBUF_INT64 int64;
-
-namespace io {
-typedef GRPC_CUSTOM_ZEROCOPYOUTPUTSTREAM ZeroCopyOutputStream;
-typedef GRPC_CUSTOM_ZEROCOPYINPUTSTREAM ZeroCopyInputStream;
-typedef GRPC_CUSTOM_CODEDINPUTSTREAM CodedInputStream;
-}  // namespace io
-
-}  // namespace protobuf
-}  // namespace grpc
+#include <grpc++/impl/codegen/config_protobuf.h>
 
 #endif  // GRPCXX_SUPPORT_CONFIG_PROTOBUF_H
diff --git a/include/grpc++/support/status.h b/include/grpc++/support/status.h
index e59bac9..a33fbed 100644
--- a/include/grpc++/support/status.h
+++ b/include/grpc++/support/status.h
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -34,43 +34,6 @@
 #ifndef GRPCXX_SUPPORT_STATUS_H
 #define GRPCXX_SUPPORT_STATUS_H
 
-#include <grpc++/support/config.h>
-#include <grpc++/support/status_code_enum.h>
-
-namespace grpc {
-
-/// Did it work? If it didn't, why?
-///
-/// See \a grpc::StatusCode for details on the available code and their meaning.
-class Status {
- public:
-  /// 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) {}
-
-  // Pre-defined special status objects.
-  /// An OK pre-defined instance.
-  static const Status& OK;
-  /// A CANCELLED pre-defined instance.
-  static const Status& CANCELLED;
-
-  /// 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_; }
-
-  /// Is the status OK?
-  bool ok() const { return code_ == StatusCode::OK; }
-
- private:
-  StatusCode code_;
-  grpc::string details_;
-};
-
-}  // namespace grpc
+#include <grpc++/impl/codegen/status.h>
 
 #endif  // GRPCXX_SUPPORT_STATUS_H
diff --git a/include/grpc++/support/status_code_enum.h b/include/grpc++/support/status_code_enum.h
index ee05b40..21b9c40 100644
--- a/include/grpc++/support/status_code_enum.h
+++ b/include/grpc++/support/status_code_enum.h
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -34,119 +34,6 @@
 #ifndef GRPCXX_SUPPORT_STATUS_CODE_ENUM_H
 #define GRPCXX_SUPPORT_STATUS_CODE_ENUM_H
 
-namespace grpc {
-
-enum StatusCode {
-  /// Not an error; returned on success.
-  OK = 0,
-
-  /// The operation was cancelled (typically by the caller).
-  CANCELLED = 1,
-
-  /// Unknown error. An example of where this error may be returned is if a
-  /// Status value received from another address space belongs to an error-space
-  /// that is not known in this address space. Also errors raised by APIs that
-  /// do not return enough error information may be converted to this error.
-  UNKNOWN = 2,
-
-  /// Client specified an invalid argument. Note that this differs from
-  /// FAILED_PRECONDITION. INVALID_ARGUMENT indicates arguments that are
-  /// problematic regardless of the state of the system (e.g., a malformed file
-  /// name).
-  INVALID_ARGUMENT = 3,
-
-  /// Deadline expired before operation could complete. For operations that
-  /// change the state of the system, this error may be returned even if the
-  /// operation has completed successfully. For example, a successful response
-  /// from a server could have been delayed long enough for the deadline to
-  /// expire.
-  DEADLINE_EXCEEDED = 4,
-
-  /// Some requested entity (e.g., file or directory) was not found.
-  NOT_FOUND = 5,
-
-  /// Some entity that we attempted to create (e.g., file or directory) already
-  /// exists.
-  ALREADY_EXISTS = 6,
-
-  /// The caller does not have permission to execute the specified operation.
-  /// PERMISSION_DENIED must not be used for rejections caused by exhausting
-  /// some resource (use RESOURCE_EXHAUSTED instead for those errors).
-  /// PERMISSION_DENIED must not be used if the caller can not be identified
-  /// (use UNAUTHENTICATED instead for those errors).
-  PERMISSION_DENIED = 7,
-
-  /// The request does not have valid authentication credentials for the
-  /// operation.
-  UNAUTHENTICATED = 16,
-
-  /// Some resource has been exhausted, perhaps a per-user quota, or perhaps the
-  /// entire file system is out of space.
-  RESOURCE_EXHAUSTED = 8,
-
-  /// Operation was rejected because the system is not in a state required for
-  /// the operation's execution. For example, directory to be deleted may be
-  /// non-empty, an rmdir operation is applied to a non-directory, etc.
-  ///
-  /// A litmus test that may help a service implementor in deciding
-  /// between FAILED_PRECONDITION, ABORTED, and UNAVAILABLE:
-  ///  (a) Use UNAVAILABLE if the client can retry just the failing call.
-  ///  (b) Use ABORTED if the client should retry at a higher-level
-  ///      (e.g., restarting a read-modify-write sequence).
-  ///  (c) Use FAILED_PRECONDITION if the client should not retry until
-  ///      the system state has been explicitly fixed. E.g., if an "rmdir"
-  ///      fails because the directory is non-empty, FAILED_PRECONDITION
-  ///      should be returned since the client should not retry unless
-  ///      they have first fixed up the directory by deleting files from it.
-  ///  (d) Use FAILED_PRECONDITION if the client performs conditional
-  ///      REST Get/Update/Delete on a resource and the resource on the
-  ///      server does not match the condition. E.g., conflicting
-  ///      read-modify-write on the same resource.
-  FAILED_PRECONDITION = 9,
-
-  /// The operation was aborted, typically due to a concurrency issue like
-  /// sequencer check failures, transaction aborts, etc.
-  ///
-  /// See litmus test above for deciding between FAILED_PRECONDITION, ABORTED,
-  /// and UNAVAILABLE.
-  ABORTED = 10,
-
-  /// Operation was attempted past the valid range. E.g., seeking or reading
-  /// past end of file.
-  ///
-  /// Unlike INVALID_ARGUMENT, this error indicates a problem that may be fixed
-  /// if the system state changes. For example, a 32-bit file system will
-  /// generate INVALID_ARGUMENT if asked to read at an offset that is not in the
-  /// range [0,2^32-1], but it will generate OUT_OF_RANGE if asked to read from
-  /// an offset past the current file size.
-  ///
-  /// There is a fair bit of overlap between FAILED_PRECONDITION and
-  /// OUT_OF_RANGE. We recommend using OUT_OF_RANGE (the more specific error)
-  /// when it applies so that callers who are iterating through a space can
-  /// easily look for an OUT_OF_RANGE error to detect when they are done.
-  OUT_OF_RANGE = 11,
-
-  /// Operation is not implemented or not supported/enabled in this service.
-  UNIMPLEMENTED = 12,
-
-  /// Internal errors. Means some invariants expected by underlying System has
-  /// been broken. If you see one of these errors, Something is very broken.
-  INTERNAL = 13,
-
-  /// The service is currently unavailable. This is a most likely a transient
-  /// condition and may be corrected by retrying with a backoff.
-  ///
-  /// See litmus test above for deciding between FAILED_PRECONDITION, ABORTED,
-  /// and UNAVAILABLE.
-  UNAVAILABLE = 14,
-
-  /// Unrecoverable data loss or corruption.
-  DATA_LOSS = 15,
-
-  /// Force users to include a default branch:
-  DO_NOT_USE = -1
-};
-
-}  // namespace grpc
+#include <grpc++/impl/codegen/status_code_enum.h>
 
 #endif  // GRPCXX_SUPPORT_STATUS_CODE_ENUM_H
diff --git a/include/grpc++/support/string_ref.h b/include/grpc++/support/string_ref.h
index 9d96526..195e5c8 100644
--- a/include/grpc++/support/string_ref.h
+++ b/include/grpc++/support/string_ref.h
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -34,90 +34,6 @@
 #ifndef GRPCXX_SUPPORT_STRING_REF_H
 #define GRPCXX_SUPPORT_STRING_REF_H
 
-#include <iterator>
-#include <iosfwd>
-
-#include <grpc++/support/config.h>
-
-namespace grpc {
-
-/// This class is a non owning reference to a string.
-///
-/// It should be a strict subset of the upcoming std::string_ref.
-///
-/// \see http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3442.html
-///
-/// The constexpr is dropped or replaced with const for legacy compiler
-/// compatibility.
-class string_ref {
- public:
-  // types
-  typedef const char* const_iterator;
-  typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
-
-  // constants
-  const static size_t npos;
-
-  // construct/copy.
-  string_ref() : data_(nullptr), length_(0) {}
-  string_ref(const string_ref& other)
-      : data_(other.data_), length_(other.length_) {}
-  string_ref& operator=(const string_ref& rhs);
-  string_ref(const char* s);
-  string_ref(const char* s, size_t l) : data_(s), length_(l) {}
-  string_ref(const grpc::string& s) : data_(s.data()), length_(s.length()) {}
-
-  // iterators
-  const_iterator begin() const { return data_; }
-  const_iterator end() const { return data_ + length_; }
-  const_iterator cbegin() const { return data_; }
-  const_iterator cend() const { return data_ + length_; }
-  const_reverse_iterator rbegin() const {
-    return const_reverse_iterator(end());
-  }
-  const_reverse_iterator rend() const {
-    return const_reverse_iterator(begin());
-  }
-  const_reverse_iterator crbegin() const {
-    return const_reverse_iterator(end());
-  }
-  const_reverse_iterator crend() const {
-    return const_reverse_iterator(begin());
-  }
-
-  // capacity
-  size_t size() const { return length_; }
-  size_t length() const { return length_; }
-  size_t max_size() const { return length_; }
-  bool empty() const { return length_ == 0; }
-
-  // element access
-  const char* data() const { return data_; }
-
-  // string operations
-  int compare(string_ref x) const;
-  bool starts_with(string_ref x) const;
-  bool ends_with(string_ref x) const;
-  size_t find(string_ref s) const;
-  size_t find(char c) const;
-
-  string_ref substr(size_t pos, size_t n = npos) const;
-
- private:
-  const char* data_;
-  size_t length_;
-};
-
-// Comparison operators
-bool operator==(string_ref x, string_ref y);
-bool operator!=(string_ref x, string_ref y);
-bool operator<(string_ref x, string_ref y);
-bool operator>(string_ref x, string_ref y);
-bool operator<=(string_ref x, string_ref y);
-bool operator>=(string_ref x, string_ref y);
-
-std::ostream& operator<<(std::ostream& stream, const string_ref& string);
-
-}  // namespace grpc
+#include <grpc++/impl/codegen/string_ref.h>
 
 #endif  // GRPCXX_SUPPORT_STRING_REF_H
diff --git a/include/grpc++/support/stub_options.h b/include/grpc++/support/stub_options.h
index 973aa9b..f8f4c87 100644
--- a/include/grpc++/support/stub_options.h
+++ b/include/grpc++/support/stub_options.h
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -34,10 +34,6 @@
 #ifndef GRPCXX_SUPPORT_STUB_OPTIONS_H
 #define GRPCXX_SUPPORT_STUB_OPTIONS_H
 
-namespace grpc {
-
-class StubOptions {};
-
-}  // namespace grpc
+#include <grpc++/impl/codegen/stub_options.h>
 
 #endif  // GRPCXX_SUPPORT_STUB_OPTIONS_H
diff --git a/include/grpc++/support/sync_stream.h b/include/grpc++/support/sync_stream.h
index daf4e36..2ea2ac5 100644
--- a/include/grpc++/support/sync_stream.h
+++ b/include/grpc++/support/sync_stream.h
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -34,382 +34,6 @@
 #ifndef GRPCXX_SUPPORT_SYNC_STREAM_H
 #define GRPCXX_SUPPORT_SYNC_STREAM_H
 
-#include <grpc/support/log.h>
-#include <grpc++/channel.h>
-#include <grpc++/client_context.h>
-#include <grpc++/completion_queue.h>
-#include <grpc++/impl/call.h>
-#include <grpc++/impl/service_type.h>
-#include <grpc++/server_context.h>
-#include <grpc++/support/status.h>
-
-namespace grpc {
-
-/// Common interface for all synchronous client side streaming.
-class ClientStreamingInterface {
- public:
-  virtual ~ClientStreamingInterface() {}
-
-  /// Wait until the stream finishes, and return the final status. When the
-  /// client side declares it has no more message to send, either implicitly or
-  /// by calling \a WritesDone(), it needs to make sure there is no more message
-  /// to be received from the server, either implicitly or by getting a false
-  /// from a \a Read().
-  ///
-  /// This function will return either:
-  /// - when all incoming messages have been read and the server has returned
-  ///   status.
-  /// - OR when the server has returned a non-OK status.
-  virtual Status Finish() = 0;
-};
-
-/// An interface that yields a sequence of messages of type \a R.
-template <class R>
-class ReaderInterface {
- public:
-  virtual ~ReaderInterface() {}
-
-  /// Blocking read a message and parse to \a msg. Returns \a true on success.
-  ///
-  /// \param[out] msg The read message.
-  ///
-  /// \return \a false when there will be no more incoming messages, either
-  /// because the other side has called \a WritesDone() or the stream has failed
-  /// (or been cancelled).
-  virtual bool Read(R* msg) = 0;
-};
-
-/// An interface that can be fed a sequence of messages of type \a W.
-template <class W>
-class WriterInterface {
- public:
-  virtual ~WriterInterface() {}
-
-  /// Blocking write \a msg to the stream with options.
-  ///
-  /// \param msg The message to be written to the stream.
-  /// \param options Options affecting the write operation.
-  ///
-  /// \return \a true on success, \a false when the stream has been closed.
-  virtual bool Write(const W& msg, const WriteOptions& options) = 0;
-
-  /// Blocking write \a msg to the stream with default options.
-  ///
-  /// \param msg The message to be written to the stream.
-  ///
-  /// \return \a true on success, \a false when the stream has been closed.
-  inline bool Write(const W& msg) { return Write(msg, WriteOptions()); }
-};
-
-/// Client-side interface for streaming reads of message of type \a R.
-template <class R>
-class ClientReaderInterface : public ClientStreamingInterface,
-                              public ReaderInterface<R> {
- public:
-  /// Blocking wait for initial metadata from server. The received metadata
-  /// can only be accessed after this call returns. Should only be called before
-  /// the first read. Calling this method is optional, and if it is not called
-  /// the metadata will be available in ClientContext after the first read.
-  virtual void WaitForInitialMetadata() = 0;
-};
-
-template <class R>
-class ClientReader GRPC_FINAL : public ClientReaderInterface<R> {
- public:
-  /// Blocking create a stream and write the first request out.
-  template <class W>
-  ClientReader(Channel* channel, const RpcMethod& method,
-               ClientContext* context, const W& request)
-      : context_(context), call_(channel->CreateCall(method, context, &cq_)) {
-    CallOpSet<CallOpSendInitialMetadata, CallOpSendMessage,
-              CallOpClientSendClose> ops;
-    ops.SendInitialMetadata(context->send_initial_metadata_);
-    // TODO(ctiller): don't assert
-    GPR_ASSERT(ops.SendMessage(request).ok());
-    ops.ClientSendClose();
-    call_.PerformOps(&ops);
-    cq_.Pluck(&ops);
-  }
-
-  void WaitForInitialMetadata() GRPC_OVERRIDE {
-    GPR_ASSERT(!context_->initial_metadata_received_);
-
-    CallOpSet<CallOpRecvInitialMetadata> ops;
-    ops.RecvInitialMetadata(context_);
-    call_.PerformOps(&ops);
-    cq_.Pluck(&ops);  /// status ignored
-  }
-
-  bool Read(R* msg) GRPC_OVERRIDE {
-    CallOpSet<CallOpRecvInitialMetadata, CallOpRecvMessage<R>> ops;
-    if (!context_->initial_metadata_received_) {
-      ops.RecvInitialMetadata(context_);
-    }
-    ops.RecvMessage(msg);
-    call_.PerformOps(&ops);
-    return cq_.Pluck(&ops) && ops.got_message;
-  }
-
-  Status Finish() GRPC_OVERRIDE {
-    CallOpSet<CallOpClientRecvStatus> ops;
-    Status status;
-    ops.ClientRecvStatus(context_, &status);
-    call_.PerformOps(&ops);
-    GPR_ASSERT(cq_.Pluck(&ops));
-    return status;
-  }
-
- private:
-  ClientContext* context_;
-  CompletionQueue cq_;
-  Call call_;
-};
-
-/// Client-side interface for streaming writes of message of type \a W.
-template <class W>
-class ClientWriterInterface : public ClientStreamingInterface,
-                              public WriterInterface<W> {
- public:
-  /// Half close writing from the client.
-  /// Block until writes are completed.
-  ///
-  /// \return Whether the writes were successful.
-  virtual bool WritesDone() = 0;
-};
-
-template <class W>
-class ClientWriter : public ClientWriterInterface<W> {
- public:
-  /// Blocking create a stream.
-  template <class R>
-  ClientWriter(Channel* channel, const RpcMethod& method,
-               ClientContext* context, R* response)
-      : context_(context), call_(channel->CreateCall(method, context, &cq_)) {
-    finish_ops_.RecvMessage(response);
-
-    CallOpSet<CallOpSendInitialMetadata> ops;
-    ops.SendInitialMetadata(context->send_initial_metadata_);
-    call_.PerformOps(&ops);
-    cq_.Pluck(&ops);
-  }
-
-  using WriterInterface<W>::Write;
-  bool Write(const W& msg, const WriteOptions& options) GRPC_OVERRIDE {
-    CallOpSet<CallOpSendMessage> ops;
-    if (!ops.SendMessage(msg, options).ok()) {
-      return false;
-    }
-    call_.PerformOps(&ops);
-    return cq_.Pluck(&ops);
-  }
-
-  bool WritesDone() GRPC_OVERRIDE {
-    CallOpSet<CallOpClientSendClose> ops;
-    ops.ClientSendClose();
-    call_.PerformOps(&ops);
-    return cq_.Pluck(&ops);
-  }
-
-  /// Read the final response and wait for the final status.
-  Status Finish() GRPC_OVERRIDE {
-    Status status;
-    finish_ops_.ClientRecvStatus(context_, &status);
-    call_.PerformOps(&finish_ops_);
-    GPR_ASSERT(cq_.Pluck(&finish_ops_));
-    return status;
-  }
-
- private:
-  ClientContext* context_;
-  CallOpSet<CallOpGenericRecvMessage, CallOpClientRecvStatus> finish_ops_;
-  CompletionQueue cq_;
-  Call call_;
-};
-
-/// Client-side interface for bi-directional streaming.
-template <class W, class R>
-class ClientReaderWriterInterface : public ClientStreamingInterface,
-                                    public WriterInterface<W>,
-                                    public ReaderInterface<R> {
- public:
-  /// Blocking wait for initial metadata from server. The received metadata
-  /// can only be accessed after this call returns. Should only be called before
-  /// the first read. Calling this method is optional, and if it is not called
-  /// the metadata will be available in ClientContext after the first read.
-  virtual void WaitForInitialMetadata() = 0;
-
-  /// Block until writes are completed.
-  ///
-  /// \return Whether the writes were successful.
-  virtual bool WritesDone() = 0;
-};
-
-template <class W, class R>
-class ClientReaderWriter GRPC_FINAL : public ClientReaderWriterInterface<W, R> {
- public:
-  /// Blocking create a stream.
-  ClientReaderWriter(Channel* channel, const RpcMethod& method,
-                     ClientContext* context)
-      : context_(context), call_(channel->CreateCall(method, context, &cq_)) {
-    CallOpSet<CallOpSendInitialMetadata> ops;
-    ops.SendInitialMetadata(context->send_initial_metadata_);
-    call_.PerformOps(&ops);
-    cq_.Pluck(&ops);
-  }
-
-  void WaitForInitialMetadata() GRPC_OVERRIDE {
-    GPR_ASSERT(!context_->initial_metadata_received_);
-
-    CallOpSet<CallOpRecvInitialMetadata> ops;
-    ops.RecvInitialMetadata(context_);
-    call_.PerformOps(&ops);
-    cq_.Pluck(&ops);  // status ignored
-  }
-
-  bool Read(R* msg) GRPC_OVERRIDE {
-    CallOpSet<CallOpRecvInitialMetadata, CallOpRecvMessage<R>> ops;
-    if (!context_->initial_metadata_received_) {
-      ops.RecvInitialMetadata(context_);
-    }
-    ops.RecvMessage(msg);
-    call_.PerformOps(&ops);
-    return cq_.Pluck(&ops) && ops.got_message;
-  }
-
-  using WriterInterface<W>::Write;
-  bool Write(const W& msg, const WriteOptions& options) GRPC_OVERRIDE {
-    CallOpSet<CallOpSendMessage> ops;
-    if (!ops.SendMessage(msg, options).ok()) return false;
-    call_.PerformOps(&ops);
-    return cq_.Pluck(&ops);
-  }
-
-  bool WritesDone() GRPC_OVERRIDE {
-    CallOpSet<CallOpClientSendClose> ops;
-    ops.ClientSendClose();
-    call_.PerformOps(&ops);
-    return cq_.Pluck(&ops);
-  }
-
-  Status Finish() GRPC_OVERRIDE {
-    CallOpSet<CallOpClientRecvStatus> ops;
-    Status status;
-    ops.ClientRecvStatus(context_, &status);
-    call_.PerformOps(&ops);
-    GPR_ASSERT(cq_.Pluck(&ops));
-    return status;
-  }
-
- private:
-  ClientContext* context_;
-  CompletionQueue cq_;
-  Call call_;
-};
-
-template <class R>
-class ServerReader GRPC_FINAL : public ReaderInterface<R> {
- public:
-  ServerReader(Call* call, ServerContext* ctx) : call_(call), ctx_(ctx) {}
-
-  void SendInitialMetadata() {
-    GPR_ASSERT(!ctx_->sent_initial_metadata_);
-
-    CallOpSet<CallOpSendInitialMetadata> ops;
-    ops.SendInitialMetadata(ctx_->initial_metadata_);
-    ctx_->sent_initial_metadata_ = true;
-    call_->PerformOps(&ops);
-    call_->cq()->Pluck(&ops);
-  }
-
-  bool Read(R* msg) GRPC_OVERRIDE {
-    CallOpSet<CallOpRecvMessage<R>> ops;
-    ops.RecvMessage(msg);
-    call_->PerformOps(&ops);
-    return call_->cq()->Pluck(&ops) && ops.got_message;
-  }
-
- private:
-  Call* const call_;
-  ServerContext* const ctx_;
-};
-
-template <class W>
-class ServerWriter GRPC_FINAL : public WriterInterface<W> {
- public:
-  ServerWriter(Call* call, ServerContext* ctx) : call_(call), ctx_(ctx) {}
-
-  void SendInitialMetadata() {
-    GPR_ASSERT(!ctx_->sent_initial_metadata_);
-
-    CallOpSet<CallOpSendInitialMetadata> ops;
-    ops.SendInitialMetadata(ctx_->initial_metadata_);
-    ctx_->sent_initial_metadata_ = true;
-    call_->PerformOps(&ops);
-    call_->cq()->Pluck(&ops);
-  }
-
-  using WriterInterface<W>::Write;
-  bool Write(const W& msg, const WriteOptions& options) GRPC_OVERRIDE {
-    CallOpSet<CallOpSendInitialMetadata, CallOpSendMessage> ops;
-    if (!ops.SendMessage(msg, options).ok()) {
-      return false;
-    }
-    if (!ctx_->sent_initial_metadata_) {
-      ops.SendInitialMetadata(ctx_->initial_metadata_);
-      ctx_->sent_initial_metadata_ = true;
-    }
-    call_->PerformOps(&ops);
-    return call_->cq()->Pluck(&ops);
-  }
-
- private:
-  Call* const call_;
-  ServerContext* const ctx_;
-};
-
-/// Server-side interface for bi-directional streaming.
-template <class W, class R>
-class ServerReaderWriter GRPC_FINAL : public WriterInterface<W>,
-                                      public ReaderInterface<R> {
- public:
-  ServerReaderWriter(Call* call, ServerContext* ctx) : call_(call), ctx_(ctx) {}
-
-  void SendInitialMetadata() {
-    GPR_ASSERT(!ctx_->sent_initial_metadata_);
-
-    CallOpSet<CallOpSendInitialMetadata> ops;
-    ops.SendInitialMetadata(ctx_->initial_metadata_);
-    ctx_->sent_initial_metadata_ = true;
-    call_->PerformOps(&ops);
-    call_->cq()->Pluck(&ops);
-  }
-
-  bool Read(R* msg) GRPC_OVERRIDE {
-    CallOpSet<CallOpRecvMessage<R>> ops;
-    ops.RecvMessage(msg);
-    call_->PerformOps(&ops);
-    return call_->cq()->Pluck(&ops) && ops.got_message;
-  }
-
-  using WriterInterface<W>::Write;
-  bool Write(const W& msg, const WriteOptions& options) GRPC_OVERRIDE {
-    CallOpSet<CallOpSendInitialMetadata, CallOpSendMessage> ops;
-    if (!ops.SendMessage(msg, options).ok()) {
-      return false;
-    }
-    if (!ctx_->sent_initial_metadata_) {
-      ops.SendInitialMetadata(ctx_->initial_metadata_);
-      ctx_->sent_initial_metadata_ = true;
-    }
-    call_->PerformOps(&ops);
-    return call_->cq()->Pluck(&ops);
-  }
-
- private:
-  Call* const call_;
-  ServerContext* const ctx_;
-};
-
-}  // namespace grpc
+#include <grpc++/impl/codegen/sync_stream.h>
 
 #endif  // GRPCXX_SUPPORT_SYNC_STREAM_H
diff --git a/include/grpc++/support/time.h b/include/grpc++/support/time.h
index e00e0d8..f0b758f 100644
--- a/include/grpc++/support/time.h
+++ b/include/grpc++/support/time.h
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -34,78 +34,6 @@
 #ifndef GRPCXX_SUPPORT_TIME_H
 #define GRPCXX_SUPPORT_TIME_H
 
-#include <grpc++/support/config.h>
-#include <grpc/support/time.h>
-
-namespace grpc {
-
-/* If you are trying to use CompletionQueue::AsyncNext with a time class that
-   isn't either gpr_timespec or std::chrono::system_clock::time_point, you
-   will most likely be looking at this comment as your compiler will have
-   fired an error below. In order to fix this issue, you have two potential
-   solutions:
-
-     1. Use gpr_timespec or std::chrono::system_clock::time_point instead
-     2. Specialize the TimePoint class with whichever time class that you
-        want to use here. See below for two examples of how to do this.
- */
-
-template <typename T>
-class TimePoint {
- public:
-  TimePoint(const T& time) { you_need_a_specialization_of_TimePoint(); }
-  gpr_timespec raw_time() {
-    gpr_timespec t;
-    return t;
-  }
-
- private:
-  void you_need_a_specialization_of_TimePoint();
-};
-
-template <>
-class TimePoint<gpr_timespec> {
- public:
-  TimePoint(const gpr_timespec& time) : time_(time) {}
-  gpr_timespec raw_time() { return time_; }
-
- private:
-  gpr_timespec time_;
-};
-
-}  // namespace grpc
-
-#ifndef GRPC_CXX0X_NO_CHRONO
-
-#include <chrono>
-
-#include <grpc/support/time.h>
-
-namespace grpc {
-
-// from and to should be absolute time.
-void Timepoint2Timespec(const std::chrono::system_clock::time_point& from,
-                        gpr_timespec* to);
-void TimepointHR2Timespec(
-    const std::chrono::high_resolution_clock::time_point& from,
-    gpr_timespec* to);
-
-std::chrono::system_clock::time_point Timespec2Timepoint(gpr_timespec t);
-
-template <>
-class TimePoint<std::chrono::system_clock::time_point> {
- public:
-  TimePoint(const std::chrono::system_clock::time_point& time) {
-    Timepoint2Timespec(time, &time_);
-  }
-  gpr_timespec raw_time() const { return time_; }
-
- private:
-  gpr_timespec time_;
-};
-
-}  // namespace grpc
-
-#endif  // !GRPC_CXX0X_NO_CHRONO
+#include <grpc++/impl/codegen/time.h>
 
 #endif  // GRPCXX_SUPPORT_TIME_H
diff --git a/include/grpc/byte_buffer.h b/include/grpc/byte_buffer.h
index ffc5982..fa1fd24 100644
--- a/include/grpc/byte_buffer.h
+++ b/include/grpc/byte_buffer.h
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -34,87 +34,6 @@
 #ifndef GRPC_BYTE_BUFFER_H
 #define GRPC_BYTE_BUFFER_H
 
-#include <grpc/compression.h>
-#include <grpc/support/slice_buffer.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-typedef enum {
-  GRPC_BB_RAW
-  /* Future types may include GRPC_BB_PROTOBUF, etc. */
-} grpc_byte_buffer_type;
-
-struct grpc_byte_buffer {
-  void *reserved;
-  grpc_byte_buffer_type type;
-  union {
-    struct {
-      void *reserved[8];
-    } reserved;
-    struct {
-      grpc_compression_algorithm compression;
-      gpr_slice_buffer slice_buffer;
-    } raw;
-  } data;
-};
-typedef struct grpc_byte_buffer grpc_byte_buffer;
-
-/** Returns a RAW byte buffer instance over the given slices (up to \a nslices).
- *
- * Increases the reference count for all \a slices processed. The user is
- * responsible for invoking grpc_byte_buffer_destroy on the returned instance.*/
-grpc_byte_buffer *grpc_raw_byte_buffer_create(gpr_slice *slices,
-                                              size_t nslices);
-
-/** Returns a *compressed* RAW byte buffer instance over the given slices (up to
- * \a nslices). The \a compression argument defines the compression algorithm
- * used to generate the data in \a slices.
- *
- * Increases the reference count for all \a slices processed. The user is
- * responsible for invoking grpc_byte_buffer_destroy on the returned instance.*/
-grpc_byte_buffer *grpc_raw_compressed_byte_buffer_create(
-    gpr_slice *slices, size_t nslices, grpc_compression_algorithm compression);
-
-/** Copies input byte buffer \a bb.
- *
- * Increases the reference count of all the source slices. The user is
- * responsible for calling grpc_byte_buffer_destroy over the returned copy. */
-grpc_byte_buffer *grpc_byte_buffer_copy(grpc_byte_buffer *bb);
-
-/** Returns the size of the given byte buffer, in bytes. */
-size_t grpc_byte_buffer_length(grpc_byte_buffer *bb);
-
-/** Destroys \a byte_buffer deallocating all its memory. */
-void grpc_byte_buffer_destroy(grpc_byte_buffer *byte_buffer);
-
-/** Reader for byte buffers. Iterates over slices in the byte buffer */
-struct grpc_byte_buffer_reader;
-typedef struct grpc_byte_buffer_reader grpc_byte_buffer_reader;
-
-/** Initialize \a reader to read over \a buffer */
-void grpc_byte_buffer_reader_init(grpc_byte_buffer_reader *reader,
-                                  grpc_byte_buffer *buffer);
-
-/** Cleanup and destroy \a reader */
-void grpc_byte_buffer_reader_destroy(grpc_byte_buffer_reader *reader);
-
-/** Updates \a slice with the next piece of data from from \a reader and returns
- * 1. Returns 0 at the end of the stream. Caller is responsible for calling
- * gpr_slice_unref on the result. */
-int grpc_byte_buffer_reader_next(grpc_byte_buffer_reader *reader,
-                                 gpr_slice *slice);
-
-/** Merge all data from \a reader into single slice */
-gpr_slice grpc_byte_buffer_reader_readall(grpc_byte_buffer_reader *reader);
-
-/** Returns a RAW byte buffer instance from the output of \a reader. */
-grpc_byte_buffer *grpc_raw_byte_buffer_from_reader(
-    grpc_byte_buffer_reader *reader);
-
-#ifdef __cplusplus
-}
-#endif
+#include <grpc/impl/codegen/byte_buffer.h>
 
 #endif /* GRPC_BYTE_BUFFER_H */
diff --git a/include/grpc/census.h b/include/grpc/census.h
index f4130c7..dfa3bd7 100644
--- a/include/grpc/census.h
+++ b/include/grpc/census.h
@@ -59,39 +59,158 @@
  * census_initialize() will return a non-zero value. It is an error to call
  * census_initialize() more than once (without an intervening
  * census_shutdown()). */
-int census_initialize(int features);
-void census_shutdown(void);
+CENSUSAPI int census_initialize(int features);
+CENSUSAPI void census_shutdown(void);
 
 /** Return the features supported by the current census implementation (not all
  * features will be available on all platforms). */
-int census_supported(void);
+CENSUSAPI int census_supported(void);
 
 /** Return the census features currently enabled. */
-int census_enabled(void);
+CENSUSAPI int census_enabled(void);
 
 /**
-  Context is a handle used by census to represent the current tracing and
-  tagging information. Contexts should be propagated across RPC's. Contexts
-  are created by any of the census_start_*_op() functions. A context is
-  typically used as argument to most census functions. Conceptually, contexts
-  should be thought of as specific to single RPC/thread. The context can be
-  serialized for passing across the wire, via census_context_serialize().
-*/
+  A Census Context is a handle used by Census to represent the current tracing
+  and stats collection information. Contexts should be propagated across RPC's
+  (this is the responsibility of the local RPC system). A context is typically
+  used as the first argument to most census functions. Conceptually, they
+  should be thought of as specific to a single RPC/thread. The user visible
+  context representation is that of a collection of key:value string pairs,
+  each of which is termed a 'tag'; these form the basis against which Census
+  metrics will be recorded. Keys are unique within a context. */
 typedef struct census_context census_context;
 
-/* This function is called by the RPC subsystem whenever it needs to get a
- * serialized form of the current census context (presumably to pass across
- * the wire). Arguments:
- * 'buffer': pointer to memory into which serialized context will be placed
- * 'buf_size': size of 'buffer'
- *
- * Returns: the number of bytes used in buffer if successful, or 0 if the
- * buffer is of insufficient size.
- *
- * TODO(aveitch): determine how best to communicate required/max buffer size
- * so caller doesn't have to guess. */
-size_t census_context_serialize(const census_context *context, char *buffer,
-                                size_t buf_size);
+/* A tag is a key:value pair. The key is a non-empty, printable (UTF-8
+   encoded), nil-terminated string. The value is a binary string, that may be
+   printable. There are limits on the sizes of both keys and values (see
+   CENSUS_MAX_TAG_KB_LEN definition below), and the number of tags that can be
+   propagated (CENSUS_MAX_PROPAGATED_TAGS). Users should also remember that
+   some systems may have limits on, e.g., the number of bytes that can be
+   transmitted as metadata, and that larger tags means more memory consumed
+   and time in processing. */
+typedef struct {
+  const char *key;
+  const char *value;
+  size_t value_len;
+  uint8_t flags;
+} census_tag;
+
+/* Maximum length of a tag's key or value. */
+#define CENSUS_MAX_TAG_KV_LEN 255
+/* Maximum number of propagatable tags. */
+#define CENSUS_MAX_PROPAGATED_TAGS 255
+
+/* Tag flags. */
+#define CENSUS_TAG_PROPAGATE 1 /* Tag should be propagated over RPC */
+#define CENSUS_TAG_STATS 2     /* Tag will be used for statistics aggregation */
+#define CENSUS_TAG_BINARY 4    /* Tag value is not printable */
+#define CENSUS_TAG_RESERVED 8  /* Reserved for internal use. */
+/* Flag values 8,16,32,64,128 are reserved for future/internal use. Clients
+   should not use or rely on their values. */
+
+#define CENSUS_TAG_IS_PROPAGATED(flags) (flags & CENSUS_TAG_PROPAGATE)
+#define CENSUS_TAG_IS_STATS(flags) (flags & CENSUS_TAG_STATS)
+#define CENSUS_TAG_IS_BINARY(flags) (flags & CENSUS_TAG_BINARY)
+
+/* An instance of this structure is kept by every context, and records the
+   basic information associated with the creation of that context. */
+typedef struct {
+  int n_propagated_tags;        /* number of propagated printable tags */
+  int n_propagated_binary_tags; /* number of propagated binary tags */
+  int n_local_tags;             /* number of non-propagated (local) tags */
+  int n_deleted_tags;           /* number of tags that were deleted */
+  int n_added_tags;             /* number of tags that were added */
+  int n_modified_tags;          /* number of tags that were modified */
+  int n_invalid_tags;           /* number of tags with bad keys or values (e.g.
+                                   longer than CENSUS_MAX_TAG_KV_LEN) */
+  int n_ignored_tags;           /* number of tags ignored because of
+                                   CENSUS_MAX_PROPAGATED_TAGS limit. */
+} census_context_status;
+
+/* Create a new context, adding and removing tags from an existing context.
+   This will copy all tags from the 'tags' input, so it is recommended
+   to add as many tags in a single operation as is practical for the client.
+   @param base Base context to build upon. Can be NULL.
+   @param tags A set of tags to be added/changed/deleted. Tags with keys that
+   are in 'tags', but not 'base', are added to the tag set. Keys that are in
+   both 'tags' and 'base' will have their value/flags modified. Tags with keys
+   in both, but with NULL or zero-length values, will be deleted from the tag
+   set. Tags with invalid (too long or short) keys or values will be ignored.
+   If adding a tag will result in more than CENSUS_MAX_PROPAGATED_TAGS in either
+   binary or non-binary tags, they will be ignored, as will deletions of
+   tags that don't exist.
+   @param ntags number of tags in 'tags'
+   @param status If not NULL, will return a pointer to a census_context_status
+   structure containing information about the new context and status of the
+   tags used in its creation.
+   @return A new, valid census_context.
+*/
+CENSUSAPI census_context *census_context_create(
+    const census_context *base, const census_tag *tags, int ntags,
+    census_context_status const **status);
+
+/* Destroy a context. Once this function has been called, the context cannot
+   be reused. */
+CENSUSAPI void census_context_destroy(census_context *context);
+
+/* Get a pointer to the original status from the context creation. */
+CENSUSAPI const census_context_status *census_context_get_status(
+    const census_context *context);
+
+/* Structure used for iterating over the tegs in a context. API clients should
+   not use or reference internal fields - neither their contents or
+   presence/absence are guaranteed. */
+typedef struct {
+  const census_context *context;
+  int base;
+  int index;
+  char *kvm;
+} census_context_iterator;
+
+/* Initialize a census_tag_iterator. Must be called before first use. */
+CENSUSAPI void census_context_initialize_iterator(
+    const census_context *context, census_context_iterator *iterator);
+
+/* Get the contents of the "next" tag in the context. If there are no more
+   tags, returns 0 (and 'tag' contents will be unchanged), otherwise returns 1.
+   */
+CENSUSAPI int census_context_next_tag(census_context_iterator *iterator,
+                                      census_tag *tag);
+
+/* Get a context tag by key. Returns 0 if the key is not present. */
+CENSUSAPI int census_context_get_tag(const census_context *context,
+                                     const char *key, census_tag *tag);
+
+/* Tag set encode/decode functionality. These functionas are intended
+   for use by RPC systems only, for purposes of transmitting/receiving contexts.
+   */
+
+/* Encode a context into a buffer. The propagated tags are encoded into the
+   buffer in two regions: one for printable tags, and one for binary tags.
+   @param context context to be encoded
+   @param buffer pointer to buffer. This address will be used to encode the
+                 printable tags.
+   @param buf_size number of available bytes in buffer.
+   @param print_buf_size Will be set to the number of bytes consumed by
+                         printable tags.
+   @param bin_buf_size Will be set to the number of bytes used to encode the
+                       binary tags.
+   @return A pointer to the binary tag's encoded, or NULL if the buffer was
+           insufficiently large to hold the encoded tags. Thus, if successful,
+           printable tags are encoded into
+           [buffer, buffer + *print_buf_size) and binary tags into
+           [returned-ptr, returned-ptr + *bin_buf_size) (and the returned
+           pointer should be buffer + *print_buf_size) */
+CENSUSAPI char *census_context_encode(const census_context *context,
+                                      char *buffer, size_t buf_size,
+                                      size_t *print_buf_size,
+                                      size_t *bin_buf_size);
+
+/* Decode context buffers encoded with census_context_encode(). Returns NULL
+   if there is an error in parsing either buffer. */
+CENSUSAPI census_context *census_context_decode(const char *buffer, size_t size,
+                                                const char *bin_buffer,
+                                                size_t bin_size);
 
 /* Distributed traces can have a number of options. */
 enum census_trace_mask_values {
@@ -101,10 +220,10 @@
 
 /** Get the current trace mask associated with this context. The value returned
     will be the logical or of census_trace_mask_values values. */
-int census_trace_mask(const census_context *context);
+CENSUSAPI int census_trace_mask(const census_context *context);
 
 /** Set the trace mask associated with a context. */
-void census_set_trace_mask(int trace_mask);
+CENSUSAPI void census_set_trace_mask(int trace_mask);
 
 /* The concept of "operation" is a fundamental concept for Census. In an RPC
    system, and operation typcially represents a single RPC, or a significant
@@ -152,7 +271,7 @@
 
   @return A timestamp representing the operation start time.
 */
-census_timestamp census_start_rpc_op_timestamp(void);
+CENSUSAPI census_timestamp census_start_rpc_op_timestamp(void);
 
 /**
   Represent functions to map RPC name ID to service/method names. Census
@@ -204,7 +323,7 @@
 
    @return A new census context.
  */
-census_context *census_start_client_rpc_op(
+CENSUSAPI census_context *census_start_client_rpc_op(
     const census_context *context, int64_t rpc_name_id,
     const census_rpc_name_info *rpc_name_info, const char *peer, int trace_mask,
     const census_timestamp *start_time);
@@ -212,7 +331,8 @@
 /**
   Add peer information to a context representing a client RPC operation.
 */
-void census_set_rpc_client_peer(census_context *context, const char *peer);
+CENSUSAPI void census_set_rpc_client_peer(census_context *context,
+                                          const char *peer);
 
 /**
    Start a server RPC operation. Returns a new context to be used in future
@@ -232,7 +352,7 @@
 
    @return A new census context.
  */
-census_context *census_start_server_rpc_op(
+CENSUSAPI census_context *census_start_server_rpc_op(
     const char *buffer, int64_t rpc_name_id,
     const census_rpc_name_info *rpc_name_info, const char *peer, int trace_mask,
     census_timestamp *start_time);
@@ -262,8 +382,9 @@
 
    @return A new census context.
  */
-census_context *census_start_op(census_context *context, const char *family,
-                                const char *name, int trace_mask);
+CENSUSAPI census_context *census_start_op(census_context *context,
+                                          const char *family, const char *name,
+                                          int trace_mask);
 
 /**
   End an operation started by any of the census_start_*_op*() calls. The
@@ -274,7 +395,7 @@
   @param status status associated with the operation. Not interpreted by
                 census.
 */
-void census_end_op(census_context *context, int status);
+CENSUSAPI void census_end_op(census_context *context, int status);
 
 #define CENSUS_TRACE_RECORD_START_OP ((uint32_t)0)
 #define CENSUS_TRACE_RECORD_END_OP ((uint32_t)1)
@@ -286,8 +407,8 @@
     @param buffer Pointer to buffer to use
     @param n Number of bytes in buffer
 */
-void census_trace_print(census_context *context, uint32_t type,
-                        const char *buffer, size_t n);
+CENSUSAPI void census_trace_print(census_context *context, uint32_t type,
+                                  const char *buffer, size_t n);
 
 /** Trace record. */
 typedef struct {
@@ -308,7 +429,7 @@
          while scanning is ongoing.
   @returns 0 on success, non-zero on failure (e.g. if a scan is already ongoing)
 */
-int census_trace_scan_start(int consume);
+CENSUSAPI int census_trace_scan_start(int consume);
 
 /** Get a trace record. The data pointed to by the trace buffer is guaranteed
     stable until the next census_get_trace_record() call (if the consume
@@ -319,147 +440,10 @@
            census_trace_scan_start()), 0 if there is no more trace data (and
            trace_record will not be modified) or 1 otherwise.
 */
-int census_get_trace_record(census_trace_record *trace_record);
+CENSUSAPI int census_get_trace_record(census_trace_record *trace_record);
 
 /** End a scan previously started by census_trace_scan_start() */
-void census_trace_scan_end();
-
-/* A Census tag set is a collection of key:value string pairs; these form the
-   basis against which Census metrics will be recorded. Keys are unique within
-   a tag set. All contexts have an associated tag set. */
-typedef struct census_tag_set census_tag_set;
-
-/* A tag is a key:value pair. The key is a non-empty, printable (UTF-8
-   encoded), nil-terminated string. The value is a binary string, that may be
-   printable. There are limits on the sizes of both keys and values (see
-   CENSUS_MAX_TAG_KB_LEN definition below), and the number of tags that can be
-   propagated (CENSUS_MAX_PROPAGATED_TAGS). Users should also remember that
-   some systems may have limits on, e.g., the number of bytes that can be
-   transmitted as metadata, and that larger tags means more memory consumed
-   and time in processing. */
-typedef struct {
-  const char *key;
-  const char *value;
-  size_t value_len;
-  uint8_t flags;
-} census_tag;
-
-/* Maximum length of a tag's key or value. */
-#define CENSUS_MAX_TAG_KV_LEN 255
-/* Maximum number of propagatable tags. */
-#define CENSUS_MAX_PROPAGATED_TAGS 255
-
-/* Tag flags. */
-#define CENSUS_TAG_PROPAGATE 1 /* Tag should be propagated over RPC */
-#define CENSUS_TAG_STATS 2     /* Tag will be used for statistics aggregation */
-#define CENSUS_TAG_BINARY 4    /* Tag value is not printable */
-#define CENSUS_TAG_RESERVED 8  /* Reserved for internal use. */
-/* Flag values 8,16,32,64,128 are reserved for future/internal use. Clients
-   should not use or rely on their values. */
-
-#define CENSUS_TAG_IS_PROPAGATED(flags) (flags & CENSUS_TAG_PROPAGATE)
-#define CENSUS_TAG_IS_STATS(flags) (flags & CENSUS_TAG_STATS)
-#define CENSUS_TAG_IS_BINARY(flags) (flags & CENSUS_TAG_BINARY)
-
-typedef struct {
-  int n_propagated_tags;        /* number of propagated printable tags */
-  int n_propagated_binary_tags; /* number of propagated binary tags */
-  int n_local_tags;             /* number of non-propagated (local) tags */
-  int n_deleted_tags;           /* number of tags that were deleted */
-  int n_added_tags;             /* number of tags that were added */
-  int n_modified_tags;          /* number of tags that were modified */
-  int n_invalid_tags;           /* number of tags with bad keys or values (e.g.
-                                   longer than CENSUS_MAX_TAG_KV_LEN) */
-  int n_ignored_tags;           /* number of tags ignored because of
-                                   CENSUS_MAX_PROPAGATED_TAGS limit. */
-} census_tag_set_create_status;
-
-/* Create a new tag set, adding and removing tags from an existing tag set.
-   This will copy all tags from it's input parameters, so it is recommended
-   to add as many tags in a single operation as is practical for the client.
-   @param base Base tag set to build upon. Can be NULL.
-   @param tags A set of tags to be added/changed/deleted. Tags with keys that
-   are in 'tags', but not 'base', are added to the tag set. Keys that are in
-   both 'tags' and 'base' will have their value/flags modified. Tags with keys
-   in both, but with NULL or zero-length values, will be deleted from the tag
-   set. Tags with invalid (too long or short) keys or values will be ignored.
-   If adding a tag will result in more than CENSUS_MAX_PROPAGATED_TAGS in either
-   binary or non-binary tags, they will be ignored, as will deletions of
-   tags that don't exist.
-   @param ntags number of tags in 'tags'
-   @param status If not NULL, will return a pointer to a
-   census_tag_set_create_status structure containing information about the new
-   tag set and status of the tags used in its creation.
-   @return A new, valid census_tag_set.
-*/
-census_tag_set *census_tag_set_create(
-    const census_tag_set *base, const census_tag *tags, int ntags,
-    census_tag_set_create_status const **status);
-
-/* Destroy a tag set created by census_tag_set_create(). Once this function
-   has been called, the tag set cannot be reused. */
-void census_tag_set_destroy(census_tag_set *tags);
-
-/* Get a pointer to the original status from the creation of this tag set. */
-const census_tag_set_create_status *census_tag_set_get_create_status(
-    const census_tag_set *tags);
-
-/* Structure used for tag set iteration. API clients should not use or
-   reference internal fields - neither their contents or presence/absence are
-   guaranteed. */
-typedef struct {
-  const census_tag_set *tags;
-  int base;
-  int index;
-  char *kvm;
-} census_tag_set_iterator;
-
-/* Initialize a tag set iterator. Must be called before first use of the
-   iterator. */
-void census_tag_set_initialize_iterator(const census_tag_set *tags,
-                                        census_tag_set_iterator *iterator);
-
-/* Get the contents of the "next" tag in the tag set. If there are no more
-   tags in the tag set, returns 0 (and 'tag' contents will be unchanged),
-   otherwise returns 1. */
-int census_tag_set_next_tag(census_tag_set_iterator *iterator, census_tag *tag);
-
-/* Get a tag by its key. Returns 0 if the key is not present in the tag
-   set. */
-int census_tag_set_get_tag_by_key(const census_tag_set *tags, const char *key,
-                                  census_tag *tag);
-
-/* Tag set encode/decode functionality. These functionas are intended
-   for use by RPC systems only, for purposes of transmitting/receiving tag
-   sets. */
-
-/* Encode a tag set into a buffer. The propagated tags are encoded into the
-   buffer in two regions: one for printable tags, and one for binary tags.
-   @param tags tag set to be encoded
-   @param buffer pointer to buffer. This address will be used to encode the
-                 printable tags.
-   @param buf_size number of available bytes in buffer.
-   @param print_buf_size Will be set to the number of bytes consumed by
-                         printable tags.
-   @param bin_buf_size Will be set to the number of bytes used to encode the
-                       binary tags.
-   @return A pointer to the binary tag's encoded, or NULL if the buffer was
-           insufficiently large to hold the encoded tags. Thus, if successful,
-           printable tags are encoded into
-           [buffer, buffer + *print_buf_size) and binary tags into
-           [returned-ptr, returned-ptr + *bin_buf_size) (and the return value
-           should be buffer + *print_buf_size) */
-char *census_tag_set_encode(const census_tag_set *tags, char *buffer,
-                            size_t buf_size, size_t *print_buf_size,
-                            size_t *bin_buf_size);
-
-/* Decode tag set buffers encoded with census_tag_set_encode_*(). Returns NULL
-   if there is an error in parsing either buffer. */
-census_tag_set *census_tag_set_decode(const char *buffer, size_t size,
-                                      const char *bin_buffer, size_t bin_size);
-
-/* Get a contexts tag set. */
-census_tag_set *census_context_tag_set(census_context *context);
+CENSUSAPI void census_trace_scan_end();
 
 /* Core stats collection API's. The following concepts are used:
    * Aggregation: A collection of values. Census supports the following
@@ -490,8 +474,8 @@
 } census_value;
 
 /* Record new usage values against the given context. */
-void census_record_values(census_context *context, census_value *values,
-                          size_t nvalues);
+CENSUSAPI void census_record_values(census_context *context,
+                                    census_value *values, size_t nvalues);
 
 /** Type representing a particular aggregation */
 typedef struct census_aggregation_ops census_aggregation_ops;
@@ -506,8 +490,7 @@
     construction via census_define_view(). */
 typedef struct {
   const census_aggregation_ops *ops;
-  const void *
-      create_arg; /* Argument to be used for aggregation initialization. */
+  const void *create_arg; /* Aaggregation initialization argument. */
 } census_aggregation;
 
 /** A census view type. Opaque. */
@@ -515,35 +498,39 @@
 
 /** Create a new view.
   @param metric_id Metric with which this view is associated.
-  @param tags tags that define the view
+  @param tags tags that define the view.
   @param aggregations aggregations to associate with the view
   @param naggregations number of aggregations
 
   @return A new census view
 */
-census_view *census_view_create(uint32_t metric_id, const census_tag_set *tags,
-                                const census_aggregation *aggregations,
-                                size_t naggregations);
+
+/* TODO(aveitch): consider if context is the right argument type to pass in
+   tags. */
+CENSUSAPI census_view *census_view_create(
+    uint32_t metric_id, const census_context *tags,
+    const census_aggregation *aggregations, size_t naggregations);
 
 /** Destroy a previously created view. */
-void census_view_delete(census_view *view);
+CENSUSAPI void census_view_delete(census_view *view);
 
 /** Metric ID associated with a view */
-size_t census_view_metric(const census_view *view);
+CENSUSAPI size_t census_view_metric(const census_view *view);
 
 /** Number of aggregations associated with view. */
-size_t census_view_naggregations(const census_view *view);
+CENSUSAPI size_t census_view_naggregations(const census_view *view);
 
 /** Get tags associated with view. */
-const census_tag_set *census_view_tags(const census_view *view);
+CENSUSAPI const census_context *census_view_tags(const census_view *view);
 
 /** Get aggregation descriptors associated with a view. */
-const census_aggregation *census_view_aggregrations(const census_view *view);
+CENSUSAPI const census_aggregation *census_view_aggregrations(
+    const census_view *view);
 
 /** Holds all the aggregation data for a particular view instantiation. Forms
   part of the data returned by census_view_data(). */
 typedef struct {
-  const census_tag_set *tags; /* Tags for this set of aggregations. */
+  const census_context *tags; /* Tags for this set of aggregations. */
   const void **data; /* One data set for every aggregation in the view. */
 } census_view_aggregation_data;
 
@@ -557,10 +544,10 @@
   @param view View from which to get data.
   @return Full set of data for all aggregations for the view.
 */
-const census_view_data *census_view_get_data(const census_view *view);
+CENSUSAPI const census_view_data *census_view_get_data(const census_view *view);
 
 /** Reset all view data to zero for the specified view */
-void census_view_reset(census_view *view);
+CENSUSAPI void census_view_reset(census_view *view);
 
 #ifdef __cplusplus
 }
diff --git a/include/grpc/compression.h b/include/grpc/compression.h
index 31d048b..acc168a 100644
--- a/include/grpc/compression.h
+++ b/include/grpc/compression.h
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -36,67 +36,43 @@
 
 #include <stdlib.h>
 
-#include <grpc/support/port_platform.h>
+#include <grpc/impl/codegen/port_platform.h>
+#include <grpc/impl/codegen/compression_types.h>
 
 #ifdef __cplusplus
 extern "C" {
 #endif
 
-/** To be used in channel arguments */
-#define GRPC_COMPRESSION_ALGORITHM_ARG "grpc.compression_algorithm"
-#define GRPC_COMPRESSION_ALGORITHM_STATE_ARG "grpc.compression_algorithm_state"
-
-/* The various compression algorithms supported by GRPC */
-typedef enum {
-  GRPC_COMPRESS_NONE = 0,
-  GRPC_COMPRESS_DEFLATE,
-  GRPC_COMPRESS_GZIP,
-  /* TODO(ctiller): snappy */
-  GRPC_COMPRESS_ALGORITHMS_COUNT
-} grpc_compression_algorithm;
-
-typedef enum {
-  GRPC_COMPRESS_LEVEL_NONE = 0,
-  GRPC_COMPRESS_LEVEL_LOW,
-  GRPC_COMPRESS_LEVEL_MED,
-  GRPC_COMPRESS_LEVEL_HIGH,
-  GRPC_COMPRESS_LEVEL_COUNT
-} grpc_compression_level;
-
-typedef struct grpc_compression_options {
-  uint32_t enabled_algorithms_bitset; /**< All algs are enabled by default */
-  grpc_compression_algorithm default_compression_algorithm; /**< for channel */
-} grpc_compression_options;
-
 /** Parses the first \a name_length bytes of \a name as a
  * grpc_compression_algorithm instance, updating \a algorithm. Returns 1 upon
  * success, 0 otherwise. */
-int grpc_compression_algorithm_parse(const char *name, size_t name_length,
-                                     grpc_compression_algorithm *algorithm);
+GRPCAPI int grpc_compression_algorithm_parse(
+    const char *name, size_t name_length,
+    grpc_compression_algorithm *algorithm);
 
 /** Updates \a name with the encoding name corresponding to a valid \a
  * algorithm.  Returns 1 upon success, 0 otherwise. */
-int grpc_compression_algorithm_name(grpc_compression_algorithm algorithm,
-                                    char **name);
+GRPCAPI int grpc_compression_algorithm_name(
+    grpc_compression_algorithm algorithm, char **name);
 
 /** Returns the compression algorithm corresponding to \a level.
  *
  * It abort()s for unknown levels . */
-grpc_compression_algorithm grpc_compression_algorithm_for_level(
-    grpc_compression_level level);
+GRPCAPI grpc_compression_algorithm
+grpc_compression_algorithm_for_level(grpc_compression_level level);
 
-void grpc_compression_options_init(grpc_compression_options *opts);
+GRPCAPI void grpc_compression_options_init(grpc_compression_options *opts);
 
 /** Mark \a algorithm as enabled in \a opts. */
-void grpc_compression_options_enable_algorithm(
+GRPCAPI void grpc_compression_options_enable_algorithm(
     grpc_compression_options *opts, grpc_compression_algorithm algorithm);
 
 /** Mark \a algorithm as disabled in \a opts. */
-void grpc_compression_options_disable_algorithm(
+GRPCAPI void grpc_compression_options_disable_algorithm(
     grpc_compression_options *opts, grpc_compression_algorithm algorithm);
 
 /** Returns true if \a algorithm is marked as enabled in \a opts. */
-int grpc_compression_options_is_algorithm_enabled(
+GRPCAPI int grpc_compression_options_is_algorithm_enabled(
     const grpc_compression_options *opts, grpc_compression_algorithm algorithm);
 
 #ifdef __cplusplus
diff --git a/include/grpc/grpc.h b/include/grpc/grpc.h
index 952e86e..5113645 100644
--- a/include/grpc/grpc.h
+++ b/include/grpc/grpc.h
@@ -40,6 +40,9 @@
 #include <grpc/byte_buffer.h>
 #include <grpc/support/slice.h>
 #include <grpc/support/time.h>
+#include <grpc/impl/codegen/connectivity_state.h>
+#include <grpc/impl/codegen/propagation_bits.h>
+#include <grpc/impl/codegen/grpc_types.h>
 
 #ifdef __cplusplus
 extern "C" {
@@ -52,348 +55,11 @@
  * functionality lives in grpc_security.h.
  */
 
-/** Completion Queues enable notification of the completion of asynchronous
-    actions. */
-typedef struct grpc_completion_queue grpc_completion_queue;
+GRPCAPI void grpc_metadata_array_init(grpc_metadata_array *array);
+GRPCAPI void grpc_metadata_array_destroy(grpc_metadata_array *array);
 
-/** An alarm associated with a completion queue. */
-typedef struct grpc_alarm grpc_alarm;
-
-/** The Channel interface allows creation of Call objects. */
-typedef struct grpc_channel grpc_channel;
-
-/** A server listens to some port and responds to request calls */
-typedef struct grpc_server grpc_server;
-
-/** A Call represents an RPC. When created, it is in a configuration state
-    allowing properties to be set until it is invoked. After invoke, the Call
-    can have messages written to it and read from it. */
-typedef struct grpc_call grpc_call;
-
-/** Type specifier for grpc_arg */
-typedef enum {
-  GRPC_ARG_STRING,
-  GRPC_ARG_INTEGER,
-  GRPC_ARG_POINTER
-} grpc_arg_type;
-
-/** A single argument... each argument has a key and a value
-
-    A note on naming keys:
-      Keys are namespaced into groups, usually grouped by library, and are
-      keys for module XYZ are named XYZ.key1, XYZ.key2, etc. Module names must
-      be restricted to the regex [A-Za-z][_A-Za-z0-9]{,15}.
-      Key names must be restricted to the regex [A-Za-z][_A-Za-z0-9]{,47}.
-
-    GRPC core library keys are prefixed by grpc.
-
-    Library authors are strongly encouraged to \#define symbolic constants for
-    their keys so that it's possible to change them in the future. */
-typedef struct {
-  grpc_arg_type type;
-  char *key;
-  union {
-    char *string;
-    int integer;
-    struct {
-      void *p;
-      void *(*copy)(void *p);
-      void (*destroy)(void *p);
-    } pointer;
-  } value;
-} grpc_arg;
-
-/** An array of arguments that can be passed around.
-
-    Used to set optional channel-level configuration.
-    These configuration options are modelled as key-value pairs as defined
-    by grpc_arg; keys are strings to allow easy backwards-compatible extension
-    by arbitrary parties.
-    All evaluation is performed at channel creation time (i.e. the values in
-    this structure need only live through the creation invocation). */
-typedef struct {
-  size_t num_args;
-  grpc_arg *args;
-} grpc_channel_args;
-
-/* Channel argument keys: */
-/** Enable census for tracing and stats collection */
-#define GRPC_ARG_ENABLE_CENSUS "grpc.census"
-/** Maximum number of concurrent incoming streams to allow on a http2
-    connection */
-#define GRPC_ARG_MAX_CONCURRENT_STREAMS "grpc.max_concurrent_streams"
-/** Maximum message length that the channel can receive */
-#define GRPC_ARG_MAX_MESSAGE_LENGTH "grpc.max_message_length"
-/** Initial sequence number for http2 transports */
-#define GRPC_ARG_HTTP2_INITIAL_SEQUENCE_NUMBER \
-  "grpc.http2.initial_sequence_number"
-/** Amount to read ahead on individual streams. Defaults to 64kb, larger
-    values can help throughput on high-latency connections.
-    NOTE: at some point we'd like to auto-tune this, and this parameter
-    will become a no-op. */
-#define GRPC_ARG_HTTP2_STREAM_LOOKAHEAD_BYTES "grpc.http2.lookahead_bytes"
-/** How much memory to use for hpack decoding */
-#define GRPC_ARG_HTTP2_HPACK_TABLE_SIZE_DECODER \
-  "grpc.http2.hpack_table_size.decoder"
-/** How much memory to use for hpack encoding */
-#define GRPC_ARG_HTTP2_HPACK_TABLE_SIZE_ENCODER \
-  "grpc.http2.hpack_table_size.encoder"
-/** Default authority to pass if none specified on call construction */
-#define GRPC_ARG_DEFAULT_AUTHORITY "grpc.default_authority"
-/** Primary user agent: goes at the start of the user-agent metadata
-    sent on each request */
-#define GRPC_ARG_PRIMARY_USER_AGENT_STRING "grpc.primary_user_agent"
-/** Secondary user agent: goes at the end of the user-agent metadata
-    sent on each request */
-#define GRPC_ARG_SECONDARY_USER_AGENT_STRING "grpc.secondary_user_agent"
-/* The caller of the secure_channel_create functions may override the target
-   name used for SSL host name checking using this channel argument which is of
-   type GRPC_ARG_STRING. This *should* be used for testing only.
-   If this argument is not specified, the name used for SSL host name checking
-   will be the target parameter (assuming that the secure channel is an SSL
-   channel). If this parameter is specified and the underlying is not an SSL
-   channel, it will just be ignored. */
-#define GRPC_SSL_TARGET_NAME_OVERRIDE_ARG "grpc.ssl_target_name_override"
-
-/** Connectivity state of a channel. */
-typedef enum {
-  /** channel is idle */
-  GRPC_CHANNEL_IDLE,
-  /** channel is connecting */
-  GRPC_CHANNEL_CONNECTING,
-  /** channel is ready for work */
-  GRPC_CHANNEL_READY,
-  /** channel has seen a failure but expects to recover */
-  GRPC_CHANNEL_TRANSIENT_FAILURE,
-  /** channel has seen a failure that it cannot recover from */
-  GRPC_CHANNEL_FATAL_FAILURE
-} grpc_connectivity_state;
-
-/** Result of a grpc call. If the caller satisfies the prerequisites of a
-    particular operation, the grpc_call_error returned will be GRPC_CALL_OK.
-    Receiving any other value listed here is an indication of a bug in the
-    caller. */
-typedef enum grpc_call_error {
-  /** everything went ok */
-  GRPC_CALL_OK = 0,
-  /** something failed, we don't know what */
-  GRPC_CALL_ERROR,
-  /** this method is not available on the server */
-  GRPC_CALL_ERROR_NOT_ON_SERVER,
-  /** this method is not available on the client */
-  GRPC_CALL_ERROR_NOT_ON_CLIENT,
-  /** this method must be called before server_accept */
-  GRPC_CALL_ERROR_ALREADY_ACCEPTED,
-  /** this method must be called before invoke */
-  GRPC_CALL_ERROR_ALREADY_INVOKED,
-  /** this method must be called after invoke */
-  GRPC_CALL_ERROR_NOT_INVOKED,
-  /** this call is already finished
-      (writes_done or write_status has already been called) */
-  GRPC_CALL_ERROR_ALREADY_FINISHED,
-  /** there is already an outstanding read/write operation on the call */
-  GRPC_CALL_ERROR_TOO_MANY_OPERATIONS,
-  /** the flags value was illegal for this call */
-  GRPC_CALL_ERROR_INVALID_FLAGS,
-  /** invalid metadata was passed to this call */
-  GRPC_CALL_ERROR_INVALID_METADATA,
-  /** invalid message was passed to this call */
-  GRPC_CALL_ERROR_INVALID_MESSAGE,
-  /** completion queue for notification has not been registered with the
-      server */
-  GRPC_CALL_ERROR_NOT_SERVER_COMPLETION_QUEUE,
-  /** this batch of operations leads to more operations than allowed */
-  GRPC_CALL_ERROR_BATCH_TOO_BIG
-} grpc_call_error;
-
-/* Write Flags: */
-/** Hint that the write may be buffered and need not go out on the wire
-    immediately. GRPC is free to buffer the message until the next non-buffered
-    write, or until writes_done, but it need not buffer completely or at all. */
-#define GRPC_WRITE_BUFFER_HINT (0x00000001u)
-/** Force compression to be disabled for a particular write
-    (start_write/add_metadata). Illegal on invoke/accept. */
-#define GRPC_WRITE_NO_COMPRESS (0x00000002u)
-/** Mask of all valid flags. */
-#define GRPC_WRITE_USED_MASK (GRPC_WRITE_BUFFER_HINT | GRPC_WRITE_NO_COMPRESS)
-
-/** A single metadata element */
-typedef struct grpc_metadata {
-  const char *key;
-  const char *value;
-  size_t value_length;
-  uint32_t flags;
-
-  /** The following fields are reserved for grpc internal use.
-      There is no need to initialize them, and they will be set to garbage
-      during calls to grpc. */
-  struct {
-    void *obfuscated[4];
-  } internal_data;
-} grpc_metadata;
-
-/** The type of completion (for grpc_event) */
-typedef enum grpc_completion_type {
-  /** Shutting down */
-  GRPC_QUEUE_SHUTDOWN,
-  /** No event before timeout */
-  GRPC_QUEUE_TIMEOUT,
-  /** Operation completion */
-  GRPC_OP_COMPLETE
-} grpc_completion_type;
-
-/** The result of an operation.
-
-    Returned by a completion queue when the operation started with tag. */
-typedef struct grpc_event {
-  /** The type of the completion. */
-  grpc_completion_type type;
-  /** non-zero if the operation was successful, 0 upon failure.
-      Only GRPC_OP_COMPLETE can succeed or fail. */
-  int success;
-  /** The tag passed to grpc_call_start_batch etc to start this operation.
-      Only GRPC_OP_COMPLETE has a tag. */
-  void *tag;
-} grpc_event;
-
-typedef struct {
-  size_t count;
-  size_t capacity;
-  grpc_metadata *metadata;
-} grpc_metadata_array;
-
-void grpc_metadata_array_init(grpc_metadata_array *array);
-void grpc_metadata_array_destroy(grpc_metadata_array *array);
-
-typedef struct {
-  char *method;
-  size_t method_capacity;
-  char *host;
-  size_t host_capacity;
-  gpr_timespec deadline;
-  void *reserved;
-} grpc_call_details;
-
-void grpc_call_details_init(grpc_call_details *details);
-void grpc_call_details_destroy(grpc_call_details *details);
-
-typedef enum {
-  /** Send initial metadata: one and only one instance MUST be sent for each
-      call, unless the call was cancelled - in which case this can be skipped.
-      This op completes after all bytes of metadata have been accepted by
-      outgoing flow control. */
-  GRPC_OP_SEND_INITIAL_METADATA = 0,
-  /** Send a message: 0 or more of these operations can occur for each call.
-      This op completes after all bytes for the message have been accepted by
-      outgoing flow control. */
-  GRPC_OP_SEND_MESSAGE,
-  /** Send a close from the client: one and only one instance MUST be sent from
-      the client, unless the call was cancelled - in which case this can be
-      skipped.
-      This op completes after all bytes for the call (including the close)
-      have passed outgoing flow control. */
-  GRPC_OP_SEND_CLOSE_FROM_CLIENT,
-  /** Send status from the server: one and only one instance MUST be sent from
-      the server unless the call was cancelled - in which case this can be
-      skipped.
-      This op completes after all bytes for the call (including the status)
-      have passed outgoing flow control. */
-  GRPC_OP_SEND_STATUS_FROM_SERVER,
-  /** Receive initial metadata: one and only one MUST be made on the client,
-      must not be made on the server.
-      This op completes after all initial metadata has been read from the
-      peer. */
-  GRPC_OP_RECV_INITIAL_METADATA,
-  /** Receive a message: 0 or more of these operations can occur for each call.
-      This op completes after all bytes of the received message have been
-      read, or after a half-close has been received on this call. */
-  GRPC_OP_RECV_MESSAGE,
-  /** Receive status on the client: one and only one must be made on the client.
-      This operation always succeeds, meaning ops paired with this operation
-      will also appear to succeed, even though they may not have. In that case
-      the status will indicate some failure.
-      This op completes after all activity on the call has completed. */
-  GRPC_OP_RECV_STATUS_ON_CLIENT,
-  /** Receive close on the server: one and only one must be made on the
-      server.
-      This op completes after the close has been received by the server. */
-  GRPC_OP_RECV_CLOSE_ON_SERVER
-} grpc_op_type;
-
-/** Operation data: one field for each op type (except SEND_CLOSE_FROM_CLIENT
-   which has no arguments) */
-typedef struct grpc_op {
-  /** Operation type, as defined by grpc_op_type */
-  grpc_op_type op;
-  /** Write flags bitset for grpc_begin_messages */
-  uint32_t flags;
-  /** Reserved for future usage */
-  void *reserved;
-  union {
-    /** Reserved for future usage */
-    struct {
-      void *reserved[8];
-    } reserved;
-    struct {
-      size_t count;
-      grpc_metadata *metadata;
-    } send_initial_metadata;
-    grpc_byte_buffer *send_message;
-    struct {
-      size_t trailing_metadata_count;
-      grpc_metadata *trailing_metadata;
-      grpc_status_code status;
-      const char *status_details;
-    } send_status_from_server;
-    /** ownership of the array is with the caller, but ownership of the elements
-        stays with the call object (ie key, value members are owned by the call
-        object, recv_initial_metadata->array is owned by the caller).
-        After the operation completes, call grpc_metadata_array_destroy on this
-        value, or reuse it in a future op. */
-    grpc_metadata_array *recv_initial_metadata;
-    /** ownership of the byte buffer is moved to the caller; the caller must
-        call grpc_byte_buffer_destroy on this value, or reuse it in a future op.
-       */
-    grpc_byte_buffer **recv_message;
-    struct {
-      /** ownership of the array is with the caller, but ownership of the
-          elements stays with the call object (ie key, value members are owned
-          by the call object, trailing_metadata->array is owned by the caller).
-          After the operation completes, call grpc_metadata_array_destroy on
-         this
-          value, or reuse it in a future op. */
-      grpc_metadata_array *trailing_metadata;
-      grpc_status_code *status;
-      /** status_details is a buffer owned by the application before the op
-          completes and after the op has completed. During the operation
-          status_details may be reallocated to a size larger than
-          *status_details_capacity, in which case *status_details_capacity will
-          be updated with the new array capacity.
-
-          Pre-allocating space:
-          size_t my_capacity = 8;
-          char *my_details = gpr_malloc(my_capacity);
-          x.status_details = &my_details;
-          x.status_details_capacity = &my_capacity;
-
-          Not pre-allocating space:
-          size_t my_capacity = 0;
-          char *my_details = NULL;
-          x.status_details = &my_details;
-          x.status_details_capacity = &my_capacity;
-
-          After the call:
-          gpr_free(my_details); */
-      char **status_details;
-      size_t *status_details_capacity;
-    } recv_status_on_client;
-    struct {
-      /** out argument, set to 1 if the call failed in any way (seen as a
-          cancellation on the server), or 0 if the call succeeded */
-      int *cancelled;
-    } recv_close_on_server;
-  } data;
-} grpc_op;
+GRPCAPI void grpc_call_details_init(grpc_call_details *details);
+GRPCAPI void grpc_call_details_destroy(grpc_call_details *details);
 
 /** Registers a plugin to be initialized and destroyed with the library.
 
@@ -403,27 +69,7 @@
     (and hence so will \a init and \a destroy).
     It is safe to pass NULL to either argument. Plugins are destroyed in
     the reverse order they were initialized. */
-void grpc_register_plugin(void (*init)(void), void (*destroy)(void));
-
-/* Propagation bits: this can be bitwise or-ed to form propagation_mask for
- * grpc_call */
-/** Propagate deadline */
-#define GRPC_PROPAGATE_DEADLINE ((uint32_t)1)
-/** Propagate census context */
-#define GRPC_PROPAGATE_CENSUS_STATS_CONTEXT ((uint32_t)2)
-#define GRPC_PROPAGATE_CENSUS_TRACING_CONTEXT ((uint32_t)4)
-/** Propagate cancellation */
-#define GRPC_PROPAGATE_CANCELLATION ((uint32_t)8)
-
-/* Default propagation mask: clients of the core API are encouraged to encode
-   deltas from this in their implementations... ie write:
-   GRPC_PROPAGATE_DEFAULTS & ~GRPC_PROPAGATE_DEADLINE to disable deadline
-   propagation. Doing so gives flexibility in the future to define new
-   propagation types that are default inherited or not. */
-#define GRPC_PROPAGATE_DEFAULTS                                                \
-  ((uint32_t)((                                                                \
-      0xffff | GRPC_PROPAGATE_DEADLINE | GRPC_PROPAGATE_CENSUS_STATS_CONTEXT | \
-      GRPC_PROPAGATE_CENSUS_TRACING_CONTEXT | GRPC_PROPAGATE_CANCELLATION)))
+GRPCAPI void grpc_register_plugin(void (*init)(void), void (*destroy)(void));
 
 /** Initialize the grpc library.
 
@@ -431,7 +77,7 @@
     (To avoid overhead, little checking is done, and some things may work. We
     do not warrant that they will continue to do so in future revisions of this
     library). */
-void grpc_init(void);
+GRPCAPI void grpc_init(void);
 
 /** Shut down the grpc library.
 
@@ -439,13 +85,13 @@
     executing within the grpc library.
     Prior to calling, all application owned grpc objects must have been
     destroyed. */
-void grpc_shutdown(void);
+GRPCAPI void grpc_shutdown(void);
 
 /** Return a string representing the current version of grpc */
-const char *grpc_version_string(void);
+GRPCAPI const char *grpc_version_string(void);
 
 /** Create a completion queue */
-grpc_completion_queue *grpc_completion_queue_create(void *reserved);
+GRPCAPI grpc_completion_queue *grpc_completion_queue_create(void *reserved);
 
 /** Blocks until an event is available, the completion queue is being shut down,
     or deadline is reached.
@@ -455,8 +101,9 @@
 
     Callers must not call grpc_completion_queue_next and
     grpc_completion_queue_pluck simultaneously on the same completion queue. */
-grpc_event grpc_completion_queue_next(grpc_completion_queue *cq,
-                                      gpr_timespec deadline, void *reserved);
+GRPCAPI grpc_event grpc_completion_queue_next(grpc_completion_queue *cq,
+                                              gpr_timespec deadline,
+                                              void *reserved);
 
 /** Blocks until an event with tag 'tag' is available, the completion queue is
     being shutdown or deadline is reached.
@@ -469,8 +116,9 @@
 
     Completion queues support a maximum of GRPC_MAX_COMPLETION_QUEUE_PLUCKERS
     concurrently executing plucks at any time. */
-grpc_event grpc_completion_queue_pluck(grpc_completion_queue *cq, void *tag,
-                                       gpr_timespec deadline, void *reserved);
+GRPCAPI grpc_event grpc_completion_queue_pluck(grpc_completion_queue *cq,
+                                               void *tag, gpr_timespec deadline,
+                                               void *reserved);
 
 /** Maximum number of outstanding grpc_completion_queue_pluck executions per
     completion queue */
@@ -483,11 +131,11 @@
 
     After calling this function applications should ensure that no
     NEW work is added to be published on this completion queue. */
-void grpc_completion_queue_shutdown(grpc_completion_queue *cq);
+GRPCAPI void grpc_completion_queue_shutdown(grpc_completion_queue *cq);
 
 /** Destroy a completion queue. The caller must ensure that the queue is
     drained and no threads are executing grpc_completion_queue_next */
-void grpc_completion_queue_destroy(grpc_completion_queue *cq);
+GRPCAPI void grpc_completion_queue_destroy(grpc_completion_queue *cq);
 
 /** Create a completion queue alarm instance associated to \a cq.
  *
@@ -495,26 +143,27 @@
  * grpc_alarm_cancel), an event with tag \a tag will be added to \a cq. If the
  * alarm expired, the event's success bit will be true, false otherwise (ie,
  * upon cancellation). */
-grpc_alarm *grpc_alarm_create(grpc_completion_queue *cq, gpr_timespec deadline,
-                              void *tag);
+GRPCAPI grpc_alarm *grpc_alarm_create(grpc_completion_queue *cq,
+                                      gpr_timespec deadline, void *tag);
 
 /** Cancel a completion queue alarm. Calling this function over an alarm that
  * has already fired has no effect. */
-void grpc_alarm_cancel(grpc_alarm *alarm);
+GRPCAPI void grpc_alarm_cancel(grpc_alarm *alarm);
 
 /** Destroy the given completion queue alarm, cancelling it in the process. */
-void grpc_alarm_destroy(grpc_alarm *alarm);
+GRPCAPI void grpc_alarm_destroy(grpc_alarm *alarm);
 
 /** Check the connectivity state of a channel. */
-grpc_connectivity_state grpc_channel_check_connectivity_state(
-    grpc_channel *channel, int try_to_connect);
+GRPCAPI grpc_connectivity_state
+grpc_channel_check_connectivity_state(grpc_channel *channel,
+                                      int try_to_connect);
 
 /** Watch for a change in connectivity state.
     Once the channel connectivity state is different from last_observed_state,
     tag will be enqueued on cq with success=1.
     If deadline expires BEFORE the state is changed, tag will be enqueued on cq
     with success=0. */
-void grpc_channel_watch_connectivity_state(
+GRPCAPI void grpc_channel_watch_connectivity_state(
     grpc_channel *channel, grpc_connectivity_state last_observed_state,
     gpr_timespec deadline, grpc_completion_queue *cq, void *tag);
 
@@ -524,24 +173,23 @@
     If parent_call is non-NULL, it must be a server-side call. It will be used
     to propagate properties from the server call to this new client call.
     */
-grpc_call *grpc_channel_create_call(grpc_channel *channel,
-                                    grpc_call *parent_call,
-                                    uint32_t propagation_mask,
-                                    grpc_completion_queue *completion_queue,
-                                    const char *method, const char *host,
-                                    gpr_timespec deadline, void *reserved);
+GRPCAPI grpc_call *grpc_channel_create_call(
+    grpc_channel *channel, grpc_call *parent_call, uint32_t propagation_mask,
+    grpc_completion_queue *completion_queue, const char *method,
+    const char *host, gpr_timespec deadline, void *reserved);
 
 /** Ping the channels peer (load balanced channels will select one sub-channel
     to ping); if the channel is not connected, posts a failed. */
-void grpc_channel_ping(grpc_channel *channel, grpc_completion_queue *cq,
-                       void *tag, void *reserved);
+GRPCAPI void grpc_channel_ping(grpc_channel *channel, grpc_completion_queue *cq,
+                               void *tag, void *reserved);
 
 /** Pre-register a method/host pair on a channel. */
-void *grpc_channel_register_call(grpc_channel *channel, const char *method,
-                                 const char *host, void *reserved);
+GRPCAPI void *grpc_channel_register_call(grpc_channel *channel,
+                                         const char *method, const char *host,
+                                         void *reserved);
 
 /** Create a call given a handle returned from grpc_channel_register_call */
-grpc_call *grpc_channel_create_registered_call(
+GRPCAPI grpc_call *grpc_channel_create_registered_call(
     grpc_channel *channel, grpc_call *parent_call, uint32_t propagation_mask,
     grpc_completion_queue *completion_queue, void *registered_call_handle,
     gpr_timespec deadline, void *reserved);
@@ -557,8 +205,9 @@
     needs to be synchronized. As an optimization, you may synchronize batches
     containing just send operations independently from batches containing just
     receive operations. */
-grpc_call_error grpc_call_start_batch(grpc_call *call, const grpc_op *ops,
-                                      size_t nops, void *tag, void *reserved);
+GRPCAPI grpc_call_error grpc_call_start_batch(grpc_call *call,
+                                              const grpc_op *ops, size_t nops,
+                                              void *tag, void *reserved);
 
 /** Returns a newly allocated string representing the endpoint to which this
     call is communicating with. The string is in the uri format accepted by
@@ -568,38 +217,36 @@
     WARNING: this value is never authenticated or subject to any security
     related code. It must not be used for any authentication related
     functionality. Instead, use grpc_auth_context. */
-char *grpc_call_get_peer(grpc_call *call);
+GRPCAPI char *grpc_call_get_peer(grpc_call *call);
 
 struct census_context;
 
 /* Set census context for a call; Must be called before first call to
    grpc_call_start_batch(). */
-void grpc_census_call_set_context(grpc_call *call,
-                                  struct census_context *context);
+GRPCAPI void grpc_census_call_set_context(grpc_call *call,
+                                          struct census_context *context);
 
 /* Retrieve the calls current census context. */
-struct census_context *grpc_census_call_get_context(grpc_call *call);
+GRPCAPI struct census_context *grpc_census_call_get_context(grpc_call *call);
 
 /** Return a newly allocated string representing the target a channel was
     created for. */
-char *grpc_channel_get_target(grpc_channel *channel);
+GRPCAPI char *grpc_channel_get_target(grpc_channel *channel);
 
 /** Create a client channel to 'target'. Additional channel level configuration
     MAY be provided by grpc_channel_args, though the expectation is that most
     clients will want to simply pass NULL. See grpc_channel_args definition for
     more on this. The data in 'args' need only live through the invocation of
     this function. */
-grpc_channel *grpc_insecure_channel_create(const char *target,
-                                           const grpc_channel_args *args,
-                                           void *reserved);
+GRPCAPI grpc_channel *grpc_insecure_channel_create(
+    const char *target, const grpc_channel_args *args, void *reserved);
 
 /** Create a lame client: this client fails every operation attempted on it. */
-grpc_channel *grpc_lame_client_channel_create(const char *target,
-                                              grpc_status_code error_code,
-                                              const char *error_message);
+GRPCAPI grpc_channel *grpc_lame_client_channel_create(
+    const char *target, grpc_status_code error_code, const char *error_message);
 
 /** Close and destroy a grpc channel */
-void grpc_channel_destroy(grpc_channel *channel);
+GRPCAPI void grpc_channel_destroy(grpc_channel *channel);
 
 /* Error handling for grpc_call
    Most grpc_call functions return a grpc_error. If the error is not GRPC_OK
@@ -612,7 +259,7 @@
     THREAD-SAFETY grpc_call_cancel and grpc_call_cancel_with_status
     are thread-safe, and can be called at any point before grpc_call_destroy
     is called.*/
-grpc_call_error grpc_call_cancel(grpc_call *call, void *reserved);
+GRPCAPI grpc_call_error grpc_call_cancel(grpc_call *call, void *reserved);
 
 /** Called by clients to cancel an RPC on the server.
     Can be called multiple times, from any thread.
@@ -620,14 +267,13 @@
     and description passed in.
     Importantly, this function does not send status nor description to the
     remote endpoint. */
-grpc_call_error grpc_call_cancel_with_status(grpc_call *call,
-                                             grpc_status_code status,
-                                             const char *description,
-                                             void *reserved);
+GRPCAPI grpc_call_error
+grpc_call_cancel_with_status(grpc_call *call, grpc_status_code status,
+                             const char *description, void *reserved);
 
 /** Destroy a call.
     THREAD SAFETY: grpc_call_destroy is thread-compatible */
-void grpc_call_destroy(grpc_call *call);
+GRPCAPI void grpc_call_destroy(grpc_call *call);
 
 /** Request notification of a new call.
     Once a call is received, a notification tagged with \a tag_new is added to
@@ -637,11 +283,13 @@
     to \a cq_bound_to_call.
     Note that \a cq_for_notification must have been registered to the server via
     \a grpc_server_register_completion_queue. */
-grpc_call_error grpc_server_request_call(
-    grpc_server *server, grpc_call **call, grpc_call_details *details,
-    grpc_metadata_array *request_metadata,
-    grpc_completion_queue *cq_bound_to_call,
-    grpc_completion_queue *cq_for_notification, void *tag_new);
+GRPCAPI grpc_call_error
+grpc_server_request_call(grpc_server *server, grpc_call **call,
+                         grpc_call_details *details,
+                         grpc_metadata_array *request_metadata,
+                         grpc_completion_queue *cq_bound_to_call,
+                         grpc_completion_queue *cq_for_notification,
+                         void *tag_new);
 
 /** Registers a method in the server.
     Methods to this (host, method) pair will not be reported by
@@ -650,13 +298,13 @@
     registered_method (as returned by this function).
     Must be called before grpc_server_start.
     Returns NULL on failure. */
-void *grpc_server_register_method(grpc_server *server, const char *method,
-                                  const char *host);
+GRPCAPI void *grpc_server_register_method(grpc_server *server,
+                                          const char *method, const char *host);
 
 /** Request notification of a new pre-registered call. 'cq_for_notification'
     must have been registered to the server via
     grpc_server_register_completion_queue. */
-grpc_call_error grpc_server_request_registered_call(
+GRPCAPI grpc_call_error grpc_server_request_registered_call(
     grpc_server *server, void *registered_method, grpc_call **call,
     gpr_timespec *deadline, grpc_metadata_array *request_metadata,
     grpc_byte_buffer **optional_payload,
@@ -667,23 +315,25 @@
     be specified with args. If no additional configuration is needed, args can
     be NULL. See grpc_channel_args for more. The data in 'args' need only live
     through the invocation of this function. */
-grpc_server *grpc_server_create(const grpc_channel_args *args, void *reserved);
+GRPCAPI grpc_server *grpc_server_create(const grpc_channel_args *args,
+                                        void *reserved);
 
 /** Register a completion queue with the server. Must be done for any
     notification completion queue that is passed to grpc_server_request_*_call
     and to grpc_server_shutdown_and_notify. Must be performed prior to
     grpc_server_start. */
-void grpc_server_register_completion_queue(grpc_server *server,
-                                           grpc_completion_queue *cq,
-                                           void *reserved);
+GRPCAPI void grpc_server_register_completion_queue(grpc_server *server,
+                                                   grpc_completion_queue *cq,
+                                                   void *reserved);
 
 /** Add a HTTP2 over plaintext over tcp listener.
     Returns bound port number on success, 0 on failure.
     REQUIRES: server not started */
-int grpc_server_add_insecure_http2_port(grpc_server *server, const char *addr);
+GRPCAPI int grpc_server_add_insecure_http2_port(grpc_server *server,
+                                                const char *addr);
 
 /** Start a server - tells all listeners to start listening */
-void grpc_server_start(grpc_server *server);
+GRPCAPI void grpc_server_start(grpc_server *server);
 
 /** Begin shutting down a server.
     After completion, no new calls or connections will be admitted.
@@ -692,18 +342,19 @@
     Shutdown is idempotent, and all tags will be notified at once if multiple
     grpc_server_shutdown_and_notify calls are made. 'cq' must have been
     registered to this server via grpc_server_register_completion_queue. */
-void grpc_server_shutdown_and_notify(grpc_server *server,
-                                     grpc_completion_queue *cq, void *tag);
+GRPCAPI void grpc_server_shutdown_and_notify(grpc_server *server,
+                                             grpc_completion_queue *cq,
+                                             void *tag);
 
 /** Cancel all in-progress calls.
     Only usable after shutdown. */
-void grpc_server_cancel_all_calls(grpc_server *server);
+GRPCAPI void grpc_server_cancel_all_calls(grpc_server *server);
 
 /** Destroy a server.
     Shutdown must have completed beforehand (i.e. all tags generated by
     grpc_server_shutdown_and_notify must have been received, and at least
     one call to grpc_server_shutdown_and_notify must have been made). */
-void grpc_server_destroy(grpc_server *server);
+GRPCAPI void grpc_server_destroy(grpc_server *server);
 
 /** Enable or disable a tracer.
 
@@ -713,17 +364,17 @@
 
     Use of this function is not strictly thread-safe, but the
     thread-safety issues raised by it should not be of concern. */
-int grpc_tracer_set_enabled(const char *name, int enabled);
+GRPCAPI int grpc_tracer_set_enabled(const char *name, int enabled);
 
 /** Check whether a metadata key is legal (will be accepted by core) */
-int grpc_header_key_is_legal(const char *key, size_t length);
+GRPCAPI int grpc_header_key_is_legal(const char *key, size_t length);
 
 /** Check whether a non-binary metadata value is legal (will be accepted by
     core) */
-int grpc_header_nonbin_value_is_legal(const char *value, size_t length);
+GRPCAPI int grpc_header_nonbin_value_is_legal(const char *value, size_t length);
 
 /** Check whether a metadata key corresponds to a binary value */
-int grpc_is_binary_header(const char *key, size_t length);
+GRPCAPI int grpc_is_binary_header(const char *key, size_t length);
 
 #ifdef __cplusplus
 }
diff --git a/include/grpc/grpc_security.h b/include/grpc/grpc_security.h
index 655f45a..3de5cae 100644
--- a/include/grpc/grpc_security.h
+++ b/include/grpc/grpc_security.h
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -65,37 +65,39 @@
 } grpc_auth_property;
 
 /* Returns NULL when the iterator is at the end. */
-const grpc_auth_property *grpc_auth_property_iterator_next(
+GRPCAPI const grpc_auth_property *grpc_auth_property_iterator_next(
     grpc_auth_property_iterator *it);
 
 /* Iterates over the auth context. */
-grpc_auth_property_iterator grpc_auth_context_property_iterator(
-    const grpc_auth_context *ctx);
+GRPCAPI grpc_auth_property_iterator
+grpc_auth_context_property_iterator(const grpc_auth_context *ctx);
 
 /* Gets the peer identity. Returns an empty iterator (first _next will return
    NULL) if the peer is not authenticated. */
-grpc_auth_property_iterator grpc_auth_context_peer_identity(
-    const grpc_auth_context *ctx);
+GRPCAPI grpc_auth_property_iterator
+grpc_auth_context_peer_identity(const grpc_auth_context *ctx);
 
 /* Finds a property in the context. May return an empty iterator (first _next
    will return NULL) if no property with this name was found in the context. */
-grpc_auth_property_iterator grpc_auth_context_find_properties_by_name(
-    const grpc_auth_context *ctx, const char *name);
+GRPCAPI grpc_auth_property_iterator
+grpc_auth_context_find_properties_by_name(const grpc_auth_context *ctx,
+                                          const char *name);
 
 /* Gets the name of the property that indicates the peer identity. Will return
    NULL if the peer is not authenticated. */
-const char *grpc_auth_context_peer_identity_property_name(
+GRPCAPI const char *grpc_auth_context_peer_identity_property_name(
     const grpc_auth_context *ctx);
 
 /* Returns 1 if the peer is authenticated, 0 otherwise. */
-int grpc_auth_context_peer_is_authenticated(const grpc_auth_context *ctx);
+GRPCAPI int grpc_auth_context_peer_is_authenticated(
+    const grpc_auth_context *ctx);
 
 /* Gets the auth context from the call. Caller needs to call
    grpc_auth_context_release on the returned context. */
-grpc_auth_context *grpc_call_auth_context(grpc_call *call);
+GRPCAPI grpc_auth_context *grpc_call_auth_context(grpc_call *call);
 
 /* Releases the auth context returned from grpc_call_auth_context. */
-void grpc_auth_context_release(grpc_auth_context *context);
+GRPCAPI void grpc_auth_context_release(grpc_auth_context *context);
 
 /* --
    The following auth context methods should only be called by a server metadata
@@ -103,18 +105,19 @@
    -- */
 
 /* Add a property. */
-void grpc_auth_context_add_property(grpc_auth_context *ctx, const char *name,
-                                    const char *value, size_t value_length);
+GRPCAPI void grpc_auth_context_add_property(grpc_auth_context *ctx,
+                                            const char *name, const char *value,
+                                            size_t value_length);
 
 /* Add a C string property. */
-void grpc_auth_context_add_cstring_property(grpc_auth_context *ctx,
-                                            const char *name,
-                                            const char *value);
+GRPCAPI void grpc_auth_context_add_cstring_property(grpc_auth_context *ctx,
+                                                    const char *name,
+                                                    const char *value);
 
 /* Sets the property name. Returns 1 if successful or 0 in case of failure
    (which means that no property with this name exists). */
-int grpc_auth_context_set_peer_identity_property_name(grpc_auth_context *ctx,
-                                                      const char *name);
+GRPCAPI int grpc_auth_context_set_peer_identity_property_name(
+    grpc_auth_context *ctx, const char *name);
 
 /* --- grpc_channel_credentials object. ---
 
@@ -125,7 +128,7 @@
 
 /* Releases a channel credentials object.
    The creator of the credentials object is responsible for its release. */
-void grpc_channel_credentials_release(grpc_channel_credentials *creds);
+GRPCAPI void grpc_channel_credentials_release(grpc_channel_credentials *creds);
 
 /* Environment variable that points to the google default application
    credentials json key or refresh token. Used in the
@@ -135,7 +138,7 @@
 /* Creates default credentials to connect to a google gRPC service.
    WARNING: Do NOT use this credentials to connect to a non-google service as
    this could result in an oauth2 token leak. */
-grpc_channel_credentials *grpc_google_default_credentials_create(void);
+GRPCAPI grpc_channel_credentials *grpc_google_default_credentials_create(void);
 
 /* Environment variable that points to the default SSL roots file. This file
    must be a PEM encoded file with all the roots such as the one that can be
@@ -143,6 +146,29 @@
 #define GRPC_DEFAULT_SSL_ROOTS_FILE_PATH_ENV_VAR \
   "GRPC_DEFAULT_SSL_ROOTS_FILE_PATH"
 
+/* Results for the SSL roots override callback. */
+typedef enum {
+  GRPC_SSL_ROOTS_OVERRIDE_OK,
+  GRPC_SSL_ROOTS_OVERRIDE_FAIL_PERMANENTLY, /* Do not try fallback options. */
+  GRPC_SSL_ROOTS_OVERRIDE_FAIL
+} grpc_ssl_roots_override_result;
+
+/* Callback for getting the SSL roots override from the application.
+   In case of success, *pem_roots_certs must be set to a NULL terminated string
+   containing the list of PEM encoded root certificates. The ownership is passed
+   to the core and freed (laster by the core) with gpr_free.
+   If this function fails and GRPC_DEFAULT_SSL_ROOTS_FILE_PATH environment is
+   set to a valid path, it will override the roots specified this func */
+typedef grpc_ssl_roots_override_result (*grpc_ssl_roots_override_callback)(
+    char **pem_root_certs);
+
+/* Setup a callback to override the default TLS/SSL roots.
+   This function is not thread-safe and must be called at initialization time
+   before any ssl credentials are created to have the desired side effect.
+   If GRPC_DEFAULT_SSL_ROOTS_FILE_PATH environment is set to a valid path, the
+   callback will not be called. */
+void grpc_set_ssl_roots_override_callback(grpc_ssl_roots_override_callback cb);
+
 /* Object that holds a private key / certificate chain pair in PEM format. */
 typedef struct {
   /* private_key is the NULL-terminated string containing the PEM encoding of
@@ -159,12 +185,13 @@
      of the server root certificates. If this parameter is NULL, the
      implementation will first try to dereference the file pointed by the
      GRPC_DEFAULT_SSL_ROOTS_FILE_PATH environment variable, and if that fails,
-     get the roots from a well-known place on disk (in the grpc install
-     directory).
+     try to get the roots set by grpc_override_ssl_default_roots. Eventually,
+     if all these fail, it will try to get the roots from a well-known place on
+     disk (in the grpc install directory).
    - pem_key_cert_pair is a pointer on the object containing client's private
      key and certificate chain. This parameter can be NULL if the client does
      not have such a key/cert pair. */
-grpc_channel_credentials *grpc_ssl_credentials_create(
+GRPCAPI grpc_channel_credentials *grpc_ssl_credentials_create(
     const char *pem_root_certs, grpc_ssl_pem_key_cert_pair *pem_key_cert_pair,
     void *reserved);
 
@@ -178,33 +205,35 @@
 
 /* Releases a call credentials object.
    The creator of the credentials object is responsible for its release. */
-void grpc_call_credentials_release(grpc_call_credentials *creds);
+GRPCAPI void grpc_call_credentials_release(grpc_call_credentials *creds);
 
 /* Creates a composite channel credentials object. */
-grpc_channel_credentials *grpc_composite_channel_credentials_create(
+GRPCAPI grpc_channel_credentials *grpc_composite_channel_credentials_create(
     grpc_channel_credentials *channel_creds, grpc_call_credentials *call_creds,
     void *reserved);
 
 /* Creates a composite call credentials object. */
-grpc_call_credentials *grpc_composite_call_credentials_create(
+GRPCAPI grpc_call_credentials *grpc_composite_call_credentials_create(
     grpc_call_credentials *creds1, grpc_call_credentials *creds2,
     void *reserved);
 
 /* Creates a compute engine credentials object for connecting to Google.
    WARNING: Do NOT use this credentials to connect to a non-google service as
    this could result in an oauth2 token leak. */
-grpc_call_credentials *grpc_google_compute_engine_credentials_create(
+GRPCAPI grpc_call_credentials *grpc_google_compute_engine_credentials_create(
     void *reserved);
 
-extern const gpr_timespec grpc_max_auth_token_lifetime;
+GRPCAPI gpr_timespec grpc_max_auth_token_lifetime();
 
 /* Creates a JWT credentials object. May return NULL if the input is invalid.
    - json_key is the JSON key string containing the client's private key.
    - token_lifetime is the lifetime of each Json Web Token (JWT) created with
      this credentials.  It should not exceed grpc_max_auth_token_lifetime or
      will be cropped to this value.  */
-grpc_call_credentials *grpc_service_account_jwt_access_credentials_create(
-    const char *json_key, gpr_timespec token_lifetime, void *reserved);
+GRPCAPI grpc_call_credentials *
+grpc_service_account_jwt_access_credentials_create(const char *json_key,
+                                                   gpr_timespec token_lifetime,
+                                                   void *reserved);
 
 /* Creates an Oauth2 Refresh Token credentials object for connecting to Google.
    May return NULL if the input is invalid.
@@ -212,16 +241,16 @@
    this could result in an oauth2 token leak.
    - json_refresh_token is the JSON string containing the refresh token itself
      along with a client_id and client_secret. */
-grpc_call_credentials *grpc_google_refresh_token_credentials_create(
+GRPCAPI grpc_call_credentials *grpc_google_refresh_token_credentials_create(
     const char *json_refresh_token, void *reserved);
 
 /* Creates an Oauth2 Access Token credentials with an access token that was
    aquired by an out of band mechanism. */
-grpc_call_credentials *grpc_access_token_credentials_create(
+GRPCAPI grpc_call_credentials *grpc_access_token_credentials_create(
     const char *access_token, void *reserved);
 
 /* Creates an IAM credentials object for connecting to Google. */
-grpc_call_credentials *grpc_google_iam_credentials_create(
+GRPCAPI grpc_call_credentials *grpc_google_iam_credentials_create(
     const char *authorization_token, const char *authority_selector,
     void *reserved);
 
@@ -283,16 +312,15 @@
 } grpc_metadata_credentials_plugin;
 
 /* Creates a credentials object from a plugin. */
-grpc_call_credentials *grpc_metadata_credentials_create_from_plugin(
+GRPCAPI grpc_call_credentials *grpc_metadata_credentials_create_from_plugin(
     grpc_metadata_credentials_plugin plugin, void *reserved);
 
 /* --- Secure channel creation. --- */
 
 /* Creates a secure channel using the passed-in credentials. */
-grpc_channel *grpc_secure_channel_create(grpc_channel_credentials *creds,
-                                         const char *target,
-                                         const grpc_channel_args *args,
-                                         void *reserved);
+GRPCAPI grpc_channel *grpc_secure_channel_create(
+    grpc_channel_credentials *creds, const char *target,
+    const grpc_channel_args *args, void *reserved);
 
 /* --- grpc_server_credentials object. ---
 
@@ -303,7 +331,7 @@
 /* Releases a server_credentials object.
    The creator of the server_credentials object is responsible for its release.
    */
-void grpc_server_credentials_release(grpc_server_credentials *creds);
+GRPCAPI void grpc_server_credentials_release(grpc_server_credentials *creds);
 
 /* Creates an SSL server_credentials object.
    - pem_roots_cert is the NULL-terminated string containing the PEM encoding of
@@ -316,7 +344,7 @@
    - force_client_auth, if set to non-zero will force the client to authenticate
      with an SSL cert. Note that this option is ignored if pem_root_certs is
      NULL. */
-grpc_server_credentials *grpc_ssl_server_credentials_create(
+GRPCAPI grpc_server_credentials *grpc_ssl_server_credentials_create(
     const char *pem_root_certs, grpc_ssl_pem_key_cert_pair *pem_key_cert_pairs,
     size_t num_key_cert_pairs, int force_client_auth, void *reserved);
 
@@ -325,15 +353,16 @@
 /* Add a HTTP2 over an encrypted link over tcp listener.
    Returns bound port number on success, 0 on failure.
    REQUIRES: server not started */
-int grpc_server_add_secure_http2_port(grpc_server *server, const char *addr,
-                                      grpc_server_credentials *creds);
+GRPCAPI int grpc_server_add_secure_http2_port(grpc_server *server,
+                                              const char *addr,
+                                              grpc_server_credentials *creds);
 
 /* --- Call specific credentials. --- */
 
 /* Sets a credentials to a call. Can only be called on the client side before
    grpc_call_start_batch. */
-grpc_call_error grpc_call_set_credentials(grpc_call *call,
-                                          grpc_call_credentials *creds);
+GRPCAPI grpc_call_error
+grpc_call_set_credentials(grpc_call *call, grpc_call_credentials *creds);
 
 /* --- Auth Metadata Processing --- */
 
@@ -364,7 +393,7 @@
   void *state;
 } grpc_auth_metadata_processor;
 
-void grpc_server_credentials_set_auth_metadata_processor(
+GRPCAPI void grpc_server_credentials_set_auth_metadata_processor(
     grpc_server_credentials *creds, grpc_auth_metadata_processor processor);
 
 #ifdef __cplusplus
diff --git a/include/grpc/grpc_zookeeper.h b/include/grpc/grpc_zookeeper.h
index 2b195c1..b23bd88 100644
--- a/include/grpc/grpc_zookeeper.h
+++ b/include/grpc/grpc_zookeeper.h
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff --git a/include/grpc/impl/codegen/alloc.h b/include/grpc/impl/codegen/alloc.h
new file mode 100644
index 0000000..2351354
--- /dev/null
+++ b/include/grpc/impl/codegen/alloc.h
@@ -0,0 +1,74 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef GRPC_IMPL_CODEGEN_ALLOC_H
+#define GRPC_IMPL_CODEGEN_ALLOC_H
+
+#include <stddef.h>
+
+#include <grpc/impl/codegen/port_platform.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct gpr_allocation_functions {
+  void *(*malloc_fn)(size_t size);
+  void *(*realloc_fn)(void *ptr, size_t size);
+  void (*free_fn)(void *ptr);
+} gpr_allocation_functions;
+
+/* malloc, never returns NULL */
+GPRAPI void *gpr_malloc(size_t size);
+/* free */
+GPRAPI void gpr_free(void *ptr);
+/* realloc, never returns NULL */
+GPRAPI void *gpr_realloc(void *p, size_t size);
+/* aligned malloc, never returns NULL, will align to 1 << alignment_log */
+GPRAPI void *gpr_malloc_aligned(size_t size, size_t alignment_log);
+/* free memory allocated by gpr_malloc_aligned */
+GPRAPI void gpr_free_aligned(void *ptr);
+
+/** Request the family of allocation functions in \a functions be used. NOTE
+ * that this request will be honored in a *best effort* basis and that no
+ * guarantees are made about the default functions (eg, malloc) being called. */
+GPRAPI void gpr_set_allocation_functions(gpr_allocation_functions functions);
+
+/** Return the family of allocation functions currently in effect. */
+GPRAPI gpr_allocation_functions gpr_get_allocation_functions();
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* GRPC_IMPL_CODEGEN_ALLOC_H */
diff --git a/include/grpc/impl/codegen/atm.h b/include/grpc/impl/codegen/atm.h
new file mode 100644
index 0000000..35b9750
--- /dev/null
+++ b/include/grpc/impl/codegen/atm.h
@@ -0,0 +1,92 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef GRPC_IMPL_CODEGEN_ATM_H
+#define GRPC_IMPL_CODEGEN_ATM_H
+
+/* This interface provides atomic operations and barriers.
+   It is internal to gpr support code and should not be used outside it.
+
+   If an operation with acquire semantics precedes another memory access by the
+   same thread, the operation will precede that other access as seen by other
+   threads.
+
+   If an operation with release semantics follows another memory access by the
+   same thread, the operation will follow that other access as seen by other
+   threads.
+
+   Routines with "acq" or "full" in the name have acquire semantics.  Routines
+   with "rel" or "full" in the name have release semantics.  Routines with
+   "no_barrier" in the name have neither acquire not release semantics.
+
+   The routines may be implemented as macros.
+
+   // Atomic operations act on an intergral_type gpr_atm that is guaranteed to
+   // be the same size as a pointer.
+   typedef intptr_t gpr_atm;
+
+   // A memory barrier, providing both acquire and release semantics, but not
+   // otherwise acting on memory.
+   void gpr_atm_full_barrier(void);
+
+   // Atomically return *p, with acquire semantics.
+   gpr_atm gpr_atm_acq_load(gpr_atm *p);
+
+   // Atomically set *p = value, with release semantics.
+   void gpr_atm_rel_store(gpr_atm *p, gpr_atm value);
+
+   // Atomically add delta to *p, and return the old value of *p, with
+   // the barriers specified.
+   gpr_atm gpr_atm_no_barrier_fetch_add(gpr_atm *p, gpr_atm delta);
+   gpr_atm gpr_atm_full_fetch_add(gpr_atm *p, gpr_atm delta);
+
+   // Atomically, if *p==o, set *p=n and return non-zero otherwise return 0,
+   // with the barriers specified if the operation succeeds.
+   int gpr_atm_no_barrier_cas(gpr_atm *p, gpr_atm o, gpr_atm n);
+   int gpr_atm_acq_cas(gpr_atm *p, gpr_atm o, gpr_atm n);
+   int gpr_atm_rel_cas(gpr_atm *p, gpr_atm o, gpr_atm n);
+*/
+
+#include <grpc/impl/codegen/port_platform.h>
+
+#if defined(GPR_GCC_ATOMIC)
+#include <grpc/impl/codegen/atm_gcc_atomic.h>
+#elif defined(GPR_GCC_SYNC)
+#include <grpc/impl/codegen/atm_gcc_sync.h>
+#elif defined(GPR_WIN32_ATOMIC)
+#include <grpc/impl/codegen/atm_win32.h>
+#else
+#error could not determine platform for atm
+#endif
+
+#endif /* GRPC_IMPL_CODEGEN_ATM_H */
diff --git a/include/grpc/impl/codegen/atm_gcc_atomic.h b/include/grpc/impl/codegen/atm_gcc_atomic.h
new file mode 100644
index 0000000..196d2ae
--- /dev/null
+++ b/include/grpc/impl/codegen/atm_gcc_atomic.h
@@ -0,0 +1,72 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef GRPC_IMPL_CODEGEN_ATM_GCC_ATOMIC_H
+#define GRPC_IMPL_CODEGEN_ATM_GCC_ATOMIC_H
+
+/* atm_platform.h for gcc and gcc-like compilers with the
+   __atomic_* interface.  */
+#include <grpc/impl/codegen/port_platform.h>
+
+typedef intptr_t gpr_atm;
+
+#define gpr_atm_full_barrier() (__atomic_thread_fence(__ATOMIC_SEQ_CST))
+
+#define gpr_atm_acq_load(p) (__atomic_load_n((p), __ATOMIC_ACQUIRE))
+#define gpr_atm_no_barrier_load(p) (__atomic_load_n((p), __ATOMIC_RELAXED))
+#define gpr_atm_rel_store(p, value) \
+  (__atomic_store_n((p), (intptr_t)(value), __ATOMIC_RELEASE))
+#define gpr_atm_no_barrier_store(p, value) \
+  (__atomic_store_n((p), (intptr_t)(value), __ATOMIC_RELAXED))
+
+#define gpr_atm_no_barrier_fetch_add(p, delta) \
+  (__atomic_fetch_add((p), (intptr_t)(delta), __ATOMIC_RELAXED))
+#define gpr_atm_full_fetch_add(p, delta) \
+  (__atomic_fetch_add((p), (intptr_t)(delta), __ATOMIC_ACQ_REL))
+
+static __inline int gpr_atm_no_barrier_cas(gpr_atm *p, gpr_atm o, gpr_atm n) {
+  return __atomic_compare_exchange_n(p, &o, n, 0, __ATOMIC_RELAXED,
+                                     __ATOMIC_RELAXED);
+}
+
+static __inline int gpr_atm_acq_cas(gpr_atm *p, gpr_atm o, gpr_atm n) {
+  return __atomic_compare_exchange_n(p, &o, n, 0, __ATOMIC_ACQUIRE,
+                                     __ATOMIC_RELAXED);
+}
+
+static __inline int gpr_atm_rel_cas(gpr_atm *p, gpr_atm o, gpr_atm n) {
+  return __atomic_compare_exchange_n(p, &o, n, 0, __ATOMIC_RELEASE,
+                                     __ATOMIC_RELAXED);
+}
+
+#endif /* GRPC_IMPL_CODEGEN_ATM_GCC_ATOMIC_H */
diff --git a/include/grpc/impl/codegen/atm_gcc_sync.h b/include/grpc/impl/codegen/atm_gcc_sync.h
new file mode 100644
index 0000000..56f7559
--- /dev/null
+++ b/include/grpc/impl/codegen/atm_gcc_sync.h
@@ -0,0 +1,87 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef GRPC_IMPL_CODEGEN_ATM_GCC_SYNC_H
+#define GRPC_IMPL_CODEGEN_ATM_GCC_SYNC_H
+
+/* variant of atm_platform.h for gcc and gcc-like compiers with __sync_*
+   interface */
+#include <grpc/impl/codegen/port_platform.h>
+
+typedef intptr_t gpr_atm;
+
+#define GPR_ATM_COMPILE_BARRIER_() __asm__ __volatile__("" : : : "memory")
+
+#if defined(__i386) || defined(__x86_64__)
+/* All loads are acquire loads and all stores are release stores.  */
+#define GPR_ATM_LS_BARRIER_() GPR_ATM_COMPILE_BARRIER_()
+#else
+#define GPR_ATM_LS_BARRIER_() gpr_atm_full_barrier()
+#endif
+
+#define gpr_atm_full_barrier() (__sync_synchronize())
+
+static __inline gpr_atm gpr_atm_acq_load(const gpr_atm *p) {
+  gpr_atm value = *p;
+  GPR_ATM_LS_BARRIER_();
+  return value;
+}
+
+static __inline gpr_atm gpr_atm_no_barrier_load(const gpr_atm *p) {
+  gpr_atm value = *p;
+  GPR_ATM_COMPILE_BARRIER_();
+  return value;
+}
+
+static __inline void gpr_atm_rel_store(gpr_atm *p, gpr_atm value) {
+  GPR_ATM_LS_BARRIER_();
+  *p = value;
+}
+
+static __inline void gpr_atm_no_barrier_store(gpr_atm *p, gpr_atm value) {
+  GPR_ATM_COMPILE_BARRIER_();
+  *p = value;
+}
+
+#undef GPR_ATM_LS_BARRIER_
+#undef GPR_ATM_COMPILE_BARRIER_
+
+#define gpr_atm_no_barrier_fetch_add(p, delta) \
+  gpr_atm_full_fetch_add((p), (delta))
+#define gpr_atm_full_fetch_add(p, delta) (__sync_fetch_and_add((p), (delta)))
+
+#define gpr_atm_no_barrier_cas(p, o, n) gpr_atm_acq_cas((p), (o), (n))
+#define gpr_atm_acq_cas(p, o, n) (__sync_bool_compare_and_swap((p), (o), (n)))
+#define gpr_atm_rel_cas(p, o, n) gpr_atm_acq_cas((p), (o), (n))
+
+#endif /* GRPC_IMPL_CODEGEN_ATM_GCC_SYNC_H */
diff --git a/include/grpc/impl/codegen/atm_win32.h b/include/grpc/impl/codegen/atm_win32.h
new file mode 100644
index 0000000..9d26462
--- /dev/null
+++ b/include/grpc/impl/codegen/atm_win32.h
@@ -0,0 +1,125 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef GRPC_IMPL_CODEGEN_ATM_WIN32_H
+#define GRPC_IMPL_CODEGEN_ATM_WIN32_H
+
+/* Win32 variant of atm_platform.h */
+#include <grpc/impl/codegen/port_platform.h>
+
+typedef intptr_t gpr_atm;
+
+#define gpr_atm_full_barrier MemoryBarrier
+
+static __inline gpr_atm gpr_atm_acq_load(const gpr_atm *p) {
+  gpr_atm result = *p;
+  gpr_atm_full_barrier();
+  return result;
+}
+
+static __inline gpr_atm gpr_atm_no_barrier_load(const gpr_atm *p) {
+  /* TODO(dklempner): Can we implement something better here? */
+  return gpr_atm_acq_load(p);
+}
+
+static __inline void gpr_atm_rel_store(gpr_atm *p, gpr_atm value) {
+  gpr_atm_full_barrier();
+  *p = value;
+}
+
+static __inline void gpr_atm_no_barrier_store(gpr_atm *p, gpr_atm value) {
+  /* TODO(ctiller): Can we implement something better here? */
+  gpr_atm_rel_store(p, value);
+}
+
+static __inline int gpr_atm_no_barrier_cas(gpr_atm *p, gpr_atm o, gpr_atm n) {
+/* InterlockedCompareExchangePointerNoFence() not available on vista or
+   windows7 */
+#ifdef GPR_ARCH_64
+  return o == (gpr_atm)InterlockedCompareExchangeAcquire64(
+                  (volatile LONGLONG *)p, (LONGLONG)n, (LONGLONG)o);
+#else
+  return o == (gpr_atm)InterlockedCompareExchangeAcquire((volatile LONG *)p,
+                                                         (LONG)n, (LONG)o);
+#endif
+}
+
+static __inline int gpr_atm_acq_cas(gpr_atm *p, gpr_atm o, gpr_atm n) {
+#ifdef GPR_ARCH_64
+  return o == (gpr_atm)InterlockedCompareExchangeAcquire64(
+                  (volatile LONGLONG *)p, (LONGLONG)n, (LONGLONG)o);
+#else
+  return o == (gpr_atm)InterlockedCompareExchangeAcquire((volatile LONG *)p,
+                                                         (LONG)n, (LONG)o);
+#endif
+}
+
+static __inline int gpr_atm_rel_cas(gpr_atm *p, gpr_atm o, gpr_atm n) {
+#ifdef GPR_ARCH_64
+  return o == (gpr_atm)InterlockedCompareExchangeRelease64(
+                  (volatile LONGLONG *)p, (LONGLONG)n, (LONGLONG)o);
+#else
+  return o == (gpr_atm)InterlockedCompareExchangeRelease((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 */
+  gpr_atm old;
+  do {
+    old = *p;
+  } while (!gpr_atm_no_barrier_cas(p, old, old + delta));
+  return old;
+}
+
+static __inline gpr_atm gpr_atm_full_fetch_add(gpr_atm *p, gpr_atm delta) {
+  /* Use a CAS operation to get pointer-sized fetch and add */
+  gpr_atm old;
+#ifdef GPR_ARCH_64
+  do {
+    old = *p;
+  } while (old != (gpr_atm)InterlockedCompareExchange64((volatile LONGLONG *)p,
+                                                        (LONGLONG)old + delta,
+                                                        (LONGLONG)old));
+#else
+  do {
+    old = *p;
+  } while (old != (gpr_atm)InterlockedCompareExchange(
+                      (volatile LONG *)p, (LONG)old + delta, (LONG)old));
+#endif
+  return old;
+}
+
+#endif /* GRPC_IMPL_CODEGEN_ATM_WIN32_H */
diff --git a/include/grpc/impl/codegen/byte_buffer.h b/include/grpc/impl/codegen/byte_buffer.h
new file mode 100644
index 0000000..9e96d4b
--- /dev/null
+++ b/include/grpc/impl/codegen/byte_buffer.h
@@ -0,0 +1,121 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef GRPC_IMPL_CODEGEN_BYTE_BUFFER_H
+#define GRPC_IMPL_CODEGEN_BYTE_BUFFER_H
+
+#include <grpc/impl/codegen/compression_types.h>
+#include <grpc/impl/codegen/slice_buffer.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef enum {
+  GRPC_BB_RAW
+  /* Future types may include GRPC_BB_PROTOBUF, etc. */
+} grpc_byte_buffer_type;
+
+struct grpc_byte_buffer {
+  void *reserved;
+  grpc_byte_buffer_type type;
+  union {
+    struct {
+      void *reserved[8];
+    } reserved;
+    struct {
+      grpc_compression_algorithm compression;
+      gpr_slice_buffer slice_buffer;
+    } raw;
+  } data;
+};
+typedef struct grpc_byte_buffer grpc_byte_buffer;
+
+/** Returns a RAW byte buffer instance over the given slices (up to \a nslices).
+ *
+ * Increases the reference count for all \a slices processed. The user is
+ * responsible for invoking grpc_byte_buffer_destroy on the returned instance.*/
+GRPCAPI grpc_byte_buffer *grpc_raw_byte_buffer_create(gpr_slice *slices,
+                                                      size_t nslices);
+
+/** Returns a *compressed* RAW byte buffer instance over the given slices (up to
+ * \a nslices). The \a compression argument defines the compression algorithm
+ * used to generate the data in \a slices.
+ *
+ * Increases the reference count for all \a slices processed. The user is
+ * responsible for invoking grpc_byte_buffer_destroy on the returned instance.*/
+GRPCAPI grpc_byte_buffer *grpc_raw_compressed_byte_buffer_create(
+    gpr_slice *slices, size_t nslices, grpc_compression_algorithm compression);
+
+/** Copies input byte buffer \a bb.
+ *
+ * Increases the reference count of all the source slices. The user is
+ * responsible for calling grpc_byte_buffer_destroy over the returned copy. */
+GRPCAPI grpc_byte_buffer *grpc_byte_buffer_copy(grpc_byte_buffer *bb);
+
+/** Returns the size of the given byte buffer, in bytes. */
+GRPCAPI size_t grpc_byte_buffer_length(grpc_byte_buffer *bb);
+
+/** Destroys \a byte_buffer deallocating all its memory. */
+GRPCAPI void grpc_byte_buffer_destroy(grpc_byte_buffer *byte_buffer);
+
+/** Reader for byte buffers. Iterates over slices in the byte buffer */
+struct grpc_byte_buffer_reader;
+typedef struct grpc_byte_buffer_reader grpc_byte_buffer_reader;
+
+/** Initialize \a reader to read over \a buffer */
+GRPCAPI void grpc_byte_buffer_reader_init(grpc_byte_buffer_reader *reader,
+                                          grpc_byte_buffer *buffer);
+
+/** Cleanup and destroy \a reader */
+GRPCAPI void grpc_byte_buffer_reader_destroy(grpc_byte_buffer_reader *reader);
+
+/** Updates \a slice with the next piece of data from from \a reader and returns
+ * 1. Returns 0 at the end of the stream. Caller is responsible for calling
+ * gpr_slice_unref on the result. */
+GRPCAPI int grpc_byte_buffer_reader_next(grpc_byte_buffer_reader *reader,
+                                         gpr_slice *slice);
+
+/** Merge all data from \a reader into single slice */
+GRPCAPI gpr_slice
+grpc_byte_buffer_reader_readall(grpc_byte_buffer_reader *reader);
+
+/** Returns a RAW byte buffer instance from the output of \a reader. */
+GRPCAPI grpc_byte_buffer *grpc_raw_byte_buffer_from_reader(
+    grpc_byte_buffer_reader *reader);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* GRPC_IMPL_CODEGEN_BYTE_BUFFER_H */
diff --git a/include/grpc/impl/codegen/compression_types.h b/include/grpc/impl/codegen/compression_types.h
new file mode 100644
index 0000000..0daccd9
--- /dev/null
+++ b/include/grpc/impl/codegen/compression_types.h
@@ -0,0 +1,73 @@
+/*
+ *
+ * Copyright 2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef GRPC_IMPL_CODEGEN_COMPRESSION_TYPES_H
+#define GRPC_IMPL_CODEGEN_COMPRESSION_TYPES_H
+
+#include <grpc/impl/codegen/port_platform.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** To be used in channel arguments */
+#define GRPC_COMPRESSION_ALGORITHM_ARG "grpc.compression_algorithm"
+#define GRPC_COMPRESSION_ALGORITHM_STATE_ARG "grpc.compression_algorithm_state"
+
+/* The various compression algorithms supported by GRPC */
+typedef enum {
+  GRPC_COMPRESS_NONE = 0,
+  GRPC_COMPRESS_DEFLATE,
+  GRPC_COMPRESS_GZIP,
+  /* TODO(ctiller): snappy */
+  GRPC_COMPRESS_ALGORITHMS_COUNT
+} grpc_compression_algorithm;
+
+typedef enum {
+  GRPC_COMPRESS_LEVEL_NONE = 0,
+  GRPC_COMPRESS_LEVEL_LOW,
+  GRPC_COMPRESS_LEVEL_MED,
+  GRPC_COMPRESS_LEVEL_HIGH,
+  GRPC_COMPRESS_LEVEL_COUNT
+} grpc_compression_level;
+
+typedef struct grpc_compression_options {
+  uint32_t enabled_algorithms_bitset; /**< All algs are enabled by default */
+  grpc_compression_algorithm default_compression_algorithm; /**< for channel */
+} grpc_compression_options;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* GRPC_IMPL_CODEGEN_COMPRESSION_TYPES_H */
diff --git a/src/objective-c/GRPCClient/private/GRPCUnsecuredChannel.h b/include/grpc/impl/codegen/connectivity_state.h
similarity index 68%
copy from src/objective-c/GRPCClient/private/GRPCUnsecuredChannel.h
copy to include/grpc/impl/codegen/connectivity_state.h
index 8528be4..5bb9eb8 100644
--- a/src/objective-c/GRPCClient/private/GRPCUnsecuredChannel.h
+++ b/include/grpc/impl/codegen/connectivity_state.h
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -31,8 +31,29 @@
  *
  */
 
-#import "GRPCChannel.h"
+#ifndef GRPC_IMPL_CODEGEN_CONNECTIVITY_STATE_H
+#define GRPC_IMPL_CODEGEN_CONNECTIVITY_STATE_H
 
-@interface GRPCUnsecuredChannel : GRPCChannel
-- (instancetype)initWithHost:(NSString *)host NS_DESIGNATED_INITIALIZER;
-@end
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** Connectivity state of a channel. */
+typedef enum {
+  /** channel is idle */
+  GRPC_CHANNEL_IDLE,
+  /** channel is connecting */
+  GRPC_CHANNEL_CONNECTING,
+  /** channel is ready for work */
+  GRPC_CHANNEL_READY,
+  /** channel has seen a failure but expects to recover */
+  GRPC_CHANNEL_TRANSIENT_FAILURE,
+  /** channel has seen a failure that it cannot recover from */
+  GRPC_CHANNEL_FATAL_FAILURE
+} grpc_connectivity_state;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* GRPC_IMPL_CODEGEN_CONNECTIVITY_STATE_H */
diff --git a/include/grpc/impl/codegen/grpc_types.h b/include/grpc/impl/codegen/grpc_types.h
new file mode 100644
index 0000000..ea1e96c
--- /dev/null
+++ b/include/grpc/impl/codegen/grpc_types.h
@@ -0,0 +1,373 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef GRPC_IMPL_CODEGEN_GRPC_TYPES_H
+#define GRPC_IMPL_CODEGEN_GRPC_TYPES_H
+
+#include <grpc/impl/codegen/byte_buffer.h>
+#include <grpc/impl/codegen/status.h>
+
+#include <stddef.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** Completion Queues enable notification of the completion of asynchronous
+    actions. */
+typedef struct grpc_completion_queue grpc_completion_queue;
+
+/** An alarm associated with a completion queue. */
+typedef struct grpc_alarm grpc_alarm;
+
+/** The Channel interface allows creation of Call objects. */
+typedef struct grpc_channel grpc_channel;
+
+/** A server listens to some port and responds to request calls */
+typedef struct grpc_server grpc_server;
+
+/** A Call represents an RPC. When created, it is in a configuration state
+    allowing properties to be set until it is invoked. After invoke, the Call
+    can have messages written to it and read from it. */
+typedef struct grpc_call grpc_call;
+
+/** Type specifier for grpc_arg */
+typedef enum {
+  GRPC_ARG_STRING,
+  GRPC_ARG_INTEGER,
+  GRPC_ARG_POINTER
+} grpc_arg_type;
+
+/** A single argument... each argument has a key and a value
+
+    A note on naming keys:
+      Keys are namespaced into groups, usually grouped by library, and are
+      keys for module XYZ are named XYZ.key1, XYZ.key2, etc. Module names must
+      be restricted to the regex [A-Za-z][_A-Za-z0-9]{,15}.
+      Key names must be restricted to the regex [A-Za-z][_A-Za-z0-9]{,47}.
+
+    GRPC core library keys are prefixed by grpc.
+
+    Library authors are strongly encouraged to \#define symbolic constants for
+    their keys so that it's possible to change them in the future. */
+typedef struct {
+  grpc_arg_type type;
+  char *key;
+  union {
+    char *string;
+    int integer;
+    struct {
+      void *p;
+      void *(*copy)(void *p);
+      void (*destroy)(void *p);
+    } pointer;
+  } value;
+} grpc_arg;
+
+/** An array of arguments that can be passed around.
+
+    Used to set optional channel-level configuration.
+    These configuration options are modelled as key-value pairs as defined
+    by grpc_arg; keys are strings to allow easy backwards-compatible extension
+    by arbitrary parties.
+    All evaluation is performed at channel creation time (i.e. the values in
+    this structure need only live through the creation invocation). */
+typedef struct {
+  size_t num_args;
+  grpc_arg *args;
+} grpc_channel_args;
+
+/* Channel argument keys: */
+/** Enable census for tracing and stats collection */
+#define GRPC_ARG_ENABLE_CENSUS "grpc.census"
+/** Maximum number of concurrent incoming streams to allow on a http2
+    connection */
+#define GRPC_ARG_MAX_CONCURRENT_STREAMS "grpc.max_concurrent_streams"
+/** Maximum message length that the channel can receive */
+#define GRPC_ARG_MAX_MESSAGE_LENGTH "grpc.max_message_length"
+/** Initial sequence number for http2 transports */
+#define GRPC_ARG_HTTP2_INITIAL_SEQUENCE_NUMBER \
+  "grpc.http2.initial_sequence_number"
+/** Amount to read ahead on individual streams. Defaults to 64kb, larger
+    values can help throughput on high-latency connections.
+    NOTE: at some point we'd like to auto-tune this, and this parameter
+    will become a no-op. */
+#define GRPC_ARG_HTTP2_STREAM_LOOKAHEAD_BYTES "grpc.http2.lookahead_bytes"
+/** How much memory to use for hpack decoding */
+#define GRPC_ARG_HTTP2_HPACK_TABLE_SIZE_DECODER \
+  "grpc.http2.hpack_table_size.decoder"
+/** How much memory to use for hpack encoding */
+#define GRPC_ARG_HTTP2_HPACK_TABLE_SIZE_ENCODER \
+  "grpc.http2.hpack_table_size.encoder"
+/** Default authority to pass if none specified on call construction */
+#define GRPC_ARG_DEFAULT_AUTHORITY "grpc.default_authority"
+/** Primary user agent: goes at the start of the user-agent metadata
+    sent on each request */
+#define GRPC_ARG_PRIMARY_USER_AGENT_STRING "grpc.primary_user_agent"
+/** Secondary user agent: goes at the end of the user-agent metadata
+    sent on each request */
+#define GRPC_ARG_SECONDARY_USER_AGENT_STRING "grpc.secondary_user_agent"
+/* The caller of the secure_channel_create functions may override the target
+   name used for SSL host name checking using this channel argument which is of
+   type GRPC_ARG_STRING. This *should* be used for testing only.
+   If this argument is not specified, the name used for SSL host name checking
+   will be the target parameter (assuming that the secure channel is an SSL
+   channel). If this parameter is specified and the underlying is not an SSL
+   channel, it will just be ignored. */
+#define GRPC_SSL_TARGET_NAME_OVERRIDE_ARG "grpc.ssl_target_name_override"
+
+/** Result of a grpc call. If the caller satisfies the prerequisites of a
+    particular operation, the grpc_call_error returned will be GRPC_CALL_OK.
+    Receiving any other value listed here is an indication of a bug in the
+    caller. */
+typedef enum grpc_call_error {
+  /** everything went ok */
+  GRPC_CALL_OK = 0,
+  /** something failed, we don't know what */
+  GRPC_CALL_ERROR,
+  /** this method is not available on the server */
+  GRPC_CALL_ERROR_NOT_ON_SERVER,
+  /** this method is not available on the client */
+  GRPC_CALL_ERROR_NOT_ON_CLIENT,
+  /** this method must be called before server_accept */
+  GRPC_CALL_ERROR_ALREADY_ACCEPTED,
+  /** this method must be called before invoke */
+  GRPC_CALL_ERROR_ALREADY_INVOKED,
+  /** this method must be called after invoke */
+  GRPC_CALL_ERROR_NOT_INVOKED,
+  /** this call is already finished
+      (writes_done or write_status has already been called) */
+  GRPC_CALL_ERROR_ALREADY_FINISHED,
+  /** there is already an outstanding read/write operation on the call */
+  GRPC_CALL_ERROR_TOO_MANY_OPERATIONS,
+  /** the flags value was illegal for this call */
+  GRPC_CALL_ERROR_INVALID_FLAGS,
+  /** invalid metadata was passed to this call */
+  GRPC_CALL_ERROR_INVALID_METADATA,
+  /** invalid message was passed to this call */
+  GRPC_CALL_ERROR_INVALID_MESSAGE,
+  /** completion queue for notification has not been registered with the
+      server */
+  GRPC_CALL_ERROR_NOT_SERVER_COMPLETION_QUEUE,
+  /** this batch of operations leads to more operations than allowed */
+  GRPC_CALL_ERROR_BATCH_TOO_BIG
+} grpc_call_error;
+
+/* Write Flags: */
+/** Hint that the write may be buffered and need not go out on the wire
+    immediately. GRPC is free to buffer the message until the next non-buffered
+    write, or until writes_done, but it need not buffer completely or at all. */
+#define GRPC_WRITE_BUFFER_HINT (0x00000001u)
+/** Force compression to be disabled for a particular write
+    (start_write/add_metadata). Illegal on invoke/accept. */
+#define GRPC_WRITE_NO_COMPRESS (0x00000002u)
+/** Mask of all valid flags. */
+#define GRPC_WRITE_USED_MASK (GRPC_WRITE_BUFFER_HINT | GRPC_WRITE_NO_COMPRESS)
+
+/** A single metadata element */
+typedef struct grpc_metadata {
+  const char *key;
+  const char *value;
+  size_t value_length;
+  uint32_t flags;
+
+  /** The following fields are reserved for grpc internal use.
+      There is no need to initialize them, and they will be set to garbage
+      during calls to grpc. */
+  struct {
+    void *obfuscated[4];
+  } internal_data;
+} grpc_metadata;
+
+/** The type of completion (for grpc_event) */
+typedef enum grpc_completion_type {
+  /** Shutting down */
+  GRPC_QUEUE_SHUTDOWN,
+  /** No event before timeout */
+  GRPC_QUEUE_TIMEOUT,
+  /** Operation completion */
+  GRPC_OP_COMPLETE
+} grpc_completion_type;
+
+/** The result of an operation.
+
+    Returned by a completion queue when the operation started with tag. */
+typedef struct grpc_event {
+  /** The type of the completion. */
+  grpc_completion_type type;
+  /** non-zero if the operation was successful, 0 upon failure.
+      Only GRPC_OP_COMPLETE can succeed or fail. */
+  int success;
+  /** The tag passed to grpc_call_start_batch etc to start this operation.
+      Only GRPC_OP_COMPLETE has a tag. */
+  void *tag;
+} grpc_event;
+
+typedef struct {
+  size_t count;
+  size_t capacity;
+  grpc_metadata *metadata;
+} grpc_metadata_array;
+
+typedef struct {
+  char *method;
+  size_t method_capacity;
+  char *host;
+  size_t host_capacity;
+  gpr_timespec deadline;
+  void *reserved;
+} grpc_call_details;
+
+typedef enum {
+  /** Send initial metadata: one and only one instance MUST be sent for each
+      call, unless the call was cancelled - in which case this can be skipped.
+      This op completes after all bytes of metadata have been accepted by
+      outgoing flow control. */
+  GRPC_OP_SEND_INITIAL_METADATA = 0,
+  /** Send a message: 0 or more of these operations can occur for each call.
+      This op completes after all bytes for the message have been accepted by
+      outgoing flow control. */
+  GRPC_OP_SEND_MESSAGE,
+  /** Send a close from the client: one and only one instance MUST be sent from
+      the client, unless the call was cancelled - in which case this can be
+      skipped.
+      This op completes after all bytes for the call (including the close)
+      have passed outgoing flow control. */
+  GRPC_OP_SEND_CLOSE_FROM_CLIENT,
+  /** Send status from the server: one and only one instance MUST be sent from
+      the server unless the call was cancelled - in which case this can be
+      skipped.
+      This op completes after all bytes for the call (including the status)
+      have passed outgoing flow control. */
+  GRPC_OP_SEND_STATUS_FROM_SERVER,
+  /** Receive initial metadata: one and only one MUST be made on the client,
+      must not be made on the server.
+      This op completes after all initial metadata has been read from the
+      peer. */
+  GRPC_OP_RECV_INITIAL_METADATA,
+  /** Receive a message: 0 or more of these operations can occur for each call.
+      This op completes after all bytes of the received message have been
+      read, or after a half-close has been received on this call. */
+  GRPC_OP_RECV_MESSAGE,
+  /** Receive status on the client: one and only one must be made on the client.
+      This operation always succeeds, meaning ops paired with this operation
+      will also appear to succeed, even though they may not have. In that case
+      the status will indicate some failure.
+      This op completes after all activity on the call has completed. */
+  GRPC_OP_RECV_STATUS_ON_CLIENT,
+  /** Receive close on the server: one and only one must be made on the
+      server.
+      This op completes after the close has been received by the server. */
+  GRPC_OP_RECV_CLOSE_ON_SERVER
+} grpc_op_type;
+
+/** Operation data: one field for each op type (except SEND_CLOSE_FROM_CLIENT
+   which has no arguments) */
+typedef struct grpc_op {
+  /** Operation type, as defined by grpc_op_type */
+  grpc_op_type op;
+  /** Write flags bitset for grpc_begin_messages */
+  uint32_t flags;
+  /** Reserved for future usage */
+  void *reserved;
+  union {
+    /** Reserved for future usage */
+    struct {
+      void *reserved[8];
+    } reserved;
+    struct {
+      size_t count;
+      grpc_metadata *metadata;
+    } send_initial_metadata;
+    grpc_byte_buffer *send_message;
+    struct {
+      size_t trailing_metadata_count;
+      grpc_metadata *trailing_metadata;
+      grpc_status_code status;
+      const char *status_details;
+    } send_status_from_server;
+    /** ownership of the array is with the caller, but ownership of the elements
+        stays with the call object (ie key, value members are owned by the call
+        object, recv_initial_metadata->array is owned by the caller).
+        After the operation completes, call grpc_metadata_array_destroy on this
+        value, or reuse it in a future op. */
+    grpc_metadata_array *recv_initial_metadata;
+    /** ownership of the byte buffer is moved to the caller; the caller must
+        call grpc_byte_buffer_destroy on this value, or reuse it in a future op.
+       */
+    grpc_byte_buffer **recv_message;
+    struct {
+      /** ownership of the array is with the caller, but ownership of the
+          elements stays with the call object (ie key, value members are owned
+          by the call object, trailing_metadata->array is owned by the caller).
+          After the operation completes, call grpc_metadata_array_destroy on
+         this
+          value, or reuse it in a future op. */
+      grpc_metadata_array *trailing_metadata;
+      grpc_status_code *status;
+      /** status_details is a buffer owned by the application before the op
+          completes and after the op has completed. During the operation
+          status_details may be reallocated to a size larger than
+          *status_details_capacity, in which case *status_details_capacity will
+          be updated with the new array capacity.
+
+          Pre-allocating space:
+          size_t my_capacity = 8;
+          char *my_details = gpr_malloc(my_capacity);
+          x.status_details = &my_details;
+          x.status_details_capacity = &my_capacity;
+
+          Not pre-allocating space:
+          size_t my_capacity = 0;
+          char *my_details = NULL;
+          x.status_details = &my_details;
+          x.status_details_capacity = &my_capacity;
+
+          After the call:
+          gpr_free(my_details); */
+      char **status_details;
+      size_t *status_details_capacity;
+    } recv_status_on_client;
+    struct {
+      /** out argument, set to 1 if the call failed in any way (seen as a
+          cancellation on the server), or 0 if the call succeeded */
+      int *cancelled;
+    } recv_close_on_server;
+  } data;
+} grpc_op;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* GRPC_IMPL_CODEGEN_GRPC_TYPES_H */
diff --git a/include/grpc/impl/codegen/log.h b/include/grpc/impl/codegen/log.h
new file mode 100644
index 0000000..d6e18e9
--- /dev/null
+++ b/include/grpc/impl/codegen/log.h
@@ -0,0 +1,110 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef GRPC_IMPL_CODEGEN_LOG_H
+#define GRPC_IMPL_CODEGEN_LOG_H
+
+#include <stdlib.h> /* for abort() */
+#include <stdarg.h>
+
+#include <grpc/impl/codegen/port_platform.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* GPR log API.
+
+   Usage (within grpc):
+
+   int argument1 = 3;
+   char* argument2 = "hello";
+   gpr_log(GPR_DEBUG, "format string %d", argument1);
+   gpr_log(GPR_INFO, "hello world");
+   gpr_log(GPR_ERROR, "%d %s!!", argument1, argument2); */
+
+/* The severity of a log message - use the #defines below when calling into
+   gpr_log to additionally supply file and line data */
+typedef enum gpr_log_severity {
+  GPR_LOG_SEVERITY_DEBUG,
+  GPR_LOG_SEVERITY_INFO,
+  GPR_LOG_SEVERITY_ERROR
+} gpr_log_severity;
+
+/* Returns a string representation of the log severity */
+const char *gpr_log_severity_string(gpr_log_severity severity);
+
+/* Macros to build log contexts at various severity levels */
+#define GPR_DEBUG __FILE__, __LINE__, GPR_LOG_SEVERITY_DEBUG
+#define GPR_INFO __FILE__, __LINE__, GPR_LOG_SEVERITY_INFO
+#define GPR_ERROR __FILE__, __LINE__, GPR_LOG_SEVERITY_ERROR
+
+/* Log a message. It's advised to use GPR_xxx above to generate the context
+ * for each message */
+GPRAPI void gpr_log(const char *file, int line, gpr_log_severity severity,
+                    const char *format, ...);
+
+GPRAPI void gpr_log_message(const char *file, int line,
+                            gpr_log_severity severity, const char *message);
+
+/* Log overrides: applications can use this API to intercept logging calls
+   and use their own implementations */
+
+typedef struct {
+  const char *file;
+  int line;
+  gpr_log_severity severity;
+  const char *message;
+} gpr_log_func_args;
+
+typedef void (*gpr_log_func)(gpr_log_func_args *args);
+GPRAPI void gpr_set_log_function(gpr_log_func func);
+
+/* abort() the process if x is zero, having written a line to the log.
+
+   Intended for internal invariants.  If the error can be recovered from,
+   without the possibility of corruption, or might best be reflected via
+   an exception in a higher-level language, consider returning error code.  */
+#define GPR_ASSERT(x)                                 \
+  do {                                                \
+    if (!(x)) {                                       \
+      gpr_log(GPR_ERROR, "assertion failed: %s", #x); \
+      abort();                                        \
+    }                                                 \
+  } while (0)
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* GRPC_IMPL_CODEGEN_LOG_H */
diff --git a/include/grpc/impl/codegen/port_platform.h b/include/grpc/impl/codegen/port_platform.h
new file mode 100644
index 0000000..258063f
--- /dev/null
+++ b/include/grpc/impl/codegen/port_platform.h
@@ -0,0 +1,362 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef GRPC_IMPL_CODEGEN_PORT_PLATFORM_H
+#define GRPC_IMPL_CODEGEN_PORT_PLATFORM_H
+
+/* Get windows.h included everywhere (we need it) */
+#if defined(_WIN64) || defined(WIN64) || defined(_WIN32) || defined(WIN32)
+#ifndef WIN32_LEAN_AND_MEAN
+#define GRPC_WIN32_LEAN_AND_MEAN_WAS_NOT_DEFINED
+#define WIN32_LEAN_AND_MEAN
+#endif /* WIN32_LEAN_AND_MEAN */
+
+#ifndef NOMINMAX
+#define GRPC_NOMINMX_WAS_NOT_DEFINED
+#define NOMINMAX
+#endif /* NOMINMAX */
+
+#ifndef _WIN32_WINNT
+#error \
+    "Please compile grpc with _WIN32_WINNT of at least 0x600 (aka Windows Vista)"
+#else /* !defined(_WIN32_WINNT) */
+#if (_WIN32_WINNT < 0x0600)
+#error \
+    "Please compile grpc with _WIN32_WINNT of at least 0x600 (aka Windows Vista)"
+#endif /* _WIN32_WINNT < 0x0600 */
+#endif /* defined(_WIN32_WINNT) */
+
+#include <windows.h>
+
+#ifdef GRPC_WIN32_LEAN_AND_MEAN_WAS_NOT_DEFINED
+#undef GRPC_WIN32_LEAN_AND_MEAN_WAS_NOT_DEFINED
+#undef WIN32_LEAN_AND_MEAN
+#endif /* GRPC_WIN32_LEAN_AND_MEAN_WAS_NOT_DEFINED */
+
+#ifdef GRPC_NOMINMAX_WAS_NOT_DEFINED
+#undef GRPC_NOMINMAX_WAS_NOT_DEFINED
+#undef NOMINMAX
+#endif /* GRPC_WIN32_LEAN_AND_MEAN_WAS_NOT_DEFINED */
+#endif /* defined(_WIN64) || defined(WIN64) || defined(_WIN32) || \
+          defined(WIN32) */
+
+/* Override this file with one for your platform if you need to redefine
+   things.  */
+
+#if !defined(GPR_NO_AUTODETECT_PLATFORM)
+#if defined(_WIN64) || defined(WIN64)
+#define GPR_PLATFORM_STRING "windows"
+#define GPR_WIN32 1
+#define GPR_ARCH_64 1
+#define GPR_GETPID_IN_PROCESS_H 1
+#define GPR_WINSOCK_SOCKET 1
+#define GPR_WINDOWS_SUBPROCESS 1
+#ifdef __GNUC__
+#define GPR_GCC_ATOMIC 1
+#define GPR_GCC_TLS 1
+#else
+#define GPR_WIN32_ATOMIC 1
+#define GPR_MSVC_TLS 1
+#endif
+#define GPR_WINDOWS_CRASH_HANDLER 1
+#elif defined(_WIN32) || defined(WIN32)
+#define GPR_PLATFORM_STRING "windows"
+#define GPR_ARCH_32 1
+#define GPR_WIN32 1
+#define GPR_GETPID_IN_PROCESS_H 1
+#define GPR_WINSOCK_SOCKET 1
+#define GPR_WINDOWS_SUBPROCESS 1
+#ifdef __GNUC__
+#define GPR_GCC_ATOMIC 1
+#define GPR_GCC_TLS 1
+#else
+#define GPR_WIN32_ATOMIC 1
+#define GPR_MSVC_TLS 1
+#endif
+#define GPR_WINDOWS_CRASH_HANDLER 1
+#elif defined(ANDROID) || defined(__ANDROID__)
+#define GPR_PLATFORM_STRING "android"
+#define GPR_ANDROID 1
+#define GPR_ARCH_32 1
+#define GPR_CPU_LINUX 1
+#define GPR_GCC_SYNC 1
+#define GPR_GCC_TLS 1
+#define GPR_POSIX_MULTIPOLL_WITH_POLL 1
+#define GPR_POSIX_WAKEUP_FD 1
+#define GPR_LINUX_EVENTFD 1
+#define GPR_POSIX_SOCKET 1
+#define GPR_POSIX_SOCKETADDR 1
+#define GPR_POSIX_SOCKETUTILS 1
+#define GPR_POSIX_ENV 1
+#define GPR_POSIX_FILE 1
+#define GPR_POSIX_STRING 1
+#define GPR_POSIX_SUBPROCESS 1
+#define GPR_POSIX_SYNC 1
+#define GPR_POSIX_TIME 1
+#define GPR_GETPID_IN_UNISTD_H 1
+#define GPR_HAVE_MSG_NOSIGNAL 1
+#elif defined(__linux__)
+#define GPR_POSIX_CRASH_HANDLER 1
+#define GPR_PLATFORM_STRING "linux"
+#ifndef _BSD_SOURCE
+#define _BSD_SOURCE
+#endif
+#ifndef _DEFAULT_SOURCE
+#define _DEFAULT_SOURCE
+#endif
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE
+#endif
+#include <features.h>
+#define GPR_CPU_LINUX 1
+#define GPR_GCC_ATOMIC 1
+#define GPR_GCC_TLS 1
+#define GPR_LINUX 1
+#define GPR_LINUX_MULTIPOLL_WITH_EPOLL 1
+#define GPR_POSIX_WAKEUP_FD 1
+#define GPR_POSIX_SOCKET 1
+#define GPR_POSIX_SOCKETADDR 1
+#ifdef __GLIBC_PREREQ
+#if __GLIBC_PREREQ(2, 9)
+#define GPR_LINUX_EVENTFD 1
+#endif
+#if __GLIBC_PREREQ(2, 10)
+#define GPR_LINUX_SOCKETUTILS 1
+#endif
+#endif
+#define GPR_LINUX_ENV 1
+#ifndef GPR_LINUX_EVENTFD
+#define GPR_POSIX_NO_SPECIAL_WAKEUP_FD 1
+#endif
+#ifndef GPR_LINUX_SOCKETUTILS
+#define GPR_POSIX_SOCKETUTILS
+#endif
+#define GPR_POSIX_FILE 1
+#define GPR_POSIX_STRING 1
+#define GPR_POSIX_SUBPROCESS 1
+#define GPR_POSIX_SYNC 1
+#define GPR_POSIX_TIME 1
+#define GPR_GETPID_IN_UNISTD_H 1
+#define GPR_HAVE_MSG_NOSIGNAL 1
+#ifdef _LP64
+#define GPR_ARCH_64 1
+#else /* _LP64 */
+#define GPR_ARCH_32 1
+#endif /* _LP64 */
+#elif defined(__APPLE__)
+#include <TargetConditionals.h>
+#ifndef _BSD_SOURCE
+#define _BSD_SOURCE
+#endif
+#define GPR_MSG_IOVLEN_TYPE int
+#if TARGET_OS_IPHONE
+#define GPR_FORBID_UNREACHABLE_CODE 1
+#define GPR_PLATFORM_STRING "ios"
+#define GPR_CPU_IPHONE 1
+#define GPR_PTHREAD_TLS 1
+#else /* TARGET_OS_IPHONE */
+#define GPR_PLATFORM_STRING "osx"
+#define GPR_CPU_POSIX 1
+#define GPR_GCC_TLS 1
+#define GPR_POSIX_CRASH_HANDLER 1
+#endif
+#define GPR_GCC_ATOMIC 1
+#define GPR_POSIX_LOG 1
+#define GPR_POSIX_MULTIPOLL_WITH_POLL 1
+#define GPR_POSIX_WAKEUP_FD 1
+#define GPR_POSIX_NO_SPECIAL_WAKEUP_FD 1
+#define GPR_POSIX_SOCKET 1
+#define GPR_POSIX_SOCKETADDR 1
+#define GPR_POSIX_SOCKETUTILS 1
+#define GPR_POSIX_ENV 1
+#define GPR_POSIX_FILE 1
+#define GPR_POSIX_STRING 1
+#define GPR_POSIX_SUBPROCESS 1
+#define GPR_POSIX_SYNC 1
+#define GPR_POSIX_TIME 1
+#define GPR_GETPID_IN_UNISTD_H 1
+#define GPR_HAVE_SO_NOSIGPIPE 1
+#ifdef _LP64
+#define GPR_ARCH_64 1
+#else /* _LP64 */
+#define GPR_ARCH_32 1
+#endif /* _LP64 */
+#elif defined(__FreeBSD__)
+#define GPR_PLATFORM_STRING "freebsd"
+#ifndef _BSD_SOURCE
+#define _BSD_SOURCE
+#endif
+#define GPR_CPU_POSIX 1
+#define GPR_GCC_ATOMIC 1
+#define GPR_GCC_TLS 1
+#define GPR_POSIX_LOG 1
+#define GPR_POSIX_MULTIPOLL_WITH_POLL 1
+#define GPR_POSIX_WAKEUP_FD 1
+#define GPR_POSIX_NO_SPECIAL_WAKEUP_FD 1
+#define GPR_POSIX_SOCKET 1
+#define GPR_POSIX_SOCKETADDR 1
+#define GPR_POSIX_SOCKETUTILS 1
+#define GPR_POSIX_ENV 1
+#define GPR_POSIX_FILE 1
+#define GPR_POSIX_STRING 1
+#define GPR_POSIX_SUBPROCESS 1
+#define GPR_POSIX_SYNC 1
+#define GPR_POSIX_TIME 1
+#define GPR_GETPID_IN_UNISTD_H 1
+#define GPR_HAVE_SO_NOSIGPIPE 1
+#ifdef _LP64
+#define GPR_ARCH_64 1
+#else /* _LP64 */
+#define GPR_ARCH_32 1
+#endif /* _LP64 */
+#else
+#error Could not auto-detect platform
+#endif
+#endif /* GPR_NO_AUTODETECT_PLATFORM */
+
+#ifndef GPR_PLATFORM_STRING
+#warning "GPR_PLATFORM_STRING not auto-detected"
+#define GPR_PLATFORM_STRING "unknown"
+#endif
+
+#ifdef GPR_GCOV
+#undef GPR_FORBID_UNREACHABLE_CODE
+#define GPR_FORBID_UNREACHABLE_CODE 1
+#endif
+
+#ifdef _MSC_VER
+#if _MSC_VER < 1700
+typedef __int8 int8_t;
+typedef __int16 int16_t;
+typedef __int32 int32_t;
+typedef __int64 int64_t;
+typedef unsigned __int8 uint8_t;
+typedef unsigned __int16 uint16_t;
+typedef unsigned __int32 uint32_t;
+typedef unsigned __int64 uint64_t;
+#else
+#include <stdint.h>
+#endif /* _MSC_VER < 1700 */
+#else
+#include <stdint.h>
+#endif /* _MSC_VER */
+
+/* Cache line alignment */
+#ifndef GPR_CACHELINE_SIZE_LOG
+#if defined(__i386__) || defined(__x86_64__)
+#define GPR_CACHELINE_SIZE_LOG 6
+#endif
+#ifndef GPR_CACHELINE_SIZE_LOG
+/* A reasonable default guess. Note that overestimates tend to waste more
+   space, while underestimates tend to waste more time. */
+#define GPR_CACHELINE_SIZE_LOG 6
+#endif /* GPR_CACHELINE_SIZE_LOG */
+#endif /* GPR_CACHELINE_SIZE_LOG */
+
+#define GPR_CACHELINE_SIZE (1 << GPR_CACHELINE_SIZE_LOG)
+
+/* scrub GCC_ATOMIC if it's not available on this compiler */
+#if defined(GPR_GCC_ATOMIC) && !defined(__ATOMIC_RELAXED)
+#undef GPR_GCC_ATOMIC
+#define GPR_GCC_SYNC 1
+#endif
+
+/* Validate platform combinations */
+#if defined(GPR_GCC_ATOMIC) + defined(GPR_GCC_SYNC) + \
+        defined(GPR_WIN32_ATOMIC) !=                  \
+    1
+#error Must define exactly one of GPR_GCC_ATOMIC, GPR_GCC_SYNC, GPR_WIN32_ATOMIC
+#endif
+
+#if defined(GPR_ARCH_32) + defined(GPR_ARCH_64) != 1
+#error Must define exactly one of GPR_ARCH_32, GPR_ARCH_64
+#endif
+
+#if defined(GPR_CPU_LINUX) + defined(GPR_CPU_POSIX) + defined(GPR_WIN32) + \
+        defined(GPR_CPU_IPHONE) + defined(GPR_CPU_CUSTOM) !=               \
+    1
+#error Must define exactly one of GPR_CPU_LINUX, GPR_CPU_POSIX, GPR_WIN32, GPR_CPU_IPHONE, GPR_CPU_CUSTOM
+#endif
+
+#if defined(GPR_POSIX_MULTIPOLL_WITH_POLL) && !defined(GPR_POSIX_SOCKET)
+#error Must define GPR_POSIX_SOCKET to use GPR_POSIX_MULTIPOLL_WITH_POLL
+#endif
+
+#if defined(GPR_POSIX_SOCKET) + defined(GPR_WINSOCK_SOCKET) + \
+        defined(GPR_CUSTOM_SOCKET) !=                         \
+    1
+#error Must define exactly one of GPR_POSIX_SOCKET, GPR_WINSOCK_SOCKET, GPR_CUSTOM_SOCKET
+#endif
+
+#if defined(GPR_MSVC_TLS) + defined(GPR_GCC_TLS) + defined(GPR_PTHREAD_TLS) + \
+        defined(GPR_CUSTOM_TLS) !=                                            \
+    1
+#error Must define exactly one of GPR_MSVC_TLS, GPR_GCC_TLS, GPR_PTHREAD_TLS, GPR_CUSTOM_TLS
+#endif
+
+/* maximum alignment needed for any type on this platform, rounded up to a
+   power of two */
+#define GPR_MAX_ALIGNMENT 16
+
+#ifndef GRPC_MUST_USE_RESULT
+#ifdef __GNUC__
+#define GRPC_MUST_USE_RESULT __attribute__((warn_unused_result))
+#else
+#define GRPC_MUST_USE_RESULT
+#endif
+#endif
+
+#if GPR_FORBID_UNREACHABLE_CODE
+#define GPR_UNREACHABLE_CODE(STATEMENT)
+#else
+#define GPR_UNREACHABLE_CODE(STATEMENT)             \
+  do {                                              \
+    gpr_log(GPR_ERROR, "Should never reach here."); \
+    abort();                                        \
+    STATEMENT;                                      \
+  } while (0)
+#endif /* GPR_FORBID_UNREACHABLE_CODE */
+
+#ifndef GPRAPI
+#define GPRAPI
+#endif
+
+#ifndef GRPCAPI
+#define GRPCAPI GPRAPI
+#endif
+
+#ifndef CENSUSAPI
+#define CENSUSAPI GRPCAPI
+#endif
+
+#endif /* GRPC_IMPL_CODEGEN_PORT_PLATFORM_H */
diff --git a/include/grpc/impl/codegen/propagation_bits.h b/include/grpc/impl/codegen/propagation_bits.h
new file mode 100644
index 0000000..cdd6997
--- /dev/null
+++ b/include/grpc/impl/codegen/propagation_bits.h
@@ -0,0 +1,67 @@
+/*
+ *
+ * Copyright 2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef GRPC_IMPL_CODEGEN_H
+#define GRPC_IMPL_CODEGEN_H
+
+#include <grpc/impl/codegen/port_platform.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Propagation bits: this can be bitwise or-ed to form propagation_mask for
+ * grpc_call */
+/** Propagate deadline */
+#define GRPC_PROPAGATE_DEADLINE ((uint32_t)1)
+/** Propagate census context */
+#define GRPC_PROPAGATE_CENSUS_STATS_CONTEXT ((uint32_t)2)
+#define GRPC_PROPAGATE_CENSUS_TRACING_CONTEXT ((uint32_t)4)
+/** Propagate cancellation */
+#define GRPC_PROPAGATE_CANCELLATION ((uint32_t)8)
+
+/* Default propagation mask: clients of the core API are encouraged to encode
+   deltas from this in their implementations... ie write:
+   GRPC_PROPAGATE_DEFAULTS & ~GRPC_PROPAGATE_DEADLINE to disable deadline
+   propagation. Doing so gives flexibility in the future to define new
+   propagation types that are default inherited or not. */
+#define GRPC_PROPAGATE_DEFAULTS                                                \
+  ((uint32_t)((                                                                \
+      0xffff | GRPC_PROPAGATE_DEADLINE | GRPC_PROPAGATE_CENSUS_STATS_CONTEXT | \
+      GRPC_PROPAGATE_CENSUS_TRACING_CONTEXT | GRPC_PROPAGATE_CANCELLATION)))
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* GRPC_IMPL_CODEGEN_H */
diff --git a/include/grpc/impl/codegen/slice.h b/include/grpc/impl/codegen/slice.h
new file mode 100644
index 0000000..a62fdd0
--- /dev/null
+++ b/include/grpc/impl/codegen/slice.h
@@ -0,0 +1,182 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef GRPC_IMPL_CODEGEN_SLICE_H
+#define GRPC_IMPL_CODEGEN_SLICE_H
+
+#include <grpc/impl/codegen/sync.h>
+
+#include <stddef.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Slice API
+
+   A slice represents a contiguous reference counted array of bytes.
+   It is cheap to take references to a slice, and it is cheap to create a
+   slice pointing to a subset of another slice.
+
+   The data-structure for slices is exposed here to allow non-gpr code to
+   build slices from whatever data they have available.
+
+   When defining interfaces that handle slices, care should be taken to define
+   reference ownership semantics (who should call unref?) and mutability
+   constraints (is the callee allowed to modify the slice?) */
+
+/* Reference count container for gpr_slice. Contains function pointers to
+   increment and decrement reference counts. Implementations should cleanup
+   when the reference count drops to zero.
+   Typically client code should not touch this, and use gpr_slice_malloc,
+   gpr_slice_new, or gpr_slice_new_with_len instead. */
+typedef struct gpr_slice_refcount {
+  void (*ref)(void *);
+  void (*unref)(void *);
+} gpr_slice_refcount;
+
+#define GPR_SLICE_INLINED_SIZE (sizeof(size_t) + sizeof(uint8_t *) - 1)
+
+/* A gpr_slice s, if initialized, represents the byte range
+   s.bytes[0..s.length-1].
+
+   It can have an associated ref count which has a destruction routine to be run
+   when the ref count reaches zero (see gpr_slice_new() and grp_slice_unref()).
+   Multiple gpr_slice values may share a ref count.
+
+   If the slice does not have a refcount, it represents an inlined small piece
+   of data that is copied by value. */
+typedef struct gpr_slice {
+  struct gpr_slice_refcount *refcount;
+  union {
+    struct {
+      uint8_t *bytes;
+      size_t length;
+    } refcounted;
+    struct {
+      uint8_t length;
+      uint8_t bytes[GPR_SLICE_INLINED_SIZE];
+    } inlined;
+  } data;
+} gpr_slice;
+
+#define GPR_SLICE_START_PTR(slice)                  \
+  ((slice).refcount ? (slice).data.refcounted.bytes \
+                    : (slice).data.inlined.bytes)
+#define GPR_SLICE_LENGTH(slice)                      \
+  ((slice).refcount ? (slice).data.refcounted.length \
+                    : (slice).data.inlined.length)
+#define GPR_SLICE_SET_LENGTH(slice, newlen)                               \
+  ((slice).refcount ? ((slice).data.refcounted.length = (size_t)(newlen)) \
+                    : ((slice).data.inlined.length = (uint8_t)(newlen)))
+#define GPR_SLICE_END_PTR(slice) \
+  GPR_SLICE_START_PTR(slice) + GPR_SLICE_LENGTH(slice)
+#define GPR_SLICE_IS_EMPTY(slice) (GPR_SLICE_LENGTH(slice) == 0)
+
+/* Increment the refcount of s. Requires slice is initialized.
+   Returns s. */
+GPRAPI gpr_slice gpr_slice_ref(gpr_slice s);
+
+/* Decrement the ref count of s.  If the ref count of s reaches zero, all
+   slices sharing the ref count are destroyed, and considered no longer
+   initialized.  If s is ultimately derived from a call to gpr_slice_new(start,
+   len, dest) where dest!=NULL , then (*dest)(start) is called, else if s is
+   ultimately derived from a call to gpr_slice_new_with_len(start, len, dest)
+   where dest!=NULL , then (*dest)(start, len).  Requires s initialized.  */
+GPRAPI void gpr_slice_unref(gpr_slice s);
+
+/* Create a slice pointing at some data. Calls malloc to allocate a refcount
+   for the object, and arranges that destroy will be called with the pointer
+   passed in at destruction. */
+GPRAPI gpr_slice gpr_slice_new(void *p, size_t len, void (*destroy)(void *));
+
+/* Equivalent to gpr_slice_new, but with a two argument destroy function that
+   also takes the slice length. */
+GPRAPI gpr_slice
+gpr_slice_new_with_len(void *p, size_t len, void (*destroy)(void *, size_t));
+
+/* Equivalent to gpr_slice_new(malloc(len), len, free), but saves one malloc()
+   call.
+   Aborts if malloc() fails. */
+GPRAPI gpr_slice gpr_slice_malloc(size_t length);
+
+/* Create a slice by copying a string.
+   Does not preserve null terminators.
+   Equivalent to:
+     size_t len = strlen(source);
+     gpr_slice slice = gpr_slice_malloc(len);
+     memcpy(slice->data, source, len); */
+GPRAPI gpr_slice gpr_slice_from_copied_string(const char *source);
+
+/* Create a slice by copying a buffer.
+   Equivalent to:
+     gpr_slice slice = gpr_slice_malloc(len);
+     memcpy(slice->data, source, len); */
+GPRAPI gpr_slice gpr_slice_from_copied_buffer(const char *source, size_t len);
+
+/* Create a slice pointing to constant memory */
+GPRAPI gpr_slice gpr_slice_from_static_string(const char *source);
+
+/* Return a result slice derived from s, which shares a ref count with s, where
+   result.data==s.data+begin, and result.length==end-begin.
+   The ref count of s is increased by one.
+   Requires s initialized, begin <= end, begin <= s.length, and
+   end <= source->length. */
+GPRAPI gpr_slice gpr_slice_sub(gpr_slice s, size_t begin, size_t end);
+
+/* The same as gpr_slice_sub, but without altering the ref count */
+GPRAPI gpr_slice gpr_slice_sub_no_ref(gpr_slice s, size_t begin, size_t end);
+
+/* Splits s into two: modifies s to be s[0:split], and returns a new slice,
+   sharing a refcount with s, that contains s[split:s.length].
+   Requires s intialized, split <= s.length */
+GPRAPI gpr_slice gpr_slice_split_tail(gpr_slice *s, size_t split);
+
+/* Splits s into two: modifies s to be s[split:s.length], and returns a new
+   slice, sharing a refcount with s, that contains s[0:split].
+   Requires s intialized, split <= s.length */
+GPRAPI gpr_slice gpr_slice_split_head(gpr_slice *s, size_t split);
+
+GPRAPI gpr_slice gpr_empty_slice(void);
+
+/* Returns <0 if a < b, ==0 if a == b, >0 if a > b
+   The order is arbitrary, and is not guaranteed to be stable across different
+   versions of the API. */
+GPRAPI int gpr_slice_cmp(gpr_slice a, gpr_slice b);
+GPRAPI int gpr_slice_str_cmp(gpr_slice a, const char *b);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* GRPC_IMPL_CODEGEN_SLICE_H */
diff --git a/include/grpc/impl/codegen/slice_buffer.h b/include/grpc/impl/codegen/slice_buffer.h
new file mode 100644
index 0000000..4fe909e
--- /dev/null
+++ b/include/grpc/impl/codegen/slice_buffer.h
@@ -0,0 +1,105 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef GRPC_IMPL_CODEGEN_SLICE_BUFFER_H
+#define GRPC_IMPL_CODEGEN_SLICE_BUFFER_H
+
+#include <grpc/impl/codegen/slice.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define GRPC_SLICE_BUFFER_INLINE_ELEMENTS 8
+
+/* Represents an expandable array of slices, to be interpreted as a single item
+   TODO(ctiller): inline some small number of elements into the struct, to
+                  avoid per-call allocations */
+typedef struct {
+  /* slices in the array */
+  gpr_slice *slices;
+  /* the number of slices in the array */
+  size_t count;
+  /* the number of slices allocated in the array */
+  size_t capacity;
+  /* the combined length of all slices in the array */
+  size_t length;
+  /* inlined elements to avoid allocations */
+  gpr_slice inlined[GRPC_SLICE_BUFFER_INLINE_ELEMENTS];
+} gpr_slice_buffer;
+
+/* initialize a slice buffer */
+GPRAPI void gpr_slice_buffer_init(gpr_slice_buffer *sb);
+/* destroy a slice buffer - unrefs any held elements */
+GPRAPI void gpr_slice_buffer_destroy(gpr_slice_buffer *sb);
+/* Add an element to a slice buffer - takes ownership of the slice.
+   This function is allowed to concatenate the passed in slice to the end of
+   some other slice if desired by the slice buffer. */
+GPRAPI void gpr_slice_buffer_add(gpr_slice_buffer *sb, gpr_slice slice);
+/* add an element to a slice buffer - takes ownership of the slice and returns
+   the index of the slice.
+   Guarantees that the slice will not be concatenated at the end of another
+   slice (i.e. the data for this slice will begin at the first byte of the
+   slice at the returned index in sb->slices)
+   The implementation MAY decide to concatenate data at the end of a small
+   slice added in this fashion. */
+GPRAPI size_t
+gpr_slice_buffer_add_indexed(gpr_slice_buffer *sb, gpr_slice slice);
+GPRAPI void gpr_slice_buffer_addn(gpr_slice_buffer *sb, gpr_slice *slices,
+                                  size_t n);
+/* add a very small (less than 8 bytes) amount of data to the end of a slice
+   buffer: returns a pointer into which to add the data */
+GPRAPI uint8_t *gpr_slice_buffer_tiny_add(gpr_slice_buffer *sb, size_t len);
+/* pop the last buffer, but don't unref it */
+GPRAPI void gpr_slice_buffer_pop(gpr_slice_buffer *sb);
+/* clear a slice buffer, unref all elements */
+GPRAPI void gpr_slice_buffer_reset_and_unref(gpr_slice_buffer *sb);
+/* swap the contents of two slice buffers */
+GPRAPI void gpr_slice_buffer_swap(gpr_slice_buffer *a, gpr_slice_buffer *b);
+/* move all of the elements of src into dst */
+GPRAPI void gpr_slice_buffer_move_into(gpr_slice_buffer *src,
+                                       gpr_slice_buffer *dst);
+/* remove n bytes from the end of a slice buffer */
+GPRAPI void gpr_slice_buffer_trim_end(gpr_slice_buffer *src, size_t n,
+                                      gpr_slice_buffer *garbage);
+/* move the first n bytes of src into dst */
+GPRAPI void gpr_slice_buffer_move_first(gpr_slice_buffer *src, size_t n,
+                                        gpr_slice_buffer *dst);
+/* take the first slice in the slice buffer */
+GPRAPI gpr_slice gpr_slice_buffer_take_first(gpr_slice_buffer *src);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* GRPC_IMPL_CODEGEN_SLICE_BUFFER_H */
diff --git a/include/grpc/impl/codegen/status.h b/include/grpc/impl/codegen/status.h
new file mode 100644
index 0000000..814bb4c
--- /dev/null
+++ b/include/grpc/impl/codegen/status.h
@@ -0,0 +1,163 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef GRPC_IMPL_CODEGEN_STATUS_H
+#define GRPC_IMPL_CODEGEN_STATUS_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef enum {
+  /* Not an error; returned on success */
+  GRPC_STATUS_OK = 0,
+
+  /* The operation was cancelled (typically by the caller). */
+  GRPC_STATUS_CANCELLED = 1,
+
+  /* Unknown error.  An example of where this error may be returned is
+     if a Status value received from another address space belongs to
+     an error-space that is not known in this address space.  Also
+     errors raised by APIs that do not return enough error information
+     may be converted to this error. */
+  GRPC_STATUS_UNKNOWN = 2,
+
+  /* Client specified an invalid argument.  Note that this differs
+     from FAILED_PRECONDITION.  INVALID_ARGUMENT indicates arguments
+     that are problematic regardless of the state of the system
+     (e.g., a malformed file name). */
+  GRPC_STATUS_INVALID_ARGUMENT = 3,
+
+  /* Deadline expired before operation could complete.  For operations
+     that change the state of the system, this error may be returned
+     even if the operation has completed successfully.  For example, a
+     successful response from a server could have been delayed long
+     enough for the deadline to expire. */
+  GRPC_STATUS_DEADLINE_EXCEEDED = 4,
+
+  /* Some requested entity (e.g., file or directory) was not found. */
+  GRPC_STATUS_NOT_FOUND = 5,
+
+  /* Some entity that we attempted to create (e.g., file or directory)
+     already exists. */
+  GRPC_STATUS_ALREADY_EXISTS = 6,
+
+  /* The caller does not have permission to execute the specified
+     operation.  PERMISSION_DENIED must not be used for rejections
+     caused by exhausting some resource (use RESOURCE_EXHAUSTED
+     instead for those errors).  PERMISSION_DENIED must not be
+     used if the caller can not be identified (use UNAUTHENTICATED
+     instead for those errors). */
+  GRPC_STATUS_PERMISSION_DENIED = 7,
+
+  /* The request does not have valid authentication credentials for the
+     operation. */
+  GRPC_STATUS_UNAUTHENTICATED = 16,
+
+  /* Some resource has been exhausted, perhaps a per-user quota, or
+     perhaps the entire file system is out of space. */
+  GRPC_STATUS_RESOURCE_EXHAUSTED = 8,
+
+  /* Operation was rejected because the system is not in a state
+     required for the operation's execution.  For example, directory
+     to be deleted may be non-empty, an rmdir operation is applied to
+     a non-directory, etc.
+
+     A litmus test that may help a service implementor in deciding
+     between FAILED_PRECONDITION, ABORTED, and UNAVAILABLE:
+      (a) Use UNAVAILABLE if the client can retry just the failing call.
+      (b) Use ABORTED if the client should retry at a higher-level
+          (e.g., restarting a read-modify-write sequence).
+      (c) Use FAILED_PRECONDITION if the client should not retry until
+          the system state has been explicitly fixed.  E.g., if an "rmdir"
+          fails because the directory is non-empty, FAILED_PRECONDITION
+          should be returned since the client should not retry unless
+          they have first fixed up the directory by deleting files from it.
+      (d) Use FAILED_PRECONDITION if the client performs conditional
+          REST Get/Update/Delete on a resource and the resource on the
+          server does not match the condition. E.g., conflicting
+          read-modify-write on the same resource. */
+  GRPC_STATUS_FAILED_PRECONDITION = 9,
+
+  /* The operation was aborted, typically due to a concurrency issue
+     like sequencer check failures, transaction aborts, etc.
+
+     See litmus test above for deciding between FAILED_PRECONDITION,
+     ABORTED, and UNAVAILABLE. */
+  GRPC_STATUS_ABORTED = 10,
+
+  /* Operation was attempted past the valid range.  E.g., seeking or
+     reading past end of file.
+
+     Unlike INVALID_ARGUMENT, this error indicates a problem that may
+     be fixed if the system state changes. For example, a 32-bit file
+     system will generate INVALID_ARGUMENT if asked to read at an
+     offset that is not in the range [0,2^32-1], but it will generate
+     OUT_OF_RANGE if asked to read from an offset past the current
+     file size.
+
+     There is a fair bit of overlap between FAILED_PRECONDITION and
+     OUT_OF_RANGE.  We recommend using OUT_OF_RANGE (the more specific
+     error) when it applies so that callers who are iterating through
+     a space can easily look for an OUT_OF_RANGE error to detect when
+     they are done. */
+  GRPC_STATUS_OUT_OF_RANGE = 11,
+
+  /* Operation is not implemented or not supported/enabled in this service. */
+  GRPC_STATUS_UNIMPLEMENTED = 12,
+
+  /* Internal errors.  Means some invariants expected by underlying
+     system has been broken.  If you see one of these errors,
+     something is very broken. */
+  GRPC_STATUS_INTERNAL = 13,
+
+  /* The service is currently unavailable.  This is a most likely a
+     transient condition and may be corrected by retrying with
+     a backoff.
+
+     See litmus test above for deciding between FAILED_PRECONDITION,
+     ABORTED, and UNAVAILABLE. */
+  GRPC_STATUS_UNAVAILABLE = 14,
+
+  /* Unrecoverable data loss or corruption. */
+  GRPC_STATUS_DATA_LOSS = 15,
+
+  /* Force users to include a default branch: */
+  GRPC_STATUS__DO_NOT_USE = -1
+} grpc_status_code;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* GRPC_IMPL_CODEGEN_STATUS_H */
diff --git a/include/grpc/impl/codegen/sync.h b/include/grpc/impl/codegen/sync.h
new file mode 100644
index 0000000..d2f19d3
--- /dev/null
+++ b/include/grpc/impl/codegen/sync.h
@@ -0,0 +1,316 @@
+/*
+ *
+ * Copyright 2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef GRPC_IMPL_CODEGEN_SYNC_H
+#define GRPC_IMPL_CODEGEN_SYNC_H
+/* Synchronization primitives for GPR.
+
+   The type  gpr_mu              provides a non-reentrant mutex (lock).
+
+   The type  gpr_cv              provides a condition variable.
+
+   The type  gpr_once            provides for one-time initialization.
+
+   The type gpr_event            provides one-time-setting, reading, and
+                                 waiting of a void*, with memory barriers.
+
+   The type gpr_refcount         provides an object reference counter,
+                                 with memory barriers suitable to control
+                                 object lifetimes.
+
+   The type gpr_stats_counter    provides an atomic statistics counter. It
+                                 provides no memory barriers.
+ */
+
+/* Platform-specific type declarations of gpr_mu and gpr_cv.   */
+#include <grpc/impl/codegen/port_platform.h>
+#include <grpc/impl/codegen/sync_generic.h>
+
+#if defined(GPR_POSIX_SYNC)
+#include <grpc/impl/codegen/sync_posix.h>
+#elif defined(GPR_WIN32)
+#include <grpc/impl/codegen/sync_win32.h>
+#elif !defined(GPR_CUSTOM_SYNC)
+#error Unable to determine platform for sync
+#endif
+
+#include <grpc/impl/codegen/time.h> /* for gpr_timespec */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* --- Mutex interface ---
+
+   At most one thread may hold an exclusive lock on a mutex at any given time.
+   Actions taken by a thread that holds a mutex exclusively happen after
+   actions taken by all previous holders of the mutex.  Variables of type
+   gpr_mu are uninitialized when first declared.  */
+
+/* Initialize *mu.  Requires:  *mu uninitialized.  */
+GPRAPI void gpr_mu_init(gpr_mu *mu);
+
+/* Cause *mu no longer to be initialized, freeing any memory in use.  Requires:
+   *mu initialized; no other concurrent operation on *mu.  */
+GPRAPI void gpr_mu_destroy(gpr_mu *mu);
+
+/* Wait until no thread has a lock on *mu, cause the calling thread to own an
+   exclusive lock on *mu, then return.  May block indefinitely or crash if the
+   calling thread has a lock on *mu.  Requires:  *mu initialized.  */
+GPRAPI void gpr_mu_lock(gpr_mu *mu);
+
+/* Release an exclusive lock on *mu held by the calling thread.  Requires:  *mu
+   initialized; the calling thread holds an exclusive lock on *mu.  */
+GPRAPI void gpr_mu_unlock(gpr_mu *mu);
+
+/* Without blocking, attempt to acquire an exclusive lock on *mu for the
+   calling thread, then return non-zero iff success.  Fail, if any thread holds
+   the lock; succeeds with high probability if no thread holds the lock.
+   Requires:  *mu initialized.  */
+GPRAPI int gpr_mu_trylock(gpr_mu *mu);
+
+/* --- Condition variable interface ---
+
+   A while-loop should be used with gpr_cv_wait() when waiting for conditions
+   to become true.  See the example below.  Variables of type gpr_cv are
+   uninitialized when first declared.  */
+
+/* Initialize *cv.  Requires:  *cv uninitialized.  */
+GPRAPI void gpr_cv_init(gpr_cv *cv);
+
+/* Cause *cv no longer to be initialized, freeing any memory in use.  Requires:
+   *cv initialized; no other concurrent operation on *cv.*/
+GPRAPI void gpr_cv_destroy(gpr_cv *cv);
+
+/* Atomically release *mu and wait on *cv.  When the calling thread is woken
+   from *cv or the deadline abs_deadline is exceeded, execute gpr_mu_lock(mu)
+   and return whether the deadline was exceeded.  Use
+   abs_deadline==gpr_inf_future for no deadline.  abs_deadline can be either
+   an absolute deadline, or a GPR_TIMESPAN.  May return even when not
+   woken explicitly.  Requires:  *mu and *cv initialized; the calling thread
+   holds an exclusive lock on *mu.  */
+GPRAPI int gpr_cv_wait(gpr_cv *cv, gpr_mu *mu, gpr_timespec abs_deadline);
+
+/* If any threads are waiting on *cv, wake at least one.
+   Clients may treat this as an optimization of gpr_cv_broadcast()
+   for use in the case where waking more than one waiter is not useful.
+   Requires:  *cv initialized.  */
+GPRAPI void gpr_cv_signal(gpr_cv *cv);
+
+/* Wake all threads waiting on *cv.  Requires:  *cv initialized.  */
+GPRAPI void gpr_cv_broadcast(gpr_cv *cv);
+
+/* --- One-time initialization ---
+
+   gpr_once must be declared with static storage class, and initialized with
+   GPR_ONCE_INIT.  e.g.,
+     static gpr_once once_var = GPR_ONCE_INIT;     */
+
+/* Ensure that (*init_routine)() has been called exactly once (for the
+   specified gpr_once instance) and then return.
+   If multiple threads call gpr_once() on the same gpr_once instance, one of
+   them will call (*init_routine)(), and the others will block until that call
+   finishes.*/
+GPRAPI void gpr_once_init(gpr_once *once, void (*init_routine)(void));
+
+/* --- One-time event notification ---
+
+  These operations act on a gpr_event, which should be initialized with
+  gpr_ev_init(), or with GPR_EVENT_INIT if static, e.g.,
+       static gpr_event event_var = GPR_EVENT_INIT;
+  It requires no destruction.  */
+
+/* Initialize *ev. */
+GPRAPI void gpr_event_init(gpr_event *ev);
+
+/* Set *ev so that gpr_event_get() and gpr_event_wait() will return value.
+   Requires:  *ev initialized; value != NULL; no prior or concurrent calls to
+   gpr_event_set(ev, ...) since initialization.  */
+GPRAPI void gpr_event_set(gpr_event *ev, void *value);
+
+/* Return the value set by gpr_event_set(ev, ...), or NULL if no such call has
+   completed.  If the result is non-NULL, all operations that occurred prior to
+   the gpr_event_set(ev, ...) set will be visible after this call returns.
+   Requires:  *ev initialized.  This operation is faster than acquiring a mutex
+   on most platforms.  */
+GPRAPI void *gpr_event_get(gpr_event *ev);
+
+/* Wait until *ev is set by gpr_event_set(ev, ...), or abs_deadline is
+   exceeded, then return gpr_event_get(ev).  Requires:  *ev initialized.  Use
+   abs_deadline==gpr_inf_future for no deadline.  When the event has been
+   signalled before the call, this operation is faster than acquiring a mutex
+   on most platforms.  */
+GPRAPI void *gpr_event_wait(gpr_event *ev, gpr_timespec abs_deadline);
+
+/* --- Reference counting ---
+
+   These calls act on the type gpr_refcount.  It requires no destruction.  */
+
+/* Initialize *r to value n.  */
+GPRAPI void gpr_ref_init(gpr_refcount *r, int n);
+
+/* Increment the reference count *r.  Requires *r initialized. */
+GPRAPI void gpr_ref(gpr_refcount *r);
+
+/* Increment the reference count *r by n.  Requires *r initialized, n > 0. */
+GPRAPI void gpr_refn(gpr_refcount *r, int n);
+
+/* Decrement the reference count *r and return non-zero iff it has reached
+   zero. .  Requires *r initialized. */
+GPRAPI int gpr_unref(gpr_refcount *r);
+
+/* --- Stats counters ---
+
+   These calls act on the integral type gpr_stats_counter.  It requires no
+   destruction.  Static instances may be initialized with
+       gpr_stats_counter c = GPR_STATS_INIT;
+   Beware:  These operations do not imply memory barriers.  Do not use them to
+   synchronize other events.  */
+
+/* Initialize *c to the value n. */
+GPRAPI void gpr_stats_init(gpr_stats_counter *c, intptr_t n);
+
+/* *c += inc.  Requires: *c initialized. */
+GPRAPI void gpr_stats_inc(gpr_stats_counter *c, intptr_t inc);
+
+/* Return *c.  Requires: *c initialized. */
+GPRAPI intptr_t gpr_stats_read(const gpr_stats_counter *c);
+
+/* ==================Example use of interface===================
+   A producer-consumer queue of up to N integers,
+   illustrating the use of the calls in this interface. */
+#if 0
+
+#define N 4
+
+   typedef struct queue {
+     gpr_cv non_empty;  /* Signalled when length becomes non-zero. */
+     gpr_cv non_full;   /* Signalled when length becomes non-N. */
+     gpr_mu mu;         /* Protects all fields below.
+                            (That is, except during initialization or
+                            destruction, the fields below should be accessed
+                            only by a thread that holds mu.) */
+     int head;           /* Index of head of queue 0..N-1. */
+     int length;         /* Number of valid elements in queue 0..N. */
+     int elem[N];        /* elem[head .. head+length-1] are queue elements. */
+   } queue;
+
+   /* Initialize *q. */
+   void queue_init(queue *q) {
+     gpr_mu_init(&q->mu);
+     gpr_cv_init(&q->non_empty);
+     gpr_cv_init(&q->non_full);
+     q->head = 0;
+     q->length = 0;
+   }
+
+   /* Free storage associated with *q. */
+   void queue_destroy(queue *q) {
+     gpr_mu_destroy(&q->mu);
+     gpr_cv_destroy(&q->non_empty);
+     gpr_cv_destroy(&q->non_full);
+   }
+
+   /* Wait until there is room in *q, then append x to *q. */
+   void queue_append(queue *q, int x) {
+     gpr_mu_lock(&q->mu);
+     /* To wait for a predicate without a deadline, loop on the negation of the
+        predicate, and use gpr_cv_wait(..., gpr_inf_future) inside the loop
+        to release the lock, wait, and reacquire on each iteration.  Code that
+        makes the condition true should use gpr_cv_broadcast() on the
+        corresponding condition variable.  The predicate must be on state
+        protected by the lock.  */
+     while (q->length == N) {
+       gpr_cv_wait(&q->non_full, &q->mu, gpr_inf_future);
+     }
+     if (q->length == 0) {  /* Wake threads blocked in queue_remove(). */
+       /* It's normal to use gpr_cv_broadcast() or gpr_signal() while
+          holding the lock. */
+       gpr_cv_broadcast(&q->non_empty);
+     }
+     q->elem[(q->head + q->length) % N] = x;
+     q->length++;
+     gpr_mu_unlock(&q->mu);
+   }
+
+   /* If it can be done without blocking, append x to *q and return non-zero.
+      Otherwise return 0. */
+   int queue_try_append(queue *q, int x) {
+     int result = 0;
+     if (gpr_mu_trylock(&q->mu)) {
+       if (q->length != N) {
+         if (q->length == 0) {  /* Wake threads blocked in queue_remove(). */
+           gpr_cv_broadcast(&q->non_empty);
+         }
+         q->elem[(q->head + q->length) % N] = x;
+         q->length++;
+         result = 1;
+       }
+       gpr_mu_unlock(&q->mu);
+     }
+     return result;
+   }
+
+   /* Wait until the *q is non-empty or deadline abs_deadline passes.  If the
+      queue is non-empty, remove its head entry, place it in *head, and return
+      non-zero.  Otherwise return 0.  */
+   int queue_remove(queue *q, int *head, gpr_timespec abs_deadline) {
+     int result = 0;
+     gpr_mu_lock(&q->mu);
+     /* To wait for a predicate with a deadline, loop on the negation of the
+        predicate or until gpr_cv_wait() returns true.  Code that makes
+        the condition true should use gpr_cv_broadcast() on the corresponding
+        condition variable.  The predicate must be on state protected by the
+        lock. */
+     while (q->length == 0 &&
+            !gpr_cv_wait(&q->non_empty, &q->mu, abs_deadline)) {
+     }
+     if (q->length != 0) {    /* Queue is non-empty. */
+       result = 1;
+       if (q->length == N) {  /* Wake threads blocked in queue_append(). */
+         gpr_cv_broadcast(&q->non_full);
+       }
+       *head = q->elem[q->head];
+       q->head = (q->head + 1) % N;
+       q->length--;
+     } /* else deadline exceeded */
+     gpr_mu_unlock(&q->mu);
+     return result;
+   }
+#endif /* 0 */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* GRPC_IMPL_CODEGEN_SYNC_H */
diff --git a/src/objective-c/GRPCClient/private/GRPCUnsecuredChannel.h b/include/grpc/impl/codegen/sync_generic.h
similarity index 74%
copy from src/objective-c/GRPCClient/private/GRPCUnsecuredChannel.h
copy to include/grpc/impl/codegen/sync_generic.h
index 8528be4..71443b5 100644
--- a/src/objective-c/GRPCClient/private/GRPCUnsecuredChannel.h
+++ b/include/grpc/impl/codegen/sync_generic.h
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -31,8 +31,25 @@
  *
  */
 
-#import "GRPCChannel.h"
+#ifndef GRPC_IMPL_CODEGEN_SYNC_GENERIC_H
+#define GRPC_IMPL_CODEGEN_SYNC_GENERIC_H
+/* Generic type defintions for gpr_sync. */
 
-@interface GRPCUnsecuredChannel : GRPCChannel
-- (instancetype)initWithHost:(NSString *)host NS_DESIGNATED_INITIALIZER;
-@end
+#include <grpc/impl/codegen/atm.h>
+
+/* gpr_event */
+typedef struct { gpr_atm state; } gpr_event;
+
+#define GPR_EVENT_INIT \
+  { 0 }
+
+/* gpr_refcount */
+typedef struct { gpr_atm count; } gpr_refcount;
+
+/* gpr_stats_counter */
+typedef struct { gpr_atm value; } gpr_stats_counter;
+
+#define GPR_STATS_INIT \
+  { 0 }
+
+#endif /* GRPC_IMPL_CODEGEN_SYNC_GENERIC_H */
diff --git a/src/objective-c/GRPCClient/private/GRPCUnsecuredChannel.h b/include/grpc/impl/codegen/sync_posix.h
similarity index 80%
copy from src/objective-c/GRPCClient/private/GRPCUnsecuredChannel.h
copy to include/grpc/impl/codegen/sync_posix.h
index 8528be4..f6e0a91 100644
--- a/src/objective-c/GRPCClient/private/GRPCUnsecuredChannel.h
+++ b/include/grpc/impl/codegen/sync_posix.h
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -31,8 +31,17 @@
  *
  */
 
-#import "GRPCChannel.h"
+#ifndef GRPC_IMPL_CODEGEN_SYNC_POSIX_H
+#define GRPC_IMPL_CODEGEN_SYNC_POSIX_H
 
-@interface GRPCUnsecuredChannel : GRPCChannel
-- (instancetype)initWithHost:(NSString *)host NS_DESIGNATED_INITIALIZER;
-@end
+#include <grpc/impl/codegen/sync_generic.h>
+
+#include <pthread.h>
+
+typedef pthread_mutex_t gpr_mu;
+typedef pthread_cond_t gpr_cv;
+typedef pthread_once_t gpr_once;
+
+#define GPR_ONCE_INIT PTHREAD_ONCE_INIT
+
+#endif /* GRPC_IMPL_CODEGEN_SYNC_POSIX_H */
diff --git a/src/objective-c/GRPCClient/private/GRPCUnsecuredChannel.h b/include/grpc/impl/codegen/sync_win32.h
similarity index 77%
copy from src/objective-c/GRPCClient/private/GRPCUnsecuredChannel.h
copy to include/grpc/impl/codegen/sync_win32.h
index 8528be4..1a6596c 100644
--- a/src/objective-c/GRPCClient/private/GRPCUnsecuredChannel.h
+++ b/include/grpc/impl/codegen/sync_win32.h
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -31,8 +31,19 @@
  *
  */
 
-#import "GRPCChannel.h"
+#ifndef GRPC_IMPL_CODEGEN_SYNC_WIN32_H
+#define GRPC_IMPL_CODEGEN_SYNC_WIN32_H
 
-@interface GRPCUnsecuredChannel : GRPCChannel
-- (instancetype)initWithHost:(NSString *)host NS_DESIGNATED_INITIALIZER;
-@end
+#include <grpc/impl/codegen/sync_generic.h>
+
+typedef struct {
+  CRITICAL_SECTION cs; /* Not an SRWLock until Vista is unsupported */
+  int locked;
+} gpr_mu;
+
+typedef CONDITION_VARIABLE gpr_cv;
+
+typedef INIT_ONCE gpr_once;
+#define GPR_ONCE_INIT INIT_ONCE_STATIC_INIT
+
+#endif /* GRPC_IMPL_CODEGEN_SYNC_WIN32_H */
diff --git a/include/grpc/impl/codegen/time.h b/include/grpc/impl/codegen/time.h
new file mode 100644
index 0000000..c22bedf
--- /dev/null
+++ b/include/grpc/impl/codegen/time.h
@@ -0,0 +1,130 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef GRPC_IMPL_CODEGEN_TIME_H
+#define GRPC_IMPL_CODEGEN_TIME_H
+/* Time support.
+   We use gpr_timespec, which is analogous to struct timespec.  On some
+   machines, absolute times may be in local time.  */
+
+#include <grpc/impl/codegen/port_platform.h>
+#include <stddef.h>
+#include <time.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* The clocks we support. */
+typedef enum {
+  /* Monotonic clock. Epoch undefined. Always moves forwards. */
+  GPR_CLOCK_MONOTONIC = 0,
+  /* Realtime clock. May jump forwards or backwards. Settable by
+     the system administrator. Has its epoch at 0:00:00 UTC 1 Jan 1970. */
+  GPR_CLOCK_REALTIME,
+  /* CPU cycle time obtained by rdtsc instruction on x86 platforms. Epoch
+     undefined. Degrades to GPR_CLOCK_REALTIME on other platforms. */
+  GPR_CLOCK_PRECISE,
+  /* Unmeasurable clock type: no base, created by taking the difference
+     between two times */
+  GPR_TIMESPAN
+} gpr_clock_type;
+
+typedef struct gpr_timespec {
+  int64_t tv_sec;
+  int32_t tv_nsec;
+  /** Against which clock was this time measured? (or GPR_TIMESPAN if
+      this is a relative time meaure) */
+  gpr_clock_type clock_type;
+} gpr_timespec;
+
+/* Time constants. */
+GPRAPI gpr_timespec
+gpr_time_0(gpr_clock_type type); /* The zero time interval. */
+GPRAPI gpr_timespec gpr_inf_future(gpr_clock_type type); /* The far future */
+GPRAPI gpr_timespec gpr_inf_past(gpr_clock_type type);   /* The far past. */
+
+#define GPR_MS_PER_SEC 1000
+#define GPR_US_PER_SEC 1000000
+#define GPR_NS_PER_SEC 1000000000
+#define GPR_NS_PER_MS 1000000
+#define GPR_NS_PER_US 1000
+#define GPR_US_PER_MS 1000
+
+/* initialize time subsystem */
+GPRAPI void gpr_time_init(void);
+
+/* Return the current time measured from the given clocks epoch. */
+GPRAPI gpr_timespec gpr_now(gpr_clock_type clock);
+
+/* Convert a timespec from one clock to another */
+GPRAPI gpr_timespec
+gpr_convert_clock_type(gpr_timespec t, gpr_clock_type target_clock);
+
+/* Return -ve, 0, or +ve according to whether a < b, a == b, or a > b
+   respectively.  */
+GPRAPI int gpr_time_cmp(gpr_timespec a, gpr_timespec b);
+
+GPRAPI gpr_timespec gpr_time_max(gpr_timespec a, gpr_timespec b);
+GPRAPI gpr_timespec gpr_time_min(gpr_timespec a, gpr_timespec b);
+
+/* Add and subtract times.  Calculations saturate at infinities. */
+GPRAPI gpr_timespec gpr_time_add(gpr_timespec a, gpr_timespec b);
+GPRAPI gpr_timespec gpr_time_sub(gpr_timespec a, gpr_timespec b);
+
+/* Return a timespec representing a given number of time units. INT64_MIN is
+   interpreted as gpr_inf_past, and INT64_MAX as gpr_inf_future.  */
+GPRAPI gpr_timespec gpr_time_from_micros(int64_t x, gpr_clock_type clock_type);
+GPRAPI gpr_timespec gpr_time_from_nanos(int64_t x, gpr_clock_type clock_type);
+GPRAPI gpr_timespec gpr_time_from_millis(int64_t x, gpr_clock_type clock_type);
+GPRAPI gpr_timespec gpr_time_from_seconds(int64_t x, gpr_clock_type clock_type);
+GPRAPI gpr_timespec gpr_time_from_minutes(int64_t x, gpr_clock_type clock_type);
+GPRAPI gpr_timespec gpr_time_from_hours(int64_t x, gpr_clock_type clock_type);
+
+GPRAPI int32_t gpr_time_to_millis(gpr_timespec timespec);
+
+/* Return 1 if two times are equal or within threshold of each other,
+   0 otherwise */
+GPRAPI int gpr_time_similar(gpr_timespec a, gpr_timespec b,
+                            gpr_timespec threshold);
+
+/* Sleep until at least 'until' - an absolute timeout */
+GPRAPI void gpr_sleep_until(gpr_timespec until);
+
+GPRAPI double gpr_timespec_to_micros(gpr_timespec t);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* GRPC_IMPL_CODEGEN_TIME_H */
diff --git a/include/grpc/status.h b/include/grpc/status.h
index 65ce410..3889a16 100644
--- a/include/grpc/status.h
+++ b/include/grpc/status.h
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -34,130 +34,6 @@
 #ifndef GRPC_STATUS_H
 #define GRPC_STATUS_H
 
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-typedef enum {
-  /* Not an error; returned on success */
-  GRPC_STATUS_OK = 0,
-
-  /* The operation was cancelled (typically by the caller). */
-  GRPC_STATUS_CANCELLED = 1,
-
-  /* Unknown error.  An example of where this error may be returned is
-     if a Status value received from another address space belongs to
-     an error-space that is not known in this address space.  Also
-     errors raised by APIs that do not return enough error information
-     may be converted to this error. */
-  GRPC_STATUS_UNKNOWN = 2,
-
-  /* Client specified an invalid argument.  Note that this differs
-     from FAILED_PRECONDITION.  INVALID_ARGUMENT indicates arguments
-     that are problematic regardless of the state of the system
-     (e.g., a malformed file name). */
-  GRPC_STATUS_INVALID_ARGUMENT = 3,
-
-  /* Deadline expired before operation could complete.  For operations
-     that change the state of the system, this error may be returned
-     even if the operation has completed successfully.  For example, a
-     successful response from a server could have been delayed long
-     enough for the deadline to expire. */
-  GRPC_STATUS_DEADLINE_EXCEEDED = 4,
-
-  /* Some requested entity (e.g., file or directory) was not found. */
-  GRPC_STATUS_NOT_FOUND = 5,
-
-  /* Some entity that we attempted to create (e.g., file or directory)
-     already exists. */
-  GRPC_STATUS_ALREADY_EXISTS = 6,
-
-  /* The caller does not have permission to execute the specified
-     operation.  PERMISSION_DENIED must not be used for rejections
-     caused by exhausting some resource (use RESOURCE_EXHAUSTED
-     instead for those errors).  PERMISSION_DENIED must not be
-     used if the caller can not be identified (use UNAUTHENTICATED
-     instead for those errors). */
-  GRPC_STATUS_PERMISSION_DENIED = 7,
-
-  /* The request does not have valid authentication credentials for the
-     operation. */
-  GRPC_STATUS_UNAUTHENTICATED = 16,
-
-  /* Some resource has been exhausted, perhaps a per-user quota, or
-     perhaps the entire file system is out of space. */
-  GRPC_STATUS_RESOURCE_EXHAUSTED = 8,
-
-  /* Operation was rejected because the system is not in a state
-     required for the operation's execution.  For example, directory
-     to be deleted may be non-empty, an rmdir operation is applied to
-     a non-directory, etc.
-
-     A litmus test that may help a service implementor in deciding
-     between FAILED_PRECONDITION, ABORTED, and UNAVAILABLE:
-      (a) Use UNAVAILABLE if the client can retry just the failing call.
-      (b) Use ABORTED if the client should retry at a higher-level
-          (e.g., restarting a read-modify-write sequence).
-      (c) Use FAILED_PRECONDITION if the client should not retry until
-          the system state has been explicitly fixed.  E.g., if an "rmdir"
-          fails because the directory is non-empty, FAILED_PRECONDITION
-          should be returned since the client should not retry unless
-          they have first fixed up the directory by deleting files from it.
-      (d) Use FAILED_PRECONDITION if the client performs conditional
-          REST Get/Update/Delete on a resource and the resource on the
-          server does not match the condition. E.g., conflicting
-          read-modify-write on the same resource. */
-  GRPC_STATUS_FAILED_PRECONDITION = 9,
-
-  /* The operation was aborted, typically due to a concurrency issue
-     like sequencer check failures, transaction aborts, etc.
-
-     See litmus test above for deciding between FAILED_PRECONDITION,
-     ABORTED, and UNAVAILABLE. */
-  GRPC_STATUS_ABORTED = 10,
-
-  /* Operation was attempted past the valid range.  E.g., seeking or
-     reading past end of file.
-
-     Unlike INVALID_ARGUMENT, this error indicates a problem that may
-     be fixed if the system state changes. For example, a 32-bit file
-     system will generate INVALID_ARGUMENT if asked to read at an
-     offset that is not in the range [0,2^32-1], but it will generate
-     OUT_OF_RANGE if asked to read from an offset past the current
-     file size.
-
-     There is a fair bit of overlap between FAILED_PRECONDITION and
-     OUT_OF_RANGE.  We recommend using OUT_OF_RANGE (the more specific
-     error) when it applies so that callers who are iterating through
-     a space can easily look for an OUT_OF_RANGE error to detect when
-     they are done. */
-  GRPC_STATUS_OUT_OF_RANGE = 11,
-
-  /* Operation is not implemented or not supported/enabled in this service. */
-  GRPC_STATUS_UNIMPLEMENTED = 12,
-
-  /* Internal errors.  Means some invariants expected by underlying
-     system has been broken.  If you see one of these errors,
-     something is very broken. */
-  GRPC_STATUS_INTERNAL = 13,
-
-  /* The service is currently unavailable.  This is a most likely a
-     transient condition and may be corrected by retrying with
-     a backoff.
-
-     See litmus test above for deciding between FAILED_PRECONDITION,
-     ABORTED, and UNAVAILABLE. */
-  GRPC_STATUS_UNAVAILABLE = 14,
-
-  /* Unrecoverable data loss or corruption. */
-  GRPC_STATUS_DATA_LOSS = 15,
-
-  /* Force users to include a default branch: */
-  GRPC_STATUS__DO_NOT_USE = -1
-} grpc_status_code;
-
-#ifdef __cplusplus
-}
-#endif
+#include <grpc/impl/codegen/status.h>
 
 #endif /* GRPC_STATUS_H */
diff --git a/include/grpc/support/alloc.h b/include/grpc/support/alloc.h
index f5cdade..649cb2b 100644
--- a/include/grpc/support/alloc.h
+++ b/include/grpc/support/alloc.h
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -34,39 +34,6 @@
 #ifndef GRPC_SUPPORT_ALLOC_H
 #define GRPC_SUPPORT_ALLOC_H
 
-#include <stddef.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-typedef struct gpr_allocation_functions {
-  void *(*malloc_fn)(size_t size);
-  void *(*realloc_fn)(void *ptr, size_t size);
-  void (*free_fn)(void *ptr);
-} gpr_allocation_functions;
-
-/* malloc, never returns NULL */
-void *gpr_malloc(size_t size);
-/* free */
-void gpr_free(void *ptr);
-/* realloc, never returns NULL */
-void *gpr_realloc(void *p, size_t size);
-/* aligned malloc, never returns NULL, will align to 1 << alignment_log */
-void *gpr_malloc_aligned(size_t size, size_t alignment_log);
-/* free memory allocated by gpr_malloc_aligned */
-void gpr_free_aligned(void *ptr);
-
-/** Request the family of allocation functions in \a functions be used. NOTE
- * that this request will be honored in a *best effort* basis and that no
- * guarantees are made about the default functions (eg, malloc) being called. */
-void gpr_set_allocation_functions(gpr_allocation_functions functions);
-
-/** Return the family of allocation functions currently in effect. */
-gpr_allocation_functions gpr_get_allocation_functions();
-
-#ifdef __cplusplus
-}
-#endif
+#include <grpc/impl/codegen/alloc.h>
 
 #endif /* GRPC_SUPPORT_ALLOC_H */
diff --git a/include/grpc/support/atm.h b/include/grpc/support/atm.h
index cbb3813..37975db 100644
--- a/include/grpc/support/atm.h
+++ b/include/grpc/support/atm.h
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -34,59 +34,6 @@
 #ifndef GRPC_SUPPORT_ATM_H
 #define GRPC_SUPPORT_ATM_H
 
-/* This interface provides atomic operations and barriers.
-   It is internal to gpr support code and should not be used outside it.
-
-   If an operation with acquire semantics precedes another memory access by the
-   same thread, the operation will precede that other access as seen by other
-   threads.
-
-   If an operation with release semantics follows another memory access by the
-   same thread, the operation will follow that other access as seen by other
-   threads.
-
-   Routines with "acq" or "full" in the name have acquire semantics.  Routines
-   with "rel" or "full" in the name have release semantics.  Routines with
-   "no_barrier" in the name have neither acquire not release semantics.
-
-   The routines may be implemented as macros.
-
-   // Atomic operations act on an intergral_type gpr_atm that is guaranteed to
-   // be the same size as a pointer.
-   typedef intptr_t gpr_atm;
-
-   // A memory barrier, providing both acquire and release semantics, but not
-   // otherwise acting on memory.
-   void gpr_atm_full_barrier(void);
-
-   // Atomically return *p, with acquire semantics.
-   gpr_atm gpr_atm_acq_load(gpr_atm *p);
-
-   // Atomically set *p = value, with release semantics.
-   void gpr_atm_rel_store(gpr_atm *p, gpr_atm value);
-
-   // Atomically add delta to *p, and return the old value of *p, with
-   // the barriers specified.
-   gpr_atm gpr_atm_no_barrier_fetch_add(gpr_atm *p, gpr_atm delta);
-   gpr_atm gpr_atm_full_fetch_add(gpr_atm *p, gpr_atm delta);
-
-   // Atomically, if *p==o, set *p=n and return non-zero otherwise return 0,
-   // with the barriers specified if the operation succeeds.
-   int gpr_atm_no_barrier_cas(gpr_atm *p, gpr_atm o, gpr_atm n);
-   int gpr_atm_acq_cas(gpr_atm *p, gpr_atm o, gpr_atm n);
-   int gpr_atm_rel_cas(gpr_atm *p, gpr_atm o, gpr_atm n);
-*/
-
-#include <grpc/support/port_platform.h>
-
-#if defined(GPR_GCC_ATOMIC)
-#include <grpc/support/atm_gcc_atomic.h>
-#elif defined(GPR_GCC_SYNC)
-#include <grpc/support/atm_gcc_sync.h>
-#elif defined(GPR_WIN32_ATOMIC)
-#include <grpc/support/atm_win32.h>
-#else
-#error could not determine platform for atm
-#endif
+#include <grpc/impl/codegen/atm.h>
 
 #endif /* GRPC_SUPPORT_ATM_H */
diff --git a/include/grpc/support/atm_gcc_atomic.h b/include/grpc/support/atm_gcc_atomic.h
index 90d91dd..7e1f7fd 100644
--- a/include/grpc/support/atm_gcc_atomic.h
+++ b/include/grpc/support/atm_gcc_atomic.h
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -31,42 +31,9 @@
  *
  */
 
-#ifndef GRPC_SUPPORT_ATM_GCC_ATOMIC_H
-#define GRPC_SUPPORT_ATM_GCC_ATOMIC_H
+#ifndef GRPC_IMPL_CODEGEN_ATM_GCC_ATOMIC_H
+#define GRPC_IMPL_CODEGEN_ATM_GCC_ATOMIC_H
 
-/* atm_platform.h for gcc and gcc-like compilers with the
-   __atomic_* interface.  */
-#include <grpc/support/port_platform.h>
+#include <grpc/impl/codegen/atm_gcc_atomic.h>
 
-typedef intptr_t gpr_atm;
-
-#define gpr_atm_full_barrier() (__atomic_thread_fence(__ATOMIC_SEQ_CST))
-
-#define gpr_atm_acq_load(p) (__atomic_load_n((p), __ATOMIC_ACQUIRE))
-#define gpr_atm_no_barrier_load(p) (__atomic_load_n((p), __ATOMIC_RELAXED))
-#define gpr_atm_rel_store(p, value) \
-  (__atomic_store_n((p), (intptr_t)(value), __ATOMIC_RELEASE))
-#define gpr_atm_no_barrier_store(p, value) \
-  (__atomic_store_n((p), (intptr_t)(value), __ATOMIC_RELAXED))
-
-#define gpr_atm_no_barrier_fetch_add(p, delta) \
-  (__atomic_fetch_add((p), (intptr_t)(delta), __ATOMIC_RELAXED))
-#define gpr_atm_full_fetch_add(p, delta) \
-  (__atomic_fetch_add((p), (intptr_t)(delta), __ATOMIC_ACQ_REL))
-
-static __inline int gpr_atm_no_barrier_cas(gpr_atm *p, gpr_atm o, gpr_atm n) {
-  return __atomic_compare_exchange_n(p, &o, n, 0, __ATOMIC_RELAXED,
-                                     __ATOMIC_RELAXED);
-}
-
-static __inline int gpr_atm_acq_cas(gpr_atm *p, gpr_atm o, gpr_atm n) {
-  return __atomic_compare_exchange_n(p, &o, n, 0, __ATOMIC_ACQUIRE,
-                                     __ATOMIC_RELAXED);
-}
-
-static __inline int gpr_atm_rel_cas(gpr_atm *p, gpr_atm o, gpr_atm n) {
-  return __atomic_compare_exchange_n(p, &o, n, 0, __ATOMIC_RELEASE,
-                                     __ATOMIC_RELAXED);
-}
-
-#endif /* GRPC_SUPPORT_ATM_GCC_ATOMIC_H */
+#endif /* GRPC_IMPL_CODEGEN_ATM_GCC_ATOMIC_H */
diff --git a/include/grpc/support/atm_gcc_sync.h b/include/grpc/support/atm_gcc_sync.h
index 9d72cd4..4a61dbd 100644
--- a/include/grpc/support/atm_gcc_sync.h
+++ b/include/grpc/support/atm_gcc_sync.h
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -34,54 +34,6 @@
 #ifndef GRPC_SUPPORT_ATM_GCC_SYNC_H
 #define GRPC_SUPPORT_ATM_GCC_SYNC_H
 
-/* variant of atm_platform.h for gcc and gcc-like compiers with __sync_*
-   interface */
-#include <grpc/support/port_platform.h>
-
-typedef intptr_t gpr_atm;
-
-#define GPR_ATM_COMPILE_BARRIER_() __asm__ __volatile__("" : : : "memory")
-
-#if defined(__i386) || defined(__x86_64__)
-/* All loads are acquire loads and all stores are release stores.  */
-#define GPR_ATM_LS_BARRIER_() GPR_ATM_COMPILE_BARRIER_()
-#else
-#define GPR_ATM_LS_BARRIER_() gpr_atm_full_barrier()
-#endif
-
-#define gpr_atm_full_barrier() (__sync_synchronize())
-
-static __inline gpr_atm gpr_atm_acq_load(const gpr_atm *p) {
-  gpr_atm value = *p;
-  GPR_ATM_LS_BARRIER_();
-  return value;
-}
-
-static __inline gpr_atm gpr_atm_no_barrier_load(const gpr_atm *p) {
-  gpr_atm value = *p;
-  GPR_ATM_COMPILE_BARRIER_();
-  return value;
-}
-
-static __inline void gpr_atm_rel_store(gpr_atm *p, gpr_atm value) {
-  GPR_ATM_LS_BARRIER_();
-  *p = value;
-}
-
-static __inline void gpr_atm_no_barrier_store(gpr_atm *p, gpr_atm value) {
-  GPR_ATM_COMPILE_BARRIER_();
-  *p = value;
-}
-
-#undef GPR_ATM_LS_BARRIER_
-#undef GPR_ATM_COMPILE_BARRIER_
-
-#define gpr_atm_no_barrier_fetch_add(p, delta) \
-  gpr_atm_full_fetch_add((p), (delta))
-#define gpr_atm_full_fetch_add(p, delta) (__sync_fetch_and_add((p), (delta)))
-
-#define gpr_atm_no_barrier_cas(p, o, n) gpr_atm_acq_cas((p), (o), (n))
-#define gpr_atm_acq_cas(p, o, n) (__sync_bool_compare_and_swap((p), (o), (n)))
-#define gpr_atm_rel_cas(p, o, n) gpr_atm_acq_cas((p), (o), (n))
+#include <grpc/impl/codegen/atm_gcc_sync.h>
 
 #endif /* GRPC_SUPPORT_ATM_GCC_SYNC_H */
diff --git a/include/grpc/support/atm_win32.h b/include/grpc/support/atm_win32.h
index 8b1de76..ebb6a67 100644
--- a/include/grpc/support/atm_win32.h
+++ b/include/grpc/support/atm_win32.h
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -34,92 +34,6 @@
 #ifndef GRPC_SUPPORT_ATM_WIN32_H
 #define GRPC_SUPPORT_ATM_WIN32_H
 
-/* Win32 variant of atm_platform.h */
-#include <grpc/support/port_platform.h>
-
-typedef intptr_t gpr_atm;
-
-#define gpr_atm_full_barrier MemoryBarrier
-
-static __inline gpr_atm gpr_atm_acq_load(const gpr_atm *p) {
-  gpr_atm result = *p;
-  gpr_atm_full_barrier();
-  return result;
-}
-
-static __inline gpr_atm gpr_atm_no_barrier_load(const gpr_atm *p) {
-  /* TODO(dklempner): Can we implement something better here? */
-  return gpr_atm_acq_load(p);
-}
-
-static __inline void gpr_atm_rel_store(gpr_atm *p, gpr_atm value) {
-  gpr_atm_full_barrier();
-  *p = value;
-}
-
-static __inline void gpr_atm_no_barrier_store(gpr_atm *p, gpr_atm value) {
-  /* TODO(ctiller): Can we implement something better here? */
-  gpr_atm_rel_store(p, value);
-}
-
-static __inline int gpr_atm_no_barrier_cas(gpr_atm *p, gpr_atm o, gpr_atm n) {
-/* InterlockedCompareExchangePointerNoFence() not available on vista or
-   windows7 */
-#ifdef GPR_ARCH_64
-  return o == (gpr_atm)InterlockedCompareExchangeAcquire64(
-                  (volatile LONGLONG *)p, (LONGLONG)n, (LONGLONG)o);
-#else
-  return o == (gpr_atm)InterlockedCompareExchangeAcquire((volatile LONG *)p,
-                                                         (LONG)n, (LONG)o);
-#endif
-}
-
-static __inline int gpr_atm_acq_cas(gpr_atm *p, gpr_atm o, gpr_atm n) {
-#ifdef GPR_ARCH_64
-  return o == (gpr_atm)InterlockedCompareExchangeAcquire64(
-                  (volatile LONGLONG *)p, (LONGLONG)n, (LONGLONG)o);
-#else
-  return o == (gpr_atm)InterlockedCompareExchangeAcquire((volatile LONG *)p,
-                                                         (LONG)n, (LONG)o);
-#endif
-}
-
-static __inline int gpr_atm_rel_cas(gpr_atm *p, gpr_atm o, gpr_atm n) {
-#ifdef GPR_ARCH_64
-  return o == (gpr_atm)InterlockedCompareExchangeRelease64(
-                  (volatile LONGLONG *)p, (LONGLONG)n, (LONGLONG)o);
-#else
-  return o == (gpr_atm)InterlockedCompareExchangeRelease((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 */
-  gpr_atm old;
-  do {
-    old = *p;
-  } while (!gpr_atm_no_barrier_cas(p, old, old + delta));
-  return old;
-}
-
-static __inline gpr_atm gpr_atm_full_fetch_add(gpr_atm *p, gpr_atm delta) {
-  /* Use a CAS operation to get pointer-sized fetch and add */
-  gpr_atm old;
-#ifdef GPR_ARCH_64
-  do {
-    old = *p;
-  } while (old != (gpr_atm)InterlockedCompareExchange64((volatile LONGLONG *)p,
-                                                        (LONGLONG)old + delta,
-                                                        (LONGLONG)old));
-#else
-  do {
-    old = *p;
-  } while (old != (gpr_atm)InterlockedCompareExchange(
-                      (volatile LONG *)p, (LONG)old + delta, (LONG)old));
-#endif
-  return old;
-}
+#include <grpc/impl/codegen/atm_win32.h>
 
 #endif /* GRPC_SUPPORT_ATM_WIN32_H */
diff --git a/include/grpc/support/avl.h b/include/grpc/support/avl.h
index d462f52..28eb5b1 100644
--- a/include/grpc/support/avl.h
+++ b/include/grpc/support/avl.h
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -69,23 +69,23 @@
 } gpr_avl;
 
 /** create an immutable AVL tree */
-gpr_avl gpr_avl_create(const gpr_avl_vtable *vtable);
+GPRAPI gpr_avl gpr_avl_create(const gpr_avl_vtable *vtable);
 /** add a reference to an existing tree - returns
     the tree as a convenience */
-gpr_avl gpr_avl_ref(gpr_avl avl);
+GPRAPI gpr_avl gpr_avl_ref(gpr_avl avl);
 /** remove a reference to a tree - destroying it if there
     are no references left */
-void gpr_avl_unref(gpr_avl avl);
+GPRAPI void gpr_avl_unref(gpr_avl avl);
 /** return a new tree with (key, value) added to avl.
     implicitly unrefs avl to allow easy chaining.
     if key exists in avl, the new tree's key entry updated
     (i.e. a duplicate is not created) */
-gpr_avl gpr_avl_add(gpr_avl avl, void *key, void *value);
+GPRAPI gpr_avl gpr_avl_add(gpr_avl avl, void *key, void *value);
 /** return a new tree with key deleted */
-gpr_avl gpr_avl_remove(gpr_avl avl, void *key);
+GPRAPI gpr_avl gpr_avl_remove(gpr_avl avl, void *key);
 /** lookup key, and return the associated value.
     does not mutate avl.
     returns NULL if key is not found. */
-void *gpr_avl_get(gpr_avl avl, void *key);
+GPRAPI void *gpr_avl_get(gpr_avl avl, void *key);
 
 #endif
diff --git a/include/grpc/support/cmdline.h b/include/grpc/support/cmdline.h
index 3058cf9..55e2ffd 100644
--- a/include/grpc/support/cmdline.h
+++ b/include/grpc/support/cmdline.h
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -34,6 +34,8 @@
 #ifndef GRPC_SUPPORT_CMDLINE_H
 #define GRPC_SUPPORT_CMDLINE_H
 
+#include <grpc/support/port_platform.h>
+
 #ifdef __cplusplus
 extern "C" {
 #endif
@@ -68,31 +70,31 @@
 
 /* Construct a command line parser: takes a short description of the tool
    doing the parsing */
-gpr_cmdline *gpr_cmdline_create(const char *description);
+GPRAPI gpr_cmdline *gpr_cmdline_create(const char *description);
 /* Add an integer parameter, with a name (used on the command line) and some
    helpful text (used in the command usage) */
-void gpr_cmdline_add_int(gpr_cmdline *cl, const char *name, const char *help,
-                         int *value);
+GPRAPI void gpr_cmdline_add_int(gpr_cmdline *cl, const char *name,
+                                const char *help, int *value);
 /* The same, for a boolean flag */
-void gpr_cmdline_add_flag(gpr_cmdline *cl, const char *name, const char *help,
-                          int *value);
+GPRAPI void gpr_cmdline_add_flag(gpr_cmdline *cl, const char *name,
+                                 const char *help, int *value);
 /* And for a string */
-void gpr_cmdline_add_string(gpr_cmdline *cl, const char *name, const char *help,
-                            char **value);
+GPRAPI void gpr_cmdline_add_string(gpr_cmdline *cl, const char *name,
+                                   const char *help, char **value);
 /* Set a callback for non-named arguments */
-void gpr_cmdline_on_extra_arg(
+GPRAPI void gpr_cmdline_on_extra_arg(
     gpr_cmdline *cl, const char *name, const char *help,
     void (*on_extra_arg)(void *user_data, const char *arg), void *user_data);
 /* Enable surviving failure: default behavior is to exit the process */
-void gpr_cmdline_set_survive_failure(gpr_cmdline *cl);
+GPRAPI void gpr_cmdline_set_survive_failure(gpr_cmdline *cl);
 /* Parse the command line; returns 1 on success, on failure either dies
    (by default) or returns 0 if gpr_cmdline_set_survive_failure() has been
    called */
-int gpr_cmdline_parse(gpr_cmdline *cl, int argc, char **argv);
+GPRAPI int gpr_cmdline_parse(gpr_cmdline *cl, int argc, char **argv);
 /* Destroy the parser */
-void gpr_cmdline_destroy(gpr_cmdline *cl);
+GPRAPI void gpr_cmdline_destroy(gpr_cmdline *cl);
 /* Get a string describing usage */
-char *gpr_cmdline_usage_string(gpr_cmdline *cl, const char *argv0);
+GPRAPI char *gpr_cmdline_usage_string(gpr_cmdline *cl, const char *argv0);
 
 #ifdef __cplusplus
 }
diff --git a/include/grpc/support/cpu.h b/include/grpc/support/cpu.h
index 7d8af59..3ca83b5 100644
--- a/include/grpc/support/cpu.h
+++ b/include/grpc/support/cpu.h
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -34,6 +34,8 @@
 #ifndef GRPC_SUPPORT_CPU_H
 #define GRPC_SUPPORT_CPU_H
 
+#include <grpc/support/port_platform.h>
+
 #ifdef __cplusplus
 extern "C" {
 #endif
@@ -42,13 +44,13 @@
 
 /* Return the number of CPU cores on the current system. Will return 0 if
    the information is not available. */
-unsigned gpr_cpu_num_cores(void);
+GPRAPI unsigned gpr_cpu_num_cores(void);
 
 /* Return the CPU on which the current thread is executing; N.B. This should
    be considered advisory only - it is possible that the thread is switched
    to a different CPU at any time. Returns a value in range
    [0, gpr_cpu_num_cores() - 1] */
-unsigned gpr_cpu_current_cpu(void);
+GPRAPI unsigned gpr_cpu_current_cpu(void);
 
 #ifdef __cplusplus
 }  // extern "C"
diff --git a/include/grpc/support/histogram.h b/include/grpc/support/histogram.h
index 8774676..c34c8c8 100644
--- a/include/grpc/support/histogram.h
+++ b/include/grpc/support/histogram.h
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -43,31 +43,34 @@
 
 typedef struct gpr_histogram gpr_histogram;
 
-gpr_histogram *gpr_histogram_create(double resolution, double max_bucket_start);
-void gpr_histogram_destroy(gpr_histogram *h);
-void gpr_histogram_add(gpr_histogram *h, double x);
+GPRAPI gpr_histogram *gpr_histogram_create(double resolution,
+                                           double max_bucket_start);
+GPRAPI void gpr_histogram_destroy(gpr_histogram *h);
+GPRAPI void gpr_histogram_add(gpr_histogram *h, double x);
 
 /* The following merges the second histogram into the first. It only works
    if they have the same buckets and resolution. Returns 0 on failure, 1
    on success */
-int gpr_histogram_merge(gpr_histogram *dst, const gpr_histogram *src);
+GPRAPI int gpr_histogram_merge(gpr_histogram *dst, const gpr_histogram *src);
 
-double gpr_histogram_percentile(gpr_histogram *histogram, double percentile);
-double gpr_histogram_mean(gpr_histogram *histogram);
-double gpr_histogram_stddev(gpr_histogram *histogram);
-double gpr_histogram_variance(gpr_histogram *histogram);
-double gpr_histogram_maximum(gpr_histogram *histogram);
-double gpr_histogram_minimum(gpr_histogram *histogram);
-double gpr_histogram_count(gpr_histogram *histogram);
-double gpr_histogram_sum(gpr_histogram *histogram);
-double gpr_histogram_sum_of_squares(gpr_histogram *histogram);
+GPRAPI double gpr_histogram_percentile(gpr_histogram *histogram,
+                                       double percentile);
+GPRAPI double gpr_histogram_mean(gpr_histogram *histogram);
+GPRAPI double gpr_histogram_stddev(gpr_histogram *histogram);
+GPRAPI double gpr_histogram_variance(gpr_histogram *histogram);
+GPRAPI double gpr_histogram_maximum(gpr_histogram *histogram);
+GPRAPI double gpr_histogram_minimum(gpr_histogram *histogram);
+GPRAPI double gpr_histogram_count(gpr_histogram *histogram);
+GPRAPI double gpr_histogram_sum(gpr_histogram *histogram);
+GPRAPI double gpr_histogram_sum_of_squares(gpr_histogram *histogram);
 
-const uint32_t *gpr_histogram_get_contents(gpr_histogram *histogram,
-                                           size_t *count);
-void gpr_histogram_merge_contents(gpr_histogram *histogram,
-                                  const uint32_t *data, size_t data_count,
-                                  double min_seen, double max_seen, double sum,
-                                  double sum_of_squares, double count);
+GPRAPI const uint32_t *gpr_histogram_get_contents(gpr_histogram *histogram,
+                                                  size_t *count);
+GPRAPI void gpr_histogram_merge_contents(gpr_histogram *histogram,
+                                         const uint32_t *data,
+                                         size_t data_count, double min_seen,
+                                         double max_seen, double sum,
+                                         double sum_of_squares, double count);
 
 #ifdef __cplusplus
 }
diff --git a/include/grpc/support/host_port.h b/include/grpc/support/host_port.h
index 375d177..53cc917 100644
--- a/include/grpc/support/host_port.h
+++ b/include/grpc/support/host_port.h
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -34,6 +34,8 @@
 #ifndef GRPC_SUPPORT_HOST_PORT_H
 #define GRPC_SUPPORT_HOST_PORT_H
 
+#include <grpc/support/port_platform.h>
+
 #ifdef __cplusplus
 extern "C" {
 #endif
@@ -48,14 +50,14 @@
    destroyed using gpr_free().
 
    In the unlikely event of an error, returns -1 and sets *out to NULL. */
-int gpr_join_host_port(char **out, const char *host, int port);
+GPRAPI int gpr_join_host_port(char **out, const char *host, int port);
 
 /* Given a name in the form "host:port" or "[ho:st]:port", split into hostname
    and port number, into newly allocated strings, which must later be
    destroyed using gpr_free().
    Return 1 on success, 0 on failure. Guarantees *host and *port == NULL on
    failure. */
-int gpr_split_host_port(const char *name, char **host, char **port);
+GPRAPI int gpr_split_host_port(const char *name, char **host, char **port);
 
 #ifdef __cplusplus
 }
diff --git a/include/grpc/support/log.h b/include/grpc/support/log.h
index 59db4ba..e6f6dd9 100644
--- a/include/grpc/support/log.h
+++ b/include/grpc/support/log.h
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -34,75 +34,6 @@
 #ifndef GRPC_SUPPORT_LOG_H
 #define GRPC_SUPPORT_LOG_H
 
-#include <stdlib.h> /* for abort() */
-#include <stdarg.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/* GPR log API.
-
-   Usage (within grpc):
-
-   int argument1 = 3;
-   char* argument2 = "hello";
-   gpr_log(GPR_DEBUG, "format string %d", argument1);
-   gpr_log(GPR_INFO, "hello world");
-   gpr_log(GPR_ERROR, "%d %s!!", argument1, argument2); */
-
-/* The severity of a log message - use the #defines below when calling into
-   gpr_log to additionally supply file and line data */
-typedef enum gpr_log_severity {
-  GPR_LOG_SEVERITY_DEBUG,
-  GPR_LOG_SEVERITY_INFO,
-  GPR_LOG_SEVERITY_ERROR
-} gpr_log_severity;
-
-/* Returns a string representation of the log severity */
-const char *gpr_log_severity_string(gpr_log_severity severity);
-
-/* Macros to build log contexts at various severity levels */
-#define GPR_DEBUG __FILE__, __LINE__, GPR_LOG_SEVERITY_DEBUG
-#define GPR_INFO __FILE__, __LINE__, GPR_LOG_SEVERITY_INFO
-#define GPR_ERROR __FILE__, __LINE__, GPR_LOG_SEVERITY_ERROR
-
-/* Log a message. It's advised to use GPR_xxx above to generate the context
- * for each message */
-void gpr_log(const char *file, int line, gpr_log_severity severity,
-             const char *format, ...);
-
-void gpr_log_message(const char *file, int line, gpr_log_severity severity,
-                     const char *message);
-
-/* Log overrides: applications can use this API to intercept logging calls
-   and use their own implementations */
-
-typedef struct {
-  const char *file;
-  int line;
-  gpr_log_severity severity;
-  const char *message;
-} gpr_log_func_args;
-
-typedef void (*gpr_log_func)(gpr_log_func_args *args);
-void gpr_set_log_function(gpr_log_func func);
-
-/* abort() the process if x is zero, having written a line to the log.
-
-   Intended for internal invariants.  If the error can be recovered from,
-   without the possibility of corruption, or might best be reflected via
-   an exception in a higher-level language, consider returning error code.  */
-#define GPR_ASSERT(x)                                 \
-  do {                                                \
-    if (!(x)) {                                       \
-      gpr_log(GPR_ERROR, "assertion failed: %s", #x); \
-      abort();                                        \
-    }                                                 \
-  } while (0)
-
-#ifdef __cplusplus
-}
-#endif
+#include <grpc/impl/codegen/log.h>
 
 #endif /* GRPC_SUPPORT_LOG_H */
diff --git a/include/grpc/support/log_win32.h b/include/grpc/support/log_win32.h
index ea6b16d..49c9ab0 100644
--- a/include/grpc/support/log_win32.h
+++ b/include/grpc/support/log_win32.h
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -42,7 +42,7 @@
  * formatted error message, corresponding to the error messageid.
  * Use in conjunction with GetLastError() et al.
  */
-char *gpr_format_message(DWORD messageid);
+GPRAPI char *gpr_format_message(int messageid);
 
 #ifdef __cplusplus
 }
diff --git a/include/grpc/support/port_platform.h b/include/grpc/support/port_platform.h
index 8a30f1d..6b14f8b 100644
--- a/include/grpc/support/port_platform.h
+++ b/include/grpc/support/port_platform.h
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -34,307 +34,6 @@
 #ifndef GRPC_SUPPORT_PORT_PLATFORM_H
 #define GRPC_SUPPORT_PORT_PLATFORM_H
 
-/* Get windows.h included everywhere (we need it) */
-#if defined(_WIN64) || defined(WIN64) || defined(_WIN32) || defined(WIN32)
-#ifndef WIN32_LEAN_AND_MEAN
-#define GRPC_WIN32_LEAN_AND_MEAN_WAS_NOT_DEFINED
-#define WIN32_LEAN_AND_MEAN
-#endif /* WIN32_LEAN_AND_MEAN */
-
-#ifndef NOMINMAX
-#define GRPC_NOMINMX_WAS_NOT_DEFINED
-#define NOMINMAX
-#endif /* NOMINMAX */
-
-#ifndef _WIN32_WINNT
-#error \
-    "Please compile grpc with _WIN32_WINNT of at least 0x600 (aka Windows Vista)"
-#else /* !defined(_WIN32_WINNT) */
-#if (_WIN32_WINNT < 0x0600)
-#error \
-    "Please compile grpc with _WIN32_WINNT of at least 0x600 (aka Windows Vista)"
-#endif /* _WIN32_WINNT < 0x0600 */
-#endif /* defined(_WIN32_WINNT) */
-
-#include <windows.h>
-
-#ifdef GRPC_WIN32_LEAN_AND_MEAN_WAS_NOT_DEFINED
-#undef GRPC_WIN32_LEAN_AND_MEAN_WAS_NOT_DEFINED
-#undef WIN32_LEAN_AND_MEAN
-#endif /* GRPC_WIN32_LEAN_AND_MEAN_WAS_NOT_DEFINED */
-
-#ifdef GRPC_NOMINMAX_WAS_NOT_DEFINED
-#undef GRPC_NOMINMAX_WAS_NOT_DEFINED
-#undef NOMINMAX
-#endif /* GRPC_WIN32_LEAN_AND_MEAN_WAS_NOT_DEFINED */
-#endif /* defined(_WIN64) || defined(WIN64) || defined(_WIN32) || \
-          defined(WIN32) */
-
-/* Override this file with one for your platform if you need to redefine
-   things.  */
-
-#if !defined(GPR_NO_AUTODETECT_PLATFORM)
-#if defined(_WIN64) || defined(WIN64)
-#define GPR_PLATFORM_STRING "windows"
-#define GPR_WIN32 1
-#define GPR_ARCH_64 1
-#define GPR_GETPID_IN_PROCESS_H 1
-#define GPR_WINSOCK_SOCKET 1
-#ifdef __GNUC__
-#define GPR_GCC_ATOMIC 1
-#define GPR_GCC_TLS 1
-#else
-#define GPR_WIN32_ATOMIC 1
-#define GPR_MSVC_TLS 1
-#endif
-#define GPR_WINDOWS_CRASH_HANDLER 1
-#elif defined(_WIN32) || defined(WIN32)
-#define GPR_PLATFORM_STRING "windows"
-#define GPR_ARCH_32 1
-#define GPR_WIN32 1
-#define GPR_GETPID_IN_PROCESS_H 1
-#define GPR_WINSOCK_SOCKET 1
-#ifdef __GNUC__
-#define GPR_GCC_ATOMIC 1
-#define GPR_GCC_TLS 1
-#else
-#define GPR_WIN32_ATOMIC 1
-#define GPR_MSVC_TLS 1
-#endif
-#define GPR_WINDOWS_CRASH_HANDLER 1
-#elif defined(ANDROID) || defined(__ANDROID__)
-#define GPR_PLATFORM_STRING "android"
-#define GPR_ANDROID 1
-#define GPR_ARCH_32 1
-#define GPR_CPU_LINUX 1
-#define GPR_GCC_SYNC 1
-#define GPR_GCC_TLS 1
-#define GPR_POSIX_MULTIPOLL_WITH_POLL 1
-#define GPR_POSIX_WAKEUP_FD 1
-#define GPR_LINUX_EVENTFD 1
-#define GPR_POSIX_SOCKET 1
-#define GPR_POSIX_SOCKETADDR 1
-#define GPR_POSIX_SOCKETUTILS 1
-#define GPR_POSIX_ENV 1
-#define GPR_POSIX_FILE 1
-#define GPR_POSIX_STRING 1
-#define GPR_POSIX_SUBPROCESS 1
-#define GPR_POSIX_SYNC 1
-#define GPR_POSIX_TIME 1
-#define GPR_GETPID_IN_UNISTD_H 1
-#define GPR_HAVE_MSG_NOSIGNAL 1
-#elif defined(__linux__)
-#define GPR_POSIX_CRASH_HANDLER 1
-#define GPR_PLATFORM_STRING "linux"
-#ifndef _BSD_SOURCE
-#define _BSD_SOURCE
-#endif
-#ifndef _DEFAULT_SOURCE
-#define _DEFAULT_SOURCE
-#endif
-#ifndef _GNU_SOURCE
-#define _GNU_SOURCE
-#endif
-#include <features.h>
-#define GPR_CPU_LINUX 1
-#define GPR_GCC_ATOMIC 1
-#define GPR_GCC_TLS 1
-#define GPR_LINUX 1
-#define GPR_LINUX_MULTIPOLL_WITH_EPOLL 1
-#define GPR_POSIX_WAKEUP_FD 1
-#define GPR_POSIX_SOCKET 1
-#define GPR_POSIX_SOCKETADDR 1
-#ifdef __GLIBC_PREREQ
-#if __GLIBC_PREREQ(2, 9)
-#define GPR_LINUX_EVENTFD 1
-#endif
-#if __GLIBC_PREREQ(2, 10)
-#define GPR_LINUX_SOCKETUTILS 1
-#endif
-#if __GLIBC_PREREQ(2, 17)
-#define GPR_LINUX_ENV 1
-#endif
-#endif
-#ifndef GPR_LINUX_EVENTFD
-#define GPR_POSIX_NO_SPECIAL_WAKEUP_FD 1
-#endif
-#ifndef GPR_LINUX_SOCKETUTILS
-#define GPR_POSIX_SOCKETUTILS
-#endif
-#ifndef GPR_LINUX_ENV
-#define GPR_POSIX_ENV 1
-#endif
-#define GPR_POSIX_FILE 1
-#define GPR_POSIX_STRING 1
-#define GPR_POSIX_SUBPROCESS 1
-#define GPR_POSIX_SYNC 1
-#define GPR_POSIX_TIME 1
-#define GPR_GETPID_IN_UNISTD_H 1
-#define GPR_HAVE_MSG_NOSIGNAL 1
-#ifdef _LP64
-#define GPR_ARCH_64 1
-#else /* _LP64 */
-#define GPR_ARCH_32 1
-#endif /* _LP64 */
-#elif defined(__APPLE__)
-#include <TargetConditionals.h>
-#ifndef _BSD_SOURCE
-#define _BSD_SOURCE
-#endif
-#define GPR_MSG_IOVLEN_TYPE int
-#if TARGET_OS_IPHONE
-#define GPR_FORBID_UNREACHABLE_CODE 1
-#define GPR_PLATFORM_STRING "ios"
-#define GPR_CPU_IPHONE 1
-#define GPR_PTHREAD_TLS 1
-#else /* TARGET_OS_IPHONE */
-#define GPR_PLATFORM_STRING "osx"
-#define GPR_CPU_POSIX 1
-#define GPR_GCC_TLS 1
-#define GPR_POSIX_CRASH_HANDLER 1
-#endif
-#define GPR_GCC_ATOMIC 1
-#define GPR_POSIX_LOG 1
-#define GPR_POSIX_MULTIPOLL_WITH_POLL 1
-#define GPR_POSIX_WAKEUP_FD 1
-#define GPR_POSIX_NO_SPECIAL_WAKEUP_FD 1
-#define GPR_POSIX_SOCKET 1
-#define GPR_POSIX_SOCKETADDR 1
-#define GPR_POSIX_SOCKETUTILS 1
-#define GPR_POSIX_ENV 1
-#define GPR_POSIX_FILE 1
-#define GPR_POSIX_STRING 1
-#define GPR_POSIX_SUBPROCESS 1
-#define GPR_POSIX_SYNC 1
-#define GPR_POSIX_TIME 1
-#define GPR_GETPID_IN_UNISTD_H 1
-#define GPR_HAVE_SO_NOSIGPIPE 1
-#ifdef _LP64
-#define GPR_ARCH_64 1
-#else /* _LP64 */
-#define GPR_ARCH_32 1
-#endif /* _LP64 */
-#elif defined(__FreeBSD__)
-#define GPR_PLATFORM_STRING "freebsd"
-#ifndef _BSD_SOURCE
-#define _BSD_SOURCE
-#endif
-#define GPR_CPU_POSIX 1
-#define GPR_GCC_ATOMIC 1
-#define GPR_GCC_TLS 1
-#define GPR_POSIX_LOG 1
-#define GPR_POSIX_MULTIPOLL_WITH_POLL 1
-#define GPR_POSIX_WAKEUP_FD 1
-#define GPR_POSIX_NO_SPECIAL_WAKEUP_FD 1
-#define GPR_POSIX_SOCKET 1
-#define GPR_POSIX_SOCKETADDR 1
-#define GPR_POSIX_SOCKETUTILS 1
-#define GPR_POSIX_ENV 1
-#define GPR_POSIX_FILE 1
-#define GPR_POSIX_STRING 1
-#define GPR_POSIX_SUBPROCESS 1
-#define GPR_POSIX_SYNC 1
-#define GPR_POSIX_TIME 1
-#define GPR_GETPID_IN_UNISTD_H 1
-#define GPR_HAVE_SO_NOSIGPIPE 1
-#ifdef _LP64
-#define GPR_ARCH_64 1
-#else /* _LP64 */
-#define GPR_ARCH_32 1
-#endif /* _LP64 */
-#else
-#error Could not auto-detect platform
-#endif
-#endif /* GPR_NO_AUTODETECT_PLATFORM */
-
-#ifndef GPR_PLATFORM_STRING
-#warning "GPR_PLATFORM_STRING not auto-detected"
-#define GPR_PLATFORM_STRING "unknown"
-#endif
-
-#ifdef GPR_GCOV
-#undef GPR_FORBID_UNREACHABLE_CODE
-#define GPR_FORBID_UNREACHABLE_CODE 1
-#endif
-
-/* For a common case, assume that the platform has a C99-like stdint.h */
-
-#include <stdint.h>
-
-/* Cache line alignment */
-#ifndef GPR_CACHELINE_SIZE_LOG
-#if defined(__i386__) || defined(__x86_64__)
-#define GPR_CACHELINE_SIZE_LOG 6
-#endif
-#ifndef GPR_CACHELINE_SIZE_LOG
-/* A reasonable default guess. Note that overestimates tend to waste more
-   space, while underestimates tend to waste more time. */
-#define GPR_CACHELINE_SIZE_LOG 6
-#endif /* GPR_CACHELINE_SIZE_LOG */
-#endif /* GPR_CACHELINE_SIZE_LOG */
-
-#define GPR_CACHELINE_SIZE (1 << GPR_CACHELINE_SIZE_LOG)
-
-/* scrub GCC_ATOMIC if it's not available on this compiler */
-#if defined(GPR_GCC_ATOMIC) && !defined(__ATOMIC_RELAXED)
-#undef GPR_GCC_ATOMIC
-#define GPR_GCC_SYNC 1
-#endif
-
-/* Validate platform combinations */
-#if defined(GPR_GCC_ATOMIC) + defined(GPR_GCC_SYNC) + \
-        defined(GPR_WIN32_ATOMIC) !=                  \
-    1
-#error Must define exactly one of GPR_GCC_ATOMIC, GPR_GCC_SYNC, GPR_WIN32_ATOMIC
-#endif
-
-#if defined(GPR_ARCH_32) + defined(GPR_ARCH_64) != 1
-#error Must define exactly one of GPR_ARCH_32, GPR_ARCH_64
-#endif
-
-#if defined(GPR_CPU_LINUX) + defined(GPR_CPU_POSIX) + defined(GPR_WIN32) + \
-        defined(GPR_CPU_IPHONE) + defined(GPR_CPU_CUSTOM) !=               \
-    1
-#error Must define exactly one of GPR_CPU_LINUX, GPR_CPU_POSIX, GPR_WIN32, GPR_CPU_IPHONE, GPR_CPU_CUSTOM
-#endif
-
-#if defined(GPR_POSIX_MULTIPOLL_WITH_POLL) && !defined(GPR_POSIX_SOCKET)
-#error Must define GPR_POSIX_SOCKET to use GPR_POSIX_MULTIPOLL_WITH_POLL
-#endif
-
-#if defined(GPR_POSIX_SOCKET) + defined(GPR_WINSOCK_SOCKET) + \
-        defined(GPR_CUSTOM_SOCKET) !=                         \
-    1
-#error Must define exactly one of GPR_POSIX_SOCKET, GPR_WINSOCK_SOCKET, GPR_CUSTOM_SOCKET
-#endif
-
-#if defined(GPR_MSVC_TLS) + defined(GPR_GCC_TLS) + defined(GPR_PTHREAD_TLS) + \
-        defined(GPR_CUSTOM_TLS) !=                                            \
-    1
-#error Must define exactly one of GPR_MSVC_TLS, GPR_GCC_TLS, GPR_PTHREAD_TLS, GPR_CUSTOM_TLS
-#endif
-
-/* maximum alignment needed for any type on this platform, rounded up to a
-   power of two */
-#define GPR_MAX_ALIGNMENT 16
-
-#ifndef GRPC_MUST_USE_RESULT
-#ifdef __GNUC__
-#define GRPC_MUST_USE_RESULT __attribute__((warn_unused_result))
-#else
-#define GRPC_MUST_USE_RESULT
-#endif
-#endif
-
-#if GPR_FORBID_UNREACHABLE_CODE
-#define GPR_UNREACHABLE_CODE(STATEMENT)
-#else
-#define GPR_UNREACHABLE_CODE(STATEMENT)             \
-  do {                                              \
-    gpr_log(GPR_ERROR, "Should never reach here."); \
-    abort();                                        \
-    STATEMENT;                                      \
-  } while (0)
-#endif /* GPR_FORBID_UNREACHABLE_CODE */
+#include <grpc/impl/codegen/port_platform.h>
 
 #endif /* GRPC_SUPPORT_PORT_PLATFORM_H */
diff --git a/include/grpc/support/slice.h b/include/grpc/support/slice.h
index 26ca9a8..b3a73b2 100644
--- a/include/grpc/support/slice.h
+++ b/include/grpc/support/slice.h
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -34,149 +34,6 @@
 #ifndef GRPC_SUPPORT_SLICE_H
 #define GRPC_SUPPORT_SLICE_H
 
-#include <grpc/support/sync.h>
-
-#include <stddef.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/* Slice API
-
-   A slice represents a contiguous reference counted array of bytes.
-   It is cheap to take references to a slice, and it is cheap to create a
-   slice pointing to a subset of another slice.
-
-   The data-structure for slices is exposed here to allow non-gpr code to
-   build slices from whatever data they have available.
-
-   When defining interfaces that handle slices, care should be taken to define
-   reference ownership semantics (who should call unref?) and mutability
-   constraints (is the callee allowed to modify the slice?) */
-
-/* Reference count container for gpr_slice. Contains function pointers to
-   increment and decrement reference counts. Implementations should cleanup
-   when the reference count drops to zero.
-   Typically client code should not touch this, and use gpr_slice_malloc,
-   gpr_slice_new, or gpr_slice_new_with_len instead. */
-typedef struct gpr_slice_refcount {
-  void (*ref)(void *);
-  void (*unref)(void *);
-} gpr_slice_refcount;
-
-#define GPR_SLICE_INLINED_SIZE (sizeof(size_t) + sizeof(uint8_t *) - 1)
-
-/* A gpr_slice s, if initialized, represents the byte range
-   s.bytes[0..s.length-1].
-
-   It can have an associated ref count which has a destruction routine to be run
-   when the ref count reaches zero (see gpr_slice_new() and grp_slice_unref()).
-   Multiple gpr_slice values may share a ref count.
-
-   If the slice does not have a refcount, it represents an inlined small piece
-   of data that is copied by value. */
-typedef struct gpr_slice {
-  struct gpr_slice_refcount *refcount;
-  union {
-    struct {
-      uint8_t *bytes;
-      size_t length;
-    } refcounted;
-    struct {
-      uint8_t length;
-      uint8_t bytes[GPR_SLICE_INLINED_SIZE];
-    } inlined;
-  } data;
-} gpr_slice;
-
-#define GPR_SLICE_START_PTR(slice)                  \
-  ((slice).refcount ? (slice).data.refcounted.bytes \
-                    : (slice).data.inlined.bytes)
-#define GPR_SLICE_LENGTH(slice)                      \
-  ((slice).refcount ? (slice).data.refcounted.length \
-                    : (slice).data.inlined.length)
-#define GPR_SLICE_SET_LENGTH(slice, newlen)                               \
-  ((slice).refcount ? ((slice).data.refcounted.length = (size_t)(newlen)) \
-                    : ((slice).data.inlined.length = (uint8_t)(newlen)))
-#define GPR_SLICE_END_PTR(slice) \
-  GPR_SLICE_START_PTR(slice) + GPR_SLICE_LENGTH(slice)
-#define GPR_SLICE_IS_EMPTY(slice) (GPR_SLICE_LENGTH(slice) == 0)
-
-/* Increment the refcount of s. Requires slice is initialized.
-   Returns s. */
-gpr_slice gpr_slice_ref(gpr_slice s);
-
-/* Decrement the ref count of s.  If the ref count of s reaches zero, all
-   slices sharing the ref count are destroyed, and considered no longer
-   initialized.  If s is ultimately derived from a call to gpr_slice_new(start,
-   len, dest) where dest!=NULL , then (*dest)(start) is called, else if s is
-   ultimately derived from a call to gpr_slice_new_with_len(start, len, dest)
-   where dest!=NULL , then (*dest)(start, len).  Requires s initialized.  */
-void gpr_slice_unref(gpr_slice s);
-
-/* Create a slice pointing at some data. Calls malloc to allocate a refcount
-   for the object, and arranges that destroy will be called with the pointer
-   passed in at destruction. */
-gpr_slice gpr_slice_new(void *p, size_t len, void (*destroy)(void *));
-
-/* Equivalent to gpr_slice_new, but with a two argument destroy function that
-   also takes the slice length. */
-gpr_slice gpr_slice_new_with_len(void *p, size_t len,
-                                 void (*destroy)(void *, size_t));
-
-/* Equivalent to gpr_slice_new(malloc(len), len, free), but saves one malloc()
-   call.
-   Aborts if malloc() fails. */
-gpr_slice gpr_slice_malloc(size_t length);
-
-/* Create a slice by copying a string.
-   Does not preserve null terminators.
-   Equivalent to:
-     size_t len = strlen(source);
-     gpr_slice slice = gpr_slice_malloc(len);
-     memcpy(slice->data, source, len); */
-gpr_slice gpr_slice_from_copied_string(const char *source);
-
-/* Create a slice by copying a buffer.
-   Equivalent to:
-     gpr_slice slice = gpr_slice_malloc(len);
-     memcpy(slice->data, source, len); */
-gpr_slice gpr_slice_from_copied_buffer(const char *source, size_t len);
-
-/* Create a slice pointing to constant memory */
-gpr_slice gpr_slice_from_static_string(const char *source);
-
-/* Return a result slice derived from s, which shares a ref count with s, where
-   result.data==s.data+begin, and result.length==end-begin.
-   The ref count of s is increased by one.
-   Requires s initialized, begin <= end, begin <= s.length, and
-   end <= source->length. */
-gpr_slice gpr_slice_sub(gpr_slice s, size_t begin, size_t end);
-
-/* The same as gpr_slice_sub, but without altering the ref count */
-gpr_slice gpr_slice_sub_no_ref(gpr_slice s, size_t begin, size_t end);
-
-/* Splits s into two: modifies s to be s[0:split], and returns a new slice,
-   sharing a refcount with s, that contains s[split:s.length].
-   Requires s intialized, split <= s.length */
-gpr_slice gpr_slice_split_tail(gpr_slice *s, size_t split);
-
-/* Splits s into two: modifies s to be s[split:s.length], and returns a new
-   slice, sharing a refcount with s, that contains s[0:split].
-   Requires s intialized, split <= s.length */
-gpr_slice gpr_slice_split_head(gpr_slice *s, size_t split);
-
-gpr_slice gpr_empty_slice(void);
-
-/* Returns <0 if a < b, ==0 if a == b, >0 if a > b
-   The order is arbitrary, and is not guaranteed to be stable across different
-   versions of the API. */
-int gpr_slice_cmp(gpr_slice a, gpr_slice b);
-int gpr_slice_str_cmp(gpr_slice a, const char *b);
-
-#ifdef __cplusplus
-}
-#endif
+#include <grpc/impl/codegen/slice.h>
 
 #endif /* GRPC_SUPPORT_SLICE_H */
diff --git a/include/grpc/support/slice_buffer.h b/include/grpc/support/slice_buffer.h
index 99f3881..7bee4dd 100644
--- a/include/grpc/support/slice_buffer.h
+++ b/include/grpc/support/slice_buffer.h
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -34,69 +34,6 @@
 #ifndef GRPC_SUPPORT_SLICE_BUFFER_H
 #define GRPC_SUPPORT_SLICE_BUFFER_H
 
-#include <grpc/support/slice.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#define GRPC_SLICE_BUFFER_INLINE_ELEMENTS 8
-
-/* Represents an expandable array of slices, to be interpreted as a single item
-   TODO(ctiller): inline some small number of elements into the struct, to
-                  avoid per-call allocations */
-typedef struct {
-  /* slices in the array */
-  gpr_slice *slices;
-  /* the number of slices in the array */
-  size_t count;
-  /* the number of slices allocated in the array */
-  size_t capacity;
-  /* the combined length of all slices in the array */
-  size_t length;
-  /* inlined elements to avoid allocations */
-  gpr_slice inlined[GRPC_SLICE_BUFFER_INLINE_ELEMENTS];
-} gpr_slice_buffer;
-
-/* initialize a slice buffer */
-void gpr_slice_buffer_init(gpr_slice_buffer *sb);
-/* destroy a slice buffer - unrefs any held elements */
-void gpr_slice_buffer_destroy(gpr_slice_buffer *sb);
-/* Add an element to a slice buffer - takes ownership of the slice.
-   This function is allowed to concatenate the passed in slice to the end of
-   some other slice if desired by the slice buffer. */
-void gpr_slice_buffer_add(gpr_slice_buffer *sb, gpr_slice slice);
-/* add an element to a slice buffer - takes ownership of the slice and returns
-   the index of the slice.
-   Guarantees that the slice will not be concatenated at the end of another
-   slice (i.e. the data for this slice will begin at the first byte of the
-   slice at the returned index in sb->slices)
-   The implementation MAY decide to concatenate data at the end of a small
-   slice added in this fashion. */
-size_t gpr_slice_buffer_add_indexed(gpr_slice_buffer *sb, gpr_slice slice);
-void gpr_slice_buffer_addn(gpr_slice_buffer *sb, gpr_slice *slices, size_t n);
-/* add a very small (less than 8 bytes) amount of data to the end of a slice
-   buffer: returns a pointer into which to add the data */
-uint8_t *gpr_slice_buffer_tiny_add(gpr_slice_buffer *sb, size_t len);
-/* pop the last buffer, but don't unref it */
-void gpr_slice_buffer_pop(gpr_slice_buffer *sb);
-/* clear a slice buffer, unref all elements */
-void gpr_slice_buffer_reset_and_unref(gpr_slice_buffer *sb);
-/* swap the contents of two slice buffers */
-void gpr_slice_buffer_swap(gpr_slice_buffer *a, gpr_slice_buffer *b);
-/* move all of the elements of src into dst */
-void gpr_slice_buffer_move_into(gpr_slice_buffer *src, gpr_slice_buffer *dst);
-/* remove n bytes from the end of a slice buffer */
-void gpr_slice_buffer_trim_end(gpr_slice_buffer *src, size_t n,
-                               gpr_slice_buffer *garbage);
-/* move the first n bytes of src into dst */
-void gpr_slice_buffer_move_first(gpr_slice_buffer *src, size_t n,
-                                 gpr_slice_buffer *dst);
-/* take the first slice in the slice buffer */
-gpr_slice gpr_slice_buffer_take_first(gpr_slice_buffer *src);
-
-#ifdef __cplusplus
-}
-#endif
+#include <grpc/impl/codegen/slice_buffer.h>
 
 #endif /* GRPC_SUPPORT_SLICE_BUFFER_H */
diff --git a/include/grpc/support/string_util.h b/include/grpc/support/string_util.h
index 109f9ff..6fc38cb 100644
--- a/include/grpc/support/string_util.h
+++ b/include/grpc/support/string_util.h
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -42,7 +42,7 @@
 
 /* Returns a copy of src that can be passed to gpr_free().
    If allocation fails or if src is NULL, returns NULL. */
-char *gpr_strdup(const char *src);
+GPRAPI char *gpr_strdup(const char *src);
 
 /* printf to a newly-allocated string.  The set of supported formats may vary
    between platforms.
@@ -52,7 +52,7 @@
 
    On error, returns -1 and sets *strp to NULL. If the format string is bad,
    the result is undefined. */
-int gpr_asprintf(char **strp, const char *format, ...);
+GPRAPI int gpr_asprintf(char **strp, const char *format, ...);
 
 #ifdef __cplusplus
 }
diff --git a/include/grpc/support/subprocess.h b/include/grpc/support/subprocess.h
index 654623f..6a49460 100644
--- a/include/grpc/support/subprocess.h
+++ b/include/grpc/support/subprocess.h
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -34,6 +34,8 @@
 #ifndef GRPC_SUPPORT_SUBPROCESS_H
 #define GRPC_SUPPORT_SUBPROCESS_H
 
+#include <grpc/support/port_platform.h>
+
 #ifdef __cplusplus
 extern "C" {
 #endif
@@ -41,14 +43,14 @@
 typedef struct gpr_subprocess gpr_subprocess;
 
 /* .exe on windows, empty on unices */
-const char *gpr_subprocess_binary_extension();
+GPRAPI const char *gpr_subprocess_binary_extension();
 
-gpr_subprocess *gpr_subprocess_create(int argc, const char **argv);
+GPRAPI gpr_subprocess *gpr_subprocess_create(int argc, const char **argv);
 /* if subprocess has not been joined, kill it */
-void gpr_subprocess_destroy(gpr_subprocess *p);
+GPRAPI void gpr_subprocess_destroy(gpr_subprocess *p);
 /* returns exit status; can be called at most once */
-int gpr_subprocess_join(gpr_subprocess *p);
-void gpr_subprocess_interrupt(gpr_subprocess *p);
+GPRAPI int gpr_subprocess_join(gpr_subprocess *p);
+GPRAPI void gpr_subprocess_interrupt(gpr_subprocess *p);
 
 #ifdef __cplusplus
 }  // extern "C"
diff --git a/include/grpc/support/sync.h b/include/grpc/support/sync.h
index 4f42cff..89cc76f 100644
--- a/include/grpc/support/sync.h
+++ b/include/grpc/support/sync.h
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -33,283 +33,7 @@
 
 #ifndef GRPC_SUPPORT_SYNC_H
 #define GRPC_SUPPORT_SYNC_H
-/* Synchronization primitives for GPR.
 
-   The type  gpr_mu              provides a non-reentrant mutex (lock).
-
-   The type  gpr_cv              provides a condition variable.
-
-   The type  gpr_once            provides for one-time initialization.
-
-   The type gpr_event            provides one-time-setting, reading, and
-                                 waiting of a void*, with memory barriers.
-
-   The type gpr_refcount         provides an object reference counter,
-                                 with memory barriers suitable to control
-                                 object lifetimes.
-
-   The type gpr_stats_counter    provides an atomic statistics counter. It
-                                 provides no memory barriers.
- */
-
-/* Platform-specific type declarations of gpr_mu and gpr_cv.   */
-#include <grpc/support/port_platform.h>
-#include <grpc/support/sync_generic.h>
-
-#if defined(GPR_POSIX_SYNC)
-#include <grpc/support/sync_posix.h>
-#elif defined(GPR_WIN32)
-#include <grpc/support/sync_win32.h>
-#elif !defined(GPR_CUSTOM_SYNC)
-#error Unable to determine platform for sync
-#endif
-
-#include <grpc/support/time.h> /* for gpr_timespec */
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/* --- Mutex interface ---
-
-   At most one thread may hold an exclusive lock on a mutex at any given time.
-   Actions taken by a thread that holds a mutex exclusively happen after
-   actions taken by all previous holders of the mutex.  Variables of type
-   gpr_mu are uninitialized when first declared.  */
-
-/* Initialize *mu.  Requires:  *mu uninitialized.  */
-void gpr_mu_init(gpr_mu *mu);
-
-/* Cause *mu no longer to be initialized, freeing any memory in use.  Requires:
-   *mu initialized; no other concurrent operation on *mu.  */
-void gpr_mu_destroy(gpr_mu *mu);
-
-/* Wait until no thread has a lock on *mu, cause the calling thread to own an
-   exclusive lock on *mu, then return.  May block indefinitely or crash if the
-   calling thread has a lock on *mu.  Requires:  *mu initialized.  */
-void gpr_mu_lock(gpr_mu *mu);
-
-/* Release an exclusive lock on *mu held by the calling thread.  Requires:  *mu
-   initialized; the calling thread holds an exclusive lock on *mu.  */
-void gpr_mu_unlock(gpr_mu *mu);
-
-/* Without blocking, attempt to acquire an exclusive lock on *mu for the
-   calling thread, then return non-zero iff success.  Fail, if any thread holds
-   the lock; succeeds with high probability if no thread holds the lock.
-   Requires:  *mu initialized.  */
-int gpr_mu_trylock(gpr_mu *mu);
-
-/* --- Condition variable interface ---
-
-   A while-loop should be used with gpr_cv_wait() when waiting for conditions
-   to become true.  See the example below.  Variables of type gpr_cv are
-   uninitialized when first declared.  */
-
-/* Initialize *cv.  Requires:  *cv uninitialized.  */
-void gpr_cv_init(gpr_cv *cv);
-
-/* Cause *cv no longer to be initialized, freeing any memory in use.  Requires:
-   *cv initialized; no other concurrent operation on *cv.*/
-void gpr_cv_destroy(gpr_cv *cv);
-
-/* Atomically release *mu and wait on *cv.  When the calling thread is woken
-   from *cv or the deadline abs_deadline is exceeded, execute gpr_mu_lock(mu)
-   and return whether the deadline was exceeded.  Use
-   abs_deadline==gpr_inf_future for no deadline.  May return even when not
-   woken explicitly.  Requires:  *mu and *cv initialized; the calling thread
-   holds an exclusive lock on *mu.  */
-int gpr_cv_wait(gpr_cv *cv, gpr_mu *mu, gpr_timespec abs_deadline);
-
-/* If any threads are waiting on *cv, wake at least one.
-   Clients may treat this as an optimization of gpr_cv_broadcast()
-   for use in the case where waking more than one waiter is not useful.
-   Requires:  *cv initialized.  */
-void gpr_cv_signal(gpr_cv *cv);
-
-/* Wake all threads waiting on *cv.  Requires:  *cv initialized.  */
-void gpr_cv_broadcast(gpr_cv *cv);
-
-/* --- One-time initialization ---
-
-   gpr_once must be declared with static storage class, and initialized with
-   GPR_ONCE_INIT.  e.g.,
-     static gpr_once once_var = GPR_ONCE_INIT;     */
-
-/* Ensure that (*init_routine)() has been called exactly once (for the
-   specified gpr_once instance) and then return.
-   If multiple threads call gpr_once() on the same gpr_once instance, one of
-   them will call (*init_routine)(), and the others will block until that call
-   finishes.*/
-void gpr_once_init(gpr_once *once, void (*init_routine)(void));
-
-/* --- One-time event notification ---
-
-  These operations act on a gpr_event, which should be initialized with
-  gpr_ev_init(), or with GPR_EVENT_INIT if static, e.g.,
-       static gpr_event event_var = GPR_EVENT_INIT;
-  It requires no destruction.  */
-
-/* Initialize *ev. */
-void gpr_event_init(gpr_event *ev);
-
-/* Set *ev so that gpr_event_get() and gpr_event_wait() will return value.
-   Requires:  *ev initialized; value != NULL; no prior or concurrent calls to
-   gpr_event_set(ev, ...) since initialization.  */
-void gpr_event_set(gpr_event *ev, void *value);
-
-/* Return the value set by gpr_event_set(ev, ...), or NULL if no such call has
-   completed.  If the result is non-NULL, all operations that occurred prior to
-   the gpr_event_set(ev, ...) set will be visible after this call returns.
-   Requires:  *ev initialized.  This operation is faster than acquiring a mutex
-   on most platforms.  */
-void *gpr_event_get(gpr_event *ev);
-
-/* Wait until *ev is set by gpr_event_set(ev, ...), or abs_deadline is
-   exceeded, then return gpr_event_get(ev).  Requires:  *ev initialized.  Use
-   abs_deadline==gpr_inf_future for no deadline.  When the event has been
-   signalled before the call, this operation is faster than acquiring a mutex
-   on most platforms.  */
-void *gpr_event_wait(gpr_event *ev, gpr_timespec abs_deadline);
-
-/* --- Reference counting ---
-
-   These calls act on the type gpr_refcount.  It requires no destruction.  */
-
-/* Initialize *r to value n.  */
-void gpr_ref_init(gpr_refcount *r, int n);
-
-/* Increment the reference count *r.  Requires *r initialized. */
-void gpr_ref(gpr_refcount *r);
-
-/* Increment the reference count *r by n.  Requires *r initialized, n > 0. */
-void gpr_refn(gpr_refcount *r, int n);
-
-/* Decrement the reference count *r and return non-zero iff it has reached
-   zero. .  Requires *r initialized. */
-int gpr_unref(gpr_refcount *r);
-
-/* --- Stats counters ---
-
-   These calls act on the integral type gpr_stats_counter.  It requires no
-   destruction.  Static instances may be initialized with
-       gpr_stats_counter c = GPR_STATS_INIT;
-   Beware:  These operations do not imply memory barriers.  Do not use them to
-   synchronize other events.  */
-
-/* Initialize *c to the value n. */
-void gpr_stats_init(gpr_stats_counter *c, intptr_t n);
-
-/* *c += inc.  Requires: *c initialized. */
-void gpr_stats_inc(gpr_stats_counter *c, intptr_t inc);
-
-/* Return *c.  Requires: *c initialized. */
-intptr_t gpr_stats_read(const gpr_stats_counter *c);
-
-/* ==================Example use of interface===================
-   A producer-consumer queue of up to N integers,
-   illustrating the use of the calls in this interface. */
-#if 0
-
-#define N 4
-
-   typedef struct queue {
-     gpr_cv non_empty;  /* Signalled when length becomes non-zero. */
-     gpr_cv non_full;   /* Signalled when length becomes non-N. */
-     gpr_mu mu;         /* Protects all fields below.
-                            (That is, except during initialization or
-                            destruction, the fields below should be accessed
-                            only by a thread that holds mu.) */
-     int head;           /* Index of head of queue 0..N-1. */
-     int length;         /* Number of valid elements in queue 0..N. */
-     int elem[N];        /* elem[head .. head+length-1] are queue elements. */
-   } queue;
-
-   /* Initialize *q. */
-   void queue_init(queue *q) {
-     gpr_mu_init(&q->mu);
-     gpr_cv_init(&q->non_empty);
-     gpr_cv_init(&q->non_full);
-     q->head = 0;
-     q->length = 0;
-   }
-
-   /* Free storage associated with *q. */
-   void queue_destroy(queue *q) {
-     gpr_mu_destroy(&q->mu);
-     gpr_cv_destroy(&q->non_empty);
-     gpr_cv_destroy(&q->non_full);
-   }
-
-   /* Wait until there is room in *q, then append x to *q. */
-   void queue_append(queue *q, int x) {
-     gpr_mu_lock(&q->mu);
-     /* To wait for a predicate without a deadline, loop on the negation of the
-        predicate, and use gpr_cv_wait(..., gpr_inf_future) inside the loop
-        to release the lock, wait, and reacquire on each iteration.  Code that
-        makes the condition true should use gpr_cv_broadcast() on the
-        corresponding condition variable.  The predicate must be on state
-        protected by the lock.  */
-     while (q->length == N) {
-       gpr_cv_wait(&q->non_full, &q->mu, gpr_inf_future);
-     }
-     if (q->length == 0) {  /* Wake threads blocked in queue_remove(). */
-       /* It's normal to use gpr_cv_broadcast() or gpr_signal() while
-          holding the lock. */
-       gpr_cv_broadcast(&q->non_empty);
-     }
-     q->elem[(q->head + q->length) % N] = x;
-     q->length++;
-     gpr_mu_unlock(&q->mu);
-   }
-
-   /* If it can be done without blocking, append x to *q and return non-zero.
-      Otherwise return 0. */
-   int queue_try_append(queue *q, int x) {
-     int result = 0;
-     if (gpr_mu_trylock(&q->mu)) {
-       if (q->length != N) {
-         if (q->length == 0) {  /* Wake threads blocked in queue_remove(). */
-           gpr_cv_broadcast(&q->non_empty);
-         }
-         q->elem[(q->head + q->length) % N] = x;
-         q->length++;
-         result = 1;
-       }
-       gpr_mu_unlock(&q->mu);
-     }
-     return result;
-   }
-
-   /* Wait until the *q is non-empty or deadline abs_deadline passes.  If the
-      queue is non-empty, remove its head entry, place it in *head, and return
-      non-zero.  Otherwise return 0.  */
-   int queue_remove(queue *q, int *head, gpr_timespec abs_deadline) {
-     int result = 0;
-     gpr_mu_lock(&q->mu);
-     /* To wait for a predicate with a deadline, loop on the negation of the
-        predicate or until gpr_cv_wait() returns true.  Code that makes
-        the condition true should use gpr_cv_broadcast() on the corresponding
-        condition variable.  The predicate must be on state protected by the
-        lock. */
-     while (q->length == 0 &&
-            !gpr_cv_wait(&q->non_empty, &q->mu, abs_deadline)) {
-     }
-     if (q->length != 0) {    /* Queue is non-empty. */
-       result = 1;
-       if (q->length == N) {  /* Wake threads blocked in queue_append(). */
-         gpr_cv_broadcast(&q->non_full);
-       }
-       *head = q->elem[q->head];
-       q->head = (q->head + 1) % N;
-       q->length--;
-     } /* else deadline exceeded */
-     gpr_mu_unlock(&q->mu);
-     return result;
-   }
-#endif /* 0 */
-
-#ifdef __cplusplus
-}
-#endif
+#include <grpc/impl/codegen/sync.h>
 
 #endif /* GRPC_SUPPORT_SYNC_H */
diff --git a/include/grpc/support/sync_generic.h b/include/grpc/support/sync_generic.h
index fd55e02..28e3ab6 100644
--- a/include/grpc/support/sync_generic.h
+++ b/include/grpc/support/sync_generic.h
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -33,23 +33,7 @@
 
 #ifndef GRPC_SUPPORT_SYNC_GENERIC_H
 #define GRPC_SUPPORT_SYNC_GENERIC_H
-/* Generic type defintions for gpr_sync. */
 
-#include <grpc/support/atm.h>
-
-/* gpr_event */
-typedef struct { gpr_atm state; } gpr_event;
-
-#define GPR_EVENT_INIT \
-  { 0 }
-
-/* gpr_refcount */
-typedef struct { gpr_atm count; } gpr_refcount;
-
-/* gpr_stats_counter */
-typedef struct { gpr_atm value; } gpr_stats_counter;
-
-#define GPR_STATS_INIT \
-  { 0 }
+#include <grpc/impl/codegen/sync_generic.h>
 
 #endif /* GRPC_SUPPORT_SYNC_GENERIC_H */
diff --git a/include/grpc/support/sync_posix.h b/include/grpc/support/sync_posix.h
index 81ffa25..fa0324f 100644
--- a/include/grpc/support/sync_posix.h
+++ b/include/grpc/support/sync_posix.h
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -34,14 +34,6 @@
 #ifndef GRPC_SUPPORT_SYNC_POSIX_H
 #define GRPC_SUPPORT_SYNC_POSIX_H
 
-#include <grpc/support/sync_generic.h>
-
-#include <pthread.h>
-
-typedef pthread_mutex_t gpr_mu;
-typedef pthread_cond_t gpr_cv;
-typedef pthread_once_t gpr_once;
-
-#define GPR_ONCE_INIT PTHREAD_ONCE_INIT
+#include <grpc/impl/codegen/sync_posix.h>
 
 #endif /* GRPC_SUPPORT_SYNC_POSIX_H */
diff --git a/include/grpc/support/sync_win32.h b/include/grpc/support/sync_win32.h
index 8ddbeaa..bfbc99e 100644
--- a/include/grpc/support/sync_win32.h
+++ b/include/grpc/support/sync_win32.h
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -34,16 +34,6 @@
 #ifndef GRPC_SUPPORT_SYNC_WIN32_H
 #define GRPC_SUPPORT_SYNC_WIN32_H
 
-#include <grpc/support/sync_generic.h>
-
-typedef struct {
-  CRITICAL_SECTION cs; /* Not an SRWLock until Vista is unsupported */
-  int locked;
-} gpr_mu;
-
-typedef CONDITION_VARIABLE gpr_cv;
-
-typedef INIT_ONCE gpr_once;
-#define GPR_ONCE_INIT INIT_ONCE_STATIC_INIT
+#include <grpc/impl/codegen/sync_win32.h>
 
 #endif /* GRPC_SUPPORT_SYNC_WIN32_H */
diff --git a/include/grpc/support/thd.h b/include/grpc/support/thd.h
index 58b8a83..abe57eb 100644
--- a/include/grpc/support/thd.h
+++ b/include/grpc/support/thd.h
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -48,7 +48,7 @@
 extern "C" {
 #endif
 
-typedef uint64_t gpr_thd_id;
+typedef uintptr_t gpr_thd_id;
 
 /* Thread creation options. */
 typedef struct {
@@ -59,30 +59,30 @@
    in *t, and return true.  If there are insufficient resources, return false.
    If options==NULL, default options are used.
    The thread is immediately runnable, and exits when (*thd_body)() returns.  */
-int gpr_thd_new(gpr_thd_id *t, void (*thd_body)(void *arg), void *arg,
-                const gpr_thd_options *options);
+GPRAPI int gpr_thd_new(gpr_thd_id *t, void (*thd_body)(void *arg), void *arg,
+                       const gpr_thd_options *options);
 
 /* Return a gpr_thd_options struct with all fields set to defaults. */
-gpr_thd_options gpr_thd_options_default(void);
+GPRAPI gpr_thd_options gpr_thd_options_default(void);
 
 /* Set the thread to become detached on startup - this is the default. */
-void gpr_thd_options_set_detached(gpr_thd_options *options);
+GPRAPI void gpr_thd_options_set_detached(gpr_thd_options *options);
 
 /* Set the thread to become joinable - mutually exclusive with detached. */
-void gpr_thd_options_set_joinable(gpr_thd_options *options);
+GPRAPI void gpr_thd_options_set_joinable(gpr_thd_options *options);
 
 /* Returns non-zero if the option detached is set. */
-int gpr_thd_options_is_detached(const gpr_thd_options *options);
+GPRAPI int gpr_thd_options_is_detached(const gpr_thd_options *options);
 
 /* Returns non-zero if the option joinable is set. */
-int gpr_thd_options_is_joinable(const gpr_thd_options *options);
+GPRAPI int gpr_thd_options_is_joinable(const gpr_thd_options *options);
 
 /* Returns the identifier of the current thread. */
-gpr_thd_id gpr_thd_currentid(void);
+GPRAPI gpr_thd_id gpr_thd_currentid(void);
 
 /* Blocks until the specified thread properly terminates.
    Calling this on a detached thread has unpredictable results. */
-void gpr_thd_join(gpr_thd_id t);
+GPRAPI void gpr_thd_join(gpr_thd_id t);
 
 #ifdef __cplusplus
 }
diff --git a/include/grpc/support/time.h b/include/grpc/support/time.h
index d2607f3..2c7f853 100644
--- a/include/grpc/support/time.h
+++ b/include/grpc/support/time.h
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -33,96 +33,7 @@
 
 #ifndef GRPC_SUPPORT_TIME_H
 #define GRPC_SUPPORT_TIME_H
-/* Time support.
-   We use gpr_timespec, which is analogous to struct timespec.  On some
-   machines, absolute times may be in local time.  */
 
-#include <grpc/support/port_platform.h>
-#include <stddef.h>
-#include <time.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/* The clocks we support. */
-typedef enum {
-  /* Monotonic clock. Epoch undefined. Always moves forwards. */
-  GPR_CLOCK_MONOTONIC = 0,
-  /* Realtime clock. May jump forwards or backwards. Settable by
-     the system administrator. Has its epoch at 0:00:00 UTC 1 Jan 1970. */
-  GPR_CLOCK_REALTIME,
-  /* CPU cycle time obtained by rdtsc instruction on x86 platforms. Epoch
-     undefined. Degrades to GPR_CLOCK_REALTIME on other platforms. */
-  GPR_CLOCK_PRECISE,
-  /* Unmeasurable clock type: no base, created by taking the difference
-     between two times */
-  GPR_TIMESPAN
-} gpr_clock_type;
-
-typedef struct gpr_timespec {
-  int64_t tv_sec;
-  int32_t tv_nsec;
-  /** Against which clock was this time measured? (or GPR_TIMESPAN if
-      this is a relative time meaure) */
-  gpr_clock_type clock_type;
-} gpr_timespec;
-
-/* Time constants. */
-gpr_timespec gpr_time_0(gpr_clock_type type);     /* The zero time interval. */
-gpr_timespec gpr_inf_future(gpr_clock_type type); /* The far future */
-gpr_timespec gpr_inf_past(gpr_clock_type type);   /* The far past. */
-
-#define GPR_MS_PER_SEC 1000
-#define GPR_US_PER_SEC 1000000
-#define GPR_NS_PER_SEC 1000000000
-#define GPR_NS_PER_MS 1000000
-#define GPR_NS_PER_US 1000
-#define GPR_US_PER_MS 1000
-
-/* initialize time subsystem */
-void gpr_time_init(void);
-
-/* Return the current time measured from the given clocks epoch. */
-gpr_timespec gpr_now(gpr_clock_type clock);
-
-/* Convert a timespec from one clock to another */
-gpr_timespec gpr_convert_clock_type(gpr_timespec t,
-                                    gpr_clock_type target_clock);
-
-/* Return -ve, 0, or +ve according to whether a < b, a == b, or a > b
-   respectively.  */
-int gpr_time_cmp(gpr_timespec a, gpr_timespec b);
-
-gpr_timespec gpr_time_max(gpr_timespec a, gpr_timespec b);
-gpr_timespec gpr_time_min(gpr_timespec a, gpr_timespec b);
-
-/* Add and subtract times.  Calculations saturate at infinities. */
-gpr_timespec gpr_time_add(gpr_timespec a, gpr_timespec b);
-gpr_timespec gpr_time_sub(gpr_timespec a, gpr_timespec b);
-
-/* Return a timespec representing a given number of time units. LONG_MIN is
-   interpreted as gpr_inf_past, and LONG_MAX as gpr_inf_future.  */
-gpr_timespec gpr_time_from_micros(long x, gpr_clock_type clock_type);
-gpr_timespec gpr_time_from_nanos(long x, gpr_clock_type clock_type);
-gpr_timespec gpr_time_from_millis(long x, gpr_clock_type clock_type);
-gpr_timespec gpr_time_from_seconds(long x, gpr_clock_type clock_type);
-gpr_timespec gpr_time_from_minutes(long x, gpr_clock_type clock_type);
-gpr_timespec gpr_time_from_hours(long x, gpr_clock_type clock_type);
-
-int32_t gpr_time_to_millis(gpr_timespec timespec);
-
-/* Return 1 if two times are equal or within threshold of each other,
-   0 otherwise */
-int gpr_time_similar(gpr_timespec a, gpr_timespec b, gpr_timespec threshold);
-
-/* Sleep until at least 'until' - an absolute timeout */
-void gpr_sleep_until(gpr_timespec until);
-
-double gpr_timespec_to_micros(gpr_timespec t);
-
-#ifdef __cplusplus
-}
-#endif
+#include <grpc/impl/codegen/time.h>
 
 #endif /* GRPC_SUPPORT_TIME_H */
diff --git a/package.json b/package.json
index 2abc266..1b79ecf 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
 {
   "name": "grpc",
-  "version": "0.12.0",
+  "version": "0.14.0-dev",
   "author": "Google Inc.",
   "description": "gRPC Library for Node",
   "homepage": "http://www.grpc.io/",
@@ -45,7 +45,7 @@
     "poisson-process": "^0.2.1"
   },
   "engines": {
-    "node": ">=0.10.13"
+    "node": ">=0.12.0"
   },
   "binary": {
     "module_name": "grpc_node",
@@ -84,9 +84,16 @@
     "src/node/src/client.js",
     "src/node/src/common.js",
     "src/node/src/credentials.js",
+    "src/node/src/grpc_extension.js",
     "src/node/src/metadata.js",
     "src/node/src/server.js",
     "include/grpc/grpc_security.h",
+    "include/grpc/impl/codegen/byte_buffer.h",
+    "include/grpc/impl/codegen/compression_types.h",
+    "include/grpc/impl/codegen/connectivity_state.h",
+    "include/grpc/impl/codegen/grpc_types.h",
+    "include/grpc/impl/codegen/propagation_bits.h",
+    "include/grpc/impl/codegen/status.h",
     "include/grpc/byte_buffer.h",
     "include/grpc/byte_buffer_reader.h",
     "include/grpc/compression.h",
@@ -221,7 +228,6 @@
     "src/core/transport/transport.h",
     "src/core/transport/transport_impl.h",
     "src/core/census/aggregation.h",
-    "src/core/census/context.h",
     "src/core/census/rpc_metric_id.h",
     "src/core/httpcli/httpcli_security_connector.c",
     "src/core/security/base64.c",
@@ -322,6 +328,7 @@
     "src/core/json/json_reader.c",
     "src/core/json/json_string.c",
     "src/core/json/json_writer.c",
+    "src/core/surface/alarm.c",
     "src/core/surface/api_trace.c",
     "src/core/surface/byte_buffer.c",
     "src/core/surface/byte_buffer_reader.c",
@@ -373,7 +380,7 @@
     "src/core/census/context.c",
     "src/core/census/initialize.c",
     "src/core/census/operation.c",
-    "src/core/census/tag_set.c",
+    "src/core/census/placeholders.c",
     "src/core/census/tracing.c",
     "third_party/zlib/crc32.h",
     "third_party/zlib/deflate.h",
@@ -429,6 +436,20 @@
     "include/grpc/support/tls_msvc.h",
     "include/grpc/support/tls_pthread.h",
     "include/grpc/support/useful.h",
+    "include/grpc/impl/codegen/alloc.h",
+    "include/grpc/impl/codegen/atm.h",
+    "include/grpc/impl/codegen/atm_gcc_atomic.h",
+    "include/grpc/impl/codegen/atm_gcc_sync.h",
+    "include/grpc/impl/codegen/atm_win32.h",
+    "include/grpc/impl/codegen/log.h",
+    "include/grpc/impl/codegen/port_platform.h",
+    "include/grpc/impl/codegen/slice.h",
+    "include/grpc/impl/codegen/slice_buffer.h",
+    "include/grpc/impl/codegen/sync.h",
+    "include/grpc/impl/codegen/sync_generic.h",
+    "include/grpc/impl/codegen/sync_posix.h",
+    "include/grpc/impl/codegen/sync_win32.h",
+    "include/grpc/impl/codegen/time.h",
     "src/core/profiling/timers.h",
     "src/core/support/block_annotate.h",
     "src/core/support/env.h",
@@ -469,6 +490,7 @@
     "src/core/support/string_posix.c",
     "src/core/support/string_win32.c",
     "src/core/support/subprocess_posix.c",
+    "src/core/support/subprocess_windows.c",
     "src/core/support/sync.c",
     "src/core/support/sync_posix.c",
     "src/core/support/sync_win32.c",
@@ -480,6 +502,7 @@
     "src/core/support/time_precise.c",
     "src/core/support/time_win32.c",
     "src/core/support/tls_pthread.c",
+    "src/core/support/wrap_memcpy.c",
     "third_party/boringssl/crypto/aes/internal.h",
     "third_party/boringssl/crypto/asn1/asn1_locl.h",
     "third_party/boringssl/crypto/bio/internal.h",
diff --git a/requirements.txt b/requirements.txt
index 9d00274..a1cc88c 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -3,3 +3,4 @@
 futures>=2.2.0
 cython>=0.23
 coverage>=4.0
+six>=1.10
diff --git a/setup.cfg b/setup.cfg
index add6ee8..7194716 100644
--- a/setup.cfg
+++ b/setup.cfg
@@ -3,6 +3,9 @@
 [coverage:run]
 plugins = Cython.Coverage
 
+[build]
+build_base=python_build
+
 [build_ext]
 inplace=1
 
diff --git a/setup.py b/setup.py
index 52d3d22..ceca6f6 100644
--- a/setup.py
+++ b/setup.py
@@ -54,6 +54,7 @@
 # Break import-style to ensure we can actually find our in-repo dependencies.
 import commands
 import grpc_core_dependencies
+import grpc_version
 
 LICENSE = '3-clause BSD'
 
@@ -75,17 +76,37 @@
 
 CYTHON_EXTENSION_MODULE_NAMES = ('grpc._cython.cygrpc',)
 
+CYTHON_HELPER_C_FILES = (
+    os.path.join(PYTHON_STEM, 'grpc/_cython/loader.c'),
+    os.path.join(PYTHON_STEM, 'grpc/_cython/imports.generated.c'),
+)
+
+CORE_C_FILES = ()
+if not "win32" in sys.platform:
+  CORE_C_FILES += tuple(grpc_core_dependencies.CORE_SOURCE_FILES)
+
 EXTENSION_INCLUDE_DIRECTORIES = (
     (PYTHON_STEM,) + CORE_INCLUDE + BORINGSSL_INCLUDE + ZLIB_INCLUDE)
 
-EXTENSION_LIBRARIES = ('m',)
-if not "darwin" in sys.platform:
-    EXTENSION_LIBRARIES += ('rt',)
+EXTENSION_LIBRARIES = ()
+if "linux" in sys.platform:
+  EXTENSION_LIBRARIES += ('rt',)
+if not "win32" in sys.platform:
+  EXTENSION_LIBRARIES += ('m',)
 
-DEFINE_MACROS = (('OPENSSL_NO_ASM', 1),)
+DEFINE_MACROS = (('OPENSSL_NO_ASM', 1), ('_WIN32_WINNT', 0x600))
 
-def cython_extensions(package_names, module_names, include_dirs, libraries,
-                      define_macros, build_with_cython=False):
+CFLAGS = ()
+LDFLAGS = ()
+if "linux" in sys.platform:
+  LDFLAGS += ('-Wl,-wrap,memcpy',)
+if "linux" in sys.platform or "darwin" in sys.platform:
+  CFLAGS += ('-fvisibility=hidden',)
+  DEFINE_MACROS += (('PyMODINIT_FUNC', '__attribute__((visibility ("default"))) void'),)
+
+
+def cython_extensions(package_names, module_names, extra_sources, include_dirs,
+                      libraries, define_macros, build_with_cython=False):
   if ENABLE_CYTHON_TRACING:
     define_macros = define_macros + [('CYTHON_TRACE_NOGIL', 1)]
   file_extension = 'pyx' if build_with_cython else 'c'
@@ -95,9 +116,11 @@
   extensions = [
       _extension.Extension(
           name=module_name,
-          sources=[module_file] + grpc_core_dependencies.CORE_SOURCE_FILES,
+          sources=[module_file] + extra_sources,
           include_dirs=include_dirs, libraries=libraries,
           define_macros=define_macros,
+          extra_compile_args=list(CFLAGS),
+          extra_link_args=list(LDFLAGS),
       ) for (module_name, module_file) in zip(module_names, module_files)
   ]
   if build_with_cython:
@@ -111,6 +134,7 @@
 
 CYTHON_EXTENSION_MODULES = cython_extensions(
     list(CYTHON_EXTENSION_PACKAGE_NAMES), list(CYTHON_EXTENSION_MODULE_NAMES),
+    list(CYTHON_HELPER_C_FILES) + list(CORE_C_FILES),
     list(EXTENSION_INCLUDE_DIRECTORIES), list(EXTENSION_LIBRARIES),
     list(DEFINE_MACROS), bool(BUILD_WITH_CYTHON))
 
@@ -119,6 +143,7 @@
 }
 
 INSTALL_REQUIRES = (
+    'six>=1.10',
     'enum34>=1.0.4',
     'futures>=2.2.0',
     # TODO(atash): eventually split the grpcio package into a metapackage
@@ -131,6 +156,7 @@
 ) + INSTALL_REQUIRES
 
 COMMAND_CLASS = {
+    'install': commands.Install,
     'doc': commands.SphinxDocumentation,
     'build_proto_modules': commands.BuildProtoModules,
     'build_project_metadata': commands.BuildProjectMetadata,
@@ -138,10 +164,11 @@
     'build_ext': commands.BuildExt,
     'gather': commands.Gather,
     'run_interop': commands.RunInterop,
+    'bdist_egg_grpc_custom': commands.BdistEggCustomName,
 }
 
 # Ensure that package data is copied over before any commands have been run:
-credentials_dir = os.path.join(PYTHON_STEM, 'grpc/_adapter/credentials')
+credentials_dir = os.path.join(PYTHON_STEM, 'grpc/_cython/_credentials')
 try:
   os.mkdir(credentials_dir)
 except OSError:
@@ -162,9 +189,6 @@
         'credentials/server1.key',
         'credentials/server1.pem',
     ],
-    'grpc._adapter': [
-        'credentials/roots.pem'
-    ],
 }
 
 TESTS_REQUIRE = (
@@ -177,7 +201,13 @@
 TEST_LOADER = 'tests:Loader'
 TEST_RUNNER = 'tests:Runner'
 
-PACKAGE_DATA = {}
+PACKAGE_DATA = {
+    'grpc._cython': [
+        '_credentials/roots.pem',
+        '_windows/grpc_c.32.python',
+        '_windows/grpc_c.64.python',
+    ],
+}
 if INSTALL_TESTS:
   PACKAGE_DATA = dict(PACKAGE_DATA, **TEST_PACKAGE_DATA)
   PACKAGES = setuptools.find_packages(PYTHON_STEM)
@@ -187,7 +217,7 @@
 
 setuptools.setup(
     name='grpcio',
-    version='0.12.0b5',
+    version=grpc_version.VERSION,
     license=LICENSE,
     ext_modules=CYTHON_EXTENSION_MODULES,
     packages=list(PACKAGES),
diff --git a/src/boringssl/gen_build_yaml.py b/src/boringssl/gen_build_yaml.py
index b635ee4..3a7116b 100755
--- a/src/boringssl/gen_build_yaml.py
+++ b/src/boringssl/gen_build_yaml.py
@@ -33,6 +33,8 @@
 import os
 import yaml
 
+sys.dont_write_bytecode = True
+
 boring_ssl_root = os.path.abspath(os.path.join(
     os.path.dirname(sys.argv[0]), 
     '../../third_party/boringssl'))
@@ -82,6 +84,7 @@
               for f in files['ssl_headers'] + files['ssl_internal_headers'] + files['crypto_headers'] + files['crypto_internal_headers']
             ),
             'boringssl': True,
+            'defaults': 'boringssl',
           },
           {
             'name': 'boringssl_test_util',
@@ -89,6 +92,7 @@
             'language': 'c++',
             'secure': 'no',
             'boringssl': True,
+            'defaults': 'boringssl',
             'src': [
               map_dir(f)
               for f in sorted(files['test_support'])
@@ -103,6 +107,7 @@
             'src': [map_dir(test)],
             'vs_proj_dir': 'test/boringssl',
             'boringssl': True,
+            'defaults': 'boringssl',
             'deps': [
                 'boringssl_test_util',
                 'boringssl',
@@ -120,6 +125,7 @@
             'src': [],
             'vs_proj_dir': 'test/boringssl',
             'boringssl': True,
+            'defaults': 'boringssl',
             'deps': [
                 'boringssl_%s_lib' % os.path.splitext(os.path.basename(test))[0],
                 'boringssl_test_util',
@@ -138,6 +144,7 @@
             'flaky': False,
             'language': 'c++',
             'boringssl': True,
+            'defaults': 'boringssl',
             'cpu_cost': 1.0
           }
           for test in files['tests']
diff --git a/src/compiler/cpp_generator.cc b/src/compiler/cpp_generator.cc
index 3c8ca8a..97295be 100644
--- a/src/compiler/cpp_generator.cc
+++ b/src/compiler/cpp_generator.cc
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -112,18 +112,17 @@
 grpc::string GetHeaderIncludes(const grpc::protobuf::FileDescriptor *file,
                                const Parameters &params) {
   grpc::string temp =
-      "#include <grpc++/support/async_stream.h>\n"
-      "#include <grpc++/impl/rpc_method.h>\n"
-      "#include <grpc++/impl/proto_utils.h>\n"
-      "#include <grpc++/impl/service_type.h>\n"
-      "#include <grpc++/support/async_unary_call.h>\n"
-      "#include <grpc++/support/status.h>\n"
-      "#include <grpc++/support/stub_options.h>\n"
-      "#include <grpc++/support/sync_stream.h>\n"
+      "#include <grpc++/impl/codegen/async_stream.h>\n"
+      "#include <grpc++/impl/codegen/async_unary_call.h>\n"
+      "#include <grpc++/impl/codegen/proto_utils.h>\n"
+      "#include <grpc++/impl/codegen/rpc_method.h>\n"
+      "#include <grpc++/impl/codegen/service_type.h>\n"
+      "#include <grpc++/impl/codegen/status.h>\n"
+      "#include <grpc++/impl/codegen/stub_options.h>\n"
+      "#include <grpc++/impl/codegen/sync_stream.h>\n"
       "\n"
       "namespace grpc {\n"
       "class CompletionQueue;\n"
-      "class Channel;\n"
       "class RpcService;\n"
       "class ServerCompletionQueue;\n"
       "class ServerContext;\n"
@@ -491,39 +490,186 @@
       grpc_cpp_generator::ClassName(method->input_type(), true);
   (*vars)["Response"] =
       grpc_cpp_generator::ClassName(method->output_type(), true);
+  printer->Print(*vars, "template <class BaseClass>\n");
+  printer->Print(*vars,
+                 "class WithAsyncMethod_$Method$ : public BaseClass {\n");
+  printer->Print(
+      " private:\n"
+      "  void BaseClassMustBeDerivedFromService(Service *service) {}\n");
+  printer->Print(" public:\n");
+  printer->Indent();
+  printer->Print(*vars,
+                 "WithAsyncMethod_$Method$() {\n"
+                 "  ::grpc::Service::MarkMethodAsync($Idx$);\n"
+                 "}\n");
+  printer->Print(*vars,
+                 "~WithAsyncMethod_$Method$() GRPC_OVERRIDE {\n"
+                 "  BaseClassMustBeDerivedFromService(this);\n"
+                 "}\n");
   if (NoStreaming(method)) {
     printer->Print(
         *vars,
+        "// disable synchronous version of this method\n"
+        "::grpc::Status $Method$("
+        "::grpc::ServerContext* context, const $Request$* request, "
+        "$Response$* response) GRPC_FINAL GRPC_OVERRIDE {\n"
+        "  abort();\n"
+        "  return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, \"\");\n"
+        "}\n");
+    printer->Print(
+        *vars,
         "void Request$Method$("
         "::grpc::ServerContext* context, $Request$* request, "
         "::grpc::ServerAsyncResponseWriter< $Response$>* response, "
         "::grpc::CompletionQueue* new_call_cq, "
-        "::grpc::ServerCompletionQueue* notification_cq, void *tag);\n");
+        "::grpc::ServerCompletionQueue* notification_cq, void *tag) {\n");
+    printer->Print(*vars,
+                   "  ::grpc::Service::RequestAsyncUnary($Idx$, context, "
+                   "request, response, new_call_cq, notification_cq, tag);\n");
+    printer->Print("}\n");
   } else if (ClientOnlyStreaming(method)) {
     printer->Print(
         *vars,
+        "// disable synchronous version of this method\n"
+        "::grpc::Status $Method$("
+        "::grpc::ServerContext* context, "
+        "::grpc::ServerReader< $Request$>* reader, "
+        "$Response$* response) GRPC_FINAL GRPC_OVERRIDE {\n"
+        "  abort();\n"
+        "  return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, \"\");\n"
+        "}\n");
+    printer->Print(
+        *vars,
         "void Request$Method$("
         "::grpc::ServerContext* context, "
         "::grpc::ServerAsyncReader< $Response$, $Request$>* reader, "
         "::grpc::CompletionQueue* new_call_cq, "
-        "::grpc::ServerCompletionQueue* notification_cq, void *tag);\n");
+        "::grpc::ServerCompletionQueue* notification_cq, void *tag) {\n");
+    printer->Print(*vars,
+                   "  ::grpc::Service::RequestAsyncClientStreaming($Idx$, "
+                   "context, reader, new_call_cq, notification_cq, tag);\n");
+    printer->Print("}\n");
   } else if (ServerOnlyStreaming(method)) {
     printer->Print(
         *vars,
+        "// disable synchronous version of this method\n"
+        "::grpc::Status $Method$("
+        "::grpc::ServerContext* context, const $Request$* request, "
+        "::grpc::ServerWriter< $Response$>* writer) GRPC_FINAL GRPC_OVERRIDE "
+        "{\n"
+        "  abort();\n"
+        "  return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, \"\");\n"
+        "}\n");
+    printer->Print(
+        *vars,
         "void Request$Method$("
         "::grpc::ServerContext* context, $Request$* request, "
         "::grpc::ServerAsyncWriter< $Response$>* writer, "
         "::grpc::CompletionQueue* new_call_cq, "
-        "::grpc::ServerCompletionQueue* notification_cq, void *tag);\n");
+        "::grpc::ServerCompletionQueue* notification_cq, void *tag) {\n");
+    printer->Print(
+        *vars,
+        "  ::grpc::Service::RequestAsyncServerStreaming($Idx$, "
+        "context, request, writer, new_call_cq, notification_cq, tag);\n");
+    printer->Print("}\n");
   } else if (BidiStreaming(method)) {
     printer->Print(
         *vars,
+        "// disable synchronous version of this method\n"
+        "::grpc::Status $Method$("
+        "::grpc::ServerContext* context, "
+        "::grpc::ServerReaderWriter< $Response$, $Request$>* stream) "
+        "GRPC_FINAL GRPC_OVERRIDE {\n"
+        "  abort();\n"
+        "  return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, \"\");\n"
+        "}\n");
+    printer->Print(
+        *vars,
         "void Request$Method$("
         "::grpc::ServerContext* context, "
         "::grpc::ServerAsyncReaderWriter< $Response$, $Request$>* stream, "
         "::grpc::CompletionQueue* new_call_cq, "
-        "::grpc::ServerCompletionQueue* notification_cq, void *tag);\n");
+        "::grpc::ServerCompletionQueue* notification_cq, void *tag) {\n");
+    printer->Print(*vars,
+                   "  ::grpc::Service::RequestAsyncBidiStreaming($Idx$, "
+                   "context, stream, new_call_cq, notification_cq, tag);\n");
+    printer->Print("}\n");
   }
+  printer->Outdent();
+  printer->Print(*vars, "};\n");
+}
+
+void PrintHeaderServerMethodGeneric(
+    grpc::protobuf::io::Printer *printer,
+    const grpc::protobuf::MethodDescriptor *method,
+    std::map<grpc::string, grpc::string> *vars) {
+  (*vars)["Method"] = method->name();
+  (*vars)["Request"] =
+      grpc_cpp_generator::ClassName(method->input_type(), true);
+  (*vars)["Response"] =
+      grpc_cpp_generator::ClassName(method->output_type(), true);
+  printer->Print(*vars, "template <class BaseClass>\n");
+  printer->Print(*vars,
+                 "class WithGenericMethod_$Method$ : public BaseClass {\n");
+  printer->Print(
+      " private:\n"
+      "  void BaseClassMustBeDerivedFromService(Service *service) {}\n");
+  printer->Print(" public:\n");
+  printer->Indent();
+  printer->Print(*vars,
+                 "WithGenericMethod_$Method$() {\n"
+                 "  ::grpc::Service::MarkMethodGeneric($Idx$);\n"
+                 "}\n");
+  printer->Print(*vars,
+                 "~WithGenericMethod_$Method$() GRPC_OVERRIDE {\n"
+                 "  BaseClassMustBeDerivedFromService(this);\n"
+                 "}\n");
+  if (NoStreaming(method)) {
+    printer->Print(
+        *vars,
+        "// disable synchronous version of this method\n"
+        "::grpc::Status $Method$("
+        "::grpc::ServerContext* context, const $Request$* request, "
+        "$Response$* response) GRPC_FINAL GRPC_OVERRIDE {\n"
+        "  abort();\n"
+        "  return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, \"\");\n"
+        "}\n");
+  } else if (ClientOnlyStreaming(method)) {
+    printer->Print(
+        *vars,
+        "// disable synchronous version of this method\n"
+        "::grpc::Status $Method$("
+        "::grpc::ServerContext* context, "
+        "::grpc::ServerReader< $Request$>* reader, "
+        "$Response$* response) GRPC_FINAL GRPC_OVERRIDE {\n"
+        "  abort();\n"
+        "  return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, \"\");\n"
+        "}\n");
+  } else if (ServerOnlyStreaming(method)) {
+    printer->Print(
+        *vars,
+        "// disable synchronous version of this method\n"
+        "::grpc::Status $Method$("
+        "::grpc::ServerContext* context, const $Request$* request, "
+        "::grpc::ServerWriter< $Response$>* writer) GRPC_FINAL GRPC_OVERRIDE "
+        "{\n"
+        "  abort();\n"
+        "  return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, \"\");\n"
+        "}\n");
+  } else if (BidiStreaming(method)) {
+    printer->Print(
+        *vars,
+        "// disable synchronous version of this method\n"
+        "::grpc::Status $Method$("
+        "::grpc::ServerContext* context, "
+        "::grpc::ServerReaderWriter< $Response$, $Request$>* stream) "
+        "GRPC_FINAL GRPC_OVERRIDE {\n"
+        "  abort();\n"
+        "  return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, \"\");\n"
+        "}\n");
+  }
+  printer->Outdent();
+  printer->Print(*vars, "};\n");
 }
 
 void PrintHeaderService(grpc::protobuf::io::Printer *printer,
@@ -557,14 +703,14 @@
       "class Stub GRPC_FINAL : public StubInterface"
       " {\n public:\n");
   printer->Indent();
-  printer->Print("Stub(const std::shared_ptr< ::grpc::Channel>& channel);\n");
+  printer->Print("Stub(const std::shared_ptr< ::grpc::ChannelInterface>& channel);\n");
   for (int i = 0; i < service->method_count(); ++i) {
     PrintHeaderClientMethod(printer, service->method(i), vars, true);
   }
   printer->Outdent();
   printer->Print("\n private:\n");
   printer->Indent();
-  printer->Print("std::shared_ptr< ::grpc::Channel> channel_;\n");
+  printer->Print("std::shared_ptr< ::grpc::ChannelInterface> channel_;\n");
   for (int i = 0; i < service->method_count(); ++i) {
     PrintHeaderClientMethod(printer, service->method(i), vars, false);
   }
@@ -575,14 +721,14 @@
   printer->Print("};\n");
   printer->Print(
       "static std::unique_ptr<Stub> NewStub(const std::shared_ptr< "
-      "::grpc::Channel>& channel, "
+      "::grpc::ChannelInterface>& channel, "
       "const ::grpc::StubOptions& options = ::grpc::StubOptions());\n");
 
   printer->Print("\n");
 
-  // Server side - Synchronous
+  // Server side - base
   printer->Print(
-      "class Service : public ::grpc::SynchronousService {\n"
+      "class Service : public ::grpc::Service {\n"
       " public:\n");
   printer->Indent();
   printer->Print("Service();\n");
@@ -590,26 +736,32 @@
   for (int i = 0; i < service->method_count(); ++i) {
     PrintHeaderServerMethodSync(printer, service->method(i), vars);
   }
-  printer->Print("::grpc::RpcService* service() GRPC_OVERRIDE GRPC_FINAL;\n");
   printer->Outdent();
-  printer->Print(
-      " private:\n"
-      "  std::unique_ptr< ::grpc::RpcService> service_;\n");
   printer->Print("};\n");
 
   // Server side - Asynchronous
-  printer->Print(
-      "class AsyncService GRPC_FINAL : public ::grpc::AsynchronousService {\n"
-      " public:\n");
-  printer->Indent();
-  (*vars)["MethodCount"] = as_string(service->method_count());
-  printer->Print("explicit AsyncService();\n");
-  printer->Print("~AsyncService() {};\n");
   for (int i = 0; i < service->method_count(); ++i) {
+    (*vars)["Idx"] = as_string(i);
     PrintHeaderServerMethodAsync(printer, service->method(i), vars);
   }
-  printer->Outdent();
-  printer->Print("};\n");
+
+  printer->Print("typedef ");
+
+  for (int i = 0; i < service->method_count(); ++i) {
+    (*vars)["method_name"] = service->method(i)->name();
+    printer->Print(*vars, "WithAsyncMethod_$method_name$<");
+  }
+  printer->Print("Service");
+  for (int i = 0; i < service->method_count(); ++i) {
+    printer->Print(" >");
+  }
+  printer->Print(" AsyncService;\n");
+
+  // Server side - Generic
+  for (int i = 0; i < service->method_count(); ++i) {
+    (*vars)["Idx"] = as_string(i);
+    PrintHeaderServerMethodGeneric(printer, service->method(i), vars);
+  }
 
   printer->Outdent();
   printer->Print("};\n");
@@ -623,6 +775,12 @@
     grpc::protobuf::io::StringOutputStream output_stream(&output);
     grpc::protobuf::io::Printer printer(&output_stream, '$');
     std::map<grpc::string, grpc::string> vars;
+    // Package string is empty or ends with a dot. It is used to fully qualify
+    // method names.
+    vars["Package"] = file->package();
+    if (!file->package().empty()) {
+      vars["Package"].append(".");
+    }
 
     if (!params.services_namespace.empty()) {
       vars["services_namespace"] = params.services_namespace;
@@ -702,13 +860,16 @@
     grpc::protobuf::io::Printer printer(&output_stream, '$');
     std::map<grpc::string, grpc::string> vars;
 
-    printer.Print(vars, "#include <grpc++/channel.h>\n");
-    printer.Print(vars, "#include <grpc++/impl/client_unary_call.h>\n");
-    printer.Print(vars, "#include <grpc++/impl/rpc_service_method.h>\n");
-    printer.Print(vars, "#include <grpc++/impl/service_type.h>\n");
-    printer.Print(vars, "#include <grpc++/support/async_unary_call.h>\n");
-    printer.Print(vars, "#include <grpc++/support/async_stream.h>\n");
-    printer.Print(vars, "#include <grpc++/support/sync_stream.h>\n");
+    printer.Print(vars, "#include <grpc++/impl/codegen/async_stream.h>\n");
+    printer.Print(vars, "#include <grpc++/impl/codegen/async_unary_call.h>\n");
+    printer.Print(vars, "#include <grpc++/impl/codegen/channel_interface.h>\n");
+    printer.Print(vars, "#include <grpc++/impl/codegen/client_unary_call.h>\n");
+    printer.Print(vars,
+                  "#include <grpc++/impl/codegen/method_handler_impl.h>\n");
+    printer.Print(vars,
+                  "#include <grpc++/impl/codegen/rpc_service_method.h>\n");
+    printer.Print(vars, "#include <grpc++/impl/codegen/service_type.h>\n");
+    printer.Print(vars, "#include <grpc++/impl/codegen/sync_stream.h>\n");
 
     if (!file->package().empty()) {
       std::vector<grpc::string> parts =
@@ -889,69 +1050,6 @@
   }
 }
 
-void PrintSourceServerAsyncMethod(
-    grpc::protobuf::io::Printer *printer,
-    const grpc::protobuf::MethodDescriptor *method,
-    std::map<grpc::string, grpc::string> *vars) {
-  (*vars)["Method"] = method->name();
-  (*vars)["Request"] =
-      grpc_cpp_generator::ClassName(method->input_type(), true);
-  (*vars)["Response"] =
-      grpc_cpp_generator::ClassName(method->output_type(), true);
-  if (NoStreaming(method)) {
-    printer->Print(
-        *vars,
-        "void $ns$$Service$::AsyncService::Request$Method$("
-        "::grpc::ServerContext* context, "
-        "$Request$* request, "
-        "::grpc::ServerAsyncResponseWriter< $Response$>* response, "
-        "::grpc::CompletionQueue* new_call_cq, "
-        "::grpc::ServerCompletionQueue* notification_cq, void *tag) {\n");
-    printer->Print(*vars,
-                   "  AsynchronousService::RequestAsyncUnary($Idx$, context, "
-                   "request, response, new_call_cq, notification_cq, tag);\n");
-    printer->Print("}\n\n");
-  } else if (ClientOnlyStreaming(method)) {
-    printer->Print(
-        *vars,
-        "void $ns$$Service$::AsyncService::Request$Method$("
-        "::grpc::ServerContext* context, "
-        "::grpc::ServerAsyncReader< $Response$, $Request$>* reader, "
-        "::grpc::CompletionQueue* new_call_cq, "
-        "::grpc::ServerCompletionQueue* notification_cq, void *tag) {\n");
-    printer->Print(*vars,
-                   "  AsynchronousService::RequestClientStreaming($Idx$, "
-                   "context, reader, new_call_cq, notification_cq, tag);\n");
-    printer->Print("}\n\n");
-  } else if (ServerOnlyStreaming(method)) {
-    printer->Print(
-        *vars,
-        "void $ns$$Service$::AsyncService::Request$Method$("
-        "::grpc::ServerContext* context, "
-        "$Request$* request, "
-        "::grpc::ServerAsyncWriter< $Response$>* writer, "
-        "::grpc::CompletionQueue* new_call_cq, "
-        "::grpc::ServerCompletionQueue* notification_cq, void *tag) {\n");
-    printer->Print(
-        *vars,
-        "  AsynchronousService::RequestServerStreaming($Idx$, "
-        "context, request, writer, new_call_cq, notification_cq, tag);\n");
-    printer->Print("}\n\n");
-  } else if (BidiStreaming(method)) {
-    printer->Print(
-        *vars,
-        "void $ns$$Service$::AsyncService::Request$Method$("
-        "::grpc::ServerContext* context, "
-        "::grpc::ServerAsyncReaderWriter< $Response$, $Request$>* stream, "
-        "::grpc::CompletionQueue* new_call_cq, "
-        "::grpc::ServerCompletionQueue* notification_cq, void *tag) {\n");
-    printer->Print(*vars,
-                   "  AsynchronousService::RequestBidiStreaming($Idx$, "
-                   "context, stream, new_call_cq, notification_cq, tag);\n");
-    printer->Print("}\n\n");
-  }
-}
-
 void PrintSourceService(grpc::protobuf::io::Printer *printer,
                         const grpc::protobuf::ServiceDescriptor *service,
                         std::map<grpc::string, grpc::string> *vars) {
@@ -967,7 +1065,7 @@
 
   printer->Print(*vars,
                  "std::unique_ptr< $ns$$Service$::Stub> $ns$$Service$::NewStub("
-                 "const std::shared_ptr< ::grpc::Channel>& channel, "
+                 "const std::shared_ptr< ::grpc::ChannelInterface>& channel, "
                  "const ::grpc::StubOptions& options) {\n"
                  "  std::unique_ptr< $ns$$Service$::Stub> stub(new "
                  "$ns$$Service$::Stub(channel));\n"
@@ -975,7 +1073,7 @@
                  "}\n\n");
   printer->Print(*vars,
                  "$ns$$Service$::Stub::Stub(const std::shared_ptr< "
-                 "::grpc::Channel>& channel)\n");
+                 "::grpc::ChannelInterface>& channel)\n");
   printer->Indent();
   printer->Print(": channel_(channel)");
   for (int i = 0; i < service->method_count(); ++i) {
@@ -1006,32 +1104,9 @@
     PrintSourceClientMethod(printer, service->method(i), vars);
   }
 
-  (*vars)["MethodCount"] = as_string(service->method_count());
-  printer->Print(*vars,
-                 "$ns$$Service$::AsyncService::AsyncService() : "
-                 "::grpc::AsynchronousService("
-                 "$prefix$$Service$_method_names, $MethodCount$) "
-                 "{}\n\n");
-
-  printer->Print(*vars,
-                 "$ns$$Service$::Service::Service() {\n"
-                 "}\n\n");
-  printer->Print(*vars,
-                 "$ns$$Service$::Service::~Service() {\n"
-                 "}\n\n");
-  for (int i = 0; i < service->method_count(); ++i) {
-    (*vars)["Idx"] = as_string(i);
-    PrintSourceServerMethod(printer, service->method(i), vars);
-    PrintSourceServerAsyncMethod(printer, service->method(i), vars);
-  }
-  printer->Print(*vars,
-                 "::grpc::RpcService* $ns$$Service$::Service::service() {\n");
+  printer->Print(*vars, "$ns$$Service$::Service::Service() {\n");
   printer->Indent();
-  printer->Print(
-      "if (service_) {\n"
-      "  return service_.get();\n"
-      "}\n");
-  printer->Print("service_ = std::unique_ptr< ::grpc::RpcService>(new ::grpc::RpcService());\n");
+  printer->Print(*vars, "(void)$prefix$$Service$_method_names;\n");
   for (int i = 0; i < service->method_count(); ++i) {
     const grpc::protobuf::MethodDescriptor *method = service->method(i);
     (*vars)["Idx"] = as_string(i);
@@ -1043,7 +1118,7 @@
     if (NoStreaming(method)) {
       printer->Print(
           *vars,
-          "service_->AddMethod(new ::grpc::RpcServiceMethod(\n"
+          "AddMethod(new ::grpc::RpcServiceMethod(\n"
           "    $prefix$$Service$_method_names[$Idx$],\n"
           "    ::grpc::RpcMethod::NORMAL_RPC,\n"
           "    new ::grpc::RpcMethodHandler< $ns$$Service$::Service, "
@@ -1053,7 +1128,7 @@
     } else if (ClientOnlyStreaming(method)) {
       printer->Print(
           *vars,
-          "service_->AddMethod(new ::grpc::RpcServiceMethod(\n"
+          "AddMethod(new ::grpc::RpcServiceMethod(\n"
           "    $prefix$$Service$_method_names[$Idx$],\n"
           "    ::grpc::RpcMethod::CLIENT_STREAMING,\n"
           "    new ::grpc::ClientStreamingHandler< "
@@ -1062,7 +1137,7 @@
     } else if (ServerOnlyStreaming(method)) {
       printer->Print(
           *vars,
-          "service_->AddMethod(new ::grpc::RpcServiceMethod(\n"
+          "AddMethod(new ::grpc::RpcServiceMethod(\n"
           "    $prefix$$Service$_method_names[$Idx$],\n"
           "    ::grpc::RpcMethod::SERVER_STREAMING,\n"
           "    new ::grpc::ServerStreamingHandler< "
@@ -1071,7 +1146,7 @@
     } else if (BidiStreaming(method)) {
       printer->Print(
           *vars,
-          "service_->AddMethod(new ::grpc::RpcServiceMethod(\n"
+          "AddMethod(new ::grpc::RpcServiceMethod(\n"
           "    $prefix$$Service$_method_names[$Idx$],\n"
           "    ::grpc::RpcMethod::BIDI_STREAMING,\n"
           "    new ::grpc::BidiStreamingHandler< "
@@ -1079,9 +1154,15 @@
           "        std::mem_fn(&$ns$$Service$::Service::$Method$), this)));\n");
     }
   }
-  printer->Print("return service_.get();\n");
   printer->Outdent();
-  printer->Print("}\n\n");
+  printer->Print(*vars, "}\n\n");
+  printer->Print(*vars,
+                 "$ns$$Service$::Service::~Service() {\n"
+                 "}\n\n");
+  for (int i = 0; i < service->method_count(); ++i) {
+    (*vars)["Idx"] = as_string(i);
+    PrintSourceServerMethod(printer, service->method(i), vars);
+  }
 }
 
 grpc::string GetSourceServices(const grpc::protobuf::FileDescriptor *file,
diff --git a/src/compiler/python_generator.cc b/src/compiler/python_generator.cc
index c754ae2..4fd5dfb 100644
--- a/src/compiler/python_generator.cc
+++ b/src/compiler/python_generator.cc
@@ -42,7 +42,6 @@
 #include <tuple>
 #include <vector>
 
-#include <grpc++/support/config.h>
 #include "src/compiler/config.h"
 #include "src/compiler/generator_helpers.h"
 #include "src/compiler/python_generator.h"
diff --git a/src/core/census/context.c b/src/core/census/context.c
index cab58b6..e60330d 100644
--- a/src/core/census/context.c
+++ b/src/core/census/context.c
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -31,16 +31,500 @@
  *
  */
 
-#include "src/core/census/context.h"
-
-#include <string.h>
 #include <grpc/census.h>
 #include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+#include <grpc/support/port_platform.h>
+#include <grpc/support/useful.h>
+#include <stdbool.h>
+#include <string.h>
+#include "src/core/support/string.h"
 
-/* Placeholder implementation only. */
+// Functions in this file support the public context API, including
+// encoding/decoding as part of context propagation across RPC's. The overall
+// requirements (in approximate priority order) for the
+// context representation:
+// 1. Efficient conversion to/from wire format
+// 2. Minimal bytes used on-wire
+// 3. Efficient context creation
+// 4. Efficient lookup of tag value for a key
+// 5. Efficient iteration over tags
+// 6. Minimal memory footprint
+//
+// Notes on tradeoffs/decisions:
+// * tag includes 1 byte length of key, as well as nil-terminating byte. These
+//   are to aid in efficient parsing and the ability to directly return key
+//   strings. This is more important than saving a single byte/tag on the wire.
+// * The wire encoding uses only single byte values. This eliminates the need
+//   to handle endian-ness conversions. It also means there is a hard upper
+//   limit of 255 for both CENSUS_MAX_TAG_KV_LEN and CENSUS_MAX_PROPAGATED_TAGS.
+// * Keep all tag information (keys/values/flags) in a single memory buffer,
+//   that can be directly copied to the wire.
+// * Binary tags share the same structure as, but are encoded separately from,
+//   non-binary tags. This is primarily because non-binary tags are far more
+//   likely to be repeated across multiple RPC calls, so are more efficiently
+//   cached and compressed in any metadata schemes.
 
-size_t census_context_serialize(const census_context *context, char *buffer,
-                                size_t buf_size) {
-  /* TODO(aveitch): implement serialization */
+// Structure representing a set of tags. Essentially a count of number of tags
+// present, and pointer to a chunk of memory that contains the per-tag details.
+struct tag_set {
+  int ntags;        // number of tags.
+  int ntags_alloc;  // ntags + number of deleted tags (total number of tags
+  // in all of kvm). This will always be == ntags, except during the process
+  // of building a new tag set.
+  size_t kvm_size;  // number of bytes allocated for key/value storage.
+  size_t kvm_used;  // number of bytes of used key/value memory
+  char *kvm;        // key/value memory. Consists of repeated entries of:
+  //   Offset  Size  Description
+  //     0      1    Key length, including trailing 0. (K)
+  //     1      1    Value length. (V)
+  //     2      1    Flags
+  //     3      K    Key bytes
+  //     3 + K  V    Value bytes
+  //
+  // We refer to the first 3 entries as the 'tag header'. If extra values are
+  // introduced in the header, you will need to modify the TAG_HEADER_SIZE
+  // constant, the raw_tag structure (and everything that uses it) and the
+  // encode/decode functions appropriately.
+};
+
+// Number of bytes in tag header.
+#define TAG_HEADER_SIZE 3  // key length (1) + value length (1) + flags (1)
+// Offsets to tag header entries.
+#define KEY_LEN_OFFSET 0
+#define VALUE_LEN_OFFSET 1
+#define FLAG_OFFSET 2
+
+// raw_tag represents the raw-storage form of a tag in the kvm of a tag_set.
+struct raw_tag {
+  uint8_t key_len;
+  uint8_t value_len;
+  uint8_t flags;
+  char *key;
+  char *value;
+};
+
+// Use a reserved flag bit for indication of deleted tag.
+#define CENSUS_TAG_DELETED CENSUS_TAG_RESERVED
+#define CENSUS_TAG_IS_DELETED(flags) (flags & CENSUS_TAG_DELETED)
+
+// Primary (external) representation of a context. Composed of 3 underlying
+// tag_set structs, one for each of the binary/printable propagated tags, and
+// one for everything else. This is to efficiently support tag
+// encoding/decoding.
+struct census_context {
+  struct tag_set tags[3];
+  census_context_status status;
+};
+
+// Indices into the tags member of census_context
+#define PROPAGATED_TAGS 0
+#define PROPAGATED_BINARY_TAGS 1
+#define LOCAL_TAGS 2
+
+// Extract a raw tag given a pointer (raw) to the tag header. Allow for some
+// extra bytes in the tag header (see encode/decode functions for usage: this
+// allows for future expansion of the tag header).
+static char *decode_tag(struct raw_tag *tag, char *header, int offset) {
+  tag->key_len = (uint8_t)(*header++);
+  tag->value_len = (uint8_t)(*header++);
+  tag->flags = (uint8_t)(*header++);
+  header += offset;
+  tag->key = header;
+  header += tag->key_len;
+  tag->value = header;
+  return header + tag->value_len;
+}
+
+// Make a copy (in 'to') of an existing tag_set.
+static void tag_set_copy(struct tag_set *to, const struct tag_set *from) {
+  memcpy(to, from, sizeof(struct tag_set));
+  to->kvm = gpr_malloc(to->kvm_size);
+  memcpy(to->kvm, from->kvm, from->kvm_used);
+}
+
+// Delete a tag from a tag_set, if it exists (returns true if it did).
+static bool tag_set_delete_tag(struct tag_set *tags, const char *key,
+                               size_t key_len) {
+  char *kvp = tags->kvm;
+  for (int i = 0; i < tags->ntags_alloc; i++) {
+    uint8_t *flags = (uint8_t *)(kvp + FLAG_OFFSET);
+    struct raw_tag tag;
+    kvp = decode_tag(&tag, kvp, 0);
+    if (CENSUS_TAG_IS_DELETED(tag.flags)) continue;
+    if ((key_len == tag.key_len) && (memcmp(key, tag.key, key_len) == 0)) {
+      *flags |= CENSUS_TAG_DELETED;
+      tags->ntags--;
+      return true;
+    }
+  }
+  return false;
+}
+
+// Delete a tag from a context, return true if it existed.
+static bool context_delete_tag(census_context *context, const census_tag *tag,
+                               size_t key_len) {
+  return (
+      tag_set_delete_tag(&context->tags[LOCAL_TAGS], tag->key, key_len) ||
+      tag_set_delete_tag(&context->tags[PROPAGATED_TAGS], tag->key, key_len) ||
+      tag_set_delete_tag(&context->tags[PROPAGATED_BINARY_TAGS], tag->key,
+                         key_len));
+}
+
+// Add a tag to a tag_set. Return true on success, false if the tag could
+// not be added because of constraints on tag set size. This function should
+// not be called if the tag may already exist (in a non-deleted state) in
+// the tag_set, as that would result in two tags with the same key.
+static bool tag_set_add_tag(struct tag_set *tags, const census_tag *tag,
+                            size_t key_len) {
+  if (tags->ntags == CENSUS_MAX_PROPAGATED_TAGS) {
+    return false;
+  }
+  const size_t tag_size = key_len + tag->value_len + TAG_HEADER_SIZE;
+  if (tags->kvm_used + tag_size > tags->kvm_size) {
+    // allocate new memory if needed
+    tags->kvm_size += 2 * CENSUS_MAX_TAG_KV_LEN + TAG_HEADER_SIZE;
+    char *new_kvm = gpr_malloc(tags->kvm_size);
+    memcpy(new_kvm, tags->kvm, tags->kvm_used);
+    gpr_free(tags->kvm);
+    tags->kvm = new_kvm;
+  }
+  char *kvp = tags->kvm + tags->kvm_used;
+  *kvp++ = (char)key_len;
+  *kvp++ = (char)tag->value_len;
+  // ensure reserved flags are not used.
+  *kvp++ = (char)(tag->flags & (CENSUS_TAG_PROPAGATE | CENSUS_TAG_STATS |
+                                CENSUS_TAG_BINARY));
+  memcpy(kvp, tag->key, key_len);
+  kvp += key_len;
+  memcpy(kvp, tag->value, tag->value_len);
+  tags->kvm_used += tag_size;
+  tags->ntags++;
+  tags->ntags_alloc++;
+  return true;
+}
+
+// Add/modify/delete a tag to/in a context. Caller must validate that tag key
+// etc. are valid.
+static void context_modify_tag(census_context *context, const census_tag *tag,
+                               size_t key_len) {
+  // First delete the tag if it is already present.
+  bool deleted = context_delete_tag(context, tag, key_len);
+  // Determine if we need to add it back.
+  bool call_add = tag->value != NULL && tag->value_len != 0;
+  bool added = false;
+  if (call_add) {
+    if (CENSUS_TAG_IS_PROPAGATED(tag->flags)) {
+      if (CENSUS_TAG_IS_BINARY(tag->flags)) {
+        added = tag_set_add_tag(&context->tags[PROPAGATED_BINARY_TAGS], tag,
+                                key_len);
+      } else {
+        added = tag_set_add_tag(&context->tags[PROPAGATED_TAGS], tag, key_len);
+      }
+    } else {
+      added = tag_set_add_tag(&context->tags[LOCAL_TAGS], tag, key_len);
+    }
+  }
+  if (deleted) {
+    if (call_add) {
+      context->status.n_modified_tags++;
+    } else {
+      context->status.n_deleted_tags++;
+    }
+  } else {
+    if (added) {
+      context->status.n_added_tags++;
+    } else {
+      context->status.n_ignored_tags++;
+    }
+  }
+}
+
+// Remove memory used for deleted tags from a tag set. Basic algorithm:
+// 1) Walk through tag set to find first deleted tag. Record where it is.
+// 2) Find the next not-deleted tag. Copy all of kvm from there to the end
+//    "over" the deleted tags
+// 3) repeat #1 and #2 until we have seen all tags
+// 4) if we are still looking for a not-deleted tag, then all the end portion
+//    of the kvm is deleted. Just reduce the used amount of memory by the
+//    appropriate amount.
+static void tag_set_flatten(struct tag_set *tags) {
+  if (tags->ntags == tags->ntags_alloc) return;
+  bool found_deleted = false;  // found a deleted tag.
+  char *kvp = tags->kvm;
+  char *dbase = NULL;  // record location of deleted tag
+  for (int i = 0; i < tags->ntags_alloc; i++) {
+    struct raw_tag tag;
+    char *next_kvp = decode_tag(&tag, kvp, 0);
+    if (found_deleted) {
+      if (!CENSUS_TAG_IS_DELETED(tag.flags)) {
+        ptrdiff_t reduce = kvp - dbase;  // #bytes in deleted tags
+        GPR_ASSERT(reduce > 0);
+        ptrdiff_t copy_size = tags->kvm + tags->kvm_used - kvp;
+        GPR_ASSERT(copy_size > 0);
+        memmove(dbase, kvp, (size_t)copy_size);
+        tags->kvm_used -= (size_t)reduce;
+        next_kvp -= reduce;
+        found_deleted = false;
+      }
+    } else {
+      if (CENSUS_TAG_IS_DELETED(tag.flags)) {
+        dbase = kvp;
+        found_deleted = true;
+      }
+    }
+    kvp = next_kvp;
+  }
+  if (found_deleted) {
+    GPR_ASSERT(dbase > tags->kvm);
+    tags->kvm_used = (size_t)(dbase - tags->kvm);
+  }
+  tags->ntags_alloc = tags->ntags;
+}
+
+census_context *census_context_create(const census_context *base,
+                                      const census_tag *tags, int ntags,
+                                      census_context_status const **status) {
+  census_context *context = gpr_malloc(sizeof(census_context));
+  // If we are given a base, copy it into our new tag set. Otherwise set it
+  // to zero/NULL everything.
+  if (base == NULL) {
+    memset(context, 0, sizeof(census_context));
+  } else {
+    tag_set_copy(&context->tags[PROPAGATED_TAGS], &base->tags[PROPAGATED_TAGS]);
+    tag_set_copy(&context->tags[PROPAGATED_BINARY_TAGS],
+                 &base->tags[PROPAGATED_BINARY_TAGS]);
+    tag_set_copy(&context->tags[LOCAL_TAGS], &base->tags[LOCAL_TAGS]);
+    memset(&context->status, 0, sizeof(context->status));
+  }
+  // Walk over the additional tags and, for those that aren't invalid, modify
+  // the context to add/replace/delete as required.
+  for (int i = 0; i < ntags; i++) {
+    const census_tag *tag = &tags[i];
+    size_t key_len = strlen(tag->key) + 1;
+    // ignore the tag if it is too long/short.
+    if (key_len != 1 && key_len <= CENSUS_MAX_TAG_KV_LEN &&
+        tag->value_len <= CENSUS_MAX_TAG_KV_LEN) {
+      context_modify_tag(context, tag, key_len);
+    } else {
+      context->status.n_invalid_tags++;
+    }
+  }
+  // Remove any deleted tags, update status if needed, and return.
+  tag_set_flatten(&context->tags[PROPAGATED_TAGS]);
+  tag_set_flatten(&context->tags[PROPAGATED_BINARY_TAGS]);
+  tag_set_flatten(&context->tags[LOCAL_TAGS]);
+  context->status.n_propagated_tags = context->tags[PROPAGATED_TAGS].ntags;
+  context->status.n_propagated_binary_tags =
+      context->tags[PROPAGATED_BINARY_TAGS].ntags;
+  context->status.n_local_tags = context->tags[LOCAL_TAGS].ntags;
+  if (status) {
+    *status = &context->status;
+  }
+  return context;
+}
+
+const census_context_status *census_context_get_status(
+    const census_context *context) {
+  return &context->status;
+}
+
+void census_context_destroy(census_context *context) {
+  gpr_free(context->tags[PROPAGATED_TAGS].kvm);
+  gpr_free(context->tags[PROPAGATED_BINARY_TAGS].kvm);
+  gpr_free(context->tags[LOCAL_TAGS].kvm);
+  gpr_free(context);
+}
+
+void census_context_initialize_iterator(const census_context *context,
+                                        census_context_iterator *iterator) {
+  iterator->context = context;
+  iterator->index = 0;
+  if (context->tags[PROPAGATED_TAGS].ntags != 0) {
+    iterator->base = PROPAGATED_TAGS;
+    iterator->kvm = context->tags[PROPAGATED_TAGS].kvm;
+  } else if (context->tags[PROPAGATED_BINARY_TAGS].ntags != 0) {
+    iterator->base = PROPAGATED_BINARY_TAGS;
+    iterator->kvm = context->tags[PROPAGATED_BINARY_TAGS].kvm;
+  } else if (context->tags[LOCAL_TAGS].ntags != 0) {
+    iterator->base = LOCAL_TAGS;
+    iterator->kvm = context->tags[LOCAL_TAGS].kvm;
+  } else {
+    iterator->base = -1;
+  }
+}
+
+int census_context_next_tag(census_context_iterator *iterator,
+                            census_tag *tag) {
+  if (iterator->base < 0) {
+    return 0;
+  }
+  struct raw_tag raw;
+  iterator->kvm = decode_tag(&raw, iterator->kvm, 0);
+  tag->key = raw.key;
+  tag->value = raw.value;
+  tag->value_len = raw.value_len;
+  tag->flags = raw.flags;
+  if (++iterator->index == iterator->context->tags[iterator->base].ntags) {
+    do {
+      if (iterator->base == LOCAL_TAGS) {
+        iterator->base = -1;
+        return 1;
+      }
+    } while (iterator->context->tags[++iterator->base].ntags == 0);
+    iterator->index = 0;
+    iterator->kvm = iterator->context->tags[iterator->base].kvm;
+  }
+  return 1;
+}
+
+// Find a tag in a tag_set by key. Return true if found, false otherwise.
+static bool tag_set_get_tag(const struct tag_set *tags, const char *key,
+                            size_t key_len, census_tag *tag) {
+  char *kvp = tags->kvm;
+  for (int i = 0; i < tags->ntags; i++) {
+    struct raw_tag raw;
+    kvp = decode_tag(&raw, kvp, 0);
+    if (key_len == raw.key_len && memcmp(raw.key, key, key_len) == 0) {
+      tag->key = raw.key;
+      tag->value = raw.value;
+      tag->value_len = raw.value_len;
+      tag->flags = raw.flags;
+      return true;
+    }
+  }
+  return false;
+}
+
+int census_context_get_tag(const census_context *context, const char *key,
+                           census_tag *tag) {
+  size_t key_len = strlen(key) + 1;
+  if (key_len == 1) {
+    return 0;
+  }
+  if (tag_set_get_tag(&context->tags[PROPAGATED_TAGS], key, key_len, tag) ||
+      tag_set_get_tag(&context->tags[PROPAGATED_BINARY_TAGS], key, key_len,
+                      tag) ||
+      tag_set_get_tag(&context->tags[LOCAL_TAGS], key, key_len, tag)) {
+    return 1;
+  }
   return 0;
 }
+
+// Context encoding and decoding functions.
+//
+// Wire format for tag_set's on the wire:
+//
+// First, a tag set header:
+//
+// offset   bytes  description
+//   0        1    version number
+//   1        1    number of bytes in this header. This allows for future
+//                 expansion.
+//   2        1    number of bytes in each tag header.
+//   3        1    ntags value from tag set.
+//
+//   This is followed by the key/value memory from struct tag_set.
+
+#define ENCODED_VERSION 0      // Version number
+#define ENCODED_HEADER_SIZE 4  // size of tag set header
+
+// Encode a tag set. Returns 0 if buffer is too small.
+static size_t tag_set_encode(const struct tag_set *tags, char *buffer,
+                             size_t buf_size) {
+  if (buf_size < ENCODED_HEADER_SIZE + tags->kvm_used) {
+    return 0;
+  }
+  buf_size -= ENCODED_HEADER_SIZE;
+  *buffer++ = (char)ENCODED_VERSION;
+  *buffer++ = (char)ENCODED_HEADER_SIZE;
+  *buffer++ = (char)TAG_HEADER_SIZE;
+  *buffer++ = (char)tags->ntags;
+  if (tags->ntags == 0) {
+    return ENCODED_HEADER_SIZE;
+  }
+  memcpy(buffer, tags->kvm, tags->kvm_used);
+  return ENCODED_HEADER_SIZE + tags->kvm_used;
+}
+
+char *census_context_encode(const census_context *context, char *buffer,
+                            size_t buf_size, size_t *print_buf_size,
+                            size_t *bin_buf_size) {
+  *print_buf_size =
+      tag_set_encode(&context->tags[PROPAGATED_TAGS], buffer, buf_size);
+  if (*print_buf_size == 0) {
+    return NULL;
+  }
+  char *b_buffer = buffer + *print_buf_size;
+  *bin_buf_size = tag_set_encode(&context->tags[PROPAGATED_BINARY_TAGS],
+                                 b_buffer, buf_size - *print_buf_size);
+  if (*bin_buf_size == 0) {
+    return NULL;
+  }
+  return b_buffer;
+}
+
+// Decode a tag set.
+static void tag_set_decode(struct tag_set *tags, const char *buffer,
+                           size_t size) {
+  uint8_t version = (uint8_t)(*buffer++);
+  uint8_t header_size = (uint8_t)(*buffer++);
+  uint8_t tag_header_size = (uint8_t)(*buffer++);
+  tags->ntags = tags->ntags_alloc = (int)(*buffer++);
+  if (tags->ntags == 0) {
+    tags->ntags_alloc = 0;
+    tags->kvm_size = 0;
+    tags->kvm_used = 0;
+    tags->kvm = NULL;
+    return;
+  }
+  if (header_size != ENCODED_HEADER_SIZE) {
+    GPR_ASSERT(version != ENCODED_VERSION);
+    GPR_ASSERT(ENCODED_HEADER_SIZE < header_size);
+    buffer += (header_size - ENCODED_HEADER_SIZE);
+  }
+  tags->kvm_used = size - header_size;
+  tags->kvm_size = tags->kvm_used + CENSUS_MAX_TAG_KV_LEN;
+  tags->kvm = gpr_malloc(tags->kvm_size);
+  if (tag_header_size != TAG_HEADER_SIZE) {
+    // something new in the tag information. I don't understand it, so
+    // don't copy it over.
+    GPR_ASSERT(version != ENCODED_VERSION);
+    GPR_ASSERT(tag_header_size > TAG_HEADER_SIZE);
+    char *kvp = tags->kvm;
+    for (int i = 0; i < tags->ntags; i++) {
+      memcpy(kvp, buffer, TAG_HEADER_SIZE);
+      kvp += header_size;
+      struct raw_tag raw;
+      buffer =
+          decode_tag(&raw, (char *)buffer, tag_header_size - TAG_HEADER_SIZE);
+      memcpy(kvp, raw.key, (size_t)raw.key_len + raw.value_len);
+      kvp += raw.key_len + raw.value_len;
+    }
+  } else {
+    memcpy(tags->kvm, buffer, tags->kvm_used);
+  }
+}
+
+census_context *census_context_decode(const char *buffer, size_t size,
+                                      const char *bin_buffer, size_t bin_size) {
+  census_context *context = gpr_malloc(sizeof(census_context));
+  memset(&context->tags[LOCAL_TAGS], 0, sizeof(struct tag_set));
+  if (buffer == NULL) {
+    memset(&context->tags[PROPAGATED_TAGS], 0, sizeof(struct tag_set));
+  } else {
+    tag_set_decode(&context->tags[PROPAGATED_TAGS], buffer, size);
+  }
+  if (bin_buffer == NULL) {
+    memset(&context->tags[PROPAGATED_BINARY_TAGS], 0, sizeof(struct tag_set));
+  } else {
+    tag_set_decode(&context->tags[PROPAGATED_BINARY_TAGS], bin_buffer,
+                   bin_size);
+  }
+  memset(&context->status, 0, sizeof(context->status));
+  context->status.n_propagated_tags = context->tags[PROPAGATED_TAGS].ntags;
+  context->status.n_propagated_binary_tags =
+      context->tags[PROPAGATED_BINARY_TAGS].ntags;
+  // TODO(aveitch): check that BINARY flag is correct for each type.
+  return context;
+}
diff --git a/src/core/census/grpc_filter.c b/src/core/census/grpc_filter.c
index ee1f62f..c8aaf31 100644
--- a/src/core/census/grpc_filter.c
+++ b/src/core/census/grpc_filter.c
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -91,7 +91,7 @@
 }
 
 static void server_on_done_recv(grpc_exec_ctx *exec_ctx, void *ptr,
-                                int success) {
+                                bool success) {
   grpc_call_element *elem = ptr;
   call_data *calld = elem->call_data;
   channel_data *chand = elem->channel_data;
@@ -107,8 +107,8 @@
   if (op->recv_initial_metadata) {
     /* substitute our callback for the op callback */
     calld->recv_initial_metadata = op->recv_initial_metadata;
-    calld->on_done_recv = op->on_complete;
-    op->on_complete = &calld->finish_recv;
+    calld->on_done_recv = op->recv_initial_metadata_ready;
+    op->recv_initial_metadata_ready = &calld->finish_recv;
   }
 }
 
diff --git a/src/core/census/placeholders.c b/src/core/census/placeholders.c
new file mode 100644
index 0000000..fe23d13
--- /dev/null
+++ b/src/core/census/placeholders.c
@@ -0,0 +1,109 @@
+/*
+ *
+ * Copyright 2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <grpc/census.h>
+
+#include <grpc/support/log.h>
+
+/* Placeholders for the pending APIs */
+
+int census_get_trace_record(census_trace_record *trace_record) {
+  (void)trace_record;
+  abort();
+}
+
+void census_record_values(census_context *context, census_value *values,
+                          size_t nvalues) {
+  (void)context;
+  (void)values;
+  (void)nvalues;
+  abort();
+}
+
+void census_set_rpc_client_peer(census_context *context, const char *peer) {
+  (void)context;
+  (void)peer;
+  abort();
+}
+
+void census_trace_scan_end() { abort(); }
+
+int census_trace_scan_start(int consume) {
+  (void)consume;
+  abort();
+}
+
+const census_aggregation *census_view_aggregrations(const census_view *view) {
+  (void)view;
+  abort();
+}
+
+census_view *census_view_create(uint32_t metric_id, const census_context *tags,
+                                const census_aggregation *aggregations,
+                                size_t naggregations) {
+  (void)metric_id;
+  (void)tags;
+  (void)aggregations;
+  (void)naggregations;
+  abort();
+}
+
+const census_context *census_view_tags(const census_view *view) {
+  (void)view;
+  abort();
+}
+
+void census_view_delete(census_view *view) {
+  (void)view;
+  abort();
+}
+
+const census_view_data *census_view_get_data(const census_view *view) {
+  (void)view;
+  abort();
+}
+
+size_t census_view_metric(const census_view *view) {
+  (void)view;
+  abort();
+}
+
+size_t census_view_naggregations(const census_view *view) {
+  (void)view;
+  abort();
+}
+
+void census_view_reset(census_view *view) {
+  (void)view;
+  abort();
+}
diff --git a/src/core/census/tag_set.c b/src/core/census/tag_set.c
deleted file mode 100644
index 9b65a1d..0000000
--- a/src/core/census/tag_set.c
+++ /dev/null
@@ -1,535 +0,0 @@
-/*
- *
- * Copyright 2015-2016, Google Inc.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- *     * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *     * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#include <grpc/census.h>
-#include <grpc/support/alloc.h>
-#include <grpc/support/log.h>
-#include <grpc/support/port_platform.h>
-#include <grpc/support/useful.h>
-#include <stdbool.h>
-#include <string.h>
-#include "src/core/support/string.h"
-
-// Functions in this file support the public tag_set API, as well as
-// encoding/decoding tag_sets as part of context propagation across
-// RPC's. The overall requirements (in approximate priority order) for the
-// tag_set representations:
-// 1. Efficient conversion to/from wire format
-// 2. Minimal bytes used on-wire
-// 3. Efficient tag set creation
-// 4. Efficient lookup of value for a key
-// 5. Efficient lookup of value for an index (to support iteration)
-// 6. Minimal memory footprint
-//
-// Notes on tradeoffs/decisions:
-// * tag includes 1 byte length of key, as well as nil-terminating byte. These
-//   are to aid in efficient parsing and the ability to directly return key
-//   strings. This is more important than saving a single byte/tag on the wire.
-// * The wire encoding uses only single byte values. This eliminates the need
-//   to handle endian-ness conversions. It also means there is a hard upper
-//   limit of 255 for both CENSUS_MAX_TAG_KV_LEN and CENSUS_MAX_PROPAGATED_TAGS.
-// * Keep all tag information (keys/values/flags) in a single memory buffer,
-//   that can be directly copied to the wire.14
-// * Binary tags share the same structure as, but are encoded separately from,
-//   non-binary tags. This is primarily because non-binary tags are far more
-//   likely to be repeated across multiple RPC calls, so are more efficiently
-//   cached and compressed in any metadata schemes.
-// * all lengths etc. are restricted to one byte. This eliminates endian
-//   issues.
-
-// Structure representing a set of tags. Essentially a count of number of tags
-// present, and pointer to a chunk of memory that contains the per-tag details.
-struct tag_set {
-  int ntags;        // number of tags.
-  int ntags_alloc;  // ntags + number of deleted tags (total number of tags
-  // in all of kvm). This will always be == ntags, except during the process
-  // of building a new tag set.
-  size_t kvm_size;  // number of bytes allocated for key/value storage.
-  size_t kvm_used;  // number of bytes of used key/value memory
-  char *kvm;        // key/value memory. Consists of repeated entries of:
-  //   Offset  Size  Description
-  //     0      1    Key length, including trailing 0. (K)
-  //     1      1    Value length. (V)
-  //     2      1    Flags
-  //     3      K    Key bytes
-  //     3 + K  V    Value bytes
-  //
-  // We refer to the first 3 entries as the 'tag header'. If extra values are
-  // introduced in the header, you will need to modify the TAG_HEADER_SIZE
-  // constant, the raw_tag structure (and everything that uses it) and the
-  // encode/decode functions appropriately.
-};
-
-// Number of bytes in tag header.
-#define TAG_HEADER_SIZE 3  // key length (1) + value length (1) + flags (1)
-// Offsets to tag header entries.
-#define KEY_LEN_OFFSET 0
-#define VALUE_LEN_OFFSET 1
-#define FLAG_OFFSET 2
-
-// raw_tag represents the raw-storage form of a tag in the kvm of a tag_set.
-struct raw_tag {
-  uint8_t key_len;
-  uint8_t value_len;
-  uint8_t flags;
-  char *key;
-  char *value;
-};
-
-// Use a reserved flag bit for indication of deleted tag.
-#define CENSUS_TAG_DELETED CENSUS_TAG_RESERVED
-#define CENSUS_TAG_IS_DELETED(flags) (flags & CENSUS_TAG_DELETED)
-
-// Primary (external) representation of a tag set. Composed of 3 underlying
-// tag_set structs, one for each of the binary/printable propagated tags, and
-// one for everything else. This is to efficiently support tag
-// encoding/decoding.
-struct census_tag_set {
-  struct tag_set tags[3];
-  census_tag_set_create_status status;
-};
-
-// Indices into the tags member of census_tag_set
-#define PROPAGATED_TAGS 0
-#define PROPAGATED_BINARY_TAGS 1
-#define LOCAL_TAGS 2
-
-// Extract a raw tag given a pointer (raw) to the tag header. Allow for some
-// extra bytes in the tag header (see encode/decode functions for usage: this
-// allows for future expansion of the tag header).
-static char *decode_tag(struct raw_tag *tag, char *header, int offset) {
-  tag->key_len = (uint8_t)(*header++);
-  tag->value_len = (uint8_t)(*header++);
-  tag->flags = (uint8_t)(*header++);
-  header += offset;
-  tag->key = header;
-  header += tag->key_len;
-  tag->value = header;
-  return header + tag->value_len;
-}
-
-// Make a copy (in 'to') of an existing tag_set.
-static void tag_set_copy(struct tag_set *to, const struct tag_set *from) {
-  memcpy(to, from, sizeof(struct tag_set));
-  to->kvm = gpr_malloc(to->kvm_size);
-  memcpy(to->kvm, from->kvm, from->kvm_used);
-}
-
-// Delete a tag from a tag_set, if it exists (returns true if it did).
-static bool tag_set_delete_tag(struct tag_set *tags, const char *key,
-                               size_t key_len) {
-  char *kvp = tags->kvm;
-  for (int i = 0; i < tags->ntags_alloc; i++) {
-    uint8_t *flags = (uint8_t *)(kvp + FLAG_OFFSET);
-    struct raw_tag tag;
-    kvp = decode_tag(&tag, kvp, 0);
-    if (CENSUS_TAG_IS_DELETED(tag.flags)) continue;
-    if ((key_len == tag.key_len) && (memcmp(key, tag.key, key_len) == 0)) {
-      *flags |= CENSUS_TAG_DELETED;
-      tags->ntags--;
-      return true;
-    }
-  }
-  return false;
-}
-
-// Delete a tag from a census_tag_set, return true if it existed.
-static bool cts_delete_tag(census_tag_set *tags, const census_tag *tag,
-                           size_t key_len) {
-  return (tag_set_delete_tag(&tags->tags[LOCAL_TAGS], tag->key, key_len) ||
-          tag_set_delete_tag(&tags->tags[PROPAGATED_TAGS], tag->key, key_len) ||
-          tag_set_delete_tag(&tags->tags[PROPAGATED_BINARY_TAGS], tag->key,
-                             key_len));
-}
-
-// Add a tag to a tag_set. Return true on sucess, false if the tag could
-// not be added because of constraints on tag set size. This function should
-// not be called if the tag may already exist (in a non-deleted state) in
-// the tag_set, as that would result in two tags with the same key.
-static bool tag_set_add_tag(struct tag_set *tags, const census_tag *tag,
-                            size_t key_len) {
-  if (tags->ntags == CENSUS_MAX_PROPAGATED_TAGS) {
-    return false;
-  }
-  const size_t tag_size = key_len + tag->value_len + TAG_HEADER_SIZE;
-  if (tags->kvm_used + tag_size > tags->kvm_size) {
-    // allocate new memory if needed
-    tags->kvm_size += 2 * CENSUS_MAX_TAG_KV_LEN + TAG_HEADER_SIZE;
-    char *new_kvm = gpr_malloc(tags->kvm_size);
-    memcpy(new_kvm, tags->kvm, tags->kvm_used);
-    gpr_free(tags->kvm);
-    tags->kvm = new_kvm;
-  }
-  char *kvp = tags->kvm + tags->kvm_used;
-  *kvp++ = (char)key_len;
-  *kvp++ = (char)tag->value_len;
-  // ensure reserved flags are not used.
-  *kvp++ = (char)(tag->flags & (CENSUS_TAG_PROPAGATE | CENSUS_TAG_STATS |
-                                CENSUS_TAG_BINARY));
-  memcpy(kvp, tag->key, key_len);
-  kvp += key_len;
-  memcpy(kvp, tag->value, tag->value_len);
-  tags->kvm_used += tag_size;
-  tags->ntags++;
-  tags->ntags_alloc++;
-  return true;
-}
-
-// Add/modify/delete a tag to/in a census_tag_set. Caller must validate that
-// tag key etc. are valid.
-static void cts_modify_tag(census_tag_set *tags, const census_tag *tag,
-                           size_t key_len) {
-  // First delete the tag if it is already present.
-  bool deleted = cts_delete_tag(tags, tag, key_len);
-  // Determine if we need to add it back.
-  bool call_add = tag->value != NULL && tag->value_len != 0;
-  bool added = false;
-  if (call_add) {
-    if (CENSUS_TAG_IS_PROPAGATED(tag->flags)) {
-      if (CENSUS_TAG_IS_BINARY(tag->flags)) {
-        added =
-            tag_set_add_tag(&tags->tags[PROPAGATED_BINARY_TAGS], tag, key_len);
-      } else {
-        added = tag_set_add_tag(&tags->tags[PROPAGATED_TAGS], tag, key_len);
-      }
-    } else {
-      added = tag_set_add_tag(&tags->tags[LOCAL_TAGS], tag, key_len);
-    }
-  }
-  if (deleted) {
-    if (call_add) {
-      tags->status.n_modified_tags++;
-    } else {
-      tags->status.n_deleted_tags++;
-    }
-  } else {
-    if (added) {
-      tags->status.n_added_tags++;
-    } else {
-      tags->status.n_ignored_tags++;
-    }
-  }
-}
-
-// Remove memory used for deleted tags from the tag set. Basic algorithm:
-// 1) Walk through tag set to find first deleted tag. Record where it is.
-// 2) Find the next not-deleted tag. Copy all of kvm from there to the end
-//    "over" the deleted tags
-// 3) repeat #1 and #2 until we have seen all tags
-// 4) if we are still looking for a not-deleted tag, then all the end portion
-//    of the kvm is deleted. Just reduce the used amount of memory by the
-//    appropriate amount.
-static void tag_set_flatten(struct tag_set *tags) {
-  if (tags->ntags == tags->ntags_alloc) return;
-  bool found_deleted = false;  // found a deleted tag.
-  char *kvp = tags->kvm;
-  char *dbase = NULL;  // record location of deleted tag
-  for (int i = 0; i < tags->ntags_alloc; i++) {
-    struct raw_tag tag;
-    char *next_kvp = decode_tag(&tag, kvp, 0);
-    if (found_deleted) {
-      if (!CENSUS_TAG_IS_DELETED(tag.flags)) {
-        ptrdiff_t reduce = kvp - dbase;  // #bytes in deleted tags
-        GPR_ASSERT(reduce > 0);
-        ptrdiff_t copy_size = tags->kvm + tags->kvm_used - kvp;
-        GPR_ASSERT(copy_size > 0);
-        memmove(dbase, kvp, (size_t)copy_size);
-        tags->kvm_used -= (size_t)reduce;
-        next_kvp -= reduce;
-        found_deleted = false;
-      }
-    } else {
-      if (CENSUS_TAG_IS_DELETED(tag.flags)) {
-        dbase = kvp;
-        found_deleted = true;
-      }
-    }
-    kvp = next_kvp;
-  }
-  if (found_deleted) {
-    GPR_ASSERT(dbase > tags->kvm);
-    tags->kvm_used = (size_t)(dbase - tags->kvm);
-  }
-  tags->ntags_alloc = tags->ntags;
-}
-
-census_tag_set *census_tag_set_create(
-    const census_tag_set *base, const census_tag *tags, int ntags,
-    census_tag_set_create_status const **status) {
-  census_tag_set *new_ts = gpr_malloc(sizeof(census_tag_set));
-  // If we are given a base, copy it into our new tag set. Otherwise set it
-  // to zero/NULL everything.
-  if (base == NULL) {
-    memset(new_ts, 0, sizeof(census_tag_set));
-  } else {
-    tag_set_copy(&new_ts->tags[PROPAGATED_TAGS], &base->tags[PROPAGATED_TAGS]);
-    tag_set_copy(&new_ts->tags[PROPAGATED_BINARY_TAGS],
-                 &base->tags[PROPAGATED_BINARY_TAGS]);
-    tag_set_copy(&new_ts->tags[LOCAL_TAGS], &base->tags[LOCAL_TAGS]);
-    memset(&new_ts->status, 0, sizeof(new_ts->status));
-  }
-  // Walk over the additional tags and, for those that aren't invalid, modify
-  // the tag set to add/replace/delete as required.
-  for (int i = 0; i < ntags; i++) {
-    const census_tag *tag = &tags[i];
-    size_t key_len = strlen(tag->key) + 1;
-    // ignore the tag if it is too long/short.
-    if (key_len != 1 && key_len <= CENSUS_MAX_TAG_KV_LEN &&
-        tag->value_len <= CENSUS_MAX_TAG_KV_LEN) {
-      cts_modify_tag(new_ts, tag, key_len);
-    } else {
-      new_ts->status.n_invalid_tags++;
-    }
-  }
-  // Remove any deleted tags, update status if needed, and return.
-  tag_set_flatten(&new_ts->tags[PROPAGATED_TAGS]);
-  tag_set_flatten(&new_ts->tags[PROPAGATED_BINARY_TAGS]);
-  tag_set_flatten(&new_ts->tags[LOCAL_TAGS]);
-  new_ts->status.n_propagated_tags = new_ts->tags[PROPAGATED_TAGS].ntags;
-  new_ts->status.n_propagated_binary_tags =
-      new_ts->tags[PROPAGATED_BINARY_TAGS].ntags;
-  new_ts->status.n_local_tags = new_ts->tags[LOCAL_TAGS].ntags;
-  if (status) {
-    *status = &new_ts->status;
-  }
-  return new_ts;
-}
-
-const census_tag_set_create_status *census_tag_set_get_create_status(
-    const census_tag_set *tags) {
-  return &tags->status;
-}
-
-void census_tag_set_destroy(census_tag_set *tags) {
-  gpr_free(tags->tags[PROPAGATED_TAGS].kvm);
-  gpr_free(tags->tags[PROPAGATED_BINARY_TAGS].kvm);
-  gpr_free(tags->tags[LOCAL_TAGS].kvm);
-  gpr_free(tags);
-}
-
-// Initialize a tag set iterator. Must be called before first use of the
-// iterator.
-void census_tag_set_initialize_iterator(const census_tag_set *tags,
-                                        census_tag_set_iterator *iterator) {
-  iterator->tags = tags;
-  iterator->index = 0;
-  if (tags->tags[PROPAGATED_TAGS].ntags != 0) {
-    iterator->base = PROPAGATED_TAGS;
-    iterator->kvm = tags->tags[PROPAGATED_TAGS].kvm;
-  } else if (tags->tags[PROPAGATED_BINARY_TAGS].ntags != 0) {
-    iterator->base = PROPAGATED_BINARY_TAGS;
-    iterator->kvm = tags->tags[PROPAGATED_BINARY_TAGS].kvm;
-  } else if (tags->tags[LOCAL_TAGS].ntags != 0) {
-    iterator->base = LOCAL_TAGS;
-    iterator->kvm = tags->tags[LOCAL_TAGS].kvm;
-  } else {
-    iterator->base = -1;
-  }
-}
-
-// Get the contents of the "next" tag in the tag set. If there are no more
-// tags in the tag set, returns 0 (and 'tag' contents will be unchanged),
-// otherwise returns 1. */
-int census_tag_set_next_tag(census_tag_set_iterator *iterator,
-                            census_tag *tag) {
-  if (iterator->base < 0) {
-    return 0;
-  }
-  struct raw_tag raw;
-  iterator->kvm = decode_tag(&raw, iterator->kvm, 0);
-  tag->key = raw.key;
-  tag->value = raw.value;
-  tag->value_len = raw.value_len;
-  tag->flags = raw.flags;
-  if (++iterator->index == iterator->tags->tags[iterator->base].ntags) {
-    do {
-      if (iterator->base == LOCAL_TAGS) {
-        iterator->base = -1;
-        return 1;
-      }
-    } while (iterator->tags->tags[++iterator->base].ntags == 0);
-    iterator->index = 0;
-    iterator->kvm = iterator->tags->tags[iterator->base].kvm;
-  }
-  return 1;
-}
-
-// Find a tag in a tag_set by key. Return true if found, false otherwise.
-static bool tag_set_get_tag_by_key(const struct tag_set *tags, const char *key,
-                                   size_t key_len, census_tag *tag) {
-  char *kvp = tags->kvm;
-  for (int i = 0; i < tags->ntags; i++) {
-    struct raw_tag raw;
-    kvp = decode_tag(&raw, kvp, 0);
-    if (key_len == raw.key_len && memcmp(raw.key, key, key_len) == 0) {
-      tag->key = raw.key;
-      tag->value = raw.value;
-      tag->value_len = raw.value_len;
-      tag->flags = raw.flags;
-      return true;
-    }
-  }
-  return false;
-}
-
-int census_tag_set_get_tag_by_key(const census_tag_set *tags, const char *key,
-                                  census_tag *tag) {
-  size_t key_len = strlen(key) + 1;
-  if (key_len == 1) {
-    return 0;
-  }
-  if (tag_set_get_tag_by_key(&tags->tags[PROPAGATED_TAGS], key, key_len, tag) ||
-      tag_set_get_tag_by_key(&tags->tags[PROPAGATED_BINARY_TAGS], key, key_len,
-                             tag) ||
-      tag_set_get_tag_by_key(&tags->tags[LOCAL_TAGS], key, key_len, tag)) {
-    return 1;
-  }
-  return 0;
-}
-
-// tag_set encoding and decoding functions.
-//
-// Wire format for tag sets on the wire:
-//
-// First, a tag set header:
-//
-// offset   bytes  description
-//   0        1    version number
-//   1        1    number of bytes in this header. This allows for future
-//                 expansion.
-//   2        1    number of bytes in each tag header.
-//   3        1    ntags value from tag set.
-//
-//   This is followed by the key/value memory from struct tag_set.
-
-#define ENCODED_VERSION 0      // Version number
-#define ENCODED_HEADER_SIZE 4  // size of tag set header
-
-// Encode a tag set. Returns 0 if buffer is too small.
-static size_t tag_set_encode(const struct tag_set *tags, char *buffer,
-                             size_t buf_size) {
-  if (buf_size < ENCODED_HEADER_SIZE + tags->kvm_used) {
-    return 0;
-  }
-  buf_size -= ENCODED_HEADER_SIZE;
-  *buffer++ = (char)ENCODED_VERSION;
-  *buffer++ = (char)ENCODED_HEADER_SIZE;
-  *buffer++ = (char)TAG_HEADER_SIZE;
-  *buffer++ = (char)tags->ntags;
-  if (tags->ntags == 0) {
-    return ENCODED_HEADER_SIZE;
-  }
-  memcpy(buffer, tags->kvm, tags->kvm_used);
-  return ENCODED_HEADER_SIZE + tags->kvm_used;
-}
-
-char *census_tag_set_encode(const census_tag_set *tags, char *buffer,
-                            size_t buf_size, size_t *print_buf_size,
-                            size_t *bin_buf_size) {
-  *print_buf_size =
-      tag_set_encode(&tags->tags[PROPAGATED_TAGS], buffer, buf_size);
-  if (*print_buf_size == 0) {
-    return NULL;
-  }
-  char *b_buffer = buffer + *print_buf_size;
-  *bin_buf_size = tag_set_encode(&tags->tags[PROPAGATED_BINARY_TAGS], b_buffer,
-                                 buf_size - *print_buf_size);
-  if (*bin_buf_size == 0) {
-    return NULL;
-  }
-  return b_buffer;
-}
-
-// Decode a tag set.
-static void tag_set_decode(struct tag_set *tags, const char *buffer,
-                           size_t size) {
-  uint8_t version = (uint8_t)(*buffer++);
-  uint8_t header_size = (uint8_t)(*buffer++);
-  uint8_t tag_header_size = (uint8_t)(*buffer++);
-  tags->ntags = tags->ntags_alloc = (int)(*buffer++);
-  if (tags->ntags == 0) {
-    tags->ntags_alloc = 0;
-    tags->kvm_size = 0;
-    tags->kvm_used = 0;
-    tags->kvm = NULL;
-    return;
-  }
-  if (header_size != ENCODED_HEADER_SIZE) {
-    GPR_ASSERT(version != ENCODED_VERSION);
-    GPR_ASSERT(ENCODED_HEADER_SIZE < header_size);
-    buffer += (header_size - ENCODED_HEADER_SIZE);
-  }
-  tags->kvm_used = size - header_size;
-  tags->kvm_size = tags->kvm_used + CENSUS_MAX_TAG_KV_LEN;
-  tags->kvm = gpr_malloc(tags->kvm_size);
-  if (tag_header_size != TAG_HEADER_SIZE) {
-    // something new in the tag information. I don't understand it, so
-    // don't copy it over.
-    GPR_ASSERT(version != ENCODED_VERSION);
-    GPR_ASSERT(tag_header_size > TAG_HEADER_SIZE);
-    char *kvp = tags->kvm;
-    for (int i = 0; i < tags->ntags; i++) {
-      memcpy(kvp, buffer, TAG_HEADER_SIZE);
-      kvp += header_size;
-      struct raw_tag raw;
-      buffer =
-          decode_tag(&raw, (char *)buffer, tag_header_size - TAG_HEADER_SIZE);
-      memcpy(kvp, raw.key, (size_t)raw.key_len + raw.value_len);
-      kvp += raw.key_len + raw.value_len;
-    }
-  } else {
-    memcpy(tags->kvm, buffer, tags->kvm_used);
-  }
-}
-
-census_tag_set *census_tag_set_decode(const char *buffer, size_t size,
-                                      const char *bin_buffer, size_t bin_size) {
-  census_tag_set *new_ts = gpr_malloc(sizeof(census_tag_set));
-  memset(&new_ts->tags[LOCAL_TAGS], 0, sizeof(struct tag_set));
-  if (buffer == NULL) {
-    memset(&new_ts->tags[PROPAGATED_TAGS], 0, sizeof(struct tag_set));
-  } else {
-    tag_set_decode(&new_ts->tags[PROPAGATED_TAGS], buffer, size);
-  }
-  if (bin_buffer == NULL) {
-    memset(&new_ts->tags[PROPAGATED_BINARY_TAGS], 0, sizeof(struct tag_set));
-  } else {
-    tag_set_decode(&new_ts->tags[PROPAGATED_BINARY_TAGS], bin_buffer, bin_size);
-  }
-  memset(&new_ts->status, 0, sizeof(new_ts->status));
-  new_ts->status.n_propagated_tags = new_ts->tags[PROPAGATED_TAGS].ntags;
-  new_ts->status.n_propagated_binary_tags =
-      new_ts->tags[PROPAGATED_BINARY_TAGS].ntags;
-  // TODO(aveitch): check that BINARY flag is correct for each type.
-  return new_ts;
-}
diff --git a/src/core/channel/channel_args.c b/src/core/channel/channel_args.c
index 487db11..0427ce0 100644
--- a/src/core/channel/channel_args.c
+++ b/src/core/channel/channel_args.c
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -35,6 +35,7 @@
 #include "src/core/channel/channel_args.h"
 #include "src/core/support/string.h"
 
+#include <grpc/census.h>
 #include <grpc/support/alloc.h>
 #include <grpc/support/string_util.h>
 #include <grpc/support/useful.h>
@@ -119,10 +120,10 @@
   if (a == NULL) return 0;
   for (i = 0; i < a->num_args; i++) {
     if (0 == strcmp(a->args[i].key, GRPC_ARG_ENABLE_CENSUS)) {
-      return a->args[i].value.integer != 0;
+      return a->args[i].value.integer != 0 && census_enabled();
     }
   }
-  return 0;
+  return census_enabled();
 }
 
 grpc_compression_algorithm grpc_channel_args_get_compression_algorithm(
diff --git a/src/core/channel/client_channel.c b/src/core/channel/client_channel.c
index a92a6ec..7176c01 100644
--- a/src/core/channel/client_channel.c
+++ b/src/core/channel/client_channel.c
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -135,7 +135,7 @@
 }
 
 static void on_lb_policy_state_changed(grpc_exec_ctx *exec_ctx, void *arg,
-                                       int iomgr_success) {
+                                       bool iomgr_success) {
   lb_policy_connectivity_watcher *w = arg;
 
   gpr_mu_lock(&w->chand->mu_config);
@@ -161,7 +161,7 @@
 }
 
 static void cc_on_config_changed(grpc_exec_ctx *exec_ctx, void *arg,
-                                 int iomgr_success) {
+                                 bool iomgr_success) {
   channel_data *chand = arg;
   grpc_lb_policy *lb_policy = NULL;
   grpc_lb_policy *old_lb_policy;
@@ -191,7 +191,8 @@
   old_lb_policy = chand->lb_policy;
   chand->lb_policy = lb_policy;
   if (lb_policy != NULL || chand->resolver == NULL /* disconnected */) {
-    grpc_exec_ctx_enqueue_list(exec_ctx, &chand->waiting_for_config_closures);
+    grpc_exec_ctx_enqueue_list(exec_ctx, &chand->waiting_for_config_closures,
+                               NULL);
   }
   if (lb_policy != NULL && chand->exit_idle_when_lb_policy_arrives) {
     GRPC_LB_POLICY_REF(lb_policy, "exit_idle");
@@ -249,7 +250,7 @@
   channel_data *chand = elem->channel_data;
   grpc_resolver *destroy_resolver = NULL;
 
-  grpc_exec_ctx_enqueue(exec_ctx, op->on_consumed, 1);
+  grpc_exec_ctx_enqueue(exec_ctx, op->on_consumed, true, NULL);
 
   GPR_ASSERT(op->set_accept_stream == NULL);
   if (op->bind_pollset != NULL) {
@@ -268,7 +269,7 @@
 
   if (op->send_ping != NULL) {
     if (chand->lb_policy == NULL) {
-      grpc_exec_ctx_enqueue(exec_ctx, op->send_ping, 0);
+      grpc_exec_ctx_enqueue(exec_ctx, op->send_ping, false, NULL);
     } else {
       grpc_lb_policy_ping_one(exec_ctx, chand->lb_policy, op->send_ping);
       op->bind_pollset = NULL;
@@ -310,15 +311,15 @@
                               grpc_connected_subchannel **connected_subchannel,
                               grpc_closure *on_ready);
 
-static void continue_picking(grpc_exec_ctx *exec_ctx, void *arg, int success) {
+static void continue_picking(grpc_exec_ctx *exec_ctx, void *arg, bool success) {
   continue_picking_args *cpa = arg;
   if (!success) {
-    grpc_exec_ctx_enqueue(exec_ctx, cpa->on_ready, 0);
+    grpc_exec_ctx_enqueue(exec_ctx, cpa->on_ready, false, NULL);
   } else if (cpa->connected_subchannel == NULL) {
     /* cancelled, do nothing */
   } else if (cc_pick_subchannel(exec_ctx, cpa->elem, cpa->initial_metadata,
                                 cpa->connected_subchannel, cpa->on_ready)) {
-    grpc_exec_ctx_enqueue(exec_ctx, cpa->on_ready, 1);
+    grpc_exec_ctx_enqueue(exec_ctx, cpa->on_ready, true, NULL);
   }
   gpr_free(cpa);
 }
@@ -346,7 +347,7 @@
       cpa = closure->cb_arg;
       if (cpa->connected_subchannel == connected_subchannel) {
         cpa->connected_subchannel = NULL;
-        grpc_exec_ctx_enqueue(exec_ctx, cpa->on_ready, 0);
+        grpc_exec_ctx_enqueue(exec_ctx, cpa->on_ready, false, NULL);
       }
     }
     gpr_mu_unlock(&chand->mu_config);
@@ -497,7 +498,7 @@
 } external_connectivity_watcher;
 
 static void on_external_watch_complete(grpc_exec_ctx *exec_ctx, void *arg,
-                                       int iomgr_success) {
+                                       bool iomgr_success) {
   external_connectivity_watcher *w = arg;
   grpc_closure *follow_up = w->on_complete;
   grpc_pollset_set_del_pollset(exec_ctx, &w->chand->interested_parties,
diff --git a/src/core/channel/client_uchannel.c b/src/core/channel/client_uchannel.c
index 2c0b07d..b1e7155 100644
--- a/src/core/channel/client_uchannel.c
+++ b/src/core/channel/client_uchannel.c
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -79,7 +79,7 @@
 typedef grpc_subchannel_call_holder call_data;
 
 static void monitor_subchannel(grpc_exec_ctx *exec_ctx, void *arg,
-                               int iomgr_success) {
+                               bool iomgr_success) {
   channel_data *chand = arg;
   grpc_connectivity_state_set(exec_ctx, &chand->state_tracker,
                               chand->subchannel_connectivity,
@@ -105,7 +105,7 @@
                                    grpc_transport_op *op) {
   channel_data *chand = elem->channel_data;
 
-  grpc_exec_ctx_enqueue(exec_ctx, op->on_consumed, 1);
+  grpc_exec_ctx_enqueue(exec_ctx, op->on_consumed, true, NULL);
 
   GPR_ASSERT(op->set_accept_stream == NULL);
   GPR_ASSERT(op->bind_pollset == NULL);
diff --git a/src/core/channel/compress_filter.c b/src/core/channel/compress_filter.c
index 3de1ef8..3e7ca08 100644
--- a/src/core/channel/compress_filter.c
+++ b/src/core/channel/compress_filter.c
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -153,7 +153,7 @@
 static void continue_send_message(grpc_exec_ctx *exec_ctx,
                                   grpc_call_element *elem);
 
-static void send_done(grpc_exec_ctx *exec_ctx, void *elemp, int success) {
+static void send_done(grpc_exec_ctx *exec_ctx, void *elemp, bool success) {
   grpc_call_element *elem = elemp;
   call_data *calld = elem->call_data;
   gpr_slice_buffer_reset_and_unref(&calld->slices);
@@ -183,7 +183,7 @@
   grpc_call_next_op(exec_ctx, elem, &calld->send_op);
 }
 
-static void got_slice(grpc_exec_ctx *exec_ctx, void *elemp, int success) {
+static void got_slice(grpc_exec_ctx *exec_ctx, void *elemp, bool success) {
   grpc_call_element *elem = elemp;
   call_data *calld = elem->call_data;
   gpr_slice_buffer_add(&calld->slices, calld->incoming_slice);
diff --git a/src/core/channel/http_client_filter.c b/src/core/channel/http_client_filter.c
index 65cfb77..1aa2720 100644
--- a/src/core/channel/http_client_filter.c
+++ b/src/core/channel/http_client_filter.c
@@ -1,5 +1,5 @@
 /*
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -80,7 +80,7 @@
   return md;
 }
 
-static void hc_on_recv(grpc_exec_ctx *exec_ctx, void *user_data, int success) {
+static void hc_on_recv(grpc_exec_ctx *exec_ctx, void *user_data, bool success) {
   grpc_call_element *elem = user_data;
   call_data *calld = elem->call_data;
   client_recv_filter_args a;
@@ -127,8 +127,8 @@
   if (op->recv_initial_metadata != NULL) {
     /* substitute our callback for the higher callback */
     calld->recv_initial_metadata = op->recv_initial_metadata;
-    calld->on_done_recv = op->on_complete;
-    op->on_complete = &calld->hc_on_recv;
+    calld->on_done_recv = op->recv_initial_metadata_ready;
+    op->recv_initial_metadata_ready = &calld->hc_on_recv;
   }
 }
 
diff --git a/src/core/channel/http_server_filter.c b/src/core/channel/http_server_filter.c
index a10b105..370f8db 100644
--- a/src/core/channel/http_server_filter.c
+++ b/src/core/channel/http_server_filter.c
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -131,7 +131,7 @@
   }
 }
 
-static void hs_on_recv(grpc_exec_ctx *exec_ctx, void *user_data, int success) {
+static void hs_on_recv(grpc_exec_ctx *exec_ctx, void *user_data, bool success) {
   grpc_call_element *elem = user_data;
   call_data *calld = elem->call_data;
   if (success) {
@@ -186,8 +186,8 @@
   if (op->recv_initial_metadata) {
     /* substitute our callback for the higher callback */
     calld->recv_initial_metadata = op->recv_initial_metadata;
-    calld->on_done_recv = op->on_complete;
-    op->on_complete = &calld->hs_on_recv;
+    calld->on_done_recv = op->recv_initial_metadata_ready;
+    op->recv_initial_metadata_ready = &calld->hs_on_recv;
   }
 }
 
diff --git a/src/core/channel/subchannel_call_holder.c b/src/core/channel/subchannel_call_holder.c
index 1e8f4ba..81297c8 100644
--- a/src/core/channel/subchannel_call_holder.c
+++ b/src/core/channel/subchannel_call_holder.c
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -43,9 +43,9 @@
 #define CANCELLED_CALL ((grpc_subchannel_call *)1)
 
 static void subchannel_ready(grpc_exec_ctx *exec_ctx, void *holder,
-                             int success);
+                             bool success);
 static void retry_ops(grpc_exec_ctx *exec_ctx, void *retry_ops_args,
-                      int success);
+                      bool success);
 
 static void add_waiting_locked(grpc_subchannel_call_holder *holder,
                                grpc_transport_stream_op *op);
@@ -166,7 +166,7 @@
   GPR_TIMER_END("grpc_subchannel_call_holder_perform_op", 0);
 }
 
-static void subchannel_ready(grpc_exec_ctx *exec_ctx, void *arg, int success) {
+static void subchannel_ready(grpc_exec_ctx *exec_ctx, void *arg, bool success) {
   grpc_subchannel_call_holder *holder = arg;
   grpc_subchannel_call *call;
   gpr_mu_lock(&holder->mu);
@@ -209,10 +209,11 @@
   holder->waiting_ops_count = 0;
   holder->waiting_ops_capacity = 0;
   GRPC_SUBCHANNEL_CALL_REF(a->call, "retry_ops");
-  grpc_exec_ctx_enqueue(exec_ctx, grpc_closure_create(retry_ops, a), 1);
+  grpc_exec_ctx_enqueue(exec_ctx, grpc_closure_create(retry_ops, a), true,
+                        NULL);
 }
 
-static void retry_ops(grpc_exec_ctx *exec_ctx, void *args, int success) {
+static void retry_ops(grpc_exec_ctx *exec_ctx, void *args, bool success) {
   retry_ops_args *a = args;
   size_t i;
   for (i = 0; i < a->nops; i++) {
@@ -240,9 +241,8 @@
                         grpc_subchannel_call_holder *holder) {
   size_t i;
   for (i = 0; i < holder->waiting_ops_count; i++) {
-    grpc_exec_ctx_enqueue(exec_ctx, holder->waiting_ops[i].on_complete, 0);
-    grpc_exec_ctx_enqueue(exec_ctx, holder->waiting_ops[i].recv_message_ready,
-                          0);
+    grpc_transport_stream_op_finish_with_failure(exec_ctx,
+                                                 &holder->waiting_ops[i]);
   }
   holder->waiting_ops_count = 0;
 }
diff --git a/src/core/client_config/lb_policies/pick_first.c b/src/core/client_config/lb_policies/pick_first.c
index 5b10600..459bbeb 100644
--- a/src/core/client_config/lb_policies/pick_first.c
+++ b/src/core/client_config/lb_policies/pick_first.c
@@ -121,7 +121,7 @@
     *pp->target = NULL;
     grpc_pollset_set_del_pollset(exec_ctx, &p->base.interested_parties,
                                  pp->pollset);
-    grpc_exec_ctx_enqueue(exec_ctx, pp->on_complete, 1);
+    grpc_exec_ctx_enqueue(exec_ctx, pp->on_complete, true, NULL);
     gpr_free(pp);
     pp = next;
   }
@@ -140,7 +140,7 @@
       grpc_pollset_set_del_pollset(exec_ctx, &p->base.interested_parties,
                                    pp->pollset);
       *target = NULL;
-      grpc_exec_ctx_enqueue(exec_ctx, pp->on_complete, 0);
+      grpc_exec_ctx_enqueue(exec_ctx, pp->on_complete, false, NULL);
       gpr_free(pp);
     } else {
       pp->next = p->pending_picks;
@@ -209,7 +209,7 @@
 }
 
 static void destroy_subchannels(grpc_exec_ctx *exec_ctx, void *arg,
-                                int iomgr_success) {
+                                bool iomgr_success) {
   pick_first_lb_policy *p = arg;
   size_t i;
   size_t num_subchannels = p->num_subchannels;
@@ -230,7 +230,7 @@
 }
 
 static void pf_connectivity_changed(grpc_exec_ctx *exec_ctx, void *arg,
-                                    int iomgr_success) {
+                                    bool iomgr_success) {
   pick_first_lb_policy *p = arg;
   grpc_subchannel *selected_subchannel;
   pending_pick *pp;
@@ -272,15 +272,15 @@
         /* drop the pick list: we are connected now */
         GRPC_LB_POLICY_WEAK_REF(&p->base, "destroy_subchannels");
         gpr_atm_rel_store(&p->selected, (gpr_atm)selected);
-        grpc_exec_ctx_enqueue(exec_ctx,
-                              grpc_closure_create(destroy_subchannels, p), 1);
+        grpc_exec_ctx_enqueue(
+            exec_ctx, grpc_closure_create(destroy_subchannels, p), true, NULL);
         /* update any calls that were waiting for a pick */
         while ((pp = p->pending_picks)) {
           p->pending_picks = pp->next;
           *pp->target = selected;
           grpc_pollset_set_del_pollset(exec_ctx, &p->base.interested_parties,
                                        pp->pollset);
-          grpc_exec_ctx_enqueue(exec_ctx, pp->on_complete, 1);
+          grpc_exec_ctx_enqueue(exec_ctx, pp->on_complete, true, NULL);
           gpr_free(pp);
         }
         grpc_connected_subchannel_notify_on_state_change(
@@ -327,7 +327,7 @@
           while ((pp = p->pending_picks)) {
             p->pending_picks = pp->next;
             *pp->target = NULL;
-            grpc_exec_ctx_enqueue(exec_ctx, pp->on_complete, 1);
+            grpc_exec_ctx_enqueue(exec_ctx, pp->on_complete, true, NULL);
             gpr_free(pp);
           }
           GRPC_LB_POLICY_WEAK_UNREF(exec_ctx, &p->base,
@@ -374,7 +374,7 @@
   if (selected) {
     grpc_connected_subchannel_ping(exec_ctx, selected, closure);
   } else {
-    grpc_exec_ctx_enqueue(exec_ctx, closure, 0);
+    grpc_exec_ctx_enqueue(exec_ctx, closure, false, NULL);
   }
 }
 
diff --git a/src/core/client_config/lb_policies/round_robin.c b/src/core/client_config/lb_policies/round_robin.c
index d487456..b1171c4 100644
--- a/src/core/client_config/lb_policies/round_robin.c
+++ b/src/core/client_config/lb_policies/round_robin.c
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -237,7 +237,7 @@
   while ((pp = p->pending_picks)) {
     p->pending_picks = pp->next;
     *pp->target = NULL;
-    grpc_exec_ctx_enqueue(exec_ctx, pp->on_complete, 0);
+    grpc_exec_ctx_enqueue(exec_ctx, pp->on_complete, false, NULL);
     gpr_free(pp);
   }
   grpc_connectivity_state_set(exec_ctx, &p->state_tracker,
@@ -263,7 +263,7 @@
       grpc_pollset_set_del_pollset(exec_ctx, &p->base.interested_parties,
                                    pp->pollset);
       *target = NULL;
-      grpc_exec_ctx_enqueue(exec_ctx, pp->on_complete, 0);
+      grpc_exec_ctx_enqueue(exec_ctx, pp->on_complete, false, NULL);
       gpr_free(pp);
     } else {
       pp->next = p->pending_picks;
@@ -336,7 +336,7 @@
 }
 
 static void rr_connectivity_changed(grpc_exec_ctx *exec_ctx, void *arg,
-                                    int iomgr_success) {
+                                    bool iomgr_success) {
   subchannel_data *sd = arg;
   round_robin_lb_policy *p = sd->policy;
   pending_pick *pp;
@@ -376,7 +376,7 @@
           }
           grpc_pollset_set_del_pollset(exec_ctx, &p->base.interested_parties,
                                        pp->pollset);
-          grpc_exec_ctx_enqueue(exec_ctx, pp->on_complete, 1);
+          grpc_exec_ctx_enqueue(exec_ctx, pp->on_complete, true, NULL);
           gpr_free(pp);
         }
         grpc_subchannel_notify_on_state_change(
@@ -428,7 +428,7 @@
           while ((pp = p->pending_picks)) {
             p->pending_picks = pp->next;
             *pp->target = NULL;
-            grpc_exec_ctx_enqueue(exec_ctx, pp->on_complete, 1);
+            grpc_exec_ctx_enqueue(exec_ctx, pp->on_complete, true, NULL);
             gpr_free(pp);
           }
         } else {
@@ -479,7 +479,7 @@
     grpc_connected_subchannel_ping(exec_ctx, target, closure);
   } else {
     gpr_mu_unlock(&p->mu);
-    grpc_exec_ctx_enqueue(exec_ctx, closure, 0);
+    grpc_exec_ctx_enqueue(exec_ctx, closure, false, NULL);
   }
 }
 
diff --git a/src/core/client_config/resolvers/dns_resolver.c b/src/core/client_config/resolvers/dns_resolver.c
index 28ca30b..376b6b3 100644
--- a/src/core/client_config/resolvers/dns_resolver.c
+++ b/src/core/client_config/resolvers/dns_resolver.c
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -93,7 +93,7 @@
   gpr_mu_lock(&r->mu);
   if (r->next_completion != NULL) {
     *r->target_config = NULL;
-    grpc_exec_ctx_enqueue(exec_ctx, r->next_completion, 1);
+    grpc_exec_ctx_enqueue(exec_ctx, r->next_completion, true, NULL);
     r->next_completion = NULL;
   }
   gpr_mu_unlock(&r->mu);
@@ -182,7 +182,7 @@
     if (r->resolved_config) {
       grpc_client_config_ref(r->resolved_config);
     }
-    grpc_exec_ctx_enqueue(exec_ctx, r->next_completion, 1);
+    grpc_exec_ctx_enqueue(exec_ctx, r->next_completion, true, NULL);
     r->next_completion = NULL;
     r->published_version = r->resolved_version;
   }
diff --git a/src/core/client_config/resolvers/sockaddr_resolver.c b/src/core/client_config/resolvers/sockaddr_resolver.c
index 6343259..68910ad 100644
--- a/src/core/client_config/resolvers/sockaddr_resolver.c
+++ b/src/core/client_config/resolvers/sockaddr_resolver.c
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -98,7 +98,7 @@
   gpr_mu_lock(&r->mu);
   if (r->next_completion != NULL) {
     *r->target_config = NULL;
-    grpc_exec_ctx_enqueue(exec_ctx, r->next_completion, 1);
+    grpc_exec_ctx_enqueue(exec_ctx, r->next_completion, true, NULL);
     r->next_completion = NULL;
   }
   gpr_mu_unlock(&r->mu);
@@ -153,7 +153,7 @@
     GRPC_LB_POLICY_UNREF(exec_ctx, lb_policy, "sockaddr");
     r->published = 1;
     *r->target_config = cfg;
-    grpc_exec_ctx_enqueue(exec_ctx, r->next_completion, 1);
+    grpc_exec_ctx_enqueue(exec_ctx, r->next_completion, true, NULL);
     r->next_completion = NULL;
   }
 }
diff --git a/src/core/client_config/resolvers/zookeeper_resolver.c b/src/core/client_config/resolvers/zookeeper_resolver.c
index 4924ca7..166738e 100644
--- a/src/core/client_config/resolvers/zookeeper_resolver.c
+++ b/src/core/client_config/resolvers/zookeeper_resolver.c
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -420,7 +420,7 @@
     if (r->resolved_config != NULL) {
       grpc_client_config_ref(r->resolved_config);
     }
-    grpc_exec_ctx_enqueue(exec_ctx, r->next_completion, 1);
+    grpc_exec_ctx_enqueue(exec_ctx, r->next_completion, true, NULL);
     r->next_completion = NULL;
     r->published_version = r->resolved_version;
   }
diff --git a/src/core/client_config/subchannel.c b/src/core/client_config/subchannel.c
index 748eef9..0a996a1 100644
--- a/src/core/client_config/subchannel.c
+++ b/src/core/client_config/subchannel.c
@@ -145,7 +145,7 @@
 
 static gpr_timespec compute_connect_deadline(grpc_subchannel *c);
 static void subchannel_connected(grpc_exec_ctx *exec_ctx, void *subchannel,
-                                 int iomgr_success);
+                                 bool iomgr_success);
 
 #ifdef GRPC_STREAM_REFCOUNT_DEBUG
 #define REF_REASON reason
@@ -175,7 +175,7 @@
  */
 
 static void connection_destroy(grpc_exec_ctx *exec_ctx, void *arg,
-                               int success) {
+                               bool success) {
   grpc_connected_subchannel *c = arg;
   grpc_channel_stack_destroy(exec_ctx, CHANNEL_STACK_FROM_CONNECTION(c));
   gpr_free(c);
@@ -198,7 +198,7 @@
  */
 
 static void subchannel_destroy(grpc_exec_ctx *exec_ctx, void *arg,
-                               int success) {
+                               bool success) {
   grpc_subchannel *c = arg;
   gpr_free((void *)c->filters);
   grpc_channel_args_destroy(c->args);
@@ -268,7 +268,7 @@
   old_refs = ref_mutate(c, -(gpr_atm)1, 1 REF_MUTATE_PURPOSE("WEAK_UNREF"));
   if (old_refs == 1) {
     grpc_exec_ctx_enqueue(exec_ctx, grpc_closure_create(subchannel_destroy, c),
-                          1);
+                          true, NULL);
   }
 }
 
@@ -284,9 +284,13 @@
   c->connector = connector;
   grpc_connector_ref(c->connector);
   c->num_filters = args->filter_count;
-  c->filters = gpr_malloc(sizeof(grpc_channel_filter *) * c->num_filters);
-  memcpy((void *)c->filters, args->filters,
-         sizeof(grpc_channel_filter *) * c->num_filters);
+  if (c->num_filters > 0) {
+    c->filters = gpr_malloc(sizeof(grpc_channel_filter *) * c->num_filters);
+    memcpy((void *)c->filters, args->filters,
+           sizeof(grpc_channel_filter *) * c->num_filters);
+  } else {
+    c->filters = NULL;
+  }
   c->addr = gpr_malloc(args->addr_len);
   memcpy(c->addr, args->addr, args->addr_len);
   grpc_pollset_set_init(&c->pollset_set);
@@ -337,7 +341,7 @@
 }
 
 static void on_external_state_watcher_done(grpc_exec_ctx *exec_ctx, void *arg,
-                                           int success) {
+                                           bool success) {
   external_state_watcher *w = arg;
   grpc_closure *follow_up = w->notify;
   if (w->pollset_set != NULL) {
@@ -409,7 +413,7 @@
 }
 
 static void subchannel_on_child_state_changed(grpc_exec_ctx *exec_ctx, void *p,
-                                              int iomgr_success) {
+                                              bool iomgr_success) {
   state_watcher *sw = p;
   grpc_subchannel *c = sw->subchannel;
   gpr_mu *mu = &c->mu;
@@ -483,7 +487,9 @@
   /* build final filter list */
   num_filters = c->num_filters + c->connecting_result.num_filters + 1;
   filters = gpr_malloc(sizeof(*filters) * num_filters);
-  memcpy((void *)filters, c->filters, sizeof(*filters) * c->num_filters);
+  if (c->num_filters > 0) {
+    memcpy((void *)filters, c->filters, sizeof(*filters) * c->num_filters);
+  }
   memcpy((void *)(filters + c->num_filters), c->connecting_result.filters,
          sizeof(*filters) * c->connecting_result.num_filters);
   filters[num_filters - 1] = &grpc_connected_channel_filter;
@@ -588,7 +594,7 @@
       gpr_time_add(c->next_attempt, gpr_time_from_millis(jitter, GPR_TIMESPAN));
 }
 
-static void on_alarm(grpc_exec_ctx *exec_ctx, void *arg, int iomgr_success) {
+static void on_alarm(grpc_exec_ctx *exec_ctx, void *arg, bool iomgr_success) {
   grpc_subchannel *c = arg;
   gpr_mu_lock(&c->mu);
   c->have_alarm = 0;
@@ -605,7 +611,7 @@
 }
 
 static void subchannel_connected(grpc_exec_ctx *exec_ctx, void *arg,
-                                 int iomgr_success) {
+                                 bool iomgr_success) {
   grpc_subchannel *c = arg;
 
   if (c->connecting_result.transport != NULL) {
@@ -641,7 +647,7 @@
  */
 
 static void subchannel_call_destroy(grpc_exec_ctx *exec_ctx, void *call,
-                                    int success) {
+                                    bool success) {
   grpc_subchannel_call *c = call;
   GPR_TIMER_BEGIN("grpc_subchannel_call_unref.destroy", 0);
   grpc_call_stack_destroy(exec_ctx, SUBCHANNEL_CALL_TO_CALL_STACK(c));
diff --git a/src/core/httpcli/httpcli.c b/src/core/httpcli/httpcli.c
index b5cd8d8..71237bb 100644
--- a/src/core/httpcli/httpcli.c
+++ b/src/core/httpcli/httpcli.c
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -114,13 +114,13 @@
   gpr_free(req);
 }
 
-static void on_read(grpc_exec_ctx *exec_ctx, void *user_data, int success);
+static void on_read(grpc_exec_ctx *exec_ctx, void *user_data, bool success);
 
 static void do_read(grpc_exec_ctx *exec_ctx, internal_request *req) {
   grpc_endpoint_read(exec_ctx, req->ep, &req->incoming, &req->on_read);
 }
 
-static void on_read(grpc_exec_ctx *exec_ctx, void *user_data, int success) {
+static void on_read(grpc_exec_ctx *exec_ctx, void *user_data, bool success) {
   internal_request *req = user_data;
   size_t i;
 
@@ -147,7 +147,7 @@
   do_read(exec_ctx, req);
 }
 
-static void done_write(grpc_exec_ctx *exec_ctx, void *arg, int success) {
+static void done_write(grpc_exec_ctx *exec_ctx, void *arg, bool success) {
   internal_request *req = arg;
   if (success) {
     on_written(exec_ctx, req);
@@ -175,7 +175,7 @@
   start_write(exec_ctx, req);
 }
 
-static void on_connected(grpc_exec_ctx *exec_ctx, void *arg, int success) {
+static void on_connected(grpc_exec_ctx *exec_ctx, void *arg, bool success) {
   internal_request *req = arg;
 
   if (!req->ep) {
diff --git a/src/core/iomgr/closure.c b/src/core/iomgr/closure.c
index 7646a88..3a96f73 100644
--- a/src/core/iomgr/closure.c
+++ b/src/core/iomgr/closure.c
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -43,7 +43,7 @@
 }
 
 void grpc_closure_list_add(grpc_closure_list *closure_list,
-                           grpc_closure *closure, int success) {
+                           grpc_closure *closure, bool success) {
   if (closure == NULL) return;
   closure->final_data = (success != 0);
   if (closure_list->head == NULL) {
@@ -54,7 +54,7 @@
   closure_list->tail = closure;
 }
 
-int grpc_closure_list_empty(grpc_closure_list closure_list) {
+bool grpc_closure_list_empty(grpc_closure_list closure_list) {
   return closure_list.head == NULL;
 }
 
@@ -77,7 +77,7 @@
   grpc_closure wrapper;
 } wrapped_closure;
 
-static void closure_wrapper(grpc_exec_ctx *exec_ctx, void *arg, int success) {
+static void closure_wrapper(grpc_exec_ctx *exec_ctx, void *arg, bool success) {
   wrapped_closure *wc = arg;
   grpc_iomgr_cb_func cb = wc->cb;
   void *cb_arg = wc->cb_arg;
diff --git a/src/core/iomgr/closure.h b/src/core/iomgr/closure.h
index 98ef91e..ea96c19 100644
--- a/src/core/iomgr/closure.h
+++ b/src/core/iomgr/closure.h
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -35,6 +35,7 @@
 #define GRPC_INTERNAL_CORE_IOMGR_CLOSURE_H
 
 #include <grpc/support/port_platform.h>
+#include <stdbool.h>
 
 struct grpc_closure;
 typedef struct grpc_closure grpc_closure;
@@ -54,7 +55,7 @@
  * \param success An indication on the state of the iomgr. On false, cleanup
  * actions should be taken (eg, shutdown). */
 typedef void (*grpc_iomgr_cb_func)(grpc_exec_ctx *exec_ctx, void *arg,
-                                   int success);
+                                   bool success);
 
 /** A closure over a grpc_iomgr_cb_func. */
 struct grpc_closure {
@@ -83,13 +84,13 @@
 /** add \a closure to the end of \a list and set \a closure's success to \a
  * success */
 void grpc_closure_list_add(grpc_closure_list *list, grpc_closure *closure,
-                           int success);
+                           bool success);
 
 /** append all closures from \a src to \a dst and empty \a src. */
 void grpc_closure_list_move(grpc_closure_list *src, grpc_closure_list *dst);
 
 /** return whether \a list is empty. */
-int grpc_closure_list_empty(grpc_closure_list list);
+bool grpc_closure_list_empty(grpc_closure_list list);
 
 /** return the next pointer for a queued closure list */
 grpc_closure *grpc_closure_next(grpc_closure *closure);
diff --git a/src/core/iomgr/exec_ctx.c b/src/core/iomgr/exec_ctx.c
index 6059a60..1fd79f6 100644
--- a/src/core/iomgr/exec_ctx.c
+++ b/src/core/iomgr/exec_ctx.c
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -37,16 +37,16 @@
 
 #include "src/core/profiling/timers.h"
 
-int grpc_exec_ctx_flush(grpc_exec_ctx *exec_ctx) {
-  int did_something = 0;
+bool grpc_exec_ctx_flush(grpc_exec_ctx *exec_ctx) {
+  bool did_something = 0;
   GPR_TIMER_BEGIN("grpc_exec_ctx_flush", 0);
   while (!grpc_closure_list_empty(exec_ctx->closure_list)) {
     grpc_closure *c = exec_ctx->closure_list.head;
     exec_ctx->closure_list.head = exec_ctx->closure_list.tail = NULL;
     while (c != NULL) {
-      int success = (int)(c->final_data & 1);
+      bool success = (bool)(c->final_data & 1);
       grpc_closure *next = (grpc_closure *)(c->final_data & ~(uintptr_t)1);
-      did_something++;
+      did_something = true;
       GPR_TIMER_BEGIN("grpc_exec_ctx_flush.cb", 0);
       c->cb(exec_ctx, c->cb_arg, success);
       GPR_TIMER_END("grpc_exec_ctx_flush.cb", 0);
@@ -62,11 +62,15 @@
 }
 
 void grpc_exec_ctx_enqueue(grpc_exec_ctx *exec_ctx, grpc_closure *closure,
-                           int success) {
+                           bool success,
+                           grpc_workqueue *offload_target_or_null) {
+  GPR_ASSERT(offload_target_or_null == NULL);
   grpc_closure_list_add(&exec_ctx->closure_list, closure, success);
 }
 
 void grpc_exec_ctx_enqueue_list(grpc_exec_ctx *exec_ctx,
-                                grpc_closure_list *list) {
+                                grpc_closure_list *list,
+                                grpc_workqueue *offload_target_or_null) {
+  GPR_ASSERT(offload_target_or_null == NULL);
   grpc_closure_list_move(list, &exec_ctx->closure_list);
 }
diff --git a/src/core/iomgr/exec_ctx.h b/src/core/iomgr/exec_ctx.h
index 43df488..9a9b2e5 100644
--- a/src/core/iomgr/exec_ctx.h
+++ b/src/core/iomgr/exec_ctx.h
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -57,22 +57,29 @@
   grpc_closure_list closure_list;
 };
 
+/** A workqueue represents a list of work to be executed asynchronously.
+    Forward declared here to avoid a circular dependency with workqueue.h. */
+struct grpc_workqueue;
+typedef struct grpc_workqueue grpc_workqueue;
+
 #define GRPC_EXEC_CTX_INIT \
   { GRPC_CLOSURE_LIST_INIT }
 
 /** Flush any work that has been enqueued onto this grpc_exec_ctx.
  *  Caller must guarantee that no interfering locks are held.
- *  Returns 1 if work was performed, 0 otherwise. */
-int grpc_exec_ctx_flush(grpc_exec_ctx *exec_ctx);
+ *  Returns true if work was performed, false otherwise. */
+bool grpc_exec_ctx_flush(grpc_exec_ctx *exec_ctx);
 /** Finish any pending work for a grpc_exec_ctx. Must be called before
  *  the instance is destroyed, or work may be lost. */
 void grpc_exec_ctx_finish(grpc_exec_ctx *exec_ctx);
 /** Add a closure to be executed at the next flush/finish point */
 void grpc_exec_ctx_enqueue(grpc_exec_ctx *exec_ctx, grpc_closure *closure,
-                           int success);
+                           bool success,
+                           grpc_workqueue *offload_target_or_null);
 /** Add a list of closures to be executed at the next flush/finish point.
  *  Leaves \a list empty. */
 void grpc_exec_ctx_enqueue_list(grpc_exec_ctx *exec_ctx,
-                                grpc_closure_list *list);
+                                grpc_closure_list *list,
+                                grpc_workqueue *offload_target_or_null);
 
 #endif
diff --git a/src/core/iomgr/executor.c b/src/core/iomgr/executor.c
index 00c68f7..f22d8f3 100644
--- a/src/core/iomgr/executor.c
+++ b/src/core/iomgr/executor.c
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -77,7 +77,7 @@
       gpr_mu_unlock(&g_executor.mu);
       break;
     } else {
-      grpc_exec_ctx_enqueue_list(&exec_ctx, &g_executor.closures);
+      grpc_exec_ctx_enqueue_list(&exec_ctx, &g_executor.closures, NULL);
     }
     gpr_mu_unlock(&g_executor.mu);
     grpc_exec_ctx_flush(&exec_ctx);
@@ -112,7 +112,7 @@
   g_executor.pending_join = 1;
 }
 
-void grpc_executor_enqueue(grpc_closure *closure, int success) {
+void grpc_executor_enqueue(grpc_closure *closure, bool success) {
   gpr_mu_lock(&g_executor.mu);
   if (g_executor.shutting_down == 0) {
     grpc_closure_list_add(&g_executor.closures, closure, success);
@@ -133,7 +133,7 @@
    * list below because we aren't accepting new work */
 
   /* Execute pending callbacks, some may be performing cleanups */
-  grpc_exec_ctx_enqueue_list(&exec_ctx, &g_executor.closures);
+  grpc_exec_ctx_enqueue_list(&exec_ctx, &g_executor.closures, NULL);
   grpc_exec_ctx_finish(&exec_ctx);
   GPR_ASSERT(grpc_closure_list_empty(g_executor.closures));
   if (pending_join) {
diff --git a/src/core/iomgr/executor.h b/src/core/iomgr/executor.h
index 6da446a..aac057d 100644
--- a/src/core/iomgr/executor.h
+++ b/src/core/iomgr/executor.h
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -45,7 +45,7 @@
 
 /** Enqueue \a closure for its eventual execution of \a f(arg) on a separate
  * thread */
-void grpc_executor_enqueue(grpc_closure *closure, int success);
+void grpc_executor_enqueue(grpc_closure *closure, bool success);
 
 /** Shutdown the executor, running all pending work as part of the call */
 void grpc_executor_shutdown();
diff --git a/src/core/iomgr/fd_posix.c b/src/core/iomgr/fd_posix.c
index 89c938b..85eadd7 100644
--- a/src/core/iomgr/fd_posix.c
+++ b/src/core/iomgr/fd_posix.c
@@ -218,7 +218,7 @@
   } else {
     grpc_remove_fd_from_all_epoll_sets(fd->fd);
   }
-  grpc_exec_ctx_enqueue(exec_ctx, fd->on_done_closure, 1);
+  grpc_exec_ctx_enqueue(exec_ctx, fd->on_done_closure, true, NULL);
 }
 
 int grpc_fd_wrapped_fd(grpc_fd *fd) {
@@ -273,7 +273,7 @@
   } else if (*st == CLOSURE_READY) {
     /* already ready ==> queue the closure to run immediately */
     *st = CLOSURE_NOT_READY;
-    grpc_exec_ctx_enqueue(exec_ctx, closure, !fd->shutdown);
+    grpc_exec_ctx_enqueue(exec_ctx, closure, !fd->shutdown, NULL);
     maybe_wake_one_watcher_locked(fd);
   } else {
     /* upcallptr was set to a different closure.  This is an error! */
@@ -296,7 +296,7 @@
     return 0;
   } else {
     /* waiting ==> queue closure */
-    grpc_exec_ctx_enqueue(exec_ctx, *st, !fd->shutdown);
+    grpc_exec_ctx_enqueue(exec_ctx, *st, !fd->shutdown, NULL);
     *st = CLOSURE_NOT_READY;
     return 1;
   }
diff --git a/src/core/iomgr/iocp_windows.c b/src/core/iomgr/iocp_windows.c
index d3868ce..759340e 100644
--- a/src/core/iomgr/iocp_windows.c
+++ b/src/core/iomgr/iocp_windows.c
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -57,7 +57,7 @@
 static DWORD deadline_to_millis_timeout(gpr_timespec deadline,
                                         gpr_timespec now) {
   gpr_timespec timeout;
-  static const int max_spin_polling_us = 10;
+  static const int64_t max_spin_polling_us = 10;
   if (gpr_time_cmp(deadline, gpr_inf_future(deadline.clock_type)) == 0) {
     return INFINITE;
   }
@@ -67,7 +67,7 @@
     return 0;
   }
   timeout = gpr_time_sub(deadline, now);
-  return gpr_time_to_millis(gpr_time_add(
+  return (DWORD)gpr_time_to_millis(gpr_time_add(
       timeout, gpr_time_from_nanos(GPR_NS_PER_MS - 1, GPR_TIMESPAN)));
 }
 
@@ -120,7 +120,7 @@
     info->has_pending_iocp = 1;
   }
   gpr_mu_unlock(&socket->state_mu);
-  grpc_exec_ctx_enqueue(exec_ctx, closure, 1);
+  grpc_exec_ctx_enqueue(exec_ctx, closure, true, NULL);
 }
 
 void grpc_iocp_init(void) {
@@ -179,13 +179,11 @@
 static void socket_notify_on_iocp(grpc_exec_ctx *exec_ctx,
                                   grpc_winsocket *socket, grpc_closure *closure,
                                   grpc_winsocket_callback_info *info) {
-  int run_now = 0;
   GPR_ASSERT(info->closure == NULL);
   gpr_mu_lock(&socket->state_mu);
   if (info->has_pending_iocp) {
-    run_now = 1;
     info->has_pending_iocp = 0;
-    grpc_exec_ctx_enqueue(exec_ctx, closure, 1);
+    grpc_exec_ctx_enqueue(exec_ctx, closure, true, NULL);
   } else {
     info->closure = closure;
   }
diff --git a/src/core/iomgr/pollset_multipoller_with_epoll.c b/src/core/iomgr/pollset_multipoller_with_epoll.c
index d117485..4acae2b 100644
--- a/src/core/iomgr/pollset_multipoller_with_epoll.c
+++ b/src/core/iomgr/pollset_multipoller_with_epoll.c
@@ -141,7 +141,7 @@
 }
 
 static void perform_delayed_add(grpc_exec_ctx *exec_ctx, void *arg,
-                                int iomgr_status) {
+                                bool iomgr_status) {
   delayed_add *da = arg;
 
   if (!grpc_fd_is_orphaned(da->fd)) {
@@ -154,7 +154,7 @@
     /* We don't care about this pollset anymore. */
     if (da->pollset->in_flight_cbs == 0 && !da->pollset->called_shutdown) {
       da->pollset->called_shutdown = 1;
-      grpc_exec_ctx_enqueue(exec_ctx, da->pollset->shutdown_done, 1);
+      grpc_exec_ctx_enqueue(exec_ctx, da->pollset->shutdown_done, true, NULL);
     }
   }
   gpr_mu_unlock(&da->pollset->mu);
@@ -178,7 +178,7 @@
     GRPC_FD_REF(fd, "delayed_add");
     grpc_closure_init(&da->closure, perform_delayed_add, da);
     pollset->in_flight_cbs++;
-    grpc_exec_ctx_enqueue(exec_ctx, &da->closure, 1);
+    grpc_exec_ctx_enqueue(exec_ctx, &da->closure, true, NULL);
   }
 }
 
diff --git a/src/core/iomgr/pollset_posix.c b/src/core/iomgr/pollset_posix.c
index c325b63..19ee665 100644
--- a/src/core/iomgr/pollset_posix.c
+++ b/src/core/iomgr/pollset_posix.c
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -243,7 +243,7 @@
 static void finish_shutdown(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset) {
   GPR_ASSERT(grpc_closure_list_empty(pollset->idle_jobs));
   pollset->vtable->finish_shutdown(pollset);
-  grpc_exec_ctx_enqueue(exec_ctx, pollset->shutdown_done, 1);
+  grpc_exec_ctx_enqueue(exec_ctx, pollset->shutdown_done, true, NULL);
 }
 
 void grpc_pollset_work(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset,
@@ -271,7 +271,7 @@
   if (!grpc_pollset_has_workers(pollset) &&
       !grpc_closure_list_empty(pollset->idle_jobs)) {
     GPR_TIMER_MARK("grpc_pollset_work.idle_jobs", 0);
-    grpc_exec_ctx_enqueue_list(exec_ctx, &pollset->idle_jobs);
+    grpc_exec_ctx_enqueue_list(exec_ctx, &pollset->idle_jobs, NULL);
     goto done;
   }
   /* Check alarms - these are a global resource so we just ping
@@ -365,7 +365,7 @@
        * TODO(dklempner): Can we refactor the shutdown logic to avoid this? */
       gpr_mu_lock(&pollset->mu);
     } else if (!grpc_closure_list_empty(pollset->idle_jobs)) {
-      grpc_exec_ctx_enqueue_list(exec_ctx, &pollset->idle_jobs);
+      grpc_exec_ctx_enqueue_list(exec_ctx, &pollset->idle_jobs, NULL);
       gpr_mu_unlock(&pollset->mu);
       grpc_exec_ctx_flush(exec_ctx);
       gpr_mu_lock(&pollset->mu);
@@ -381,7 +381,7 @@
   pollset->shutdown_done = closure;
   grpc_pollset_kick(pollset, GRPC_POLLSET_KICK_BROADCAST);
   if (!grpc_pollset_has_workers(pollset)) {
-    grpc_exec_ctx_enqueue_list(exec_ctx, &pollset->idle_jobs);
+    grpc_exec_ctx_enqueue_list(exec_ctx, &pollset->idle_jobs, NULL);
   }
   if (!pollset->called_shutdown && pollset->in_flight_cbs == 0 &&
       !grpc_pollset_has_workers(pollset)) {
@@ -393,7 +393,7 @@
 int grpc_poll_deadline_to_millis_timeout(gpr_timespec deadline,
                                          gpr_timespec now) {
   gpr_timespec timeout;
-  static const int max_spin_polling_us = 10;
+  static const int64_t max_spin_polling_us = 10;
   if (gpr_time_cmp(deadline, gpr_inf_future(deadline.clock_type)) == 0) {
     return -1;
   }
@@ -419,7 +419,8 @@
   grpc_closure promotion_closure;
 } grpc_unary_promote_args;
 
-static void basic_do_promote(grpc_exec_ctx *exec_ctx, void *args, int success) {
+static void basic_do_promote(grpc_exec_ctx *exec_ctx, void *args,
+                             bool success) {
   grpc_unary_promote_args *up_args = args;
   const grpc_pollset_vtable *original_vtable = up_args->original_vtable;
   grpc_pollset *pollset = up_args->pollset;
diff --git a/src/core/iomgr/pollset_windows.c b/src/core/iomgr/pollset_windows.c
index deb6615..02c6678 100644
--- a/src/core/iomgr/pollset_windows.c
+++ b/src/core/iomgr/pollset_windows.c
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -81,15 +81,6 @@
   }
 }
 
-static void push_back_worker(grpc_pollset_worker *root,
-                             grpc_pollset_worker_link_type type,
-                             grpc_pollset_worker *worker) {
-  worker->links[type].next = root;
-  worker->links[type].prev = worker->links[type].next->links[type].prev;
-  worker->links[type].prev->links[type].next =
-      worker->links[type].next->links[type].prev = worker;
-}
-
 static void push_front_worker(grpc_pollset_worker *root,
                               grpc_pollset_worker_link_type type,
                               grpc_pollset_worker *worker) {
@@ -116,7 +107,7 @@
   pollset->shutting_down = 1;
   grpc_pollset_kick(pollset, GRPC_POLLSET_KICK_BROADCAST);
   if (!pollset->is_iocp_worker) {
-    grpc_exec_ctx_enqueue(exec_ctx, closure, 1);
+    grpc_exec_ctx_enqueue(exec_ctx, closure, true, NULL);
   } else {
     pollset->on_shutdown = closure;
   }
@@ -174,7 +165,7 @@
       }
 
       if (pollset->shutting_down && pollset->on_shutdown != NULL) {
-        grpc_exec_ctx_enqueue(exec_ctx, pollset->on_shutdown, 1);
+        grpc_exec_ctx_enqueue(exec_ctx, pollset->on_shutdown, true, NULL);
         pollset->on_shutdown = NULL;
       }
       goto done;
@@ -221,10 +212,8 @@
         grpc_iocp_kick();
       }
     } else {
-      if (p->is_iocp_worker) {
-        if (g_active_poller == specific_worker) {
-          grpc_iocp_kick();
-        }
+      if (p->is_iocp_worker && g_active_poller == specific_worker) {
+        grpc_iocp_kick();
       } else {
         specific_worker->kicked = 1;
         gpr_cv_signal(&specific_worker->cv);
diff --git a/src/core/iomgr/resolve_address_posix.c b/src/core/iomgr/resolve_address_posix.c
index 555c74c..c51745b 100644
--- a/src/core/iomgr/resolve_address_posix.c
+++ b/src/core/iomgr/resolve_address_posix.c
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -152,7 +152,7 @@
 
 /* Callback to be passed to grpc_executor to asynch-ify
  * grpc_blocking_resolve_address */
-static void do_request_thread(grpc_exec_ctx *exec_ctx, void *rp, int success) {
+static void do_request_thread(grpc_exec_ctx *exec_ctx, void *rp, bool success) {
   request *r = rp;
   grpc_resolved_addresses *resolved =
       grpc_blocking_resolve_address(r->name, r->default_port);
diff --git a/src/core/iomgr/resolve_address_windows.c b/src/core/iomgr/resolve_address_windows.c
index 007c855..28c8661 100644
--- a/src/core/iomgr/resolve_address_windows.c
+++ b/src/core/iomgr/resolve_address_windows.c
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -135,7 +135,7 @@
 
 /* Callback to be passed to grpc_executor to asynch-ify
  * grpc_blocking_resolve_address */
-static void do_request_thread(grpc_exec_ctx *exec_ctx, void *rp, int success) {
+static void do_request_thread(grpc_exec_ctx *exec_ctx, void *rp, bool success) {
   request *r = rp;
   grpc_resolved_addresses *resolved =
       grpc_blocking_resolve_address(r->name, r->default_port);
diff --git a/src/core/iomgr/sockaddr_win32.h b/src/core/iomgr/sockaddr_win32.h
index fe2be99..8e3946a 100644
--- a/src/core/iomgr/sockaddr_win32.h
+++ b/src/core/iomgr/sockaddr_win32.h
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -38,9 +38,4 @@
 #include <ws2tcpip.h>
 #include <mswsock.h>
 
-#ifdef __MINGW32__
-/* mingw seems to be missing that definition. */
-const char *inet_ntop(int af, const void *src, char *dst, socklen_t size);
-#endif
-
 #endif /* GRPC_INTERNAL_CORE_IOMGR_SOCKADDR_WIN32_H */
diff --git a/src/core/iomgr/tcp_client_posix.c b/src/core/iomgr/tcp_client_posix.c
index d9d24ee..c76c2e3 100644
--- a/src/core/iomgr/tcp_client_posix.c
+++ b/src/core/iomgr/tcp_client_posix.c
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -91,7 +91,7 @@
   return 0;
 }
 
-static void tc_on_alarm(grpc_exec_ctx *exec_ctx, void *acp, int success) {
+static void tc_on_alarm(grpc_exec_ctx *exec_ctx, void *acp, bool success) {
   int done;
   async_connect *ac = acp;
   if (grpc_tcp_trace) {
@@ -111,7 +111,7 @@
   }
 }
 
-static void on_writable(grpc_exec_ctx *exec_ctx, void *acp, int success) {
+static void on_writable(grpc_exec_ctx *exec_ctx, void *acp, bool success) {
   async_connect *ac = acp;
   int so_error = 0;
   socklen_t so_error_size;
@@ -206,7 +206,7 @@
     gpr_free(ac->addr_str);
     gpr_free(ac);
   }
-  grpc_exec_ctx_enqueue(exec_ctx, closure, *ep != NULL);
+  grpc_exec_ctx_enqueue(exec_ctx, closure, *ep != NULL, NULL);
 }
 
 void grpc_tcp_client_connect(grpc_exec_ctx *exec_ctx, grpc_closure *closure,
@@ -243,7 +243,7 @@
     addr_len = sizeof(addr4_copy);
   }
   if (!prepare_socket(addr, fd)) {
-    grpc_exec_ctx_enqueue(exec_ctx, closure, 0);
+    grpc_exec_ctx_enqueue(exec_ctx, closure, false, NULL);
     return;
   }
 
@@ -259,14 +259,14 @@
 
   if (err >= 0) {
     *ep = grpc_tcp_create(fdobj, GRPC_TCP_DEFAULT_READ_SLICE_SIZE, addr_str);
-    grpc_exec_ctx_enqueue(exec_ctx, closure, 1);
+    grpc_exec_ctx_enqueue(exec_ctx, closure, true, NULL);
     goto done;
   }
 
   if (errno != EWOULDBLOCK && errno != EINPROGRESS) {
     gpr_log(GPR_ERROR, "connect error to '%s': %s", addr_str, strerror(errno));
     grpc_fd_orphan(exec_ctx, fdobj, NULL, NULL, "tcp_client_connect_error");
-    grpc_exec_ctx_enqueue(exec_ctx, closure, 0);
+    grpc_exec_ctx_enqueue(exec_ctx, closure, false, NULL);
     goto done;
   }
 
diff --git a/src/core/iomgr/tcp_client_windows.c b/src/core/iomgr/tcp_client_windows.c
index e5691b7..689c6f7 100644
--- a/src/core/iomgr/tcp_client_windows.c
+++ b/src/core/iomgr/tcp_client_windows.c
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -74,7 +74,7 @@
   }
 }
 
-static void on_alarm(grpc_exec_ctx *exec_ctx, void *acp, int occured) {
+static void on_alarm(grpc_exec_ctx *exec_ctx, void *acp, bool occured) {
   async_connect *ac = acp;
   gpr_mu_lock(&ac->mu);
   /* If the alarm didn't occur, it got cancelled. */
@@ -84,7 +84,7 @@
   async_connect_unlock_and_cleanup(ac);
 }
 
-static void on_connect(grpc_exec_ctx *exec_ctx, void *acp, int from_iocp) {
+static void on_connect(grpc_exec_ctx *exec_ctx, void *acp, bool from_iocp) {
   async_connect *ac = acp;
   SOCKET sock = ac->socket->socket;
   grpc_endpoint **ep = ac->endpoint;
@@ -215,7 +215,7 @@
   } else if (sock != INVALID_SOCKET) {
     closesocket(sock);
   }
-  grpc_exec_ctx_enqueue(exec_ctx, on_done, 0);
+  grpc_exec_ctx_enqueue(exec_ctx, on_done, false, NULL);
 }
 
 #endif /* GPR_WINSOCK_SOCKET */
diff --git a/src/core/iomgr/tcp_posix.c b/src/core/iomgr/tcp_posix.c
index 4fa8ca8..048e907 100644
--- a/src/core/iomgr/tcp_posix.c
+++ b/src/core/iomgr/tcp_posix.c
@@ -100,9 +100,9 @@
 } grpc_tcp;
 
 static void tcp_handle_read(grpc_exec_ctx *exec_ctx, void *arg /* grpc_tcp */,
-                            int success);
+                            bool success);
 static void tcp_handle_write(grpc_exec_ctx *exec_ctx, void *arg /* grpc_tcp */,
-                             int success);
+                             bool success);
 
 static void tcp_shutdown(grpc_exec_ctx *exec_ctx, grpc_endpoint *ep) {
   grpc_tcp *tcp = (grpc_tcp *)ep;
@@ -247,7 +247,7 @@
 }
 
 static void tcp_handle_read(grpc_exec_ctx *exec_ctx, void *arg /* grpc_tcp */,
-                            int success) {
+                            bool success) {
   grpc_tcp *tcp = (grpc_tcp *)arg;
   GPR_ASSERT(!tcp->finished_edge);
 
@@ -273,7 +273,7 @@
     tcp->finished_edge = 0;
     grpc_fd_notify_on_read(exec_ctx, tcp->em_fd, &tcp->read_closure);
   } else {
-    grpc_exec_ctx_enqueue(exec_ctx, &tcp->read_closure, 1);
+    grpc_exec_ctx_enqueue(exec_ctx, &tcp->read_closure, true, NULL);
   }
 }
 
@@ -360,7 +360,7 @@
 }
 
 static void tcp_handle_write(grpc_exec_ctx *exec_ctx, void *arg /* grpc_tcp */,
-                             int success) {
+                             bool success) {
   grpc_tcp *tcp = (grpc_tcp *)arg;
   flush_result status;
   grpc_closure *cb;
@@ -407,7 +407,7 @@
 
   if (buf->length == 0) {
     GPR_TIMER_END("tcp_write", 0);
-    grpc_exec_ctx_enqueue(exec_ctx, cb, 1);
+    grpc_exec_ctx_enqueue(exec_ctx, cb, true, NULL);
     return;
   }
   tcp->outgoing_buffer = buf;
@@ -420,7 +420,7 @@
     tcp->write_cb = cb;
     grpc_fd_notify_on_write(exec_ctx, tcp->em_fd, &tcp->write_closure);
   } else {
-    grpc_exec_ctx_enqueue(exec_ctx, cb, status == FLUSH_DONE);
+    grpc_exec_ctx_enqueue(exec_ctx, cb, status == FLUSH_DONE, NULL);
   }
 
   GPR_TIMER_END("tcp_write", 0);
diff --git a/src/core/iomgr/tcp_server.h b/src/core/iomgr/tcp_server.h
index 8f3184f..a39dd3b 100644
--- a/src/core/iomgr/tcp_server.h
+++ b/src/core/iomgr/tcp_server.h
@@ -40,15 +40,14 @@
 /* Forward decl of grpc_tcp_server */
 typedef struct grpc_tcp_server grpc_tcp_server;
 
-typedef struct grpc_tcp_server_acceptor grpc_tcp_server_acceptor;
-struct grpc_tcp_server_acceptor {
+typedef struct grpc_tcp_server_acceptor {
   /* grpc_tcp_server_cb functions share a ref on from_server that is valid
      until the function returns. */
   grpc_tcp_server *from_server;
   /* Indices that may be passed to grpc_tcp_server_port_fd(). */
   unsigned port_index;
   unsigned fd_index;
-};
+} grpc_tcp_server_acceptor;
 
 /* Called for newly connected TCP connections. */
 typedef void (*grpc_tcp_server_cb)(grpc_exec_ctx *exec_ctx, void *arg,
@@ -57,7 +56,7 @@
 
 /* Create a server, initially not bound to any ports. The caller owns one ref.
    If shutdown_complete is not NULL, it will be used by
-   grpc_tcp_server_unref(). */
+   grpc_tcp_server_unref() when the ref count reaches zero. */
 grpc_tcp_server *grpc_tcp_server_create(grpc_closure *shutdown_complete);
 
 /* Start listening to bound ports */
@@ -84,7 +83,7 @@
 /* Returns the file descriptor of the Mth (fd_index) listening socket of the Nth
    (port_index) call to add_port() on this server, or -1 if the indices are out
    of bounds. The file descriptor remains owned by the server, and will be
-   cleaned up when grpc_tcp_server_destroy is called. */
+   cleaned up when the ref count reaches zero. */
 int grpc_tcp_server_port_fd(grpc_tcp_server *s, unsigned port_index,
                             unsigned fd_index);
 
@@ -97,7 +96,7 @@
 void grpc_tcp_server_shutdown_starting_add(grpc_tcp_server *s,
                                            grpc_closure *shutdown_starting);
 
-/* If the recount drops to zero, delete s, and call (exec_ctx==NULL) or enqueue
+/* If the refcount drops to zero, delete s, and call (exec_ctx==NULL) or enqueue
    a call (exec_ctx!=NULL) to shutdown_complete. */
 void grpc_tcp_server_unref(grpc_exec_ctx *exec_ctx, grpc_tcp_server *s);
 
diff --git a/src/core/iomgr/tcp_server_posix.c b/src/core/iomgr/tcp_server_posix.c
index adf14ae..5e07f82 100644
--- a/src/core/iomgr/tcp_server_posix.c
+++ b/src/core/iomgr/tcp_server_posix.c
@@ -160,7 +160,7 @@
 
 static void finish_shutdown(grpc_exec_ctx *exec_ctx, grpc_tcp_server *s) {
   if (s->shutdown_complete != NULL) {
-    grpc_exec_ctx_enqueue(exec_ctx, s->shutdown_complete, 1);
+    grpc_exec_ctx_enqueue(exec_ctx, s->shutdown_complete, true, NULL);
   }
 
   gpr_mu_destroy(&s->mu);
@@ -174,7 +174,8 @@
   gpr_free(s);
 }
 
-static void destroyed_port(grpc_exec_ctx *exec_ctx, void *server, int success) {
+static void destroyed_port(grpc_exec_ctx *exec_ctx, void *server,
+                           bool success) {
   grpc_tcp_server *s = server;
   gpr_mu_lock(&s->mu);
   s->destroyed_ports++;
@@ -317,7 +318,7 @@
 }
 
 /* event manager callback when reads are ready */
-static void on_read(grpc_exec_ctx *exec_ctx, void *arg, int success) {
+static void on_read(grpc_exec_ctx *exec_ctx, void *arg, bool success) {
   grpc_tcp_listener *sp = arg;
   grpc_tcp_server_acceptor acceptor = {sp->server, sp->port_index,
                                        sp->fd_index};
@@ -602,7 +603,7 @@
     /* Complete shutdown_starting work before destroying. */
     grpc_exec_ctx local_exec_ctx = GRPC_EXEC_CTX_INIT;
     gpr_mu_lock(&s->mu);
-    grpc_exec_ctx_enqueue_list(&local_exec_ctx, &s->shutdown_starting);
+    grpc_exec_ctx_enqueue_list(&local_exec_ctx, &s->shutdown_starting, NULL);
     gpr_mu_unlock(&s->mu);
     if (exec_ctx == NULL) {
       grpc_exec_ctx_flush(&local_exec_ctx);
diff --git a/src/core/iomgr/tcp_server_windows.c b/src/core/iomgr/tcp_server_windows.c
index 8ee8149..ce930b8 100644
--- a/src/core/iomgr/tcp_server_windows.c
+++ b/src/core/iomgr/tcp_server_windows.c
@@ -119,7 +119,7 @@
 
 static void finish_shutdown(grpc_exec_ctx *exec_ctx, grpc_tcp_server *s) {
   if (s->shutdown_complete != NULL) {
-    grpc_exec_ctx_enqueue(exec_ctx, s->shutdown_complete, 1);
+    grpc_exec_ctx_enqueue(exec_ctx, s->shutdown_complete, true, NULL);
   }
 
   /* Now that the accepts have been aborted, we can destroy the sockets.
@@ -173,7 +173,7 @@
     /* Complete shutdown_starting work before destroying. */
     grpc_exec_ctx local_exec_ctx = GRPC_EXEC_CTX_INIT;
     gpr_mu_lock(&s->mu);
-    grpc_exec_ctx_enqueue_list(&local_exec_ctx, &s->shutdown_starting);
+    grpc_exec_ctx_enqueue_list(&local_exec_ctx, &s->shutdown_starting, NULL);
     gpr_mu_unlock(&s->mu);
     if (exec_ctx == NULL) {
       grpc_exec_ctx_flush(&local_exec_ctx);
@@ -311,7 +311,7 @@
 }
 
 /* Event manager callback when reads are ready. */
-static void on_accept(grpc_exec_ctx *exec_ctx, void *arg, int from_iocp) {
+static void on_accept(grpc_exec_ctx *exec_ctx, void *arg, bool from_iocp) {
   grpc_tcp_listener *sp = arg;
   grpc_tcp_server_acceptor acceptor = {sp->server, sp->port_index, 0};
   SOCKET sock = sp->new_socket;
@@ -531,7 +531,7 @@
   for (sp = s->head; sp && port_index != 0; sp = sp->next, --port_index)
     ;
   if (sp) {
-    return _open_osfhandle(sp->socket->socket, 0);
+    return _open_osfhandle((intptr_t)sp->socket->socket, 0);
   } else {
     return -1;
   }
diff --git a/src/core/iomgr/tcp_windows.c b/src/core/iomgr/tcp_windows.c
index cc7f7ff..038e415 100644
--- a/src/core/iomgr/tcp_windows.c
+++ b/src/core/iomgr/tcp_windows.c
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -138,15 +138,12 @@
 #endif
 
 /* Asynchronous callback from the IOCP, or the background thread. */
-static void on_read(grpc_exec_ctx *exec_ctx, void *tcpp, int success) {
+static void on_read(grpc_exec_ctx *exec_ctx, void *tcpp, bool success) {
   grpc_tcp *tcp = tcpp;
   grpc_closure *cb = tcp->read_cb;
   grpc_winsocket *socket = tcp->socket;
   gpr_slice sub;
-  gpr_slice *slice = NULL;
-  size_t nslices = 0;
   grpc_winsocket_callback_info *info = &socket->read_info;
-  int do_abort = 0;
 
   if (success) {
     if (socket->read_info.wsa_error != 0 && !tcp->shutting_down) {
@@ -187,7 +184,7 @@
   WSABUF buffer;
 
   if (tcp->shutting_down) {
-    grpc_exec_ctx_enqueue(exec_ctx, cb, 0);
+    grpc_exec_ctx_enqueue(exec_ctx, cb, false, NULL);
     return;
   }
 
@@ -211,7 +208,7 @@
   /* Did we get data immediately ? Yay. */
   if (info->wsa_error != WSAEWOULDBLOCK) {
     info->bytes_transfered = bytes_read;
-    grpc_exec_ctx_enqueue(exec_ctx, &tcp->on_read, 1);
+    grpc_exec_ctx_enqueue(exec_ctx, &tcp->on_read, true, NULL);
     return;
   }
 
@@ -224,7 +221,7 @@
     int wsa_error = WSAGetLastError();
     if (wsa_error != WSA_IO_PENDING) {
       info->wsa_error = wsa_error;
-      grpc_exec_ctx_enqueue(exec_ctx, &tcp->on_read, 0);
+      grpc_exec_ctx_enqueue(exec_ctx, &tcp->on_read, false, NULL);
       return;
     }
   }
@@ -233,12 +230,11 @@
 }
 
 /* Asynchronous callback from the IOCP, or the background thread. */
-static void on_write(grpc_exec_ctx *exec_ctx, void *tcpp, int success) {
+static void on_write(grpc_exec_ctx *exec_ctx, void *tcpp, bool success) {
   grpc_tcp *tcp = (grpc_tcp *)tcpp;
   grpc_winsocket *handle = tcp->socket;
   grpc_winsocket_callback_info *info = &handle->write_info;
   grpc_closure *cb;
-  int do_abort = 0;
 
   gpr_mu_lock(&tcp->mu);
   cb = tcp->write_cb;
@@ -277,7 +273,7 @@
   size_t len;
 
   if (tcp->shutting_down) {
-    grpc_exec_ctx_enqueue(exec_ctx, cb, 0);
+    grpc_exec_ctx_enqueue(exec_ctx, cb, false, NULL);
     return;
   }
 
@@ -305,9 +301,9 @@
      connection that has its send queue filled up. But if we don't, then we can
      avoid doing an async write operation at all. */
   if (info->wsa_error != WSAEWOULDBLOCK) {
-    int ok = 0;
+    bool ok = false;
     if (status == 0) {
-      ok = 1;
+      ok = true;
       GPR_ASSERT(bytes_sent == tcp->write_slices->length);
     } else {
       if (socket->read_info.wsa_error != WSAECONNRESET) {
@@ -317,7 +313,7 @@
       }
     }
     if (allocated) gpr_free(allocated);
-    grpc_exec_ctx_enqueue(exec_ctx, cb, ok);
+    grpc_exec_ctx_enqueue(exec_ctx, cb, ok, NULL);
     return;
   }
 
@@ -334,7 +330,7 @@
     int wsa_error = WSAGetLastError();
     if (wsa_error != WSA_IO_PENDING) {
       TCP_UNREF(tcp, "write");
-      grpc_exec_ctx_enqueue(exec_ctx, cb, 0);
+      grpc_exec_ctx_enqueue(exec_ctx, cb, false, NULL);
       return;
     }
   }
diff --git a/src/core/iomgr/timer.c b/src/core/iomgr/timer.c
index 24d6204..a33d8f6 100644
--- a/src/core/iomgr/timer.c
+++ b/src/core/iomgr/timer.c
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -224,7 +224,7 @@
   shard_type *shard = &g_shards[shard_idx(timer)];
   gpr_mu_lock(&shard->mu);
   if (!timer->triggered) {
-    grpc_exec_ctx_enqueue(exec_ctx, &timer->closure, 0);
+    grpc_exec_ctx_enqueue(exec_ctx, &timer->closure, false, NULL);
     timer->triggered = 1;
     if (timer->heap_index == INVALID_HEAP_INDEX) {
       list_remove(timer);
@@ -290,7 +290,7 @@
   grpc_timer *timer;
   gpr_mu_lock(&shard->mu);
   while ((timer = pop_one(shard, now))) {
-    grpc_exec_ctx_enqueue(exec_ctx, &timer->closure, success);
+    grpc_exec_ctx_enqueue(exec_ctx, &timer->closure, success, NULL);
     n++;
   }
   *new_min_deadline = compute_min_deadline(shard);
diff --git a/src/core/iomgr/udp_server.c b/src/core/iomgr/udp_server.c
index a1a6b04..fe006c6 100644
--- a/src/core/iomgr/udp_server.c
+++ b/src/core/iomgr/udp_server.c
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -425,15 +425,5 @@
   gpr_mu_unlock(&s->mu);
 }
 
-/* TODO(rjshade): Add a test for this method. */
-void grpc_udp_server_write(server_port *sp, const char *buffer, size_t buf_len,
-                           const struct sockaddr *peer_address) {
-  ssize_t rc;
-  rc = sendto(sp->fd, buffer, buf_len, 0, peer_address, sizeof(peer_address));
-  if (rc < 0) {
-    gpr_log(GPR_ERROR, "Unable to send data: %s", strerror(errno));
-  }
-}
-
 #endif
 #endif
diff --git a/src/core/iomgr/udp_server.h b/src/core/iomgr/udp_server.h
index de5736c..73a21c8 100644
--- a/src/core/iomgr/udp_server.h
+++ b/src/core/iomgr/udp_server.h
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -72,12 +72,4 @@
 void grpc_udp_server_destroy(grpc_exec_ctx *exec_ctx, grpc_udp_server *server,
                              grpc_closure *on_done);
 
-/* Write the contents of buffer to the underlying UDP socket. */
-/*
-void grpc_udp_server_write(grpc_udp_server *s,
-                           const char *buffer,
-                           int buf_len,
-                           const struct sockaddr* to);
-                           */
-
 #endif /* GRPC_INTERNAL_CORE_IOMGR_UDP_SERVER_H */
diff --git a/src/core/iomgr/workqueue.h b/src/core/iomgr/workqueue.h
index 7145362..36dd133 100644
--- a/src/core/iomgr/workqueue.h
+++ b/src/core/iomgr/workqueue.h
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -47,9 +47,7 @@
 #include "src/core/iomgr/workqueue_windows.h"
 #endif
 
-/** A workqueue represents a list of work to be executed asynchronously. */
-struct grpc_workqueue;
-typedef struct grpc_workqueue grpc_workqueue;
+/* grpc_workqueue is forward declared in exec_ctx.h */
 
 /** Create a work queue */
 grpc_workqueue *grpc_workqueue_create(grpc_exec_ctx *exec_ctx);
diff --git a/src/core/iomgr/workqueue_posix.c b/src/core/iomgr/workqueue_posix.c
index d2a1c34..da11df6 100644
--- a/src/core/iomgr/workqueue_posix.c
+++ b/src/core/iomgr/workqueue_posix.c
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -45,7 +45,7 @@
 
 #include "src/core/iomgr/fd_posix.h"
 
-static void on_readable(grpc_exec_ctx *exec_ctx, void *arg, int success);
+static void on_readable(grpc_exec_ctx *exec_ctx, void *arg, bool success);
 
 grpc_workqueue *grpc_workqueue_create(grpc_exec_ctx *exec_ctx) {
   char name[32];
@@ -110,7 +110,7 @@
   gpr_mu_unlock(&workqueue->mu);
 }
 
-static void on_readable(grpc_exec_ctx *exec_ctx, void *arg, int success) {
+static void on_readable(grpc_exec_ctx *exec_ctx, void *arg, bool success) {
   grpc_workqueue *workqueue = arg;
 
   if (!success) {
diff --git a/src/core/security/credentials.c b/src/core/security/credentials.c
index 8b56c57..afba007 100644
--- a/src/core/security/credentials.c
+++ b/src/core/security/credentials.c
@@ -793,7 +793,7 @@
 }
 
 static void on_simulated_token_fetch_done(grpc_exec_ctx *exec_ctx,
-                                          void *user_data, int success) {
+                                          void *user_data, bool success) {
   grpc_credentials_metadata_request *r =
       (grpc_credentials_metadata_request *)user_data;
   grpc_md_only_test_credentials *c = (grpc_md_only_test_credentials *)r->creds;
@@ -812,7 +812,7 @@
     grpc_credentials_metadata_request *cb_arg =
         grpc_credentials_metadata_request_create(creds, cb, user_data);
     grpc_executor_enqueue(
-        grpc_closure_create(on_simulated_token_fetch_done, cb_arg), 1);
+        grpc_closure_create(on_simulated_token_fetch_done, cb_arg), true);
   } else {
     cb(exec_ctx, user_data, c->md_store->entries, 1, GRPC_CREDENTIALS_OK);
   }
diff --git a/src/core/security/google_default_credentials.c b/src/core/security/google_default_credentials.c
index 5385e41..f3ac145 100644
--- a/src/core/security/google_default_credentials.c
+++ b/src/core/security/google_default_credentials.c
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -86,7 +86,7 @@
   gpr_mu_unlock(GRPC_POLLSET_MU(&detector->pollset));
 }
 
-static void destroy_pollset(grpc_exec_ctx *exec_ctx, void *p, int s) {
+static void destroy_pollset(grpc_exec_ctx *exec_ctx, void *p, bool s) {
   grpc_pollset_destroy(p);
 }
 
@@ -157,7 +157,7 @@
   if (grpc_auth_json_key_is_valid(&key)) {
     result =
         grpc_service_account_jwt_access_credentials_create_from_auth_json_key(
-            key, grpc_max_auth_token_lifetime);
+            key, grpc_max_auth_token_lifetime());
     goto end;
   }
 
diff --git a/src/core/security/handshake.c b/src/core/security/handshake.c
index 364b765..a8b2fef 100644
--- a/src/core/security/handshake.c
+++ b/src/core/security/handshake.c
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -61,10 +61,10 @@
 } grpc_security_handshake;
 
 static void on_handshake_data_received_from_peer(grpc_exec_ctx *exec_ctx,
-                                                 void *setup, int success);
+                                                 void *setup, bool success);
 
 static void on_handshake_data_sent_to_peer(grpc_exec_ctx *exec_ctx, void *setup,
-                                           int success);
+                                           bool success);
 
 static void security_connector_remove_handshake(grpc_security_handshake *h) {
   grpc_security_connector_handshake_list *node;
@@ -198,7 +198,8 @@
 }
 
 static void on_handshake_data_received_from_peer(grpc_exec_ctx *exec_ctx,
-                                                 void *handshake, int success) {
+                                                 void *handshake,
+                                                 bool success) {
   grpc_security_handshake *h = handshake;
   size_t consumed_slice_size = 0;
   tsi_result result = TSI_OK;
@@ -265,7 +266,7 @@
 
 /* If handshake is NULL, the handshake is done. */
 static void on_handshake_data_sent_to_peer(grpc_exec_ctx *exec_ctx,
-                                           void *handshake, int success) {
+                                           void *handshake, bool success) {
   grpc_security_handshake *h = handshake;
 
   /* Make sure that write is OK. */
diff --git a/src/core/security/json_token.c b/src/core/security/json_token.c
index 4d4bc4b..762f029 100644
--- a/src/core/security/json_token.c
+++ b/src/core/security/json_token.c
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -49,7 +49,13 @@
 /* --- Constants. --- */
 
 /* 1 hour max. */
-const gpr_timespec grpc_max_auth_token_lifetime = {3600, 0, GPR_TIMESPAN};
+gpr_timespec grpc_max_auth_token_lifetime() {
+  gpr_timespec out;
+  out.tv_sec = 3600;
+  out.tv_nsec = 0;
+  out.clock_type = GPR_TIMESPAN;
+  return out;
+}
 
 #define GRPC_JWT_RSA_SHA256_ALGORITHM "RS256"
 #define GRPC_JWT_TYPE "JWT"
@@ -211,9 +217,9 @@
   gpr_timespec expiration = gpr_time_add(now, token_lifetime);
   char now_str[GPR_LTOA_MIN_BUFSIZE];
   char expiration_str[GPR_LTOA_MIN_BUFSIZE];
-  if (gpr_time_cmp(token_lifetime, grpc_max_auth_token_lifetime) > 0) {
+  if (gpr_time_cmp(token_lifetime, grpc_max_auth_token_lifetime()) > 0) {
     gpr_log(GPR_INFO, "Cropping token lifetime to maximum allowed value.");
-    expiration = gpr_time_add(now, grpc_max_auth_token_lifetime);
+    expiration = gpr_time_add(now, grpc_max_auth_token_lifetime());
   }
   int64_ttoa(now.tv_sec, now_str);
   int64_ttoa(expiration.tv_sec, expiration_str);
diff --git a/src/core/security/secure_endpoint.c b/src/core/security/secure_endpoint.c
index 9b87e26..d11c43b 100644
--- a/src/core/security/secure_endpoint.c
+++ b/src/core/security/secure_endpoint.c
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -126,7 +126,7 @@
 }
 
 static void call_read_cb(grpc_exec_ctx *exec_ctx, secure_endpoint *ep,
-                         int success) {
+                         bool success) {
   if (grpc_trace_secure_endpoint) {
     size_t i;
     for (i = 0; i < ep->read_buffer->count; i++) {
@@ -137,11 +137,11 @@
     }
   }
   ep->read_buffer = NULL;
-  grpc_exec_ctx_enqueue(exec_ctx, ep->read_cb, success);
+  grpc_exec_ctx_enqueue(exec_ctx, ep->read_cb, success, NULL);
   SECURE_ENDPOINT_UNREF(exec_ctx, ep, "read");
 }
 
-static void on_read(grpc_exec_ctx *exec_ctx, void *user_data, int success) {
+static void on_read(grpc_exec_ctx *exec_ctx, void *user_data, bool success) {
   unsigned i;
   uint8_t keep_looping = 0;
   tsi_result result = TSI_OK;
@@ -315,7 +315,7 @@
   if (result != TSI_OK) {
     /* TODO(yangg) do different things according to the error type? */
     gpr_slice_buffer_reset_and_unref(&ep->output_buffer);
-    grpc_exec_ctx_enqueue(exec_ctx, cb, 0);
+    grpc_exec_ctx_enqueue(exec_ctx, cb, false, NULL);
     return;
   }
 
diff --git a/src/core/security/security_connector.c b/src/core/security/security_connector.c
index 61336a1..bdccbab 100644
--- a/src/core/security/security_connector.c
+++ b/src/core/security/security_connector.c
@@ -61,6 +61,14 @@
     INSTALL_PREFIX "/share/grpc/roots.pem";
 #endif
 
+/* -- Overridden default roots. -- */
+
+static grpc_ssl_roots_override_callback ssl_roots_override_cb = NULL;
+
+void grpc_set_ssl_roots_override_callback(grpc_ssl_roots_override_callback cb) {
+  ssl_roots_override_cb = cb;
+}
+
 /* -- Cipher suites. -- */
 
 /* Defines the cipher suites that we accept by default. All these cipher suites
@@ -595,23 +603,44 @@
 static grpc_security_connector_vtable ssl_server_vtable = {
     ssl_server_destroy, ssl_server_do_handshake, ssl_server_check_peer};
 
-static gpr_slice default_pem_root_certs;
+static gpr_slice compute_default_pem_root_certs_once(void) {
+  gpr_slice result = gpr_empty_slice();
 
-static void init_default_pem_root_certs(void) {
   /* First try to load the roots from the environment. */
   char *default_root_certs_path =
       gpr_getenv(GRPC_DEFAULT_SSL_ROOTS_FILE_PATH_ENV_VAR);
-  if (default_root_certs_path == NULL) {
-    default_pem_root_certs = gpr_empty_slice();
-  } else {
-    default_pem_root_certs = gpr_load_file(default_root_certs_path, 0, NULL);
+  if (default_root_certs_path != NULL) {
+    result = gpr_load_file(default_root_certs_path, 0, NULL);
     gpr_free(default_root_certs_path);
   }
 
-  /* Fall back to installed certs if needed. */
-  if (GPR_SLICE_IS_EMPTY(default_pem_root_certs)) {
-    default_pem_root_certs = gpr_load_file(installed_roots_path, 0, NULL);
+  /* Try overridden roots if needed. */
+  grpc_ssl_roots_override_result ovrd_res = GRPC_SSL_ROOTS_OVERRIDE_FAIL;
+  if (GPR_SLICE_IS_EMPTY(result) && ssl_roots_override_cb != NULL) {
+    char *pem_root_certs = NULL;
+    ovrd_res = ssl_roots_override_cb(&pem_root_certs);
+    if (ovrd_res == GRPC_SSL_ROOTS_OVERRIDE_OK) {
+      GPR_ASSERT(pem_root_certs != NULL);
+      result = gpr_slice_new(pem_root_certs, strlen(pem_root_certs), gpr_free);
+    }
   }
+
+  /* Fall back to installed certs if needed. */
+  if (GPR_SLICE_IS_EMPTY(result) &&
+      ovrd_res != GRPC_SSL_ROOTS_OVERRIDE_FAIL_PERMANENTLY) {
+    result = gpr_load_file(installed_roots_path, 0, NULL);
+  }
+  return result;
+}
+
+static gpr_slice default_pem_root_certs;
+
+static void init_default_pem_root_certs(void) {
+  default_pem_root_certs = compute_default_pem_root_certs_once();
+}
+
+gpr_slice grpc_get_default_ssl_roots_for_testing(void) {
+  return compute_default_pem_root_certs_once();
 }
 
 size_t grpc_get_default_ssl_roots(const unsigned char **pem_root_certs) {
diff --git a/src/core/security/security_connector.h b/src/core/security/security_connector.h
index 2b73410..39df782 100644
--- a/src/core/security/security_connector.h
+++ b/src/core/security/security_connector.h
@@ -209,6 +209,9 @@
 /* Gets the default ssl roots. */
 size_t grpc_get_default_ssl_roots(const unsigned char **pem_root_certs);
 
+/* Exposed for TESTING ONLY!. */
+gpr_slice grpc_get_default_ssl_roots_for_testing(void);
+
 /* Config for ssl servers. */
 typedef struct {
   unsigned char **pem_private_keys;
diff --git a/src/core/security/server_auth_filter.c b/src/core/security/server_auth_filter.c
index d5c8c54..3d8e5e8 100644
--- a/src/core/security/server_auth_filter.c
+++ b/src/core/security/server_auth_filter.c
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -153,7 +153,7 @@
 }
 
 static void auth_on_recv(grpc_exec_ctx *exec_ctx, void *user_data,
-                         int success) {
+                         bool success) {
   grpc_call_element *elem = user_data;
   call_data *calld = elem->call_data;
   channel_data *chand = elem->channel_data;
@@ -176,8 +176,8 @@
   if (op->recv_initial_metadata != NULL) {
     /* substitute our callback for the higher callback */
     calld->recv_initial_metadata = op->recv_initial_metadata;
-    calld->on_done_recv = op->on_complete;
-    op->on_complete = &calld->auth_on_recv;
+    calld->on_done_recv = op->recv_initial_metadata_ready;
+    op->recv_initial_metadata_ready = &calld->auth_on_recv;
     calld->transport_op = *op;
   }
 }
diff --git a/src/core/security/server_secure_chttp2.c b/src/core/security/server_secure_chttp2.c
index 08713fc..84a8833 100644
--- a/src/core/security/server_secure_chttp2.c
+++ b/src/core/security/server_secure_chttp2.c
@@ -142,7 +142,7 @@
                         on_accept, state);
 }
 
-static void destroy_done(grpc_exec_ctx *exec_ctx, void *statep, int success) {
+static void destroy_done(grpc_exec_ctx *exec_ctx, void *statep, bool success) {
   grpc_server_secure_state *state = statep;
   if (state->destroy_callback != NULL) {
     state->destroy_callback->cb(exec_ctx, state->destroy_callback->cb_arg,
@@ -208,6 +208,14 @@
     goto error;
   }
 
+  state->server = server;
+  state->tcp = tcp;
+  state->sc = sc;
+  state->creds = grpc_server_credentials_ref(creds);
+  state->is_shutdown = 0;
+  gpr_mu_init(&state->mu);
+  gpr_ref_init(&state->refcount, 1);
+
   for (i = 0; i < resolved->naddrs; i++) {
     port_temp = grpc_tcp_server_add_port(
         tcp, (struct sockaddr *)&resolved->addrs[i].addr,
@@ -233,15 +241,6 @@
   }
   grpc_resolved_addresses_destroy(resolved);
 
-  state->server = server;
-  state->tcp = tcp;
-  state->sc = sc;
-  state->creds = grpc_server_credentials_ref(creds);
-
-  state->is_shutdown = 0;
-  gpr_mu_init(&state->mu);
-  gpr_ref_init(&state->refcount, 1);
-
   /* Register with the server only upon success */
   grpc_server_add_listener(&exec_ctx, server, state, start, destroy);
 
@@ -250,17 +249,18 @@
 
 /* Error path: cleanup and return */
 error:
-  if (sc) {
-    GRPC_SECURITY_CONNECTOR_UNREF(sc, "server");
-  }
   if (resolved) {
     grpc_resolved_addresses_destroy(resolved);
   }
   if (tcp) {
     grpc_tcp_server_unref(&exec_ctx, tcp);
-  }
-  if (state) {
-    gpr_free(state);
+  } else {
+    if (sc) {
+      GRPC_SECURITY_CONNECTOR_UNREF(sc, "server");
+    }
+    if (state) {
+      gpr_free(state);
+    }
   }
   grpc_exec_ctx_finish(&exec_ctx);
   return 0;
diff --git a/src/core/statistics/census_init.c b/src/core/statistics/census_init.c
index e6306f5..b6a962f 100644
--- a/src/core/statistics/census_init.c
+++ b/src/core/statistics/census_init.c
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff --git a/src/core/support/env_linux.c b/src/core/support/env_linux.c
index 2e03365..442cd82 100644
--- a/src/core/support/env_linux.c
+++ b/src/core/support/env_linux.c
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -42,15 +42,25 @@
 
 #include "src/core/support/env.h"
 
+#include <dlfcn.h>
 #include <stdlib.h>
 
 #include <grpc/support/log.h>
 #include <grpc/support/string_util.h>
+#include <grpc/support/useful.h>
 
 #include "src/core/support/string.h"
 
 char *gpr_getenv(const char *name) {
-  char *result = secure_getenv(name);
+  typedef char *(*getenv_type)(const char *);
+  static getenv_type getenv_func = NULL;
+  /* Check to see which getenv variant is supported (go from most
+   * to least secure) */
+  const char *names[] = {"secure_getenv", "__secure_getenv", "getenv"};
+  for (size_t i = 0; getenv_func == NULL && i < GPR_ARRAY_SIZE(names); i++) {
+    getenv_func = (getenv_type)dlsym(RTLD_DEFAULT, names[i]);
+  }
+  char *result = getenv_func(name);
   return result == NULL ? result : gpr_strdup(result);
 }
 
diff --git a/src/core/support/env_win32.c b/src/core/support/env_win32.c
index 6b1ff10..1025828 100644
--- a/src/core/support/env_win32.c
+++ b/src/core/support/env_win32.c
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -38,7 +38,12 @@
 #include "src/core/support/env.h"
 #include "src/core/support/string.h"
 
+#ifdef __MINGW32__
+errno_t getenv_s(size_t *size_needed, char *buffer, size_t size,
+                 const char *varname);
+#else
 #include <stdlib.h>
+#endif
 
 #include <grpc/support/alloc.h>
 #include <grpc/support/log.h>
@@ -47,14 +52,17 @@
 char *gpr_getenv(const char *name) {
   size_t size;
   char *result = NULL;
-  char *duplicated;
   errno_t err;
 
-  err = _dupenv_s(&result, &size, name);
-  if (err) return NULL;
-  duplicated = gpr_strdup(result);
-  free(result);
-  return duplicated;
+  err = getenv_s(&size, NULL, 0, name);
+  if (err || (size == 0)) return NULL;
+  result = gpr_malloc(size);
+  err = getenv_s(&size, result, size, name);
+  if (err) {
+    gpr_free(result);
+    return NULL;
+  }
+  return result;
 }
 
 void gpr_setenv(const char *name, const char *value) {
diff --git a/src/core/support/log_win32.c b/src/core/support/log_win32.c
index 40adcd1..e18e667 100644
--- a/src/core/support/log_win32.c
+++ b/src/core/support/log_win32.c
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -109,13 +109,13 @@
   fflush(stderr);
 }
 
-char *gpr_format_message(DWORD messageid) {
+char *gpr_format_message(int messageid) {
   LPTSTR tmessage;
   char *message;
   DWORD status = FormatMessage(
       FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM |
           FORMAT_MESSAGE_IGNORE_INSERTS,
-      NULL, messageid, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
+      NULL, (DWORD)messageid, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
       (LPTSTR)(&tmessage), 0, NULL);
   if (status == 0) return gpr_strdup("Unable to retrieve error string");
   message = gpr_tchar_to_char(tmessage);
diff --git a/src/core/support/stack_lockfree.c b/src/core/support/stack_lockfree.c
index cd0afdd..9daecd2 100644
--- a/src/core/support/stack_lockfree.c
+++ b/src/core/support/stack_lockfree.c
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -99,6 +99,11 @@
 
   /* Point the head at reserved dummy entry */
   stack->head.contents.index = INVALID_ENTRY_INDEX;
+/* Fill in the pad and aba_ctr to avoid confusing memcheck tools */
+#ifdef GPR_ARCH_64
+  stack->head.contents.pad = 0;
+#endif
+  stack->head.contents.aba_ctr = 0;
   return stack;
 }
 
@@ -115,6 +120,11 @@
 
   /* First fill in the entry's index and aba ctr for new head */
   newhead.contents.index = (uint16_t)entry;
+#ifdef GPR_ARCH_64
+  /* Fill in the pad to avoid confusing memcheck tools */
+  newhead.contents.pad = 0;
+#endif
+
   /* Also post-increment the aba_ctr */
   curent.atm = gpr_atm_no_barrier_load(&stack->entries[entry].atm);
   newhead.contents.aba_ctr = ++curent.contents.aba_ctr;
diff --git a/src/core/support/string_win32.c b/src/core/support/string_win32.c
index 914ba87..3b1f702 100644
--- a/src/core/support/string_win32.c
+++ b/src/core/support/string_win32.c
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -85,8 +85,8 @@
 gpr_char_to_tchar(LPCSTR input) {
   LPTSTR ret;
   int needed = MultiByteToWideChar(CP_UTF8, 0, input, -1, NULL, 0);
-  if (needed == 0) return NULL;
-  ret = gpr_malloc(needed * sizeof(TCHAR));
+  if (needed <= 0) return NULL;
+  ret = gpr_malloc((unsigned)needed * sizeof(TCHAR));
   MultiByteToWideChar(CP_UTF8, 0, input, -1, ret, needed);
   return ret;
 }
@@ -95,8 +95,8 @@
 gpr_tchar_to_char(LPCTSTR input) {
   LPSTR ret;
   int needed = WideCharToMultiByte(CP_UTF8, 0, input, -1, NULL, 0, NULL, NULL);
-  if (needed == 0) return NULL;
-  ret = gpr_malloc(needed);
+  if (needed <= 0) return NULL;
+  ret = gpr_malloc((unsigned)needed);
   WideCharToMultiByte(CP_UTF8, 0, input, -1, ret, needed, NULL, NULL);
   return ret;
 }
diff --git a/src/core/support/subprocess_windows.c b/src/core/support/subprocess_windows.c
new file mode 100644
index 0000000..2b25ef0
--- /dev/null
+++ b/src/core/support/subprocess_windows.c
@@ -0,0 +1,141 @@
+/*
+ *
+ * Copyright 2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <grpc/support/port_platform.h>
+
+#ifdef GPR_WINDOWS_SUBPROCESS
+
+#include <windows.h>
+#include <string.h>
+#include <tchar.h>
+
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+#include <grpc/support/subprocess.h>
+#include "src/core/support/string.h"
+#include "src/core/support/string_win32.h"
+
+struct gpr_subprocess {
+  PROCESS_INFORMATION pi;
+  int joined;
+  int interrupted;
+};
+
+const char *gpr_subprocess_binary_extension() { return ".exe"; }
+
+gpr_subprocess *gpr_subprocess_create(int argc, const char **argv) {
+  gpr_subprocess *r;
+
+  STARTUPINFO si;
+  PROCESS_INFORMATION pi;
+
+  char *args = gpr_strjoin_sep(argv, (size_t)argc, " ", NULL);
+  TCHAR *args_tchar;
+
+  args_tchar = gpr_char_to_tchar(args);
+  gpr_free(args);
+
+  memset(&si, 0, sizeof(si));
+  si.cb = sizeof(si);
+  memset(&pi, 0, sizeof(pi));
+
+  if (!CreateProcess(NULL, args_tchar, NULL, NULL, FALSE,
+                     CREATE_NEW_PROCESS_GROUP, NULL, NULL, &si, &pi)) {
+    gpr_free(args_tchar);
+    return NULL;
+  }
+  gpr_free(args_tchar);
+
+  r = gpr_malloc(sizeof(gpr_subprocess));
+  memset(r, 0, sizeof(*r));
+  r->pi = pi;
+  return r;
+}
+
+void gpr_subprocess_destroy(gpr_subprocess *p) {
+  if (p) {
+    if (!p->joined) {
+      gpr_subprocess_interrupt(p);
+      gpr_subprocess_join(p);
+    }
+    if (p->pi.hProcess) {
+      CloseHandle(p->pi.hProcess);
+    }
+    if (p->pi.hThread) {
+      CloseHandle(p->pi.hThread);
+    }
+    gpr_free(p);
+  }
+}
+
+int gpr_subprocess_join(gpr_subprocess *p) {
+  DWORD dwExitCode;
+  if (GetExitCodeProcess(p->pi.hProcess, &dwExitCode)) {
+    if (dwExitCode == STILL_ACTIVE) {
+      if (WaitForSingleObject(p->pi.hProcess, INFINITE) == WAIT_OBJECT_0) {
+        p->joined = 1;
+        goto getExitCode;
+      }
+      return -1;  // failed to join
+    } else {
+      goto getExitCode;
+    }
+  } else {
+    return -1;  // failed to get exit code
+  }
+
+getExitCode:
+  if (p->interrupted) {
+    return 0;
+  }
+  if (GetExitCodeProcess(p->pi.hProcess, &dwExitCode)) {
+    return (int)dwExitCode;
+  } else {
+    return -1;  // failed to get exit code
+  }
+}
+
+void gpr_subprocess_interrupt(gpr_subprocess *p) {
+  DWORD dwExitCode;
+  if (GetExitCodeProcess(p->pi.hProcess, &dwExitCode)) {
+    if (dwExitCode == STILL_ACTIVE) {
+      gpr_log(GPR_INFO, "sending ctrl-break");
+      GenerateConsoleCtrlEvent(CTRL_BREAK_EVENT, p->pi.dwProcessId);
+      p->joined = 1;
+      p->interrupted = 1;
+    }
+  }
+  return;
+}
+
+#endif /* GPR_WINDOWS_SUBPROCESS */
diff --git a/src/core/support/sync_win32.c b/src/core/support/sync_win32.c
index 51a082b..41998eb 100644
--- a/src/core/support/sync_win32.c
+++ b/src/core/support/sync_win32.c
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -87,6 +87,7 @@
       0) {
     SleepConditionVariableCS(cv, &mu->cs, INFINITE);
   } else {
+    abs_deadline = gpr_convert_clock_type(abs_deadline, GPR_CLOCK_REALTIME);
     gpr_timespec now = gpr_now(abs_deadline.clock_type);
     int64_t now_ms = (int64_t)now.tv_sec * 1000 + now.tv_nsec / 1000000;
     int64_t deadline_ms =
@@ -94,7 +95,11 @@
     if (now_ms >= deadline_ms) {
       timeout = 1;
     } else {
-      timeout_max_ms = (DWORD)min(deadline_ms - now_ms, INFINITE - 1);
+      if ((deadline_ms - now_ms) >= INFINITE) {
+        timeout_max_ms = INFINITE - 1;
+      } else {
+        timeout_max_ms = (DWORD)(deadline_ms - now_ms);
+      }
       timeout = (SleepConditionVariableCS(cv, &mu->cs, timeout_max_ms) == 0 &&
                  GetLastError() == ERROR_TIMEOUT);
     }
diff --git a/src/core/support/time.c b/src/core/support/time.c
index ac8c3bc..423d12f 100644
--- a/src/core/support/time.c
+++ b/src/core/support/time.c
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -83,12 +83,12 @@
 /* TODO(ctiller): consider merging _nanos, _micros, _millis into a single
    function for maintainability. Similarly for _seconds, _minutes, and _hours */
 
-gpr_timespec gpr_time_from_nanos(long ns, gpr_clock_type type) {
+gpr_timespec gpr_time_from_nanos(int64_t ns, gpr_clock_type type) {
   gpr_timespec result;
   result.clock_type = type;
-  if (ns == LONG_MAX) {
+  if (ns == INT64_MAX) {
     result = gpr_inf_future(type);
-  } else if (ns == LONG_MIN) {
+  } else if (ns == INT64_MIN) {
     result = gpr_inf_past(type);
   } else if (ns >= 0) {
     result.tv_sec = ns / GPR_NS_PER_SEC;
@@ -101,12 +101,12 @@
   return result;
 }
 
-gpr_timespec gpr_time_from_micros(long us, gpr_clock_type type) {
+gpr_timespec gpr_time_from_micros(int64_t us, gpr_clock_type type) {
   gpr_timespec result;
   result.clock_type = type;
-  if (us == LONG_MAX) {
+  if (us == INT64_MAX) {
     result = gpr_inf_future(type);
-  } else if (us == LONG_MIN) {
+  } else if (us == INT64_MIN) {
     result = gpr_inf_past(type);
   } else if (us >= 0) {
     result.tv_sec = us / 1000000;
@@ -119,12 +119,12 @@
   return result;
 }
 
-gpr_timespec gpr_time_from_millis(long ms, gpr_clock_type type) {
+gpr_timespec gpr_time_from_millis(int64_t ms, gpr_clock_type type) {
   gpr_timespec result;
   result.clock_type = type;
-  if (ms == LONG_MAX) {
+  if (ms == INT64_MAX) {
     result = gpr_inf_future(type);
-  } else if (ms == LONG_MIN) {
+  } else if (ms == INT64_MIN) {
     result = gpr_inf_past(type);
   } else if (ms >= 0) {
     result.tv_sec = ms / 1000;
@@ -137,12 +137,12 @@
   return result;
 }
 
-gpr_timespec gpr_time_from_seconds(long s, gpr_clock_type type) {
+gpr_timespec gpr_time_from_seconds(int64_t s, gpr_clock_type type) {
   gpr_timespec result;
   result.clock_type = type;
-  if (s == LONG_MAX) {
+  if (s == INT64_MAX) {
     result = gpr_inf_future(type);
-  } else if (s == LONG_MIN) {
+  } else if (s == INT64_MIN) {
     result = gpr_inf_past(type);
   } else {
     result.tv_sec = s;
@@ -151,12 +151,12 @@
   return result;
 }
 
-gpr_timespec gpr_time_from_minutes(long m, gpr_clock_type type) {
+gpr_timespec gpr_time_from_minutes(int64_t m, gpr_clock_type type) {
   gpr_timespec result;
   result.clock_type = type;
-  if (m >= LONG_MAX / 60) {
+  if (m >= INT64_MAX / 60) {
     result = gpr_inf_future(type);
-  } else if (m <= LONG_MIN / 60) {
+  } else if (m <= INT64_MIN / 60) {
     result = gpr_inf_past(type);
   } else {
     result.tv_sec = m * 60;
@@ -165,12 +165,12 @@
   return result;
 }
 
-gpr_timespec gpr_time_from_hours(long h, gpr_clock_type type) {
+gpr_timespec gpr_time_from_hours(int64_t h, gpr_clock_type type) {
   gpr_timespec result;
   result.clock_type = type;
-  if (h >= LONG_MAX / 3600) {
+  if (h >= INT64_MAX / 3600) {
     result = gpr_inf_future(type);
-  } else if (h <= LONG_MIN / 3600) {
+  } else if (h <= INT64_MIN / 3600) {
     result = gpr_inf_past(type);
   } else {
     result.tv_sec = h * 3600;
diff --git a/src/core/support/time_posix.c b/src/core/support/time_posix.c
index 06bb78c..1f92d7f 100644
--- a/src/core/support/time_posix.c
+++ b/src/core/support/time_posix.c
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -39,6 +39,9 @@
 #include <stdlib.h>
 #include <time.h>
 #include <unistd.h>
+#ifdef __linux__
+#include <sys/syscall.h>
+#endif
 #include <grpc/support/log.h>
 #include <grpc/support/time.h>
 #include "src/core/support/block_annotate.h"
@@ -70,7 +73,8 @@
 }
 
 /** maps gpr_clock_type --> clockid_t for clock_gettime */
-static clockid_t clockid_for_gpr_clock[] = {CLOCK_MONOTONIC, CLOCK_REALTIME};
+static const clockid_t clockid_for_gpr_clock[] = {CLOCK_MONOTONIC,
+                                                  CLOCK_REALTIME};
 
 void gpr_time_init(void) { gpr_precise_clock_init(); }
 
@@ -82,7 +86,12 @@
     gpr_precise_clock_now(&ret);
     return ret;
   } else {
+#if defined(__linux__) && !defined(GPR_NO_DIRECT_SYSCALLS)
+    /* avoid ABI problems by invoking syscalls directly */
+    syscall(SYS_clock_gettime, clockid_for_gpr_clock[clock_type], &now);
+#else
     clock_gettime(clockid_for_gpr_clock[clock_type], &now);
+#endif
     return gpr_from_timespec(now, clock_type);
   }
 }
diff --git a/src/core/support/time_win32.c b/src/core/support/time_win32.c
index 2bed0f6..8af957e 100644
--- a/src/core/support/time_win32.c
+++ b/src/core/support/time_win32.c
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -37,9 +37,12 @@
 
 #ifdef GPR_WIN32
 
+#include <grpc/support/log.h>
 #include <grpc/support/time.h>
 #include <src/core/support/time_precise.h>
 #include <sys/timeb.h>
+#include <process.h>
+#include <limits.h>
 
 #include "src/core/support/block_annotate.h"
 
@@ -50,11 +53,12 @@
   LARGE_INTEGER frequency;
   QueryPerformanceFrequency(&frequency);
   QueryPerformanceCounter(&g_start_time);
-  g_time_scale = 1.0 / frequency.QuadPart;
+  g_time_scale = 1.0 / (double)frequency.QuadPart;
 }
 
 gpr_timespec gpr_now(gpr_clock_type clock) {
   gpr_timespec now_tv;
+  LONGLONG diff;
   struct _timeb now_tb;
   LARGE_INTEGER timestamp;
   double now_dbl;
@@ -68,10 +72,14 @@
     case GPR_CLOCK_MONOTONIC:
     case GPR_CLOCK_PRECISE:
       QueryPerformanceCounter(&timestamp);
-      now_dbl = (timestamp.QuadPart - g_start_time.QuadPart) * g_time_scale;
+      diff = timestamp.QuadPart - g_start_time.QuadPart;
+      now_dbl = (double)diff * g_time_scale;
       now_tv.tv_sec = (int64_t)now_dbl;
       now_tv.tv_nsec = (int32_t)((now_dbl - (double)now_tv.tv_sec) * 1e9);
       break;
+    case GPR_TIMESPAN:
+      abort();
+      break;
   }
   return now_tv;
 }
@@ -79,7 +87,7 @@
 void gpr_sleep_until(gpr_timespec until) {
   gpr_timespec now;
   gpr_timespec delta;
-  DWORD sleep_millis;
+  int64_t sleep_millis;
 
   for (;;) {
     /* We could simplify by using clock_nanosleep instead, but it might be
@@ -91,9 +99,10 @@
 
     delta = gpr_time_sub(until, now);
     sleep_millis =
-        (DWORD)delta.tv_sec * GPR_MS_PER_SEC + delta.tv_nsec / GPR_NS_PER_MS;
+        delta.tv_sec * GPR_MS_PER_SEC + delta.tv_nsec / GPR_NS_PER_MS;
+    GPR_ASSERT((sleep_millis >= 0) && (sleep_millis <= INT_MAX));
     GRPC_SCHEDULING_START_BLOCKING_REGION;
-    Sleep(sleep_millis);
+    Sleep((DWORD)sleep_millis);
     GRPC_SCHEDULING_END_BLOCKING_REGION;
   }
 }
diff --git a/src/objective-c/GRPCClient/private/GRPCUnsecuredChannel.h b/src/core/support/wrap_memcpy.c
similarity index 72%
copy from src/objective-c/GRPCClient/private/GRPCUnsecuredChannel.h
copy to src/core/support/wrap_memcpy.c
index 8528be4..15c289f 100644
--- a/src/objective-c/GRPCClient/private/GRPCUnsecuredChannel.h
+++ b/src/core/support/wrap_memcpy.c
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -31,8 +31,23 @@
  *
  */
 
-#import "GRPCChannel.h"
+#include <string.h>
 
-@interface GRPCUnsecuredChannel : GRPCChannel
-- (instancetype)initWithHost:(NSString *)host NS_DESIGNATED_INITIALIZER;
-@end
+/* Provide a wrapped memcpy for targets that need to be backwards
+ * compatible with older libc's.
+ *
+ * Enable by setting LDFLAGS=-Wl,-wrap,memcpy when linking.
+ */
+
+#ifdef __linux__
+#ifdef __x86_64__
+__asm__(".symver memcpy,memcpy@GLIBC_2.2.5");
+void *__wrap_memcpy(void *destination, const void *source, size_t num) {
+  return memcpy(destination, source, num);
+}
+#else /* !__x86_64__ */
+void *__wrap_memcpy(void *destination, const void *source, size_t num) {
+  return memmove(destination, source, num);
+}
+#endif
+#endif
diff --git a/src/core/surface/alarm.c b/src/core/surface/alarm.c
index 7c47dd5..d753023 100644
--- a/src/core/surface/alarm.c
+++ b/src/core/surface/alarm.c
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -48,7 +48,7 @@
 static void do_nothing_end_completion(grpc_exec_ctx *exec_ctx, void *arg,
                                       grpc_cq_completion *c) {}
 
-static void alarm_cb(grpc_exec_ctx *exec_ctx, void *arg, int success) {
+static void alarm_cb(grpc_exec_ctx *exec_ctx, void *arg, bool success) {
   grpc_alarm *alarm = arg;
   grpc_cq_end_op(exec_ctx, alarm->cq, alarm->tag, success,
                  do_nothing_end_completion, NULL, &alarm->completion);
@@ -65,7 +65,7 @@
 
   grpc_timer_init(&exec_ctx, &alarm->alarm, deadline, alarm_cb, alarm,
                   gpr_now(GPR_CLOCK_MONOTONIC));
-  grpc_cq_begin_op(cq);
+  grpc_cq_begin_op(cq, tag);
   grpc_exec_ctx_finish(&exec_ctx);
   return alarm;
 }
diff --git a/src/core/surface/call.c b/src/core/surface/call.c
index 880666b..1b117aa 100644
--- a/src/core/surface/call.c
+++ b/src/core/surface/call.c
@@ -159,6 +159,9 @@
   uint8_t receiving_message;
   uint8_t received_final_op;
 
+  /* have we received initial metadata */
+  bool has_initial_md_been_received;
+
   batch_control active_batches[MAX_CONCURRENT_BATCHES];
 
   /* first idx: is_receiving, second idx: is_trailing */
@@ -200,6 +203,7 @@
   gpr_slice receiving_slice;
   grpc_closure receiving_slice_ready;
   grpc_closure receiving_stream_ready;
+  grpc_closure receiving_initial_metadata_ready;
   uint32_t test_only_last_message_flags;
 
   union {
@@ -212,6 +216,11 @@
       int *cancelled;
     } server;
   } final_op;
+
+  struct {
+    void *bctlp;
+    bool success;
+  } saved_receiving_stream_ready_ctx;
 };
 
 #define CALL_STACK_FROM_CALL(call) ((grpc_call_stack *)((call) + 1))
@@ -229,9 +238,9 @@
                                           grpc_status_code status,
                                           const char *description);
 static void destroy_call(grpc_exec_ctx *exec_ctx, void *call_stack,
-                         int success);
+                         bool success);
 static void receiving_slice_ready(grpc_exec_ctx *exec_ctx, void *bctlp,
-                                  int success);
+                                  bool success);
 
 grpc_call *grpc_call_create(grpc_channel *channel, grpc_call *parent_call,
                             uint32_t propagation_mask,
@@ -351,7 +360,7 @@
   GRPC_CALL_STACK_UNREF(exec_ctx, CALL_STACK_FROM_CALL(c), REF_REASON);
 }
 
-static void destroy_call(grpc_exec_ctx *exec_ctx, void *call, int success) {
+static void destroy_call(grpc_exec_ctx *exec_ctx, void *call, bool success) {
   size_t i;
   int ii;
   grpc_call *c = call;
@@ -688,13 +697,13 @@
   grpc_status_code status;
 } cancel_closure;
 
-static void done_cancel(grpc_exec_ctx *exec_ctx, void *ccp, int success) {
+static void done_cancel(grpc_exec_ctx *exec_ctx, void *ccp, bool success) {
   cancel_closure *cc = ccp;
   GRPC_CALL_INTERNAL_UNREF(exec_ctx, cc->call, "cancel");
   gpr_free(cc);
 }
 
-static void send_cancel(grpc_exec_ctx *exec_ctx, void *ccp, int success) {
+static void send_cancel(grpc_exec_ctx *exec_ctx, void *ccp, bool success) {
   grpc_transport_stream_op op;
   cancel_closure *cc = ccp;
   memset(&op, 0, sizeof(op));
@@ -721,7 +730,7 @@
   cc->call = c;
   cc->status = status;
   GRPC_CALL_INTERNAL_REF(c, "cancel");
-  grpc_exec_ctx_enqueue(exec_ctx, &cc->closure, 1);
+  grpc_exec_ctx_enqueue(exec_ctx, &cc->closure, true, NULL);
 
   return GRPC_CALL_OK;
 }
@@ -757,7 +766,7 @@
   return CALL_FROM_TOP_ELEM(elem);
 }
 
-static void call_alarm(grpc_exec_ctx *exec_ctx, void *arg, int success) {
+static void call_alarm(grpc_exec_ctx *exec_ctx, void *arg, bool success) {
   grpc_call *call = arg;
   gpr_mu_lock(&call->mu);
   call->have_alarm = 0;
@@ -934,7 +943,7 @@
                                   batch_control *bctl) {
   grpc_call *call = bctl->call;
   if (bctl->is_notify_tag_closure) {
-    grpc_exec_ctx_enqueue(exec_ctx, bctl->notify_tag, bctl->success);
+    grpc_exec_ctx_enqueue(exec_ctx, bctl->notify_tag, bctl->success, NULL);
     gpr_mu_lock(&call->mu);
     bctl->call->used_batches =
         (uint8_t)(bctl->call->used_batches &
@@ -974,7 +983,7 @@
 }
 
 static void receiving_slice_ready(grpc_exec_ctx *exec_ctx, void *bctlp,
-                                  int success) {
+                                  bool success) {
   batch_control *bctl = bctlp;
   grpc_call *call = bctl->call;
 
@@ -993,7 +1002,95 @@
   }
 }
 
-static void finish_batch(grpc_exec_ctx *exec_ctx, void *bctlp, int success) {
+static void process_data_after_md(grpc_exec_ctx *exec_ctx, batch_control *bctl,
+                                  bool success) {
+  grpc_call *call = bctl->call;
+  if (call->receiving_stream == NULL) {
+    *call->receiving_buffer = NULL;
+    call->receiving_message = 0;
+    if (gpr_unref(&bctl->steps_to_complete)) {
+      post_batch_completion(exec_ctx, bctl);
+    }
+  } else if (call->receiving_stream->length >
+             grpc_channel_get_max_message_length(call->channel)) {
+    cancel_with_status(exec_ctx, call, GRPC_STATUS_INTERNAL,
+                       "Max message size exceeded");
+    grpc_byte_stream_destroy(exec_ctx, call->receiving_stream);
+    call->receiving_stream = NULL;
+    *call->receiving_buffer = NULL;
+    call->receiving_message = 0;
+    if (gpr_unref(&bctl->steps_to_complete)) {
+      post_batch_completion(exec_ctx, bctl);
+    }
+  } else {
+    call->test_only_last_message_flags = call->receiving_stream->flags;
+    if ((call->receiving_stream->flags & GRPC_WRITE_INTERNAL_COMPRESS) &&
+        (call->compression_algorithm > GRPC_COMPRESS_NONE)) {
+      *call->receiving_buffer = grpc_raw_compressed_byte_buffer_create(
+          NULL, 0, call->compression_algorithm);
+    } else {
+      *call->receiving_buffer = grpc_raw_byte_buffer_create(NULL, 0);
+    }
+    grpc_closure_init(&call->receiving_slice_ready, receiving_slice_ready,
+                      bctl);
+    continue_receiving_slices(exec_ctx, bctl);
+    /* early out */
+    return;
+  }
+}
+
+static void receiving_stream_ready(grpc_exec_ctx *exec_ctx, void *bctlp,
+                                   bool success) {
+  batch_control *bctl = bctlp;
+  grpc_call *call = bctl->call;
+
+  gpr_mu_lock(&bctl->call->mu);
+  if (bctl->call->has_initial_md_been_received) {
+    gpr_mu_unlock(&bctl->call->mu);
+    process_data_after_md(exec_ctx, bctlp, success);
+  } else {
+    call->saved_receiving_stream_ready_ctx.bctlp = bctlp;
+    call->saved_receiving_stream_ready_ctx.success = success;
+    gpr_mu_unlock(&bctl->call->mu);
+  }
+}
+
+static void receiving_initial_metadata_ready(grpc_exec_ctx *exec_ctx,
+                                             void *bctlp, bool success) {
+  batch_control *bctl = bctlp;
+  grpc_call *call = bctl->call;
+
+  gpr_mu_lock(&call->mu);
+
+  grpc_metadata_batch *md =
+      &call->metadata_batch[1 /* is_receiving */][0 /* is_trailing */];
+  grpc_metadata_batch_filter(md, recv_initial_filter, call);
+  call->has_initial_md_been_received = true;
+
+  if (gpr_time_cmp(md->deadline, gpr_inf_future(md->deadline.clock_type)) !=
+          0 &&
+      !call->is_client) {
+    GPR_TIMER_BEGIN("set_deadline_alarm", 0);
+    set_deadline_alarm(exec_ctx, call, md->deadline);
+    GPR_TIMER_END("set_deadline_alarm", 0);
+  }
+
+  if (call->saved_receiving_stream_ready_ctx.bctlp != NULL) {
+    grpc_closure *saved_rsr_closure = grpc_closure_create(
+        receiving_stream_ready, call->saved_receiving_stream_ready_ctx.bctlp);
+    grpc_exec_ctx_enqueue(exec_ctx, saved_rsr_closure,
+                          call->saved_receiving_stream_ready_ctx.success, NULL);
+    call->saved_receiving_stream_ready_ctx.bctlp = NULL;
+  }
+
+  gpr_mu_unlock(&call->mu);
+
+  if (gpr_unref(&bctl->steps_to_complete)) {
+    post_batch_completion(exec_ctx, bctl);
+  }
+}
+
+static void finish_batch(grpc_exec_ctx *exec_ctx, void *bctlp, bool success) {
   batch_control *bctl = bctlp;
   grpc_call *call = bctl->call;
   grpc_call *child_call;
@@ -1011,19 +1108,6 @@
     grpc_metadata_batch_destroy(
         &call->metadata_batch[0 /* is_receiving */][1 /* is_trailing */]);
   }
-  if (bctl->recv_initial_metadata) {
-    grpc_metadata_batch *md =
-        &call->metadata_batch[1 /* is_receiving */][0 /* is_trailing */];
-    grpc_metadata_batch_filter(md, recv_initial_filter, call);
-
-    if (gpr_time_cmp(md->deadline, gpr_inf_future(md->deadline.clock_type)) !=
-            0 &&
-        !call->is_client) {
-      GPR_TIMER_BEGIN("set_deadline_alarm", 0);
-      set_deadline_alarm(exec_ctx, call, md->deadline);
-      GPR_TIMER_END("set_deadline_alarm", 0);
-    }
-  }
   if (bctl->recv_final_op) {
     grpc_metadata_batch *md =
         &call->metadata_batch[1 /* is_receiving */][1 /* is_trailing */];
@@ -1065,45 +1149,6 @@
   }
 }
 
-static void receiving_stream_ready(grpc_exec_ctx *exec_ctx, void *bctlp,
-                                   int success) {
-  batch_control *bctl = bctlp;
-  grpc_call *call = bctl->call;
-
-  if (call->receiving_stream == NULL) {
-    *call->receiving_buffer = NULL;
-    call->receiving_message = 0;
-    if (gpr_unref(&bctl->steps_to_complete)) {
-      post_batch_completion(exec_ctx, bctl);
-    }
-  } else if (call->receiving_stream->length >
-             grpc_channel_get_max_message_length(call->channel)) {
-    cancel_with_status(exec_ctx, call, GRPC_STATUS_INTERNAL,
-                       "Max message size exceeded");
-    grpc_byte_stream_destroy(exec_ctx, call->receiving_stream);
-    call->receiving_stream = NULL;
-    *call->receiving_buffer = NULL;
-    call->receiving_message = 0;
-    if (gpr_unref(&bctl->steps_to_complete)) {
-      post_batch_completion(exec_ctx, bctl);
-    }
-  } else {
-    call->test_only_last_message_flags = call->receiving_stream->flags;
-    if ((call->receiving_stream->flags & GRPC_WRITE_INTERNAL_COMPRESS) &&
-        (call->compression_algorithm > GRPC_COMPRESS_NONE)) {
-      *call->receiving_buffer = grpc_raw_compressed_byte_buffer_create(
-          NULL, 0, call->compression_algorithm);
-    } else {
-      *call->receiving_buffer = grpc_raw_byte_buffer_create(NULL, 0);
-    }
-    grpc_closure_init(&call->receiving_slice_ready, receiving_slice_ready,
-                      bctl);
-    continue_receiving_slices(exec_ctx, bctl);
-    /* early out */
-    return;
-  }
-}
-
 static grpc_call_error call_start_batch(grpc_exec_ctx *exec_ctx,
                                         grpc_call *call, const grpc_op *ops,
                                         size_t nops, void *notify_tag,
@@ -1273,9 +1318,14 @@
         }
         call->received_initial_metadata = 1;
         call->buffered_metadata[0] = op->data.recv_initial_metadata;
+        grpc_closure_init(&call->receiving_initial_metadata_ready,
+                          receiving_initial_metadata_ready, bctl);
         bctl->recv_initial_metadata = 1;
         stream_op.recv_initial_metadata =
             &call->metadata_batch[1 /* is_receiving */][0 /* is_trailing */];
+        stream_op.recv_initial_metadata_ready =
+            &call->receiving_initial_metadata_ready;
+        num_completion_callbacks_needed++;
         break;
       case GRPC_OP_RECV_MESSAGE:
         /* Flag validation: currently allow no flags */
diff --git a/src/core/surface/channel.c b/src/core/surface/channel.c
index 0016923..12d8ebc 100644
--- a/src/core/surface/channel.c
+++ b/src/core/surface/channel.c
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -80,7 +80,7 @@
 /* the protobuf library will (by default) start warning at 100megs */
 #define DEFAULT_MAX_MESSAGE_LENGTH (100 * 1024 * 1024)
 
-static void destroy_channel(grpc_exec_ctx *exec_ctx, void *arg, int success);
+static void destroy_channel(grpc_exec_ctx *exec_ctx, void *arg, bool success);
 
 grpc_channel *grpc_channel_create_from_filters(
     grpc_exec_ctx *exec_ctx, const char *target,
@@ -268,7 +268,7 @@
 }
 
 static void destroy_channel(grpc_exec_ctx *exec_ctx, void *arg,
-                            int iomgr_success) {
+                            bool iomgr_success) {
   grpc_channel *channel = arg;
   grpc_channel_stack_destroy(exec_ctx, CHANNEL_STACK_FROM_CHANNEL(channel));
   while (channel->registered_calls) {
diff --git a/src/core/surface/channel_connectivity.c b/src/core/surface/channel_connectivity.c
index 10f5c4d..2dd4fce 100644
--- a/src/core/surface/channel_connectivity.c
+++ b/src/core/surface/channel_connectivity.c
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -165,11 +165,11 @@
   }
 }
 
-static void watch_complete(grpc_exec_ctx *exec_ctx, void *pw, int success) {
+static void watch_complete(grpc_exec_ctx *exec_ctx, void *pw, bool success) {
   partly_done(exec_ctx, pw, 1);
 }
 
-static void timeout_complete(grpc_exec_ctx *exec_ctx, void *pw, int success) {
+static void timeout_complete(grpc_exec_ctx *exec_ctx, void *pw, bool success) {
   partly_done(exec_ctx, pw, 0);
 }
 
diff --git a/src/core/surface/channel_create.c b/src/core/surface/channel_create.c
index 49083f08..4d4337d 100644
--- a/src/core/surface/channel_create.c
+++ b/src/core/surface/channel_create.c
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -80,11 +80,11 @@
 }
 
 static void on_initial_connect_string_sent(grpc_exec_ctx *exec_ctx, void *arg,
-                                           int success) {
+                                           bool success) {
   connector_unref(exec_ctx, arg);
 }
 
-static void connected(grpc_exec_ctx *exec_ctx, void *arg, int success) {
+static void connected(grpc_exec_ctx *exec_ctx, void *arg, bool success) {
   connector *c = arg;
   grpc_closure *notify;
   grpc_endpoint *tcp = c->tcp;
diff --git a/src/core/surface/channel_ping.c b/src/core/surface/channel_ping.c
index b4ce282..983f1c8 100644
--- a/src/core/surface/channel_ping.c
+++ b/src/core/surface/channel_ping.c
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -53,7 +53,7 @@
   gpr_free(arg);
 }
 
-static void ping_done(grpc_exec_ctx *exec_ctx, void *arg, int success) {
+static void ping_done(grpc_exec_ctx *exec_ctx, void *arg, bool success) {
   ping_result *pr = arg;
   grpc_cq_end_op(exec_ctx, pr->cq, pr->tag, success, ping_destroy, pr,
                  &pr->completion_storage);
diff --git a/src/core/surface/completion_queue.c b/src/core/surface/completion_queue.c
index c0db9c5..75298eb 100644
--- a/src/core/surface/completion_queue.c
+++ b/src/core/surface/completion_queue.c
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -86,7 +86,7 @@
 grpc_completion_queue *g_freelist;
 
 static void on_pollset_shutdown_done(grpc_exec_ctx *exec_ctx, void *cc,
-                                     int success);
+                                     bool success);
 
 void grpc_cq_global_init(void) { gpr_mu_init(&g_freelist_mu); }
 
@@ -169,7 +169,7 @@
 }
 
 static void on_pollset_shutdown_done(grpc_exec_ctx *exec_ctx, void *arg,
-                                     int success) {
+                                     bool success) {
   grpc_completion_queue *cc = arg;
   GRPC_CQ_INTERNAL_UNREF(cc, "pollset_destroy");
 }
diff --git a/src/core/surface/lame_client.c b/src/core/surface/lame_client.c
index a60e9d2..537069e 100644
--- a/src/core/surface/lame_client.c
+++ b/src/core/surface/lame_client.c
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -78,8 +78,7 @@
   } else if (op->recv_trailing_metadata != NULL) {
     fill_metadata(elem, op->recv_trailing_metadata);
   }
-  grpc_exec_ctx_enqueue(exec_ctx, op->on_complete, 0);
-  grpc_exec_ctx_enqueue(exec_ctx, op->recv_message_ready, 0);
+  grpc_transport_stream_op_finish_with_failure(exec_ctx, op);
 }
 
 static char *lame_get_peer(grpc_exec_ctx *exec_ctx, grpc_call_element *elem) {
diff --git a/src/core/surface/secure_channel_create.c b/src/core/surface/secure_channel_create.c
index 552a570..dd1441a 100644
--- a/src/core/surface/secure_channel_create.c
+++ b/src/core/surface/secure_channel_create.c
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -128,14 +128,14 @@
 }
 
 static void on_initial_connect_string_sent(grpc_exec_ctx *exec_ctx, void *arg,
-                                           int success) {
+                                           bool success) {
   connector *c = arg;
   grpc_security_connector_do_handshake(exec_ctx, &c->security_connector->base,
                                        c->connecting_endpoint,
                                        on_secure_handshake_done, c);
 }
 
-static void connected(grpc_exec_ctx *exec_ctx, void *arg, int success) {
+static void connected(grpc_exec_ctx *exec_ctx, void *arg, bool success) {
   connector *c = arg;
   grpc_closure *notify;
   grpc_endpoint *tcp = c->newly_connecting_endpoint;
diff --git a/src/core/surface/server.c b/src/core/surface/server.c
index 79db138..fb5e0d4 100644
--- a/src/core/surface/server.c
+++ b/src/core/surface/server.c
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -260,7 +260,7 @@
 };
 
 static void shutdown_cleanup(grpc_exec_ctx *exec_ctx, void *arg,
-                             int iomgr_status_ignored) {
+                             bool iomgr_status_ignored) {
   struct shutdown_cleanup_args *a = arg;
   gpr_slice_unref(a->slice);
   gpr_free(a);
@@ -313,7 +313,7 @@
   gpr_stack_lockfree_destroy(rm->requests);
 }
 
-static void kill_zombie(grpc_exec_ctx *exec_ctx, void *elem, int success) {
+static void kill_zombie(grpc_exec_ctx *exec_ctx, void *elem, bool success) {
   grpc_call_destroy(grpc_call_from_top_element(elem));
 }
 
@@ -328,7 +328,7 @@
     grpc_closure_init(
         &calld->kill_zombie_closure, kill_zombie,
         grpc_call_stack_element(grpc_call_get_call_stack(calld->call), 0));
-    grpc_exec_ctx_enqueue(exec_ctx, &calld->kill_zombie_closure, 1);
+    grpc_exec_ctx_enqueue(exec_ctx, &calld->kill_zombie_closure, true, NULL);
   }
 }
 
@@ -392,7 +392,7 @@
 }
 
 static void finish_destroy_channel(grpc_exec_ctx *exec_ctx, void *cd,
-                                   int success) {
+                                   bool success) {
   channel_data *chand = cd;
   grpc_server *server = chand->server;
   GRPC_CHANNEL_INTERNAL_UNREF(exec_ctx, chand->channel, "server");
@@ -407,7 +407,8 @@
   maybe_finish_shutdown(exec_ctx, chand->server);
   chand->finish_destroy_channel_closure.cb = finish_destroy_channel;
   chand->finish_destroy_channel_closure.cb_arg = chand;
-  grpc_exec_ctx_enqueue(exec_ctx, &chand->finish_destroy_channel_closure, 1);
+  grpc_exec_ctx_enqueue(exec_ctx, &chand->finish_destroy_channel_closure, true,
+                        NULL);
 }
 
 static void finish_start_new_rpc(grpc_exec_ctx *exec_ctx, grpc_server *server,
@@ -420,7 +421,7 @@
     calld->state = ZOMBIED;
     gpr_mu_unlock(&calld->mu_state);
     grpc_closure_init(&calld->kill_zombie_closure, kill_zombie, elem);
-    grpc_exec_ctx_enqueue(exec_ctx, &calld->kill_zombie_closure, 1);
+    grpc_exec_ctx_enqueue(exec_ctx, &calld->kill_zombie_closure, true, NULL);
     return;
   }
 
@@ -569,7 +570,7 @@
 }
 
 static void server_on_recv_initial_metadata(grpc_exec_ctx *exec_ctx, void *ptr,
-                                            int success) {
+                                            bool success) {
   grpc_call_element *elem = ptr;
   call_data *calld = elem->call_data;
   gpr_timespec op_deadline;
@@ -595,8 +596,8 @@
 
   if (op->recv_initial_metadata != NULL) {
     calld->recv_initial_metadata = op->recv_initial_metadata;
-    calld->on_done_recv_initial_metadata = op->on_complete;
-    op->on_complete = &calld->server_on_recv_initial_metadata;
+    calld->on_done_recv_initial_metadata = op->recv_initial_metadata_ready;
+    op->recv_initial_metadata_ready = &calld->server_on_recv_initial_metadata;
   }
 }
 
@@ -609,7 +610,7 @@
 }
 
 static void got_initial_metadata(grpc_exec_ctx *exec_ctx, void *ptr,
-                                 int success) {
+                                 bool success) {
   grpc_call_element *elem = ptr;
   call_data *calld = elem->call_data;
   if (success) {
@@ -620,7 +621,7 @@
       calld->state = ZOMBIED;
       gpr_mu_unlock(&calld->mu_state);
       grpc_closure_init(&calld->kill_zombie_closure, kill_zombie, elem);
-      grpc_exec_ctx_enqueue(exec_ctx, &calld->kill_zombie_closure, 1);
+      grpc_exec_ctx_enqueue(exec_ctx, &calld->kill_zombie_closure, true, NULL);
     } else if (calld->state == PENDING) {
       calld->state = ZOMBIED;
       gpr_mu_unlock(&calld->mu_state);
@@ -653,7 +654,7 @@
 }
 
 static void channel_connectivity_changed(grpc_exec_ctx *exec_ctx, void *cd,
-                                         int iomgr_status_ignored) {
+                                         bool iomgr_status_ignored) {
   channel_data *chand = cd;
   grpc_server *server = chand->server;
   if (chand->connectivity_state != GRPC_CHANNEL_FATAL_FAILURE) {
@@ -779,9 +780,7 @@
     const grpc_channel_filter **filters, size_t filter_count,
     const grpc_channel_args *args) {
   size_t i;
-  /* TODO(census): restore this once we finalize census filter etc.
-     int census_enabled = grpc_channel_args_is_census_enabled(args); */
-  int census_enabled = 0;
+  int census_enabled = grpc_channel_args_is_census_enabled(args);
 
   grpc_server *server = gpr_malloc(sizeof(grpc_server));
 
@@ -987,7 +986,7 @@
 }
 
 static void listener_destroy_done(grpc_exec_ctx *exec_ctx, void *s,
-                                  int success) {
+                                  bool success) {
   grpc_server *server = s;
   gpr_mu_lock(&server->mu_global);
   server->listeners_destroyed++;
@@ -1142,7 +1141,8 @@
         grpc_closure_init(
             &calld->kill_zombie_closure, kill_zombie,
             grpc_call_stack_element(grpc_call_get_call_stack(calld->call), 0));
-        grpc_exec_ctx_enqueue(exec_ctx, &calld->kill_zombie_closure, 1);
+        grpc_exec_ctx_enqueue(exec_ctx, &calld->kill_zombie_closure, true,
+                              NULL);
       } else {
         GPR_ASSERT(calld->state == PENDING);
         calld->state = ACTIVATED;
@@ -1231,7 +1231,7 @@
 }
 
 static void publish_registered_or_batch(grpc_exec_ctx *exec_ctx,
-                                        void *user_data, int success);
+                                        void *user_data, bool success);
 
 static void cpstr(char **dest, size_t *capacity, grpc_mdstr *value) {
   gpr_slice slice = value->slice;
@@ -1317,7 +1317,7 @@
 }
 
 static void publish_registered_or_batch(grpc_exec_ctx *exec_ctx, void *prc,
-                                        int success) {
+                                        bool success) {
   requested_call *rc = prc;
   grpc_call *call = *rc->call;
   grpc_call_element *elem =
diff --git a/src/core/surface/server_chttp2.c b/src/core/surface/server_chttp2.c
index 6e21d2d..ce970df 100644
--- a/src/core/surface/server_chttp2.c
+++ b/src/core/surface/server_chttp2.c
@@ -82,7 +82,7 @@
                     grpc_closure *destroy_done) {
   grpc_tcp_server *tcp = tcpp;
   grpc_tcp_server_unref(exec_ctx, tcp);
-  grpc_exec_ctx_enqueue(exec_ctx, destroy_done, 1);
+  grpc_exec_ctx_enqueue(exec_ctx, destroy_done, true, NULL);
 }
 
 int grpc_server_add_insecure_http2_port(grpc_server *server, const char *addr) {
diff --git a/src/core/surface/server_create.c b/src/core/surface/server_create.c
index f30093e..5e37e80 100644
--- a/src/core/surface/server_create.c
+++ b/src/core/surface/server_create.c
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -43,9 +43,6 @@
   const grpc_channel_filter *filters[3];
   size_t num_filters = 0;
   filters[num_filters++] = &grpc_compress_filter;
-  if (grpc_channel_args_is_census_enabled(args)) {
-    filters[num_filters++] = &grpc_server_census_filter;
-  }
   GRPC_API_TRACE("grpc_server_create(%p, %p)", 2, (args, reserved));
   return grpc_server_create_from_filters(filters, num_filters, args);
 }
diff --git a/src/core/surface/version.c b/src/core/surface/version.c
index 262a13f..7723f39 100644
--- a/src/core/surface/version.c
+++ b/src/core/surface/version.c
@@ -36,4 +36,4 @@
 
 #include <grpc/grpc.h>
 
-const char *grpc_version_string(void) { return "0.13.0.0"; }
+const char *grpc_version_string(void) { return "0.14.0-dev"; }
diff --git a/src/core/transport/chttp2/hpack_encoder.c b/src/core/transport/chttp2/hpack_encoder.c
index 89a80d8..f30f574 100644
--- a/src/core/transport/chttp2/hpack_encoder.c
+++ b/src/core/transport/chttp2/hpack_encoder.c
@@ -283,7 +283,7 @@
   len_val_len = GRPC_CHTTP2_VARINT_LENGTH((uint32_t)len_val, 1);
   GRPC_CHTTP2_WRITE_VARINT(key_index, 2, 0x40,
                            add_tiny_header_data(st, len_pfx), len_pfx);
-  GRPC_CHTTP2_WRITE_VARINT((uint32_t)len_val, 1, 0x00,
+  GRPC_CHTTP2_WRITE_VARINT((uint32_t)len_val, 1, huffman_prefix,
                            add_tiny_header_data(st, len_val_len), len_val_len);
   add_header_data(st, gpr_slice_ref(value_slice));
 }
@@ -300,7 +300,7 @@
   len_val_len = GRPC_CHTTP2_VARINT_LENGTH((uint32_t)len_val, 1);
   GRPC_CHTTP2_WRITE_VARINT(key_index, 4, 0x00,
                            add_tiny_header_data(st, len_pfx), len_pfx);
-  GRPC_CHTTP2_WRITE_VARINT((uint32_t)len_val, 1, 0x00,
+  GRPC_CHTTP2_WRITE_VARINT((uint32_t)len_val, 1, huffman_prefix,
                            add_tiny_header_data(st, len_val_len), len_val_len);
   add_header_data(st, gpr_slice_ref(value_slice));
 }
diff --git a/src/core/transport/chttp2/internal.h b/src/core/transport/chttp2/internal.h
index a8262b7..0e1e2c4 100644
--- a/src/core/transport/chttp2/internal.h
+++ b/src/core/transport/chttp2/internal.h
@@ -35,6 +35,7 @@
 #define GRPC_INTERNAL_CORE_CHTTP2_INTERNAL_H
 
 #include <assert.h>
+#include <stdbool.h>
 
 #include "src/core/iomgr/endpoint.h"
 #include "src/core/transport/chttp2/frame.h"
@@ -67,6 +68,9 @@
   GRPC_CHTTP2_LIST_CLOSED_WAITING_FOR_PARSING,
   GRPC_CHTTP2_LIST_CLOSED_WAITING_FOR_WRITING,
   GRPC_CHTTP2_LIST_STALLED_BY_TRANSPORT,
+  /* streams waiting for the outgoing window in the writing path, they will be
+   * merged to the stalled list or writable list under transport lock. */
+  GRPC_CHTTP2_LIST_WRITING_STALLED_BY_TRANSPORT,
   /** streams that are waiting to start because there are too many concurrent
       streams on the connection */
   GRPC_CHTTP2_LIST_WAITING_FOR_CONCURRENCY,
@@ -381,7 +385,7 @@
   grpc_closure *send_trailing_metadata_finished;
 
   grpc_metadata_batch *recv_initial_metadata;
-  grpc_closure *recv_initial_metadata_finished;
+  grpc_closure *recv_initial_metadata_ready;
   grpc_byte_stream **recv_message;
   grpc_closure *recv_message_ready;
   grpc_metadata_batch *recv_trailing_metadata;
@@ -488,7 +492,7 @@
     grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_writing *transport_writing,
     grpc_endpoint *endpoint);
 void grpc_chttp2_terminate_writing(grpc_exec_ctx *exec_ctx,
-                                   void *transport_writing, int success);
+                                   void *transport_writing, bool success);
 void grpc_chttp2_cleanup_writing(grpc_exec_ctx *exec_ctx,
                                  grpc_chttp2_transport_global *global,
                                  grpc_chttp2_transport_writing *writing);
@@ -504,11 +508,11 @@
                                grpc_chttp2_transport_global *global,
                                grpc_chttp2_transport_parsing *parsing);
 
-/** Get a writable stream
-    returns non-zero if there was a stream available */
 void grpc_chttp2_list_add_writable_stream(
     grpc_chttp2_transport_global *transport_global,
     grpc_chttp2_stream_global *stream_global);
+/** Get a writable stream
+    returns non-zero if there was a stream available */
 int grpc_chttp2_list_pop_writable_stream(
     grpc_chttp2_transport_global *transport_global,
     grpc_chttp2_transport_writing *transport_writing,
@@ -560,9 +564,12 @@
     grpc_chttp2_transport_global *transport_global,
     grpc_chttp2_stream_global **stream_global);
 
-void grpc_chttp2_list_add_stalled_by_transport(
+void grpc_chttp2_list_add_writing_stalled_by_transport(
     grpc_chttp2_transport_writing *transport_writing,
     grpc_chttp2_stream_writing *stream_writing);
+void grpc_chttp2_list_flush_writing_stalled_by_transport(
+    grpc_chttp2_transport_writing *transport_writing, bool is_window_available);
+
 int grpc_chttp2_list_pop_stalled_by_transport(
     grpc_chttp2_transport_global *transport_global,
     grpc_chttp2_stream_global **stream_global);
diff --git a/src/core/transport/chttp2/stream_lists.c b/src/core/transport/chttp2/stream_lists.c
index 273a513..2f31a47 100644
--- a/src/core/transport/chttp2/stream_lists.c
+++ b/src/core/transport/chttp2/stream_lists.c
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -313,12 +313,27 @@
   return r;
 }
 
-void grpc_chttp2_list_add_stalled_by_transport(
+void grpc_chttp2_list_add_writing_stalled_by_transport(
     grpc_chttp2_transport_writing *transport_writing,
     grpc_chttp2_stream_writing *stream_writing) {
   stream_list_add(TRANSPORT_FROM_WRITING(transport_writing),
                   STREAM_FROM_WRITING(stream_writing),
-                  GRPC_CHTTP2_LIST_STALLED_BY_TRANSPORT);
+                  GRPC_CHTTP2_LIST_WRITING_STALLED_BY_TRANSPORT);
+}
+
+void grpc_chttp2_list_flush_writing_stalled_by_transport(
+    grpc_chttp2_transport_writing *transport_writing,
+    bool is_window_available) {
+  grpc_chttp2_stream *stream;
+  grpc_chttp2_transport *transport = TRANSPORT_FROM_WRITING(transport_writing);
+  while (stream_list_pop(transport, &stream,
+                         GRPC_CHTTP2_LIST_WRITING_STALLED_BY_TRANSPORT)) {
+    if (is_window_available) {
+      grpc_chttp2_list_add_writable_stream(&transport->global, &stream->global);
+    } else {
+      stream_list_add(transport, stream, GRPC_CHTTP2_LIST_STALLED_BY_TRANSPORT);
+    }
+  }
 }
 
 int grpc_chttp2_list_pop_stalled_by_transport(
diff --git a/src/core/transport/chttp2/writing.c b/src/core/transport/chttp2/writing.c
index fdad05b..cafecf1 100644
--- a/src/core/transport/chttp2/writing.c
+++ b/src/core/transport/chttp2/writing.c
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -75,6 +75,9 @@
 
   GRPC_CHTTP2_FLOW_MOVE_TRANSPORT("write", transport_writing, outgoing_window,
                                   transport_global, outgoing_window);
+  bool is_window_available = transport_writing->outgoing_window > 0;
+  grpc_chttp2_list_flush_writing_stalled_by_transport(transport_writing,
+                                                      is_window_available);
 
   /* for each grpc_chttp2_stream that's become writable, frame it's data
      (according to available window sizes) and add to the output buffer */
@@ -130,8 +133,8 @@
             GRPC_CHTTP2_STREAM_REF(stream_global, "chttp2_writing");
           }
         } else {
-          grpc_chttp2_list_add_stalled_by_transport(transport_writing,
-                                                    stream_writing);
+          grpc_chttp2_list_add_writing_stalled_by_transport(transport_writing,
+                                                            stream_writing);
         }
       }
       if (stream_global->send_trailing_metadata) {
@@ -188,7 +191,7 @@
     grpc_endpoint_write(exec_ctx, endpoint, &transport_writing->outbuf,
                         &transport_writing->done_cb);
   } else {
-    grpc_exec_ctx_enqueue(exec_ctx, &transport_writing->done_cb, 1);
+    grpc_exec_ctx_enqueue(exec_ctx, &transport_writing->done_cb, true, NULL);
   }
 }
 
@@ -273,8 +276,8 @@
           stream_writing->sent_message = 1;
         }
       } else if (transport_writing->outgoing_window == 0) {
-        grpc_chttp2_list_add_stalled_by_transport(transport_writing,
-                                                  stream_writing);
+        grpc_chttp2_list_add_writing_stalled_by_transport(transport_writing,
+                                                          stream_writing);
         grpc_chttp2_list_add_written_stream(transport_writing, stream_writing);
       }
     }
@@ -312,8 +315,8 @@
           /* do nothing - already reffed */
         }
       } else {
-        grpc_chttp2_list_add_stalled_by_transport(transport_writing,
-                                                  stream_writing);
+        grpc_chttp2_list_add_writing_stalled_by_transport(transport_writing,
+                                                          stream_writing);
         grpc_chttp2_list_add_written_stream(transport_writing, stream_writing);
       }
     } else {
diff --git a/src/core/transport/chttp2_transport.c b/src/core/transport/chttp2_transport.c
index 05b25fd..617d988 100644
--- a/src/core/transport/chttp2_transport.c
+++ b/src/core/transport/chttp2_transport.c
@@ -86,14 +86,14 @@
 
 /* forward declarations of various callbacks that we'll build closures around */
 static void writing_action(grpc_exec_ctx *exec_ctx, void *t,
-                           int iomgr_success_ignored);
+                           bool iomgr_success_ignored);
 
 /** Set a transport level setting, and push it to our peer */
 static void push_setting(grpc_chttp2_transport *t, grpc_chttp2_setting_id id,
                          uint32_t value);
 
 /** Endpoint callback to process incoming data */
-static void recv_data(grpc_exec_ctx *exec_ctx, void *tp, int success);
+static void recv_data(grpc_exec_ctx *exec_ctx, void *tp, bool success);
 
 /** Start disconnection chain */
 static void drop_connection(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t);
@@ -183,7 +183,7 @@
      and maybe they hold resources that need to be freed */
   while (t->global.pings.next != &t->global.pings) {
     grpc_chttp2_outstanding_ping *ping = t->global.pings.next;
-    grpc_exec_ctx_enqueue(exec_ctx, ping->on_recv, 0);
+    grpc_exec_ctx_enqueue(exec_ctx, ping->on_recv, false, NULL);
     ping->next->prev = ping->prev;
     ping->prev->next = ping->next;
     gpr_free(ping);
@@ -544,7 +544,7 @@
   GPR_ASSERT(s->global.send_initial_metadata_finished == NULL);
   GPR_ASSERT(s->global.send_message_finished == NULL);
   GPR_ASSERT(s->global.send_trailing_metadata_finished == NULL);
-  GPR_ASSERT(s->global.recv_initial_metadata_finished == NULL);
+  GPR_ASSERT(s->global.recv_initial_metadata_ready == NULL);
   GPR_ASSERT(s->global.recv_message_ready == NULL);
   GPR_ASSERT(s->global.recv_trailing_metadata_finished == NULL);
   grpc_chttp2_data_parser_destroy(exec_ctx, &s->parsing.data_parser);
@@ -602,7 +602,7 @@
                                          t->parsing_active)) {
     t->writing_active = 1;
     REF_TRANSPORT(t, "writing");
-    grpc_exec_ctx_enqueue(exec_ctx, &t->writing_action, 1);
+    grpc_exec_ctx_enqueue(exec_ctx, &t->writing_action, true, NULL);
     prevent_endpoint_shutdown(t);
   }
   check_read_ops(exec_ctx, &t->global);
@@ -631,7 +631,7 @@
 }
 
 void grpc_chttp2_terminate_writing(grpc_exec_ctx *exec_ctx,
-                                   void *transport_writing_ptr, int success) {
+                                   void *transport_writing_ptr, bool success) {
   grpc_chttp2_transport_writing *transport_writing = transport_writing_ptr;
   grpc_chttp2_transport *t = TRANSPORT_FROM_WRITING(transport_writing);
   grpc_chttp2_stream_global *stream_global;
@@ -669,7 +669,7 @@
 }
 
 static void writing_action(grpc_exec_ctx *exec_ctx, void *gt,
-                           int iomgr_success_ignored) {
+                           bool iomgr_success_ignored) {
   grpc_chttp2_transport *t = gt;
   GPR_TIMER_BEGIN("writing_action", 0);
   grpc_chttp2_perform_writes(exec_ctx, &t->writing, t->ep);
@@ -759,7 +759,7 @@
     closure->final_data |= 1;
   }
   if (closure->final_data < 2) {
-    grpc_exec_ctx_enqueue(exec_ctx, closure, closure->final_data == 0);
+    grpc_exec_ctx_enqueue(exec_ctx, closure, closure->final_data == 0, NULL);
   }
   *pclosure = NULL;
 }
@@ -777,7 +777,7 @@
   return 0;
 }
 
-static void do_nothing(grpc_exec_ctx *exec_ctx, void *arg, int success) {}
+static void do_nothing(grpc_exec_ctx *exec_ctx, void *arg, bool success) {}
 
 static void perform_stream_op_locked(
     grpc_exec_ctx *exec_ctx, grpc_chttp2_transport_global *transport_global,
@@ -863,9 +863,9 @@
   }
 
   if (op->recv_initial_metadata != NULL) {
-    GPR_ASSERT(stream_global->recv_initial_metadata_finished == NULL);
-    stream_global->recv_initial_metadata_finished =
-        add_closure_barrier(on_complete);
+    GPR_ASSERT(stream_global->recv_initial_metadata_ready == NULL);
+    stream_global->recv_initial_metadata_ready =
+        op->recv_initial_metadata_ready;
     stream_global->recv_initial_metadata = op->recv_initial_metadata;
     grpc_chttp2_list_add_check_read_ops(transport_global, stream_global);
   }
@@ -934,7 +934,7 @@
   for (ping = transport_global->pings.next; ping != &transport_global->pings;
        ping = ping->next) {
     if (0 == memcmp(opaque_8bytes, ping->id, 8)) {
-      grpc_exec_ctx_enqueue(exec_ctx, ping->on_recv, 1);
+      grpc_exec_ctx_enqueue(exec_ctx, ping->on_recv, true, NULL);
       ping->next->prev = ping->prev;
       ping->prev->next = ping->next;
       gpr_free(ping);
@@ -951,7 +951,7 @@
 
   lock(t);
 
-  grpc_exec_ctx_enqueue(exec_ctx, op->on_consumed, 1);
+  grpc_exec_ctx_enqueue(exec_ctx, op->on_consumed, true, NULL);
 
   if (op->on_connectivity_state_change != NULL) {
     grpc_connectivity_state_notify_on_state_change(
@@ -1009,24 +1009,27 @@
   grpc_byte_stream *bs;
   while (
       grpc_chttp2_list_pop_check_read_ops(transport_global, &stream_global)) {
-    if (stream_global->recv_initial_metadata_finished != NULL &&
+    if (stream_global->recv_initial_metadata_ready != NULL &&
         stream_global->published_initial_metadata) {
       grpc_chttp2_incoming_metadata_buffer_publish(
           &stream_global->received_initial_metadata,
           stream_global->recv_initial_metadata);
-      grpc_chttp2_complete_closure_step(
-          exec_ctx, &stream_global->recv_initial_metadata_finished, 1);
+      grpc_exec_ctx_enqueue(
+          exec_ctx, stream_global->recv_initial_metadata_ready, true, NULL);
+      stream_global->recv_initial_metadata_ready = NULL;
     }
     if (stream_global->recv_message_ready != NULL) {
       if (stream_global->incoming_frames.head != NULL) {
         *stream_global->recv_message = grpc_chttp2_incoming_frame_queue_pop(
             &stream_global->incoming_frames);
         GPR_ASSERT(*stream_global->recv_message != NULL);
-        grpc_exec_ctx_enqueue(exec_ctx, stream_global->recv_message_ready, 1);
+        grpc_exec_ctx_enqueue(exec_ctx, stream_global->recv_message_ready, true,
+                              NULL);
         stream_global->recv_message_ready = NULL;
       } else if (stream_global->published_trailing_metadata) {
         *stream_global->recv_message = NULL;
-        grpc_exec_ctx_enqueue(exec_ctx, stream_global->recv_message_ready, 1);
+        grpc_exec_ctx_enqueue(exec_ctx, stream_global->recv_message_ready, true,
+                              NULL);
         stream_global->recv_message_ready = NULL;
       }
     }
@@ -1336,7 +1339,7 @@
 }
 
 /* tcp read callback */
-static void recv_data(grpc_exec_ctx *exec_ctx, void *tp, int success) {
+static void recv_data(grpc_exec_ctx *exec_ctx, void *tp, bool success) {
   size_t i;
   int keep_reading = 0;
   grpc_chttp2_transport *t = tp;
@@ -1523,7 +1526,7 @@
     unlock(exec_ctx, bs->transport);
     return 1;
   } else if (bs->failed) {
-    grpc_exec_ctx_enqueue(exec_ctx, on_complete, 0);
+    grpc_exec_ctx_enqueue(exec_ctx, on_complete, false, NULL);
     unlock(exec_ctx, bs->transport);
     return 0;
   } else {
@@ -1552,7 +1555,7 @@
   gpr_mu_lock(&bs->transport->mu);
   if (bs->on_next != NULL) {
     *bs->next = slice;
-    grpc_exec_ctx_enqueue(exec_ctx, bs->on_next, 1);
+    grpc_exec_ctx_enqueue(exec_ctx, bs->on_next, true, NULL);
     bs->on_next = NULL;
   } else {
     gpr_slice_buffer_add(&bs->slices, slice);
@@ -1567,7 +1570,7 @@
     if (from_parsing_thread) {
       gpr_mu_lock(&bs->transport->mu);
     }
-    grpc_exec_ctx_enqueue(exec_ctx, bs->on_next, 0);
+    grpc_exec_ctx_enqueue(exec_ctx, bs->on_next, false, NULL);
     bs->on_next = NULL;
     bs->failed = 1;
     if (from_parsing_thread) {
diff --git a/src/core/transport/connectivity_state.c b/src/core/transport/connectivity_state.c
index 3c3fd46..87765b9 100644
--- a/src/core/transport/connectivity_state.c
+++ b/src/core/transport/connectivity_state.c
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -78,7 +78,7 @@
     } else {
       success = 0;
     }
-    grpc_exec_ctx_enqueue(exec_ctx, w->notify, success);
+    grpc_exec_ctx_enqueue(exec_ctx, w->notify, success, NULL);
     gpr_free(w);
   }
   gpr_free(tracker->name);
@@ -109,7 +109,7 @@
   if (current == NULL) {
     grpc_connectivity_state_watcher *w = tracker->watchers;
     if (w != NULL && w->notify == notify) {
-      grpc_exec_ctx_enqueue(exec_ctx, notify, 0);
+      grpc_exec_ctx_enqueue(exec_ctx, notify, false, NULL);
       tracker->watchers = w->next;
       gpr_free(w);
       return 0;
@@ -117,7 +117,7 @@
     while (w != NULL) {
       grpc_connectivity_state_watcher *rm_candidate = w->next;
       if (rm_candidate != NULL && rm_candidate->notify == notify) {
-        grpc_exec_ctx_enqueue(exec_ctx, notify, 0);
+        grpc_exec_ctx_enqueue(exec_ctx, notify, false, NULL);
         w->next = w->next->next;
         gpr_free(rm_candidate);
         return 0;
@@ -128,7 +128,7 @@
   } else {
     if (tracker->current_state != *current) {
       *current = tracker->current_state;
-      grpc_exec_ctx_enqueue(exec_ctx, notify, 1);
+      grpc_exec_ctx_enqueue(exec_ctx, notify, true, NULL);
     } else {
       grpc_connectivity_state_watcher *w = gpr_malloc(sizeof(*w));
       w->current = current;
@@ -158,7 +158,7 @@
   while ((w = tracker->watchers) != NULL) {
     *w->current = tracker->current_state;
     tracker->watchers = w->next;
-    grpc_exec_ctx_enqueue(exec_ctx, w->notify, 1);
+    grpc_exec_ctx_enqueue(exec_ctx, w->notify, true, NULL);
     gpr_free(w);
   }
 }
diff --git a/src/core/transport/static_metadata.c b/src/core/transport/static_metadata.c
index 233e5c0..eeedae0 100644
--- a/src/core/transport/static_metadata.c
+++ b/src/core/transport/static_metadata.c
@@ -35,11 +35,11 @@
  * WARNING: Auto-generated code.
  *
  * To make changes to this file, change
- *tools/codegen/core/gen_static_metadata.py,
+ * tools/codegen/core/gen_static_metadata.py,
  * and then re-run it.
  *
  * See metadata.h for an explanation of the interface here, and metadata.c for
- *an
+ * an
  * explanation of what's going on.
  */
 
@@ -69,21 +69,21 @@
     "0", "1", "2", "200", "204", "206", "304", "400", "404", "500", "accept",
     "accept-charset", "accept-encoding", "accept-language", "accept-ranges",
     "access-control-allow-origin", "age", "allow", "application/grpc",
-    ":authority", "authorization", "cache-control", "census", "census-bin",
-    "content-disposition", "content-encoding", "content-language",
-    "content-length", "content-location", "content-range", "content-type",
-    "cookie", "date", "deflate", "deflate,gzip", "", "etag", "expect",
-    "expires", "from", "GET", "grpc", "grpc-accept-encoding", "grpc-encoding",
-    "grpc-internal-encoding-request", "grpc-message", "grpc-status",
-    "grpc-timeout", "gzip", "gzip, deflate", "host", "http", "https",
-    "identity", "identity,deflate", "identity,deflate,gzip", "identity,gzip",
-    "if-match", "if-modified-since", "if-none-match", "if-range",
-    "if-unmodified-since", "last-modified", "link", "location", "max-forwards",
-    ":method", ":path", "POST", "proxy-authenticate", "proxy-authorization",
-    "range", "referer", "refresh", "retry-after", ":scheme", "server",
-    "set-cookie", "/", "/index.html", ":status", "strict-transport-security",
-    "te", "trailers", "transfer-encoding", "user-agent", "vary", "via",
-    "www-authenticate"};
+    ":authority", "authorization", "cache-control", "census-bin",
+    "census-binary-bin", "content-disposition", "content-encoding",
+    "content-language", "content-length", "content-location", "content-range",
+    "content-type", "cookie", "date", "deflate", "deflate,gzip", "", "etag",
+    "expect", "expires", "from", "GET", "grpc", "grpc-accept-encoding",
+    "grpc-encoding", "grpc-internal-encoding-request", "grpc-message",
+    "grpc-status", "grpc-timeout", "gzip", "gzip, deflate", "host", "http",
+    "https", "identity", "identity,deflate", "identity,deflate,gzip",
+    "identity,gzip", "if-match", "if-modified-since", "if-none-match",
+    "if-range", "if-unmodified-since", "last-modified", "link", "location",
+    "max-forwards", ":method", ":path", "POST", "proxy-authenticate",
+    "proxy-authorization", "range", "referer", "refresh", "retry-after",
+    ":scheme", "server", "set-cookie", "/", "/index.html", ":status",
+    "strict-transport-security", "te", "trailers", "transfer-encoding",
+    "user-agent", "vary", "via", "www-authenticate"};
 
 const uint8_t grpc_static_accept_encoding_metadata[8] = {0,  29, 26, 30,
                                                          28, 32, 27, 31};
diff --git a/src/core/transport/static_metadata.h b/src/core/transport/static_metadata.h
index 3803a04..ef72b80 100644
--- a/src/core/transport/static_metadata.h
+++ b/src/core/transport/static_metadata.h
@@ -94,10 +94,10 @@
 #define GRPC_MDSTR_AUTHORIZATION (&grpc_static_mdstr_table[20])
 /* "cache-control" */
 #define GRPC_MDSTR_CACHE_CONTROL (&grpc_static_mdstr_table[21])
-/* "census" */
-#define GRPC_MDSTR_CENSUS (&grpc_static_mdstr_table[22])
 /* "census-bin" */
-#define GRPC_MDSTR_CENSUS_BIN (&grpc_static_mdstr_table[23])
+#define GRPC_MDSTR_CENSUS_BIN (&grpc_static_mdstr_table[22])
+/* "census-binary-bin" */
+#define GRPC_MDSTR_CENSUS_BINARY_BIN (&grpc_static_mdstr_table[23])
 /* "content-disposition" */
 #define GRPC_MDSTR_CONTENT_DISPOSITION (&grpc_static_mdstr_table[24])
 /* "content-encoding" */
diff --git a/src/core/transport/transport.c b/src/core/transport/transport.c
index 2ab978b..6e154b6 100644
--- a/src/core/transport/transport.c
+++ b/src/core/transport/transport.c
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -59,7 +59,7 @@
                        grpc_stream_refcount *refcount) {
 #endif
   if (gpr_unref(&refcount->refs)) {
-    grpc_exec_ctx_enqueue(exec_ctx, &refcount->destroy, 1);
+    grpc_exec_ctx_enqueue(exec_ctx, &refcount->destroy, true, NULL);
   }
 }
 
@@ -125,8 +125,9 @@
 
 void grpc_transport_stream_op_finish_with_failure(
     grpc_exec_ctx *exec_ctx, grpc_transport_stream_op *op) {
-  grpc_exec_ctx_enqueue(exec_ctx, op->recv_message_ready, 0);
-  grpc_exec_ctx_enqueue(exec_ctx, op->on_complete, 0);
+  grpc_exec_ctx_enqueue(exec_ctx, op->recv_message_ready, false, NULL);
+  grpc_exec_ctx_enqueue(exec_ctx, op->recv_initial_metadata_ready, false, NULL);
+  grpc_exec_ctx_enqueue(exec_ctx, op->on_complete, false, NULL);
 }
 
 void grpc_transport_stream_op_add_cancellation(grpc_transport_stream_op *op,
@@ -150,7 +151,7 @@
   grpc_closure closure;
 } close_message_data;
 
-static void free_message(grpc_exec_ctx *exec_ctx, void *p, int iomgr_success) {
+static void free_message(grpc_exec_ctx *exec_ctx, void *p, bool iomgr_success) {
   close_message_data *cmd = p;
   gpr_slice_unref(cmd->message);
   if (cmd->then_call != NULL) {
diff --git a/src/core/transport/transport.h b/src/core/transport/transport.h
index f94f0ae..8902c5d 100644
--- a/src/core/transport/transport.h
+++ b/src/core/transport/transport.h
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -81,16 +81,32 @@
 /* Transport stream op: a set of operations to perform on a transport
    against a single stream */
 typedef struct grpc_transport_stream_op {
+  /** Send initial metadata to the peer, from the provided metadata batch. */
   grpc_metadata_batch *send_initial_metadata;
+
+  /** Send trailing metadata to the peer, from the provided metadata batch. */
   grpc_metadata_batch *send_trailing_metadata;
 
+  /** Send message data to the peer, from the provided byte stream. */
   grpc_byte_stream *send_message;
 
+  /** Receive initial metadata from the stream, into provided metadata batch. */
   grpc_metadata_batch *recv_initial_metadata;
+  /** Should be enqueued when initial metadata is ready to be processed. */
+  grpc_closure *recv_initial_metadata_ready;
+
+  /** Receive message data from the stream, into provided byte stream. */
   grpc_byte_stream **recv_message;
+  /** Should be enqueued when one message is ready to be processed. */
   grpc_closure *recv_message_ready;
+
+  /** Receive trailing metadata from the stream, into provided metadata batch.
+   */
   grpc_metadata_batch *recv_trailing_metadata;
 
+  /** Should be enqueued when all requested operations (excluding recv_message
+      and recv_initial_metadata which have their own closures) in a given batch
+      have been completed. */
   grpc_closure *on_complete;
 
   /** If != GRPC_STATUS_OK, cancel this stream */
diff --git a/src/cpp/client/channel.cc b/src/cpp/client/channel.cc
index c7974d6..ae20392 100644
--- a/src/cpp/client/channel.cc
+++ b/src/cpp/client/channel.cc
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -35,24 +35,29 @@
 
 #include <memory>
 
-#include <grpc/grpc.h>
-#include <grpc/support/log.h>
-#include <grpc/support/slice.h>
 #include <grpc++/client_context.h>
 #include <grpc++/completion_queue.h>
-#include <grpc++/security/credentials.h>
 #include <grpc++/impl/call.h>
+#include <grpc++/impl/codegen/completion_queue_tag.h>
+#include <grpc++/impl/grpc_library.h>
 #include <grpc++/impl/rpc_method.h>
+#include <grpc++/security/credentials.h>
 #include <grpc++/support/channel_arguments.h>
 #include <grpc++/support/config.h>
 #include <grpc++/support/status.h>
 #include <grpc++/support/time.h>
+#include <grpc/grpc.h>
+#include <grpc/support/log.h>
+#include <grpc/support/slice.h>
 #include "src/core/profiling/timers.h"
 
 namespace grpc {
 
+static internal::GrpcLibraryInitializer g_gli_initializer;
 Channel::Channel(const grpc::string& host, grpc_channel* channel)
-    : host_(host), c_channel_(channel) {}
+    : host_(host), c_channel_(channel) {
+  g_gli_initializer.summon();
+}
 
 Channel::~Channel() { grpc_channel_destroy(c_channel_); }
 
diff --git a/src/cpp/client/client_context.cc b/src/cpp/client/client_context.cc
index 710d7cb..73147fd 100644
--- a/src/cpp/client/client_context.cc
+++ b/src/cpp/client/client_context.cc
@@ -33,6 +33,7 @@
 
 #include <grpc++/client_context.h>
 
+#include <grpc/compression.h>
 #include <grpc/grpc.h>
 #include <grpc/support/alloc.h>
 #include <grpc/support/string_util.h>
diff --git a/src/cpp/client/create_channel.cc b/src/cpp/client/create_channel.cc
index 3bbca80..fdaa28f 100644
--- a/src/cpp/client/create_channel.cc
+++ b/src/cpp/client/create_channel.cc
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -36,6 +36,7 @@
 
 #include <grpc++/channel.h>
 #include <grpc++/create_channel.h>
+#include <grpc++/impl/grpc_library.h>
 #include <grpc++/support/channel_arguments.h>
 
 #include "src/cpp/client/create_channel_internal.h"
@@ -53,7 +54,8 @@
     const grpc::string& target,
     const std::shared_ptr<ChannelCredentials>& creds,
     const ChannelArguments& args) {
-  GrpcLibrary init_lib;  // We need to call init in case of a bad creds.
+  internal::GrpcLibrary
+      init_lib;  // We need to call init in case of a bad creds.
   ChannelArguments cp_args = args;
   std::ostringstream user_agent_prefix;
   user_agent_prefix << "grpc-c++/" << grpc_version_string();
diff --git a/src/cpp/client/credentials.cc b/src/cpp/client/credentials.cc
index 0c08db1..6fb620b 100644
--- a/src/cpp/client/credentials.cc
+++ b/src/cpp/client/credentials.cc
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -31,12 +31,18 @@
  *
  */
 
+#include <grpc++/impl/grpc_library.h>
 #include <grpc++/security/credentials.h>
 
 namespace grpc {
 
+static internal::GrpcLibraryInitializer g_gli_initializer;
+ChannelCredentials::ChannelCredentials() { g_gli_initializer.summon(); }
+
 ChannelCredentials::~ChannelCredentials() {}
 
+CallCredentials::CallCredentials() { g_gli_initializer.summon(); }
+
 CallCredentials::~CallCredentials() {}
 
 }  // namespace grpc
diff --git a/src/cpp/client/secure_credentials.cc b/src/cpp/client/secure_credentials.cc
index 96ae25b..074dae7 100644
--- a/src/cpp/client/secure_credentials.cc
+++ b/src/cpp/client/secure_credentials.cc
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -41,6 +41,13 @@
 
 namespace grpc {
 
+static internal::GrpcLibraryInitializer g_gli_initializer;
+SecureChannelCredentials::SecureChannelCredentials(
+    grpc_channel_credentials* c_creds)
+    : c_creds_(c_creds) {
+  g_gli_initializer.summon();
+}
+
 std::shared_ptr<grpc::Channel> SecureChannelCredentials::CreateChannel(
     const string& target, const grpc::ChannelArguments& args) {
   grpc_channel_args channel_args;
@@ -51,6 +58,12 @@
                                  nullptr));
 }
 
+SecureCallCredentials::SecureCallCredentials(grpc_call_credentials* c_creds)
+    : c_creds_(c_creds) {
+  internal::GrpcLibraryInitializer gli_initializer;
+  gli_initializer.summon();
+}
+
 bool SecureCallCredentials::ApplyToCall(grpc_call* call) {
   return grpc_call_set_credentials(call, c_creds_) == GRPC_CALL_OK;
 }
diff --git a/src/cpp/client/secure_credentials.h b/src/cpp/client/secure_credentials.h
index cef5929..9e84102 100644
--- a/src/cpp/client/secure_credentials.h
+++ b/src/cpp/client/secure_credentials.h
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -45,11 +45,8 @@
 
 class SecureChannelCredentials GRPC_FINAL : public ChannelCredentials {
  public:
-  explicit SecureChannelCredentials(grpc_channel_credentials* c_creds)
-      : c_creds_(c_creds) {}
-  ~SecureChannelCredentials() GRPC_OVERRIDE {
-    grpc_channel_credentials_release(c_creds_);
-  }
+  explicit SecureChannelCredentials(grpc_channel_credentials* c_creds);
+  ~SecureChannelCredentials() { grpc_channel_credentials_release(c_creds_); }
   grpc_channel_credentials* GetRawCreds() { return c_creds_; }
 
   std::shared_ptr<grpc::Channel> CreateChannel(
@@ -62,11 +59,8 @@
 
 class SecureCallCredentials GRPC_FINAL : public CallCredentials {
  public:
-  explicit SecureCallCredentials(grpc_call_credentials* c_creds)
-      : c_creds_(c_creds) {}
-  ~SecureCallCredentials() GRPC_OVERRIDE {
-    grpc_call_credentials_release(c_creds_);
-  }
+  explicit SecureCallCredentials(grpc_call_credentials* c_creds);
+  ~SecureCallCredentials() { grpc_call_credentials_release(c_creds_); }
   grpc_call_credentials* GetRawCreds() { return c_creds_; }
 
   bool ApplyToCall(grpc_call* call) GRPC_OVERRIDE;
diff --git a/src/objective-c/GRPCClient/private/GRPCUnsecuredChannel.h b/src/cpp/codegen/grpc_library.cc
similarity index 88%
rename from src/objective-c/GRPCClient/private/GRPCUnsecuredChannel.h
rename to src/cpp/codegen/grpc_library.cc
index 8528be4..48acec3 100644
--- a/src/objective-c/GRPCClient/private/GRPCUnsecuredChannel.h
+++ b/src/cpp/codegen/grpc_library.cc
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -31,8 +31,10 @@
  *
  */
 
-#import "GRPCChannel.h"
+#include <grpc++/impl/codegen/grpc_library.h>
 
-@interface GRPCUnsecuredChannel : GRPCChannel
-- (instancetype)initWithHost:(NSString *)host NS_DESIGNATED_INITIALIZER;
-@end
+namespace grpc {
+
+GrpcLibraryInterface *g_glip = nullptr;
+
+}  // namespace grpc
diff --git a/src/cpp/common/alarm.cc b/src/cpp/common/alarm.cc
index 1f0f041..a289688 100644
--- a/src/cpp/common/alarm.cc
+++ b/src/cpp/common/alarm.cc
@@ -1,5 +1,5 @@
 /*
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -30,13 +30,19 @@
  *
  */
 
-#include <grpc/grpc.h>
 #include <grpc++/alarm.h>
+#include <grpc++/completion_queue.h>
+#include <grpc++/impl/grpc_library.h>
+#include <grpc/grpc.h>
 
 namespace grpc {
 
+static internal::GrpcLibraryInitializer g_gli_initializer;
 Alarm::Alarm(CompletionQueue* cq, gpr_timespec deadline, void* tag)
-    : alarm_(grpc_alarm_create(cq->cq(), deadline, tag)) {}
+    : tag_(tag),
+      alarm_(grpc_alarm_create(cq->cq(), deadline, static_cast<void*>(&tag_))) {
+  g_gli_initializer.summon();
+}
 
 Alarm::~Alarm() { grpc_alarm_destroy(alarm_); }
 
diff --git a/src/cpp/common/completion_queue.cc b/src/cpp/common/completion_queue.cc
index a175beb..4f76dff 100644
--- a/src/cpp/common/completion_queue.cc
+++ b/src/cpp/common/completion_queue.cc
@@ -1,5 +1,5 @@
 /*
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -34,13 +34,17 @@
 
 #include <memory>
 
+#include <grpc++/impl/codegen/completion_queue_tag.h>
+#include <grpc++/impl/grpc_library.h>
+#include <grpc++/support/time.h>
 #include <grpc/grpc.h>
 #include <grpc/support/log.h>
-#include <grpc++/support/time.h>
 
 namespace grpc {
 
+static internal::GrpcLibraryInitializer g_gli_initializer;
 CompletionQueue::CompletionQueue() {
+  g_gli_initializer.summon();
   cq_ = grpc_completion_queue_create(nullptr);
 }
 
diff --git a/src/cpp/server/server.cc b/src/cpp/server/server.cc
index 3bf9f3f..0d31140 100644
--- a/src/cpp/server/server.cc
+++ b/src/cpp/server/server.cc
@@ -35,16 +35,19 @@
 
 #include <utility>
 
+#include <grpc++/completion_queue.h>
+#include <grpc++/generic/async_generic_service.h>
+#include <grpc++/impl/codegen/completion_queue_tag.h>
+#include <grpc++/impl/grpc_library.h>
+#include <grpc++/impl/method_handler_impl.h>
+#include <grpc++/impl/rpc_service_method.h>
+#include <grpc++/impl/service_type.h>
+#include <grpc++/security/server_credentials.h>
+#include <grpc++/server_context.h>
+#include <grpc++/support/time.h>
 #include <grpc/grpc.h>
 #include <grpc/support/alloc.h>
 #include <grpc/support/log.h>
-#include <grpc++/completion_queue.h>
-#include <grpc++/generic/async_generic_service.h>
-#include <grpc++/impl/rpc_service_method.h>
-#include <grpc++/impl/service_type.h>
-#include <grpc++/server_context.h>
-#include <grpc++/security/server_credentials.h>
-#include <grpc++/support/time.h>
 
 #include "src/core/profiling/timers.h"
 #include "src/cpp/server/thread_pool_interface.h"
@@ -275,6 +278,7 @@
   return grpc_server_create(&channel_args, nullptr);
 }
 
+static internal::GrpcLibraryInitializer g_gli_initializer;
 Server::Server(ThreadPoolInterface* thread_pool, bool thread_pool_owned,
                int max_message_size, const ChannelArguments& args)
     : max_message_size_(max_message_size),
@@ -286,6 +290,7 @@
       server_(CreateServer(args)),
       thread_pool_(thread_pool),
       thread_pool_owned_(thread_pool_owned) {
+  g_gli_initializer.summon();
   gpr_once_init(&g_once_init_callbacks, InitGlobalCallbacks);
   global_callbacks_ = g_callbacks;
   grpc_server_register_completion_queue(server_, cq_.cq(), nullptr);
@@ -297,6 +302,8 @@
     if (started_ && !shutdown_) {
       lock.unlock();
       Shutdown();
+    } else if (!started_) {
+      cq_.Shutdown();
     }
   }
   void* got_tag;
@@ -315,36 +322,31 @@
   g_callbacks.reset(callbacks);
 }
 
-bool Server::RegisterService(const grpc::string* host, RpcService* service) {
-  for (int i = 0; i < service->GetMethodCount(); ++i) {
-    RpcServiceMethod* method = service->GetMethod(i);
+bool Server::RegisterService(const grpc::string* host, Service* service) {
+  bool has_async_methods = service->has_async_methods();
+  if (has_async_methods) {
+    GPR_ASSERT(service->server_ == nullptr &&
+               "Can only register an asynchronous service against one server.");
+    service->server_ = this;
+  }
+  for (auto it = service->methods_.begin(); it != service->methods_.end();
+       ++it) {
+    if (it->get() == nullptr) {  // Handled by generic service if any.
+      continue;
+    }
+    RpcServiceMethod* method = it->get();
     void* tag = grpc_server_register_method(server_, method->name(),
                                             host ? host->c_str() : nullptr);
-    if (!tag) {
+    if (tag == nullptr) {
       gpr_log(GPR_DEBUG, "Attempt to register %s multiple times",
               method->name());
       return false;
     }
-    sync_methods_->emplace_back(method, tag);
-  }
-  return true;
-}
-
-bool Server::RegisterAsyncService(const grpc::string* host,
-                                  AsynchronousService* service) {
-  GPR_ASSERT(service->server_ == nullptr &&
-             "Can only register an asynchronous service against one server.");
-  service->server_ = this;
-  service->request_args_ = new void* [service->method_count_];
-  for (size_t i = 0; i < service->method_count_; ++i) {
-    void* tag = grpc_server_register_method(server_, service->method_names_[i],
-                                            host ? host->c_str() : nullptr);
-    if (!tag) {
-      gpr_log(GPR_DEBUG, "Attempt to register %s multiple times",
-              service->method_names_[i]);
-      return false;
+    if (method->handler() == nullptr) {
+      method->set_server_tag(tag);
+    } else {
+      sync_methods_->emplace_back(method, tag);
     }
-    service->request_args_[i] = tag;
   }
   return true;
 }
@@ -440,8 +442,8 @@
   GPR_ASSERT(GRPC_CALL_OK == result);
 }
 
-Server::BaseAsyncRequest::BaseAsyncRequest(
-    Server* server, ServerContext* context,
+ServerInterface::BaseAsyncRequest::BaseAsyncRequest(
+    ServerInterface* server, ServerContext* context,
     ServerAsyncStreamingInterface* stream, CompletionQueue* call_cq, void* tag,
     bool delete_on_finalize)
     : server_(server),
@@ -454,9 +456,8 @@
   memset(&initial_metadata_array_, 0, sizeof(initial_metadata_array_));
 }
 
-Server::BaseAsyncRequest::~BaseAsyncRequest() {}
-
-bool Server::BaseAsyncRequest::FinalizeResult(void** tag, bool* status) {
+bool ServerInterface::BaseAsyncRequest::FinalizeResult(void** tag,
+                                                       bool* status) {
   if (*status) {
     for (size_t i = 0; i < initial_metadata_array_.count; i++) {
       context_->client_metadata_.insert(
@@ -470,7 +471,7 @@
   grpc_metadata_array_destroy(&initial_metadata_array_);
   context_->set_call(call_);
   context_->cq_ = call_cq_;
-  Call call(call_, server_, call_cq_, server_->max_message_size_);
+  Call call(call_, server_, call_cq_, server_->max_message_size());
   if (*status && call_) {
     context_->BeginCompletionOp(&call);
   }
@@ -483,22 +484,22 @@
   return true;
 }
 
-Server::RegisteredAsyncRequest::RegisteredAsyncRequest(
-    Server* server, ServerContext* context,
+ServerInterface::RegisteredAsyncRequest::RegisteredAsyncRequest(
+    ServerInterface* server, ServerContext* context,
     ServerAsyncStreamingInterface* stream, CompletionQueue* call_cq, void* tag)
     : BaseAsyncRequest(server, context, stream, call_cq, tag, true) {}
 
-void Server::RegisteredAsyncRequest::IssueRequest(
+void ServerInterface::RegisteredAsyncRequest::IssueRequest(
     void* registered_method, grpc_byte_buffer** payload,
     ServerCompletionQueue* notification_cq) {
   grpc_server_request_registered_call(
-      server_->server_, registered_method, &call_, &context_->deadline_,
+      server_->server(), registered_method, &call_, &context_->deadline_,
       &initial_metadata_array_, payload, call_cq_->cq(), notification_cq->cq(),
       this);
 }
 
-Server::GenericAsyncRequest::GenericAsyncRequest(
-    Server* server, GenericServerContext* context,
+ServerInterface::GenericAsyncRequest::GenericAsyncRequest(
+    ServerInterface* server, GenericServerContext* context,
     ServerAsyncStreamingInterface* stream, CompletionQueue* call_cq,
     ServerCompletionQueue* notification_cq, void* tag, bool delete_on_finalize)
     : BaseAsyncRequest(server, context, stream, call_cq, tag,
@@ -506,12 +507,13 @@
   grpc_call_details_init(&call_details_);
   GPR_ASSERT(notification_cq);
   GPR_ASSERT(call_cq);
-  grpc_server_request_call(server->server_, &call_, &call_details_,
+  grpc_server_request_call(server->server(), &call_, &call_details_,
                            &initial_metadata_array_, call_cq->cq(),
                            notification_cq->cq(), this);
 }
 
-bool Server::GenericAsyncRequest::FinalizeResult(void** tag, bool* status) {
+bool ServerInterface::GenericAsyncRequest::FinalizeResult(void** tag,
+                                                          bool* status) {
   // TODO(yangg) remove the copy here.
   if (*status) {
     static_cast<GenericServerContext*>(context_)->method_ =
diff --git a/src/cpp/server/server_builder.cc b/src/cpp/server/server_builder.cc
index 26c0724..a8c188e 100644
--- a/src/cpp/server/server_builder.cc
+++ b/src/cpp/server/server_builder.cc
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -43,7 +43,7 @@
 namespace grpc {
 
 ServerBuilder::ServerBuilder()
-    : max_message_size_(-1), generic_service_(nullptr), thread_pool_(nullptr) {
+    : max_message_size_(-1), generic_service_(nullptr) {
   grpc_compression_options_init(&compression_options_);
 }
 
@@ -53,24 +53,13 @@
   return std::unique_ptr<ServerCompletionQueue>(cq);
 }
 
-void ServerBuilder::RegisterService(SynchronousService* service) {
-  services_.emplace_back(new NamedService<RpcService>(service->service()));
-}
-
-void ServerBuilder::RegisterAsyncService(AsynchronousService* service) {
-  async_services_.emplace_back(new NamedService<AsynchronousService>(service));
+void ServerBuilder::RegisterService(Service* service) {
+  services_.emplace_back(new NamedService(service));
 }
 
 void ServerBuilder::RegisterService(const grpc::string& addr,
-                                    SynchronousService* service) {
-  services_.emplace_back(
-      new NamedService<RpcService>(addr, service->service()));
-}
-
-void ServerBuilder::RegisterAsyncService(const grpc::string& addr,
-                                         AsynchronousService* service) {
-  async_services_.emplace_back(
-      new NamedService<AsynchronousService>(addr, service));
+                                    Service* service) {
+  services_.emplace_back(new NamedService(addr, service));
 }
 
 void ServerBuilder::RegisterAsyncGenericService(AsyncGenericService* service) {
@@ -96,14 +85,14 @@
 }
 
 std::unique_ptr<Server> ServerBuilder::BuildAndStart() {
-  bool thread_pool_owned = false;
-  if (!async_services_.empty() && !services_.empty()) {
-    gpr_log(GPR_ERROR, "Mixing async and sync services is unsupported for now");
-    return nullptr;
-  }
-  if (!thread_pool_ && !services_.empty()) {
-    thread_pool_ = CreateDefaultThreadPool();
-    thread_pool_owned = true;
+  std::unique_ptr<ThreadPoolInterface> thread_pool;
+  for (auto it = services_.begin(); it != services_.end(); ++it) {
+    if ((*it)->service->has_synchronous_methods()) {
+      if (thread_pool == nullptr) {
+        thread_pool.reset(CreateDefaultThreadPool());
+        break;
+      }
+    }
   }
   ChannelArguments args;
   for (auto option = options_.begin(); option != options_.end(); ++option) {
@@ -115,7 +104,7 @@
   args.SetInt(GRPC_COMPRESSION_ALGORITHM_STATE_ARG,
               compression_options_.enabled_algorithms_bitset);
   std::unique_ptr<Server> server(
-      new Server(thread_pool_, thread_pool_owned, max_message_size_, args));
+      new Server(thread_pool.release(), true, max_message_size_, args));
   for (auto cq = cqs_.begin(); cq != cqs_.end(); ++cq) {
     grpc_server_register_completion_queue(server->server_, (*cq)->cq(),
                                           nullptr);
@@ -126,15 +115,17 @@
       return nullptr;
     }
   }
-  for (auto service = async_services_.begin(); service != async_services_.end();
-       service++) {
-    if (!server->RegisterAsyncService((*service)->host.get(),
-                                      (*service)->service)) {
-      return nullptr;
-    }
-  }
   if (generic_service_) {
     server->RegisterAsyncGenericService(generic_service_);
+  } else {
+    for (auto it = services_.begin(); it != services_.end(); ++it) {
+      if ((*it)->service->has_generic_methods()) {
+        gpr_log(GPR_ERROR,
+                "Some methods were marked generic but there is no "
+                "generic service registered.");
+        return nullptr;
+      }
+    }
   }
   for (auto port = ports_.begin(); port != ports_.end(); port++) {
     int r = server->AddListeningPort(port->addr, port->creds.get());
diff --git a/src/cpp/server/server_context.cc b/src/cpp/server/server_context.cc
index b3a74c7..e205a19 100644
--- a/src/cpp/server/server_context.cc
+++ b/src/cpp/server/server_context.cc
@@ -33,12 +33,14 @@
 
 #include <grpc++/server_context.h>
 
-#include <grpc/grpc.h>
-#include <grpc/support/alloc.h>
-#include <grpc/support/log.h>
+#include <grpc++/completion_queue.h>
 #include <grpc++/impl/call.h>
 #include <grpc++/impl/sync.h>
 #include <grpc++/support/time.h>
+#include <grpc/compression.h>
+#include <grpc/grpc.h>
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
 
 #include "src/core/channel/compress_filter.h"
 #include "src/cpp/common/create_auth_context.h"
@@ -171,6 +173,14 @@
   trailing_metadata_.insert(std::make_pair(key, value));
 }
 
+void ServerContext::TryCancel() const {
+  grpc_call_error err = grpc_call_cancel_with_status(
+      call_, GRPC_STATUS_CANCELLED, "Cancelled on the server side", NULL);
+  if (err != GRPC_CALL_OK) {
+    gpr_log(GPR_ERROR, "TryCancel failed with: %d", err);
+  }
+}
+
 bool ServerContext::IsCancelled() const {
   return completion_op_ && completion_op_->CheckCancelled(cq_);
 }
diff --git a/src/csharp/Grpc.Core.Tests/GrpcEnvironmentTest.cs b/src/csharp/Grpc.Core.Tests/GrpcEnvironmentTest.cs
index 78295cf..fac93fc 100644
--- a/src/csharp/Grpc.Core.Tests/GrpcEnvironmentTest.cs
+++ b/src/csharp/Grpc.Core.Tests/GrpcEnvironmentTest.cs
@@ -1,6 +1,6 @@
 #region Copyright notice and license
 
-// Copyright 2015, Google Inc.
+// Copyright 2015-2016, Google Inc.
 // All rights reserved.
 //
 // Redistribution and use in source and binary forms, with or without
@@ -84,7 +84,7 @@
         {
             var coreVersion = GrpcEnvironment.GetCoreVersionString();
             var parts = coreVersion.Split('.');
-            Assert.AreEqual(4, parts.Length);
+            Assert.AreEqual(3, parts.Length);
         }
     }
 }
diff --git a/src/csharp/Grpc.Core/Grpc.Core.csproj b/src/csharp/Grpc.Core/Grpc.Core.csproj
index 307c0e8..9587503 100644
--- a/src/csharp/Grpc.Core/Grpc.Core.csproj
+++ b/src/csharp/Grpc.Core/Grpc.Core.csproj
@@ -128,6 +128,7 @@
     <Compile Include="Profiling\ProfilerScope.cs" />
     <Compile Include="Profiling\IProfiler.cs" />
     <Compile Include="Profiling\Profilers.cs" />
+    <Compile Include="Internal\DefaultSslRootsOverride.cs" />
   </ItemGroup>
   <ItemGroup>
     <None Include="Grpc.Core.nuspec" />
@@ -135,4 +136,12 @@
   </ItemGroup>
   <Import Project="NativeDeps.targets" />
   <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
+  <ItemGroup>
+    <Folder Include="Resources\" />
+  </ItemGroup>
+  <ItemGroup>
+    <EmbeddedResource Include="..\..\..\etc\roots.pem">
+      <Link>Resources\roots.pem</Link>
+    </EmbeddedResource>
+  </ItemGroup>
 </Project>
\ No newline at end of file
diff --git a/src/csharp/Grpc.Core/Grpc.Core.nuspec b/src/csharp/Grpc.Core/Grpc.Core.nuspec
index 9a4c1a3..49bccb0 100644
--- a/src/csharp/Grpc.Core/Grpc.Core.nuspec
+++ b/src/csharp/Grpc.Core/Grpc.Core.nuspec
@@ -20,7 +20,6 @@
     </dependencies>
   </metadata>
   <files>
-    <file src="..\..\..\etc\roots.pem" target="tools" />
     <file src="bin/ReleaseSigned/Grpc.Core.dll" target="lib/net45" />
     <file src="bin/ReleaseSigned/Grpc.Core.pdb" target="lib/net45" />
     <file src="bin/ReleaseSigned/Grpc.Core.xml" target="lib/net45" />
diff --git a/src/csharp/Grpc.Core/Internal/DefaultSslRootsOverride.cs b/src/csharp/Grpc.Core/Internal/DefaultSslRootsOverride.cs
new file mode 100644
index 0000000..eeaa7ad
--- /dev/null
+++ b/src/csharp/Grpc.Core/Internal/DefaultSslRootsOverride.cs
@@ -0,0 +1,72 @@
+#region Copyright notice and license
+
+// Copyright 2015-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.
+
+#endregion
+
+using System;
+using System.Collections.Concurrent;
+using System.Diagnostics;
+using System.IO;
+using System.Reflection;
+using System.Runtime.InteropServices;
+using System.Threading;
+
+namespace Grpc.Core.Internal
+{
+    /// <summary>
+    /// Overrides the content of default SSL roots.
+    /// </summary>
+    internal static class DefaultSslRootsOverride
+    {
+        const string RootsPemResourceName = "Grpc.Core.Resources.roots.pem";
+        static object staticLock = new object();
+
+        /// <summary>
+        /// Overrides C core's default roots with roots.pem loaded as embedded resource.
+        /// </summary>
+        public static void Override(NativeMethods native)
+        {
+            lock (staticLock)
+            {
+                var stream = Assembly.GetExecutingAssembly().GetManifestResourceStream(RootsPemResourceName);
+                if (stream == null)
+                {
+                    throw new IOException(string.Format("Error loading the embedded resource \"{0}\"", RootsPemResourceName));   
+                }
+                using (var streamReader = new StreamReader(stream))
+                {
+                    var pemRootCerts = streamReader.ReadToEnd();
+                    native.grpcsharp_override_default_ssl_roots(pemRootCerts);
+                }
+            }
+        }
+    }
+}
diff --git a/src/csharp/Grpc.Core/Internal/NativeExtension.cs b/src/csharp/Grpc.Core/Internal/NativeExtension.cs
index 137533b..4c742ab 100644
--- a/src/csharp/Grpc.Core/Internal/NativeExtension.cs
+++ b/src/csharp/Grpc.Core/Internal/NativeExtension.cs
@@ -60,6 +60,8 @@
             // to make sure we don't lose any logs.
             NativeLogRedirector.Redirect(this.nativeMethods);
 
+            DefaultSslRootsOverride.Override(this.nativeMethods);
+
             Logger.Debug("gRPC native library loaded successfully.");
         }
 
@@ -104,7 +106,7 @@
 
         private static string GetExecutingAssemblyDirectory()
         {
-            return Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
+            return Path.GetDirectoryName(typeof(NativeExtension).GetTypeInfo().Assembly.Location);
         }
 
         private static string GetPlatformString()
diff --git a/src/csharp/Grpc.Core/Internal/NativeMethods.cs b/src/csharp/Grpc.Core/Internal/NativeMethods.cs
index af37d61..19a5735 100644
--- a/src/csharp/Grpc.Core/Internal/NativeMethods.cs
+++ b/src/csharp/Grpc.Core/Internal/NativeMethods.cs
@@ -97,6 +97,7 @@
         public readonly Delegates.grpcsharp_channel_args_set_integer_delegate grpcsharp_channel_args_set_integer;
         public readonly Delegates.grpcsharp_channel_args_destroy_delegate grpcsharp_channel_args_destroy;
 
+        public readonly Delegates.grpcsharp_override_default_ssl_roots grpcsharp_override_default_ssl_roots;
         public readonly Delegates.grpcsharp_ssl_credentials_create_delegate grpcsharp_ssl_credentials_create;
         public readonly Delegates.grpcsharp_composite_channel_credentials_create_delegate grpcsharp_composite_channel_credentials_create;
         public readonly Delegates.grpcsharp_channel_credentials_release_delegate grpcsharp_channel_credentials_release;
@@ -203,6 +204,7 @@
                 this.grpcsharp_channel_args_set_integer = GetMethodDelegate<Delegates.grpcsharp_channel_args_set_integer_delegate>(library);
                 this.grpcsharp_channel_args_destroy = GetMethodDelegate<Delegates.grpcsharp_channel_args_destroy_delegate>(library);
 
+                this.grpcsharp_override_default_ssl_roots = GetMethodDelegate<Delegates.grpcsharp_override_default_ssl_roots>(library);
                 this.grpcsharp_ssl_credentials_create = GetMethodDelegate<Delegates.grpcsharp_ssl_credentials_create_delegate>(library);
                 this.grpcsharp_composite_channel_credentials_create = GetMethodDelegate<Delegates.grpcsharp_composite_channel_credentials_create_delegate>(library);
                 this.grpcsharp_channel_credentials_release = GetMethodDelegate<Delegates.grpcsharp_channel_credentials_release_delegate>(library);
@@ -306,6 +308,7 @@
                 this.grpcsharp_channel_args_set_integer = PInvokeMethods.grpcsharp_channel_args_set_integer;
                 this.grpcsharp_channel_args_destroy = PInvokeMethods.grpcsharp_channel_args_destroy;
 
+                this.grpcsharp_override_default_ssl_roots = PInvokeMethods.grpcsharp_override_default_ssl_roots;
                 this.grpcsharp_ssl_credentials_create = PInvokeMethods.grpcsharp_ssl_credentials_create;
                 this.grpcsharp_composite_channel_credentials_create = PInvokeMethods.grpcsharp_composite_channel_credentials_create;
                 this.grpcsharp_channel_credentials_release = PInvokeMethods.grpcsharp_channel_credentials_release;
@@ -449,6 +452,7 @@
             public delegate void grpcsharp_channel_args_set_integer_delegate(ChannelArgsSafeHandle args, UIntPtr index, string key, int value);
             public delegate void grpcsharp_channel_args_destroy_delegate(IntPtr args);
 
+            public delegate void grpcsharp_override_default_ssl_roots(string pemRootCerts);
             public delegate ChannelCredentialsSafeHandle grpcsharp_ssl_credentials_create_delegate(string pemRootCerts, string keyCertPairCertChain, string keyCertPairPrivateKey);
             public delegate ChannelCredentialsSafeHandle grpcsharp_composite_channel_credentials_create_delegate(ChannelCredentialsSafeHandle channelCreds, CallCredentialsSafeHandle callCreds);
             public delegate void grpcsharp_channel_credentials_release_delegate(IntPtr credentials);
@@ -658,6 +662,9 @@
             // ChannelCredentialsSafeHandle
 
             [DllImport("grpc_csharp_ext.dll", CharSet = CharSet.Ansi)]
+            public static extern void grpcsharp_override_default_ssl_roots(string pemRootCerts);
+
+            [DllImport("grpc_csharp_ext.dll", CharSet = CharSet.Ansi)]
             public static extern ChannelCredentialsSafeHandle grpcsharp_ssl_credentials_create(string pemRootCerts, string keyCertPairCertChain, string keyCertPairPrivateKey);
 
             [DllImport("grpc_csharp_ext.dll")]
diff --git a/src/csharp/Grpc.Core/Internal/PlatformApis.cs b/src/csharp/Grpc.Core/Internal/PlatformApis.cs
index d71e7ec..f0c5b0f 100644
--- a/src/csharp/Grpc.Core/Internal/PlatformApis.cs
+++ b/src/csharp/Grpc.Core/Internal/PlatformApis.cs
@@ -49,6 +49,7 @@
         static readonly bool isLinux;
         static readonly bool isMacOSX;
         static readonly bool isWindows;
+        static readonly bool isMono;
 
         static PlatformApis()
         {
@@ -58,6 +59,7 @@
             isMacOSX = (platform == PlatformID.Unix && GetUname() == "Darwin");
             isLinux = (platform == PlatformID.Unix && !isMacOSX);
             isWindows = (platform == PlatformID.Win32NT || platform == PlatformID.Win32S || platform == PlatformID.Win32Windows);
+            isMono = Type.GetType("Mono.Runtime") != null;
         }
 
         public static bool IsLinux
@@ -75,6 +77,11 @@
             get { return isWindows; }
         }
 
+        public static bool IsMono
+        {
+            get { return isMono; }
+        }
+
         public static bool Is64Bit
         {
             get { return IntPtr.Size == 8; }
diff --git a/src/csharp/Grpc.Core/Internal/UnmanagedLibrary.cs b/src/csharp/Grpc.Core/Internal/UnmanagedLibrary.cs
index e614cab..95a8797 100644
--- a/src/csharp/Grpc.Core/Internal/UnmanagedLibrary.cs
+++ b/src/csharp/Grpc.Core/Internal/UnmanagedLibrary.cs
@@ -91,6 +91,10 @@
         {
             if (PlatformApis.IsLinux)
             {
+                if (PlatformApis.IsMono)
+                {
+                    return Mono.dlsym(this.handle, symbolName);
+                }
                 return Linux.dlsym(this.handle, symbolName);
             }
             if (PlatformApis.IsMacOSX)
@@ -122,6 +126,10 @@
             }
             if (PlatformApis.IsLinux)
             {
+                if (PlatformApis.IsMono)
+                {
+                    return Mono.dlopen(libraryPath, RTLD_GLOBAL + RTLD_LAZY);
+                }
                 return Linux.dlopen(libraryPath, RTLD_GLOBAL + RTLD_LAZY);
             }
             if (PlatformApis.IsMacOSX)
@@ -154,5 +162,21 @@
             [DllImport("libSystem.dylib")]
             internal static extern IntPtr dlsym(IntPtr handle, string symbol);
         }
+
+        /// <summary>
+        /// On Linux systems, using using dlopen and dlsym results in
+        /// DllNotFoundException("libdl.so not found") if libc6-dev
+        /// is not installed. As a workaround, we load symbols for
+        /// dlopen and dlsym from the current process as on Linux
+        /// Mono sure is linked against these symbols.
+        /// </summary>
+        private static class Mono
+        {
+            [DllImport("__Internal")]
+            internal static extern IntPtr dlopen(string filename, int flags);
+
+            [DllImport("__Internal")]
+            internal static extern IntPtr dlsym(IntPtr handle, string symbol);
+        }
     }
 }
diff --git a/src/csharp/Grpc.Core/Profiling/Profilers.cs b/src/csharp/Grpc.Core/Profiling/Profilers.cs
index 471ee20..8a18144 100644
--- a/src/csharp/Grpc.Core/Profiling/Profilers.cs
+++ b/src/csharp/Grpc.Core/Profiling/Profilers.cs
@@ -1,6 +1,6 @@
 #region Copyright notice and license
 
-// Copyright 2015, Google Inc.
+// Copyright 2015-2016, Google Inc.
 // All rights reserved.
 //
 // Redistribution and use in source and binary forms, with or without
@@ -111,7 +111,7 @@
 
         public void Dump(string filepath)
         {
-            using (var stream = new StreamWriter(filepath))
+            using (var stream = File.CreateText(filepath))
             {
                 Dump(stream);
             }
diff --git a/src/csharp/Grpc.Core/Version.cs b/src/csharp/Grpc.Core/Version.cs
index d02b301..6d88438 100644
--- a/src/csharp/Grpc.Core/Version.cs
+++ b/src/csharp/Grpc.Core/Version.cs
@@ -1,6 +1,6 @@
 #region Copyright notice and license
 
-// Copyright 2015, Google Inc.
+// Copyright 2015-2016, Google Inc.
 // All rights reserved.
 //
 // Redistribution and use in source and binary forms, with or without
@@ -34,4 +34,4 @@
 using System.Reflection;
 
 // The current version of gRPC C#.
-[assembly: AssemblyVersion(Grpc.Core.VersionInfo.CurrentVersion + ".0")]
+[assembly: AssemblyVersion(Grpc.Core.VersionInfo.CurrentAssemblyVersion)]
diff --git a/src/csharp/Grpc.Core/VersionInfo.cs b/src/csharp/Grpc.Core/VersionInfo.cs
index 6581390..4bd4f20 100644
--- a/src/csharp/Grpc.Core/VersionInfo.cs
+++ b/src/csharp/Grpc.Core/VersionInfo.cs
@@ -39,8 +39,13 @@
     public static class VersionInfo
     {
         /// <summary>
+        /// Current version of gRPC C# assemblies
+        /// </summary>
+        public const string CurrentAssemblyVersion = "0.14.0.0";
+
+        /// <summary>
         /// Current version of gRPC C#
         /// </summary>
-        public const string CurrentVersion = "0.13.0";
+        public const string CurrentVersion = "0.14.0-dev";
     }
 }
diff --git a/src/csharp/build_packages.bat b/src/csharp/build_packages.bat
index 7a34bf3..b7768f7 100644
--- a/src/csharp/build_packages.bat
+++ b/src/csharp/build_packages.bat
@@ -1,7 +1,7 @@
 @rem Builds gRPC NuGet packages
 
 @rem Current package versions
-set VERSION=0.13.0
+set VERSION=0.14.0-dev
 set PROTOBUF_VERSION=3.0.0-beta2
 
 @rem Packages that depend on prerelease packages (like Google.Protobuf) need to have prerelease suffix as well.
@@ -49,6 +49,10 @@
 @rem copy resulting nuget packages to artifacts directory
 xcopy /Y /I *.nupkg ..\..\artifacts\
 
+@rem create a zipfile with the artifacts as well
+powershell -Command "Add-Type -Assembly 'System.IO.Compression.FileSystem'; [System.IO.Compression.ZipFile]::CreateFromDirectory('..\..\artifacts', 'csharp_nugets.zip');"
+xcopy /Y /I csharp_nugets.zip ..\..\artifacts\
+
 goto :EOF
 
 :error
diff --git a/src/csharp/ext/grpc_csharp_ext.c b/src/csharp/ext/grpc_csharp_ext.c
index 26f1537..1df74a0 100644
--- a/src/csharp/ext/grpc_csharp_ext.c
+++ b/src/csharp/ext/grpc_csharp_ext.c
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -835,6 +835,30 @@
 
 /* Security */
 
+static char *default_pem_root_certs = NULL;
+
+static grpc_ssl_roots_override_result override_ssl_roots_handler(
+    char **pem_root_certs) {
+  if (!default_pem_root_certs) {
+    *pem_root_certs = NULL;
+    return GRPC_SSL_ROOTS_OVERRIDE_FAIL_PERMANENTLY;
+  }
+  *pem_root_certs = gpr_strdup(default_pem_root_certs);
+  return GRPC_SSL_ROOTS_OVERRIDE_OK;
+}
+
+GPR_EXPORT void GPR_CALLTYPE grpcsharp_override_default_ssl_roots(
+    const char *pem_root_certs) {
+  /*
+   * This currently wastes ~300kB of memory by keeping a copy of roots
+   * in a static variable, but for desktop/server use, the overhead
+   * is negligible. In the future, we might want to change the behavior
+   * for mobile (e.g. Xamarin).
+   */
+  default_pem_root_certs = gpr_strdup(pem_root_certs);
+  grpc_set_ssl_roots_override_callback(override_ssl_roots_handler);
+}
+
 GPR_EXPORT grpc_channel_credentials *GPR_CALLTYPE
 grpcsharp_ssl_credentials_create(const char *pem_root_certs,
                                  const char *key_cert_pair_cert_chain,
@@ -917,6 +941,7 @@
   return grpc_composite_call_credentials_create(creds1, creds2, NULL);
 }
 
+
 /* Metadata credentials plugin */
 
 GPR_EXPORT void GPR_CALLTYPE grpcsharp_metadata_credentials_notify_from_plugin(
diff --git a/src/node/ext/byte_buffer.cc b/src/node/ext/byte_buffer.cc
index ee703fd..0f7edad 100644
--- a/src/node/ext/byte_buffer.cc
+++ b/src/node/ext/byte_buffer.cc
@@ -63,6 +63,10 @@
   return byte_buffer;
 }
 
+namespace {
+void delete_buffer(char *data, void *hint) { delete[] data; }
+}
+
 Local<Value> ByteBufferToBuffer(grpc_byte_buffer *buffer) {
   Nan::EscapableHandleScope scope;
   if (buffer == NULL) {
@@ -80,7 +84,7 @@
     gpr_slice_unref(next);
   }
   return scope.Escape(MakeFastBuffer(
-      Nan::NewBuffer(result, length).ToLocalChecked()));
+      Nan::NewBuffer(result, length, delete_buffer, NULL).ToLocalChecked()));
 }
 
 Local<Value> MakeFastBuffer(Local<Value> slowBuffer) {
diff --git a/src/node/ext/node_grpc.cc b/src/node/ext/node_grpc.cc
index a2b8e0d..654c5ae 100644
--- a/src/node/ext/node_grpc.cc
+++ b/src/node/ext/node_grpc.cc
@@ -112,8 +112,8 @@
   Nan::Set(exports, Nan::New("callError").ToLocalChecked(), call_error);
   Local<Value> OK(Nan::New<Uint32, uint32_t>(GRPC_CALL_OK));
   Nan::Set(call_error, Nan::New("OK").ToLocalChecked(), OK);
-  Local<Value> ERROR(Nan::New<Uint32, uint32_t>(GRPC_CALL_ERROR));
-  Nan::Set(call_error, Nan::New("ERROR").ToLocalChecked(), ERROR);
+  Local<Value> CALL_ERROR(Nan::New<Uint32, uint32_t>(GRPC_CALL_ERROR));
+  Nan::Set(call_error, Nan::New("ERROR").ToLocalChecked(), CALL_ERROR);
   Local<Value> NOT_ON_SERVER(
       Nan::New<Uint32, uint32_t>(GRPC_CALL_ERROR_NOT_ON_SERVER));
   Nan::Set(call_error, Nan::New("NOT_ON_SERVER").ToLocalChecked(),
diff --git a/src/node/ext/timeval.cc b/src/node/ext/timeval.cc
index 64015e8..c8f8534 100644
--- a/src/node/ext/timeval.cc
+++ b/src/node/ext/timeval.cc
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -32,6 +32,7 @@
  */
 
 #include <limits>
+#include <cstdint>
 
 #include "grpc/grpc.h"
 #include "grpc/support/time.h"
@@ -46,7 +47,7 @@
   } else if (millis == -std::numeric_limits<double>::infinity()) {
     return gpr_inf_past(GPR_CLOCK_REALTIME);
   } else {
-    return gpr_time_from_micros(static_cast<long>(millis * 1000),
+    return gpr_time_from_micros(static_cast<int64_t>(millis * 1000),
                                 GPR_CLOCK_REALTIME);
   }
 }
diff --git a/src/node/performance/benchmark_server.js b/src/node/performance/benchmark_server.js
index ba61e52..e48acd4 100644
--- a/src/node/performance/benchmark_server.js
+++ b/src/node/performance/benchmark_server.js
@@ -76,7 +76,7 @@
  */
 function streamingCall(call) {
   call.on('data', function(value) {
-    var payload = {body: zeroBuffer(value.repsonse_size)};
+    var payload = {body: zeroBuffer(value.response_size)};
     call.write({payload: payload});
   });
   call.on('end', function() {
diff --git a/src/node/performance/worker_service_impl.js b/src/node/performance/worker_service_impl.js
index 8841ae1..1439249 100644
--- a/src/node/performance/worker_service_impl.js
+++ b/src/node/performance/worker_service_impl.js
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -33,9 +33,15 @@
 
 'use strict';
 
+var os = require('os');
 var BenchmarkClient = require('./benchmark_client');
 var BenchmarkServer = require('./benchmark_server');
 
+exports.quitWorker = function quitWorker(call, callback) {
+  callback(null, {});
+  process.exit(0);
+}
+
 exports.runClient = function runClient(call) {
   var client;
   call.on('data', function(request) {
@@ -99,7 +105,7 @@
     var stats;
     switch (request.argtype) {
       case 'setup':
-      server = new BenchmarkServer(request.setup.host, request.setup.port,
+      server = new BenchmarkServer('[::]', request.setup.port,
                                    request.setup.security_params);
       server.start();
       stats = server.mark();
@@ -130,3 +136,7 @@
     });
   });
 };
+
+exports.coreCount = function coreCount(call, callback) {
+  callback(null, {cores: os.cpus().length});
+};
diff --git a/src/node/src/grpc_extension.js b/src/node/src/grpc_extension.js
index d4eca65..6a8fe2c 100644
--- a/src/node/src/grpc_extension.js
+++ b/src/node/src/grpc_extension.js
@@ -33,8 +33,8 @@
 
 var binary = require('node-pre-gyp');
 var path = require('path');
-var binding_path = binary.find(path.resolve(
-    path.join(__dirname,'../../../package.json')));
+var binding_path =
+    binary.find(path.resolve(path.join(__dirname, '../../../package.json')));
 var binding = require(binding_path);
 
 module.exports = binding;
diff --git a/src/node/test/surface_test.js b/src/node/test/surface_test.js
index c65d95f..530f1f7 100644
--- a/src/node/test/surface_test.js
+++ b/src/node/test/surface_test.js
@@ -970,9 +970,7 @@
       proxy.start();
       var proxy_client = new Client('localhost:' + proxy_port,
                                     grpc.credentials.createInsecure());
-      call = proxy_client.unary({}, function(err, value) {
-        done();
-      });
+      call = proxy_client.unary({}, function(err, value) { done(); });
     });
     it('With a client stream call', function(done) {
       done = multiDone(done, 2);
@@ -994,9 +992,7 @@
       proxy.start();
       var proxy_client = new Client('localhost:' + proxy_port,
                                     grpc.credentials.createInsecure());
-      call = proxy_client.clientStream(function(err, value) {
-        done();
-      });
+      call = proxy_client.clientStream(function(err, value) { done(); });
     });
     it('With a server stream call', function(done) {
       done = multiDone(done, 2);
diff --git a/src/objective-c/BoringSSL.podspec b/src/objective-c/BoringSSL.podspec
index f5b7382..4a6df91 100644
--- a/src/objective-c/BoringSSL.podspec
+++ b/src/objective-c/BoringSSL.podspec
@@ -31,7 +31,7 @@
 
 Pod::Spec.new do |s|
   s.name     = 'BoringSSL'
-  s.version  = '1.0'
+  s.version  = '2.0'
   s.summary  = 'BoringSSL is a fork of OpenSSL that is designed to meet Google’s needs.'
   # Adapted from the homepage:
   s.description = <<-DESC
@@ -67,7 +67,7 @@
   s.authors  = 'Adam Langley', 'David Benjamin', 'Matt Braithwaite'
 
   s.source = { :git => 'https://boringssl.googlesource.com/boringssl',
-               :tag => 'version_for_cocoapods_1.0' }
+               :tag => 'version_for_cocoapods_2.0' }
 
   s.source_files = 'ssl/*.{h,c}',
                    'ssl/**/*.{h,c}',
diff --git a/src/objective-c/GRPCClient/private/GRPCUnsecuredChannel.h b/src/objective-c/GRPCClient/GRPCCall+ChannelArg.h
similarity index 80%
copy from src/objective-c/GRPCClient/private/GRPCUnsecuredChannel.h
copy to src/objective-c/GRPCClient/GRPCCall+ChannelArg.h
index 8528be4..bd6b064 100644
--- a/src/objective-c/GRPCClient/private/GRPCUnsecuredChannel.h
+++ b/src/objective-c/GRPCClient/GRPCCall+ChannelArg.h
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -30,9 +30,17 @@
  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  *
  */
+#import "GRPCCall.h"
 
-#import "GRPCChannel.h"
+/**
+ * Methods to configure GRPC channel options.
+ */
+@interface GRPCCall (ChannelArg)
 
-@interface GRPCUnsecuredChannel : GRPCChannel
-- (instancetype)initWithHost:(NSString *)host NS_DESIGNATED_INITIALIZER;
+/**
+ * Use the provided @c userAgentPrefix at the beginning of the HTTP User Agent string for all calls
+ * to the specified @c host.
+ */
++ (void)setUserAgentPrefix:(NSString *)userAgentPrefix forHost:(NSString *)host;
+
 @end
diff --git a/src/objective-c/GRPCClient/private/GRPCUnsecuredChannel.h b/src/objective-c/GRPCClient/GRPCCall+ChannelArg.m
similarity index 76%
copy from src/objective-c/GRPCClient/private/GRPCUnsecuredChannel.h
copy to src/objective-c/GRPCClient/GRPCCall+ChannelArg.m
index 8528be4..5f9932d 100644
--- a/src/objective-c/GRPCClient/private/GRPCUnsecuredChannel.h
+++ b/src/objective-c/GRPCClient/GRPCCall+ChannelArg.m
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -31,8 +31,19 @@
  *
  */
 
-#import "GRPCChannel.h"
+#import "GRPCCall+ChannelArg.h"
 
-@interface GRPCUnsecuredChannel : GRPCChannel
-- (instancetype)initWithHost:(NSString *)host NS_DESIGNATED_INITIALIZER;
+#import "private/GRPCHost.h"
+
+@implementation GRPCCall (ChannelArg)
+
++ (void)setUserAgentPrefix:(NSString *)userAgentPrefix forHost:(NSString *)host {
+  if (!host) {
+    [NSException raise:NSInvalidArgumentException
+                format:@"host and userAgentPrefix must be provided."];
+  }
+  GRPCHost *hostConfig = [GRPCHost hostWithAddress:host];
+  hostConfig.userAgentPrefix = userAgentPrefix;
+}
+
 @end
diff --git a/src/objective-c/GRPCClient/private/GRPCChannel.h b/src/objective-c/GRPCClient/private/GRPCChannel.h
index e2d19d5..8661ae6 100644
--- a/src/objective-c/GRPCClient/private/GRPCChannel.h
+++ b/src/objective-c/GRPCClient/private/GRPCChannel.h
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -33,18 +33,51 @@
 
 #import <Foundation/Foundation.h>
 
-struct grpc_channel;
+#include <grpc/grpc.h>
+
+struct grpc_channel_credentials;
+
 
 /**
  * Each separate instance of this class represents at least one TCP connection to the provided host.
- * Create them using one of the subclasses |GRPCSecureChannel| and |GRPCUnsecuredChannel|.
  */
 @interface GRPCChannel : NSObject
-@property(nonatomic, readonly) struct grpc_channel *unmanagedChannel;
+
+@property(nonatomic, readonly, nonnull) struct grpc_channel *unmanagedChannel;
+
+- (nullable instancetype)init NS_UNAVAILABLE;
 
 /**
- * This initializer takes ownership of the passed channel, and will destroy it when this object is
- * deallocated. It's illegal to pass the same grpc_channel to two different GRPCChannel objects.
+ * Creates a secure channel to the specified @c host using default credentials and channel
+ * arguments. If certificates could not be found to create a secure channel, then @c nil is
+ * returned.
  */
-- (instancetype)initWithChannel:(struct grpc_channel *)unmanagedChannel NS_DESIGNATED_INITIALIZER;
++ (nullable GRPCChannel *)secureChannelWithHost:(nonnull NSString *)host;
+
+/**
+ * Creates a secure channel to the specified @c host using the specified @c pathToCertificates and 
+ * @c channelArgs. Only in tests should @c pathToCertificates be nil or
+ * @c GRPC_SSL_TARGET_NAME_OVERRIDE_ARG channel arg be set. Passing nil for @c pathToCertificates
+ * results in using the default root certificates distributed with the library. If certificates
+ * could not be found in any case, then @c nil is returned.
+ */
++ (nullable GRPCChannel *)secureChannelWithHost:(nonnull NSString *)host
+                             pathToCertificates:(nullable NSString *)pathToCertificates
+                                    channelArgs:(nullable NSDictionary *)channelArgs;
+
+
+/**
+ * Creates a secure channel to the specified @c host using the specified @c credentials and
+ * @c channelArgs. Only in tests should @c GRPC_SSL_TARGET_NAME_OVERRIDE_ARG channel arg be set.
+ */
++ (nonnull GRPCChannel *)secureChannelWithHost:(nonnull NSString *)host
+    credentials:(nonnull struct grpc_channel_credentials *)credentials
+    channelArgs:(nullable NSDictionary *)channelArgs;
+
+/**
+ * Creates an insecure channel to the specified @c host using the specified @c channelArgs.
+ */
++ (nonnull GRPCChannel *)insecureChannelWithHost:(nonnull NSString *)host
+                                     channelArgs:(nullable NSDictionary *)channelArgs;
+
 @end
diff --git a/src/objective-c/GRPCClient/private/GRPCChannel.m b/src/objective-c/GRPCClient/private/GRPCChannel.m
index 4366e63..7e55a47 100644
--- a/src/objective-c/GRPCClient/private/GRPCChannel.m
+++ b/src/objective-c/GRPCClient/private/GRPCChannel.m
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -33,22 +33,114 @@
 
 #import "GRPCChannel.h"
 
-#include <grpc/grpc.h>
+#include <grpc/grpc_security.h>
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+#include <grpc/support/string_util.h>
 
-@implementation GRPCChannel
-
-- (instancetype)init {
-  return [self initWithChannel:NULL];
+/**
+ * Returns @c grpc_channel_credentials from the specified @c path. If the file at the path could not
+ * be read then NULL is returned. If NULL is returned, @c errorPtr may not be NULL if there are
+ * details available describing what went wrong.
+ */
+static grpc_channel_credentials *CertificatesAtPath(NSString *path, NSError **errorPtr) {
+  // Files in PEM format can have non-ASCII characters in their comments (e.g. for the name of the
+  // issuer). Load them as UTF8 and produce an ASCII equivalent.
+  NSString *contentInUTF8 = [NSString stringWithContentsOfFile:path
+                                                      encoding:NSUTF8StringEncoding
+                                                         error:errorPtr];
+  NSData *contentInASCII = [contentInUTF8 dataUsingEncoding:NSASCIIStringEncoding
+                                       allowLossyConversion:YES];
+  if (!contentInASCII.bytes) {
+    // Passing NULL to grpc_ssl_credentials_create produces behavior we don't want, so return.
+    return NULL;
+  }
+  return grpc_ssl_credentials_create(contentInASCII.bytes, NULL, NULL);
 }
 
-// Designated initializer
-- (instancetype)initWithChannel:(grpc_channel *)unmanagedChannel {
-  if (!unmanagedChannel) {
+void freeChannelArgs(grpc_channel_args *channel_args) {
+  for (size_t i = 0; i < channel_args->num_args; ++i) {
+    grpc_arg *arg = &channel_args->args[i];
+    gpr_free(arg->key);
+    if (arg->type == GRPC_ARG_STRING) {
+      gpr_free(arg->value.string);
+    }
+  }
+  gpr_free(channel_args);
+}
+
+/**
+ * Allocates a @c grpc_channel_args and populates it with the options specified in the
+ * @c dictionary. Keys must be @c NSString. If the value responds to @c @selector(UTF8String) then
+ * it will be mapped to @c GRPC_ARG_STRING. If not, it will be mapped to @c GRPC_ARG_INTEGER if the
+ * value responds to @c @selector(intValue). Otherwise, an exception will be raised. The caller of
+ * this function is responsible for calling @c freeChannelArgs on a non-NULL returned value.
+ */
+grpc_channel_args * buildChannelArgs(NSDictionary *dictionary) {
+  if (!dictionary) {
+    return NULL;
+  }
+
+  NSArray *keys = [dictionary allKeys];
+  NSUInteger argCount = [keys count];
+
+  grpc_channel_args *channelArgs = gpr_malloc(sizeof(grpc_channel_args));
+  channelArgs->num_args = argCount;
+  channelArgs->args = gpr_malloc(argCount * sizeof(grpc_arg));
+
+  // TODO(kriswuollett) Check that keys adhere to GRPC core library requirements
+
+  for (NSUInteger i = 0; i < argCount; ++i) {
+    grpc_arg *arg = &channelArgs->args[i];
+    arg->key = gpr_strdup([keys[i] UTF8String]);
+
+    id value = dictionary[keys[i]];
+    if ([value respondsToSelector:@selector(UTF8String)]) {
+      arg->type = GRPC_ARG_STRING;
+      arg->value.string = gpr_strdup([value UTF8String]);
+    } else if ([value respondsToSelector:@selector(intValue)]) {
+      arg->type = GRPC_ARG_INTEGER;
+      arg->value.integer = [value intValue];
+    } else {
+      [NSException raise:NSInvalidArgumentException
+                  format:@"Invalid value type: %@", [value class]];
+    }
+  }
+
+  return channelArgs;
+}
+
+@implementation GRPCChannel {
+  // Retain arguments to channel_create because they may not be used on the thread that invoked
+  // the channel_create function.
+  NSString *_host;
+  grpc_channel_args *_channelArgs;
+}
+
+
+- (instancetype)initWithHost:(NSString *)host
+                      secure:(BOOL)secure
+                 credentials:(struct grpc_channel_credentials *)credentials
+                 channelArgs:(NSDictionary *)channelArgs {
+  if (!host) {
+    [NSException raise:NSInvalidArgumentException format:@"host argument missing"];
+  }
+
+  if (secure && !credentials) {
     return nil;
   }
-  if ((self = [super init])) {
-    _unmanagedChannel = unmanagedChannel;
+
+  if (self = [super init]) {
+    _channelArgs = buildChannelArgs(channelArgs);
+    _host = [host copy];
+    if (secure) {
+      _unmanagedChannel = grpc_secure_channel_create(credentials, _host.UTF8String, _channelArgs,
+                                                     NULL);
+    } else {
+      _unmanagedChannel = grpc_insecure_channel_create(_host.UTF8String, _channelArgs, NULL);
+    }
   }
+
   return self;
 }
 
@@ -56,5 +148,61 @@
   // TODO(jcanizales): Be sure to add a test with a server that closes the connection prematurely,
   // as in the past that made this call to crash.
   grpc_channel_destroy(_unmanagedChannel);
+  freeChannelArgs(_channelArgs);
 }
+
++ (GRPCChannel *)secureChannelWithHost:(NSString *)host {
+  return [[GRPCChannel alloc] initWithHost:host secure:YES credentials:NULL channelArgs:NULL];
+}
+
++ (GRPCChannel *)secureChannelWithHost:(NSString *)host
+                    pathToCertificates:(NSString *)path
+                           channelArgs:(NSDictionary *)channelArgs {
+  // Load default SSL certificates once.
+  static grpc_channel_credentials *kDefaultCertificates;
+  static dispatch_once_t loading;
+  dispatch_once(&loading, ^{
+    NSString *defaultPath = @"gRPCCertificates.bundle/roots"; // .pem
+    // Do not use NSBundle.mainBundle, as it's nil for tests of library projects.
+    NSBundle *bundle = [NSBundle bundleForClass:self.class];
+    NSString *path = [bundle pathForResource:defaultPath ofType:@"pem"];
+    NSError *error;
+    kDefaultCertificates = CertificatesAtPath(path, &error);
+    NSAssert(kDefaultCertificates, @"Could not read %@/%@.pem. This file, with the root "
+             "certificates, is needed to establish secure (TLS) connections. Because the file is "
+             "distributed with the gRPC library, this error is usually a sign that the library "
+             "wasn't configured correctly for your project. Error: %@",
+             bundle.bundlePath, defaultPath, error);
+  });
+
+  //TODO(jcanizales): Add NSError** parameter to the initializer.
+  grpc_channel_credentials *certificates = path
+      ? CertificatesAtPath(path, NULL)
+      : kDefaultCertificates;
+
+  return [[GRPCChannel alloc] initWithHost:host
+                                    secure:YES
+                               credentials:certificates
+                               channelArgs:channelArgs];
+}
+
+
++ (GRPCChannel *)secureChannelWithHost:(NSString *)host
+                           credentials:(struct grpc_channel_credentials *)credentials
+                           channelArgs:(NSDictionary *)channelArgs {
+  return [[GRPCChannel alloc] initWithHost:host
+                                    secure:YES
+                               credentials:credentials
+                               channelArgs:channelArgs];
+
+}
+
++ (GRPCChannel *)insecureChannelWithHost:(NSString *)host
+                             channelArgs:(NSDictionary *)channelArgs {
+  return [[GRPCChannel alloc] initWithHost:host
+                                    secure:NO
+                               credentials:NULL
+                               channelArgs:channelArgs];
+}
+
 @end
diff --git a/src/objective-c/GRPCClient/private/GRPCHost.h b/src/objective-c/GRPCClient/private/GRPCHost.h
index 6b4f987..82c0ad6 100644
--- a/src/objective-c/GRPCClient/private/GRPCHost.h
+++ b/src/objective-c/GRPCClient/private/GRPCHost.h
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -39,6 +39,7 @@
 @interface GRPCHost : NSObject
 
 @property(nonatomic, readonly) NSString *address;
+@property(nonatomic, copy) NSString *userAgentPrefix;
 
 /** The following properties should only be modified for testing: */
 
diff --git a/src/objective-c/GRPCClient/private/GRPCHost.m b/src/objective-c/GRPCClient/private/GRPCHost.m
index a8cd3a0..eb1db89 100644
--- a/src/objective-c/GRPCClient/private/GRPCHost.m
+++ b/src/objective-c/GRPCClient/private/GRPCHost.m
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -34,11 +34,15 @@
 #import "GRPCHost.h"
 
 #include <grpc/grpc.h>
+#import <GRPCClient/GRPCCall+ChannelArg.h>
 
 #import "GRPCChannel.h"
 #import "GRPCCompletionQueue.h"
-#import "GRPCSecureChannel.h"
-#import "GRPCUnsecuredChannel.h"
+#import "NSDictionary+GRPC.h"
+
+// TODO(jcanizales): Generate the version in a standalone header, from templates. Like
+// templates/src/core/surface/version.c.template .
+#define GRPC_OBJC_VERSION_STRING @"0.13.0"
 
 @interface GRPCHost ()
 // TODO(mlumish): Investigate whether caching channels with strong links is a good idea.
@@ -106,13 +110,28 @@
 - (GRPCChannel *)channel {
   // Create it lazily, because we don't want to open a connection just because someone is
   // configuring a host.
+
   if (!_channel) {
+    NSMutableDictionary *args = [NSMutableDictionary dictionary];
+
+    // TODO(jcanizales): Add OS and device information (see
+    // https://github.com/grpc/grpc/blob/master/doc/PROTOCOL-HTTP2.md#user-agents ).
+    NSString *userAgent = @"grpc-objc/" GRPC_OBJC_VERSION_STRING;
+    if (_userAgentPrefix) {
+      userAgent = [@[_userAgentPrefix, userAgent] componentsJoinedByString:@" "];
+    }
+    args[@GRPC_ARG_PRIMARY_USER_AGENT_STRING] = userAgent;
+
     if (_secure) {
-      _channel = [[GRPCSecureChannel alloc] initWithHost:_address
-                                      pathToCertificates:_pathToCertificates
-                                        hostNameOverride:_hostNameOverride];
+      if (_hostNameOverride) {
+        args[@GRPC_SSL_TARGET_NAME_OVERRIDE_ARG] = _hostNameOverride;
+      }
+
+      _channel = [GRPCChannel secureChannelWithHost:_address
+                                 pathToCertificates:_pathToCertificates
+                                        channelArgs:args];
     } else {
-      _channel = [[GRPCUnsecuredChannel alloc] initWithHost:_address];
+      _channel = [GRPCChannel insecureChannelWithHost:_address channelArgs:args];
     }
   }
   return _channel;
diff --git a/src/objective-c/GRPCClient/private/GRPCSecureChannel.h b/src/objective-c/GRPCClient/private/GRPCSecureChannel.h
deleted file mode 100644
index b82b9fe..0000000
--- a/src/objective-c/GRPCClient/private/GRPCSecureChannel.h
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- *
- * Copyright 2015, Google Inc.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- *     * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *     * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#include <grpc/grpc.h>
-
-#import "GRPCChannel.h"
-
-struct grpc_channel_credentials;
-
-@interface GRPCSecureChannel : GRPCChannel
-- (instancetype)initWithHost:(NSString *)host;
-
-/**
- * Only in tests shouldn't pathToCertificates or hostNameOverride be nil. Passing nil for
- * pathToCertificates results in using the default root certificates distributed with the library.
- */
-- (instancetype)initWithHost:(NSString *)host
-          pathToCertificates:(NSString *)path
-            hostNameOverride:(NSString *)hostNameOverride;
-
-/** The passed arguments aren't required to be valid beyond the invocation of this initializer. */
-- (instancetype)initWithHost:(NSString *)host
-                 credentials:(struct grpc_channel_credentials *)credentials
-                        args:(grpc_channel_args *)args NS_DESIGNATED_INITIALIZER;
-@end
diff --git a/src/objective-c/GRPCClient/private/GRPCSecureChannel.m b/src/objective-c/GRPCClient/private/GRPCSecureChannel.m
deleted file mode 100644
index a573c17..0000000
--- a/src/objective-c/GRPCClient/private/GRPCSecureChannel.m
+++ /dev/null
@@ -1,118 +0,0 @@
-/*
- *
- * Copyright 2015, Google Inc.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- *     * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *     * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#import "GRPCSecureChannel.h"
-
-#include <grpc/grpc_security.h>
-
-// Returns NULL if the file at path couldn't be read. In that case, if errorPtr isn't NULL,
-// *errorPtr will be an object describing what went wrong.
-static grpc_channel_credentials *CertificatesAtPath(NSString *path, NSError **errorPtr) {
-  // Files in PEM format can have non-ASCII characters in their comments (e.g. for the name of the
-  // issuer). Load them as UTF8 and produce an ASCII equivalent.
-  NSString *contentInUTF8 = [NSString stringWithContentsOfFile:path
-                                                     encoding:NSUTF8StringEncoding
-                                                        error:errorPtr];
-  NSData *contentInASCII = [contentInUTF8 dataUsingEncoding:NSASCIIStringEncoding
-                                       allowLossyConversion:YES];
-  if (!contentInASCII.bytes) {
-    // Passing NULL to grpc_ssl_credentials_create produces behavior we don't want, so return.
-    return NULL;
-  }
-  return grpc_ssl_credentials_create(contentInASCII.bytes, NULL, NULL);
-}
-
-@implementation GRPCSecureChannel
-
-- (instancetype)initWithHost:(NSString *)host {
-  return [self initWithHost:host pathToCertificates:nil hostNameOverride:nil];
-}
-
-- (instancetype)initWithHost:(NSString *)host
-          pathToCertificates:(NSString *)path
-            hostNameOverride:(NSString *)hostNameOverride {
-  // Load default SSL certificates once.
-  static grpc_channel_credentials *kDefaultCertificates;
-  static dispatch_once_t loading;
-  dispatch_once(&loading, ^{
-    NSString *defaultPath = @"gRPCCertificates.bundle/roots"; // .pem
-    // Do not use NSBundle.mainBundle, as it's nil for tests of library projects.
-    NSBundle *bundle = [NSBundle bundleForClass:self.class];
-    NSString *path = [bundle pathForResource:defaultPath ofType:@"pem"];
-    NSError *error;
-    kDefaultCertificates = CertificatesAtPath(path, &error);
-    NSAssert(kDefaultCertificates, @"Could not read %@/%@.pem. This file, with the root "
-             "certificates, is needed to establish secure (TLS) connections. Because the file is "
-             "distributed with the gRPC library, this error is usually a sign that the library "
-             "wasn't configured correctly for your project. Error: %@",
-             bundle.bundlePath, defaultPath, error);
-  });
-
-  //TODO(jcanizales): Add NSError** parameter to the initializer.
-  grpc_channel_credentials *certificates = path
-      ? CertificatesAtPath(path, NULL)
-      : kDefaultCertificates;
-  if (!certificates) {
-    return nil;
-  }
-
-  // Ritual to pass the SSL host name override to the C library.
-  grpc_channel_args channelArgs;
-  grpc_arg nameOverrideArg;
-  channelArgs.num_args = 1;
-  channelArgs.args = &nameOverrideArg;
-  nameOverrideArg.type = GRPC_ARG_STRING;
-  nameOverrideArg.key = GRPC_SSL_TARGET_NAME_OVERRIDE_ARG;
-  // Cast const away. Hope C gRPC doesn't modify it!
-  nameOverrideArg.value.string = (char *) hostNameOverride.UTF8String;
-  grpc_channel_args *args = hostNameOverride ? &channelArgs : NULL;
-
-  return [self initWithHost:host credentials:certificates args:args];
-}
-
-- (instancetype)initWithHost:(NSString *)host
-                 credentials:(grpc_channel_credentials *)credentials
-                        args:(grpc_channel_args *)args {
-  return (self = [super
-              initWithChannel:grpc_secure_channel_create(
-                                  credentials, host.UTF8String, args, NULL)]);
-}
-
-// TODO(jcanizales): GRPCSecureChannel and GRPCUnsecuredChannel are just convenience initializers
-// for GRPCChannel. Move them into GRPCChannel, which will make the following unnecessary.
-- (instancetype)initWithChannel:(grpc_channel *)unmanagedChannel {
-  [NSException raise:NSInternalInconsistencyException format:@"use another initializer"];
-  return [self initWithHost:nil]; // silence warnings
-}
-
-@end
diff --git a/src/objective-c/GRPCClient/private/GRPCUnsecuredChannel.m b/src/objective-c/GRPCClient/private/GRPCUnsecuredChannel.m
deleted file mode 100644
index 15b6ffc..0000000
--- a/src/objective-c/GRPCClient/private/GRPCUnsecuredChannel.m
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- *
- * Copyright 2015, Google Inc.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- *     * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *     * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#import "GRPCUnsecuredChannel.h"
-
-#include <grpc/grpc.h>
-
-@implementation GRPCUnsecuredChannel
-
-- (instancetype)initWithHost:(NSString *)host {
-  return (self = [super initWithChannel:grpc_insecure_channel_create(host.UTF8String, NULL, NULL)]);
-}
-
-// TODO(jcanizales): GRPCSecureChannel and GRPCUnsecuredChannel are just convenience initializers
-// for GRPCChannel. Move them into GRPCChannel, which will make the following unnecessary.
-- (instancetype)initWithChannel:(grpc_channel *)unmanagedChannel {
-  [NSException raise:NSInternalInconsistencyException format:@"use the other initializer"];
-  return [self initWithHost:nil]; // silence warnings
-}
-@end
diff --git a/src/proto/grpc/testing/control.proto b/src/proto/grpc/testing/control.proto
index 7ba6f98..cc365ca 100644
--- a/src/proto/grpc/testing/control.proto
+++ b/src/proto/grpc/testing/control.proto
@@ -107,6 +107,10 @@
   LoadParams load_params = 10;
   PayloadConfig payload_config = 11;
   HistogramParams histogram_params = 12;
+
+  // Specify the cores we should run the client on, if desired
+  repeated int32 core_list = 13;
+  int32 core_limit = 14;
 }
 
 message ClientStatus { ClientStats stats = 1; }
@@ -127,15 +131,17 @@
 message ServerConfig {
   ServerType server_type = 1;
   SecurityParams security_params = 2;
-  // Host on which to listen.
-  string host = 3;
   // Port on which to listen. Zero means pick unused port.
   int32 port = 4;
   // Only for async server. Number of threads used to serve the requests.
   int32 async_server_threads = 7;
-  // restrict core usage, currently unused
+  // Specify the number of cores to limit server to, if desired
   int32 core_limit = 8;
+  // payload config, used in generic server
   PayloadConfig payload_config = 9;
+
+  // Specify the cores we should run the server on, if desired
+  repeated int32 core_list = 10;
 }
 
 message ServerArgs {
@@ -149,6 +155,17 @@
   ServerStats stats = 1;
   // the port bound by the server
   int32 port = 2;
-  // Number of cores on the server. See gpr_cpu_num_cores.
+  // Number of cores available to the server
   int32 cores = 3;
 }
+
+message CoreRequest {
+}
+
+message CoreResponse {
+  // Number of cores available on the server
+  int32 cores = 1;
+}
+
+message Void {
+}
diff --git a/src/proto/grpc/testing/echo_messages.proto b/src/proto/grpc/testing/echo_messages.proto
index f01d645..d05a355 100644
--- a/src/proto/grpc/testing/echo_messages.proto
+++ b/src/proto/grpc/testing/echo_messages.proto
@@ -1,5 +1,5 @@
 
-// Copyright 2015, Google Inc.
+// Copyright 2015-2016, Google Inc.
 // All rights reserved.
 //
 // Redistribution and use in source and binary forms, with or without
@@ -41,6 +41,7 @@
   int32 response_message_length = 6;
   bool echo_peer = 7;
   string expected_client_identity = 8; // will force check_auth_context.
+  bool skip_cancelled_check = 9;
 }
 
 message EchoRequest {
diff --git a/src/proto/grpc/testing/services.proto b/src/proto/grpc/testing/services.proto
index af285ce..a2c5fda 100644
--- a/src/proto/grpc/testing/services.proto
+++ b/src/proto/grpc/testing/services.proto
@@ -1,4 +1,4 @@
-// Copyright 2015, Google Inc.
+// Copyright 2015-2016, Google Inc.
 // All rights reserved.
 //
 // Redistribution and use in source and binary forms, with or without
@@ -62,4 +62,10 @@
   // and once the shutdown has finished, the OK status is sent to terminate
   // this RPC.
   rpc RunClient(stream ClientArgs) returns (stream ClientStatus);
+
+  // Just return the core count - unary call
+  rpc CoreCount(CoreRequest) returns (CoreResponse);
+
+  // Quit this worker
+  rpc QuitWorker(Void) returns (Void);
 }
diff --git a/src/python/README.md b/src/python/README.md
deleted file mode 100644
index 8b16765..0000000
--- a/src/python/README.md
+++ /dev/null
@@ -1,100 +0,0 @@
-gRPC Python
-=========
-The Python facility of gRPC.
-
-Status
--------
-Beta : Core behavior well-used and proven; bugs lurk off the beaten path.
-
-PREREQUISITES
--------------
-- python-virtualenv, python-pip, python3-pip, python-dev, python3-dev
-- [homebrew][] on Mac OS X.  These simplify the installation of the gRPC C core.
-
-INSTALLATION
--------------
-
-**Linux (Debian):**
-
-Add [Debian jessie-backports][] to your `sources.list` file. Example:
-
-```sh
-echo "deb http://http.debian.net/debian jessie-backports main" | \
-sudo tee -a /etc/apt/sources.list
-```
-
-Install the gRPC Debian package
-
-```sh
-sudo apt-get update
-sudo apt-get install libgrpc-dev
-```
-
-Install the gRPC Python module
-
-```sh
-sudo pip install grpcio
-```
-
-**Mac OS X**
-
-Install [homebrew][]. Run the following command to install gRPC Python.
-```sh
-$ curl -fsSL https://goo.gl/getgrpc | bash -s python
-```
-This will download and run the [gRPC install script][], then install the latest version of the gRPC Python package.  It also installs the Protocol Buffers compiler (_protoc_) and the gRPC _protoc_ plugin for python.
-
-EXAMPLES
---------
-Please read our online documentation for a [Quick Start][] and a [detailed example][]
-
-BUILDING FROM SOURCE
----------------------
-- Clone this repository
-
-- Install tox
-```
-$ sudo pip install tox
-```
-
-- Initialize the git submodules
-```
-$ git submodule update --init
-```
-
-- Make the libraries
-```
-$ make
-```
-
-- Use build_python.sh to build the Python code and install it into a virtual environment
-```
-$ CONFIG=opt tools/run_tests/build_python.sh
-```
-
-TESTING
--------
-
-- Use run_python.sh to run gRPC as it was installed into the virtual environment
-```
-$ CONFIG=opt PYVER=2.7 tools/run_tests/run_python.sh
-```
-
-PACKAGING
----------
-
-- Install packaging dependencies
-```
-$ pip install setuptools twine
-```
-
-- Push to PyPI
-```
-$ ../../tools/distrib/python/submit.py
-```
-
-[homebrew]:http://brew.sh
-[gRPC install script]:https://raw.githubusercontent.com/grpc/homebrew-grpc/master/scripts/install
-[Quick Start]:http://www.grpc.io/docs/tutorials/basic/python.html
-[detailed example]:http://www.grpc.io/docs/installation/python.html
-[Debian jessie-backports]:http://backports.debian.org/Instructions/
diff --git a/src/python/grpcio/.gitignore b/src/python/grpcio/.gitignore
index 1d804e1..6e5e650 100644
--- a/src/python/grpcio/.gitignore
+++ b/src/python/grpcio/.gitignore
@@ -14,4 +14,4 @@
 doc/
 _grpcio_metadata.py
 htmlcov/
-grpc/_adapter/credentials
+grpc/_cython/_credentials
diff --git a/src/python/grpcio/commands.py b/src/python/grpcio/commands.py
index 29b506a..774e7ad 100644
--- a/src/python/grpcio/commands.py
+++ b/src/python/grpcio/commands.py
@@ -30,21 +30,35 @@
 """Provides distutils command classes for the GRPC Python setup process."""
 
 import distutils
+import glob
 import os
 import os.path
+import platform
 import re
+import shutil
 import subprocess
 import sys
+import traceback
 
 import setuptools
+from setuptools.command import bdist_egg
 from setuptools.command import build_ext
 from setuptools.command import build_py
+from setuptools.command import easy_install
+from setuptools.command import install
 from setuptools.command import test
 
 import support
 
 PYTHON_STEM = os.path.dirname(os.path.abspath(__file__))
 
+BINARIES_REPOSITORY = os.environ.get(
+    'GRPC_PYTHON_BINARIES_REPOSITORY',
+    'https://storage.googleapis.com/grpc-precompiled-binaries/python')
+
+USE_GRPC_CUSTOM_BDIST = bool(int(os.environ.get(
+    'GRPC_PYTHON_USE_CUSTOM_BDIST', '1')))
+
 CONF_PY_ADDENDUM = """
 extensions.append('sphinx.ext.napoleon')
 napoleon_google_docstring = True
@@ -58,6 +72,130 @@
   """Simple exception class for GRPC custom commands."""
 
 
+# TODO(atash): Remove this once PyPI has better Linux bdist support. See
+# https://bitbucket.org/pypa/pypi/issues/120/binary-wheels-for-linux-are-not-supported
+def _get_grpc_custom_bdist_egg(decorated_basename, target_egg_basename):
+  """Returns a string path to a .egg file for Linux to install.
+
+  If we can retrieve a pre-compiled egg from online, uses it. Else, emits a
+  warning and builds from source.
+  """
+  # Break import style to ensure that setup.py has had a chance to install the
+  # relevant package eggs.
+  from six.moves.urllib import request
+  decorated_path = decorated_basename + '.egg'
+  try:
+    url = BINARIES_REPOSITORY + '/{target}'.format(target=decorated_path)
+    egg_data = request.urlopen(url).read()
+  except IOError as error:
+    raise CommandError(
+        '{}\n\nCould not find the bdist egg {}: {}'
+            .format(traceback.format_exc(), decorated_path, error.message))
+  # Our chosen local egg path.
+  egg_path = target_egg_basename + '.egg'
+  try:
+    with open(egg_path, 'w') as egg_file:
+      egg_file.write(egg_data)
+  except IOError as error:
+    raise CommandError(
+        '{}\n\nCould not write grpcio egg: {}'
+            .format(traceback.format_exc(), error.message))
+  return egg_path
+
+
+class EggNameMixin(object):
+  """Mixin for setuptools.Command classes to enable acquiring the egg name."""
+
+  def egg_name(self, with_custom):
+    """
+    Args:
+      with_custom: Boolean describing whether or not to decorate the egg name
+        with custom gRPC-specific target information.
+    """
+    egg_command = self.get_finalized_command('bdist_egg')
+    base = os.path.splitext(os.path.basename(egg_command.egg_output))[0]
+    if with_custom:
+      flavor = 'ucs2' if sys.maxunicode == 65535 else 'ucs4'
+      return '{base}-{flavor}'.format(base=base, flavor=flavor)
+    else:
+      return base
+
+
+class Install(install.install, EggNameMixin):
+  """Custom Install command for gRPC Python.
+
+  This is for bdist shims and whatever else we might need a custom install
+  command for.
+  """
+
+  user_options = install.install.user_options + [
+      # TODO(atash): remove this once PyPI has better Linux bdist support. See
+      # https://bitbucket.org/pypa/pypi/issues/120/binary-wheels-for-linux-are-not-supported
+      ('use-grpc-custom-bdist', None,
+       'Whether to retrieve a binary from the gRPC binary repository instead '
+       'of building from source.'),
+  ]
+
+  def initialize_options(self):
+    install.install.initialize_options(self)
+    self.use_grpc_custom_bdist = USE_GRPC_CUSTOM_BDIST
+
+  def finalize_options(self):
+    install.install.finalize_options(self)
+
+  def run(self):
+    if self.use_grpc_custom_bdist:
+      try:
+        try:
+          egg_path = _get_grpc_custom_bdist_egg(self.egg_name(True),
+                                                self.egg_name(False))
+        except CommandError as error:
+          sys.stderr.write(
+              '\nWARNING: Failed to acquire grpcio prebuilt binary:\n'
+              '{}.\n\n'.format(error.message))
+          raise
+        try:
+          self._run_bdist_retrieval_install(egg_path)
+        except Exception as error:
+          # if anything else happens (and given how there's no way to really know
+          # what's happening in setuptools here, I mean *anything*), warn the user
+          # and fall back to building from source.
+          sys.stderr.write(
+              '{}\nWARNING: Failed to install grpcio prebuilt binary.\n\n'
+                  .format(traceback.format_exc()))
+          raise
+      except Exception:
+        install.install.run(self)
+    else:
+      install.install.run(self)
+
+  # TODO(atash): Remove this once PyPI has better Linux bdist support. See
+  # https://bitbucket.org/pypa/pypi/issues/120/binary-wheels-for-linux-are-not-supported
+  def _run_bdist_retrieval_install(self, bdist_egg):
+    easy_install = self.distribution.get_command_class('easy_install')
+    easy_install_command = easy_install(
+        self.distribution, args='x', root=self.root, record=self.record,
+    )
+    easy_install_command.ensure_finalized()
+    easy_install_command.always_copy_from = '.'
+    easy_install_command.package_index.scan(glob.glob('*.egg'))
+    arguments = [bdist_egg]
+    if setuptools.bootstrap_install_from:
+      args.insert(0, setuptools.bootstrap_install_from)
+    easy_install_command.args = arguments
+    easy_install_command.run()
+    setuptools.bootstrap_install_from = None
+
+
+class BdistEggCustomName(bdist_egg.bdist_egg, EggNameMixin):
+  """Thin wrapper around the bdist_egg command to build with our custom name."""
+
+  def run(self):
+    bdist_egg.bdist_egg.run(self)
+    target = os.path.join(self.dist_dir, '{}.egg'.format(self.egg_name(True)))
+    shutil.move(self.get_outputs()[0], target)
+
+
 class SphinxDocumentation(setuptools.Command):
   """Command to generate documentation via sphinx."""
 
@@ -190,11 +328,11 @@
         extension.extra_link_args += list(BuildExt.LINK_OPTIONS[compiler])
     try:
       build_ext.build_ext.build_extensions(self)
-    except KeyboardInterrupt:
-      raise
     except Exception as error:
-      support.diagnose_build_ext_error(self, error)
-      raise CommandError("Failed `build_ext` step.")
+      formatted_exception = traceback.format_exc()
+      support.diagnose_build_ext_error(self, error, formatted_exception)
+      raise CommandError(
+          "Failed `build_ext` step:\n{}".format(formatted_exception))
 
 
 class Gather(setuptools.Command):
diff --git a/src/python/grpcio/grpc/_adapter/_low.py b/src/python/grpcio/grpc/_adapter/_low.py
index a850c57..62fd52a 100644
--- a/src/python/grpcio/grpc/_adapter/_low.py
+++ b/src/python/grpcio/grpc/_adapter/_low.py
@@ -27,7 +27,6 @@
 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
-import pkg_resources
 import threading
 
 from grpc import _grpcio_metadata
@@ -35,7 +34,6 @@
 from grpc._adapter import _implementations
 from grpc._adapter import _types
 
-_ROOT_CERTIFICATES_RESOURCE_PATH = 'credentials/roots.pem'
 _USER_AGENT = 'Python-gRPC-{}'.format(_grpcio_metadata.__version__)
 
 ChannelCredentials = cygrpc.ChannelCredentials
@@ -56,9 +54,6 @@
   pair = None
   if private_key is not None or certificate_chain is not None:
     pair = cygrpc.SslPemKeyCertPair(private_key, certificate_chain)
-  if root_certificates is None:
-    root_certificates = pkg_resources.resource_string(
-      __name__, _ROOT_CERTIFICATES_RESOURCE_PATH)
   return cygrpc.channel_credentials_ssl(root_certificates, pair)
 
 
diff --git a/src/python/grpcio/grpc/_cython/.gitignore b/src/python/grpcio/grpc/_cython/.gitignore
index c315029..306e3ad 100644
--- a/src/python/grpcio/grpc/_cython/.gitignore
+++ b/src/python/grpcio/grpc/_cython/.gitignore
@@ -1,5 +1,4 @@
-*.h
-*.c
+cygrpc.c
 *.a
 *.so
 *.dll
diff --git a/src/python/grpcio/grpc/_cython/_cygrpc/grpc.pxi b/src/python/grpcio/grpc/_cython/_cygrpc/grpc.pxi
index 9b10d2a..bbeed9a 100644
--- a/src/python/grpcio/grpc/_cython/_cygrpc/grpc.pxi
+++ b/src/python/grpcio/grpc/_cython/_cygrpc/grpc.pxi
@@ -1,4 +1,4 @@
-# Copyright 2015, Google Inc.
+# Copyright 2015-2016, Google Inc.
 # All rights reserved.
 #
 # Redistribution and use in source and binary forms, with or without
@@ -28,15 +28,20 @@
 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 cimport libc.time
-from libc.stdint cimport int64_t, uint32_t, int32_t
 
 
-cdef extern from "grpc/support/alloc.h":
+cdef extern from "grpc/_cython/loader.h":
+
+  ctypedef int int32_t
+  ctypedef unsigned uint32_t
+  ctypedef long int64_t
+
+  int pygrpc_load_core(const char*)
+
   void *gpr_malloc(size_t size)
   void gpr_free(void *ptr)
   void *gpr_realloc(void *p, size_t size)
 
-cdef extern from "grpc/support/slice.h":
   ctypedef struct gpr_slice:
     # don't worry about writing out the members of gpr_slice; we never access
     # them directly.
@@ -55,9 +60,6 @@
   void *gpr_slice_start_ptr "GPR_SLICE_START_PTR" (gpr_slice s)
   size_t gpr_slice_length "GPR_SLICE_LENGTH" (gpr_slice s)
 
-
-cdef extern from "grpc/support/time.h":
-
   ctypedef enum gpr_clock_type:
     GPR_CLOCK_MONOTONIC
     GPR_CLOCK_REALTIME
@@ -78,8 +80,6 @@
   gpr_timespec gpr_convert_clock_type(gpr_timespec t,
                                       gpr_clock_type target_clock)
 
-
-cdef extern from "grpc/status.h":
   ctypedef enum grpc_status_code:
     GRPC_STATUS_OK
     GRPC_STATUS_CANCELLED
@@ -100,14 +100,15 @@
     GRPC_STATUS_DATA_LOSS
     GRPC_STATUS__DO_NOT_USE
 
+  ctypedef enum grpc_ssl_roots_override_result:
+    GRPC_SSL_ROOTS_OVERRIDE_OK
+    GRPC_SSL_ROOTS_OVERRIDE_FAILED_PERMANENTLY
+    GRPC_SSL_ROOTS_OVERRIDE_FAILED
 
-cdef extern from "grpc/byte_buffer_reader.h":
   struct grpc_byte_buffer_reader:
     # We don't care about the internals
     pass
 
-
-cdef extern from "grpc/byte_buffer.h":
   ctypedef struct grpc_byte_buffer:
     # We don't care about the internals.
     pass
@@ -123,9 +124,6 @@
                                    gpr_slice *slice)
   void grpc_byte_buffer_reader_destroy(grpc_byte_buffer_reader *reader)
 
-
-cdef extern from "grpc/grpc.h":
-
   const char *GRPC_ARG_PRIMARY_USER_AGENT_STRING
   const char *GRPC_ARG_ENABLE_CENSUS
   const char *GRPC_ARG_MAX_CONCURRENT_STREAMS
@@ -333,9 +331,6 @@
   void grpc_server_cancel_all_calls(grpc_server *server)
   void grpc_server_destroy(grpc_server *server)
 
-
-cdef extern from "grpc/grpc_security.h":
-
   ctypedef struct grpc_ssl_pem_key_cert_pair:
     const char *private_key
     const char *certificate_chain "cert_chain"
@@ -348,6 +343,10 @@
     # We don't care about the internals (and in fact don't know them)
     pass
 
+  ctypedef void (*grpc_ssl_roots_override_callback)(char **pem_root_certs)
+
+  void grpc_set_ssl_roots_override_callback(grpc_ssl_roots_override_callback cb)
+
   grpc_channel_credentials *grpc_google_default_credentials_create()
   grpc_channel_credentials *grpc_ssl_credentials_create(
       const char *pem_root_certs, grpc_ssl_pem_key_cert_pair *pem_key_cert_pair,
diff --git a/src/python/grpcio/grpc/_cython/_cygrpc/records.pyx.pxi b/src/python/grpcio/grpc/_cython/_cygrpc/records.pyx.pxi
index d7ad9e5..fa4ea99 100644
--- a/src/python/grpcio/grpc/_cython/_cygrpc/records.pyx.pxi
+++ b/src/python/grpcio/grpc/_cython/_cygrpc/records.pyx.pxi
@@ -1,4 +1,4 @@
-# Copyright 2015, Google Inc.
+# Copyright 2015-2016, Google Inc.
 # All rights reserved.
 #
 # Redistribution and use in source and binary forms, with or without
@@ -146,8 +146,13 @@
         gpr_convert_clock_type(self.c_time, GPR_CLOCK_REALTIME))
     return <double>real_time.seconds + <double>real_time.nanoseconds / 1e9
 
-  infinite_future = Timespec(float("+inf"))
-  infinite_past = Timespec(float("-inf"))
+  @staticmethod
+  def infinite_future():
+    return Timespec(float("+inf"))
+
+  @staticmethod
+  def infinite_past():
+    return Timespec(float("-inf"))
 
 
 cdef class CallDetails:
diff --git a/tools/run_tests/check_submodules.sh b/src/python/grpcio/grpc/_cython/_cygrpc/security.pxd.pxi
old mode 100755
new mode 100644
similarity index 65%
copy from tools/run_tests/check_submodules.sh
copy to src/python/grpcio/grpc/_cython/_cygrpc/security.pxd.pxi
index b4ca4fa..3a952ca
--- a/tools/run_tests/check_submodules.sh
+++ b/src/python/grpcio/grpc/_cython/_cygrpc/security.pxd.pxi
@@ -1,6 +1,4 @@
-#!/bin/sh
-
-# Copyright 2015-2016, Google Inc.
+# Copyright 2016, Google Inc.
 # All rights reserved.
 #
 # Redistribution and use in source and binary forms, with or without
@@ -30,25 +28,5 @@
 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 
-set -e
-
-export TEST=true
-
-cd `dirname $0`/../..
-
-submodules=`mktemp /tmp/submXXXXXX`
-want_submodules=`mktemp /tmp/submXXXXXX`
-
-git submodule | awk '{ print $1 }' | sort > $submodules
-cat << EOF | awk '{ print $1 }' | sort > $want_submodules
- 9f897b25800d2f54f5c442ef01a60721aeca6d87 third_party/boringssl (version_for_cocoapods_1.0-67-g9f897b2)
- 05b155ff59114735ec8cd089f669c4c3d8f59029 third_party/gflags (v2.1.0-45-g05b155f)
- c99458533a9b4c743ed51537e25989ea55944908 third_party/googletest (release-1.7.0)
- d5fb408ddc281ffcadeb08699e65bb694656d0bd third_party/protobuf (v3.0.0-beta-2)
- 50893291621658f355bc5b4d450a8d06a563053d third_party/zlib (v1.2.8)
-EOF
-
-diff -u $submodules $want_submodules
-
-rm $submodules $want_submodules
-
+cdef grpc_ssl_roots_override_result ssl_roots_override_callback(
+    char **pem_root_certs) with gil
diff --git a/tools/run_tests/check_submodules.sh b/src/python/grpcio/grpc/_cython/_cygrpc/security.pyx.pxi
old mode 100755
new mode 100644
similarity index 65%
copy from tools/run_tests/check_submodules.sh
copy to src/python/grpcio/grpc/_cython/_cygrpc/security.pyx.pxi
index b4ca4fa..23cee7b
--- a/tools/run_tests/check_submodules.sh
+++ b/src/python/grpcio/grpc/_cython/_cygrpc/security.pyx.pxi
@@ -1,6 +1,4 @@
-#!/bin/sh
-
-# Copyright 2015-2016, Google Inc.
+# Copyright 2016, Google Inc.
 # All rights reserved.
 #
 # Redistribution and use in source and binary forms, with or without
@@ -29,26 +27,18 @@
 # (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 libc.string cimport memcpy
 
-set -e
+import pkg_resources
 
-export TEST=true
 
-cd `dirname $0`/../..
-
-submodules=`mktemp /tmp/submXXXXXX`
-want_submodules=`mktemp /tmp/submXXXXXX`
-
-git submodule | awk '{ print $1 }' | sort > $submodules
-cat << EOF | awk '{ print $1 }' | sort > $want_submodules
- 9f897b25800d2f54f5c442ef01a60721aeca6d87 third_party/boringssl (version_for_cocoapods_1.0-67-g9f897b2)
- 05b155ff59114735ec8cd089f669c4c3d8f59029 third_party/gflags (v2.1.0-45-g05b155f)
- c99458533a9b4c743ed51537e25989ea55944908 third_party/googletest (release-1.7.0)
- d5fb408ddc281ffcadeb08699e65bb694656d0bd third_party/protobuf (v3.0.0-beta-2)
- 50893291621658f355bc5b4d450a8d06a563053d third_party/zlib (v1.2.8)
-EOF
-
-diff -u $submodules $want_submodules
-
-rm $submodules $want_submodules
-
+cdef grpc_ssl_roots_override_result ssl_roots_override_callback(
+    char **pem_root_certs) with gil:
+  temporary_pem_root_certs = pkg_resources.resource_string(
+      'grpc._cython', '_credentials/roots.pem')
+  pem_root_certs[0] = <char *>gpr_malloc(len(temporary_pem_root_certs) + 1)
+  memcpy(
+      pem_root_certs[0], <char *>temporary_pem_root_certs,
+      len(temporary_pem_root_certs))
+  pem_root_certs[0][len(temporary_pem_root_certs)] = '\0'
+  return GRPC_SSL_ROOTS_OVERRIDE_OK
diff --git a/src/python/grpcio/grpc/_cython/cygrpc.pxd b/src/python/grpcio/grpc/_cython/cygrpc.pxd
index f22346c..61b0fa7 100644
--- a/src/python/grpcio/grpc/_cython/cygrpc.pxd
+++ b/src/python/grpcio/grpc/_cython/cygrpc.pxd
@@ -34,4 +34,5 @@
 include "grpc/_cython/_cygrpc/credentials.pxd.pxi"
 include "grpc/_cython/_cygrpc/completion_queue.pxd.pxi"
 include "grpc/_cython/_cygrpc/records.pxd.pxi"
+include "grpc/_cython/_cygrpc/security.pxd.pxi"
 include "grpc/_cython/_cygrpc/server.pxd.pxi"
diff --git a/src/python/grpcio/grpc/_cython/cygrpc.pyx b/src/python/grpcio/grpc/_cython/cygrpc.pyx
index 297c800..30cc7a1 100644
--- a/src/python/grpcio/grpc/_cython/cygrpc.pyx
+++ b/src/python/grpcio/grpc/_cython/cygrpc.pyx
@@ -1,4 +1,4 @@
-# Copyright 2015, Google Inc.
+# Copyright 2015-2016, Google Inc.
 # All rights reserved.
 #
 # Redistribution and use in source and binary forms, with or without
@@ -29,6 +29,10 @@
 
 cimport cpython
 
+import pkg_resources
+import os.path
+import sys
+
 # TODO(atash): figure out why the coverage tool gets confused about the Cython
 # coverage plugin when the following files don't have a '.pxi' suffix.
 include "grpc/_cython/_cygrpc/call.pyx.pxi"
@@ -36,6 +40,7 @@
 include "grpc/_cython/_cygrpc/credentials.pyx.pxi"
 include "grpc/_cython/_cygrpc/completion_queue.pyx.pxi"
 include "grpc/_cython/_cygrpc/records.pyx.pxi"
+include "grpc/_cython/_cygrpc/security.pyx.pxi"
 include "grpc/_cython/_cygrpc/server.pyx.pxi"
 
 #
@@ -44,11 +49,22 @@
 
 cdef class _ModuleState:
 
+  cdef bint is_loaded
+
   def __cinit__(self):
+    if 'win32' in sys.platform:
+      filename = pkg_resources.resource_filename(
+          'grpc._cython', '_windows/grpc_c.64.python')
+      if not pygrpc_load_core(filename):
+        raise ImportError('failed to load core gRPC library')
     grpc_init()
+    self.is_loaded = True
+    grpc_set_ssl_roots_override_callback(
+        <grpc_ssl_roots_override_callback>ssl_roots_override_callback)
 
   def __dealloc__(self):
-    grpc_shutdown()
+    if self.is_loaded:
+      grpc_shutdown()
 
 _module_state = _ModuleState()
 
diff --git a/src/python/grpcio/grpc/_cython/imports.generated.c b/src/python/grpcio/grpc/_cython/imports.generated.c
new file mode 100644
index 0000000..817303c
--- /dev/null
+++ b/src/python/grpcio/grpc/_cython/imports.generated.c
@@ -0,0 +1,560 @@
+/*
+ *
+ * Copyright 2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <grpc/support/port_platform.h>
+
+#include "imports.generated.h"
+
+#ifdef GPR_WIN32
+
+census_initialize_type census_initialize_import;
+census_shutdown_type census_shutdown_import;
+census_supported_type census_supported_import;
+census_enabled_type census_enabled_import;
+census_context_create_type census_context_create_import;
+census_context_destroy_type census_context_destroy_import;
+census_context_get_status_type census_context_get_status_import;
+census_context_initialize_iterator_type census_context_initialize_iterator_import;
+census_context_next_tag_type census_context_next_tag_import;
+census_context_get_tag_type census_context_get_tag_import;
+census_context_encode_type census_context_encode_import;
+census_context_decode_type census_context_decode_import;
+census_trace_mask_type census_trace_mask_import;
+census_set_trace_mask_type census_set_trace_mask_import;
+census_start_rpc_op_timestamp_type census_start_rpc_op_timestamp_import;
+census_start_client_rpc_op_type census_start_client_rpc_op_import;
+census_set_rpc_client_peer_type census_set_rpc_client_peer_import;
+census_start_server_rpc_op_type census_start_server_rpc_op_import;
+census_start_op_type census_start_op_import;
+census_end_op_type census_end_op_import;
+census_trace_print_type census_trace_print_import;
+census_trace_scan_start_type census_trace_scan_start_import;
+census_get_trace_record_type census_get_trace_record_import;
+census_trace_scan_end_type census_trace_scan_end_import;
+census_record_values_type census_record_values_import;
+census_view_create_type census_view_create_import;
+census_view_delete_type census_view_delete_import;
+census_view_metric_type census_view_metric_import;
+census_view_naggregations_type census_view_naggregations_import;
+census_view_tags_type census_view_tags_import;
+census_view_aggregrations_type census_view_aggregrations_import;
+census_view_get_data_type census_view_get_data_import;
+census_view_reset_type census_view_reset_import;
+grpc_compression_algorithm_parse_type grpc_compression_algorithm_parse_import;
+grpc_compression_algorithm_name_type grpc_compression_algorithm_name_import;
+grpc_compression_algorithm_for_level_type grpc_compression_algorithm_for_level_import;
+grpc_compression_options_init_type grpc_compression_options_init_import;
+grpc_compression_options_enable_algorithm_type grpc_compression_options_enable_algorithm_import;
+grpc_compression_options_disable_algorithm_type grpc_compression_options_disable_algorithm_import;
+grpc_compression_options_is_algorithm_enabled_type grpc_compression_options_is_algorithm_enabled_import;
+grpc_metadata_array_init_type grpc_metadata_array_init_import;
+grpc_metadata_array_destroy_type grpc_metadata_array_destroy_import;
+grpc_call_details_init_type grpc_call_details_init_import;
+grpc_call_details_destroy_type grpc_call_details_destroy_import;
+grpc_register_plugin_type grpc_register_plugin_import;
+grpc_init_type grpc_init_import;
+grpc_shutdown_type grpc_shutdown_import;
+grpc_version_string_type grpc_version_string_import;
+grpc_completion_queue_create_type grpc_completion_queue_create_import;
+grpc_completion_queue_next_type grpc_completion_queue_next_import;
+grpc_completion_queue_pluck_type grpc_completion_queue_pluck_import;
+grpc_completion_queue_shutdown_type grpc_completion_queue_shutdown_import;
+grpc_completion_queue_destroy_type grpc_completion_queue_destroy_import;
+grpc_alarm_create_type grpc_alarm_create_import;
+grpc_alarm_cancel_type grpc_alarm_cancel_import;
+grpc_alarm_destroy_type grpc_alarm_destroy_import;
+grpc_channel_check_connectivity_state_type grpc_channel_check_connectivity_state_import;
+grpc_channel_watch_connectivity_state_type grpc_channel_watch_connectivity_state_import;
+grpc_channel_create_call_type grpc_channel_create_call_import;
+grpc_channel_ping_type grpc_channel_ping_import;
+grpc_channel_register_call_type grpc_channel_register_call_import;
+grpc_channel_create_registered_call_type grpc_channel_create_registered_call_import;
+grpc_call_start_batch_type grpc_call_start_batch_import;
+grpc_call_get_peer_type grpc_call_get_peer_import;
+grpc_census_call_set_context_type grpc_census_call_set_context_import;
+grpc_census_call_get_context_type grpc_census_call_get_context_import;
+grpc_channel_get_target_type grpc_channel_get_target_import;
+grpc_insecure_channel_create_type grpc_insecure_channel_create_import;
+grpc_lame_client_channel_create_type grpc_lame_client_channel_create_import;
+grpc_channel_destroy_type grpc_channel_destroy_import;
+grpc_call_cancel_type grpc_call_cancel_import;
+grpc_call_cancel_with_status_type grpc_call_cancel_with_status_import;
+grpc_call_destroy_type grpc_call_destroy_import;
+grpc_server_request_call_type grpc_server_request_call_import;
+grpc_server_register_method_type grpc_server_register_method_import;
+grpc_server_request_registered_call_type grpc_server_request_registered_call_import;
+grpc_server_create_type grpc_server_create_import;
+grpc_server_register_completion_queue_type grpc_server_register_completion_queue_import;
+grpc_server_add_insecure_http2_port_type grpc_server_add_insecure_http2_port_import;
+grpc_server_start_type grpc_server_start_import;
+grpc_server_shutdown_and_notify_type grpc_server_shutdown_and_notify_import;
+grpc_server_cancel_all_calls_type grpc_server_cancel_all_calls_import;
+grpc_server_destroy_type grpc_server_destroy_import;
+grpc_tracer_set_enabled_type grpc_tracer_set_enabled_import;
+grpc_header_key_is_legal_type grpc_header_key_is_legal_import;
+grpc_header_nonbin_value_is_legal_type grpc_header_nonbin_value_is_legal_import;
+grpc_is_binary_header_type grpc_is_binary_header_import;
+grpc_auth_property_iterator_next_type grpc_auth_property_iterator_next_import;
+grpc_auth_context_property_iterator_type grpc_auth_context_property_iterator_import;
+grpc_auth_context_peer_identity_type grpc_auth_context_peer_identity_import;
+grpc_auth_context_find_properties_by_name_type grpc_auth_context_find_properties_by_name_import;
+grpc_auth_context_peer_identity_property_name_type grpc_auth_context_peer_identity_property_name_import;
+grpc_auth_context_peer_is_authenticated_type grpc_auth_context_peer_is_authenticated_import;
+grpc_call_auth_context_type grpc_call_auth_context_import;
+grpc_auth_context_release_type grpc_auth_context_release_import;
+grpc_auth_context_add_property_type grpc_auth_context_add_property_import;
+grpc_auth_context_add_cstring_property_type grpc_auth_context_add_cstring_property_import;
+grpc_auth_context_set_peer_identity_property_name_type grpc_auth_context_set_peer_identity_property_name_import;
+grpc_channel_credentials_release_type grpc_channel_credentials_release_import;
+grpc_google_default_credentials_create_type grpc_google_default_credentials_create_import;
+grpc_ssl_credentials_create_type grpc_ssl_credentials_create_import;
+grpc_call_credentials_release_type grpc_call_credentials_release_import;
+grpc_composite_channel_credentials_create_type grpc_composite_channel_credentials_create_import;
+grpc_composite_call_credentials_create_type grpc_composite_call_credentials_create_import;
+grpc_google_compute_engine_credentials_create_type grpc_google_compute_engine_credentials_create_import;
+grpc_max_auth_token_lifetime_type grpc_max_auth_token_lifetime_import;
+grpc_service_account_jwt_access_credentials_create_type grpc_service_account_jwt_access_credentials_create_import;
+grpc_google_refresh_token_credentials_create_type grpc_google_refresh_token_credentials_create_import;
+grpc_access_token_credentials_create_type grpc_access_token_credentials_create_import;
+grpc_google_iam_credentials_create_type grpc_google_iam_credentials_create_import;
+grpc_metadata_credentials_create_from_plugin_type grpc_metadata_credentials_create_from_plugin_import;
+grpc_secure_channel_create_type grpc_secure_channel_create_import;
+grpc_server_credentials_release_type grpc_server_credentials_release_import;
+grpc_ssl_server_credentials_create_type grpc_ssl_server_credentials_create_import;
+grpc_server_add_secure_http2_port_type grpc_server_add_secure_http2_port_import;
+grpc_call_set_credentials_type grpc_call_set_credentials_import;
+grpc_server_credentials_set_auth_metadata_processor_type grpc_server_credentials_set_auth_metadata_processor_import;
+gpr_malloc_type gpr_malloc_import;
+gpr_free_type gpr_free_import;
+gpr_realloc_type gpr_realloc_import;
+gpr_malloc_aligned_type gpr_malloc_aligned_import;
+gpr_free_aligned_type gpr_free_aligned_import;
+gpr_set_allocation_functions_type gpr_set_allocation_functions_import;
+gpr_get_allocation_functions_type gpr_get_allocation_functions_import;
+grpc_raw_byte_buffer_create_type grpc_raw_byte_buffer_create_import;
+grpc_raw_compressed_byte_buffer_create_type grpc_raw_compressed_byte_buffer_create_import;
+grpc_byte_buffer_copy_type grpc_byte_buffer_copy_import;
+grpc_byte_buffer_length_type grpc_byte_buffer_length_import;
+grpc_byte_buffer_destroy_type grpc_byte_buffer_destroy_import;
+grpc_byte_buffer_reader_init_type grpc_byte_buffer_reader_init_import;
+grpc_byte_buffer_reader_destroy_type grpc_byte_buffer_reader_destroy_import;
+grpc_byte_buffer_reader_next_type grpc_byte_buffer_reader_next_import;
+grpc_byte_buffer_reader_readall_type grpc_byte_buffer_reader_readall_import;
+grpc_raw_byte_buffer_from_reader_type grpc_raw_byte_buffer_from_reader_import;
+gpr_log_type gpr_log_import;
+gpr_log_message_type gpr_log_message_import;
+gpr_set_log_function_type gpr_set_log_function_import;
+gpr_slice_ref_type gpr_slice_ref_import;
+gpr_slice_unref_type gpr_slice_unref_import;
+gpr_slice_new_type gpr_slice_new_import;
+gpr_slice_new_with_len_type gpr_slice_new_with_len_import;
+gpr_slice_malloc_type gpr_slice_malloc_import;
+gpr_slice_from_copied_string_type gpr_slice_from_copied_string_import;
+gpr_slice_from_copied_buffer_type gpr_slice_from_copied_buffer_import;
+gpr_slice_from_static_string_type gpr_slice_from_static_string_import;
+gpr_slice_sub_type gpr_slice_sub_import;
+gpr_slice_sub_no_ref_type gpr_slice_sub_no_ref_import;
+gpr_slice_split_tail_type gpr_slice_split_tail_import;
+gpr_slice_split_head_type gpr_slice_split_head_import;
+gpr_empty_slice_type gpr_empty_slice_import;
+gpr_slice_cmp_type gpr_slice_cmp_import;
+gpr_slice_str_cmp_type gpr_slice_str_cmp_import;
+gpr_slice_buffer_init_type gpr_slice_buffer_init_import;
+gpr_slice_buffer_destroy_type gpr_slice_buffer_destroy_import;
+gpr_slice_buffer_add_type gpr_slice_buffer_add_import;
+gpr_slice_buffer_add_indexed_type gpr_slice_buffer_add_indexed_import;
+gpr_slice_buffer_addn_type gpr_slice_buffer_addn_import;
+gpr_slice_buffer_tiny_add_type gpr_slice_buffer_tiny_add_import;
+gpr_slice_buffer_pop_type gpr_slice_buffer_pop_import;
+gpr_slice_buffer_reset_and_unref_type gpr_slice_buffer_reset_and_unref_import;
+gpr_slice_buffer_swap_type gpr_slice_buffer_swap_import;
+gpr_slice_buffer_move_into_type gpr_slice_buffer_move_into_import;
+gpr_slice_buffer_trim_end_type gpr_slice_buffer_trim_end_import;
+gpr_slice_buffer_move_first_type gpr_slice_buffer_move_first_import;
+gpr_slice_buffer_take_first_type gpr_slice_buffer_take_first_import;
+gpr_mu_init_type gpr_mu_init_import;
+gpr_mu_destroy_type gpr_mu_destroy_import;
+gpr_mu_lock_type gpr_mu_lock_import;
+gpr_mu_unlock_type gpr_mu_unlock_import;
+gpr_mu_trylock_type gpr_mu_trylock_import;
+gpr_cv_init_type gpr_cv_init_import;
+gpr_cv_destroy_type gpr_cv_destroy_import;
+gpr_cv_wait_type gpr_cv_wait_import;
+gpr_cv_signal_type gpr_cv_signal_import;
+gpr_cv_broadcast_type gpr_cv_broadcast_import;
+gpr_once_init_type gpr_once_init_import;
+gpr_event_init_type gpr_event_init_import;
+gpr_event_set_type gpr_event_set_import;
+gpr_event_get_type gpr_event_get_import;
+gpr_event_wait_type gpr_event_wait_import;
+gpr_ref_init_type gpr_ref_init_import;
+gpr_ref_type gpr_ref_import;
+gpr_refn_type gpr_refn_import;
+gpr_unref_type gpr_unref_import;
+gpr_stats_init_type gpr_stats_init_import;
+gpr_stats_inc_type gpr_stats_inc_import;
+gpr_stats_read_type gpr_stats_read_import;
+gpr_time_0_type gpr_time_0_import;
+gpr_inf_future_type gpr_inf_future_import;
+gpr_inf_past_type gpr_inf_past_import;
+gpr_time_init_type gpr_time_init_import;
+gpr_now_type gpr_now_import;
+gpr_convert_clock_type_type gpr_convert_clock_type_import;
+gpr_time_cmp_type gpr_time_cmp_import;
+gpr_time_max_type gpr_time_max_import;
+gpr_time_min_type gpr_time_min_import;
+gpr_time_add_type gpr_time_add_import;
+gpr_time_sub_type gpr_time_sub_import;
+gpr_time_from_micros_type gpr_time_from_micros_import;
+gpr_time_from_nanos_type gpr_time_from_nanos_import;
+gpr_time_from_millis_type gpr_time_from_millis_import;
+gpr_time_from_seconds_type gpr_time_from_seconds_import;
+gpr_time_from_minutes_type gpr_time_from_minutes_import;
+gpr_time_from_hours_type gpr_time_from_hours_import;
+gpr_time_to_millis_type gpr_time_to_millis_import;
+gpr_time_similar_type gpr_time_similar_import;
+gpr_sleep_until_type gpr_sleep_until_import;
+gpr_timespec_to_micros_type gpr_timespec_to_micros_import;
+gpr_avl_create_type gpr_avl_create_import;
+gpr_avl_ref_type gpr_avl_ref_import;
+gpr_avl_unref_type gpr_avl_unref_import;
+gpr_avl_add_type gpr_avl_add_import;
+gpr_avl_remove_type gpr_avl_remove_import;
+gpr_avl_get_type gpr_avl_get_import;
+gpr_cmdline_create_type gpr_cmdline_create_import;
+gpr_cmdline_add_int_type gpr_cmdline_add_int_import;
+gpr_cmdline_add_flag_type gpr_cmdline_add_flag_import;
+gpr_cmdline_add_string_type gpr_cmdline_add_string_import;
+gpr_cmdline_on_extra_arg_type gpr_cmdline_on_extra_arg_import;
+gpr_cmdline_set_survive_failure_type gpr_cmdline_set_survive_failure_import;
+gpr_cmdline_parse_type gpr_cmdline_parse_import;
+gpr_cmdline_destroy_type gpr_cmdline_destroy_import;
+gpr_cmdline_usage_string_type gpr_cmdline_usage_string_import;
+gpr_cpu_num_cores_type gpr_cpu_num_cores_import;
+gpr_cpu_current_cpu_type gpr_cpu_current_cpu_import;
+gpr_histogram_create_type gpr_histogram_create_import;
+gpr_histogram_destroy_type gpr_histogram_destroy_import;
+gpr_histogram_add_type gpr_histogram_add_import;
+gpr_histogram_merge_type gpr_histogram_merge_import;
+gpr_histogram_percentile_type gpr_histogram_percentile_import;
+gpr_histogram_mean_type gpr_histogram_mean_import;
+gpr_histogram_stddev_type gpr_histogram_stddev_import;
+gpr_histogram_variance_type gpr_histogram_variance_import;
+gpr_histogram_maximum_type gpr_histogram_maximum_import;
+gpr_histogram_minimum_type gpr_histogram_minimum_import;
+gpr_histogram_count_type gpr_histogram_count_import;
+gpr_histogram_sum_type gpr_histogram_sum_import;
+gpr_histogram_sum_of_squares_type gpr_histogram_sum_of_squares_import;
+gpr_histogram_get_contents_type gpr_histogram_get_contents_import;
+gpr_histogram_merge_contents_type gpr_histogram_merge_contents_import;
+gpr_join_host_port_type gpr_join_host_port_import;
+gpr_split_host_port_type gpr_split_host_port_import;
+gpr_format_message_type gpr_format_message_import;
+gpr_strdup_type gpr_strdup_import;
+gpr_asprintf_type gpr_asprintf_import;
+gpr_subprocess_binary_extension_type gpr_subprocess_binary_extension_import;
+gpr_subprocess_create_type gpr_subprocess_create_import;
+gpr_subprocess_destroy_type gpr_subprocess_destroy_import;
+gpr_subprocess_join_type gpr_subprocess_join_import;
+gpr_subprocess_interrupt_type gpr_subprocess_interrupt_import;
+gpr_thd_new_type gpr_thd_new_import;
+gpr_thd_options_default_type gpr_thd_options_default_import;
+gpr_thd_options_set_detached_type gpr_thd_options_set_detached_import;
+gpr_thd_options_set_joinable_type gpr_thd_options_set_joinable_import;
+gpr_thd_options_is_detached_type gpr_thd_options_is_detached_import;
+gpr_thd_options_is_joinable_type gpr_thd_options_is_joinable_import;
+gpr_thd_currentid_type gpr_thd_currentid_import;
+gpr_thd_join_type gpr_thd_join_import;
+
+void pygrpc_load_imports(HMODULE library) {
+  census_initialize_import = (census_initialize_type) GetProcAddress(library, "census_initialize");
+  census_shutdown_import = (census_shutdown_type) GetProcAddress(library, "census_shutdown");
+  census_supported_import = (census_supported_type) GetProcAddress(library, "census_supported");
+  census_enabled_import = (census_enabled_type) GetProcAddress(library, "census_enabled");
+  census_context_create_import = (census_context_create_type) GetProcAddress(library, "census_context_create");
+  census_context_destroy_import = (census_context_destroy_type) GetProcAddress(library, "census_context_destroy");
+  census_context_get_status_import = (census_context_get_status_type) GetProcAddress(library, "census_context_get_status");
+  census_context_initialize_iterator_import = (census_context_initialize_iterator_type) GetProcAddress(library, "census_context_initialize_iterator");
+  census_context_next_tag_import = (census_context_next_tag_type) GetProcAddress(library, "census_context_next_tag");
+  census_context_get_tag_import = (census_context_get_tag_type) GetProcAddress(library, "census_context_get_tag");
+  census_context_encode_import = (census_context_encode_type) GetProcAddress(library, "census_context_encode");
+  census_context_decode_import = (census_context_decode_type) GetProcAddress(library, "census_context_decode");
+  census_trace_mask_import = (census_trace_mask_type) GetProcAddress(library, "census_trace_mask");
+  census_set_trace_mask_import = (census_set_trace_mask_type) GetProcAddress(library, "census_set_trace_mask");
+  census_start_rpc_op_timestamp_import = (census_start_rpc_op_timestamp_type) GetProcAddress(library, "census_start_rpc_op_timestamp");
+  census_start_client_rpc_op_import = (census_start_client_rpc_op_type) GetProcAddress(library, "census_start_client_rpc_op");
+  census_set_rpc_client_peer_import = (census_set_rpc_client_peer_type) GetProcAddress(library, "census_set_rpc_client_peer");
+  census_start_server_rpc_op_import = (census_start_server_rpc_op_type) GetProcAddress(library, "census_start_server_rpc_op");
+  census_start_op_import = (census_start_op_type) GetProcAddress(library, "census_start_op");
+  census_end_op_import = (census_end_op_type) GetProcAddress(library, "census_end_op");
+  census_trace_print_import = (census_trace_print_type) GetProcAddress(library, "census_trace_print");
+  census_trace_scan_start_import = (census_trace_scan_start_type) GetProcAddress(library, "census_trace_scan_start");
+  census_get_trace_record_import = (census_get_trace_record_type) GetProcAddress(library, "census_get_trace_record");
+  census_trace_scan_end_import = (census_trace_scan_end_type) GetProcAddress(library, "census_trace_scan_end");
+  census_record_values_import = (census_record_values_type) GetProcAddress(library, "census_record_values");
+  census_view_create_import = (census_view_create_type) GetProcAddress(library, "census_view_create");
+  census_view_delete_import = (census_view_delete_type) GetProcAddress(library, "census_view_delete");
+  census_view_metric_import = (census_view_metric_type) GetProcAddress(library, "census_view_metric");
+  census_view_naggregations_import = (census_view_naggregations_type) GetProcAddress(library, "census_view_naggregations");
+  census_view_tags_import = (census_view_tags_type) GetProcAddress(library, "census_view_tags");
+  census_view_aggregrations_import = (census_view_aggregrations_type) GetProcAddress(library, "census_view_aggregrations");
+  census_view_get_data_import = (census_view_get_data_type) GetProcAddress(library, "census_view_get_data");
+  census_view_reset_import = (census_view_reset_type) GetProcAddress(library, "census_view_reset");
+  grpc_compression_algorithm_parse_import = (grpc_compression_algorithm_parse_type) GetProcAddress(library, "grpc_compression_algorithm_parse");
+  grpc_compression_algorithm_name_import = (grpc_compression_algorithm_name_type) GetProcAddress(library, "grpc_compression_algorithm_name");
+  grpc_compression_algorithm_for_level_import = (grpc_compression_algorithm_for_level_type) GetProcAddress(library, "grpc_compression_algorithm_for_level");
+  grpc_compression_options_init_import = (grpc_compression_options_init_type) GetProcAddress(library, "grpc_compression_options_init");
+  grpc_compression_options_enable_algorithm_import = (grpc_compression_options_enable_algorithm_type) GetProcAddress(library, "grpc_compression_options_enable_algorithm");
+  grpc_compression_options_disable_algorithm_import = (grpc_compression_options_disable_algorithm_type) GetProcAddress(library, "grpc_compression_options_disable_algorithm");
+  grpc_compression_options_is_algorithm_enabled_import = (grpc_compression_options_is_algorithm_enabled_type) GetProcAddress(library, "grpc_compression_options_is_algorithm_enabled");
+  grpc_metadata_array_init_import = (grpc_metadata_array_init_type) GetProcAddress(library, "grpc_metadata_array_init");
+  grpc_metadata_array_destroy_import = (grpc_metadata_array_destroy_type) GetProcAddress(library, "grpc_metadata_array_destroy");
+  grpc_call_details_init_import = (grpc_call_details_init_type) GetProcAddress(library, "grpc_call_details_init");
+  grpc_call_details_destroy_import = (grpc_call_details_destroy_type) GetProcAddress(library, "grpc_call_details_destroy");
+  grpc_register_plugin_import = (grpc_register_plugin_type) GetProcAddress(library, "grpc_register_plugin");
+  grpc_init_import = (grpc_init_type) GetProcAddress(library, "grpc_init");
+  grpc_shutdown_import = (grpc_shutdown_type) GetProcAddress(library, "grpc_shutdown");
+  grpc_version_string_import = (grpc_version_string_type) GetProcAddress(library, "grpc_version_string");
+  grpc_completion_queue_create_import = (grpc_completion_queue_create_type) GetProcAddress(library, "grpc_completion_queue_create");
+  grpc_completion_queue_next_import = (grpc_completion_queue_next_type) GetProcAddress(library, "grpc_completion_queue_next");
+  grpc_completion_queue_pluck_import = (grpc_completion_queue_pluck_type) GetProcAddress(library, "grpc_completion_queue_pluck");
+  grpc_completion_queue_shutdown_import = (grpc_completion_queue_shutdown_type) GetProcAddress(library, "grpc_completion_queue_shutdown");
+  grpc_completion_queue_destroy_import = (grpc_completion_queue_destroy_type) GetProcAddress(library, "grpc_completion_queue_destroy");
+  grpc_alarm_create_import = (grpc_alarm_create_type) GetProcAddress(library, "grpc_alarm_create");
+  grpc_alarm_cancel_import = (grpc_alarm_cancel_type) GetProcAddress(library, "grpc_alarm_cancel");
+  grpc_alarm_destroy_import = (grpc_alarm_destroy_type) GetProcAddress(library, "grpc_alarm_destroy");
+  grpc_channel_check_connectivity_state_import = (grpc_channel_check_connectivity_state_type) GetProcAddress(library, "grpc_channel_check_connectivity_state");
+  grpc_channel_watch_connectivity_state_import = (grpc_channel_watch_connectivity_state_type) GetProcAddress(library, "grpc_channel_watch_connectivity_state");
+  grpc_channel_create_call_import = (grpc_channel_create_call_type) GetProcAddress(library, "grpc_channel_create_call");
+  grpc_channel_ping_import = (grpc_channel_ping_type) GetProcAddress(library, "grpc_channel_ping");
+  grpc_channel_register_call_import = (grpc_channel_register_call_type) GetProcAddress(library, "grpc_channel_register_call");
+  grpc_channel_create_registered_call_import = (grpc_channel_create_registered_call_type) GetProcAddress(library, "grpc_channel_create_registered_call");
+  grpc_call_start_batch_import = (grpc_call_start_batch_type) GetProcAddress(library, "grpc_call_start_batch");
+  grpc_call_get_peer_import = (grpc_call_get_peer_type) GetProcAddress(library, "grpc_call_get_peer");
+  grpc_census_call_set_context_import = (grpc_census_call_set_context_type) GetProcAddress(library, "grpc_census_call_set_context");
+  grpc_census_call_get_context_import = (grpc_census_call_get_context_type) GetProcAddress(library, "grpc_census_call_get_context");
+  grpc_channel_get_target_import = (grpc_channel_get_target_type) GetProcAddress(library, "grpc_channel_get_target");
+  grpc_insecure_channel_create_import = (grpc_insecure_channel_create_type) GetProcAddress(library, "grpc_insecure_channel_create");
+  grpc_lame_client_channel_create_import = (grpc_lame_client_channel_create_type) GetProcAddress(library, "grpc_lame_client_channel_create");
+  grpc_channel_destroy_import = (grpc_channel_destroy_type) GetProcAddress(library, "grpc_channel_destroy");
+  grpc_call_cancel_import = (grpc_call_cancel_type) GetProcAddress(library, "grpc_call_cancel");
+  grpc_call_cancel_with_status_import = (grpc_call_cancel_with_status_type) GetProcAddress(library, "grpc_call_cancel_with_status");
+  grpc_call_destroy_import = (grpc_call_destroy_type) GetProcAddress(library, "grpc_call_destroy");
+  grpc_server_request_call_import = (grpc_server_request_call_type) GetProcAddress(library, "grpc_server_request_call");
+  grpc_server_register_method_import = (grpc_server_register_method_type) GetProcAddress(library, "grpc_server_register_method");
+  grpc_server_request_registered_call_import = (grpc_server_request_registered_call_type) GetProcAddress(library, "grpc_server_request_registered_call");
+  grpc_server_create_import = (grpc_server_create_type) GetProcAddress(library, "grpc_server_create");
+  grpc_server_register_completion_queue_import = (grpc_server_register_completion_queue_type) GetProcAddress(library, "grpc_server_register_completion_queue");
+  grpc_server_add_insecure_http2_port_import = (grpc_server_add_insecure_http2_port_type) GetProcAddress(library, "grpc_server_add_insecure_http2_port");
+  grpc_server_start_import = (grpc_server_start_type) GetProcAddress(library, "grpc_server_start");
+  grpc_server_shutdown_and_notify_import = (grpc_server_shutdown_and_notify_type) GetProcAddress(library, "grpc_server_shutdown_and_notify");
+  grpc_server_cancel_all_calls_import = (grpc_server_cancel_all_calls_type) GetProcAddress(library, "grpc_server_cancel_all_calls");
+  grpc_server_destroy_import = (grpc_server_destroy_type) GetProcAddress(library, "grpc_server_destroy");
+  grpc_tracer_set_enabled_import = (grpc_tracer_set_enabled_type) GetProcAddress(library, "grpc_tracer_set_enabled");
+  grpc_header_key_is_legal_import = (grpc_header_key_is_legal_type) GetProcAddress(library, "grpc_header_key_is_legal");
+  grpc_header_nonbin_value_is_legal_import = (grpc_header_nonbin_value_is_legal_type) GetProcAddress(library, "grpc_header_nonbin_value_is_legal");
+  grpc_is_binary_header_import = (grpc_is_binary_header_type) GetProcAddress(library, "grpc_is_binary_header");
+  grpc_auth_property_iterator_next_import = (grpc_auth_property_iterator_next_type) GetProcAddress(library, "grpc_auth_property_iterator_next");
+  grpc_auth_context_property_iterator_import = (grpc_auth_context_property_iterator_type) GetProcAddress(library, "grpc_auth_context_property_iterator");
+  grpc_auth_context_peer_identity_import = (grpc_auth_context_peer_identity_type) GetProcAddress(library, "grpc_auth_context_peer_identity");
+  grpc_auth_context_find_properties_by_name_import = (grpc_auth_context_find_properties_by_name_type) GetProcAddress(library, "grpc_auth_context_find_properties_by_name");
+  grpc_auth_context_peer_identity_property_name_import = (grpc_auth_context_peer_identity_property_name_type) GetProcAddress(library, "grpc_auth_context_peer_identity_property_name");
+  grpc_auth_context_peer_is_authenticated_import = (grpc_auth_context_peer_is_authenticated_type) GetProcAddress(library, "grpc_auth_context_peer_is_authenticated");
+  grpc_call_auth_context_import = (grpc_call_auth_context_type) GetProcAddress(library, "grpc_call_auth_context");
+  grpc_auth_context_release_import = (grpc_auth_context_release_type) GetProcAddress(library, "grpc_auth_context_release");
+  grpc_auth_context_add_property_import = (grpc_auth_context_add_property_type) GetProcAddress(library, "grpc_auth_context_add_property");
+  grpc_auth_context_add_cstring_property_import = (grpc_auth_context_add_cstring_property_type) GetProcAddress(library, "grpc_auth_context_add_cstring_property");
+  grpc_auth_context_set_peer_identity_property_name_import = (grpc_auth_context_set_peer_identity_property_name_type) GetProcAddress(library, "grpc_auth_context_set_peer_identity_property_name");
+  grpc_channel_credentials_release_import = (grpc_channel_credentials_release_type) GetProcAddress(library, "grpc_channel_credentials_release");
+  grpc_google_default_credentials_create_import = (grpc_google_default_credentials_create_type) GetProcAddress(library, "grpc_google_default_credentials_create");
+  grpc_ssl_credentials_create_import = (grpc_ssl_credentials_create_type) GetProcAddress(library, "grpc_ssl_credentials_create");
+  grpc_call_credentials_release_import = (grpc_call_credentials_release_type) GetProcAddress(library, "grpc_call_credentials_release");
+  grpc_composite_channel_credentials_create_import = (grpc_composite_channel_credentials_create_type) GetProcAddress(library, "grpc_composite_channel_credentials_create");
+  grpc_composite_call_credentials_create_import = (grpc_composite_call_credentials_create_type) GetProcAddress(library, "grpc_composite_call_credentials_create");
+  grpc_google_compute_engine_credentials_create_import = (grpc_google_compute_engine_credentials_create_type) GetProcAddress(library, "grpc_google_compute_engine_credentials_create");
+  grpc_max_auth_token_lifetime_import = (grpc_max_auth_token_lifetime_type) GetProcAddress(library, "grpc_max_auth_token_lifetime");
+  grpc_service_account_jwt_access_credentials_create_import = (grpc_service_account_jwt_access_credentials_create_type) GetProcAddress(library, "grpc_service_account_jwt_access_credentials_create");
+  grpc_google_refresh_token_credentials_create_import = (grpc_google_refresh_token_credentials_create_type) GetProcAddress(library, "grpc_google_refresh_token_credentials_create");
+  grpc_access_token_credentials_create_import = (grpc_access_token_credentials_create_type) GetProcAddress(library, "grpc_access_token_credentials_create");
+  grpc_google_iam_credentials_create_import = (grpc_google_iam_credentials_create_type) GetProcAddress(library, "grpc_google_iam_credentials_create");
+  grpc_metadata_credentials_create_from_plugin_import = (grpc_metadata_credentials_create_from_plugin_type) GetProcAddress(library, "grpc_metadata_credentials_create_from_plugin");
+  grpc_secure_channel_create_import = (grpc_secure_channel_create_type) GetProcAddress(library, "grpc_secure_channel_create");
+  grpc_server_credentials_release_import = (grpc_server_credentials_release_type) GetProcAddress(library, "grpc_server_credentials_release");
+  grpc_ssl_server_credentials_create_import = (grpc_ssl_server_credentials_create_type) GetProcAddress(library, "grpc_ssl_server_credentials_create");
+  grpc_server_add_secure_http2_port_import = (grpc_server_add_secure_http2_port_type) GetProcAddress(library, "grpc_server_add_secure_http2_port");
+  grpc_call_set_credentials_import = (grpc_call_set_credentials_type) GetProcAddress(library, "grpc_call_set_credentials");
+  grpc_server_credentials_set_auth_metadata_processor_import = (grpc_server_credentials_set_auth_metadata_processor_type) GetProcAddress(library, "grpc_server_credentials_set_auth_metadata_processor");
+  gpr_malloc_import = (gpr_malloc_type) GetProcAddress(library, "gpr_malloc");
+  gpr_free_import = (gpr_free_type) GetProcAddress(library, "gpr_free");
+  gpr_realloc_import = (gpr_realloc_type) GetProcAddress(library, "gpr_realloc");
+  gpr_malloc_aligned_import = (gpr_malloc_aligned_type) GetProcAddress(library, "gpr_malloc_aligned");
+  gpr_free_aligned_import = (gpr_free_aligned_type) GetProcAddress(library, "gpr_free_aligned");
+  gpr_set_allocation_functions_import = (gpr_set_allocation_functions_type) GetProcAddress(library, "gpr_set_allocation_functions");
+  gpr_get_allocation_functions_import = (gpr_get_allocation_functions_type) GetProcAddress(library, "gpr_get_allocation_functions");
+  grpc_raw_byte_buffer_create_import = (grpc_raw_byte_buffer_create_type) GetProcAddress(library, "grpc_raw_byte_buffer_create");
+  grpc_raw_compressed_byte_buffer_create_import = (grpc_raw_compressed_byte_buffer_create_type) GetProcAddress(library, "grpc_raw_compressed_byte_buffer_create");
+  grpc_byte_buffer_copy_import = (grpc_byte_buffer_copy_type) GetProcAddress(library, "grpc_byte_buffer_copy");
+  grpc_byte_buffer_length_import = (grpc_byte_buffer_length_type) GetProcAddress(library, "grpc_byte_buffer_length");
+  grpc_byte_buffer_destroy_import = (grpc_byte_buffer_destroy_type) GetProcAddress(library, "grpc_byte_buffer_destroy");
+  grpc_byte_buffer_reader_init_import = (grpc_byte_buffer_reader_init_type) GetProcAddress(library, "grpc_byte_buffer_reader_init");
+  grpc_byte_buffer_reader_destroy_import = (grpc_byte_buffer_reader_destroy_type) GetProcAddress(library, "grpc_byte_buffer_reader_destroy");
+  grpc_byte_buffer_reader_next_import = (grpc_byte_buffer_reader_next_type) GetProcAddress(library, "grpc_byte_buffer_reader_next");
+  grpc_byte_buffer_reader_readall_import = (grpc_byte_buffer_reader_readall_type) GetProcAddress(library, "grpc_byte_buffer_reader_readall");
+  grpc_raw_byte_buffer_from_reader_import = (grpc_raw_byte_buffer_from_reader_type) GetProcAddress(library, "grpc_raw_byte_buffer_from_reader");
+  gpr_log_import = (gpr_log_type) GetProcAddress(library, "gpr_log");
+  gpr_log_message_import = (gpr_log_message_type) GetProcAddress(library, "gpr_log_message");
+  gpr_set_log_function_import = (gpr_set_log_function_type) GetProcAddress(library, "gpr_set_log_function");
+  gpr_slice_ref_import = (gpr_slice_ref_type) GetProcAddress(library, "gpr_slice_ref");
+  gpr_slice_unref_import = (gpr_slice_unref_type) GetProcAddress(library, "gpr_slice_unref");
+  gpr_slice_new_import = (gpr_slice_new_type) GetProcAddress(library, "gpr_slice_new");
+  gpr_slice_new_with_len_import = (gpr_slice_new_with_len_type) GetProcAddress(library, "gpr_slice_new_with_len");
+  gpr_slice_malloc_import = (gpr_slice_malloc_type) GetProcAddress(library, "gpr_slice_malloc");
+  gpr_slice_from_copied_string_import = (gpr_slice_from_copied_string_type) GetProcAddress(library, "gpr_slice_from_copied_string");
+  gpr_slice_from_copied_buffer_import = (gpr_slice_from_copied_buffer_type) GetProcAddress(library, "gpr_slice_from_copied_buffer");
+  gpr_slice_from_static_string_import = (gpr_slice_from_static_string_type) GetProcAddress(library, "gpr_slice_from_static_string");
+  gpr_slice_sub_import = (gpr_slice_sub_type) GetProcAddress(library, "gpr_slice_sub");
+  gpr_slice_sub_no_ref_import = (gpr_slice_sub_no_ref_type) GetProcAddress(library, "gpr_slice_sub_no_ref");
+  gpr_slice_split_tail_import = (gpr_slice_split_tail_type) GetProcAddress(library, "gpr_slice_split_tail");
+  gpr_slice_split_head_import = (gpr_slice_split_head_type) GetProcAddress(library, "gpr_slice_split_head");
+  gpr_empty_slice_import = (gpr_empty_slice_type) GetProcAddress(library, "gpr_empty_slice");
+  gpr_slice_cmp_import = (gpr_slice_cmp_type) GetProcAddress(library, "gpr_slice_cmp");
+  gpr_slice_str_cmp_import = (gpr_slice_str_cmp_type) GetProcAddress(library, "gpr_slice_str_cmp");
+  gpr_slice_buffer_init_import = (gpr_slice_buffer_init_type) GetProcAddress(library, "gpr_slice_buffer_init");
+  gpr_slice_buffer_destroy_import = (gpr_slice_buffer_destroy_type) GetProcAddress(library, "gpr_slice_buffer_destroy");
+  gpr_slice_buffer_add_import = (gpr_slice_buffer_add_type) GetProcAddress(library, "gpr_slice_buffer_add");
+  gpr_slice_buffer_add_indexed_import = (gpr_slice_buffer_add_indexed_type) GetProcAddress(library, "gpr_slice_buffer_add_indexed");
+  gpr_slice_buffer_addn_import = (gpr_slice_buffer_addn_type) GetProcAddress(library, "gpr_slice_buffer_addn");
+  gpr_slice_buffer_tiny_add_import = (gpr_slice_buffer_tiny_add_type) GetProcAddress(library, "gpr_slice_buffer_tiny_add");
+  gpr_slice_buffer_pop_import = (gpr_slice_buffer_pop_type) GetProcAddress(library, "gpr_slice_buffer_pop");
+  gpr_slice_buffer_reset_and_unref_import = (gpr_slice_buffer_reset_and_unref_type) GetProcAddress(library, "gpr_slice_buffer_reset_and_unref");
+  gpr_slice_buffer_swap_import = (gpr_slice_buffer_swap_type) GetProcAddress(library, "gpr_slice_buffer_swap");
+  gpr_slice_buffer_move_into_import = (gpr_slice_buffer_move_into_type) GetProcAddress(library, "gpr_slice_buffer_move_into");
+  gpr_slice_buffer_trim_end_import = (gpr_slice_buffer_trim_end_type) GetProcAddress(library, "gpr_slice_buffer_trim_end");
+  gpr_slice_buffer_move_first_import = (gpr_slice_buffer_move_first_type) GetProcAddress(library, "gpr_slice_buffer_move_first");
+  gpr_slice_buffer_take_first_import = (gpr_slice_buffer_take_first_type) GetProcAddress(library, "gpr_slice_buffer_take_first");
+  gpr_mu_init_import = (gpr_mu_init_type) GetProcAddress(library, "gpr_mu_init");
+  gpr_mu_destroy_import = (gpr_mu_destroy_type) GetProcAddress(library, "gpr_mu_destroy");
+  gpr_mu_lock_import = (gpr_mu_lock_type) GetProcAddress(library, "gpr_mu_lock");
+  gpr_mu_unlock_import = (gpr_mu_unlock_type) GetProcAddress(library, "gpr_mu_unlock");
+  gpr_mu_trylock_import = (gpr_mu_trylock_type) GetProcAddress(library, "gpr_mu_trylock");
+  gpr_cv_init_import = (gpr_cv_init_type) GetProcAddress(library, "gpr_cv_init");
+  gpr_cv_destroy_import = (gpr_cv_destroy_type) GetProcAddress(library, "gpr_cv_destroy");
+  gpr_cv_wait_import = (gpr_cv_wait_type) GetProcAddress(library, "gpr_cv_wait");
+  gpr_cv_signal_import = (gpr_cv_signal_type) GetProcAddress(library, "gpr_cv_signal");
+  gpr_cv_broadcast_import = (gpr_cv_broadcast_type) GetProcAddress(library, "gpr_cv_broadcast");
+  gpr_once_init_import = (gpr_once_init_type) GetProcAddress(library, "gpr_once_init");
+  gpr_event_init_import = (gpr_event_init_type) GetProcAddress(library, "gpr_event_init");
+  gpr_event_set_import = (gpr_event_set_type) GetProcAddress(library, "gpr_event_set");
+  gpr_event_get_import = (gpr_event_get_type) GetProcAddress(library, "gpr_event_get");
+  gpr_event_wait_import = (gpr_event_wait_type) GetProcAddress(library, "gpr_event_wait");
+  gpr_ref_init_import = (gpr_ref_init_type) GetProcAddress(library, "gpr_ref_init");
+  gpr_ref_import = (gpr_ref_type) GetProcAddress(library, "gpr_ref");
+  gpr_refn_import = (gpr_refn_type) GetProcAddress(library, "gpr_refn");
+  gpr_unref_import = (gpr_unref_type) GetProcAddress(library, "gpr_unref");
+  gpr_stats_init_import = (gpr_stats_init_type) GetProcAddress(library, "gpr_stats_init");
+  gpr_stats_inc_import = (gpr_stats_inc_type) GetProcAddress(library, "gpr_stats_inc");
+  gpr_stats_read_import = (gpr_stats_read_type) GetProcAddress(library, "gpr_stats_read");
+  gpr_time_0_import = (gpr_time_0_type) GetProcAddress(library, "gpr_time_0");
+  gpr_inf_future_import = (gpr_inf_future_type) GetProcAddress(library, "gpr_inf_future");
+  gpr_inf_past_import = (gpr_inf_past_type) GetProcAddress(library, "gpr_inf_past");
+  gpr_time_init_import = (gpr_time_init_type) GetProcAddress(library, "gpr_time_init");
+  gpr_now_import = (gpr_now_type) GetProcAddress(library, "gpr_now");
+  gpr_convert_clock_type_import = (gpr_convert_clock_type_type) GetProcAddress(library, "gpr_convert_clock_type");
+  gpr_time_cmp_import = (gpr_time_cmp_type) GetProcAddress(library, "gpr_time_cmp");
+  gpr_time_max_import = (gpr_time_max_type) GetProcAddress(library, "gpr_time_max");
+  gpr_time_min_import = (gpr_time_min_type) GetProcAddress(library, "gpr_time_min");
+  gpr_time_add_import = (gpr_time_add_type) GetProcAddress(library, "gpr_time_add");
+  gpr_time_sub_import = (gpr_time_sub_type) GetProcAddress(library, "gpr_time_sub");
+  gpr_time_from_micros_import = (gpr_time_from_micros_type) GetProcAddress(library, "gpr_time_from_micros");
+  gpr_time_from_nanos_import = (gpr_time_from_nanos_type) GetProcAddress(library, "gpr_time_from_nanos");
+  gpr_time_from_millis_import = (gpr_time_from_millis_type) GetProcAddress(library, "gpr_time_from_millis");
+  gpr_time_from_seconds_import = (gpr_time_from_seconds_type) GetProcAddress(library, "gpr_time_from_seconds");
+  gpr_time_from_minutes_import = (gpr_time_from_minutes_type) GetProcAddress(library, "gpr_time_from_minutes");
+  gpr_time_from_hours_import = (gpr_time_from_hours_type) GetProcAddress(library, "gpr_time_from_hours");
+  gpr_time_to_millis_import = (gpr_time_to_millis_type) GetProcAddress(library, "gpr_time_to_millis");
+  gpr_time_similar_import = (gpr_time_similar_type) GetProcAddress(library, "gpr_time_similar");
+  gpr_sleep_until_import = (gpr_sleep_until_type) GetProcAddress(library, "gpr_sleep_until");
+  gpr_timespec_to_micros_import = (gpr_timespec_to_micros_type) GetProcAddress(library, "gpr_timespec_to_micros");
+  gpr_avl_create_import = (gpr_avl_create_type) GetProcAddress(library, "gpr_avl_create");
+  gpr_avl_ref_import = (gpr_avl_ref_type) GetProcAddress(library, "gpr_avl_ref");
+  gpr_avl_unref_import = (gpr_avl_unref_type) GetProcAddress(library, "gpr_avl_unref");
+  gpr_avl_add_import = (gpr_avl_add_type) GetProcAddress(library, "gpr_avl_add");
+  gpr_avl_remove_import = (gpr_avl_remove_type) GetProcAddress(library, "gpr_avl_remove");
+  gpr_avl_get_import = (gpr_avl_get_type) GetProcAddress(library, "gpr_avl_get");
+  gpr_cmdline_create_import = (gpr_cmdline_create_type) GetProcAddress(library, "gpr_cmdline_create");
+  gpr_cmdline_add_int_import = (gpr_cmdline_add_int_type) GetProcAddress(library, "gpr_cmdline_add_int");
+  gpr_cmdline_add_flag_import = (gpr_cmdline_add_flag_type) GetProcAddress(library, "gpr_cmdline_add_flag");
+  gpr_cmdline_add_string_import = (gpr_cmdline_add_string_type) GetProcAddress(library, "gpr_cmdline_add_string");
+  gpr_cmdline_on_extra_arg_import = (gpr_cmdline_on_extra_arg_type) GetProcAddress(library, "gpr_cmdline_on_extra_arg");
+  gpr_cmdline_set_survive_failure_import = (gpr_cmdline_set_survive_failure_type) GetProcAddress(library, "gpr_cmdline_set_survive_failure");
+  gpr_cmdline_parse_import = (gpr_cmdline_parse_type) GetProcAddress(library, "gpr_cmdline_parse");
+  gpr_cmdline_destroy_import = (gpr_cmdline_destroy_type) GetProcAddress(library, "gpr_cmdline_destroy");
+  gpr_cmdline_usage_string_import = (gpr_cmdline_usage_string_type) GetProcAddress(library, "gpr_cmdline_usage_string");
+  gpr_cpu_num_cores_import = (gpr_cpu_num_cores_type) GetProcAddress(library, "gpr_cpu_num_cores");
+  gpr_cpu_current_cpu_import = (gpr_cpu_current_cpu_type) GetProcAddress(library, "gpr_cpu_current_cpu");
+  gpr_histogram_create_import = (gpr_histogram_create_type) GetProcAddress(library, "gpr_histogram_create");
+  gpr_histogram_destroy_import = (gpr_histogram_destroy_type) GetProcAddress(library, "gpr_histogram_destroy");
+  gpr_histogram_add_import = (gpr_histogram_add_type) GetProcAddress(library, "gpr_histogram_add");
+  gpr_histogram_merge_import = (gpr_histogram_merge_type) GetProcAddress(library, "gpr_histogram_merge");
+  gpr_histogram_percentile_import = (gpr_histogram_percentile_type) GetProcAddress(library, "gpr_histogram_percentile");
+  gpr_histogram_mean_import = (gpr_histogram_mean_type) GetProcAddress(library, "gpr_histogram_mean");
+  gpr_histogram_stddev_import = (gpr_histogram_stddev_type) GetProcAddress(library, "gpr_histogram_stddev");
+  gpr_histogram_variance_import = (gpr_histogram_variance_type) GetProcAddress(library, "gpr_histogram_variance");
+  gpr_histogram_maximum_import = (gpr_histogram_maximum_type) GetProcAddress(library, "gpr_histogram_maximum");
+  gpr_histogram_minimum_import = (gpr_histogram_minimum_type) GetProcAddress(library, "gpr_histogram_minimum");
+  gpr_histogram_count_import = (gpr_histogram_count_type) GetProcAddress(library, "gpr_histogram_count");
+  gpr_histogram_sum_import = (gpr_histogram_sum_type) GetProcAddress(library, "gpr_histogram_sum");
+  gpr_histogram_sum_of_squares_import = (gpr_histogram_sum_of_squares_type) GetProcAddress(library, "gpr_histogram_sum_of_squares");
+  gpr_histogram_get_contents_import = (gpr_histogram_get_contents_type) GetProcAddress(library, "gpr_histogram_get_contents");
+  gpr_histogram_merge_contents_import = (gpr_histogram_merge_contents_type) GetProcAddress(library, "gpr_histogram_merge_contents");
+  gpr_join_host_port_import = (gpr_join_host_port_type) GetProcAddress(library, "gpr_join_host_port");
+  gpr_split_host_port_import = (gpr_split_host_port_type) GetProcAddress(library, "gpr_split_host_port");
+  gpr_format_message_import = (gpr_format_message_type) GetProcAddress(library, "gpr_format_message");
+  gpr_strdup_import = (gpr_strdup_type) GetProcAddress(library, "gpr_strdup");
+  gpr_asprintf_import = (gpr_asprintf_type) GetProcAddress(library, "gpr_asprintf");
+  gpr_subprocess_binary_extension_import = (gpr_subprocess_binary_extension_type) GetProcAddress(library, "gpr_subprocess_binary_extension");
+  gpr_subprocess_create_import = (gpr_subprocess_create_type) GetProcAddress(library, "gpr_subprocess_create");
+  gpr_subprocess_destroy_import = (gpr_subprocess_destroy_type) GetProcAddress(library, "gpr_subprocess_destroy");
+  gpr_subprocess_join_import = (gpr_subprocess_join_type) GetProcAddress(library, "gpr_subprocess_join");
+  gpr_subprocess_interrupt_import = (gpr_subprocess_interrupt_type) GetProcAddress(library, "gpr_subprocess_interrupt");
+  gpr_thd_new_import = (gpr_thd_new_type) GetProcAddress(library, "gpr_thd_new");
+  gpr_thd_options_default_import = (gpr_thd_options_default_type) GetProcAddress(library, "gpr_thd_options_default");
+  gpr_thd_options_set_detached_import = (gpr_thd_options_set_detached_type) GetProcAddress(library, "gpr_thd_options_set_detached");
+  gpr_thd_options_set_joinable_import = (gpr_thd_options_set_joinable_type) GetProcAddress(library, "gpr_thd_options_set_joinable");
+  gpr_thd_options_is_detached_import = (gpr_thd_options_is_detached_type) GetProcAddress(library, "gpr_thd_options_is_detached");
+  gpr_thd_options_is_joinable_import = (gpr_thd_options_is_joinable_type) GetProcAddress(library, "gpr_thd_options_is_joinable");
+  gpr_thd_currentid_import = (gpr_thd_currentid_type) GetProcAddress(library, "gpr_thd_currentid");
+  gpr_thd_join_import = (gpr_thd_join_type) GetProcAddress(library, "gpr_thd_join");
+}
+
+#endif /* !GPR_WIN32 */
diff --git a/src/python/grpcio/grpc/_cython/imports.generated.h b/src/python/grpcio/grpc/_cython/imports.generated.h
new file mode 100644
index 0000000..6d0a6e0
--- /dev/null
+++ b/src/python/grpcio/grpc/_cython/imports.generated.h
@@ -0,0 +1,854 @@
+/*
+ *
+ * Copyright 2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef PYGRPC_CYTHON_WINDOWS_IMPORTS_H_
+#define PYGRPC_CYTHON_WINDOWS_IMPORTS_H_
+
+#include <grpc/support/port_platform.h>
+
+#ifdef GPR_WIN32
+
+#include <windows.h>
+
+#include <grpc/census.h>
+#include <grpc/compression.h>
+#include <grpc/grpc.h>
+#include <grpc/grpc_security.h>
+#include <grpc/impl/codegen/alloc.h>
+#include <grpc/impl/codegen/byte_buffer.h>
+#include <grpc/impl/codegen/log.h>
+#include <grpc/impl/codegen/slice.h>
+#include <grpc/impl/codegen/slice_buffer.h>
+#include <grpc/impl/codegen/sync.h>
+#include <grpc/impl/codegen/time.h>
+#include <grpc/support/avl.h>
+#include <grpc/support/cmdline.h>
+#include <grpc/support/cpu.h>
+#include <grpc/support/histogram.h>
+#include <grpc/support/host_port.h>
+#include <grpc/support/log_win32.h>
+#include <grpc/support/string_util.h>
+#include <grpc/support/subprocess.h>
+#include <grpc/support/thd.h>
+
+typedef int(*census_initialize_type)(int features);
+extern census_initialize_type census_initialize_import;
+#define census_initialize census_initialize_import
+typedef void(*census_shutdown_type)(void);
+extern census_shutdown_type census_shutdown_import;
+#define census_shutdown census_shutdown_import
+typedef int(*census_supported_type)(void);
+extern census_supported_type census_supported_import;
+#define census_supported census_supported_import
+typedef int(*census_enabled_type)(void);
+extern census_enabled_type census_enabled_import;
+#define census_enabled census_enabled_import
+typedef census_context *(*census_context_create_type)(const census_context *base, const census_tag *tags, int ntags, census_context_status const **status);
+extern census_context_create_type census_context_create_import;
+#define census_context_create census_context_create_import
+typedef void(*census_context_destroy_type)(census_context *context);
+extern census_context_destroy_type census_context_destroy_import;
+#define census_context_destroy census_context_destroy_import
+typedef const census_context_status *(*census_context_get_status_type)(const census_context *context);
+extern census_context_get_status_type census_context_get_status_import;
+#define census_context_get_status census_context_get_status_import
+typedef void(*census_context_initialize_iterator_type)(const census_context *context, census_context_iterator *iterator);
+extern census_context_initialize_iterator_type census_context_initialize_iterator_import;
+#define census_context_initialize_iterator census_context_initialize_iterator_import
+typedef int(*census_context_next_tag_type)(census_context_iterator *iterator, census_tag *tag);
+extern census_context_next_tag_type census_context_next_tag_import;
+#define census_context_next_tag census_context_next_tag_import
+typedef int(*census_context_get_tag_type)(const census_context *context, const char *key, census_tag *tag);
+extern census_context_get_tag_type census_context_get_tag_import;
+#define census_context_get_tag census_context_get_tag_import
+typedef char *(*census_context_encode_type)(const census_context *context, char *buffer, size_t buf_size, size_t *print_buf_size, size_t *bin_buf_size);
+extern census_context_encode_type census_context_encode_import;
+#define census_context_encode census_context_encode_import
+typedef census_context *(*census_context_decode_type)(const char *buffer, size_t size, const char *bin_buffer, size_t bin_size);
+extern census_context_decode_type census_context_decode_import;
+#define census_context_decode census_context_decode_import
+typedef int(*census_trace_mask_type)(const census_context *context);
+extern census_trace_mask_type census_trace_mask_import;
+#define census_trace_mask census_trace_mask_import
+typedef void(*census_set_trace_mask_type)(int trace_mask);
+extern census_set_trace_mask_type census_set_trace_mask_import;
+#define census_set_trace_mask census_set_trace_mask_import
+typedef census_timestamp(*census_start_rpc_op_timestamp_type)(void);
+extern census_start_rpc_op_timestamp_type census_start_rpc_op_timestamp_import;
+#define census_start_rpc_op_timestamp census_start_rpc_op_timestamp_import
+typedef census_context *(*census_start_client_rpc_op_type)(const census_context *context, int64_t rpc_name_id, const census_rpc_name_info *rpc_name_info, const char *peer, int trace_mask, const census_timestamp *start_time);
+extern census_start_client_rpc_op_type census_start_client_rpc_op_import;
+#define census_start_client_rpc_op census_start_client_rpc_op_import
+typedef void(*census_set_rpc_client_peer_type)(census_context *context, const char *peer);
+extern census_set_rpc_client_peer_type census_set_rpc_client_peer_import;
+#define census_set_rpc_client_peer census_set_rpc_client_peer_import
+typedef census_context *(*census_start_server_rpc_op_type)(const char *buffer, int64_t rpc_name_id, const census_rpc_name_info *rpc_name_info, const char *peer, int trace_mask, census_timestamp *start_time);
+extern census_start_server_rpc_op_type census_start_server_rpc_op_import;
+#define census_start_server_rpc_op census_start_server_rpc_op_import
+typedef census_context *(*census_start_op_type)(census_context *context, const char *family, const char *name, int trace_mask);
+extern census_start_op_type census_start_op_import;
+#define census_start_op census_start_op_import
+typedef void(*census_end_op_type)(census_context *context, int status);
+extern census_end_op_type census_end_op_import;
+#define census_end_op census_end_op_import
+typedef void(*census_trace_print_type)(census_context *context, uint32_t type, const char *buffer, size_t n);
+extern census_trace_print_type census_trace_print_import;
+#define census_trace_print census_trace_print_import
+typedef int(*census_trace_scan_start_type)(int consume);
+extern census_trace_scan_start_type census_trace_scan_start_import;
+#define census_trace_scan_start census_trace_scan_start_import
+typedef int(*census_get_trace_record_type)(census_trace_record *trace_record);
+extern census_get_trace_record_type census_get_trace_record_import;
+#define census_get_trace_record census_get_trace_record_import
+typedef void(*census_trace_scan_end_type)();
+extern census_trace_scan_end_type census_trace_scan_end_import;
+#define census_trace_scan_end census_trace_scan_end_import
+typedef void(*census_record_values_type)(census_context *context, census_value *values, size_t nvalues);
+extern census_record_values_type census_record_values_import;
+#define census_record_values census_record_values_import
+typedef census_view *(*census_view_create_type)(uint32_t metric_id, const census_context *tags, const census_aggregation *aggregations, size_t naggregations);
+extern census_view_create_type census_view_create_import;
+#define census_view_create census_view_create_import
+typedef void(*census_view_delete_type)(census_view *view);
+extern census_view_delete_type census_view_delete_import;
+#define census_view_delete census_view_delete_import
+typedef size_t(*census_view_metric_type)(const census_view *view);
+extern census_view_metric_type census_view_metric_import;
+#define census_view_metric census_view_metric_import
+typedef size_t(*census_view_naggregations_type)(const census_view *view);
+extern census_view_naggregations_type census_view_naggregations_import;
+#define census_view_naggregations census_view_naggregations_import
+typedef const census_context *(*census_view_tags_type)(const census_view *view);
+extern census_view_tags_type census_view_tags_import;
+#define census_view_tags census_view_tags_import
+typedef const census_aggregation *(*census_view_aggregrations_type)(const census_view *view);
+extern census_view_aggregrations_type census_view_aggregrations_import;
+#define census_view_aggregrations census_view_aggregrations_import
+typedef const census_view_data *(*census_view_get_data_type)(const census_view *view);
+extern census_view_get_data_type census_view_get_data_import;
+#define census_view_get_data census_view_get_data_import
+typedef void(*census_view_reset_type)(census_view *view);
+extern census_view_reset_type census_view_reset_import;
+#define census_view_reset census_view_reset_import
+typedef int(*grpc_compression_algorithm_parse_type)(const char *name, size_t name_length, grpc_compression_algorithm *algorithm);
+extern grpc_compression_algorithm_parse_type grpc_compression_algorithm_parse_import;
+#define grpc_compression_algorithm_parse grpc_compression_algorithm_parse_import
+typedef int(*grpc_compression_algorithm_name_type)(grpc_compression_algorithm algorithm, char **name);
+extern grpc_compression_algorithm_name_type grpc_compression_algorithm_name_import;
+#define grpc_compression_algorithm_name grpc_compression_algorithm_name_import
+typedef grpc_compression_algorithm(*grpc_compression_algorithm_for_level_type)(grpc_compression_level level);
+extern grpc_compression_algorithm_for_level_type grpc_compression_algorithm_for_level_import;
+#define grpc_compression_algorithm_for_level grpc_compression_algorithm_for_level_import
+typedef void(*grpc_compression_options_init_type)(grpc_compression_options *opts);
+extern grpc_compression_options_init_type grpc_compression_options_init_import;
+#define grpc_compression_options_init grpc_compression_options_init_import
+typedef void(*grpc_compression_options_enable_algorithm_type)(grpc_compression_options *opts, grpc_compression_algorithm algorithm);
+extern grpc_compression_options_enable_algorithm_type grpc_compression_options_enable_algorithm_import;
+#define grpc_compression_options_enable_algorithm grpc_compression_options_enable_algorithm_import
+typedef void(*grpc_compression_options_disable_algorithm_type)(grpc_compression_options *opts, grpc_compression_algorithm algorithm);
+extern grpc_compression_options_disable_algorithm_type grpc_compression_options_disable_algorithm_import;
+#define grpc_compression_options_disable_algorithm grpc_compression_options_disable_algorithm_import
+typedef int(*grpc_compression_options_is_algorithm_enabled_type)(const grpc_compression_options *opts, grpc_compression_algorithm algorithm);
+extern grpc_compression_options_is_algorithm_enabled_type grpc_compression_options_is_algorithm_enabled_import;
+#define grpc_compression_options_is_algorithm_enabled grpc_compression_options_is_algorithm_enabled_import
+typedef void(*grpc_metadata_array_init_type)(grpc_metadata_array *array);
+extern grpc_metadata_array_init_type grpc_metadata_array_init_import;
+#define grpc_metadata_array_init grpc_metadata_array_init_import
+typedef void(*grpc_metadata_array_destroy_type)(grpc_metadata_array *array);
+extern grpc_metadata_array_destroy_type grpc_metadata_array_destroy_import;
+#define grpc_metadata_array_destroy grpc_metadata_array_destroy_import
+typedef void(*grpc_call_details_init_type)(grpc_call_details *details);
+extern grpc_call_details_init_type grpc_call_details_init_import;
+#define grpc_call_details_init grpc_call_details_init_import
+typedef void(*grpc_call_details_destroy_type)(grpc_call_details *details);
+extern grpc_call_details_destroy_type grpc_call_details_destroy_import;
+#define grpc_call_details_destroy grpc_call_details_destroy_import
+typedef void(*grpc_register_plugin_type)(void (*init)(void), void (*destroy)(void));
+extern grpc_register_plugin_type grpc_register_plugin_import;
+#define grpc_register_plugin grpc_register_plugin_import
+typedef void(*grpc_init_type)(void);
+extern grpc_init_type grpc_init_import;
+#define grpc_init grpc_init_import
+typedef void(*grpc_shutdown_type)(void);
+extern grpc_shutdown_type grpc_shutdown_import;
+#define grpc_shutdown grpc_shutdown_import
+typedef const char *(*grpc_version_string_type)(void);
+extern grpc_version_string_type grpc_version_string_import;
+#define grpc_version_string grpc_version_string_import
+typedef grpc_completion_queue *(*grpc_completion_queue_create_type)(void *reserved);
+extern grpc_completion_queue_create_type grpc_completion_queue_create_import;
+#define grpc_completion_queue_create grpc_completion_queue_create_import
+typedef grpc_event(*grpc_completion_queue_next_type)(grpc_completion_queue *cq, gpr_timespec deadline, void *reserved);
+extern grpc_completion_queue_next_type grpc_completion_queue_next_import;
+#define grpc_completion_queue_next grpc_completion_queue_next_import
+typedef grpc_event(*grpc_completion_queue_pluck_type)(grpc_completion_queue *cq, void *tag, gpr_timespec deadline, void *reserved);
+extern grpc_completion_queue_pluck_type grpc_completion_queue_pluck_import;
+#define grpc_completion_queue_pluck grpc_completion_queue_pluck_import
+typedef void(*grpc_completion_queue_shutdown_type)(grpc_completion_queue *cq);
+extern grpc_completion_queue_shutdown_type grpc_completion_queue_shutdown_import;
+#define grpc_completion_queue_shutdown grpc_completion_queue_shutdown_import
+typedef void(*grpc_completion_queue_destroy_type)(grpc_completion_queue *cq);
+extern grpc_completion_queue_destroy_type grpc_completion_queue_destroy_import;
+#define grpc_completion_queue_destroy grpc_completion_queue_destroy_import
+typedef grpc_alarm *(*grpc_alarm_create_type)(grpc_completion_queue *cq, gpr_timespec deadline, void *tag);
+extern grpc_alarm_create_type grpc_alarm_create_import;
+#define grpc_alarm_create grpc_alarm_create_import
+typedef void(*grpc_alarm_cancel_type)(grpc_alarm *alarm);
+extern grpc_alarm_cancel_type grpc_alarm_cancel_import;
+#define grpc_alarm_cancel grpc_alarm_cancel_import
+typedef void(*grpc_alarm_destroy_type)(grpc_alarm *alarm);
+extern grpc_alarm_destroy_type grpc_alarm_destroy_import;
+#define grpc_alarm_destroy grpc_alarm_destroy_import
+typedef grpc_connectivity_state(*grpc_channel_check_connectivity_state_type)(grpc_channel *channel, int try_to_connect);
+extern grpc_channel_check_connectivity_state_type grpc_channel_check_connectivity_state_import;
+#define grpc_channel_check_connectivity_state grpc_channel_check_connectivity_state_import
+typedef void(*grpc_channel_watch_connectivity_state_type)(grpc_channel *channel, grpc_connectivity_state last_observed_state, gpr_timespec deadline, grpc_completion_queue *cq, void *tag);
+extern grpc_channel_watch_connectivity_state_type grpc_channel_watch_connectivity_state_import;
+#define grpc_channel_watch_connectivity_state grpc_channel_watch_connectivity_state_import
+typedef grpc_call *(*grpc_channel_create_call_type)(grpc_channel *channel, grpc_call *parent_call, uint32_t propagation_mask, grpc_completion_queue *completion_queue, const char *method, const char *host, gpr_timespec deadline, void *reserved);
+extern grpc_channel_create_call_type grpc_channel_create_call_import;
+#define grpc_channel_create_call grpc_channel_create_call_import
+typedef void(*grpc_channel_ping_type)(grpc_channel *channel, grpc_completion_queue *cq, void *tag, void *reserved);
+extern grpc_channel_ping_type grpc_channel_ping_import;
+#define grpc_channel_ping grpc_channel_ping_import
+typedef void *(*grpc_channel_register_call_type)(grpc_channel *channel, const char *method, const char *host, void *reserved);
+extern grpc_channel_register_call_type grpc_channel_register_call_import;
+#define grpc_channel_register_call grpc_channel_register_call_import
+typedef grpc_call *(*grpc_channel_create_registered_call_type)(grpc_channel *channel, grpc_call *parent_call, uint32_t propagation_mask, grpc_completion_queue *completion_queue, void *registered_call_handle, gpr_timespec deadline, void *reserved);
+extern grpc_channel_create_registered_call_type grpc_channel_create_registered_call_import;
+#define grpc_channel_create_registered_call grpc_channel_create_registered_call_import
+typedef grpc_call_error(*grpc_call_start_batch_type)(grpc_call *call, const grpc_op *ops, size_t nops, void *tag, void *reserved);
+extern grpc_call_start_batch_type grpc_call_start_batch_import;
+#define grpc_call_start_batch grpc_call_start_batch_import
+typedef char *(*grpc_call_get_peer_type)(grpc_call *call);
+extern grpc_call_get_peer_type grpc_call_get_peer_import;
+#define grpc_call_get_peer grpc_call_get_peer_import
+typedef void(*grpc_census_call_set_context_type)(grpc_call *call, struct census_context *context);
+extern grpc_census_call_set_context_type grpc_census_call_set_context_import;
+#define grpc_census_call_set_context grpc_census_call_set_context_import
+typedef struct census_context *(*grpc_census_call_get_context_type)(grpc_call *call);
+extern grpc_census_call_get_context_type grpc_census_call_get_context_import;
+#define grpc_census_call_get_context grpc_census_call_get_context_import
+typedef char *(*grpc_channel_get_target_type)(grpc_channel *channel);
+extern grpc_channel_get_target_type grpc_channel_get_target_import;
+#define grpc_channel_get_target grpc_channel_get_target_import
+typedef grpc_channel *(*grpc_insecure_channel_create_type)(const char *target, const grpc_channel_args *args, void *reserved);
+extern grpc_insecure_channel_create_type grpc_insecure_channel_create_import;
+#define grpc_insecure_channel_create grpc_insecure_channel_create_import
+typedef grpc_channel *(*grpc_lame_client_channel_create_type)(const char *target, grpc_status_code error_code, const char *error_message);
+extern grpc_lame_client_channel_create_type grpc_lame_client_channel_create_import;
+#define grpc_lame_client_channel_create grpc_lame_client_channel_create_import
+typedef void(*grpc_channel_destroy_type)(grpc_channel *channel);
+extern grpc_channel_destroy_type grpc_channel_destroy_import;
+#define grpc_channel_destroy grpc_channel_destroy_import
+typedef grpc_call_error(*grpc_call_cancel_type)(grpc_call *call, void *reserved);
+extern grpc_call_cancel_type grpc_call_cancel_import;
+#define grpc_call_cancel grpc_call_cancel_import
+typedef grpc_call_error(*grpc_call_cancel_with_status_type)(grpc_call *call, grpc_status_code status, const char *description, void *reserved);
+extern grpc_call_cancel_with_status_type grpc_call_cancel_with_status_import;
+#define grpc_call_cancel_with_status grpc_call_cancel_with_status_import
+typedef void(*grpc_call_destroy_type)(grpc_call *call);
+extern grpc_call_destroy_type grpc_call_destroy_import;
+#define grpc_call_destroy grpc_call_destroy_import
+typedef grpc_call_error(*grpc_server_request_call_type)(grpc_server *server, grpc_call **call, grpc_call_details *details, grpc_metadata_array *request_metadata, grpc_completion_queue *cq_bound_to_call, grpc_completion_queue *cq_for_notification, void *tag_new);
+extern grpc_server_request_call_type grpc_server_request_call_import;
+#define grpc_server_request_call grpc_server_request_call_import
+typedef void *(*grpc_server_register_method_type)(grpc_server *server, const char *method, const char *host);
+extern grpc_server_register_method_type grpc_server_register_method_import;
+#define grpc_server_register_method grpc_server_register_method_import
+typedef grpc_call_error(*grpc_server_request_registered_call_type)(grpc_server *server, void *registered_method, grpc_call **call, gpr_timespec *deadline, grpc_metadata_array *request_metadata, grpc_byte_buffer **optional_payload, grpc_completion_queue *cq_bound_to_call, grpc_completion_queue *cq_for_notification, void *tag_new);
+extern grpc_server_request_registered_call_type grpc_server_request_registered_call_import;
+#define grpc_server_request_registered_call grpc_server_request_registered_call_import
+typedef grpc_server *(*grpc_server_create_type)(const grpc_channel_args *args, void *reserved);
+extern grpc_server_create_type grpc_server_create_import;
+#define grpc_server_create grpc_server_create_import
+typedef void(*grpc_server_register_completion_queue_type)(grpc_server *server, grpc_completion_queue *cq, void *reserved);
+extern grpc_server_register_completion_queue_type grpc_server_register_completion_queue_import;
+#define grpc_server_register_completion_queue grpc_server_register_completion_queue_import
+typedef int(*grpc_server_add_insecure_http2_port_type)(grpc_server *server, const char *addr);
+extern grpc_server_add_insecure_http2_port_type grpc_server_add_insecure_http2_port_import;
+#define grpc_server_add_insecure_http2_port grpc_server_add_insecure_http2_port_import
+typedef void(*grpc_server_start_type)(grpc_server *server);
+extern grpc_server_start_type grpc_server_start_import;
+#define grpc_server_start grpc_server_start_import
+typedef void(*grpc_server_shutdown_and_notify_type)(grpc_server *server, grpc_completion_queue *cq, void *tag);
+extern grpc_server_shutdown_and_notify_type grpc_server_shutdown_and_notify_import;
+#define grpc_server_shutdown_and_notify grpc_server_shutdown_and_notify_import
+typedef void(*grpc_server_cancel_all_calls_type)(grpc_server *server);
+extern grpc_server_cancel_all_calls_type grpc_server_cancel_all_calls_import;
+#define grpc_server_cancel_all_calls grpc_server_cancel_all_calls_import
+typedef void(*grpc_server_destroy_type)(grpc_server *server);
+extern grpc_server_destroy_type grpc_server_destroy_import;
+#define grpc_server_destroy grpc_server_destroy_import
+typedef int(*grpc_tracer_set_enabled_type)(const char *name, int enabled);
+extern grpc_tracer_set_enabled_type grpc_tracer_set_enabled_import;
+#define grpc_tracer_set_enabled grpc_tracer_set_enabled_import
+typedef int(*grpc_header_key_is_legal_type)(const char *key, size_t length);
+extern grpc_header_key_is_legal_type grpc_header_key_is_legal_import;
+#define grpc_header_key_is_legal grpc_header_key_is_legal_import
+typedef int(*grpc_header_nonbin_value_is_legal_type)(const char *value, size_t length);
+extern grpc_header_nonbin_value_is_legal_type grpc_header_nonbin_value_is_legal_import;
+#define grpc_header_nonbin_value_is_legal grpc_header_nonbin_value_is_legal_import
+typedef int(*grpc_is_binary_header_type)(const char *key, size_t length);
+extern grpc_is_binary_header_type grpc_is_binary_header_import;
+#define grpc_is_binary_header grpc_is_binary_header_import
+typedef const grpc_auth_property *(*grpc_auth_property_iterator_next_type)(grpc_auth_property_iterator *it);
+extern grpc_auth_property_iterator_next_type grpc_auth_property_iterator_next_import;
+#define grpc_auth_property_iterator_next grpc_auth_property_iterator_next_import
+typedef grpc_auth_property_iterator(*grpc_auth_context_property_iterator_type)(const grpc_auth_context *ctx);
+extern grpc_auth_context_property_iterator_type grpc_auth_context_property_iterator_import;
+#define grpc_auth_context_property_iterator grpc_auth_context_property_iterator_import
+typedef grpc_auth_property_iterator(*grpc_auth_context_peer_identity_type)(const grpc_auth_context *ctx);
+extern grpc_auth_context_peer_identity_type grpc_auth_context_peer_identity_import;
+#define grpc_auth_context_peer_identity grpc_auth_context_peer_identity_import
+typedef grpc_auth_property_iterator(*grpc_auth_context_find_properties_by_name_type)(const grpc_auth_context *ctx, const char *name);
+extern grpc_auth_context_find_properties_by_name_type grpc_auth_context_find_properties_by_name_import;
+#define grpc_auth_context_find_properties_by_name grpc_auth_context_find_properties_by_name_import
+typedef const char *(*grpc_auth_context_peer_identity_property_name_type)(const grpc_auth_context *ctx);
+extern grpc_auth_context_peer_identity_property_name_type grpc_auth_context_peer_identity_property_name_import;
+#define grpc_auth_context_peer_identity_property_name grpc_auth_context_peer_identity_property_name_import
+typedef int(*grpc_auth_context_peer_is_authenticated_type)(const grpc_auth_context *ctx);
+extern grpc_auth_context_peer_is_authenticated_type grpc_auth_context_peer_is_authenticated_import;
+#define grpc_auth_context_peer_is_authenticated grpc_auth_context_peer_is_authenticated_import
+typedef grpc_auth_context *(*grpc_call_auth_context_type)(grpc_call *call);
+extern grpc_call_auth_context_type grpc_call_auth_context_import;
+#define grpc_call_auth_context grpc_call_auth_context_import
+typedef void(*grpc_auth_context_release_type)(grpc_auth_context *context);
+extern grpc_auth_context_release_type grpc_auth_context_release_import;
+#define grpc_auth_context_release grpc_auth_context_release_import
+typedef void(*grpc_auth_context_add_property_type)(grpc_auth_context *ctx, const char *name, const char *value, size_t value_length);
+extern grpc_auth_context_add_property_type grpc_auth_context_add_property_import;
+#define grpc_auth_context_add_property grpc_auth_context_add_property_import
+typedef void(*grpc_auth_context_add_cstring_property_type)(grpc_auth_context *ctx, const char *name, const char *value);
+extern grpc_auth_context_add_cstring_property_type grpc_auth_context_add_cstring_property_import;
+#define grpc_auth_context_add_cstring_property grpc_auth_context_add_cstring_property_import
+typedef int(*grpc_auth_context_set_peer_identity_property_name_type)(grpc_auth_context *ctx, const char *name);
+extern grpc_auth_context_set_peer_identity_property_name_type grpc_auth_context_set_peer_identity_property_name_import;
+#define grpc_auth_context_set_peer_identity_property_name grpc_auth_context_set_peer_identity_property_name_import
+typedef void(*grpc_channel_credentials_release_type)(grpc_channel_credentials *creds);
+extern grpc_channel_credentials_release_type grpc_channel_credentials_release_import;
+#define grpc_channel_credentials_release grpc_channel_credentials_release_import
+typedef grpc_channel_credentials *(*grpc_google_default_credentials_create_type)(void);
+extern grpc_google_default_credentials_create_type grpc_google_default_credentials_create_import;
+#define grpc_google_default_credentials_create grpc_google_default_credentials_create_import
+typedef grpc_channel_credentials *(*grpc_ssl_credentials_create_type)(const char *pem_root_certs, grpc_ssl_pem_key_cert_pair *pem_key_cert_pair, void *reserved);
+extern grpc_ssl_credentials_create_type grpc_ssl_credentials_create_import;
+#define grpc_ssl_credentials_create grpc_ssl_credentials_create_import
+typedef void(*grpc_call_credentials_release_type)(grpc_call_credentials *creds);
+extern grpc_call_credentials_release_type grpc_call_credentials_release_import;
+#define grpc_call_credentials_release grpc_call_credentials_release_import
+typedef grpc_channel_credentials *(*grpc_composite_channel_credentials_create_type)(grpc_channel_credentials *channel_creds, grpc_call_credentials *call_creds, void *reserved);
+extern grpc_composite_channel_credentials_create_type grpc_composite_channel_credentials_create_import;
+#define grpc_composite_channel_credentials_create grpc_composite_channel_credentials_create_import
+typedef grpc_call_credentials *(*grpc_composite_call_credentials_create_type)(grpc_call_credentials *creds1, grpc_call_credentials *creds2, void *reserved);
+extern grpc_composite_call_credentials_create_type grpc_composite_call_credentials_create_import;
+#define grpc_composite_call_credentials_create grpc_composite_call_credentials_create_import
+typedef grpc_call_credentials *(*grpc_google_compute_engine_credentials_create_type)(void *reserved);
+extern grpc_google_compute_engine_credentials_create_type grpc_google_compute_engine_credentials_create_import;
+#define grpc_google_compute_engine_credentials_create grpc_google_compute_engine_credentials_create_import
+typedef gpr_timespec(*grpc_max_auth_token_lifetime_type)();
+extern grpc_max_auth_token_lifetime_type grpc_max_auth_token_lifetime_import;
+#define grpc_max_auth_token_lifetime grpc_max_auth_token_lifetime_import
+typedef grpc_call_credentials *(*grpc_service_account_jwt_access_credentials_create_type)(const char *json_key, gpr_timespec token_lifetime, void *reserved);
+extern grpc_service_account_jwt_access_credentials_create_type grpc_service_account_jwt_access_credentials_create_import;
+#define grpc_service_account_jwt_access_credentials_create grpc_service_account_jwt_access_credentials_create_import
+typedef grpc_call_credentials *(*grpc_google_refresh_token_credentials_create_type)(const char *json_refresh_token, void *reserved);
+extern grpc_google_refresh_token_credentials_create_type grpc_google_refresh_token_credentials_create_import;
+#define grpc_google_refresh_token_credentials_create grpc_google_refresh_token_credentials_create_import
+typedef grpc_call_credentials *(*grpc_access_token_credentials_create_type)(const char *access_token, void *reserved);
+extern grpc_access_token_credentials_create_type grpc_access_token_credentials_create_import;
+#define grpc_access_token_credentials_create grpc_access_token_credentials_create_import
+typedef grpc_call_credentials *(*grpc_google_iam_credentials_create_type)(const char *authorization_token, const char *authority_selector, void *reserved);
+extern grpc_google_iam_credentials_create_type grpc_google_iam_credentials_create_import;
+#define grpc_google_iam_credentials_create grpc_google_iam_credentials_create_import
+typedef grpc_call_credentials *(*grpc_metadata_credentials_create_from_plugin_type)(grpc_metadata_credentials_plugin plugin, void *reserved);
+extern grpc_metadata_credentials_create_from_plugin_type grpc_metadata_credentials_create_from_plugin_import;
+#define grpc_metadata_credentials_create_from_plugin grpc_metadata_credentials_create_from_plugin_import
+typedef grpc_channel *(*grpc_secure_channel_create_type)(grpc_channel_credentials *creds, const char *target, const grpc_channel_args *args, void *reserved);
+extern grpc_secure_channel_create_type grpc_secure_channel_create_import;
+#define grpc_secure_channel_create grpc_secure_channel_create_import
+typedef void(*grpc_server_credentials_release_type)(grpc_server_credentials *creds);
+extern grpc_server_credentials_release_type grpc_server_credentials_release_import;
+#define grpc_server_credentials_release grpc_server_credentials_release_import
+typedef grpc_server_credentials *(*grpc_ssl_server_credentials_create_type)(const char *pem_root_certs, grpc_ssl_pem_key_cert_pair *pem_key_cert_pairs, size_t num_key_cert_pairs, int force_client_auth, void *reserved);
+extern grpc_ssl_server_credentials_create_type grpc_ssl_server_credentials_create_import;
+#define grpc_ssl_server_credentials_create grpc_ssl_server_credentials_create_import
+typedef int(*grpc_server_add_secure_http2_port_type)(grpc_server *server, const char *addr, grpc_server_credentials *creds);
+extern grpc_server_add_secure_http2_port_type grpc_server_add_secure_http2_port_import;
+#define grpc_server_add_secure_http2_port grpc_server_add_secure_http2_port_import
+typedef grpc_call_error(*grpc_call_set_credentials_type)(grpc_call *call, grpc_call_credentials *creds);
+extern grpc_call_set_credentials_type grpc_call_set_credentials_import;
+#define grpc_call_set_credentials grpc_call_set_credentials_import
+typedef void(*grpc_server_credentials_set_auth_metadata_processor_type)(grpc_server_credentials *creds, grpc_auth_metadata_processor processor);
+extern grpc_server_credentials_set_auth_metadata_processor_type grpc_server_credentials_set_auth_metadata_processor_import;
+#define grpc_server_credentials_set_auth_metadata_processor grpc_server_credentials_set_auth_metadata_processor_import
+typedef void *(*gpr_malloc_type)(size_t size);
+extern gpr_malloc_type gpr_malloc_import;
+#define gpr_malloc gpr_malloc_import
+typedef void(*gpr_free_type)(void *ptr);
+extern gpr_free_type gpr_free_import;
+#define gpr_free gpr_free_import
+typedef void *(*gpr_realloc_type)(void *p, size_t size);
+extern gpr_realloc_type gpr_realloc_import;
+#define gpr_realloc gpr_realloc_import
+typedef void *(*gpr_malloc_aligned_type)(size_t size, size_t alignment_log);
+extern gpr_malloc_aligned_type gpr_malloc_aligned_import;
+#define gpr_malloc_aligned gpr_malloc_aligned_import
+typedef void(*gpr_free_aligned_type)(void *ptr);
+extern gpr_free_aligned_type gpr_free_aligned_import;
+#define gpr_free_aligned gpr_free_aligned_import
+typedef void(*gpr_set_allocation_functions_type)(gpr_allocation_functions functions);
+extern gpr_set_allocation_functions_type gpr_set_allocation_functions_import;
+#define gpr_set_allocation_functions gpr_set_allocation_functions_import
+typedef gpr_allocation_functions(*gpr_get_allocation_functions_type)();
+extern gpr_get_allocation_functions_type gpr_get_allocation_functions_import;
+#define gpr_get_allocation_functions gpr_get_allocation_functions_import
+typedef grpc_byte_buffer *(*grpc_raw_byte_buffer_create_type)(gpr_slice *slices, size_t nslices);
+extern grpc_raw_byte_buffer_create_type grpc_raw_byte_buffer_create_import;
+#define grpc_raw_byte_buffer_create grpc_raw_byte_buffer_create_import
+typedef grpc_byte_buffer *(*grpc_raw_compressed_byte_buffer_create_type)(gpr_slice *slices, size_t nslices, grpc_compression_algorithm compression);
+extern grpc_raw_compressed_byte_buffer_create_type grpc_raw_compressed_byte_buffer_create_import;
+#define grpc_raw_compressed_byte_buffer_create grpc_raw_compressed_byte_buffer_create_import
+typedef grpc_byte_buffer *(*grpc_byte_buffer_copy_type)(grpc_byte_buffer *bb);
+extern grpc_byte_buffer_copy_type grpc_byte_buffer_copy_import;
+#define grpc_byte_buffer_copy grpc_byte_buffer_copy_import
+typedef size_t(*grpc_byte_buffer_length_type)(grpc_byte_buffer *bb);
+extern grpc_byte_buffer_length_type grpc_byte_buffer_length_import;
+#define grpc_byte_buffer_length grpc_byte_buffer_length_import
+typedef void(*grpc_byte_buffer_destroy_type)(grpc_byte_buffer *byte_buffer);
+extern grpc_byte_buffer_destroy_type grpc_byte_buffer_destroy_import;
+#define grpc_byte_buffer_destroy grpc_byte_buffer_destroy_import
+typedef void(*grpc_byte_buffer_reader_init_type)(grpc_byte_buffer_reader *reader, grpc_byte_buffer *buffer);
+extern grpc_byte_buffer_reader_init_type grpc_byte_buffer_reader_init_import;
+#define grpc_byte_buffer_reader_init grpc_byte_buffer_reader_init_import
+typedef void(*grpc_byte_buffer_reader_destroy_type)(grpc_byte_buffer_reader *reader);
+extern grpc_byte_buffer_reader_destroy_type grpc_byte_buffer_reader_destroy_import;
+#define grpc_byte_buffer_reader_destroy grpc_byte_buffer_reader_destroy_import
+typedef int(*grpc_byte_buffer_reader_next_type)(grpc_byte_buffer_reader *reader, gpr_slice *slice);
+extern grpc_byte_buffer_reader_next_type grpc_byte_buffer_reader_next_import;
+#define grpc_byte_buffer_reader_next grpc_byte_buffer_reader_next_import
+typedef gpr_slice(*grpc_byte_buffer_reader_readall_type)(grpc_byte_buffer_reader *reader);
+extern grpc_byte_buffer_reader_readall_type grpc_byte_buffer_reader_readall_import;
+#define grpc_byte_buffer_reader_readall grpc_byte_buffer_reader_readall_import
+typedef grpc_byte_buffer *(*grpc_raw_byte_buffer_from_reader_type)(grpc_byte_buffer_reader *reader);
+extern grpc_raw_byte_buffer_from_reader_type grpc_raw_byte_buffer_from_reader_import;
+#define grpc_raw_byte_buffer_from_reader grpc_raw_byte_buffer_from_reader_import
+typedef void(*gpr_log_type)(const char *file, int line, gpr_log_severity severity, const char *format, ...);
+extern gpr_log_type gpr_log_import;
+#define gpr_log gpr_log_import
+typedef void(*gpr_log_message_type)(const char *file, int line, gpr_log_severity severity, const char *message);
+extern gpr_log_message_type gpr_log_message_import;
+#define gpr_log_message gpr_log_message_import
+typedef void(*gpr_set_log_function_type)(gpr_log_func func);
+extern gpr_set_log_function_type gpr_set_log_function_import;
+#define gpr_set_log_function gpr_set_log_function_import
+typedef gpr_slice(*gpr_slice_ref_type)(gpr_slice s);
+extern gpr_slice_ref_type gpr_slice_ref_import;
+#define gpr_slice_ref gpr_slice_ref_import
+typedef void(*gpr_slice_unref_type)(gpr_slice s);
+extern gpr_slice_unref_type gpr_slice_unref_import;
+#define gpr_slice_unref gpr_slice_unref_import
+typedef gpr_slice(*gpr_slice_new_type)(void *p, size_t len, void (*destroy)(void *));
+extern gpr_slice_new_type gpr_slice_new_import;
+#define gpr_slice_new gpr_slice_new_import
+typedef gpr_slice(*gpr_slice_new_with_len_type)(void *p, size_t len, void (*destroy)(void *, size_t));
+extern gpr_slice_new_with_len_type gpr_slice_new_with_len_import;
+#define gpr_slice_new_with_len gpr_slice_new_with_len_import
+typedef gpr_slice(*gpr_slice_malloc_type)(size_t length);
+extern gpr_slice_malloc_type gpr_slice_malloc_import;
+#define gpr_slice_malloc gpr_slice_malloc_import
+typedef gpr_slice(*gpr_slice_from_copied_string_type)(const char *source);
+extern gpr_slice_from_copied_string_type gpr_slice_from_copied_string_import;
+#define gpr_slice_from_copied_string gpr_slice_from_copied_string_import
+typedef gpr_slice(*gpr_slice_from_copied_buffer_type)(const char *source, size_t len);
+extern gpr_slice_from_copied_buffer_type gpr_slice_from_copied_buffer_import;
+#define gpr_slice_from_copied_buffer gpr_slice_from_copied_buffer_import
+typedef gpr_slice(*gpr_slice_from_static_string_type)(const char *source);
+extern gpr_slice_from_static_string_type gpr_slice_from_static_string_import;
+#define gpr_slice_from_static_string gpr_slice_from_static_string_import
+typedef gpr_slice(*gpr_slice_sub_type)(gpr_slice s, size_t begin, size_t end);
+extern gpr_slice_sub_type gpr_slice_sub_import;
+#define gpr_slice_sub gpr_slice_sub_import
+typedef gpr_slice(*gpr_slice_sub_no_ref_type)(gpr_slice s, size_t begin, size_t end);
+extern gpr_slice_sub_no_ref_type gpr_slice_sub_no_ref_import;
+#define gpr_slice_sub_no_ref gpr_slice_sub_no_ref_import
+typedef gpr_slice(*gpr_slice_split_tail_type)(gpr_slice *s, size_t split);
+extern gpr_slice_split_tail_type gpr_slice_split_tail_import;
+#define gpr_slice_split_tail gpr_slice_split_tail_import
+typedef gpr_slice(*gpr_slice_split_head_type)(gpr_slice *s, size_t split);
+extern gpr_slice_split_head_type gpr_slice_split_head_import;
+#define gpr_slice_split_head gpr_slice_split_head_import
+typedef gpr_slice(*gpr_empty_slice_type)(void);
+extern gpr_empty_slice_type gpr_empty_slice_import;
+#define gpr_empty_slice gpr_empty_slice_import
+typedef int(*gpr_slice_cmp_type)(gpr_slice a, gpr_slice b);
+extern gpr_slice_cmp_type gpr_slice_cmp_import;
+#define gpr_slice_cmp gpr_slice_cmp_import
+typedef int(*gpr_slice_str_cmp_type)(gpr_slice a, const char *b);
+extern gpr_slice_str_cmp_type gpr_slice_str_cmp_import;
+#define gpr_slice_str_cmp gpr_slice_str_cmp_import
+typedef void(*gpr_slice_buffer_init_type)(gpr_slice_buffer *sb);
+extern gpr_slice_buffer_init_type gpr_slice_buffer_init_import;
+#define gpr_slice_buffer_init gpr_slice_buffer_init_import
+typedef void(*gpr_slice_buffer_destroy_type)(gpr_slice_buffer *sb);
+extern gpr_slice_buffer_destroy_type gpr_slice_buffer_destroy_import;
+#define gpr_slice_buffer_destroy gpr_slice_buffer_destroy_import
+typedef void(*gpr_slice_buffer_add_type)(gpr_slice_buffer *sb, gpr_slice slice);
+extern gpr_slice_buffer_add_type gpr_slice_buffer_add_import;
+#define gpr_slice_buffer_add gpr_slice_buffer_add_import
+typedef size_t(*gpr_slice_buffer_add_indexed_type)(gpr_slice_buffer *sb, gpr_slice slice);
+extern gpr_slice_buffer_add_indexed_type gpr_slice_buffer_add_indexed_import;
+#define gpr_slice_buffer_add_indexed gpr_slice_buffer_add_indexed_import
+typedef void(*gpr_slice_buffer_addn_type)(gpr_slice_buffer *sb, gpr_slice *slices, size_t n);
+extern gpr_slice_buffer_addn_type gpr_slice_buffer_addn_import;
+#define gpr_slice_buffer_addn gpr_slice_buffer_addn_import
+typedef uint8_t *(*gpr_slice_buffer_tiny_add_type)(gpr_slice_buffer *sb, size_t len);
+extern gpr_slice_buffer_tiny_add_type gpr_slice_buffer_tiny_add_import;
+#define gpr_slice_buffer_tiny_add gpr_slice_buffer_tiny_add_import
+typedef void(*gpr_slice_buffer_pop_type)(gpr_slice_buffer *sb);
+extern gpr_slice_buffer_pop_type gpr_slice_buffer_pop_import;
+#define gpr_slice_buffer_pop gpr_slice_buffer_pop_import
+typedef void(*gpr_slice_buffer_reset_and_unref_type)(gpr_slice_buffer *sb);
+extern gpr_slice_buffer_reset_and_unref_type gpr_slice_buffer_reset_and_unref_import;
+#define gpr_slice_buffer_reset_and_unref gpr_slice_buffer_reset_and_unref_import
+typedef void(*gpr_slice_buffer_swap_type)(gpr_slice_buffer *a, gpr_slice_buffer *b);
+extern gpr_slice_buffer_swap_type gpr_slice_buffer_swap_import;
+#define gpr_slice_buffer_swap gpr_slice_buffer_swap_import
+typedef void(*gpr_slice_buffer_move_into_type)(gpr_slice_buffer *src, gpr_slice_buffer *dst);
+extern gpr_slice_buffer_move_into_type gpr_slice_buffer_move_into_import;
+#define gpr_slice_buffer_move_into gpr_slice_buffer_move_into_import
+typedef void(*gpr_slice_buffer_trim_end_type)(gpr_slice_buffer *src, size_t n, gpr_slice_buffer *garbage);
+extern gpr_slice_buffer_trim_end_type gpr_slice_buffer_trim_end_import;
+#define gpr_slice_buffer_trim_end gpr_slice_buffer_trim_end_import
+typedef void(*gpr_slice_buffer_move_first_type)(gpr_slice_buffer *src, size_t n, gpr_slice_buffer *dst);
+extern gpr_slice_buffer_move_first_type gpr_slice_buffer_move_first_import;
+#define gpr_slice_buffer_move_first gpr_slice_buffer_move_first_import
+typedef gpr_slice(*gpr_slice_buffer_take_first_type)(gpr_slice_buffer *src);
+extern gpr_slice_buffer_take_first_type gpr_slice_buffer_take_first_import;
+#define gpr_slice_buffer_take_first gpr_slice_buffer_take_first_import
+typedef void(*gpr_mu_init_type)(gpr_mu *mu);
+extern gpr_mu_init_type gpr_mu_init_import;
+#define gpr_mu_init gpr_mu_init_import
+typedef void(*gpr_mu_destroy_type)(gpr_mu *mu);
+extern gpr_mu_destroy_type gpr_mu_destroy_import;
+#define gpr_mu_destroy gpr_mu_destroy_import
+typedef void(*gpr_mu_lock_type)(gpr_mu *mu);
+extern gpr_mu_lock_type gpr_mu_lock_import;
+#define gpr_mu_lock gpr_mu_lock_import
+typedef void(*gpr_mu_unlock_type)(gpr_mu *mu);
+extern gpr_mu_unlock_type gpr_mu_unlock_import;
+#define gpr_mu_unlock gpr_mu_unlock_import
+typedef int(*gpr_mu_trylock_type)(gpr_mu *mu);
+extern gpr_mu_trylock_type gpr_mu_trylock_import;
+#define gpr_mu_trylock gpr_mu_trylock_import
+typedef void(*gpr_cv_init_type)(gpr_cv *cv);
+extern gpr_cv_init_type gpr_cv_init_import;
+#define gpr_cv_init gpr_cv_init_import
+typedef void(*gpr_cv_destroy_type)(gpr_cv *cv);
+extern gpr_cv_destroy_type gpr_cv_destroy_import;
+#define gpr_cv_destroy gpr_cv_destroy_import
+typedef int(*gpr_cv_wait_type)(gpr_cv *cv, gpr_mu *mu, gpr_timespec abs_deadline);
+extern gpr_cv_wait_type gpr_cv_wait_import;
+#define gpr_cv_wait gpr_cv_wait_import
+typedef void(*gpr_cv_signal_type)(gpr_cv *cv);
+extern gpr_cv_signal_type gpr_cv_signal_import;
+#define gpr_cv_signal gpr_cv_signal_import
+typedef void(*gpr_cv_broadcast_type)(gpr_cv *cv);
+extern gpr_cv_broadcast_type gpr_cv_broadcast_import;
+#define gpr_cv_broadcast gpr_cv_broadcast_import
+typedef void(*gpr_once_init_type)(gpr_once *once, void (*init_routine)(void));
+extern gpr_once_init_type gpr_once_init_import;
+#define gpr_once_init gpr_once_init_import
+typedef void(*gpr_event_init_type)(gpr_event *ev);
+extern gpr_event_init_type gpr_event_init_import;
+#define gpr_event_init gpr_event_init_import
+typedef void(*gpr_event_set_type)(gpr_event *ev, void *value);
+extern gpr_event_set_type gpr_event_set_import;
+#define gpr_event_set gpr_event_set_import
+typedef void *(*gpr_event_get_type)(gpr_event *ev);
+extern gpr_event_get_type gpr_event_get_import;
+#define gpr_event_get gpr_event_get_import
+typedef void *(*gpr_event_wait_type)(gpr_event *ev, gpr_timespec abs_deadline);
+extern gpr_event_wait_type gpr_event_wait_import;
+#define gpr_event_wait gpr_event_wait_import
+typedef void(*gpr_ref_init_type)(gpr_refcount *r, int n);
+extern gpr_ref_init_type gpr_ref_init_import;
+#define gpr_ref_init gpr_ref_init_import
+typedef void(*gpr_ref_type)(gpr_refcount *r);
+extern gpr_ref_type gpr_ref_import;
+#define gpr_ref gpr_ref_import
+typedef void(*gpr_refn_type)(gpr_refcount *r, int n);
+extern gpr_refn_type gpr_refn_import;
+#define gpr_refn gpr_refn_import
+typedef int(*gpr_unref_type)(gpr_refcount *r);
+extern gpr_unref_type gpr_unref_import;
+#define gpr_unref gpr_unref_import
+typedef void(*gpr_stats_init_type)(gpr_stats_counter *c, intptr_t n);
+extern gpr_stats_init_type gpr_stats_init_import;
+#define gpr_stats_init gpr_stats_init_import
+typedef void(*gpr_stats_inc_type)(gpr_stats_counter *c, intptr_t inc);
+extern gpr_stats_inc_type gpr_stats_inc_import;
+#define gpr_stats_inc gpr_stats_inc_import
+typedef intptr_t(*gpr_stats_read_type)(const gpr_stats_counter *c);
+extern gpr_stats_read_type gpr_stats_read_import;
+#define gpr_stats_read gpr_stats_read_import
+typedef gpr_timespec(*gpr_time_0_type)(gpr_clock_type type);
+extern gpr_time_0_type gpr_time_0_import;
+#define gpr_time_0 gpr_time_0_import
+typedef gpr_timespec(*gpr_inf_future_type)(gpr_clock_type type);
+extern gpr_inf_future_type gpr_inf_future_import;
+#define gpr_inf_future gpr_inf_future_import
+typedef gpr_timespec(*gpr_inf_past_type)(gpr_clock_type type);
+extern gpr_inf_past_type gpr_inf_past_import;
+#define gpr_inf_past gpr_inf_past_import
+typedef void(*gpr_time_init_type)(void);
+extern gpr_time_init_type gpr_time_init_import;
+#define gpr_time_init gpr_time_init_import
+typedef gpr_timespec(*gpr_now_type)(gpr_clock_type clock);
+extern gpr_now_type gpr_now_import;
+#define gpr_now gpr_now_import
+typedef gpr_timespec(*gpr_convert_clock_type_type)(gpr_timespec t, gpr_clock_type target_clock);
+extern gpr_convert_clock_type_type gpr_convert_clock_type_import;
+#define gpr_convert_clock_type gpr_convert_clock_type_import
+typedef int(*gpr_time_cmp_type)(gpr_timespec a, gpr_timespec b);
+extern gpr_time_cmp_type gpr_time_cmp_import;
+#define gpr_time_cmp gpr_time_cmp_import
+typedef gpr_timespec(*gpr_time_max_type)(gpr_timespec a, gpr_timespec b);
+extern gpr_time_max_type gpr_time_max_import;
+#define gpr_time_max gpr_time_max_import
+typedef gpr_timespec(*gpr_time_min_type)(gpr_timespec a, gpr_timespec b);
+extern gpr_time_min_type gpr_time_min_import;
+#define gpr_time_min gpr_time_min_import
+typedef gpr_timespec(*gpr_time_add_type)(gpr_timespec a, gpr_timespec b);
+extern gpr_time_add_type gpr_time_add_import;
+#define gpr_time_add gpr_time_add_import
+typedef gpr_timespec(*gpr_time_sub_type)(gpr_timespec a, gpr_timespec b);
+extern gpr_time_sub_type gpr_time_sub_import;
+#define gpr_time_sub gpr_time_sub_import
+typedef gpr_timespec(*gpr_time_from_micros_type)(int64_t x, gpr_clock_type clock_type);
+extern gpr_time_from_micros_type gpr_time_from_micros_import;
+#define gpr_time_from_micros gpr_time_from_micros_import
+typedef gpr_timespec(*gpr_time_from_nanos_type)(int64_t x, gpr_clock_type clock_type);
+extern gpr_time_from_nanos_type gpr_time_from_nanos_import;
+#define gpr_time_from_nanos gpr_time_from_nanos_import
+typedef gpr_timespec(*gpr_time_from_millis_type)(int64_t x, gpr_clock_type clock_type);
+extern gpr_time_from_millis_type gpr_time_from_millis_import;
+#define gpr_time_from_millis gpr_time_from_millis_import
+typedef gpr_timespec(*gpr_time_from_seconds_type)(int64_t x, gpr_clock_type clock_type);
+extern gpr_time_from_seconds_type gpr_time_from_seconds_import;
+#define gpr_time_from_seconds gpr_time_from_seconds_import
+typedef gpr_timespec(*gpr_time_from_minutes_type)(int64_t x, gpr_clock_type clock_type);
+extern gpr_time_from_minutes_type gpr_time_from_minutes_import;
+#define gpr_time_from_minutes gpr_time_from_minutes_import
+typedef gpr_timespec(*gpr_time_from_hours_type)(int64_t x, gpr_clock_type clock_type);
+extern gpr_time_from_hours_type gpr_time_from_hours_import;
+#define gpr_time_from_hours gpr_time_from_hours_import
+typedef int32_t(*gpr_time_to_millis_type)(gpr_timespec timespec);
+extern gpr_time_to_millis_type gpr_time_to_millis_import;
+#define gpr_time_to_millis gpr_time_to_millis_import
+typedef int(*gpr_time_similar_type)(gpr_timespec a, gpr_timespec b, gpr_timespec threshold);
+extern gpr_time_similar_type gpr_time_similar_import;
+#define gpr_time_similar gpr_time_similar_import
+typedef void(*gpr_sleep_until_type)(gpr_timespec until);
+extern gpr_sleep_until_type gpr_sleep_until_import;
+#define gpr_sleep_until gpr_sleep_until_import
+typedef double(*gpr_timespec_to_micros_type)(gpr_timespec t);
+extern gpr_timespec_to_micros_type gpr_timespec_to_micros_import;
+#define gpr_timespec_to_micros gpr_timespec_to_micros_import
+typedef gpr_avl(*gpr_avl_create_type)(const gpr_avl_vtable *vtable);
+extern gpr_avl_create_type gpr_avl_create_import;
+#define gpr_avl_create gpr_avl_create_import
+typedef gpr_avl(*gpr_avl_ref_type)(gpr_avl avl);
+extern gpr_avl_ref_type gpr_avl_ref_import;
+#define gpr_avl_ref gpr_avl_ref_import
+typedef void(*gpr_avl_unref_type)(gpr_avl avl);
+extern gpr_avl_unref_type gpr_avl_unref_import;
+#define gpr_avl_unref gpr_avl_unref_import
+typedef gpr_avl(*gpr_avl_add_type)(gpr_avl avl, void *key, void *value);
+extern gpr_avl_add_type gpr_avl_add_import;
+#define gpr_avl_add gpr_avl_add_import
+typedef gpr_avl(*gpr_avl_remove_type)(gpr_avl avl, void *key);
+extern gpr_avl_remove_type gpr_avl_remove_import;
+#define gpr_avl_remove gpr_avl_remove_import
+typedef void *(*gpr_avl_get_type)(gpr_avl avl, void *key);
+extern gpr_avl_get_type gpr_avl_get_import;
+#define gpr_avl_get gpr_avl_get_import
+typedef gpr_cmdline *(*gpr_cmdline_create_type)(const char *description);
+extern gpr_cmdline_create_type gpr_cmdline_create_import;
+#define gpr_cmdline_create gpr_cmdline_create_import
+typedef void(*gpr_cmdline_add_int_type)(gpr_cmdline *cl, const char *name, const char *help, int *value);
+extern gpr_cmdline_add_int_type gpr_cmdline_add_int_import;
+#define gpr_cmdline_add_int gpr_cmdline_add_int_import
+typedef void(*gpr_cmdline_add_flag_type)(gpr_cmdline *cl, const char *name, const char *help, int *value);
+extern gpr_cmdline_add_flag_type gpr_cmdline_add_flag_import;
+#define gpr_cmdline_add_flag gpr_cmdline_add_flag_import
+typedef void(*gpr_cmdline_add_string_type)(gpr_cmdline *cl, const char *name, const char *help, char **value);
+extern gpr_cmdline_add_string_type gpr_cmdline_add_string_import;
+#define gpr_cmdline_add_string gpr_cmdline_add_string_import
+typedef void(*gpr_cmdline_on_extra_arg_type)(gpr_cmdline *cl, const char *name, const char *help, void (*on_extra_arg)(void *user_data, const char *arg), void *user_data);
+extern gpr_cmdline_on_extra_arg_type gpr_cmdline_on_extra_arg_import;
+#define gpr_cmdline_on_extra_arg gpr_cmdline_on_extra_arg_import
+typedef void(*gpr_cmdline_set_survive_failure_type)(gpr_cmdline *cl);
+extern gpr_cmdline_set_survive_failure_type gpr_cmdline_set_survive_failure_import;
+#define gpr_cmdline_set_survive_failure gpr_cmdline_set_survive_failure_import
+typedef int(*gpr_cmdline_parse_type)(gpr_cmdline *cl, int argc, char **argv);
+extern gpr_cmdline_parse_type gpr_cmdline_parse_import;
+#define gpr_cmdline_parse gpr_cmdline_parse_import
+typedef void(*gpr_cmdline_destroy_type)(gpr_cmdline *cl);
+extern gpr_cmdline_destroy_type gpr_cmdline_destroy_import;
+#define gpr_cmdline_destroy gpr_cmdline_destroy_import
+typedef char *(*gpr_cmdline_usage_string_type)(gpr_cmdline *cl, const char *argv0);
+extern gpr_cmdline_usage_string_type gpr_cmdline_usage_string_import;
+#define gpr_cmdline_usage_string gpr_cmdline_usage_string_import
+typedef unsigned(*gpr_cpu_num_cores_type)(void);
+extern gpr_cpu_num_cores_type gpr_cpu_num_cores_import;
+#define gpr_cpu_num_cores gpr_cpu_num_cores_import
+typedef unsigned(*gpr_cpu_current_cpu_type)(void);
+extern gpr_cpu_current_cpu_type gpr_cpu_current_cpu_import;
+#define gpr_cpu_current_cpu gpr_cpu_current_cpu_import
+typedef gpr_histogram *(*gpr_histogram_create_type)(double resolution, double max_bucket_start);
+extern gpr_histogram_create_type gpr_histogram_create_import;
+#define gpr_histogram_create gpr_histogram_create_import
+typedef void(*gpr_histogram_destroy_type)(gpr_histogram *h);
+extern gpr_histogram_destroy_type gpr_histogram_destroy_import;
+#define gpr_histogram_destroy gpr_histogram_destroy_import
+typedef void(*gpr_histogram_add_type)(gpr_histogram *h, double x);
+extern gpr_histogram_add_type gpr_histogram_add_import;
+#define gpr_histogram_add gpr_histogram_add_import
+typedef int(*gpr_histogram_merge_type)(gpr_histogram *dst, const gpr_histogram *src);
+extern gpr_histogram_merge_type gpr_histogram_merge_import;
+#define gpr_histogram_merge gpr_histogram_merge_import
+typedef double(*gpr_histogram_percentile_type)(gpr_histogram *histogram, double percentile);
+extern gpr_histogram_percentile_type gpr_histogram_percentile_import;
+#define gpr_histogram_percentile gpr_histogram_percentile_import
+typedef double(*gpr_histogram_mean_type)(gpr_histogram *histogram);
+extern gpr_histogram_mean_type gpr_histogram_mean_import;
+#define gpr_histogram_mean gpr_histogram_mean_import
+typedef double(*gpr_histogram_stddev_type)(gpr_histogram *histogram);
+extern gpr_histogram_stddev_type gpr_histogram_stddev_import;
+#define gpr_histogram_stddev gpr_histogram_stddev_import
+typedef double(*gpr_histogram_variance_type)(gpr_histogram *histogram);
+extern gpr_histogram_variance_type gpr_histogram_variance_import;
+#define gpr_histogram_variance gpr_histogram_variance_import
+typedef double(*gpr_histogram_maximum_type)(gpr_histogram *histogram);
+extern gpr_histogram_maximum_type gpr_histogram_maximum_import;
+#define gpr_histogram_maximum gpr_histogram_maximum_import
+typedef double(*gpr_histogram_minimum_type)(gpr_histogram *histogram);
+extern gpr_histogram_minimum_type gpr_histogram_minimum_import;
+#define gpr_histogram_minimum gpr_histogram_minimum_import
+typedef double(*gpr_histogram_count_type)(gpr_histogram *histogram);
+extern gpr_histogram_count_type gpr_histogram_count_import;
+#define gpr_histogram_count gpr_histogram_count_import
+typedef double(*gpr_histogram_sum_type)(gpr_histogram *histogram);
+extern gpr_histogram_sum_type gpr_histogram_sum_import;
+#define gpr_histogram_sum gpr_histogram_sum_import
+typedef double(*gpr_histogram_sum_of_squares_type)(gpr_histogram *histogram);
+extern gpr_histogram_sum_of_squares_type gpr_histogram_sum_of_squares_import;
+#define gpr_histogram_sum_of_squares gpr_histogram_sum_of_squares_import
+typedef const uint32_t *(*gpr_histogram_get_contents_type)(gpr_histogram *histogram, size_t *count);
+extern gpr_histogram_get_contents_type gpr_histogram_get_contents_import;
+#define gpr_histogram_get_contents gpr_histogram_get_contents_import
+typedef void(*gpr_histogram_merge_contents_type)(gpr_histogram *histogram, const uint32_t *data, size_t data_count, double min_seen, double max_seen, double sum, double sum_of_squares, double count);
+extern gpr_histogram_merge_contents_type gpr_histogram_merge_contents_import;
+#define gpr_histogram_merge_contents gpr_histogram_merge_contents_import
+typedef int(*gpr_join_host_port_type)(char **out, const char *host, int port);
+extern gpr_join_host_port_type gpr_join_host_port_import;
+#define gpr_join_host_port gpr_join_host_port_import
+typedef int(*gpr_split_host_port_type)(const char *name, char **host, char **port);
+extern gpr_split_host_port_type gpr_split_host_port_import;
+#define gpr_split_host_port gpr_split_host_port_import
+typedef char *(*gpr_format_message_type)(int messageid);
+extern gpr_format_message_type gpr_format_message_import;
+#define gpr_format_message gpr_format_message_import
+typedef char *(*gpr_strdup_type)(const char *src);
+extern gpr_strdup_type gpr_strdup_import;
+#define gpr_strdup gpr_strdup_import
+typedef int(*gpr_asprintf_type)(char **strp, const char *format, ...);
+extern gpr_asprintf_type gpr_asprintf_import;
+#define gpr_asprintf gpr_asprintf_import
+typedef const char *(*gpr_subprocess_binary_extension_type)();
+extern gpr_subprocess_binary_extension_type gpr_subprocess_binary_extension_import;
+#define gpr_subprocess_binary_extension gpr_subprocess_binary_extension_import
+typedef gpr_subprocess *(*gpr_subprocess_create_type)(int argc, const char **argv);
+extern gpr_subprocess_create_type gpr_subprocess_create_import;
+#define gpr_subprocess_create gpr_subprocess_create_import
+typedef void(*gpr_subprocess_destroy_type)(gpr_subprocess *p);
+extern gpr_subprocess_destroy_type gpr_subprocess_destroy_import;
+#define gpr_subprocess_destroy gpr_subprocess_destroy_import
+typedef int(*gpr_subprocess_join_type)(gpr_subprocess *p);
+extern gpr_subprocess_join_type gpr_subprocess_join_import;
+#define gpr_subprocess_join gpr_subprocess_join_import
+typedef void(*gpr_subprocess_interrupt_type)(gpr_subprocess *p);
+extern gpr_subprocess_interrupt_type gpr_subprocess_interrupt_import;
+#define gpr_subprocess_interrupt gpr_subprocess_interrupt_import
+typedef int(*gpr_thd_new_type)(gpr_thd_id *t, void (*thd_body)(void *arg), void *arg, const gpr_thd_options *options);
+extern gpr_thd_new_type gpr_thd_new_import;
+#define gpr_thd_new gpr_thd_new_import
+typedef gpr_thd_options(*gpr_thd_options_default_type)(void);
+extern gpr_thd_options_default_type gpr_thd_options_default_import;
+#define gpr_thd_options_default gpr_thd_options_default_import
+typedef void(*gpr_thd_options_set_detached_type)(gpr_thd_options *options);
+extern gpr_thd_options_set_detached_type gpr_thd_options_set_detached_import;
+#define gpr_thd_options_set_detached gpr_thd_options_set_detached_import
+typedef void(*gpr_thd_options_set_joinable_type)(gpr_thd_options *options);
+extern gpr_thd_options_set_joinable_type gpr_thd_options_set_joinable_import;
+#define gpr_thd_options_set_joinable gpr_thd_options_set_joinable_import
+typedef int(*gpr_thd_options_is_detached_type)(const gpr_thd_options *options);
+extern gpr_thd_options_is_detached_type gpr_thd_options_is_detached_import;
+#define gpr_thd_options_is_detached gpr_thd_options_is_detached_import
+typedef int(*gpr_thd_options_is_joinable_type)(const gpr_thd_options *options);
+extern gpr_thd_options_is_joinable_type gpr_thd_options_is_joinable_import;
+#define gpr_thd_options_is_joinable gpr_thd_options_is_joinable_import
+typedef gpr_thd_id(*gpr_thd_currentid_type)(void);
+extern gpr_thd_currentid_type gpr_thd_currentid_import;
+#define gpr_thd_currentid gpr_thd_currentid_import
+typedef void(*gpr_thd_join_type)(gpr_thd_id t);
+extern gpr_thd_join_type gpr_thd_join_import;
+#define gpr_thd_join gpr_thd_join_import
+
+void pygrpc_load_imports(HMODULE library);
+
+#else /* !GPR_WIN32 */
+
+#include <grpc/support/alloc.h>
+#include <grpc/support/slice.h>
+#include <grpc/support/time.h>
+#include <grpc/status.h>
+#include <grpc/byte_buffer.h>
+#include <grpc/byte_buffer_reader.h>
+#include <grpc/grpc.h>
+#include <grpc/grpc_security.h>
+
+#endif /* !GPR_WIN32 */
+
+#endif
diff --git a/src/objective-c/GRPCClient/private/GRPCUnsecuredChannel.h b/src/python/grpcio/grpc/_cython/loader.c
similarity index 76%
copy from src/objective-c/GRPCClient/private/GRPCUnsecuredChannel.h
copy to src/python/grpcio/grpc/_cython/loader.c
index 8528be4..cdd47de 100644
--- a/src/objective-c/GRPCClient/private/GRPCUnsecuredChannel.h
+++ b/src/python/grpcio/grpc/_cython/loader.c
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -31,8 +31,29 @@
  *
  */
 
-#import "GRPCChannel.h"
+#include "loader.h"
 
-@interface GRPCUnsecuredChannel : GRPCChannel
-- (instancetype)initWithHost:(NSString *)host NS_DESIGNATED_INITIALIZER;
-@end
+#if GPR_WIN32
+
+int pygrpc_load_core(char *path) {
+  HMODULE grpc_c;
+#ifdef GPR_ARCH_32
+  /* Close your eyes for a moment, it'll all be over soon. */
+  char *six = strrchr(path, '6');
+  *six++ = '3';
+  *six = '2';
+#endif
+  grpc_c = LoadLibraryA(path);
+  if (grpc_c) {
+    pygrpc_load_imports(grpc_c);
+    return 1;
+  }
+
+  return 0;
+}
+
+#else
+
+int pygrpc_load_core(char *path) { return 1; }
+
+#endif
diff --git a/src/objective-c/GRPCClient/private/GRPCUnsecuredChannel.h b/src/python/grpcio/grpc/_cython/loader.h
similarity index 80%
copy from src/objective-c/GRPCClient/private/GRPCUnsecuredChannel.h
copy to src/python/grpcio/grpc/_cython/loader.h
index 8528be4..dd31e15 100644
--- a/src/objective-c/GRPCClient/private/GRPCUnsecuredChannel.h
+++ b/src/python/grpcio/grpc/_cython/loader.h
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -31,8 +31,15 @@
  *
  */
 
-#import "GRPCChannel.h"
+#ifndef PYGRPC_LOADER_H_
+#define PYGRPC_LOADER_H_
 
-@interface GRPCUnsecuredChannel : GRPCChannel
-- (instancetype)initWithHost:(NSString *)host NS_DESIGNATED_INITIALIZER;
-@end
+#include "imports.generated.h"
+
+/* Additional inclusions not covered by "imports.generated.h" */
+#include <grpc/byte_buffer_reader.h>
+
+/* Attempts to load the core if necessary, and return non-zero upon succes. */
+int pygrpc_load_core(char *path);
+
+#endif /* GRPC_RB_BYTE_BUFFER_H_ */
diff --git a/src/python/grpcio/grpc_core_dependencies.py b/src/python/grpcio/grpc_core_dependencies.py
index 98ab1ff..8e90f7a 100644
--- a/src/python/grpcio/grpc_core_dependencies.py
+++ b/src/python/grpcio/grpc_core_dependencies.py
@@ -60,6 +60,7 @@
   'src/core/support/string_posix.c',
   'src/core/support/string_win32.c',
   'src/core/support/subprocess_posix.c',
+  'src/core/support/subprocess_windows.c',
   'src/core/support/sync.c',
   'src/core/support/sync_posix.c',
   'src/core/support/sync_win32.c',
@@ -71,6 +72,7 @@
   'src/core/support/time_precise.c',
   'src/core/support/time_win32.c',
   'src/core/support/tls_pthread.c',
+  'src/core/support/wrap_memcpy.c',
   'src/core/httpcli/httpcli_security_connector.c',
   'src/core/security/base64.c',
   'src/core/security/client_auth_filter.c',
@@ -170,6 +172,7 @@
   'src/core/json/json_reader.c',
   'src/core/json/json_string.c',
   'src/core/json/json_writer.c',
+  'src/core/surface/alarm.c',
   'src/core/surface/api_trace.c',
   'src/core/surface/byte_buffer.c',
   'src/core/surface/byte_buffer_reader.c',
@@ -221,7 +224,7 @@
   'src/core/census/context.c',
   'src/core/census/initialize.c',
   'src/core/census/operation.c',
-  'src/core/census/tag_set.c',
+  'src/core/census/placeholders.c',
   'src/core/census/tracing.c',
   'src/boringssl/err_data.c',
   'third_party/boringssl/crypto/aes/aes.c',
diff --git a/tools/run_tests/check_submodules.sh b/src/python/grpcio/grpc_version.py
old mode 100755
new mode 100644
similarity index 66%
copy from tools/run_tests/check_submodules.sh
copy to src/python/grpcio/grpc_version.py
index b4ca4fa..75b88cf
--- a/tools/run_tests/check_submodules.sh
+++ b/src/python/grpcio/grpc_version.py
@@ -1,5 +1,3 @@
-#!/bin/sh
-
 # Copyright 2015-2016, Google Inc.
 # All rights reserved.
 #
@@ -29,26 +27,6 @@
 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
+# AUTO-GENERATED FROM `$REPO_ROOT/templates/src/python/grpcio/grpc_version.py.template`!!!
 
-set -e
-
-export TEST=true
-
-cd `dirname $0`/../..
-
-submodules=`mktemp /tmp/submXXXXXX`
-want_submodules=`mktemp /tmp/submXXXXXX`
-
-git submodule | awk '{ print $1 }' | sort > $submodules
-cat << EOF | awk '{ print $1 }' | sort > $want_submodules
- 9f897b25800d2f54f5c442ef01a60721aeca6d87 third_party/boringssl (version_for_cocoapods_1.0-67-g9f897b2)
- 05b155ff59114735ec8cd089f669c4c3d8f59029 third_party/gflags (v2.1.0-45-g05b155f)
- c99458533a9b4c743ed51537e25989ea55944908 third_party/googletest (release-1.7.0)
- d5fb408ddc281ffcadeb08699e65bb694656d0bd third_party/protobuf (v3.0.0-beta-2)
- 50893291621658f355bc5b4d450a8d06a563053d third_party/zlib (v1.2.8)
-EOF
-
-diff -u $submodules $want_submodules
-
-rm $submodules $want_submodules
-
+VERSION='0.14.0.dev0'
diff --git a/src/python/grpcio/support.py b/src/python/grpcio/support.py
index bbc5096..33244eb 100644
--- a/src/python/grpcio/support.py
+++ b/src/python/grpcio/support.py
@@ -76,16 +76,40 @@
         "Diagnostics found a compilation environment issue:\n{}"
             .format(error_message))
 
-def diagnose_build_ext_error(build_ext, error):
-  {
-      errors.CompileError: diagnose_compile_error
-  }[type(error)](build_ext, error)
-
 def diagnose_compile_error(build_ext, error):
-  """Attempt to run a few test files through the compiler to see if we can
-     diagnose the reason for the compile failure."""
+  """Attempt to diagnose an error during compilation."""
   for c_check, message in C_CHECKS.items():
     _expect_compile(build_ext.compiler, c_check, message)
-  raise commands.CommandError(
-      "\n\nWe could not diagnose your build failure. Please file an issue at "
-      "http://www.github.com/grpc/grpc with `[Python install]` in the title.")
+  python_sources = [
+      source for source in build_ext.get_source_files()
+      if source.startswith('./src/python') and source.endswith('c')
+  ]
+  for source in python_sources:
+    if not os.path.isfile(source):
+      raise commands.CommandError(
+          ("Diagnostics found a missing Python extension source file:\n{}\n\n"
+           "This is usually because the Cython sources haven't been transpiled "
+           "into C yet and you're building from source.\n"
+           "Try setting the environment variable "
+           "`GRPC_PYTHON_BUILD_WITH_CYTHON=1` when invoking `setup.py` or "
+           "when using `pip`, e.g.:\n\n"
+           "pip install -rrequirements.txt\n"
+           "GRPC_PYTHON_BUILD_WITH_CYTHON=1 pip install .")
+            .format(source)
+          )
+
+
+_ERROR_DIAGNOSES = {
+    errors.CompileError: diagnose_compile_error
+}
+
+def diagnose_build_ext_error(build_ext, error, formatted):
+  diagnostic = _ERROR_DIAGNOSES.get(type(error))
+  if diagnostic is None:
+    raise commands.CommandError(
+        "\n\nWe could not diagnose your build failure. Please file an issue at "
+        "http://www.github.com/grpc/grpc with `[Python install]` in the title."
+        "\n\n{}".format(formatted))
+  else:
+    diagnostic(build_ext, error)
+
diff --git a/tools/run_tests/check_submodules.sh b/src/python/grpcio/tests/unit/beta/_implementations_test.py
old mode 100755
new mode 100644
similarity index 64%
copy from tools/run_tests/check_submodules.sh
copy to src/python/grpcio/tests/unit/beta/_implementations_test.py
index b4ca4fa..6b32305
--- a/tools/run_tests/check_submodules.sh
+++ b/src/python/grpcio/tests/unit/beta/_implementations_test.py
@@ -1,6 +1,4 @@
-#!/bin/sh
-
-# Copyright 2015-2016, Google Inc.
+# Copyright 2016, Google Inc.
 # All rights reserved.
 #
 # Redistribution and use in source and binary forms, with or without
@@ -29,26 +27,28 @@
 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
+"""Tests the implementations module of the gRPC Python Beta API."""
 
-set -e
+import unittest
 
-export TEST=true
+from grpc.beta import implementations
+from tests.unit import resources
 
-cd `dirname $0`/../..
 
-submodules=`mktemp /tmp/submXXXXXX`
-want_submodules=`mktemp /tmp/submXXXXXX`
+class ChannelCredentialsTest(unittest.TestCase):
 
-git submodule | awk '{ print $1 }' | sort > $submodules
-cat << EOF | awk '{ print $1 }' | sort > $want_submodules
- 9f897b25800d2f54f5c442ef01a60721aeca6d87 third_party/boringssl (version_for_cocoapods_1.0-67-g9f897b2)
- 05b155ff59114735ec8cd089f669c4c3d8f59029 third_party/gflags (v2.1.0-45-g05b155f)
- c99458533a9b4c743ed51537e25989ea55944908 third_party/googletest (release-1.7.0)
- d5fb408ddc281ffcadeb08699e65bb694656d0bd third_party/protobuf (v3.0.0-beta-2)
- 50893291621658f355bc5b4d450a8d06a563053d third_party/zlib (v1.2.8)
-EOF
+  def test_runtime_provided_root_certificates(self):
+    channel_credentials = implementations.ssl_channel_credentials(
+        None, None, None)
+    self.assertIsInstance(
+        channel_credentials, implementations.ChannelCredentials)
+  
+  def test_application_provided_root_certificates(self):
+    channel_credentials = implementations.ssl_channel_credentials(
+        resources.test_root_certificates(), None, None)
+    self.assertIsInstance(
+        channel_credentials, implementations.ChannelCredentials)
 
-diff -u $submodules $want_submodules
 
-rm $submodules $want_submodules
-
+if __name__ == '__main__':
+  unittest.main(verbosity=2)
diff --git a/src/ruby/ext/grpc/extconf.rb b/src/ruby/ext/grpc/extconf.rb
index 018353c..b7c6cb3 100644
--- a/src/ruby/ext/grpc/extconf.rb
+++ b/src/ruby/ext/grpc/extconf.rb
@@ -1,4 +1,4 @@
-# Copyright 2015, Google Inc.
+# Copyright 2015-2016, Google Inc.
 # All rights reserved.
 #
 # Redistribution and use in source and binary forms, with or without
@@ -54,8 +54,7 @@
   LIBDIR
 ]
 
-fail 'libdl not found' unless have_library('dl', 'dlopen')
-fail 'zlib not found' unless have_library('z', 'inflate')
+windows = RUBY_PLATFORM =~ /mingw|mswin/
 
 grpc_root = File.expand_path(File.join(File.dirname(__FILE__), '../../../..'))
 
@@ -64,29 +63,67 @@
 if ENV.key?('GRPC_LIB_DIR')
   grpc_lib_dir = File.join(grpc_root, ENV['GRPC_LIB_DIR'])
 else
-  grpc_lib_dir = File.join(File.join(grpc_root, 'libs'), grpc_config)
+  grpc_lib_dir = File.join(grpc_root, 'libs', grpc_config)
 end
 
-unless File.exist?(File.join(grpc_lib_dir, 'libgrpc.a'))
-  print "Building internal gRPC\n"
-  system("make -C #{grpc_root} static_c CONFIG=#{grpc_config}")
+ENV['MACOSX_DEPLOYMENT_TARGET'] = '10.7'
+
+unless File.exist?(File.join(grpc_lib_dir, 'libgrpc.a')) or windows
+  ENV['AR'] = RbConfig::CONFIG['AR'] + ' rcs'
+  ENV['CC'] = RbConfig::CONFIG['CC']
+  ENV['LD'] = ENV['CC']
+
+  ENV['AR'] = 'libtool -o' if RUBY_PLATFORM =~ /darwin/
+
+  ENV['EMBED_OPENSSL'] = 'true'
+  ENV['EMBED_ZLIB'] = 'true'
+  ENV['ARCH_FLAGS'] = RbConfig::CONFIG['ARCH_FLAG']
+  ENV['ARCH_FLAGS'] = '-arch i386 -arch x86_64' if RUBY_PLATFORM =~ /darwin/
+
+  output_dir = File.expand_path(RbConfig::CONFIG['topdir'])
+  grpc_lib_dir = File.join(output_dir, 'libs', grpc_config)
+  ENV['BUILDDIR'] = output_dir
+
+  puts 'Building internal gRPC into ' + grpc_lib_dir
+  system("make -j -C #{grpc_root} #{grpc_lib_dir}/libgrpc.a CONFIG=#{grpc_config}")
+  exit 1 unless $? == 0
 end
 
 $CFLAGS << ' -I' + File.join(grpc_root, 'include')
-$LDFLAGS << ' ' + File.join(grpc_lib_dir, 'libgrpc.a')
-$LDFLAGS << ' ' + File.join(grpc_lib_dir, 'libgpr.a')
+$LDFLAGS << ' ' + File.join(grpc_lib_dir, 'libgrpc.a') unless windows
 if grpc_config == 'gcov'
   $CFLAGS << ' -O0 -fprofile-arcs -ftest-coverage'
   $LDFLAGS << ' -fprofile-arcs -ftest-coverage -rdynamic'
 end
 
+$LDFLAGS << ' -Wl,-wrap,memcpy' if RUBY_PLATFORM =~ /linux/
+$LDFLAGS << ' -static' if windows
+
 $CFLAGS << ' -std=c99 '
 $CFLAGS << ' -Wall '
 $CFLAGS << ' -Wextra '
 $CFLAGS << ' -pedantic '
 $CFLAGS << ' -Werror '
+$CFLAGS << ' -Wno-format '
 
-$LDFLAGS << ' -lssl '
-$LDFLAGS << ' -lcrypto '
+output = File.join('grpc', 'grpc_c')
+puts 'Generating Makefile for ' + output
+create_makefile(output)
 
-create_makefile('grpc/grpc')
+strip_tool = RbConfig::CONFIG['STRIP']
+strip_tool = 'strip -x' if RUBY_PLATFORM =~ /darwin/
+
+if grpc_config == 'opt'
+  File.open('Makefile.new', 'w') do |o|
+    o.puts 'hijack: all strip'
+    o.puts
+    File.foreach('Makefile') do |i|
+      o.puts i
+    end
+    o.puts
+    o.puts 'strip:'
+    o.puts "\t$(ECHO) Stripping $(DLLIB)"
+    o.puts "\t$(Q) #{strip_tool} $(DLLIB)"
+  end
+  File.rename('Makefile.new', 'Makefile')
+end
diff --git a/src/ruby/ext/grpc/rb_byte_buffer.c b/src/ruby/ext/grpc/rb_byte_buffer.c
index 0aa34c8..db7cac3 100644
--- a/src/ruby/ext/grpc/rb_byte_buffer.c
+++ b/src/ruby/ext/grpc/rb_byte_buffer.c
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -31,6 +31,8 @@
  *
  */
 
+#include <ruby/ruby.h>
+#include "rb_grpc_imports.generated.h"
 #include "rb_byte_buffer.h"
 
 #include <ruby/ruby.h>
diff --git a/src/ruby/ext/grpc/rb_call.c b/src/ruby/ext/grpc/rb_call.c
index 8f33d72..af05ddf 100644
--- a/src/ruby/ext/grpc/rb_call.c
+++ b/src/ruby/ext/grpc/rb_call.c
@@ -31,6 +31,8 @@
  *
  */
 
+#include <ruby/ruby.h>
+#include "rb_grpc_imports.generated.h"
 #include "rb_call.h"
 
 #include <ruby/ruby.h>
@@ -530,7 +532,8 @@
 
 /* grpc_run_batch_stack_init ensures the run_batch_stack is properly
  * initialized */
-static void grpc_run_batch_stack_init(run_batch_stack *st, unsigned write_flag) {
+static void grpc_run_batch_stack_init(run_batch_stack *st,
+                                      unsigned write_flag) {
   MEMZERO(st, run_batch_stack, 1);
   grpc_metadata_array_init(&st->send_metadata);
   grpc_metadata_array_init(&st->send_trailing_metadata);
diff --git a/src/ruby/ext/grpc/rb_call_credentials.c b/src/ruby/ext/grpc/rb_call_credentials.c
index ebcc659..2426f10 100644
--- a/src/ruby/ext/grpc/rb_call_credentials.c
+++ b/src/ruby/ext/grpc/rb_call_credentials.c
@@ -31,6 +31,8 @@
  *
  */
 
+#include <ruby/ruby.h>
+#include "rb_grpc_imports.generated.h"
 #include "rb_call_credentials.h"
 
 #include <ruby/ruby.h>
diff --git a/src/ruby/ext/grpc/rb_channel.c b/src/ruby/ext/grpc/rb_channel.c
index 2fb8a5c..0e6badb 100644
--- a/src/ruby/ext/grpc/rb_channel.c
+++ b/src/ruby/ext/grpc/rb_channel.c
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -31,6 +31,8 @@
  *
  */
 
+#include <ruby/ruby.h>
+#include "rb_grpc_imports.generated.h"
 #include "rb_channel.h"
 
 #include <ruby/ruby.h>
@@ -227,7 +229,7 @@
   }
   grpc_channel_watch_connectivity_state(
       ch,
-      NUM2LONG(last_state),
+      (grpc_connectivity_state)NUM2LONG(last_state),
       grpc_rb_time_timeval(deadline, /* absolute time */ 0),
       cq,
       ROBJECT(tag));
diff --git a/src/ruby/ext/grpc/rb_channel_args.c b/src/ruby/ext/grpc/rb_channel_args.c
index 37dd981..69827ce 100644
--- a/src/ruby/ext/grpc/rb_channel_args.c
+++ b/src/ruby/ext/grpc/rb_channel_args.c
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -31,6 +31,8 @@
  *
  */
 
+#include <ruby/ruby.h>
+#include "rb_grpc_imports.generated.h"
 #include "rb_channel_args.h"
 
 #include <ruby/ruby.h>
diff --git a/src/ruby/ext/grpc/rb_channel_credentials.c b/src/ruby/ext/grpc/rb_channel_credentials.c
index 3530081..8c6fc3b 100644
--- a/src/ruby/ext/grpc/rb_channel_credentials.c
+++ b/src/ruby/ext/grpc/rb_channel_credentials.c
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -31,6 +31,8 @@
  *
  */
 
+#include <ruby/ruby.h>
+#include "rb_grpc_imports.generated.h"
 #include "rb_channel_credentials.h"
 
 #include <ruby/ruby.h>
diff --git a/src/ruby/ext/grpc/rb_completion_queue.c b/src/ruby/ext/grpc/rb_completion_queue.c
index a7de96d..1eb5a28 100644
--- a/src/ruby/ext/grpc/rb_completion_queue.c
+++ b/src/ruby/ext/grpc/rb_completion_queue.c
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -31,6 +31,8 @@
  *
  */
 
+#include <ruby/ruby.h>
+#include "rb_grpc_imports.generated.h"
 #include "rb_completion_queue.h"
 
 #include <ruby/ruby.h>
diff --git a/src/ruby/ext/grpc/rb_event_thread.c b/src/ruby/ext/grpc/rb_event_thread.c
index 516f0bd..2649a10 100644
--- a/src/ruby/ext/grpc/rb_event_thread.c
+++ b/src/ruby/ext/grpc/rb_event_thread.c
@@ -31,6 +31,8 @@
  *
  */
 
+#include <ruby/ruby.h>
+#include "rb_grpc_imports.generated.h"
 #include "rb_event_thread.h"
 
 #include <stdbool.h>
diff --git a/src/ruby/ext/grpc/rb_grpc.c b/src/ruby/ext/grpc/rb_grpc.c
index 265ab58..eefdb93 100644
--- a/src/ruby/ext/grpc/rb_grpc.c
+++ b/src/ruby/ext/grpc/rb_grpc.c
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -31,6 +31,8 @@
  *
  */
 
+#include <ruby/ruby.h>
+#include "rb_grpc_imports.generated.h"
 #include "rb_grpc.h"
 
 #include <math.h>
@@ -45,6 +47,7 @@
 #include "rb_channel.h"
 #include "rb_channel_credentials.h"
 #include "rb_completion_queue.h"
+#include "rb_loader.h"
 #include "rb_server.h"
 #include "rb_server_credentials.h"
 
@@ -297,7 +300,12 @@
 VALUE sym_details = Qundef;
 VALUE sym_metadata = Qundef;
 
-void Init_grpc() {
+void Init_grpc_c() {
+  if (!grpc_rb_load_core()) {
+    rb_raise(rb_eLoadError, "Couldn't find or load gRPC's dynamic C core");
+    return;
+  }
+
   grpc_init();
 
 /* TODO: find alternative to ruby_vm_at_exit that is ok in Ruby 2.0 */
diff --git a/src/ruby/ext/grpc/rb_grpc_imports.generated.c b/src/ruby/ext/grpc/rb_grpc_imports.generated.c
new file mode 100644
index 0000000..d4ddb73
--- /dev/null
+++ b/src/ruby/ext/grpc/rb_grpc_imports.generated.c
@@ -0,0 +1,560 @@
+/*
+ *
+ * Copyright 2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <grpc/support/port_platform.h>
+
+#ifdef GPR_WIN32
+
+#include "rb_grpc_imports.generated.h"
+
+census_initialize_type census_initialize_import;
+census_shutdown_type census_shutdown_import;
+census_supported_type census_supported_import;
+census_enabled_type census_enabled_import;
+census_context_create_type census_context_create_import;
+census_context_destroy_type census_context_destroy_import;
+census_context_get_status_type census_context_get_status_import;
+census_context_initialize_iterator_type census_context_initialize_iterator_import;
+census_context_next_tag_type census_context_next_tag_import;
+census_context_get_tag_type census_context_get_tag_import;
+census_context_encode_type census_context_encode_import;
+census_context_decode_type census_context_decode_import;
+census_trace_mask_type census_trace_mask_import;
+census_set_trace_mask_type census_set_trace_mask_import;
+census_start_rpc_op_timestamp_type census_start_rpc_op_timestamp_import;
+census_start_client_rpc_op_type census_start_client_rpc_op_import;
+census_set_rpc_client_peer_type census_set_rpc_client_peer_import;
+census_start_server_rpc_op_type census_start_server_rpc_op_import;
+census_start_op_type census_start_op_import;
+census_end_op_type census_end_op_import;
+census_trace_print_type census_trace_print_import;
+census_trace_scan_start_type census_trace_scan_start_import;
+census_get_trace_record_type census_get_trace_record_import;
+census_trace_scan_end_type census_trace_scan_end_import;
+census_record_values_type census_record_values_import;
+census_view_create_type census_view_create_import;
+census_view_delete_type census_view_delete_import;
+census_view_metric_type census_view_metric_import;
+census_view_naggregations_type census_view_naggregations_import;
+census_view_tags_type census_view_tags_import;
+census_view_aggregrations_type census_view_aggregrations_import;
+census_view_get_data_type census_view_get_data_import;
+census_view_reset_type census_view_reset_import;
+grpc_compression_algorithm_parse_type grpc_compression_algorithm_parse_import;
+grpc_compression_algorithm_name_type grpc_compression_algorithm_name_import;
+grpc_compression_algorithm_for_level_type grpc_compression_algorithm_for_level_import;
+grpc_compression_options_init_type grpc_compression_options_init_import;
+grpc_compression_options_enable_algorithm_type grpc_compression_options_enable_algorithm_import;
+grpc_compression_options_disable_algorithm_type grpc_compression_options_disable_algorithm_import;
+grpc_compression_options_is_algorithm_enabled_type grpc_compression_options_is_algorithm_enabled_import;
+grpc_metadata_array_init_type grpc_metadata_array_init_import;
+grpc_metadata_array_destroy_type grpc_metadata_array_destroy_import;
+grpc_call_details_init_type grpc_call_details_init_import;
+grpc_call_details_destroy_type grpc_call_details_destroy_import;
+grpc_register_plugin_type grpc_register_plugin_import;
+grpc_init_type grpc_init_import;
+grpc_shutdown_type grpc_shutdown_import;
+grpc_version_string_type grpc_version_string_import;
+grpc_completion_queue_create_type grpc_completion_queue_create_import;
+grpc_completion_queue_next_type grpc_completion_queue_next_import;
+grpc_completion_queue_pluck_type grpc_completion_queue_pluck_import;
+grpc_completion_queue_shutdown_type grpc_completion_queue_shutdown_import;
+grpc_completion_queue_destroy_type grpc_completion_queue_destroy_import;
+grpc_alarm_create_type grpc_alarm_create_import;
+grpc_alarm_cancel_type grpc_alarm_cancel_import;
+grpc_alarm_destroy_type grpc_alarm_destroy_import;
+grpc_channel_check_connectivity_state_type grpc_channel_check_connectivity_state_import;
+grpc_channel_watch_connectivity_state_type grpc_channel_watch_connectivity_state_import;
+grpc_channel_create_call_type grpc_channel_create_call_import;
+grpc_channel_ping_type grpc_channel_ping_import;
+grpc_channel_register_call_type grpc_channel_register_call_import;
+grpc_channel_create_registered_call_type grpc_channel_create_registered_call_import;
+grpc_call_start_batch_type grpc_call_start_batch_import;
+grpc_call_get_peer_type grpc_call_get_peer_import;
+grpc_census_call_set_context_type grpc_census_call_set_context_import;
+grpc_census_call_get_context_type grpc_census_call_get_context_import;
+grpc_channel_get_target_type grpc_channel_get_target_import;
+grpc_insecure_channel_create_type grpc_insecure_channel_create_import;
+grpc_lame_client_channel_create_type grpc_lame_client_channel_create_import;
+grpc_channel_destroy_type grpc_channel_destroy_import;
+grpc_call_cancel_type grpc_call_cancel_import;
+grpc_call_cancel_with_status_type grpc_call_cancel_with_status_import;
+grpc_call_destroy_type grpc_call_destroy_import;
+grpc_server_request_call_type grpc_server_request_call_import;
+grpc_server_register_method_type grpc_server_register_method_import;
+grpc_server_request_registered_call_type grpc_server_request_registered_call_import;
+grpc_server_create_type grpc_server_create_import;
+grpc_server_register_completion_queue_type grpc_server_register_completion_queue_import;
+grpc_server_add_insecure_http2_port_type grpc_server_add_insecure_http2_port_import;
+grpc_server_start_type grpc_server_start_import;
+grpc_server_shutdown_and_notify_type grpc_server_shutdown_and_notify_import;
+grpc_server_cancel_all_calls_type grpc_server_cancel_all_calls_import;
+grpc_server_destroy_type grpc_server_destroy_import;
+grpc_tracer_set_enabled_type grpc_tracer_set_enabled_import;
+grpc_header_key_is_legal_type grpc_header_key_is_legal_import;
+grpc_header_nonbin_value_is_legal_type grpc_header_nonbin_value_is_legal_import;
+grpc_is_binary_header_type grpc_is_binary_header_import;
+grpc_auth_property_iterator_next_type grpc_auth_property_iterator_next_import;
+grpc_auth_context_property_iterator_type grpc_auth_context_property_iterator_import;
+grpc_auth_context_peer_identity_type grpc_auth_context_peer_identity_import;
+grpc_auth_context_find_properties_by_name_type grpc_auth_context_find_properties_by_name_import;
+grpc_auth_context_peer_identity_property_name_type grpc_auth_context_peer_identity_property_name_import;
+grpc_auth_context_peer_is_authenticated_type grpc_auth_context_peer_is_authenticated_import;
+grpc_call_auth_context_type grpc_call_auth_context_import;
+grpc_auth_context_release_type grpc_auth_context_release_import;
+grpc_auth_context_add_property_type grpc_auth_context_add_property_import;
+grpc_auth_context_add_cstring_property_type grpc_auth_context_add_cstring_property_import;
+grpc_auth_context_set_peer_identity_property_name_type grpc_auth_context_set_peer_identity_property_name_import;
+grpc_channel_credentials_release_type grpc_channel_credentials_release_import;
+grpc_google_default_credentials_create_type grpc_google_default_credentials_create_import;
+grpc_ssl_credentials_create_type grpc_ssl_credentials_create_import;
+grpc_call_credentials_release_type grpc_call_credentials_release_import;
+grpc_composite_channel_credentials_create_type grpc_composite_channel_credentials_create_import;
+grpc_composite_call_credentials_create_type grpc_composite_call_credentials_create_import;
+grpc_google_compute_engine_credentials_create_type grpc_google_compute_engine_credentials_create_import;
+grpc_max_auth_token_lifetime_type grpc_max_auth_token_lifetime_import;
+grpc_service_account_jwt_access_credentials_create_type grpc_service_account_jwt_access_credentials_create_import;
+grpc_google_refresh_token_credentials_create_type grpc_google_refresh_token_credentials_create_import;
+grpc_access_token_credentials_create_type grpc_access_token_credentials_create_import;
+grpc_google_iam_credentials_create_type grpc_google_iam_credentials_create_import;
+grpc_metadata_credentials_create_from_plugin_type grpc_metadata_credentials_create_from_plugin_import;
+grpc_secure_channel_create_type grpc_secure_channel_create_import;
+grpc_server_credentials_release_type grpc_server_credentials_release_import;
+grpc_ssl_server_credentials_create_type grpc_ssl_server_credentials_create_import;
+grpc_server_add_secure_http2_port_type grpc_server_add_secure_http2_port_import;
+grpc_call_set_credentials_type grpc_call_set_credentials_import;
+grpc_server_credentials_set_auth_metadata_processor_type grpc_server_credentials_set_auth_metadata_processor_import;
+gpr_malloc_type gpr_malloc_import;
+gpr_free_type gpr_free_import;
+gpr_realloc_type gpr_realloc_import;
+gpr_malloc_aligned_type gpr_malloc_aligned_import;
+gpr_free_aligned_type gpr_free_aligned_import;
+gpr_set_allocation_functions_type gpr_set_allocation_functions_import;
+gpr_get_allocation_functions_type gpr_get_allocation_functions_import;
+grpc_raw_byte_buffer_create_type grpc_raw_byte_buffer_create_import;
+grpc_raw_compressed_byte_buffer_create_type grpc_raw_compressed_byte_buffer_create_import;
+grpc_byte_buffer_copy_type grpc_byte_buffer_copy_import;
+grpc_byte_buffer_length_type grpc_byte_buffer_length_import;
+grpc_byte_buffer_destroy_type grpc_byte_buffer_destroy_import;
+grpc_byte_buffer_reader_init_type grpc_byte_buffer_reader_init_import;
+grpc_byte_buffer_reader_destroy_type grpc_byte_buffer_reader_destroy_import;
+grpc_byte_buffer_reader_next_type grpc_byte_buffer_reader_next_import;
+grpc_byte_buffer_reader_readall_type grpc_byte_buffer_reader_readall_import;
+grpc_raw_byte_buffer_from_reader_type grpc_raw_byte_buffer_from_reader_import;
+gpr_log_type gpr_log_import;
+gpr_log_message_type gpr_log_message_import;
+gpr_set_log_function_type gpr_set_log_function_import;
+gpr_slice_ref_type gpr_slice_ref_import;
+gpr_slice_unref_type gpr_slice_unref_import;
+gpr_slice_new_type gpr_slice_new_import;
+gpr_slice_new_with_len_type gpr_slice_new_with_len_import;
+gpr_slice_malloc_type gpr_slice_malloc_import;
+gpr_slice_from_copied_string_type gpr_slice_from_copied_string_import;
+gpr_slice_from_copied_buffer_type gpr_slice_from_copied_buffer_import;
+gpr_slice_from_static_string_type gpr_slice_from_static_string_import;
+gpr_slice_sub_type gpr_slice_sub_import;
+gpr_slice_sub_no_ref_type gpr_slice_sub_no_ref_import;
+gpr_slice_split_tail_type gpr_slice_split_tail_import;
+gpr_slice_split_head_type gpr_slice_split_head_import;
+gpr_empty_slice_type gpr_empty_slice_import;
+gpr_slice_cmp_type gpr_slice_cmp_import;
+gpr_slice_str_cmp_type gpr_slice_str_cmp_import;
+gpr_slice_buffer_init_type gpr_slice_buffer_init_import;
+gpr_slice_buffer_destroy_type gpr_slice_buffer_destroy_import;
+gpr_slice_buffer_add_type gpr_slice_buffer_add_import;
+gpr_slice_buffer_add_indexed_type gpr_slice_buffer_add_indexed_import;
+gpr_slice_buffer_addn_type gpr_slice_buffer_addn_import;
+gpr_slice_buffer_tiny_add_type gpr_slice_buffer_tiny_add_import;
+gpr_slice_buffer_pop_type gpr_slice_buffer_pop_import;
+gpr_slice_buffer_reset_and_unref_type gpr_slice_buffer_reset_and_unref_import;
+gpr_slice_buffer_swap_type gpr_slice_buffer_swap_import;
+gpr_slice_buffer_move_into_type gpr_slice_buffer_move_into_import;
+gpr_slice_buffer_trim_end_type gpr_slice_buffer_trim_end_import;
+gpr_slice_buffer_move_first_type gpr_slice_buffer_move_first_import;
+gpr_slice_buffer_take_first_type gpr_slice_buffer_take_first_import;
+gpr_mu_init_type gpr_mu_init_import;
+gpr_mu_destroy_type gpr_mu_destroy_import;
+gpr_mu_lock_type gpr_mu_lock_import;
+gpr_mu_unlock_type gpr_mu_unlock_import;
+gpr_mu_trylock_type gpr_mu_trylock_import;
+gpr_cv_init_type gpr_cv_init_import;
+gpr_cv_destroy_type gpr_cv_destroy_import;
+gpr_cv_wait_type gpr_cv_wait_import;
+gpr_cv_signal_type gpr_cv_signal_import;
+gpr_cv_broadcast_type gpr_cv_broadcast_import;
+gpr_once_init_type gpr_once_init_import;
+gpr_event_init_type gpr_event_init_import;
+gpr_event_set_type gpr_event_set_import;
+gpr_event_get_type gpr_event_get_import;
+gpr_event_wait_type gpr_event_wait_import;
+gpr_ref_init_type gpr_ref_init_import;
+gpr_ref_type gpr_ref_import;
+gpr_refn_type gpr_refn_import;
+gpr_unref_type gpr_unref_import;
+gpr_stats_init_type gpr_stats_init_import;
+gpr_stats_inc_type gpr_stats_inc_import;
+gpr_stats_read_type gpr_stats_read_import;
+gpr_time_0_type gpr_time_0_import;
+gpr_inf_future_type gpr_inf_future_import;
+gpr_inf_past_type gpr_inf_past_import;
+gpr_time_init_type gpr_time_init_import;
+gpr_now_type gpr_now_import;
+gpr_convert_clock_type_type gpr_convert_clock_type_import;
+gpr_time_cmp_type gpr_time_cmp_import;
+gpr_time_max_type gpr_time_max_import;
+gpr_time_min_type gpr_time_min_import;
+gpr_time_add_type gpr_time_add_import;
+gpr_time_sub_type gpr_time_sub_import;
+gpr_time_from_micros_type gpr_time_from_micros_import;
+gpr_time_from_nanos_type gpr_time_from_nanos_import;
+gpr_time_from_millis_type gpr_time_from_millis_import;
+gpr_time_from_seconds_type gpr_time_from_seconds_import;
+gpr_time_from_minutes_type gpr_time_from_minutes_import;
+gpr_time_from_hours_type gpr_time_from_hours_import;
+gpr_time_to_millis_type gpr_time_to_millis_import;
+gpr_time_similar_type gpr_time_similar_import;
+gpr_sleep_until_type gpr_sleep_until_import;
+gpr_timespec_to_micros_type gpr_timespec_to_micros_import;
+gpr_avl_create_type gpr_avl_create_import;
+gpr_avl_ref_type gpr_avl_ref_import;
+gpr_avl_unref_type gpr_avl_unref_import;
+gpr_avl_add_type gpr_avl_add_import;
+gpr_avl_remove_type gpr_avl_remove_import;
+gpr_avl_get_type gpr_avl_get_import;
+gpr_cmdline_create_type gpr_cmdline_create_import;
+gpr_cmdline_add_int_type gpr_cmdline_add_int_import;
+gpr_cmdline_add_flag_type gpr_cmdline_add_flag_import;
+gpr_cmdline_add_string_type gpr_cmdline_add_string_import;
+gpr_cmdline_on_extra_arg_type gpr_cmdline_on_extra_arg_import;
+gpr_cmdline_set_survive_failure_type gpr_cmdline_set_survive_failure_import;
+gpr_cmdline_parse_type gpr_cmdline_parse_import;
+gpr_cmdline_destroy_type gpr_cmdline_destroy_import;
+gpr_cmdline_usage_string_type gpr_cmdline_usage_string_import;
+gpr_cpu_num_cores_type gpr_cpu_num_cores_import;
+gpr_cpu_current_cpu_type gpr_cpu_current_cpu_import;
+gpr_histogram_create_type gpr_histogram_create_import;
+gpr_histogram_destroy_type gpr_histogram_destroy_import;
+gpr_histogram_add_type gpr_histogram_add_import;
+gpr_histogram_merge_type gpr_histogram_merge_import;
+gpr_histogram_percentile_type gpr_histogram_percentile_import;
+gpr_histogram_mean_type gpr_histogram_mean_import;
+gpr_histogram_stddev_type gpr_histogram_stddev_import;
+gpr_histogram_variance_type gpr_histogram_variance_import;
+gpr_histogram_maximum_type gpr_histogram_maximum_import;
+gpr_histogram_minimum_type gpr_histogram_minimum_import;
+gpr_histogram_count_type gpr_histogram_count_import;
+gpr_histogram_sum_type gpr_histogram_sum_import;
+gpr_histogram_sum_of_squares_type gpr_histogram_sum_of_squares_import;
+gpr_histogram_get_contents_type gpr_histogram_get_contents_import;
+gpr_histogram_merge_contents_type gpr_histogram_merge_contents_import;
+gpr_join_host_port_type gpr_join_host_port_import;
+gpr_split_host_port_type gpr_split_host_port_import;
+gpr_format_message_type gpr_format_message_import;
+gpr_strdup_type gpr_strdup_import;
+gpr_asprintf_type gpr_asprintf_import;
+gpr_subprocess_binary_extension_type gpr_subprocess_binary_extension_import;
+gpr_subprocess_create_type gpr_subprocess_create_import;
+gpr_subprocess_destroy_type gpr_subprocess_destroy_import;
+gpr_subprocess_join_type gpr_subprocess_join_import;
+gpr_subprocess_interrupt_type gpr_subprocess_interrupt_import;
+gpr_thd_new_type gpr_thd_new_import;
+gpr_thd_options_default_type gpr_thd_options_default_import;
+gpr_thd_options_set_detached_type gpr_thd_options_set_detached_import;
+gpr_thd_options_set_joinable_type gpr_thd_options_set_joinable_import;
+gpr_thd_options_is_detached_type gpr_thd_options_is_detached_import;
+gpr_thd_options_is_joinable_type gpr_thd_options_is_joinable_import;
+gpr_thd_currentid_type gpr_thd_currentid_import;
+gpr_thd_join_type gpr_thd_join_import;
+
+void grpc_rb_load_imports(HMODULE library) {
+  census_initialize_import = (census_initialize_type) GetProcAddress(library, "census_initialize");
+  census_shutdown_import = (census_shutdown_type) GetProcAddress(library, "census_shutdown");
+  census_supported_import = (census_supported_type) GetProcAddress(library, "census_supported");
+  census_enabled_import = (census_enabled_type) GetProcAddress(library, "census_enabled");
+  census_context_create_import = (census_context_create_type) GetProcAddress(library, "census_context_create");
+  census_context_destroy_import = (census_context_destroy_type) GetProcAddress(library, "census_context_destroy");
+  census_context_get_status_import = (census_context_get_status_type) GetProcAddress(library, "census_context_get_status");
+  census_context_initialize_iterator_import = (census_context_initialize_iterator_type) GetProcAddress(library, "census_context_initialize_iterator");
+  census_context_next_tag_import = (census_context_next_tag_type) GetProcAddress(library, "census_context_next_tag");
+  census_context_get_tag_import = (census_context_get_tag_type) GetProcAddress(library, "census_context_get_tag");
+  census_context_encode_import = (census_context_encode_type) GetProcAddress(library, "census_context_encode");
+  census_context_decode_import = (census_context_decode_type) GetProcAddress(library, "census_context_decode");
+  census_trace_mask_import = (census_trace_mask_type) GetProcAddress(library, "census_trace_mask");
+  census_set_trace_mask_import = (census_set_trace_mask_type) GetProcAddress(library, "census_set_trace_mask");
+  census_start_rpc_op_timestamp_import = (census_start_rpc_op_timestamp_type) GetProcAddress(library, "census_start_rpc_op_timestamp");
+  census_start_client_rpc_op_import = (census_start_client_rpc_op_type) GetProcAddress(library, "census_start_client_rpc_op");
+  census_set_rpc_client_peer_import = (census_set_rpc_client_peer_type) GetProcAddress(library, "census_set_rpc_client_peer");
+  census_start_server_rpc_op_import = (census_start_server_rpc_op_type) GetProcAddress(library, "census_start_server_rpc_op");
+  census_start_op_import = (census_start_op_type) GetProcAddress(library, "census_start_op");
+  census_end_op_import = (census_end_op_type) GetProcAddress(library, "census_end_op");
+  census_trace_print_import = (census_trace_print_type) GetProcAddress(library, "census_trace_print");
+  census_trace_scan_start_import = (census_trace_scan_start_type) GetProcAddress(library, "census_trace_scan_start");
+  census_get_trace_record_import = (census_get_trace_record_type) GetProcAddress(library, "census_get_trace_record");
+  census_trace_scan_end_import = (census_trace_scan_end_type) GetProcAddress(library, "census_trace_scan_end");
+  census_record_values_import = (census_record_values_type) GetProcAddress(library, "census_record_values");
+  census_view_create_import = (census_view_create_type) GetProcAddress(library, "census_view_create");
+  census_view_delete_import = (census_view_delete_type) GetProcAddress(library, "census_view_delete");
+  census_view_metric_import = (census_view_metric_type) GetProcAddress(library, "census_view_metric");
+  census_view_naggregations_import = (census_view_naggregations_type) GetProcAddress(library, "census_view_naggregations");
+  census_view_tags_import = (census_view_tags_type) GetProcAddress(library, "census_view_tags");
+  census_view_aggregrations_import = (census_view_aggregrations_type) GetProcAddress(library, "census_view_aggregrations");
+  census_view_get_data_import = (census_view_get_data_type) GetProcAddress(library, "census_view_get_data");
+  census_view_reset_import = (census_view_reset_type) GetProcAddress(library, "census_view_reset");
+  grpc_compression_algorithm_parse_import = (grpc_compression_algorithm_parse_type) GetProcAddress(library, "grpc_compression_algorithm_parse");
+  grpc_compression_algorithm_name_import = (grpc_compression_algorithm_name_type) GetProcAddress(library, "grpc_compression_algorithm_name");
+  grpc_compression_algorithm_for_level_import = (grpc_compression_algorithm_for_level_type) GetProcAddress(library, "grpc_compression_algorithm_for_level");
+  grpc_compression_options_init_import = (grpc_compression_options_init_type) GetProcAddress(library, "grpc_compression_options_init");
+  grpc_compression_options_enable_algorithm_import = (grpc_compression_options_enable_algorithm_type) GetProcAddress(library, "grpc_compression_options_enable_algorithm");
+  grpc_compression_options_disable_algorithm_import = (grpc_compression_options_disable_algorithm_type) GetProcAddress(library, "grpc_compression_options_disable_algorithm");
+  grpc_compression_options_is_algorithm_enabled_import = (grpc_compression_options_is_algorithm_enabled_type) GetProcAddress(library, "grpc_compression_options_is_algorithm_enabled");
+  grpc_metadata_array_init_import = (grpc_metadata_array_init_type) GetProcAddress(library, "grpc_metadata_array_init");
+  grpc_metadata_array_destroy_import = (grpc_metadata_array_destroy_type) GetProcAddress(library, "grpc_metadata_array_destroy");
+  grpc_call_details_init_import = (grpc_call_details_init_type) GetProcAddress(library, "grpc_call_details_init");
+  grpc_call_details_destroy_import = (grpc_call_details_destroy_type) GetProcAddress(library, "grpc_call_details_destroy");
+  grpc_register_plugin_import = (grpc_register_plugin_type) GetProcAddress(library, "grpc_register_plugin");
+  grpc_init_import = (grpc_init_type) GetProcAddress(library, "grpc_init");
+  grpc_shutdown_import = (grpc_shutdown_type) GetProcAddress(library, "grpc_shutdown");
+  grpc_version_string_import = (grpc_version_string_type) GetProcAddress(library, "grpc_version_string");
+  grpc_completion_queue_create_import = (grpc_completion_queue_create_type) GetProcAddress(library, "grpc_completion_queue_create");
+  grpc_completion_queue_next_import = (grpc_completion_queue_next_type) GetProcAddress(library, "grpc_completion_queue_next");
+  grpc_completion_queue_pluck_import = (grpc_completion_queue_pluck_type) GetProcAddress(library, "grpc_completion_queue_pluck");
+  grpc_completion_queue_shutdown_import = (grpc_completion_queue_shutdown_type) GetProcAddress(library, "grpc_completion_queue_shutdown");
+  grpc_completion_queue_destroy_import = (grpc_completion_queue_destroy_type) GetProcAddress(library, "grpc_completion_queue_destroy");
+  grpc_alarm_create_import = (grpc_alarm_create_type) GetProcAddress(library, "grpc_alarm_create");
+  grpc_alarm_cancel_import = (grpc_alarm_cancel_type) GetProcAddress(library, "grpc_alarm_cancel");
+  grpc_alarm_destroy_import = (grpc_alarm_destroy_type) GetProcAddress(library, "grpc_alarm_destroy");
+  grpc_channel_check_connectivity_state_import = (grpc_channel_check_connectivity_state_type) GetProcAddress(library, "grpc_channel_check_connectivity_state");
+  grpc_channel_watch_connectivity_state_import = (grpc_channel_watch_connectivity_state_type) GetProcAddress(library, "grpc_channel_watch_connectivity_state");
+  grpc_channel_create_call_import = (grpc_channel_create_call_type) GetProcAddress(library, "grpc_channel_create_call");
+  grpc_channel_ping_import = (grpc_channel_ping_type) GetProcAddress(library, "grpc_channel_ping");
+  grpc_channel_register_call_import = (grpc_channel_register_call_type) GetProcAddress(library, "grpc_channel_register_call");
+  grpc_channel_create_registered_call_import = (grpc_channel_create_registered_call_type) GetProcAddress(library, "grpc_channel_create_registered_call");
+  grpc_call_start_batch_import = (grpc_call_start_batch_type) GetProcAddress(library, "grpc_call_start_batch");
+  grpc_call_get_peer_import = (grpc_call_get_peer_type) GetProcAddress(library, "grpc_call_get_peer");
+  grpc_census_call_set_context_import = (grpc_census_call_set_context_type) GetProcAddress(library, "grpc_census_call_set_context");
+  grpc_census_call_get_context_import = (grpc_census_call_get_context_type) GetProcAddress(library, "grpc_census_call_get_context");
+  grpc_channel_get_target_import = (grpc_channel_get_target_type) GetProcAddress(library, "grpc_channel_get_target");
+  grpc_insecure_channel_create_import = (grpc_insecure_channel_create_type) GetProcAddress(library, "grpc_insecure_channel_create");
+  grpc_lame_client_channel_create_import = (grpc_lame_client_channel_create_type) GetProcAddress(library, "grpc_lame_client_channel_create");
+  grpc_channel_destroy_import = (grpc_channel_destroy_type) GetProcAddress(library, "grpc_channel_destroy");
+  grpc_call_cancel_import = (grpc_call_cancel_type) GetProcAddress(library, "grpc_call_cancel");
+  grpc_call_cancel_with_status_import = (grpc_call_cancel_with_status_type) GetProcAddress(library, "grpc_call_cancel_with_status");
+  grpc_call_destroy_import = (grpc_call_destroy_type) GetProcAddress(library, "grpc_call_destroy");
+  grpc_server_request_call_import = (grpc_server_request_call_type) GetProcAddress(library, "grpc_server_request_call");
+  grpc_server_register_method_import = (grpc_server_register_method_type) GetProcAddress(library, "grpc_server_register_method");
+  grpc_server_request_registered_call_import = (grpc_server_request_registered_call_type) GetProcAddress(library, "grpc_server_request_registered_call");
+  grpc_server_create_import = (grpc_server_create_type) GetProcAddress(library, "grpc_server_create");
+  grpc_server_register_completion_queue_import = (grpc_server_register_completion_queue_type) GetProcAddress(library, "grpc_server_register_completion_queue");
+  grpc_server_add_insecure_http2_port_import = (grpc_server_add_insecure_http2_port_type) GetProcAddress(library, "grpc_server_add_insecure_http2_port");
+  grpc_server_start_import = (grpc_server_start_type) GetProcAddress(library, "grpc_server_start");
+  grpc_server_shutdown_and_notify_import = (grpc_server_shutdown_and_notify_type) GetProcAddress(library, "grpc_server_shutdown_and_notify");
+  grpc_server_cancel_all_calls_import = (grpc_server_cancel_all_calls_type) GetProcAddress(library, "grpc_server_cancel_all_calls");
+  grpc_server_destroy_import = (grpc_server_destroy_type) GetProcAddress(library, "grpc_server_destroy");
+  grpc_tracer_set_enabled_import = (grpc_tracer_set_enabled_type) GetProcAddress(library, "grpc_tracer_set_enabled");
+  grpc_header_key_is_legal_import = (grpc_header_key_is_legal_type) GetProcAddress(library, "grpc_header_key_is_legal");
+  grpc_header_nonbin_value_is_legal_import = (grpc_header_nonbin_value_is_legal_type) GetProcAddress(library, "grpc_header_nonbin_value_is_legal");
+  grpc_is_binary_header_import = (grpc_is_binary_header_type) GetProcAddress(library, "grpc_is_binary_header");
+  grpc_auth_property_iterator_next_import = (grpc_auth_property_iterator_next_type) GetProcAddress(library, "grpc_auth_property_iterator_next");
+  grpc_auth_context_property_iterator_import = (grpc_auth_context_property_iterator_type) GetProcAddress(library, "grpc_auth_context_property_iterator");
+  grpc_auth_context_peer_identity_import = (grpc_auth_context_peer_identity_type) GetProcAddress(library, "grpc_auth_context_peer_identity");
+  grpc_auth_context_find_properties_by_name_import = (grpc_auth_context_find_properties_by_name_type) GetProcAddress(library, "grpc_auth_context_find_properties_by_name");
+  grpc_auth_context_peer_identity_property_name_import = (grpc_auth_context_peer_identity_property_name_type) GetProcAddress(library, "grpc_auth_context_peer_identity_property_name");
+  grpc_auth_context_peer_is_authenticated_import = (grpc_auth_context_peer_is_authenticated_type) GetProcAddress(library, "grpc_auth_context_peer_is_authenticated");
+  grpc_call_auth_context_import = (grpc_call_auth_context_type) GetProcAddress(library, "grpc_call_auth_context");
+  grpc_auth_context_release_import = (grpc_auth_context_release_type) GetProcAddress(library, "grpc_auth_context_release");
+  grpc_auth_context_add_property_import = (grpc_auth_context_add_property_type) GetProcAddress(library, "grpc_auth_context_add_property");
+  grpc_auth_context_add_cstring_property_import = (grpc_auth_context_add_cstring_property_type) GetProcAddress(library, "grpc_auth_context_add_cstring_property");
+  grpc_auth_context_set_peer_identity_property_name_import = (grpc_auth_context_set_peer_identity_property_name_type) GetProcAddress(library, "grpc_auth_context_set_peer_identity_property_name");
+  grpc_channel_credentials_release_import = (grpc_channel_credentials_release_type) GetProcAddress(library, "grpc_channel_credentials_release");
+  grpc_google_default_credentials_create_import = (grpc_google_default_credentials_create_type) GetProcAddress(library, "grpc_google_default_credentials_create");
+  grpc_ssl_credentials_create_import = (grpc_ssl_credentials_create_type) GetProcAddress(library, "grpc_ssl_credentials_create");
+  grpc_call_credentials_release_import = (grpc_call_credentials_release_type) GetProcAddress(library, "grpc_call_credentials_release");
+  grpc_composite_channel_credentials_create_import = (grpc_composite_channel_credentials_create_type) GetProcAddress(library, "grpc_composite_channel_credentials_create");
+  grpc_composite_call_credentials_create_import = (grpc_composite_call_credentials_create_type) GetProcAddress(library, "grpc_composite_call_credentials_create");
+  grpc_google_compute_engine_credentials_create_import = (grpc_google_compute_engine_credentials_create_type) GetProcAddress(library, "grpc_google_compute_engine_credentials_create");
+  grpc_max_auth_token_lifetime_import = (grpc_max_auth_token_lifetime_type) GetProcAddress(library, "grpc_max_auth_token_lifetime");
+  grpc_service_account_jwt_access_credentials_create_import = (grpc_service_account_jwt_access_credentials_create_type) GetProcAddress(library, "grpc_service_account_jwt_access_credentials_create");
+  grpc_google_refresh_token_credentials_create_import = (grpc_google_refresh_token_credentials_create_type) GetProcAddress(library, "grpc_google_refresh_token_credentials_create");
+  grpc_access_token_credentials_create_import = (grpc_access_token_credentials_create_type) GetProcAddress(library, "grpc_access_token_credentials_create");
+  grpc_google_iam_credentials_create_import = (grpc_google_iam_credentials_create_type) GetProcAddress(library, "grpc_google_iam_credentials_create");
+  grpc_metadata_credentials_create_from_plugin_import = (grpc_metadata_credentials_create_from_plugin_type) GetProcAddress(library, "grpc_metadata_credentials_create_from_plugin");
+  grpc_secure_channel_create_import = (grpc_secure_channel_create_type) GetProcAddress(library, "grpc_secure_channel_create");
+  grpc_server_credentials_release_import = (grpc_server_credentials_release_type) GetProcAddress(library, "grpc_server_credentials_release");
+  grpc_ssl_server_credentials_create_import = (grpc_ssl_server_credentials_create_type) GetProcAddress(library, "grpc_ssl_server_credentials_create");
+  grpc_server_add_secure_http2_port_import = (grpc_server_add_secure_http2_port_type) GetProcAddress(library, "grpc_server_add_secure_http2_port");
+  grpc_call_set_credentials_import = (grpc_call_set_credentials_type) GetProcAddress(library, "grpc_call_set_credentials");
+  grpc_server_credentials_set_auth_metadata_processor_import = (grpc_server_credentials_set_auth_metadata_processor_type) GetProcAddress(library, "grpc_server_credentials_set_auth_metadata_processor");
+  gpr_malloc_import = (gpr_malloc_type) GetProcAddress(library, "gpr_malloc");
+  gpr_free_import = (gpr_free_type) GetProcAddress(library, "gpr_free");
+  gpr_realloc_import = (gpr_realloc_type) GetProcAddress(library, "gpr_realloc");
+  gpr_malloc_aligned_import = (gpr_malloc_aligned_type) GetProcAddress(library, "gpr_malloc_aligned");
+  gpr_free_aligned_import = (gpr_free_aligned_type) GetProcAddress(library, "gpr_free_aligned");
+  gpr_set_allocation_functions_import = (gpr_set_allocation_functions_type) GetProcAddress(library, "gpr_set_allocation_functions");
+  gpr_get_allocation_functions_import = (gpr_get_allocation_functions_type) GetProcAddress(library, "gpr_get_allocation_functions");
+  grpc_raw_byte_buffer_create_import = (grpc_raw_byte_buffer_create_type) GetProcAddress(library, "grpc_raw_byte_buffer_create");
+  grpc_raw_compressed_byte_buffer_create_import = (grpc_raw_compressed_byte_buffer_create_type) GetProcAddress(library, "grpc_raw_compressed_byte_buffer_create");
+  grpc_byte_buffer_copy_import = (grpc_byte_buffer_copy_type) GetProcAddress(library, "grpc_byte_buffer_copy");
+  grpc_byte_buffer_length_import = (grpc_byte_buffer_length_type) GetProcAddress(library, "grpc_byte_buffer_length");
+  grpc_byte_buffer_destroy_import = (grpc_byte_buffer_destroy_type) GetProcAddress(library, "grpc_byte_buffer_destroy");
+  grpc_byte_buffer_reader_init_import = (grpc_byte_buffer_reader_init_type) GetProcAddress(library, "grpc_byte_buffer_reader_init");
+  grpc_byte_buffer_reader_destroy_import = (grpc_byte_buffer_reader_destroy_type) GetProcAddress(library, "grpc_byte_buffer_reader_destroy");
+  grpc_byte_buffer_reader_next_import = (grpc_byte_buffer_reader_next_type) GetProcAddress(library, "grpc_byte_buffer_reader_next");
+  grpc_byte_buffer_reader_readall_import = (grpc_byte_buffer_reader_readall_type) GetProcAddress(library, "grpc_byte_buffer_reader_readall");
+  grpc_raw_byte_buffer_from_reader_import = (grpc_raw_byte_buffer_from_reader_type) GetProcAddress(library, "grpc_raw_byte_buffer_from_reader");
+  gpr_log_import = (gpr_log_type) GetProcAddress(library, "gpr_log");
+  gpr_log_message_import = (gpr_log_message_type) GetProcAddress(library, "gpr_log_message");
+  gpr_set_log_function_import = (gpr_set_log_function_type) GetProcAddress(library, "gpr_set_log_function");
+  gpr_slice_ref_import = (gpr_slice_ref_type) GetProcAddress(library, "gpr_slice_ref");
+  gpr_slice_unref_import = (gpr_slice_unref_type) GetProcAddress(library, "gpr_slice_unref");
+  gpr_slice_new_import = (gpr_slice_new_type) GetProcAddress(library, "gpr_slice_new");
+  gpr_slice_new_with_len_import = (gpr_slice_new_with_len_type) GetProcAddress(library, "gpr_slice_new_with_len");
+  gpr_slice_malloc_import = (gpr_slice_malloc_type) GetProcAddress(library, "gpr_slice_malloc");
+  gpr_slice_from_copied_string_import = (gpr_slice_from_copied_string_type) GetProcAddress(library, "gpr_slice_from_copied_string");
+  gpr_slice_from_copied_buffer_import = (gpr_slice_from_copied_buffer_type) GetProcAddress(library, "gpr_slice_from_copied_buffer");
+  gpr_slice_from_static_string_import = (gpr_slice_from_static_string_type) GetProcAddress(library, "gpr_slice_from_static_string");
+  gpr_slice_sub_import = (gpr_slice_sub_type) GetProcAddress(library, "gpr_slice_sub");
+  gpr_slice_sub_no_ref_import = (gpr_slice_sub_no_ref_type) GetProcAddress(library, "gpr_slice_sub_no_ref");
+  gpr_slice_split_tail_import = (gpr_slice_split_tail_type) GetProcAddress(library, "gpr_slice_split_tail");
+  gpr_slice_split_head_import = (gpr_slice_split_head_type) GetProcAddress(library, "gpr_slice_split_head");
+  gpr_empty_slice_import = (gpr_empty_slice_type) GetProcAddress(library, "gpr_empty_slice");
+  gpr_slice_cmp_import = (gpr_slice_cmp_type) GetProcAddress(library, "gpr_slice_cmp");
+  gpr_slice_str_cmp_import = (gpr_slice_str_cmp_type) GetProcAddress(library, "gpr_slice_str_cmp");
+  gpr_slice_buffer_init_import = (gpr_slice_buffer_init_type) GetProcAddress(library, "gpr_slice_buffer_init");
+  gpr_slice_buffer_destroy_import = (gpr_slice_buffer_destroy_type) GetProcAddress(library, "gpr_slice_buffer_destroy");
+  gpr_slice_buffer_add_import = (gpr_slice_buffer_add_type) GetProcAddress(library, "gpr_slice_buffer_add");
+  gpr_slice_buffer_add_indexed_import = (gpr_slice_buffer_add_indexed_type) GetProcAddress(library, "gpr_slice_buffer_add_indexed");
+  gpr_slice_buffer_addn_import = (gpr_slice_buffer_addn_type) GetProcAddress(library, "gpr_slice_buffer_addn");
+  gpr_slice_buffer_tiny_add_import = (gpr_slice_buffer_tiny_add_type) GetProcAddress(library, "gpr_slice_buffer_tiny_add");
+  gpr_slice_buffer_pop_import = (gpr_slice_buffer_pop_type) GetProcAddress(library, "gpr_slice_buffer_pop");
+  gpr_slice_buffer_reset_and_unref_import = (gpr_slice_buffer_reset_and_unref_type) GetProcAddress(library, "gpr_slice_buffer_reset_and_unref");
+  gpr_slice_buffer_swap_import = (gpr_slice_buffer_swap_type) GetProcAddress(library, "gpr_slice_buffer_swap");
+  gpr_slice_buffer_move_into_import = (gpr_slice_buffer_move_into_type) GetProcAddress(library, "gpr_slice_buffer_move_into");
+  gpr_slice_buffer_trim_end_import = (gpr_slice_buffer_trim_end_type) GetProcAddress(library, "gpr_slice_buffer_trim_end");
+  gpr_slice_buffer_move_first_import = (gpr_slice_buffer_move_first_type) GetProcAddress(library, "gpr_slice_buffer_move_first");
+  gpr_slice_buffer_take_first_import = (gpr_slice_buffer_take_first_type) GetProcAddress(library, "gpr_slice_buffer_take_first");
+  gpr_mu_init_import = (gpr_mu_init_type) GetProcAddress(library, "gpr_mu_init");
+  gpr_mu_destroy_import = (gpr_mu_destroy_type) GetProcAddress(library, "gpr_mu_destroy");
+  gpr_mu_lock_import = (gpr_mu_lock_type) GetProcAddress(library, "gpr_mu_lock");
+  gpr_mu_unlock_import = (gpr_mu_unlock_type) GetProcAddress(library, "gpr_mu_unlock");
+  gpr_mu_trylock_import = (gpr_mu_trylock_type) GetProcAddress(library, "gpr_mu_trylock");
+  gpr_cv_init_import = (gpr_cv_init_type) GetProcAddress(library, "gpr_cv_init");
+  gpr_cv_destroy_import = (gpr_cv_destroy_type) GetProcAddress(library, "gpr_cv_destroy");
+  gpr_cv_wait_import = (gpr_cv_wait_type) GetProcAddress(library, "gpr_cv_wait");
+  gpr_cv_signal_import = (gpr_cv_signal_type) GetProcAddress(library, "gpr_cv_signal");
+  gpr_cv_broadcast_import = (gpr_cv_broadcast_type) GetProcAddress(library, "gpr_cv_broadcast");
+  gpr_once_init_import = (gpr_once_init_type) GetProcAddress(library, "gpr_once_init");
+  gpr_event_init_import = (gpr_event_init_type) GetProcAddress(library, "gpr_event_init");
+  gpr_event_set_import = (gpr_event_set_type) GetProcAddress(library, "gpr_event_set");
+  gpr_event_get_import = (gpr_event_get_type) GetProcAddress(library, "gpr_event_get");
+  gpr_event_wait_import = (gpr_event_wait_type) GetProcAddress(library, "gpr_event_wait");
+  gpr_ref_init_import = (gpr_ref_init_type) GetProcAddress(library, "gpr_ref_init");
+  gpr_ref_import = (gpr_ref_type) GetProcAddress(library, "gpr_ref");
+  gpr_refn_import = (gpr_refn_type) GetProcAddress(library, "gpr_refn");
+  gpr_unref_import = (gpr_unref_type) GetProcAddress(library, "gpr_unref");
+  gpr_stats_init_import = (gpr_stats_init_type) GetProcAddress(library, "gpr_stats_init");
+  gpr_stats_inc_import = (gpr_stats_inc_type) GetProcAddress(library, "gpr_stats_inc");
+  gpr_stats_read_import = (gpr_stats_read_type) GetProcAddress(library, "gpr_stats_read");
+  gpr_time_0_import = (gpr_time_0_type) GetProcAddress(library, "gpr_time_0");
+  gpr_inf_future_import = (gpr_inf_future_type) GetProcAddress(library, "gpr_inf_future");
+  gpr_inf_past_import = (gpr_inf_past_type) GetProcAddress(library, "gpr_inf_past");
+  gpr_time_init_import = (gpr_time_init_type) GetProcAddress(library, "gpr_time_init");
+  gpr_now_import = (gpr_now_type) GetProcAddress(library, "gpr_now");
+  gpr_convert_clock_type_import = (gpr_convert_clock_type_type) GetProcAddress(library, "gpr_convert_clock_type");
+  gpr_time_cmp_import = (gpr_time_cmp_type) GetProcAddress(library, "gpr_time_cmp");
+  gpr_time_max_import = (gpr_time_max_type) GetProcAddress(library, "gpr_time_max");
+  gpr_time_min_import = (gpr_time_min_type) GetProcAddress(library, "gpr_time_min");
+  gpr_time_add_import = (gpr_time_add_type) GetProcAddress(library, "gpr_time_add");
+  gpr_time_sub_import = (gpr_time_sub_type) GetProcAddress(library, "gpr_time_sub");
+  gpr_time_from_micros_import = (gpr_time_from_micros_type) GetProcAddress(library, "gpr_time_from_micros");
+  gpr_time_from_nanos_import = (gpr_time_from_nanos_type) GetProcAddress(library, "gpr_time_from_nanos");
+  gpr_time_from_millis_import = (gpr_time_from_millis_type) GetProcAddress(library, "gpr_time_from_millis");
+  gpr_time_from_seconds_import = (gpr_time_from_seconds_type) GetProcAddress(library, "gpr_time_from_seconds");
+  gpr_time_from_minutes_import = (gpr_time_from_minutes_type) GetProcAddress(library, "gpr_time_from_minutes");
+  gpr_time_from_hours_import = (gpr_time_from_hours_type) GetProcAddress(library, "gpr_time_from_hours");
+  gpr_time_to_millis_import = (gpr_time_to_millis_type) GetProcAddress(library, "gpr_time_to_millis");
+  gpr_time_similar_import = (gpr_time_similar_type) GetProcAddress(library, "gpr_time_similar");
+  gpr_sleep_until_import = (gpr_sleep_until_type) GetProcAddress(library, "gpr_sleep_until");
+  gpr_timespec_to_micros_import = (gpr_timespec_to_micros_type) GetProcAddress(library, "gpr_timespec_to_micros");
+  gpr_avl_create_import = (gpr_avl_create_type) GetProcAddress(library, "gpr_avl_create");
+  gpr_avl_ref_import = (gpr_avl_ref_type) GetProcAddress(library, "gpr_avl_ref");
+  gpr_avl_unref_import = (gpr_avl_unref_type) GetProcAddress(library, "gpr_avl_unref");
+  gpr_avl_add_import = (gpr_avl_add_type) GetProcAddress(library, "gpr_avl_add");
+  gpr_avl_remove_import = (gpr_avl_remove_type) GetProcAddress(library, "gpr_avl_remove");
+  gpr_avl_get_import = (gpr_avl_get_type) GetProcAddress(library, "gpr_avl_get");
+  gpr_cmdline_create_import = (gpr_cmdline_create_type) GetProcAddress(library, "gpr_cmdline_create");
+  gpr_cmdline_add_int_import = (gpr_cmdline_add_int_type) GetProcAddress(library, "gpr_cmdline_add_int");
+  gpr_cmdline_add_flag_import = (gpr_cmdline_add_flag_type) GetProcAddress(library, "gpr_cmdline_add_flag");
+  gpr_cmdline_add_string_import = (gpr_cmdline_add_string_type) GetProcAddress(library, "gpr_cmdline_add_string");
+  gpr_cmdline_on_extra_arg_import = (gpr_cmdline_on_extra_arg_type) GetProcAddress(library, "gpr_cmdline_on_extra_arg");
+  gpr_cmdline_set_survive_failure_import = (gpr_cmdline_set_survive_failure_type) GetProcAddress(library, "gpr_cmdline_set_survive_failure");
+  gpr_cmdline_parse_import = (gpr_cmdline_parse_type) GetProcAddress(library, "gpr_cmdline_parse");
+  gpr_cmdline_destroy_import = (gpr_cmdline_destroy_type) GetProcAddress(library, "gpr_cmdline_destroy");
+  gpr_cmdline_usage_string_import = (gpr_cmdline_usage_string_type) GetProcAddress(library, "gpr_cmdline_usage_string");
+  gpr_cpu_num_cores_import = (gpr_cpu_num_cores_type) GetProcAddress(library, "gpr_cpu_num_cores");
+  gpr_cpu_current_cpu_import = (gpr_cpu_current_cpu_type) GetProcAddress(library, "gpr_cpu_current_cpu");
+  gpr_histogram_create_import = (gpr_histogram_create_type) GetProcAddress(library, "gpr_histogram_create");
+  gpr_histogram_destroy_import = (gpr_histogram_destroy_type) GetProcAddress(library, "gpr_histogram_destroy");
+  gpr_histogram_add_import = (gpr_histogram_add_type) GetProcAddress(library, "gpr_histogram_add");
+  gpr_histogram_merge_import = (gpr_histogram_merge_type) GetProcAddress(library, "gpr_histogram_merge");
+  gpr_histogram_percentile_import = (gpr_histogram_percentile_type) GetProcAddress(library, "gpr_histogram_percentile");
+  gpr_histogram_mean_import = (gpr_histogram_mean_type) GetProcAddress(library, "gpr_histogram_mean");
+  gpr_histogram_stddev_import = (gpr_histogram_stddev_type) GetProcAddress(library, "gpr_histogram_stddev");
+  gpr_histogram_variance_import = (gpr_histogram_variance_type) GetProcAddress(library, "gpr_histogram_variance");
+  gpr_histogram_maximum_import = (gpr_histogram_maximum_type) GetProcAddress(library, "gpr_histogram_maximum");
+  gpr_histogram_minimum_import = (gpr_histogram_minimum_type) GetProcAddress(library, "gpr_histogram_minimum");
+  gpr_histogram_count_import = (gpr_histogram_count_type) GetProcAddress(library, "gpr_histogram_count");
+  gpr_histogram_sum_import = (gpr_histogram_sum_type) GetProcAddress(library, "gpr_histogram_sum");
+  gpr_histogram_sum_of_squares_import = (gpr_histogram_sum_of_squares_type) GetProcAddress(library, "gpr_histogram_sum_of_squares");
+  gpr_histogram_get_contents_import = (gpr_histogram_get_contents_type) GetProcAddress(library, "gpr_histogram_get_contents");
+  gpr_histogram_merge_contents_import = (gpr_histogram_merge_contents_type) GetProcAddress(library, "gpr_histogram_merge_contents");
+  gpr_join_host_port_import = (gpr_join_host_port_type) GetProcAddress(library, "gpr_join_host_port");
+  gpr_split_host_port_import = (gpr_split_host_port_type) GetProcAddress(library, "gpr_split_host_port");
+  gpr_format_message_import = (gpr_format_message_type) GetProcAddress(library, "gpr_format_message");
+  gpr_strdup_import = (gpr_strdup_type) GetProcAddress(library, "gpr_strdup");
+  gpr_asprintf_import = (gpr_asprintf_type) GetProcAddress(library, "gpr_asprintf");
+  gpr_subprocess_binary_extension_import = (gpr_subprocess_binary_extension_type) GetProcAddress(library, "gpr_subprocess_binary_extension");
+  gpr_subprocess_create_import = (gpr_subprocess_create_type) GetProcAddress(library, "gpr_subprocess_create");
+  gpr_subprocess_destroy_import = (gpr_subprocess_destroy_type) GetProcAddress(library, "gpr_subprocess_destroy");
+  gpr_subprocess_join_import = (gpr_subprocess_join_type) GetProcAddress(library, "gpr_subprocess_join");
+  gpr_subprocess_interrupt_import = (gpr_subprocess_interrupt_type) GetProcAddress(library, "gpr_subprocess_interrupt");
+  gpr_thd_new_import = (gpr_thd_new_type) GetProcAddress(library, "gpr_thd_new");
+  gpr_thd_options_default_import = (gpr_thd_options_default_type) GetProcAddress(library, "gpr_thd_options_default");
+  gpr_thd_options_set_detached_import = (gpr_thd_options_set_detached_type) GetProcAddress(library, "gpr_thd_options_set_detached");
+  gpr_thd_options_set_joinable_import = (gpr_thd_options_set_joinable_type) GetProcAddress(library, "gpr_thd_options_set_joinable");
+  gpr_thd_options_is_detached_import = (gpr_thd_options_is_detached_type) GetProcAddress(library, "gpr_thd_options_is_detached");
+  gpr_thd_options_is_joinable_import = (gpr_thd_options_is_joinable_type) GetProcAddress(library, "gpr_thd_options_is_joinable");
+  gpr_thd_currentid_import = (gpr_thd_currentid_type) GetProcAddress(library, "gpr_thd_currentid");
+  gpr_thd_join_import = (gpr_thd_join_type) GetProcAddress(library, "gpr_thd_join");
+}
+
+#endif /* GPR_WIN32 */
diff --git a/src/ruby/ext/grpc/rb_grpc_imports.generated.h b/src/ruby/ext/grpc/rb_grpc_imports.generated.h
new file mode 100644
index 0000000..618ae5e
--- /dev/null
+++ b/src/ruby/ext/grpc/rb_grpc_imports.generated.h
@@ -0,0 +1,843 @@
+/*
+ *
+ * Copyright 2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef GRPC_RB_GRPC_IMPORTS_H_
+#define GRPC_RB_GRPC_IMPORTS_H_
+
+#include <grpc/support/port_platform.h>
+
+#ifdef GPR_WIN32
+
+#include <windows.h>
+
+#include <grpc/census.h>
+#include <grpc/compression.h>
+#include <grpc/grpc.h>
+#include <grpc/grpc_security.h>
+#include <grpc/impl/codegen/alloc.h>
+#include <grpc/impl/codegen/byte_buffer.h>
+#include <grpc/impl/codegen/log.h>
+#include <grpc/impl/codegen/slice.h>
+#include <grpc/impl/codegen/slice_buffer.h>
+#include <grpc/impl/codegen/sync.h>
+#include <grpc/impl/codegen/time.h>
+#include <grpc/support/avl.h>
+#include <grpc/support/cmdline.h>
+#include <grpc/support/cpu.h>
+#include <grpc/support/histogram.h>
+#include <grpc/support/host_port.h>
+#include <grpc/support/log_win32.h>
+#include <grpc/support/string_util.h>
+#include <grpc/support/subprocess.h>
+#include <grpc/support/thd.h>
+
+typedef int(*census_initialize_type)(int features);
+extern census_initialize_type census_initialize_import;
+#define census_initialize census_initialize_import
+typedef void(*census_shutdown_type)(void);
+extern census_shutdown_type census_shutdown_import;
+#define census_shutdown census_shutdown_import
+typedef int(*census_supported_type)(void);
+extern census_supported_type census_supported_import;
+#define census_supported census_supported_import
+typedef int(*census_enabled_type)(void);
+extern census_enabled_type census_enabled_import;
+#define census_enabled census_enabled_import
+typedef census_context *(*census_context_create_type)(const census_context *base, const census_tag *tags, int ntags, census_context_status const **status);
+extern census_context_create_type census_context_create_import;
+#define census_context_create census_context_create_import
+typedef void(*census_context_destroy_type)(census_context *context);
+extern census_context_destroy_type census_context_destroy_import;
+#define census_context_destroy census_context_destroy_import
+typedef const census_context_status *(*census_context_get_status_type)(const census_context *context);
+extern census_context_get_status_type census_context_get_status_import;
+#define census_context_get_status census_context_get_status_import
+typedef void(*census_context_initialize_iterator_type)(const census_context *context, census_context_iterator *iterator);
+extern census_context_initialize_iterator_type census_context_initialize_iterator_import;
+#define census_context_initialize_iterator census_context_initialize_iterator_import
+typedef int(*census_context_next_tag_type)(census_context_iterator *iterator, census_tag *tag);
+extern census_context_next_tag_type census_context_next_tag_import;
+#define census_context_next_tag census_context_next_tag_import
+typedef int(*census_context_get_tag_type)(const census_context *context, const char *key, census_tag *tag);
+extern census_context_get_tag_type census_context_get_tag_import;
+#define census_context_get_tag census_context_get_tag_import
+typedef char *(*census_context_encode_type)(const census_context *context, char *buffer, size_t buf_size, size_t *print_buf_size, size_t *bin_buf_size);
+extern census_context_encode_type census_context_encode_import;
+#define census_context_encode census_context_encode_import
+typedef census_context *(*census_context_decode_type)(const char *buffer, size_t size, const char *bin_buffer, size_t bin_size);
+extern census_context_decode_type census_context_decode_import;
+#define census_context_decode census_context_decode_import
+typedef int(*census_trace_mask_type)(const census_context *context);
+extern census_trace_mask_type census_trace_mask_import;
+#define census_trace_mask census_trace_mask_import
+typedef void(*census_set_trace_mask_type)(int trace_mask);
+extern census_set_trace_mask_type census_set_trace_mask_import;
+#define census_set_trace_mask census_set_trace_mask_import
+typedef census_timestamp(*census_start_rpc_op_timestamp_type)(void);
+extern census_start_rpc_op_timestamp_type census_start_rpc_op_timestamp_import;
+#define census_start_rpc_op_timestamp census_start_rpc_op_timestamp_import
+typedef census_context *(*census_start_client_rpc_op_type)(const census_context *context, int64_t rpc_name_id, const census_rpc_name_info *rpc_name_info, const char *peer, int trace_mask, const census_timestamp *start_time);
+extern census_start_client_rpc_op_type census_start_client_rpc_op_import;
+#define census_start_client_rpc_op census_start_client_rpc_op_import
+typedef void(*census_set_rpc_client_peer_type)(census_context *context, const char *peer);
+extern census_set_rpc_client_peer_type census_set_rpc_client_peer_import;
+#define census_set_rpc_client_peer census_set_rpc_client_peer_import
+typedef census_context *(*census_start_server_rpc_op_type)(const char *buffer, int64_t rpc_name_id, const census_rpc_name_info *rpc_name_info, const char *peer, int trace_mask, census_timestamp *start_time);
+extern census_start_server_rpc_op_type census_start_server_rpc_op_import;
+#define census_start_server_rpc_op census_start_server_rpc_op_import
+typedef census_context *(*census_start_op_type)(census_context *context, const char *family, const char *name, int trace_mask);
+extern census_start_op_type census_start_op_import;
+#define census_start_op census_start_op_import
+typedef void(*census_end_op_type)(census_context *context, int status);
+extern census_end_op_type census_end_op_import;
+#define census_end_op census_end_op_import
+typedef void(*census_trace_print_type)(census_context *context, uint32_t type, const char *buffer, size_t n);
+extern census_trace_print_type census_trace_print_import;
+#define census_trace_print census_trace_print_import
+typedef int(*census_trace_scan_start_type)(int consume);
+extern census_trace_scan_start_type census_trace_scan_start_import;
+#define census_trace_scan_start census_trace_scan_start_import
+typedef int(*census_get_trace_record_type)(census_trace_record *trace_record);
+extern census_get_trace_record_type census_get_trace_record_import;
+#define census_get_trace_record census_get_trace_record_import
+typedef void(*census_trace_scan_end_type)();
+extern census_trace_scan_end_type census_trace_scan_end_import;
+#define census_trace_scan_end census_trace_scan_end_import
+typedef void(*census_record_values_type)(census_context *context, census_value *values, size_t nvalues);
+extern census_record_values_type census_record_values_import;
+#define census_record_values census_record_values_import
+typedef census_view *(*census_view_create_type)(uint32_t metric_id, const census_context *tags, const census_aggregation *aggregations, size_t naggregations);
+extern census_view_create_type census_view_create_import;
+#define census_view_create census_view_create_import
+typedef void(*census_view_delete_type)(census_view *view);
+extern census_view_delete_type census_view_delete_import;
+#define census_view_delete census_view_delete_import
+typedef size_t(*census_view_metric_type)(const census_view *view);
+extern census_view_metric_type census_view_metric_import;
+#define census_view_metric census_view_metric_import
+typedef size_t(*census_view_naggregations_type)(const census_view *view);
+extern census_view_naggregations_type census_view_naggregations_import;
+#define census_view_naggregations census_view_naggregations_import
+typedef const census_context *(*census_view_tags_type)(const census_view *view);
+extern census_view_tags_type census_view_tags_import;
+#define census_view_tags census_view_tags_import
+typedef const census_aggregation *(*census_view_aggregrations_type)(const census_view *view);
+extern census_view_aggregrations_type census_view_aggregrations_import;
+#define census_view_aggregrations census_view_aggregrations_import
+typedef const census_view_data *(*census_view_get_data_type)(const census_view *view);
+extern census_view_get_data_type census_view_get_data_import;
+#define census_view_get_data census_view_get_data_import
+typedef void(*census_view_reset_type)(census_view *view);
+extern census_view_reset_type census_view_reset_import;
+#define census_view_reset census_view_reset_import
+typedef int(*grpc_compression_algorithm_parse_type)(const char *name, size_t name_length, grpc_compression_algorithm *algorithm);
+extern grpc_compression_algorithm_parse_type grpc_compression_algorithm_parse_import;
+#define grpc_compression_algorithm_parse grpc_compression_algorithm_parse_import
+typedef int(*grpc_compression_algorithm_name_type)(grpc_compression_algorithm algorithm, char **name);
+extern grpc_compression_algorithm_name_type grpc_compression_algorithm_name_import;
+#define grpc_compression_algorithm_name grpc_compression_algorithm_name_import
+typedef grpc_compression_algorithm(*grpc_compression_algorithm_for_level_type)(grpc_compression_level level);
+extern grpc_compression_algorithm_for_level_type grpc_compression_algorithm_for_level_import;
+#define grpc_compression_algorithm_for_level grpc_compression_algorithm_for_level_import
+typedef void(*grpc_compression_options_init_type)(grpc_compression_options *opts);
+extern grpc_compression_options_init_type grpc_compression_options_init_import;
+#define grpc_compression_options_init grpc_compression_options_init_import
+typedef void(*grpc_compression_options_enable_algorithm_type)(grpc_compression_options *opts, grpc_compression_algorithm algorithm);
+extern grpc_compression_options_enable_algorithm_type grpc_compression_options_enable_algorithm_import;
+#define grpc_compression_options_enable_algorithm grpc_compression_options_enable_algorithm_import
+typedef void(*grpc_compression_options_disable_algorithm_type)(grpc_compression_options *opts, grpc_compression_algorithm algorithm);
+extern grpc_compression_options_disable_algorithm_type grpc_compression_options_disable_algorithm_import;
+#define grpc_compression_options_disable_algorithm grpc_compression_options_disable_algorithm_import
+typedef int(*grpc_compression_options_is_algorithm_enabled_type)(const grpc_compression_options *opts, grpc_compression_algorithm algorithm);
+extern grpc_compression_options_is_algorithm_enabled_type grpc_compression_options_is_algorithm_enabled_import;
+#define grpc_compression_options_is_algorithm_enabled grpc_compression_options_is_algorithm_enabled_import
+typedef void(*grpc_metadata_array_init_type)(grpc_metadata_array *array);
+extern grpc_metadata_array_init_type grpc_metadata_array_init_import;
+#define grpc_metadata_array_init grpc_metadata_array_init_import
+typedef void(*grpc_metadata_array_destroy_type)(grpc_metadata_array *array);
+extern grpc_metadata_array_destroy_type grpc_metadata_array_destroy_import;
+#define grpc_metadata_array_destroy grpc_metadata_array_destroy_import
+typedef void(*grpc_call_details_init_type)(grpc_call_details *details);
+extern grpc_call_details_init_type grpc_call_details_init_import;
+#define grpc_call_details_init grpc_call_details_init_import
+typedef void(*grpc_call_details_destroy_type)(grpc_call_details *details);
+extern grpc_call_details_destroy_type grpc_call_details_destroy_import;
+#define grpc_call_details_destroy grpc_call_details_destroy_import
+typedef void(*grpc_register_plugin_type)(void (*init)(void), void (*destroy)(void));
+extern grpc_register_plugin_type grpc_register_plugin_import;
+#define grpc_register_plugin grpc_register_plugin_import
+typedef void(*grpc_init_type)(void);
+extern grpc_init_type grpc_init_import;
+#define grpc_init grpc_init_import
+typedef void(*grpc_shutdown_type)(void);
+extern grpc_shutdown_type grpc_shutdown_import;
+#define grpc_shutdown grpc_shutdown_import
+typedef const char *(*grpc_version_string_type)(void);
+extern grpc_version_string_type grpc_version_string_import;
+#define grpc_version_string grpc_version_string_import
+typedef grpc_completion_queue *(*grpc_completion_queue_create_type)(void *reserved);
+extern grpc_completion_queue_create_type grpc_completion_queue_create_import;
+#define grpc_completion_queue_create grpc_completion_queue_create_import
+typedef grpc_event(*grpc_completion_queue_next_type)(grpc_completion_queue *cq, gpr_timespec deadline, void *reserved);
+extern grpc_completion_queue_next_type grpc_completion_queue_next_import;
+#define grpc_completion_queue_next grpc_completion_queue_next_import
+typedef grpc_event(*grpc_completion_queue_pluck_type)(grpc_completion_queue *cq, void *tag, gpr_timespec deadline, void *reserved);
+extern grpc_completion_queue_pluck_type grpc_completion_queue_pluck_import;
+#define grpc_completion_queue_pluck grpc_completion_queue_pluck_import
+typedef void(*grpc_completion_queue_shutdown_type)(grpc_completion_queue *cq);
+extern grpc_completion_queue_shutdown_type grpc_completion_queue_shutdown_import;
+#define grpc_completion_queue_shutdown grpc_completion_queue_shutdown_import
+typedef void(*grpc_completion_queue_destroy_type)(grpc_completion_queue *cq);
+extern grpc_completion_queue_destroy_type grpc_completion_queue_destroy_import;
+#define grpc_completion_queue_destroy grpc_completion_queue_destroy_import
+typedef grpc_alarm *(*grpc_alarm_create_type)(grpc_completion_queue *cq, gpr_timespec deadline, void *tag);
+extern grpc_alarm_create_type grpc_alarm_create_import;
+#define grpc_alarm_create grpc_alarm_create_import
+typedef void(*grpc_alarm_cancel_type)(grpc_alarm *alarm);
+extern grpc_alarm_cancel_type grpc_alarm_cancel_import;
+#define grpc_alarm_cancel grpc_alarm_cancel_import
+typedef void(*grpc_alarm_destroy_type)(grpc_alarm *alarm);
+extern grpc_alarm_destroy_type grpc_alarm_destroy_import;
+#define grpc_alarm_destroy grpc_alarm_destroy_import
+typedef grpc_connectivity_state(*grpc_channel_check_connectivity_state_type)(grpc_channel *channel, int try_to_connect);
+extern grpc_channel_check_connectivity_state_type grpc_channel_check_connectivity_state_import;
+#define grpc_channel_check_connectivity_state grpc_channel_check_connectivity_state_import
+typedef void(*grpc_channel_watch_connectivity_state_type)(grpc_channel *channel, grpc_connectivity_state last_observed_state, gpr_timespec deadline, grpc_completion_queue *cq, void *tag);
+extern grpc_channel_watch_connectivity_state_type grpc_channel_watch_connectivity_state_import;
+#define grpc_channel_watch_connectivity_state grpc_channel_watch_connectivity_state_import
+typedef grpc_call *(*grpc_channel_create_call_type)(grpc_channel *channel, grpc_call *parent_call, uint32_t propagation_mask, grpc_completion_queue *completion_queue, const char *method, const char *host, gpr_timespec deadline, void *reserved);
+extern grpc_channel_create_call_type grpc_channel_create_call_import;
+#define grpc_channel_create_call grpc_channel_create_call_import
+typedef void(*grpc_channel_ping_type)(grpc_channel *channel, grpc_completion_queue *cq, void *tag, void *reserved);
+extern grpc_channel_ping_type grpc_channel_ping_import;
+#define grpc_channel_ping grpc_channel_ping_import
+typedef void *(*grpc_channel_register_call_type)(grpc_channel *channel, const char *method, const char *host, void *reserved);
+extern grpc_channel_register_call_type grpc_channel_register_call_import;
+#define grpc_channel_register_call grpc_channel_register_call_import
+typedef grpc_call *(*grpc_channel_create_registered_call_type)(grpc_channel *channel, grpc_call *parent_call, uint32_t propagation_mask, grpc_completion_queue *completion_queue, void *registered_call_handle, gpr_timespec deadline, void *reserved);
+extern grpc_channel_create_registered_call_type grpc_channel_create_registered_call_import;
+#define grpc_channel_create_registered_call grpc_channel_create_registered_call_import
+typedef grpc_call_error(*grpc_call_start_batch_type)(grpc_call *call, const grpc_op *ops, size_t nops, void *tag, void *reserved);
+extern grpc_call_start_batch_type grpc_call_start_batch_import;
+#define grpc_call_start_batch grpc_call_start_batch_import
+typedef char *(*grpc_call_get_peer_type)(grpc_call *call);
+extern grpc_call_get_peer_type grpc_call_get_peer_import;
+#define grpc_call_get_peer grpc_call_get_peer_import
+typedef void(*grpc_census_call_set_context_type)(grpc_call *call, struct census_context *context);
+extern grpc_census_call_set_context_type grpc_census_call_set_context_import;
+#define grpc_census_call_set_context grpc_census_call_set_context_import
+typedef struct census_context *(*grpc_census_call_get_context_type)(grpc_call *call);
+extern grpc_census_call_get_context_type grpc_census_call_get_context_import;
+#define grpc_census_call_get_context grpc_census_call_get_context_import
+typedef char *(*grpc_channel_get_target_type)(grpc_channel *channel);
+extern grpc_channel_get_target_type grpc_channel_get_target_import;
+#define grpc_channel_get_target grpc_channel_get_target_import
+typedef grpc_channel *(*grpc_insecure_channel_create_type)(const char *target, const grpc_channel_args *args, void *reserved);
+extern grpc_insecure_channel_create_type grpc_insecure_channel_create_import;
+#define grpc_insecure_channel_create grpc_insecure_channel_create_import
+typedef grpc_channel *(*grpc_lame_client_channel_create_type)(const char *target, grpc_status_code error_code, const char *error_message);
+extern grpc_lame_client_channel_create_type grpc_lame_client_channel_create_import;
+#define grpc_lame_client_channel_create grpc_lame_client_channel_create_import
+typedef void(*grpc_channel_destroy_type)(grpc_channel *channel);
+extern grpc_channel_destroy_type grpc_channel_destroy_import;
+#define grpc_channel_destroy grpc_channel_destroy_import
+typedef grpc_call_error(*grpc_call_cancel_type)(grpc_call *call, void *reserved);
+extern grpc_call_cancel_type grpc_call_cancel_import;
+#define grpc_call_cancel grpc_call_cancel_import
+typedef grpc_call_error(*grpc_call_cancel_with_status_type)(grpc_call *call, grpc_status_code status, const char *description, void *reserved);
+extern grpc_call_cancel_with_status_type grpc_call_cancel_with_status_import;
+#define grpc_call_cancel_with_status grpc_call_cancel_with_status_import
+typedef void(*grpc_call_destroy_type)(grpc_call *call);
+extern grpc_call_destroy_type grpc_call_destroy_import;
+#define grpc_call_destroy grpc_call_destroy_import
+typedef grpc_call_error(*grpc_server_request_call_type)(grpc_server *server, grpc_call **call, grpc_call_details *details, grpc_metadata_array *request_metadata, grpc_completion_queue *cq_bound_to_call, grpc_completion_queue *cq_for_notification, void *tag_new);
+extern grpc_server_request_call_type grpc_server_request_call_import;
+#define grpc_server_request_call grpc_server_request_call_import
+typedef void *(*grpc_server_register_method_type)(grpc_server *server, const char *method, const char *host);
+extern grpc_server_register_method_type grpc_server_register_method_import;
+#define grpc_server_register_method grpc_server_register_method_import
+typedef grpc_call_error(*grpc_server_request_registered_call_type)(grpc_server *server, void *registered_method, grpc_call **call, gpr_timespec *deadline, grpc_metadata_array *request_metadata, grpc_byte_buffer **optional_payload, grpc_completion_queue *cq_bound_to_call, grpc_completion_queue *cq_for_notification, void *tag_new);
+extern grpc_server_request_registered_call_type grpc_server_request_registered_call_import;
+#define grpc_server_request_registered_call grpc_server_request_registered_call_import
+typedef grpc_server *(*grpc_server_create_type)(const grpc_channel_args *args, void *reserved);
+extern grpc_server_create_type grpc_server_create_import;
+#define grpc_server_create grpc_server_create_import
+typedef void(*grpc_server_register_completion_queue_type)(grpc_server *server, grpc_completion_queue *cq, void *reserved);
+extern grpc_server_register_completion_queue_type grpc_server_register_completion_queue_import;
+#define grpc_server_register_completion_queue grpc_server_register_completion_queue_import
+typedef int(*grpc_server_add_insecure_http2_port_type)(grpc_server *server, const char *addr);
+extern grpc_server_add_insecure_http2_port_type grpc_server_add_insecure_http2_port_import;
+#define grpc_server_add_insecure_http2_port grpc_server_add_insecure_http2_port_import
+typedef void(*grpc_server_start_type)(grpc_server *server);
+extern grpc_server_start_type grpc_server_start_import;
+#define grpc_server_start grpc_server_start_import
+typedef void(*grpc_server_shutdown_and_notify_type)(grpc_server *server, grpc_completion_queue *cq, void *tag);
+extern grpc_server_shutdown_and_notify_type grpc_server_shutdown_and_notify_import;
+#define grpc_server_shutdown_and_notify grpc_server_shutdown_and_notify_import
+typedef void(*grpc_server_cancel_all_calls_type)(grpc_server *server);
+extern grpc_server_cancel_all_calls_type grpc_server_cancel_all_calls_import;
+#define grpc_server_cancel_all_calls grpc_server_cancel_all_calls_import
+typedef void(*grpc_server_destroy_type)(grpc_server *server);
+extern grpc_server_destroy_type grpc_server_destroy_import;
+#define grpc_server_destroy grpc_server_destroy_import
+typedef int(*grpc_tracer_set_enabled_type)(const char *name, int enabled);
+extern grpc_tracer_set_enabled_type grpc_tracer_set_enabled_import;
+#define grpc_tracer_set_enabled grpc_tracer_set_enabled_import
+typedef int(*grpc_header_key_is_legal_type)(const char *key, size_t length);
+extern grpc_header_key_is_legal_type grpc_header_key_is_legal_import;
+#define grpc_header_key_is_legal grpc_header_key_is_legal_import
+typedef int(*grpc_header_nonbin_value_is_legal_type)(const char *value, size_t length);
+extern grpc_header_nonbin_value_is_legal_type grpc_header_nonbin_value_is_legal_import;
+#define grpc_header_nonbin_value_is_legal grpc_header_nonbin_value_is_legal_import
+typedef int(*grpc_is_binary_header_type)(const char *key, size_t length);
+extern grpc_is_binary_header_type grpc_is_binary_header_import;
+#define grpc_is_binary_header grpc_is_binary_header_import
+typedef const grpc_auth_property *(*grpc_auth_property_iterator_next_type)(grpc_auth_property_iterator *it);
+extern grpc_auth_property_iterator_next_type grpc_auth_property_iterator_next_import;
+#define grpc_auth_property_iterator_next grpc_auth_property_iterator_next_import
+typedef grpc_auth_property_iterator(*grpc_auth_context_property_iterator_type)(const grpc_auth_context *ctx);
+extern grpc_auth_context_property_iterator_type grpc_auth_context_property_iterator_import;
+#define grpc_auth_context_property_iterator grpc_auth_context_property_iterator_import
+typedef grpc_auth_property_iterator(*grpc_auth_context_peer_identity_type)(const grpc_auth_context *ctx);
+extern grpc_auth_context_peer_identity_type grpc_auth_context_peer_identity_import;
+#define grpc_auth_context_peer_identity grpc_auth_context_peer_identity_import
+typedef grpc_auth_property_iterator(*grpc_auth_context_find_properties_by_name_type)(const grpc_auth_context *ctx, const char *name);
+extern grpc_auth_context_find_properties_by_name_type grpc_auth_context_find_properties_by_name_import;
+#define grpc_auth_context_find_properties_by_name grpc_auth_context_find_properties_by_name_import
+typedef const char *(*grpc_auth_context_peer_identity_property_name_type)(const grpc_auth_context *ctx);
+extern grpc_auth_context_peer_identity_property_name_type grpc_auth_context_peer_identity_property_name_import;
+#define grpc_auth_context_peer_identity_property_name grpc_auth_context_peer_identity_property_name_import
+typedef int(*grpc_auth_context_peer_is_authenticated_type)(const grpc_auth_context *ctx);
+extern grpc_auth_context_peer_is_authenticated_type grpc_auth_context_peer_is_authenticated_import;
+#define grpc_auth_context_peer_is_authenticated grpc_auth_context_peer_is_authenticated_import
+typedef grpc_auth_context *(*grpc_call_auth_context_type)(grpc_call *call);
+extern grpc_call_auth_context_type grpc_call_auth_context_import;
+#define grpc_call_auth_context grpc_call_auth_context_import
+typedef void(*grpc_auth_context_release_type)(grpc_auth_context *context);
+extern grpc_auth_context_release_type grpc_auth_context_release_import;
+#define grpc_auth_context_release grpc_auth_context_release_import
+typedef void(*grpc_auth_context_add_property_type)(grpc_auth_context *ctx, const char *name, const char *value, size_t value_length);
+extern grpc_auth_context_add_property_type grpc_auth_context_add_property_import;
+#define grpc_auth_context_add_property grpc_auth_context_add_property_import
+typedef void(*grpc_auth_context_add_cstring_property_type)(grpc_auth_context *ctx, const char *name, const char *value);
+extern grpc_auth_context_add_cstring_property_type grpc_auth_context_add_cstring_property_import;
+#define grpc_auth_context_add_cstring_property grpc_auth_context_add_cstring_property_import
+typedef int(*grpc_auth_context_set_peer_identity_property_name_type)(grpc_auth_context *ctx, const char *name);
+extern grpc_auth_context_set_peer_identity_property_name_type grpc_auth_context_set_peer_identity_property_name_import;
+#define grpc_auth_context_set_peer_identity_property_name grpc_auth_context_set_peer_identity_property_name_import
+typedef void(*grpc_channel_credentials_release_type)(grpc_channel_credentials *creds);
+extern grpc_channel_credentials_release_type grpc_channel_credentials_release_import;
+#define grpc_channel_credentials_release grpc_channel_credentials_release_import
+typedef grpc_channel_credentials *(*grpc_google_default_credentials_create_type)(void);
+extern grpc_google_default_credentials_create_type grpc_google_default_credentials_create_import;
+#define grpc_google_default_credentials_create grpc_google_default_credentials_create_import
+typedef grpc_channel_credentials *(*grpc_ssl_credentials_create_type)(const char *pem_root_certs, grpc_ssl_pem_key_cert_pair *pem_key_cert_pair, void *reserved);
+extern grpc_ssl_credentials_create_type grpc_ssl_credentials_create_import;
+#define grpc_ssl_credentials_create grpc_ssl_credentials_create_import
+typedef void(*grpc_call_credentials_release_type)(grpc_call_credentials *creds);
+extern grpc_call_credentials_release_type grpc_call_credentials_release_import;
+#define grpc_call_credentials_release grpc_call_credentials_release_import
+typedef grpc_channel_credentials *(*grpc_composite_channel_credentials_create_type)(grpc_channel_credentials *channel_creds, grpc_call_credentials *call_creds, void *reserved);
+extern grpc_composite_channel_credentials_create_type grpc_composite_channel_credentials_create_import;
+#define grpc_composite_channel_credentials_create grpc_composite_channel_credentials_create_import
+typedef grpc_call_credentials *(*grpc_composite_call_credentials_create_type)(grpc_call_credentials *creds1, grpc_call_credentials *creds2, void *reserved);
+extern grpc_composite_call_credentials_create_type grpc_composite_call_credentials_create_import;
+#define grpc_composite_call_credentials_create grpc_composite_call_credentials_create_import
+typedef grpc_call_credentials *(*grpc_google_compute_engine_credentials_create_type)(void *reserved);
+extern grpc_google_compute_engine_credentials_create_type grpc_google_compute_engine_credentials_create_import;
+#define grpc_google_compute_engine_credentials_create grpc_google_compute_engine_credentials_create_import
+typedef gpr_timespec(*grpc_max_auth_token_lifetime_type)();
+extern grpc_max_auth_token_lifetime_type grpc_max_auth_token_lifetime_import;
+#define grpc_max_auth_token_lifetime grpc_max_auth_token_lifetime_import
+typedef grpc_call_credentials *(*grpc_service_account_jwt_access_credentials_create_type)(const char *json_key, gpr_timespec token_lifetime, void *reserved);
+extern grpc_service_account_jwt_access_credentials_create_type grpc_service_account_jwt_access_credentials_create_import;
+#define grpc_service_account_jwt_access_credentials_create grpc_service_account_jwt_access_credentials_create_import
+typedef grpc_call_credentials *(*grpc_google_refresh_token_credentials_create_type)(const char *json_refresh_token, void *reserved);
+extern grpc_google_refresh_token_credentials_create_type grpc_google_refresh_token_credentials_create_import;
+#define grpc_google_refresh_token_credentials_create grpc_google_refresh_token_credentials_create_import
+typedef grpc_call_credentials *(*grpc_access_token_credentials_create_type)(const char *access_token, void *reserved);
+extern grpc_access_token_credentials_create_type grpc_access_token_credentials_create_import;
+#define grpc_access_token_credentials_create grpc_access_token_credentials_create_import
+typedef grpc_call_credentials *(*grpc_google_iam_credentials_create_type)(const char *authorization_token, const char *authority_selector, void *reserved);
+extern grpc_google_iam_credentials_create_type grpc_google_iam_credentials_create_import;
+#define grpc_google_iam_credentials_create grpc_google_iam_credentials_create_import
+typedef grpc_call_credentials *(*grpc_metadata_credentials_create_from_plugin_type)(grpc_metadata_credentials_plugin plugin, void *reserved);
+extern grpc_metadata_credentials_create_from_plugin_type grpc_metadata_credentials_create_from_plugin_import;
+#define grpc_metadata_credentials_create_from_plugin grpc_metadata_credentials_create_from_plugin_import
+typedef grpc_channel *(*grpc_secure_channel_create_type)(grpc_channel_credentials *creds, const char *target, const grpc_channel_args *args, void *reserved);
+extern grpc_secure_channel_create_type grpc_secure_channel_create_import;
+#define grpc_secure_channel_create grpc_secure_channel_create_import
+typedef void(*grpc_server_credentials_release_type)(grpc_server_credentials *creds);
+extern grpc_server_credentials_release_type grpc_server_credentials_release_import;
+#define grpc_server_credentials_release grpc_server_credentials_release_import
+typedef grpc_server_credentials *(*grpc_ssl_server_credentials_create_type)(const char *pem_root_certs, grpc_ssl_pem_key_cert_pair *pem_key_cert_pairs, size_t num_key_cert_pairs, int force_client_auth, void *reserved);
+extern grpc_ssl_server_credentials_create_type grpc_ssl_server_credentials_create_import;
+#define grpc_ssl_server_credentials_create grpc_ssl_server_credentials_create_import
+typedef int(*grpc_server_add_secure_http2_port_type)(grpc_server *server, const char *addr, grpc_server_credentials *creds);
+extern grpc_server_add_secure_http2_port_type grpc_server_add_secure_http2_port_import;
+#define grpc_server_add_secure_http2_port grpc_server_add_secure_http2_port_import
+typedef grpc_call_error(*grpc_call_set_credentials_type)(grpc_call *call, grpc_call_credentials *creds);
+extern grpc_call_set_credentials_type grpc_call_set_credentials_import;
+#define grpc_call_set_credentials grpc_call_set_credentials_import
+typedef void(*grpc_server_credentials_set_auth_metadata_processor_type)(grpc_server_credentials *creds, grpc_auth_metadata_processor processor);
+extern grpc_server_credentials_set_auth_metadata_processor_type grpc_server_credentials_set_auth_metadata_processor_import;
+#define grpc_server_credentials_set_auth_metadata_processor grpc_server_credentials_set_auth_metadata_processor_import
+typedef void *(*gpr_malloc_type)(size_t size);
+extern gpr_malloc_type gpr_malloc_import;
+#define gpr_malloc gpr_malloc_import
+typedef void(*gpr_free_type)(void *ptr);
+extern gpr_free_type gpr_free_import;
+#define gpr_free gpr_free_import
+typedef void *(*gpr_realloc_type)(void *p, size_t size);
+extern gpr_realloc_type gpr_realloc_import;
+#define gpr_realloc gpr_realloc_import
+typedef void *(*gpr_malloc_aligned_type)(size_t size, size_t alignment_log);
+extern gpr_malloc_aligned_type gpr_malloc_aligned_import;
+#define gpr_malloc_aligned gpr_malloc_aligned_import
+typedef void(*gpr_free_aligned_type)(void *ptr);
+extern gpr_free_aligned_type gpr_free_aligned_import;
+#define gpr_free_aligned gpr_free_aligned_import
+typedef void(*gpr_set_allocation_functions_type)(gpr_allocation_functions functions);
+extern gpr_set_allocation_functions_type gpr_set_allocation_functions_import;
+#define gpr_set_allocation_functions gpr_set_allocation_functions_import
+typedef gpr_allocation_functions(*gpr_get_allocation_functions_type)();
+extern gpr_get_allocation_functions_type gpr_get_allocation_functions_import;
+#define gpr_get_allocation_functions gpr_get_allocation_functions_import
+typedef grpc_byte_buffer *(*grpc_raw_byte_buffer_create_type)(gpr_slice *slices, size_t nslices);
+extern grpc_raw_byte_buffer_create_type grpc_raw_byte_buffer_create_import;
+#define grpc_raw_byte_buffer_create grpc_raw_byte_buffer_create_import
+typedef grpc_byte_buffer *(*grpc_raw_compressed_byte_buffer_create_type)(gpr_slice *slices, size_t nslices, grpc_compression_algorithm compression);
+extern grpc_raw_compressed_byte_buffer_create_type grpc_raw_compressed_byte_buffer_create_import;
+#define grpc_raw_compressed_byte_buffer_create grpc_raw_compressed_byte_buffer_create_import
+typedef grpc_byte_buffer *(*grpc_byte_buffer_copy_type)(grpc_byte_buffer *bb);
+extern grpc_byte_buffer_copy_type grpc_byte_buffer_copy_import;
+#define grpc_byte_buffer_copy grpc_byte_buffer_copy_import
+typedef size_t(*grpc_byte_buffer_length_type)(grpc_byte_buffer *bb);
+extern grpc_byte_buffer_length_type grpc_byte_buffer_length_import;
+#define grpc_byte_buffer_length grpc_byte_buffer_length_import
+typedef void(*grpc_byte_buffer_destroy_type)(grpc_byte_buffer *byte_buffer);
+extern grpc_byte_buffer_destroy_type grpc_byte_buffer_destroy_import;
+#define grpc_byte_buffer_destroy grpc_byte_buffer_destroy_import
+typedef void(*grpc_byte_buffer_reader_init_type)(grpc_byte_buffer_reader *reader, grpc_byte_buffer *buffer);
+extern grpc_byte_buffer_reader_init_type grpc_byte_buffer_reader_init_import;
+#define grpc_byte_buffer_reader_init grpc_byte_buffer_reader_init_import
+typedef void(*grpc_byte_buffer_reader_destroy_type)(grpc_byte_buffer_reader *reader);
+extern grpc_byte_buffer_reader_destroy_type grpc_byte_buffer_reader_destroy_import;
+#define grpc_byte_buffer_reader_destroy grpc_byte_buffer_reader_destroy_import
+typedef int(*grpc_byte_buffer_reader_next_type)(grpc_byte_buffer_reader *reader, gpr_slice *slice);
+extern grpc_byte_buffer_reader_next_type grpc_byte_buffer_reader_next_import;
+#define grpc_byte_buffer_reader_next grpc_byte_buffer_reader_next_import
+typedef gpr_slice(*grpc_byte_buffer_reader_readall_type)(grpc_byte_buffer_reader *reader);
+extern grpc_byte_buffer_reader_readall_type grpc_byte_buffer_reader_readall_import;
+#define grpc_byte_buffer_reader_readall grpc_byte_buffer_reader_readall_import
+typedef grpc_byte_buffer *(*grpc_raw_byte_buffer_from_reader_type)(grpc_byte_buffer_reader *reader);
+extern grpc_raw_byte_buffer_from_reader_type grpc_raw_byte_buffer_from_reader_import;
+#define grpc_raw_byte_buffer_from_reader grpc_raw_byte_buffer_from_reader_import
+typedef void(*gpr_log_type)(const char *file, int line, gpr_log_severity severity, const char *format, ...);
+extern gpr_log_type gpr_log_import;
+#define gpr_log gpr_log_import
+typedef void(*gpr_log_message_type)(const char *file, int line, gpr_log_severity severity, const char *message);
+extern gpr_log_message_type gpr_log_message_import;
+#define gpr_log_message gpr_log_message_import
+typedef void(*gpr_set_log_function_type)(gpr_log_func func);
+extern gpr_set_log_function_type gpr_set_log_function_import;
+#define gpr_set_log_function gpr_set_log_function_import
+typedef gpr_slice(*gpr_slice_ref_type)(gpr_slice s);
+extern gpr_slice_ref_type gpr_slice_ref_import;
+#define gpr_slice_ref gpr_slice_ref_import
+typedef void(*gpr_slice_unref_type)(gpr_slice s);
+extern gpr_slice_unref_type gpr_slice_unref_import;
+#define gpr_slice_unref gpr_slice_unref_import
+typedef gpr_slice(*gpr_slice_new_type)(void *p, size_t len, void (*destroy)(void *));
+extern gpr_slice_new_type gpr_slice_new_import;
+#define gpr_slice_new gpr_slice_new_import
+typedef gpr_slice(*gpr_slice_new_with_len_type)(void *p, size_t len, void (*destroy)(void *, size_t));
+extern gpr_slice_new_with_len_type gpr_slice_new_with_len_import;
+#define gpr_slice_new_with_len gpr_slice_new_with_len_import
+typedef gpr_slice(*gpr_slice_malloc_type)(size_t length);
+extern gpr_slice_malloc_type gpr_slice_malloc_import;
+#define gpr_slice_malloc gpr_slice_malloc_import
+typedef gpr_slice(*gpr_slice_from_copied_string_type)(const char *source);
+extern gpr_slice_from_copied_string_type gpr_slice_from_copied_string_import;
+#define gpr_slice_from_copied_string gpr_slice_from_copied_string_import
+typedef gpr_slice(*gpr_slice_from_copied_buffer_type)(const char *source, size_t len);
+extern gpr_slice_from_copied_buffer_type gpr_slice_from_copied_buffer_import;
+#define gpr_slice_from_copied_buffer gpr_slice_from_copied_buffer_import
+typedef gpr_slice(*gpr_slice_from_static_string_type)(const char *source);
+extern gpr_slice_from_static_string_type gpr_slice_from_static_string_import;
+#define gpr_slice_from_static_string gpr_slice_from_static_string_import
+typedef gpr_slice(*gpr_slice_sub_type)(gpr_slice s, size_t begin, size_t end);
+extern gpr_slice_sub_type gpr_slice_sub_import;
+#define gpr_slice_sub gpr_slice_sub_import
+typedef gpr_slice(*gpr_slice_sub_no_ref_type)(gpr_slice s, size_t begin, size_t end);
+extern gpr_slice_sub_no_ref_type gpr_slice_sub_no_ref_import;
+#define gpr_slice_sub_no_ref gpr_slice_sub_no_ref_import
+typedef gpr_slice(*gpr_slice_split_tail_type)(gpr_slice *s, size_t split);
+extern gpr_slice_split_tail_type gpr_slice_split_tail_import;
+#define gpr_slice_split_tail gpr_slice_split_tail_import
+typedef gpr_slice(*gpr_slice_split_head_type)(gpr_slice *s, size_t split);
+extern gpr_slice_split_head_type gpr_slice_split_head_import;
+#define gpr_slice_split_head gpr_slice_split_head_import
+typedef gpr_slice(*gpr_empty_slice_type)(void);
+extern gpr_empty_slice_type gpr_empty_slice_import;
+#define gpr_empty_slice gpr_empty_slice_import
+typedef int(*gpr_slice_cmp_type)(gpr_slice a, gpr_slice b);
+extern gpr_slice_cmp_type gpr_slice_cmp_import;
+#define gpr_slice_cmp gpr_slice_cmp_import
+typedef int(*gpr_slice_str_cmp_type)(gpr_slice a, const char *b);
+extern gpr_slice_str_cmp_type gpr_slice_str_cmp_import;
+#define gpr_slice_str_cmp gpr_slice_str_cmp_import
+typedef void(*gpr_slice_buffer_init_type)(gpr_slice_buffer *sb);
+extern gpr_slice_buffer_init_type gpr_slice_buffer_init_import;
+#define gpr_slice_buffer_init gpr_slice_buffer_init_import
+typedef void(*gpr_slice_buffer_destroy_type)(gpr_slice_buffer *sb);
+extern gpr_slice_buffer_destroy_type gpr_slice_buffer_destroy_import;
+#define gpr_slice_buffer_destroy gpr_slice_buffer_destroy_import
+typedef void(*gpr_slice_buffer_add_type)(gpr_slice_buffer *sb, gpr_slice slice);
+extern gpr_slice_buffer_add_type gpr_slice_buffer_add_import;
+#define gpr_slice_buffer_add gpr_slice_buffer_add_import
+typedef size_t(*gpr_slice_buffer_add_indexed_type)(gpr_slice_buffer *sb, gpr_slice slice);
+extern gpr_slice_buffer_add_indexed_type gpr_slice_buffer_add_indexed_import;
+#define gpr_slice_buffer_add_indexed gpr_slice_buffer_add_indexed_import
+typedef void(*gpr_slice_buffer_addn_type)(gpr_slice_buffer *sb, gpr_slice *slices, size_t n);
+extern gpr_slice_buffer_addn_type gpr_slice_buffer_addn_import;
+#define gpr_slice_buffer_addn gpr_slice_buffer_addn_import
+typedef uint8_t *(*gpr_slice_buffer_tiny_add_type)(gpr_slice_buffer *sb, size_t len);
+extern gpr_slice_buffer_tiny_add_type gpr_slice_buffer_tiny_add_import;
+#define gpr_slice_buffer_tiny_add gpr_slice_buffer_tiny_add_import
+typedef void(*gpr_slice_buffer_pop_type)(gpr_slice_buffer *sb);
+extern gpr_slice_buffer_pop_type gpr_slice_buffer_pop_import;
+#define gpr_slice_buffer_pop gpr_slice_buffer_pop_import
+typedef void(*gpr_slice_buffer_reset_and_unref_type)(gpr_slice_buffer *sb);
+extern gpr_slice_buffer_reset_and_unref_type gpr_slice_buffer_reset_and_unref_import;
+#define gpr_slice_buffer_reset_and_unref gpr_slice_buffer_reset_and_unref_import
+typedef void(*gpr_slice_buffer_swap_type)(gpr_slice_buffer *a, gpr_slice_buffer *b);
+extern gpr_slice_buffer_swap_type gpr_slice_buffer_swap_import;
+#define gpr_slice_buffer_swap gpr_slice_buffer_swap_import
+typedef void(*gpr_slice_buffer_move_into_type)(gpr_slice_buffer *src, gpr_slice_buffer *dst);
+extern gpr_slice_buffer_move_into_type gpr_slice_buffer_move_into_import;
+#define gpr_slice_buffer_move_into gpr_slice_buffer_move_into_import
+typedef void(*gpr_slice_buffer_trim_end_type)(gpr_slice_buffer *src, size_t n, gpr_slice_buffer *garbage);
+extern gpr_slice_buffer_trim_end_type gpr_slice_buffer_trim_end_import;
+#define gpr_slice_buffer_trim_end gpr_slice_buffer_trim_end_import
+typedef void(*gpr_slice_buffer_move_first_type)(gpr_slice_buffer *src, size_t n, gpr_slice_buffer *dst);
+extern gpr_slice_buffer_move_first_type gpr_slice_buffer_move_first_import;
+#define gpr_slice_buffer_move_first gpr_slice_buffer_move_first_import
+typedef gpr_slice(*gpr_slice_buffer_take_first_type)(gpr_slice_buffer *src);
+extern gpr_slice_buffer_take_first_type gpr_slice_buffer_take_first_import;
+#define gpr_slice_buffer_take_first gpr_slice_buffer_take_first_import
+typedef void(*gpr_mu_init_type)(gpr_mu *mu);
+extern gpr_mu_init_type gpr_mu_init_import;
+#define gpr_mu_init gpr_mu_init_import
+typedef void(*gpr_mu_destroy_type)(gpr_mu *mu);
+extern gpr_mu_destroy_type gpr_mu_destroy_import;
+#define gpr_mu_destroy gpr_mu_destroy_import
+typedef void(*gpr_mu_lock_type)(gpr_mu *mu);
+extern gpr_mu_lock_type gpr_mu_lock_import;
+#define gpr_mu_lock gpr_mu_lock_import
+typedef void(*gpr_mu_unlock_type)(gpr_mu *mu);
+extern gpr_mu_unlock_type gpr_mu_unlock_import;
+#define gpr_mu_unlock gpr_mu_unlock_import
+typedef int(*gpr_mu_trylock_type)(gpr_mu *mu);
+extern gpr_mu_trylock_type gpr_mu_trylock_import;
+#define gpr_mu_trylock gpr_mu_trylock_import
+typedef void(*gpr_cv_init_type)(gpr_cv *cv);
+extern gpr_cv_init_type gpr_cv_init_import;
+#define gpr_cv_init gpr_cv_init_import
+typedef void(*gpr_cv_destroy_type)(gpr_cv *cv);
+extern gpr_cv_destroy_type gpr_cv_destroy_import;
+#define gpr_cv_destroy gpr_cv_destroy_import
+typedef int(*gpr_cv_wait_type)(gpr_cv *cv, gpr_mu *mu, gpr_timespec abs_deadline);
+extern gpr_cv_wait_type gpr_cv_wait_import;
+#define gpr_cv_wait gpr_cv_wait_import
+typedef void(*gpr_cv_signal_type)(gpr_cv *cv);
+extern gpr_cv_signal_type gpr_cv_signal_import;
+#define gpr_cv_signal gpr_cv_signal_import
+typedef void(*gpr_cv_broadcast_type)(gpr_cv *cv);
+extern gpr_cv_broadcast_type gpr_cv_broadcast_import;
+#define gpr_cv_broadcast gpr_cv_broadcast_import
+typedef void(*gpr_once_init_type)(gpr_once *once, void (*init_routine)(void));
+extern gpr_once_init_type gpr_once_init_import;
+#define gpr_once_init gpr_once_init_import
+typedef void(*gpr_event_init_type)(gpr_event *ev);
+extern gpr_event_init_type gpr_event_init_import;
+#define gpr_event_init gpr_event_init_import
+typedef void(*gpr_event_set_type)(gpr_event *ev, void *value);
+extern gpr_event_set_type gpr_event_set_import;
+#define gpr_event_set gpr_event_set_import
+typedef void *(*gpr_event_get_type)(gpr_event *ev);
+extern gpr_event_get_type gpr_event_get_import;
+#define gpr_event_get gpr_event_get_import
+typedef void *(*gpr_event_wait_type)(gpr_event *ev, gpr_timespec abs_deadline);
+extern gpr_event_wait_type gpr_event_wait_import;
+#define gpr_event_wait gpr_event_wait_import
+typedef void(*gpr_ref_init_type)(gpr_refcount *r, int n);
+extern gpr_ref_init_type gpr_ref_init_import;
+#define gpr_ref_init gpr_ref_init_import
+typedef void(*gpr_ref_type)(gpr_refcount *r);
+extern gpr_ref_type gpr_ref_import;
+#define gpr_ref gpr_ref_import
+typedef void(*gpr_refn_type)(gpr_refcount *r, int n);
+extern gpr_refn_type gpr_refn_import;
+#define gpr_refn gpr_refn_import
+typedef int(*gpr_unref_type)(gpr_refcount *r);
+extern gpr_unref_type gpr_unref_import;
+#define gpr_unref gpr_unref_import
+typedef void(*gpr_stats_init_type)(gpr_stats_counter *c, intptr_t n);
+extern gpr_stats_init_type gpr_stats_init_import;
+#define gpr_stats_init gpr_stats_init_import
+typedef void(*gpr_stats_inc_type)(gpr_stats_counter *c, intptr_t inc);
+extern gpr_stats_inc_type gpr_stats_inc_import;
+#define gpr_stats_inc gpr_stats_inc_import
+typedef intptr_t(*gpr_stats_read_type)(const gpr_stats_counter *c);
+extern gpr_stats_read_type gpr_stats_read_import;
+#define gpr_stats_read gpr_stats_read_import
+typedef gpr_timespec(*gpr_time_0_type)(gpr_clock_type type);
+extern gpr_time_0_type gpr_time_0_import;
+#define gpr_time_0 gpr_time_0_import
+typedef gpr_timespec(*gpr_inf_future_type)(gpr_clock_type type);
+extern gpr_inf_future_type gpr_inf_future_import;
+#define gpr_inf_future gpr_inf_future_import
+typedef gpr_timespec(*gpr_inf_past_type)(gpr_clock_type type);
+extern gpr_inf_past_type gpr_inf_past_import;
+#define gpr_inf_past gpr_inf_past_import
+typedef void(*gpr_time_init_type)(void);
+extern gpr_time_init_type gpr_time_init_import;
+#define gpr_time_init gpr_time_init_import
+typedef gpr_timespec(*gpr_now_type)(gpr_clock_type clock);
+extern gpr_now_type gpr_now_import;
+#define gpr_now gpr_now_import
+typedef gpr_timespec(*gpr_convert_clock_type_type)(gpr_timespec t, gpr_clock_type target_clock);
+extern gpr_convert_clock_type_type gpr_convert_clock_type_import;
+#define gpr_convert_clock_type gpr_convert_clock_type_import
+typedef int(*gpr_time_cmp_type)(gpr_timespec a, gpr_timespec b);
+extern gpr_time_cmp_type gpr_time_cmp_import;
+#define gpr_time_cmp gpr_time_cmp_import
+typedef gpr_timespec(*gpr_time_max_type)(gpr_timespec a, gpr_timespec b);
+extern gpr_time_max_type gpr_time_max_import;
+#define gpr_time_max gpr_time_max_import
+typedef gpr_timespec(*gpr_time_min_type)(gpr_timespec a, gpr_timespec b);
+extern gpr_time_min_type gpr_time_min_import;
+#define gpr_time_min gpr_time_min_import
+typedef gpr_timespec(*gpr_time_add_type)(gpr_timespec a, gpr_timespec b);
+extern gpr_time_add_type gpr_time_add_import;
+#define gpr_time_add gpr_time_add_import
+typedef gpr_timespec(*gpr_time_sub_type)(gpr_timespec a, gpr_timespec b);
+extern gpr_time_sub_type gpr_time_sub_import;
+#define gpr_time_sub gpr_time_sub_import
+typedef gpr_timespec(*gpr_time_from_micros_type)(int64_t x, gpr_clock_type clock_type);
+extern gpr_time_from_micros_type gpr_time_from_micros_import;
+#define gpr_time_from_micros gpr_time_from_micros_import
+typedef gpr_timespec(*gpr_time_from_nanos_type)(int64_t x, gpr_clock_type clock_type);
+extern gpr_time_from_nanos_type gpr_time_from_nanos_import;
+#define gpr_time_from_nanos gpr_time_from_nanos_import
+typedef gpr_timespec(*gpr_time_from_millis_type)(int64_t x, gpr_clock_type clock_type);
+extern gpr_time_from_millis_type gpr_time_from_millis_import;
+#define gpr_time_from_millis gpr_time_from_millis_import
+typedef gpr_timespec(*gpr_time_from_seconds_type)(int64_t x, gpr_clock_type clock_type);
+extern gpr_time_from_seconds_type gpr_time_from_seconds_import;
+#define gpr_time_from_seconds gpr_time_from_seconds_import
+typedef gpr_timespec(*gpr_time_from_minutes_type)(int64_t x, gpr_clock_type clock_type);
+extern gpr_time_from_minutes_type gpr_time_from_minutes_import;
+#define gpr_time_from_minutes gpr_time_from_minutes_import
+typedef gpr_timespec(*gpr_time_from_hours_type)(int64_t x, gpr_clock_type clock_type);
+extern gpr_time_from_hours_type gpr_time_from_hours_import;
+#define gpr_time_from_hours gpr_time_from_hours_import
+typedef int32_t(*gpr_time_to_millis_type)(gpr_timespec timespec);
+extern gpr_time_to_millis_type gpr_time_to_millis_import;
+#define gpr_time_to_millis gpr_time_to_millis_import
+typedef int(*gpr_time_similar_type)(gpr_timespec a, gpr_timespec b, gpr_timespec threshold);
+extern gpr_time_similar_type gpr_time_similar_import;
+#define gpr_time_similar gpr_time_similar_import
+typedef void(*gpr_sleep_until_type)(gpr_timespec until);
+extern gpr_sleep_until_type gpr_sleep_until_import;
+#define gpr_sleep_until gpr_sleep_until_import
+typedef double(*gpr_timespec_to_micros_type)(gpr_timespec t);
+extern gpr_timespec_to_micros_type gpr_timespec_to_micros_import;
+#define gpr_timespec_to_micros gpr_timespec_to_micros_import
+typedef gpr_avl(*gpr_avl_create_type)(const gpr_avl_vtable *vtable);
+extern gpr_avl_create_type gpr_avl_create_import;
+#define gpr_avl_create gpr_avl_create_import
+typedef gpr_avl(*gpr_avl_ref_type)(gpr_avl avl);
+extern gpr_avl_ref_type gpr_avl_ref_import;
+#define gpr_avl_ref gpr_avl_ref_import
+typedef void(*gpr_avl_unref_type)(gpr_avl avl);
+extern gpr_avl_unref_type gpr_avl_unref_import;
+#define gpr_avl_unref gpr_avl_unref_import
+typedef gpr_avl(*gpr_avl_add_type)(gpr_avl avl, void *key, void *value);
+extern gpr_avl_add_type gpr_avl_add_import;
+#define gpr_avl_add gpr_avl_add_import
+typedef gpr_avl(*gpr_avl_remove_type)(gpr_avl avl, void *key);
+extern gpr_avl_remove_type gpr_avl_remove_import;
+#define gpr_avl_remove gpr_avl_remove_import
+typedef void *(*gpr_avl_get_type)(gpr_avl avl, void *key);
+extern gpr_avl_get_type gpr_avl_get_import;
+#define gpr_avl_get gpr_avl_get_import
+typedef gpr_cmdline *(*gpr_cmdline_create_type)(const char *description);
+extern gpr_cmdline_create_type gpr_cmdline_create_import;
+#define gpr_cmdline_create gpr_cmdline_create_import
+typedef void(*gpr_cmdline_add_int_type)(gpr_cmdline *cl, const char *name, const char *help, int *value);
+extern gpr_cmdline_add_int_type gpr_cmdline_add_int_import;
+#define gpr_cmdline_add_int gpr_cmdline_add_int_import
+typedef void(*gpr_cmdline_add_flag_type)(gpr_cmdline *cl, const char *name, const char *help, int *value);
+extern gpr_cmdline_add_flag_type gpr_cmdline_add_flag_import;
+#define gpr_cmdline_add_flag gpr_cmdline_add_flag_import
+typedef void(*gpr_cmdline_add_string_type)(gpr_cmdline *cl, const char *name, const char *help, char **value);
+extern gpr_cmdline_add_string_type gpr_cmdline_add_string_import;
+#define gpr_cmdline_add_string gpr_cmdline_add_string_import
+typedef void(*gpr_cmdline_on_extra_arg_type)(gpr_cmdline *cl, const char *name, const char *help, void (*on_extra_arg)(void *user_data, const char *arg), void *user_data);
+extern gpr_cmdline_on_extra_arg_type gpr_cmdline_on_extra_arg_import;
+#define gpr_cmdline_on_extra_arg gpr_cmdline_on_extra_arg_import
+typedef void(*gpr_cmdline_set_survive_failure_type)(gpr_cmdline *cl);
+extern gpr_cmdline_set_survive_failure_type gpr_cmdline_set_survive_failure_import;
+#define gpr_cmdline_set_survive_failure gpr_cmdline_set_survive_failure_import
+typedef int(*gpr_cmdline_parse_type)(gpr_cmdline *cl, int argc, char **argv);
+extern gpr_cmdline_parse_type gpr_cmdline_parse_import;
+#define gpr_cmdline_parse gpr_cmdline_parse_import
+typedef void(*gpr_cmdline_destroy_type)(gpr_cmdline *cl);
+extern gpr_cmdline_destroy_type gpr_cmdline_destroy_import;
+#define gpr_cmdline_destroy gpr_cmdline_destroy_import
+typedef char *(*gpr_cmdline_usage_string_type)(gpr_cmdline *cl, const char *argv0);
+extern gpr_cmdline_usage_string_type gpr_cmdline_usage_string_import;
+#define gpr_cmdline_usage_string gpr_cmdline_usage_string_import
+typedef unsigned(*gpr_cpu_num_cores_type)(void);
+extern gpr_cpu_num_cores_type gpr_cpu_num_cores_import;
+#define gpr_cpu_num_cores gpr_cpu_num_cores_import
+typedef unsigned(*gpr_cpu_current_cpu_type)(void);
+extern gpr_cpu_current_cpu_type gpr_cpu_current_cpu_import;
+#define gpr_cpu_current_cpu gpr_cpu_current_cpu_import
+typedef gpr_histogram *(*gpr_histogram_create_type)(double resolution, double max_bucket_start);
+extern gpr_histogram_create_type gpr_histogram_create_import;
+#define gpr_histogram_create gpr_histogram_create_import
+typedef void(*gpr_histogram_destroy_type)(gpr_histogram *h);
+extern gpr_histogram_destroy_type gpr_histogram_destroy_import;
+#define gpr_histogram_destroy gpr_histogram_destroy_import
+typedef void(*gpr_histogram_add_type)(gpr_histogram *h, double x);
+extern gpr_histogram_add_type gpr_histogram_add_import;
+#define gpr_histogram_add gpr_histogram_add_import
+typedef int(*gpr_histogram_merge_type)(gpr_histogram *dst, const gpr_histogram *src);
+extern gpr_histogram_merge_type gpr_histogram_merge_import;
+#define gpr_histogram_merge gpr_histogram_merge_import
+typedef double(*gpr_histogram_percentile_type)(gpr_histogram *histogram, double percentile);
+extern gpr_histogram_percentile_type gpr_histogram_percentile_import;
+#define gpr_histogram_percentile gpr_histogram_percentile_import
+typedef double(*gpr_histogram_mean_type)(gpr_histogram *histogram);
+extern gpr_histogram_mean_type gpr_histogram_mean_import;
+#define gpr_histogram_mean gpr_histogram_mean_import
+typedef double(*gpr_histogram_stddev_type)(gpr_histogram *histogram);
+extern gpr_histogram_stddev_type gpr_histogram_stddev_import;
+#define gpr_histogram_stddev gpr_histogram_stddev_import
+typedef double(*gpr_histogram_variance_type)(gpr_histogram *histogram);
+extern gpr_histogram_variance_type gpr_histogram_variance_import;
+#define gpr_histogram_variance gpr_histogram_variance_import
+typedef double(*gpr_histogram_maximum_type)(gpr_histogram *histogram);
+extern gpr_histogram_maximum_type gpr_histogram_maximum_import;
+#define gpr_histogram_maximum gpr_histogram_maximum_import
+typedef double(*gpr_histogram_minimum_type)(gpr_histogram *histogram);
+extern gpr_histogram_minimum_type gpr_histogram_minimum_import;
+#define gpr_histogram_minimum gpr_histogram_minimum_import
+typedef double(*gpr_histogram_count_type)(gpr_histogram *histogram);
+extern gpr_histogram_count_type gpr_histogram_count_import;
+#define gpr_histogram_count gpr_histogram_count_import
+typedef double(*gpr_histogram_sum_type)(gpr_histogram *histogram);
+extern gpr_histogram_sum_type gpr_histogram_sum_import;
+#define gpr_histogram_sum gpr_histogram_sum_import
+typedef double(*gpr_histogram_sum_of_squares_type)(gpr_histogram *histogram);
+extern gpr_histogram_sum_of_squares_type gpr_histogram_sum_of_squares_import;
+#define gpr_histogram_sum_of_squares gpr_histogram_sum_of_squares_import
+typedef const uint32_t *(*gpr_histogram_get_contents_type)(gpr_histogram *histogram, size_t *count);
+extern gpr_histogram_get_contents_type gpr_histogram_get_contents_import;
+#define gpr_histogram_get_contents gpr_histogram_get_contents_import
+typedef void(*gpr_histogram_merge_contents_type)(gpr_histogram *histogram, const uint32_t *data, size_t data_count, double min_seen, double max_seen, double sum, double sum_of_squares, double count);
+extern gpr_histogram_merge_contents_type gpr_histogram_merge_contents_import;
+#define gpr_histogram_merge_contents gpr_histogram_merge_contents_import
+typedef int(*gpr_join_host_port_type)(char **out, const char *host, int port);
+extern gpr_join_host_port_type gpr_join_host_port_import;
+#define gpr_join_host_port gpr_join_host_port_import
+typedef int(*gpr_split_host_port_type)(const char *name, char **host, char **port);
+extern gpr_split_host_port_type gpr_split_host_port_import;
+#define gpr_split_host_port gpr_split_host_port_import
+typedef char *(*gpr_format_message_type)(int messageid);
+extern gpr_format_message_type gpr_format_message_import;
+#define gpr_format_message gpr_format_message_import
+typedef char *(*gpr_strdup_type)(const char *src);
+extern gpr_strdup_type gpr_strdup_import;
+#define gpr_strdup gpr_strdup_import
+typedef int(*gpr_asprintf_type)(char **strp, const char *format, ...);
+extern gpr_asprintf_type gpr_asprintf_import;
+#define gpr_asprintf gpr_asprintf_import
+typedef const char *(*gpr_subprocess_binary_extension_type)();
+extern gpr_subprocess_binary_extension_type gpr_subprocess_binary_extension_import;
+#define gpr_subprocess_binary_extension gpr_subprocess_binary_extension_import
+typedef gpr_subprocess *(*gpr_subprocess_create_type)(int argc, const char **argv);
+extern gpr_subprocess_create_type gpr_subprocess_create_import;
+#define gpr_subprocess_create gpr_subprocess_create_import
+typedef void(*gpr_subprocess_destroy_type)(gpr_subprocess *p);
+extern gpr_subprocess_destroy_type gpr_subprocess_destroy_import;
+#define gpr_subprocess_destroy gpr_subprocess_destroy_import
+typedef int(*gpr_subprocess_join_type)(gpr_subprocess *p);
+extern gpr_subprocess_join_type gpr_subprocess_join_import;
+#define gpr_subprocess_join gpr_subprocess_join_import
+typedef void(*gpr_subprocess_interrupt_type)(gpr_subprocess *p);
+extern gpr_subprocess_interrupt_type gpr_subprocess_interrupt_import;
+#define gpr_subprocess_interrupt gpr_subprocess_interrupt_import
+typedef int(*gpr_thd_new_type)(gpr_thd_id *t, void (*thd_body)(void *arg), void *arg, const gpr_thd_options *options);
+extern gpr_thd_new_type gpr_thd_new_import;
+#define gpr_thd_new gpr_thd_new_import
+typedef gpr_thd_options(*gpr_thd_options_default_type)(void);
+extern gpr_thd_options_default_type gpr_thd_options_default_import;
+#define gpr_thd_options_default gpr_thd_options_default_import
+typedef void(*gpr_thd_options_set_detached_type)(gpr_thd_options *options);
+extern gpr_thd_options_set_detached_type gpr_thd_options_set_detached_import;
+#define gpr_thd_options_set_detached gpr_thd_options_set_detached_import
+typedef void(*gpr_thd_options_set_joinable_type)(gpr_thd_options *options);
+extern gpr_thd_options_set_joinable_type gpr_thd_options_set_joinable_import;
+#define gpr_thd_options_set_joinable gpr_thd_options_set_joinable_import
+typedef int(*gpr_thd_options_is_detached_type)(const gpr_thd_options *options);
+extern gpr_thd_options_is_detached_type gpr_thd_options_is_detached_import;
+#define gpr_thd_options_is_detached gpr_thd_options_is_detached_import
+typedef int(*gpr_thd_options_is_joinable_type)(const gpr_thd_options *options);
+extern gpr_thd_options_is_joinable_type gpr_thd_options_is_joinable_import;
+#define gpr_thd_options_is_joinable gpr_thd_options_is_joinable_import
+typedef gpr_thd_id(*gpr_thd_currentid_type)(void);
+extern gpr_thd_currentid_type gpr_thd_currentid_import;
+#define gpr_thd_currentid gpr_thd_currentid_import
+typedef void(*gpr_thd_join_type)(gpr_thd_id t);
+extern gpr_thd_join_type gpr_thd_join_import;
+#define gpr_thd_join gpr_thd_join_import
+
+void grpc_rb_load_imports(HMODULE library);
+
+#endif /* GPR_WIN32 */
+
+#endif
diff --git a/src/objective-c/GRPCClient/private/GRPCUnsecuredChannel.h b/src/ruby/ext/grpc/rb_loader.c
similarity index 65%
copy from src/objective-c/GRPCClient/private/GRPCUnsecuredChannel.h
copy to src/ruby/ext/grpc/rb_loader.c
index 8528be4..242535f 100644
--- a/src/objective-c/GRPCClient/private/GRPCUnsecuredChannel.h
+++ b/src/ruby/ext/grpc/rb_loader.c
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -31,8 +31,42 @@
  *
  */
 
-#import "GRPCChannel.h"
+#include "rb_grpc_imports.generated.h"
 
-@interface GRPCUnsecuredChannel : GRPCChannel
-- (instancetype)initWithHost:(NSString *)host NS_DESIGNATED_INITIALIZER;
-@end
+#if GPR_WIN32
+#include <tchar.h>
+
+int grpc_rb_load_core() {
+#if GPR_ARCH_64
+  TCHAR fname[] = _T("grpc_c.64.ruby");
+#else
+  TCHAR fname[] = _T("grpc_c.32.ruby");
+#endif
+  HMODULE module = GetModuleHandle(_T("grpc_c.so"));
+  TCHAR path[2048 + 32] = _T("");
+  LPTSTR seek_back = NULL;
+  GetModuleFileName(module, path, 2048);
+
+  seek_back = _tcsrchr(path, _T('\\'));
+
+  while (seek_back) {
+    HMODULE grpc_c;
+    _tcscpy(seek_back + 1, fname);
+    grpc_c = LoadLibrary(path);
+    if (grpc_c) {
+      grpc_rb_load_imports(grpc_c);
+      return 1;
+    } else {
+      *seek_back = _T('\0');
+      seek_back = _tcsrchr(path, _T('\\'));
+    }
+  }
+
+  return 0;
+}
+
+#else
+
+int grpc_rb_load_core() { return 1; }
+
+#endif
diff --git a/src/objective-c/GRPCClient/private/GRPCUnsecuredChannel.h b/src/ruby/ext/grpc/rb_loader.h
similarity index 86%
copy from src/objective-c/GRPCClient/private/GRPCUnsecuredChannel.h
copy to src/ruby/ext/grpc/rb_loader.h
index 8528be4..d0c1613 100644
--- a/src/objective-c/GRPCClient/private/GRPCUnsecuredChannel.h
+++ b/src/ruby/ext/grpc/rb_loader.h
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -31,8 +31,10 @@
  *
  */
 
-#import "GRPCChannel.h"
+#ifndef GRPC_RB_LOADER_H_
+#define GRPC_RB_LOADER_H_
 
-@interface GRPCUnsecuredChannel : GRPCChannel
-- (instancetype)initWithHost:(NSString *)host NS_DESIGNATED_INITIALIZER;
-@end
+/* Attempts to load the core if necessary, and return non-zero upon succes. */
+int grpc_rb_load_core();
+
+#endif /* GRPC_RB_BYTE_BUFFER_H_ */
diff --git a/src/ruby/ext/grpc/rb_server.c b/src/ruby/ext/grpc/rb_server.c
index ebdd7e1..37cc55a 100644
--- a/src/ruby/ext/grpc/rb_server.c
+++ b/src/ruby/ext/grpc/rb_server.c
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -31,6 +31,8 @@
  *
  */
 
+#include <ruby/ruby.h>
+#include "rb_grpc_imports.generated.h"
 #include "rb_server.h"
 
 #include <ruby/ruby.h>
diff --git a/src/ruby/ext/grpc/rb_server_credentials.c b/src/ruby/ext/grpc/rb_server_credentials.c
index de57585..4ea59b6 100644
--- a/src/ruby/ext/grpc/rb_server_credentials.c
+++ b/src/ruby/ext/grpc/rb_server_credentials.c
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -31,6 +31,8 @@
  *
  */
 
+#include <ruby/ruby.h>
+#include "rb_grpc_imports.generated.h"
 #include "rb_server_credentials.h"
 
 #include <ruby/ruby.h>
@@ -175,7 +177,7 @@
   VALUE key = Qnil;
   VALUE key_cert = Qnil;
   int auth_client = 0;
-  int num_key_certs = 0;
+  long num_key_certs = 0;
   int i;
 
   if (NIL_P(force_client_auth) ||
diff --git a/src/ruby/lib/grpc/generic/bidi_call.rb b/src/ruby/lib/grpc/generic/bidi_call.rb
index 6b9b785..213176b 100644
--- a/src/ruby/lib/grpc/generic/bidi_call.rb
+++ b/src/ruby/lib/grpc/generic/bidi_call.rb
@@ -1,4 +1,4 @@
-# Copyright 2015, Google Inc.
+# Copyright 2015-2016, Google Inc.
 # All rights reserved.
 #
 # Redistribution and use in source and binary forms, with or without
diff --git a/src/ruby/lib/grpc/generic/rpc_desc.rb b/src/ruby/lib/grpc/generic/rpc_desc.rb
index dd90d8d..526b2ba 100644
--- a/src/ruby/lib/grpc/generic/rpc_desc.rb
+++ b/src/ruby/lib/grpc/generic/rpc_desc.rb
@@ -1,4 +1,4 @@
-# Copyright 2015, Google Inc.
+# Copyright 2015-2016, Google Inc.
 # All rights reserved.
 #
 # Redistribution and use in source and binary forms, with or without
diff --git a/src/ruby/lib/grpc/generic/rpc_server.rb b/src/ruby/lib/grpc/generic/rpc_server.rb
index 410156f..ef2997c 100644
--- a/src/ruby/lib/grpc/generic/rpc_server.rb
+++ b/src/ruby/lib/grpc/generic/rpc_server.rb
@@ -1,4 +1,4 @@
-# Copyright 2015, Google Inc.
+# Copyright 2015-2016, Google Inc.
 # All rights reserved.
 #
 # Redistribution and use in source and binary forms, with or without
diff --git a/tools/run_tests/check_submodules.sh b/src/ruby/lib/grpc/grpc.rb
old mode 100755
new mode 100644
similarity index 66%
copy from tools/run_tests/check_submodules.sh
copy to src/ruby/lib/grpc/grpc.rb
index b4ca4fa..d8a4947
--- a/tools/run_tests/check_submodules.sh
+++ b/src/ruby/lib/grpc/grpc.rb
@@ -1,5 +1,3 @@
-#!/bin/sh
-
 # Copyright 2015-2016, Google Inc.
 # All rights reserved.
 #
@@ -29,26 +27,8 @@
 # (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 -e
-
-export TEST=true
-
-cd `dirname $0`/../..
-
-submodules=`mktemp /tmp/submXXXXXX`
-want_submodules=`mktemp /tmp/submXXXXXX`
-
-git submodule | awk '{ print $1 }' | sort > $submodules
-cat << EOF | awk '{ print $1 }' | sort > $want_submodules
- 9f897b25800d2f54f5c442ef01a60721aeca6d87 third_party/boringssl (version_for_cocoapods_1.0-67-g9f897b2)
- 05b155ff59114735ec8cd089f669c4c3d8f59029 third_party/gflags (v2.1.0-45-g05b155f)
- c99458533a9b4c743ed51537e25989ea55944908 third_party/googletest (release-1.7.0)
- d5fb408ddc281ffcadeb08699e65bb694656d0bd third_party/protobuf (v3.0.0-beta-2)
- 50893291621658f355bc5b4d450a8d06a563053d third_party/zlib (v1.2.8)
-EOF
-
-diff -u $submodules $want_submodules
-
-rm $submodules $want_submodules
-
+begin
+  require "grpc/#{RUBY_VERSION.sub(/\.\d$/, '')}/grpc_c"
+rescue LoadError
+  require 'grpc/grpc_c'
+end
diff --git a/src/ruby/lib/grpc/version.rb b/src/ruby/lib/grpc/version.rb
index 956e022..ef08761 100644
--- a/src/ruby/lib/grpc/version.rb
+++ b/src/ruby/lib/grpc/version.rb
@@ -29,5 +29,5 @@
 
 # GRPC contains the General RPC module.
 module GRPC
-  VERSION = '0.12.0'
+  VERSION = '0.14.0.dev'
 end
diff --git a/src/ruby/spec/client_server_spec.rb b/src/ruby/spec/client_server_spec.rb
index 594fda1..7ef5345 100644
--- a/src/ruby/spec/client_server_spec.rb
+++ b/src/ruby/spec/client_server_spec.rb
@@ -1,4 +1,4 @@
-# Copyright 2015, Google Inc.
+# Copyright 2015-2016, Google Inc.
 # All rights reserved.
 #
 # Redistribution and use in source and binary forms, with or without
@@ -198,6 +198,7 @@
     # confirm the client can receive the server response and status.
     client_ops = {
       CallOps::SEND_CLOSE_FROM_CLIENT => nil,
+      CallOps::RECV_INITIAL_METADATA => nil,
       CallOps::RECV_MESSAGE => nil,
       CallOps::RECV_STATUS_ON_CLIENT => nil
     }
diff --git a/src/zlib/gen_build_yaml.py b/src/zlib/gen_build_yaml.py
index 8d6064b..4bd5573 100755
--- a/src/zlib/gen_build_yaml.py
+++ b/src/zlib/gen_build_yaml.py
@@ -54,6 +54,7 @@
   out['libs'] = [{
       'name': 'z',
       'zlib': True,
+      'defaults': 'zlib',
       'build': 'private',
       'language': 'c',
       'secure': 'no',
diff --git a/templates/Makefile.template b/templates/Makefile.template
index 57a0815..218f492 100644
--- a/templates/Makefile.template
+++ b/templates/Makefile.template
@@ -57,9 +57,7 @@
 
   # Basic platform detection
   HOST_SYSTEM = $(shell uname | cut -f 1 -d_)
-  ifeq ($(SYSTEM),)
-  SYSTEM = $(HOST_SYSTEM)
-  endif
+  SYSTEM ?= $(HOST_SYSTEM)
   ifeq ($(SYSTEM),MSYS)
   SYSTEM = MINGW32
   endif
@@ -153,15 +151,21 @@
   LD = $(LD_$(CONFIG))
   endif
   LDXX ?= $(LDXX_$(CONFIG))
-  ifeq ($(origin AR), default)
-  AR = ar
-  endif
   ifeq ($(SYSTEM),Linux)
+  ifeq ($(origin AR), default)
+  AR = ar rcs
+  endif
   STRIP ?= strip --strip-unneeded
   else
   ifeq ($(SYSTEM),Darwin)
+  ifeq ($(origin AR), default)
+  AR = libtool -o
+  endif
   STRIP ?= strip -x
   else
+  ifeq ($(origin AR), default)
+  AR = ar rcs
+  endif
   STRIP ?= strip
   endif
   endif
@@ -209,9 +213,11 @@
   else
   CXXFLAGS += -std=c++0x
   endif
-  CFLAGS += -g -Wall -Wextra -Werror -Wno-long-long -Wno-unused-parameter
-  CXXFLAGS += -g -Wall -Wextra -Werror -Wno-long-long -Wno-unused-parameter
-  LDFLAGS += -g
+  % for arg in ['CFLAGS', 'CXXFLAGS', 'CPPFLAGS', 'LDFLAGS', 'DEFINES']:
+  %  if defaults.get('global', []).get(arg, None) is not None:
+  ${arg} += ${defaults.get('global').get(arg)}
+  %  endif
+  % endfor
 
   CPPFLAGS += $(CPPFLAGS_$(CONFIG))
   CFLAGS += $(CFLAGS_$(CONFIG))
@@ -251,12 +257,12 @@
   endif
 
   ifeq ($(SYSTEM),Linux)
-  LIBS = rt m pthread
+  LIBS = dl rt m pthread
   LDFLAGS += -pthread
   endif
 
   ifeq ($(SYSTEM),MINGW32)
-  LIBS = m pthread
+  LIBS = m pthread ws2_32
   LDFLAGS += -pthread
   endif
 
@@ -270,7 +276,7 @@
   Q = @
   endif
 
-  VERSION = ${settings.version.major}.${settings.version.minor}.${settings.version.micro}.${settings.version.build}
+  VERSION = ${settings.core_version}
 
   CPPFLAGS_NO_ARCH += $(addprefix -I, $(INCLUDES)) $(addprefix -D, $(DEFINES))
   CPPFLAGS += $(CPPFLAGS_NO_ARCH) $(ARCH_FLAGS)
@@ -311,26 +317,18 @@
   Libs: -L${'\$${libdir}'} $(PC_LIB),\
   Libs.private: $(PC_LIBS_PRIVATE)
 
-  # gpr .pc file
-  PC_NAME = gRPC Portable Runtime
-  PC_DESCRIPTION = gRPC Portable Runtime
-  PC_CFLAGS = -pthread
-  PC_REQUIRES_PRIVATE =
-  PC_LIBS_PRIVATE = -lpthread
-  PC_LIB = -lgpr
-  ifneq ($(SYSTEM),Darwin)
-  PC_LIBS_PRIVATE += -lrt
-  endif
-  GPR_PC_FILE := $(PC_TEMPLATE)
-
   ifeq ($(SYSTEM),MINGW32)
   SHARED_EXT = dll
-  endif
-  ifeq ($(SYSTEM),Darwin)
+  SHARED_PREFIX =
+  SHARED_VERSION = -${settings.core_version.major}
+  else ifeq ($(SYSTEM),Darwin)
   SHARED_EXT = dylib
-  endif
-  ifeq ($(SHARED_EXT),)
+  SHARED_PREFIX = lib
+  SHARED_VERSION =
+  else
   SHARED_EXT = so.$(VERSION)
+  SHARED_PREFIX = lib
+  SHARED_VERSION =
   endif
 
   ifeq ($(wildcard .git),)
@@ -352,20 +350,20 @@
   OPENSSL_LIBS = ssl crypto
   endif
 
-  OPENSSL_ALPN_CHECK_CMD = $(CC) $(CFLAGS) $(CPPFLAGS) -o $(TMPOUT) test/build/openssl-alpn.c $(addprefix -l, $(OPENSSL_LIBS)) $(LDFLAGS)
-  OPENSSL_NPN_CHECK_CMD = $(CC) $(CFLAGS) $(CPPFLAGS) -o $(TMPOUT) test/build/openssl-npn.c $(addprefix -l, $(OPENSSL_LIBS)) $(LDFLAGS)
-  ZLIB_CHECK_CMD = $(CC) $(CFLAGS) $(CPPFLAGS) -o $(TMPOUT) test/build/zlib.c -lz $(LDFLAGS)
-  PROTOBUF_CHECK_CMD = $(CXX) $(CXXFLAGS) $(CPPFLAGS) -o $(TMPOUT) test/build/protobuf.cc -lprotobuf $(LDFLAGS)
+  OPENSSL_ALPN_CHECK_CMD = $(CC) $(CPPFLAGS) $(CFLAGS) -o $(TMPOUT) test/build/openssl-alpn.c $(addprefix -l, $(OPENSSL_LIBS)) $(LDFLAGS)
+  OPENSSL_NPN_CHECK_CMD = $(CC) $(CPPFLAGS) $(CFLAGS) -o $(TMPOUT) test/build/openssl-npn.c $(addprefix -l, $(OPENSSL_LIBS)) $(LDFLAGS)
+  ZLIB_CHECK_CMD = $(CC) $(CPPFLAGS) $(CFLAGS) -o $(TMPOUT) test/build/zlib.c -lz $(LDFLAGS)
+  PROTOBUF_CHECK_CMD = $(CXX) $(CPPFLAGS) $(CXXFLAGS) -o $(TMPOUT) test/build/protobuf.cc -lprotobuf $(LDFLAGS)
 
   endif # HAS_PKG_CONFIG
 
-  PERFTOOLS_CHECK_CMD = $(CC) $(CFLAGS) $(CPPFLAGS) -o $(TMPOUT) test/build/perftools.c -lprofiler $(LDFLAGS)
+  PERFTOOLS_CHECK_CMD = $(CC) $(CPPFLAGS) $(CFLAGS) -o $(TMPOUT) test/build/perftools.c -lprofiler $(LDFLAGS)
 
   PROTOC_CHECK_CMD = which protoc > /dev/null
   PROTOC_CHECK_VERSION_CMD = protoc --version | grep -q libprotoc.3
   DTRACE_CHECK_CMD = which dtrace > /dev/null
-  SYSTEMTAP_HEADERS_CHECK_CMD = $(CC) $(CFLAGS) $(CPPFLAGS) -o $(TMPOUT) test/build/systemtap.c $(LDFLAGS)
-  ZOOKEEPER_CHECK_CMD = $(CC) $(CFLAGS) $(CPPFLAGS) -o $(TMPOUT) test/build/zookeeper.c $(LDFLAGS) -lzookeeper_mt
+  SYSTEMTAP_HEADERS_CHECK_CMD = $(CC) $(CPPFLAGS) $(CFLAGS) -o $(TMPOUT) test/build/systemtap.c $(LDFLAGS)
+  ZOOKEEPER_CHECK_CMD = $(CC) $(CPPFLAGS) $(CFLAGS) -o $(TMPOUT) test/build/zookeeper.c $(LDFLAGS) -lzookeeper_mt
 
   ifndef REQUIRE_CUSTOM_LIBRARIES_$(CONFIG)
   HAS_SYSTEM_PERFTOOLS ?= $(shell $(PERFTOOLS_CHECK_CMD) 2> /dev/null && echo true || echo false)
@@ -459,7 +457,7 @@
   HAS_EMBEDDED_PROTOBUF = true
   endif
 
-  PC_REQUIRES_GRPC = gpr
+  PC_REQUIRES_GRPC =
   PC_LIBS_GRPC =
 
   ifeq ($(HAS_SYSTEM_ZLIB),false)
@@ -476,6 +474,7 @@
   ifeq ($(EMBED_ZLIB),true)
   ZLIB_DEP = $(LIBDIR)/$(CONFIG)/libz.a
   ZLIB_MERGE_LIBS = $(LIBDIR)/$(CONFIG)/libz.a
+  ZLIB_MERGE_OBJS = $(LIBZ_OBJS)
   CPPFLAGS += -Ithird_party/zlib
   LDFLAGS += -L$(LIBDIR)/$(CONFIG)/zlib
   else
@@ -518,6 +517,7 @@
   ifeq ($(EMBED_OPENSSL),true)
   OPENSSL_DEP += $(LIBDIR)/$(CONFIG)/libboringssl.a
   OPENSSL_MERGE_LIBS += $(LIBDIR)/$(CONFIG)/libboringssl.a
+  OPENSSL_MERGE_OBJS += $(LIBBORINGSSL_OBJS)
   # need to prefix these to ensure overriding system libraries
   CPPFLAGS := -Ithird_party/boringssl/include $(CPPFLAGS)
   else # EMBED_OPENSSL=false
@@ -558,7 +558,7 @@
   PC_LIB = -lgrpc
   GRPC_PC_FILE := $(PC_TEMPLATE)
 
-  # gprc_unsecure .pc file
+  # grpc_unsecure .pc file
   PC_NAME = gRPC unsecure
   PC_DESCRIPTION = high performance general RPC framework without SSL
   PC_CFLAGS =
@@ -567,7 +567,7 @@
   PC_LIB = -lgrpc
   GRPC_UNSECURE_PC_FILE := $(PC_TEMPLATE)
 
-  # gprc_zookeeper .pc file
+  # grpc_zookeeper .pc file
   PC_NAME = gRPC zookeeper
   PC_DESCRIPTION = gRPC's zookeeper plugin
   PC_CFLAGS =
@@ -788,7 +788,7 @@
 
   static: static_c static_cxx
 
-  static_c: pc_c pc_c_unsecure cache.mk pc_gpr pc_c_zookeeper\
+  static_c: pc_c pc_c_unsecure cache.mk pc_c_zookeeper\
   % for lib in libs:
   % if lib.build == 'all' and lib.language == 'c' and not lib.get('external_deps', None):
    $(LIBDIR)/$(CONFIG)/lib${lib.name}.a\
@@ -797,7 +797,7 @@
    static_zookeeper_libs
 
 
-  static_cxx: pc_cxx pc_cxx_unsecure pc_gpr cache.mk \
+  static_cxx: pc_cxx pc_cxx_unsecure cache.mk \
   % for lib in libs:
   % if lib.build == 'all' and lib.language == 'c++':
    $(LIBDIR)/$(CONFIG)/lib${lib.name}.a\
@@ -807,10 +807,10 @@
 
   shared: shared_c shared_cxx
 
-  shared_c: pc_c pc_c_unsecure pc_gpr cache.mk pc_c_zookeeper\
+  shared_c: pc_c pc_c_unsecure cache.mk pc_c_zookeeper\
   % for lib in libs:
   % if lib.build == 'all' and lib.language == 'c' and not lib.get('external_deps', None):
-   $(LIBDIR)/$(CONFIG)/lib${lib.name}.$(SHARED_EXT)\
+   $(LIBDIR)/$(CONFIG)/$(SHARED_PREFIX)${lib.name}$(SHARED_VERSION).$(SHARED_EXT)\
   % endif
   % endfor
    shared_zookeeper_libs
@@ -818,7 +818,7 @@
   shared_cxx: pc_cxx pc_cxx_unsecure cache.mk\
   % for lib in libs:
   % if lib.build == 'all' and lib.language == 'c++':
-   $(LIBDIR)/$(CONFIG)/lib${lib.name}.$(SHARED_EXT)\
+   $(LIBDIR)/$(CONFIG)/$(SHARED_PREFIX)${lib.name}$(SHARED_VERSION).$(SHARED_EXT)\
   % endif
   % endfor
 
@@ -826,7 +826,7 @@
   shared_csharp: shared_c \
   % for lib in libs:
   % if lib.build == 'all' and lib.language == 'csharp':
-   $(LIBDIR)/$(CONFIG)/lib${lib.name}.$(SHARED_EXT)\
+   $(LIBDIR)/$(CONFIG)/$(SHARED_PREFIX)${lib.name}$(SHARED_VERSION).$(SHARED_EXT)\
   % endif
   % endfor
 
@@ -841,7 +841,7 @@
   shared_zookeeper_libs:\
   % for lib in libs:
   % if lib.build == 'all' and lib.language == 'c' and 'zookeeper' in lib.get('external_deps', []):
-   $(LIBDIR)/$(CONFIG)/lib${lib.name}.$(SHARED_EXT)\
+   $(LIBDIR)/$(CONFIG)/$(SHARED_PREFIX)${lib.name}$(SHARED_VERSION).$(SHARED_EXT)\
   % endif
   % endfor
 
@@ -866,8 +866,6 @@
   % endif
   % endfor
 
-  pc_gpr: $(LIBDIR)/$(CONFIG)/pkgconfig/gpr.pc
-
   pc_c: $(LIBDIR)/$(CONFIG)/pkgconfig/grpc.pc
 
   pc_c_unsecure: $(LIBDIR)/$(CONFIG)/pkgconfig/grpc_unsecure.pc
@@ -1087,8 +1085,8 @@
   % if lib.language == "c":
   % if lib.build == "all":
   % if not lib.get('external_deps', None):
-  	$(E) "[STRIP]   Stripping lib${lib.name}.so"
-  	$(Q) $(STRIP) $(LIBDIR)/$(CONFIG)/lib${lib.name}.$(SHARED_EXT)
+  	$(E) "[STRIP]   Stripping $(SHARED_PREFIX)${lib.name}$(SHARED_VERSION).$(SHARED_EXT)"
+  	$(Q) $(STRIP) $(LIBDIR)/$(CONFIG)/$(SHARED_PREFIX)${lib.name}$(SHARED_VERSION).$(SHARED_EXT)
   % endif
   % endif
   % endif
@@ -1098,8 +1096,8 @@
   % if lib.language == "c":
   % if lib.build == "all":
   % if 'zookeeper' in lib.get('external_deps', []):
-  	$(E) "[STRIP]   Stripping lib${lib.name}.so"
-  	$(Q) $(STRIP) $(LIBDIR)/$(CONFIG)/lib${lib.name}.$(SHARED_EXT)
+  	$(E) "[STRIP]   Stripping $(SHARED_PREFIX)${lib.name}$(SHARED_VERSION).$(SHARED_EXT)"
+  	$(Q) $(STRIP) $(LIBDIR)/$(CONFIG)/$(SHARED_PREFIX)${lib.name}$(SHARED_VERSION).$(SHARED_EXT)
   % endif
   % endif
   % endif
@@ -1112,8 +1110,8 @@
   % for lib in libs:
   % if lib.language == "c++":
   % if lib.build == "all":
-  	$(E) "[STRIP]   Stripping lib${lib.name}.so"
-  	$(Q) $(STRIP) $(LIBDIR)/$(CONFIG)/lib${lib.name}.$(SHARED_EXT)
+  	$(E) "[STRIP]   Stripping $(SHARED_PREFIX)${lib.name}$(SHARED_VERSION).$(SHARED_EXT)"
+  	$(Q) $(STRIP) $(LIBDIR)/$(CONFIG)/$(SHARED_PREFIX)${lib.name}$(SHARED_VERSION).$(SHARED_EXT)
   % endif
   % endif
   % endfor
@@ -1124,8 +1122,8 @@
   % for lib in libs:
   % if lib.language == "csharp":
   % if lib.build == "all":
-  	$(E) "[STRIP]   Stripping lib${lib.name}.so"
-  	$(Q) $(STRIP) $(LIBDIR)/$(CONFIG)/lib${lib.name}.$(SHARED_EXT)
+  	$(E) "[STRIP]   Stripping $(SHARED_PREFIX)${lib.name}$(SHARED_VERSION).$(SHARED_EXT)"
+  	$(Q) $(STRIP) $(LIBDIR)/$(CONFIG)/$(SHARED_PREFIX)${lib.name}$(SHARED_VERSION).$(SHARED_EXT)
   % endif
   % endif
   % endfor
@@ -1135,11 +1133,6 @@
   	$(E) "[MAKE]    Generating $@"
   	$(Q) echo "$(CACHE_MK)" | tr , '\n' >$@
 
-  $(LIBDIR)/$(CONFIG)/pkgconfig/gpr.pc:
-  	$(E) "[MAKE]    Generating $@"
-  	$(Q) mkdir -p $(@D)
-  	$(Q) echo "$(GPR_PC_FILE)" | tr , '\n' >$@
-
   $(LIBDIR)/$(CONFIG)/pkgconfig/grpc.pc:
   	$(E) "[MAKE]    Generating $@"
   	$(Q) mkdir -p $(@D)
@@ -1198,12 +1191,12 @@
   $(OBJDIR)/$(CONFIG)/%.o : %.c
   	$(E) "[C]       Compiling $<"
   	$(Q) mkdir -p `dirname $@`
-  	$(Q) $(CC) $(CFLAGS) $(CPPFLAGS) -MMD -MF $(addsuffix .dep, $(basename $@)) -c -o $@ $<
+  	$(Q) $(CC) $(CPPFLAGS) $(CFLAGS) -MMD -MF $(addsuffix .dep, $(basename $@)) -c -o $@ $<
 
   $(OBJDIR)/$(CONFIG)/%.o : $(GENDIR)/%.pb.cc
   	$(E) "[CXX]     Compiling $<"
   	$(Q) mkdir -p `dirname $@`
-  	$(Q) $(CXX) $(CXXFLAGS) $(CPPFLAGS) -MMD -MF $(addsuffix .dep, $(basename $@)) -c -o $@ $<
+  	$(Q) $(CXX) $(CPPFLAGS) $(CXXFLAGS) -MMD -MF $(addsuffix .dep, $(basename $@)) -c -o $@ $<
 
   $(OBJDIR)/$(CONFIG)/src/compiler/%.o : src/compiler/%.cc
   	$(E) "[HOSTCXX] Compiling $<"
@@ -1213,7 +1206,7 @@
   $(OBJDIR)/$(CONFIG)/%.o : %.cc
   	$(E) "[CXX]     Compiling $<"
   	$(Q) mkdir -p `dirname $@`
-  	$(Q) $(CXX) $(CXXFLAGS) $(CPPFLAGS) -MMD -MF $(addsuffix .dep, $(basename $@)) -c -o $@ $<
+  	$(Q) $(CXX) $(CPPFLAGS) $(CXXFLAGS) -MMD -MF $(addsuffix .dep, $(basename $@)) -c -o $@ $<
 
   install: install_c install_cxx install-plugins install-certs verify-install
 
@@ -1281,19 +1274,14 @@
   % if lib.language == lang_filter:
   % if lib.build == "all":
   % if not lib.get('external_deps', None):
+  	$(E) "[INSTALL] Installing $(SHARED_PREFIX)${lib.name}$(SHARED_VERSION).$(SHARED_EXT)"
+  	$(Q) $(INSTALL) -d $(prefix)/lib
+  	$(Q) $(INSTALL) $(LIBDIR)/$(CONFIG)/$(SHARED_PREFIX)${lib.name}$(SHARED_VERSION).$(SHARED_EXT) $(prefix)/lib/$(SHARED_PREFIX)${lib.name}$(SHARED_VERSION).$(SHARED_EXT)
   ifeq ($(SYSTEM),MINGW32)
-  	$(E) "[INSTALL] Installing ${lib.name}.$(SHARED_EXT)"
-  	$(Q) $(INSTALL) -d $(prefix)/lib
-  	$(Q) $(INSTALL) $(LIBDIR)/$(CONFIG)/${lib.name}.$(SHARED_EXT) $(prefix)/lib/${lib.name}.$(SHARED_EXT)
   	$(Q) $(INSTALL) $(LIBDIR)/$(CONFIG)/lib${lib.name}-imp.a $(prefix)/lib/lib${lib.name}-imp.a
-  else
-  	$(E) "[INSTALL] Installing lib${lib.name}.$(SHARED_EXT)"
-  	$(Q) $(INSTALL) -d $(prefix)/lib
-  	$(Q) $(INSTALL) $(LIBDIR)/$(CONFIG)/lib${lib.name}.$(SHARED_EXT) $(prefix)/lib/lib${lib.name}.$(SHARED_EXT)
-  ifneq ($(SYSTEM),Darwin)
-  	$(Q) ln -sf lib${lib.name}.$(SHARED_EXT) $(prefix)/lib/lib${lib.name}.so.${settings.version.major}
-  	$(Q) ln -sf lib${lib.name}.$(SHARED_EXT) $(prefix)/lib/lib${lib.name}.so
-  endif
+  else ifneq ($(SYSTEM),Darwin)
+  	$(Q) ln -sf $(SHARED_PREFIX)${lib.name}$(SHARED_VERSION).$(SHARED_EXT) $(prefix)/lib/lib${lib.name}.so.${settings.core_version.major}
+  	$(Q) ln -sf $(SHARED_PREFIX)${lib.name}$(SHARED_VERSION).$(SHARED_EXT) $(prefix)/lib/lib${lib.name}.so
   endif
   % endif
   % endif
@@ -1304,19 +1292,14 @@
   % if lib.language == lang_filter:
   % if lib.build == "all":
   % if 'zookeeper' in lib.get('external_deps', []):
+  	$(E) "[INSTALL] Installing $(SHARED_PREFIX)${lib.name}$(SHARED_VERSION).$(SHARED_EXT)"
+  	$(Q) $(INSTALL) -d $(prefix)/lib
+  	$(Q) $(INSTALL) $(LIBDIR)/$(CONFIG)/$(SHARED_PREFIX)${lib.name}$(SHARED_VERSION).$(SHARED_EXT) $(prefix)/lib/$(SHARED_PREFIX)${lib.name}$(SHARED_VERSION).$(SHARED_EXT)
   ifeq ($(SYSTEM),MINGW32)
-  	$(E) "[INSTALL] Installing ${lib.name}.$(SHARED_EXT)"
-  	$(Q) $(INSTALL) -d $(prefix)/lib
-  	$(Q) $(INSTALL) $(LIBDIR)/$(CONFIG)/${lib.name}.$(SHARED_EXT) $(prefix)/lib/${lib.name}.$(SHARED_EXT)
   	$(Q) $(INSTALL) $(LIBDIR)/$(CONFIG)/lib${lib.name}-imp.a $(prefix)/lib/lib${lib.name}-imp.a
-  else
-  	$(E) "[INSTALL] Installing lib${lib.name}.$(SHARED_EXT)"
-  	$(Q) $(INSTALL) -d $(prefix)/lib
-  	$(Q) $(INSTALL) $(LIBDIR)/$(CONFIG)/lib${lib.name}.$(SHARED_EXT) $(prefix)/lib/lib${lib.name}.$(SHARED_EXT)
-  ifneq ($(SYSTEM),Darwin)
-  	$(Q) ln -sf lib${lib.name}.$(SHARED_EXT) $(prefix)/lib/lib${lib.name}.so.${settings.version.major}
-  	$(Q) ln -sf lib${lib.name}.$(SHARED_EXT) $(prefix)/lib/lib${lib.name}.so
-  endif
+  else ifneq ($(SYSTEM),Darwin)
+  	$(Q) ln -sf $(SHARED_PREFIX)${lib.name}$(SHARED_VERSION).$(SHARED_EXT) $(prefix)/lib/lib${lib.name}.so.${settings.core_version.major}
+  	$(Q) ln -sf $(SHARED_PREFIX)${lib.name}$(SHARED_VERSION).$(SHARED_EXT) $(prefix)/lib/lib${lib.name}.so
   endif
   % endif
   % endif
@@ -1352,10 +1335,9 @@
   % endfor
   endif
 
-  install-pkg-config_c: pc_gpr pc_c pc_c_unsecure pc_c_zookeeper
+  install-pkg-config_c: pc_c pc_c_unsecure pc_c_zookeeper
   	$(E) "[INSTALL] Installing C pkg-config files"
   	$(Q) $(INSTALL) -d $(prefix)/lib/pkgconfig
-  	$(Q) $(INSTALL) $(LIBDIR)/$(CONFIG)/pkgconfig/gpr.pc $(prefix)/lib/pkgconfig/gpr.pc
   	$(Q) $(INSTALL) $(LIBDIR)/$(CONFIG)/pkgconfig/grpc.pc $(prefix)/lib/pkgconfig/grpc.pc
   	$(Q) $(INSTALL) $(LIBDIR)/$(CONFIG)/pkgconfig/grpc_unsecure.pc $(prefix)/lib/pkgconfig/grpc_unsecure.pc
   ifeq ($(HAS_ZOOKEEPER),true)
@@ -1435,16 +1417,10 @@
 
   LIB${lib.name.upper()}_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(LIB${lib.name.upper()}_SRC))))
 
-  % if lib.boringssl:
-  # boringssl needs an override to ensure that it does not include
-  # system openssl headers regardless of other configuration
-  # we do so here with a target specific variable assignment
-  $(LIB${lib.name.upper()}_OBJS): CFLAGS := -Ithird_party/boringssl/include $(CFLAGS) -Wno-sign-conversion -Wno-conversion -Wno-unused-value -fvisibility=hidden
-  $(LIB${lib.name.upper()}_OBJS): CXXFLAGS := -Ithird_party/boringssl/include $(CXXFLAGS) -fvisibility=hidden
-  $(LIB${lib.name.upper()}_OBJS): CPPFLAGS += -DOPENSSL_NO_ASM -D_GNU_SOURCE
-  % elif lib.zlib:
-  $(LIB${lib.name.upper()}_OBJS): CFLAGS := $(CFLAGS) -Wno-sign-conversion -Wno-conversion -Wno-unused-value -Wno-implicit-function-declaration $(W_NO_SHIFT_NEGATIVE_VALUE) -fvisibility=hidden
-  % else:
+  % if lib.get('defaults', None):
+  %  for name, value in defaults.get(lib.defaults).iteritems():
+  $(LIB${lib.name.upper()}_OBJS): ${name} += ${value}
+  %  endfor
   % endif
 
   ## If the library requires OpenSSL, let's add some restrictions.
@@ -1456,11 +1432,7 @@
   $(LIBDIR)/$(CONFIG)/lib${lib.name}.a: openssl_dep_error
 
   % if lib.build == "all":
-  ifeq ($(SYSTEM),MINGW32)
-  $(LIBDIR)/$(CONFIG)/${lib.name}.$(SHARED_EXT): openssl_dep_error
-  else
-  $(LIBDIR)/$(CONFIG)/lib${lib.name}.$(SHARED_EXT): openssl_dep_error
-  endif
+  $(LIBDIR)/$(CONFIG)/$(SHARED_PREFIX)${lib.name}$(SHARED_VERSION).$(SHARED_EXT): openssl_dep_error
   % endif
 
   else
@@ -1473,11 +1445,7 @@
   $(LIBDIR)/$(CONFIG)/lib${lib.name}.a: protobuf_dep_error
 
   % if lib.build == "all":
-  ifeq ($(SYSTEM),MINGW32)
-  $(LIBDIR)/$(CONFIG)/${lib.name}.$(SHARED_EXT): protobuf_dep_error
-  else
-  $(LIBDIR)/$(CONFIG)/lib${lib.name}.$(SHARED_EXT): protobuf_dep_error
-  endif
+  $(LIBDIR)/$(CONFIG)/$(SHARED_PREFIX)${lib.name}$(SHARED_VERSION).$(SHARED_EXT): protobuf_dep_error
   % endif
 
   else
@@ -1494,53 +1462,41 @@
   $(LIBDIR)/$(CONFIG)/lib${lib.name}.a: protobuf_dep_error
 
   % if lib.build == "all":
-  ifeq ($(SYSTEM),MINGW32)
-  $(LIBDIR)/$(CONFIG)/${lib.name}.$(SHARED_EXT): protobuf_dep_error
-  else
-  $(LIBDIR)/$(CONFIG)/lib${lib.name}.$(SHARED_EXT): protobuf_dep_error
-  endif
+  $(LIBDIR)/$(CONFIG)/$(SHARED_PREFIX)${lib.name}$(SHARED_VERSION).$(SHARED_EXT): protobuf_dep_error
   % endif
 
   else
 
   % endif
-  $(LIBDIR)/$(CONFIG)/lib${lib.name}.a: $(ZLIB_DEP) $(OPENSSL_DEP) \
+  $(LIBDIR)/$(CONFIG)/lib${lib.name}.a: \
+  % if lib.name != 'z':
+  $(ZLIB_DEP) \
+  % endif
   % endif
   % if lib.language == 'c++':
    $(PROTOBUF_DEP)\
   % endif
-   $(LIB${lib.name.upper()}_OBJS)
+   $(LIB${lib.name.upper()}_OBJS) \
+  % if lib.get('baselib', False):
+   $(LIBGPR_OBJS) \
+   $(ZLIB_MERGE_OBJS) \
+  % if lib.get('secure', 'check') == True:
+   $(OPENSSL_MERGE_OBJS) \
+  % endif
+  % endif
+
   	$(E) "[AR]      Creating $@"
   	$(Q) mkdir -p `dirname $@`
   	$(Q) rm -f $(LIBDIR)/$(CONFIG)/lib${lib.name}.a
-  	$(Q) $(AR) rcs $(LIBDIR)/$(CONFIG)/lib${lib.name}.a $(LIB${lib.name.upper()}_OBJS)
+  	$(Q) $(AR) $(LIBDIR)/$(CONFIG)/lib${lib.name}.a $(LIB${lib.name.upper()}_OBJS) \
   % if lib.get('baselib', False):
-  	$(Q) rm -rf $(BUILDDIR_ABSOLUTE)/tmp-merge-${lib.name}
-  	$(Q) ( mkdir -p $(BUILDDIR_ABSOLUTE)/tmp-merge-${lib.name}/grpc ; <%text>\</%text>
-  	       cd $(BUILDDIR_ABSOLUTE)/tmp-merge-${lib.name}/grpc ; <%text>\</%text>
-  	       $(AR) x $(LIBDIR)/$(CONFIG)/lib${lib.name}.a )
-  	$(Q) for l in $(ZLIB_MERGE_LIBS) ; do ( <%text>\</%text>
-  	       mkdir -p $(BUILDDIR_ABSOLUTE)/tmp-merge-${lib.name}/zlib ; <%text>\</%text>
-  	       cd $(BUILDDIR_ABSOLUTE)/tmp-merge-${lib.name}/zlib ; <%text>\</%text>
-  	       <%text>$(AR) x $${l}</%text> ) ; done
-  	$(Q) for l in $(ZLIB_MERGE_LIBS) ; do ( <%text>\</%text>
-  	       mkdir -p $(BUILDDIR_ABSOLUTE)/tmp-merge-${lib.name}/zlib ; <%text>\</%text>
-  	       cd $(BUILDDIR_ABSOLUTE)/tmp-merge-${lib.name}/zlib ; <%text>\</%text>
-  	       <%text>$(AR) x $${l}</%text> ) ; done
+   $(LIBGPR_OBJS) \
+   $(ZLIB_MERGE_OBJS) \
   % if lib.get('secure', 'check') == True:
-  	$(Q) for l in $(OPENSSL_MERGE_LIBS) ; do ( <%text>\</%text>
-  	       mkdir -p $(BUILDDIR_ABSOLUTE)/tmp-merge-${lib.name}/ssl ; <%text>\</%text>
-  	       cd $(BUILDDIR_ABSOLUTE)/tmp-merge-${lib.name}/ssl ; <%text>\</%text>
-  	       <%text>$(AR) x $${l}</%text> ) ; done
-  	$(Q) for l in $(OPENSSL_MERGE_LIBS) ; do ( <%text>\</%text>
-  	       mkdir -p $(BUILDDIR_ABSOLUTE)/tmp-merge-${lib.name}/ssl ; <%text>\</%text>
-  	       cd $(BUILDDIR_ABSOLUTE)/tmp-merge-${lib.name}/ssl ; <%text>\</%text>
-  	       <%text>$(AR) x $${l}</%text> ) ; done
+   $(OPENSSL_MERGE_OBJS) \
   % endif
-  	$(Q) rm -f $(LIBDIR)/$(CONFIG)/lib${lib.name}.a $(BUILDDIR_ABSOLUTE)/tmp-merge-${lib.name}/*/__.SYMDEF*
-  	$(Q) ar rcs $(LIBDIR)/$(CONFIG)/lib${lib.name}.a $(BUILDDIR_ABSOLUTE)/tmp-merge-${lib.name}/*/*
-  	$(Q) rm -rf $(BUILDDIR_ABSOLUTE)/tmp-merge-${lib.name}
   % endif
+
   ifeq ($(SYSTEM),Darwin)
   	$(Q) ranlib $(LIBDIR)/$(CONFIG)/lib${lib.name}.a
   endif
@@ -1552,8 +1508,8 @@
     else:
       ld = '$(LD)'
 
-    out_base = '$(LIBDIR)/$(CONFIG)/' + lib.name
-    out_libbase = '$(LIBDIR)/$(CONFIG)/lib' + lib.name
+    out_mingbase = '$(LIBDIR)/$(CONFIG)/' + lib.name + '$(SHARED_VERSION)'
+    out_libbase = '$(LIBDIR)/$(CONFIG)/lib' + lib.name + '$(SHARED_VERSION)'
 
     common = '$(LIB' + lib.name.upper() + '_OBJS) $(LDLIBS)'
 
@@ -1599,24 +1555,28 @@
 
     if lib.language == 'c++':
       common = common + ' $(LDLIBSXX) $(LDLIBS_PROTOBUF)'
+
+    ldflags = '$(LDFLAGS)'
+    if lib.get('LDFLAGS', None):
+      ldflags += ' ' + lib['LDFLAGS']
   %>
 
   % if lib.build == "all":
   ifeq ($(SYSTEM),MINGW32)
-  ${out_base}.$(SHARED_EXT): $(LIB${lib.name.upper()}_OBJS) ${mingw_lib_deps}
+  ${out_mingbase}.$(SHARED_EXT): $(LIB${lib.name.upper()}_OBJS) ${mingw_lib_deps}
   	$(E) "[LD]      Linking $@"
   	$(Q) mkdir -p `dirname $@`
-  	$(Q) ${ld} $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -shared -Wl,--output-def=${out_base}.def -Wl,--out-implib=${out_libbase}-imp.a -o ${out_base}.$(SHARED_EXT) ${common}${mingw_libs}
+  	$(Q) ${ld} ${ldflags} -L$(LIBDIR)/$(CONFIG) -shared ${lib.name}.def -Wl,--output-def=${out_mingbase}.def -Wl,--out-implib=${out_libbase}-dll.a -o ${out_mingbase}.$(SHARED_EXT) ${common}${mingw_libs}
   else
   ${out_libbase}.$(SHARED_EXT): $(LIB${lib.name.upper()}_OBJS) ${lib_deps}
   	$(E) "[LD]      Linking $@"
   	$(Q) mkdir -p `dirname $@`
   ifeq ($(SYSTEM),Darwin)
-  	$(Q) ${ld} $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -install_name lib${lib.name}.$(SHARED_EXT) -dynamiclib -o ${out_libbase}.$(SHARED_EXT) ${common}${libs}
+  	$(Q) ${ld} ${ldflags} -L$(LIBDIR)/$(CONFIG) -install_name $(SHARED_PREFIX)${lib.name}$(SHARED_VERSION).$(SHARED_EXT) -dynamiclib -o ${out_libbase}.$(SHARED_EXT) ${common}${libs}
   else
-  	$(Q) ${ld} $(LDFLAGS) -L$(LIBDIR)/$(CONFIG) -shared -Wl,-soname,lib${lib.name}.so.${settings.version.major} -o ${out_libbase}.$(SHARED_EXT) ${common}${libs}
-  	$(Q) ln -sf lib${lib.name}.$(SHARED_EXT) ${out_libbase}.so.${settings.version.major}
-  	$(Q) ln -sf lib${lib.name}.$(SHARED_EXT) ${out_libbase}.so
+  	$(Q) ${ld} ${ldflags} -L$(LIBDIR)/$(CONFIG) -shared -Wl,-soname,lib${lib.name}.so.${settings.core_version.major} -o ${out_libbase}.$(SHARED_EXT) ${common}${libs}
+  	$(Q) ln -sf $(SHARED_PREFIX)${lib.name}$(SHARED_VERSION).$(SHARED_EXT) ${out_libbase}.so.${settings.core_version.major}
+  	$(Q) ln -sf $(SHARED_PREFIX)${lib.name}$(SHARED_VERSION).$(SHARED_EXT) ${out_libbase}.so
   endif
   endif
   % endif
@@ -1789,7 +1749,7 @@
   $(OBJDIR)/$(CONFIG)/${os.path.splitext(src)[0]}.o : ${src}
   	$(E) "[C]       Compiling $<"
   	$(Q) mkdir -p `dirname $@`
-  	$(Q) $(CC) $(CFLAGS) $(CPPFLAGS) -std=c89 -pedantic -MMD -MF $(addsuffix .dep, $(basename $@)) -c -o $@ $<
+  	$(Q) $(CC) $(CPPFLAGS) $(CFLAGS) -std=c89 -pedantic -MMD -MF $(addsuffix .dep, $(basename $@)) -c -o $@ $<
   % endfor
   % endif
 
diff --git a/templates/binding.gyp.template b/templates/binding.gyp.template
index 71276e7..7cee562 100644
--- a/templates/binding.gyp.template
+++ b/templates/binding.gyp.template
@@ -39,29 +39,49 @@
   # Some of this file is built with the help of
   # https://n8.io/converting-a-c-library-to-gyp/
   {
-    'variables': {
-      'config': '<!(echo $CONFIG)'
-    },
-    # TODO: Finish windows support
     'target_defaults': {
-        # Empirically, Node only exports ALPN symbols if its major version is >0.
-        # io.js always reports versions >0 and always exports ALPN symbols.
-        # Therefore, Node's major version will be truthy if and only if it
-        # supports ALPN. The output of "node -v" is v[major].[minor].[patch],
-        # like "v4.1.1" in a recent version. We use cut to split by period and
-        # take the first field (resulting in "v[major]"), then use cut again
-        # to take all but the first character, removing the "v".
-      'defines': [
-        'TSI_OPENSSL_ALPN_SUPPORT=<!(node --version | cut -d. -f1 | cut -c2-)'
-      ],
       'include_dirs': [
         '.',
         'include'
       ],
       'conditions': [
         ['OS == "win"', {
-          "include_dirs": [ "third_party/boringssl/include" ]
-        }, {
+          "include_dirs": [
+            "third_party/boringssl/include",
+            "third_party/zlib"
+          ],
+          "defines": [
+            '_WIN32_WINNT=0x0600',
+            'WIN32_LEAN_AND_MEAN',
+            '_HAS_EXCEPTIONS=0',
+            'UNICODE',
+            '_UNICODE',
+            'NOMINMAX',
+            'OPENSSL_NO_ASM'
+          ],
+          "msvs_settings": {
+            'VCCLCompilerTool': {
+              'RuntimeLibrary': 1, # static debug
+            }
+          },
+          "libraries": [
+            "ws2_32"
+          ]
+        }, { # OS != "win"
+          'variables': {
+            'config': '<!(echo $CONFIG)',
+            # The output of "node --version" is "v[version]". We use cut to
+            # remove the first character.
+            'target%': '<!(node --version | cut -c2-)'
+          },
+            # Empirically, Node only exports ALPN symbols if its major version is >0.
+            # io.js always reports versions >0 and always exports ALPN symbols.
+            # Therefore, Node's major version will be truthy if and only if it
+            # supports ALPN. The target is "[major].[minor].[patch]". We split by
+            # periods and take the first field to get the major version.
+          'defines': [
+            'TSI_OPENSSL_ALPN_SUPPORT=<!(echo <(target) | cut -d. -f1)'
+          ],
           'include_dirs': [
             '<(node_root_dir)/deps/openssl/openssl/include',
             '<(node_root_dir)/deps/zlib'
@@ -95,6 +115,29 @@
     'conditions': [
       ['OS == "win"', {
         'targets': [
+          {
+            # IMPORTANT WINDOWS BUILD INFORMATION
+            # This library does not build on Windows without modifying the Node
+            # development packages that node-gyp downloads in order to build.
+            # Due to https://github.com/nodejs/node/issues/4932, the headers for
+            # BoringSSL conflict with the OpenSSL headers included by default
+            # when including the Node headers. The remedy for this is to remove
+            # the OpenSSL headers, from the downloaded Node development package,
+            # which is typically located in `.node-gyp` in your home directory.
+            'target_name': 'WINDOWS_BUILD_WARNING',
+            'actions': [
+              {
+                'action_name': 'WINDOWS_BUILD_WARNING',
+                'inputs': [
+                  'package.json'
+                ],
+                'outputs': [
+                  'ignore_this_part'
+                ],
+                'action': ['echo', 'IMPORTANT: Due to https://github.com/nodejs/node/issues/4932, to build this library on Windows, you must first remove <(node_root_dir)/include/node/openssl/']
+              }
+            ]
+          },
           # Only want to compile BoringSSL and zlib under Windows
           % for module in node_modules:
           % for lib in libs:
@@ -117,8 +160,7 @@
               % for source in lib.src:
               '${source}',
               % endfor
-            ],
-            "include_dirs": [ "third_party/boringssl/include" ]
+            ]
           },
           % endif
           % endfor
@@ -180,7 +222,8 @@
             'xcode_settings': {
               'MACOSX_DEPLOYMENT_TARGET': '10.9',
               'OTHER_CFLAGS': [
-                '-stdlib=libc++'
+                '-stdlib=libc++',
+                '-std=c++11'
               ]
             }
           }],
@@ -192,6 +235,11 @@
               % endif
               % endfor
             ]
+          }],
+          ['OS=="linux"', {
+            'ldflags': [
+              '-Wl,-wrap,memcpy'
+            ]
           }]
         ],
         "target_name": "${module.name}",
diff --git a/templates/gRPC.podspec.template b/templates/gRPC.podspec.template
index 67fc8f6..a9948a4 100644
--- a/templates/gRPC.podspec.template
+++ b/templates/gRPC.podspec.template
@@ -97,7 +97,7 @@
 
       ss.requires_arc = false
       ss.libraries = 'z'
-      ss.dependency 'BoringSSL', '~> 1.0'
+      ss.dependency 'BoringSSL', '~> 2.0'
 
       # ss.compiler_flags = '-GCC_WARN_INHIBIT_ALL_WARNINGS', '-w'
     end
diff --git a/templates/grpc.def.template b/templates/grpc.def.template
new file mode 100644
index 0000000..ea3963c
--- /dev/null
+++ b/templates/grpc.def.template
@@ -0,0 +1,6 @@
+%YAML 1.2
+--- |
+  EXPORTS
+  % for api in c_apis:
+      ${api.name}
+  % endfor
diff --git a/templates/grpc.gemspec.template b/templates/grpc.gemspec.template
index fdf87ee..6cc3e96 100644
--- a/templates/grpc.gemspec.template
+++ b/templates/grpc.gemspec.template
@@ -16,9 +16,8 @@
     s.license       = 'BSD-3-Clause'
 
     s.required_ruby_version = '>= 2.0.0'
-    s.requirements << 'libgrpc ~> 0.11.0 needs to be installed'
 
-    s.files = %w( Rakefile Makefile )
+    s.files = %w( Makefile )
     s.files += %w( etc/roots.pem )
     s.files += Dir.glob('src/ruby/bin/**/*')
     s.files += Dir.glob('src/ruby/ext/**/*')
@@ -34,23 +33,24 @@
     s.require_paths = %w( src/ruby/bin src/ruby/lib src/ruby/pb )
     s.platform      = Gem::Platform::RUBY
 
-    s.add_dependency 'google-protobuf', '~> 3.0.0alpha.1.1'
-    s.add_dependency 'googleauth', '~> 0.5.1'
+    s.add_dependency 'google-protobuf', '~> 3.0.0.alpha.5.0.2'
+    s.add_dependency 'googleauth',      '~> 0.5.1'
 
-    s.add_development_dependency 'bundler', '~> 1.9'
-    s.add_development_dependency 'logging', '~> 2.0'
-    s.add_development_dependency 'simplecov', '~> 0.9'
-    s.add_development_dependency 'rake', '~> 10.4'
-    s.add_development_dependency 'rake-compiler', '~> 0.9'
-    s.add_development_dependency 'rspec', '~> 3.2'
-    s.add_development_dependency 'rubocop', '~> 0.30.0'
-    s.add_development_dependency 'signet', '~>0.7.0'
+    s.add_development_dependency 'bundler',            '~> 1.9'
+    s.add_development_dependency 'logging',            '~> 2.0'
+    s.add_development_dependency 'simplecov',          '~> 0.9'
+    s.add_development_dependency 'rake',               '~> 10.4'
+    s.add_development_dependency 'rake-compiler',      '~> 0.9'
+    s.add_development_dependency 'rake-compiler-dock', '~> 0.5.1'
+    s.add_development_dependency 'rspec',              '~> 3.2'
+    s.add_development_dependency 'rubocop',            '~> 0.30.0'
+    s.add_development_dependency 'signet',             '~> 0.7.0'
 
     s.extensions = %w(src/ruby/ext/grpc/extconf.rb)
 
     % for lib in libs:
-    % if lib.name in ('gpr', 'grpc'):
-    % for file in lib.public_headers + lib.headers + lib.src:
+    % if lib.name in ruby_gem.get('deps', []):
+    % for file in lib.get('public_headers', []) + lib.headers + lib.src:
     s.files += %w( ${file} )
     % endfor
     % endif
diff --git a/templates/package.json.template b/templates/package.json.template
index ed4dca5..d6279b9 100644
--- a/templates/package.json.template
+++ b/templates/package.json.template
@@ -2,7 +2,7 @@
 --- |
   {
     "name": "grpc",
-    "version": "0.12.0",
+    "version": "${settings.node_version}",
     "author": "Google Inc.",
     "description": "gRPC Library for Node",
     "homepage": "http://www.grpc.io/",
@@ -47,7 +47,7 @@
       "poisson-process": "^0.2.1"
     },
     "engines": {
-      "node": ">=0.10.13"
+      "node": ">=0.12.0"
     },
     "binary": {
       "module_name": "grpc_node",
diff --git a/templates/src/core/surface/version.c.template b/templates/src/core/surface/version.c.template
index 4788dc4..f2b3cfd 100644
--- a/templates/src/core/surface/version.c.template
+++ b/templates/src/core/surface/version.c.template
@@ -38,5 +38,4 @@
   
   #include <grpc/grpc.h>
   
-  const char *grpc_version_string(void) { \
-  return "${settings.version.major}.${settings.version.minor}.${settings.version.micro}.${settings.version.build}"; }
+  const char *grpc_version_string(void) { return "${settings.core_version}"; }
diff --git a/templates/src/csharp/Grpc.Core/VersionInfo.cs.template b/templates/src/csharp/Grpc.Core/VersionInfo.cs.template
index 48197ba..59864fa 100644
--- a/templates/src/csharp/Grpc.Core/VersionInfo.cs.template
+++ b/templates/src/csharp/Grpc.Core/VersionInfo.cs.template
@@ -41,8 +41,13 @@
       public static class VersionInfo
       {
           /// <summary>
+          /// Current version of gRPC C# assemblies
+          /// </summary>
+          public const string CurrentAssemblyVersion = "${settings.version.major}.${settings.version.minor}.${settings.version.patch}.0";
+
+          /// <summary>
           /// Current version of gRPC C#
           /// </summary>
-          public const string CurrentVersion = "${settings.version.major}.${settings.version.minor}.${settings.version.micro}";
+          public const string CurrentVersion = "${settings.csharp_version}";
       }
   }
diff --git a/templates/src/csharp/build_packages.bat.template b/templates/src/csharp/build_packages.bat.template
index bf831a9..b855126 100644
--- a/templates/src/csharp/build_packages.bat.template
+++ b/templates/src/csharp/build_packages.bat.template
@@ -3,7 +3,7 @@
   @rem Builds gRPC NuGet packages
   
   @rem Current package versions
-  set VERSION=${settings.version.major}.${settings.version.minor}.${settings.version.micro}
+  set VERSION=${settings.csharp_version}
   set PROTOBUF_VERSION=3.0.0-beta2
   
   @rem Packages that depend on prerelease packages (like Google.Protobuf) need to have prerelease suffix as well.
@@ -51,6 +51,10 @@
   @rem copy resulting nuget packages to artifacts directory
   xcopy /Y /I *.nupkg ..\..\artifacts${"\\"}
   
+  @rem create a zipfile with the artifacts as well
+  powershell -Command "Add-Type -Assembly 'System.IO.Compression.FileSystem'; [System.IO.Compression.ZipFile]::CreateFromDirectory('..\..\artifacts', 'csharp_nugets.zip');"
+  xcopy /Y /I csharp_nugets.zip ..\..\artifacts${"\\"}
+  
   goto :EOF
   
   :error
diff --git a/templates/src/python/grpcio/grpc/_cython/imports.generated.c.template b/templates/src/python/grpcio/grpc/_cython/imports.generated.c.template
new file mode 100644
index 0000000..be33280
--- /dev/null
+++ b/templates/src/python/grpcio/grpc/_cython/imports.generated.c.template
@@ -0,0 +1,52 @@
+%YAML 1.2
+--- |
+  /*
+   *
+   * Copyright 2016, Google Inc.
+   * All rights reserved.
+   *
+   * Redistribution and use in source and binary forms, with or without
+   * modification, are permitted provided that the following conditions are
+   * met:
+   *
+   *     * Redistributions of source code must retain the above copyright
+   * notice, this list of conditions and the following disclaimer.
+   *     * Redistributions in binary form must reproduce the above
+   * copyright notice, this list of conditions and the following disclaimer
+   * in the documentation and/or other materials provided with the
+   * distribution.
+   *     * Neither the name of Google Inc. nor the names of its
+   * contributors may be used to endorse or promote products derived from
+   * this software without specific prior written permission.
+   *
+   * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+   * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+   * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+   * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+   * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+   * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+   * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+   * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+   * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+   * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+   *
+   */
+
+  #include <grpc/support/port_platform.h>
+
+  #include "imports.generated.h"
+
+  #ifdef GPR_WIN32
+
+  %for api in c_apis:
+  ${api.name}_type ${api.name}_import;
+  %endfor
+
+  void pygrpc_load_imports(HMODULE library) {
+  %for api in c_apis:
+    ${api.name}_import = (${api.name}_type) GetProcAddress(library, "${api.name}");
+  %endfor
+  }
+
+  #endif /* !GPR_WIN32 */
diff --git a/templates/src/python/grpcio/grpc/_cython/imports.generated.h.template b/templates/src/python/grpcio/grpc/_cython/imports.generated.h.template
new file mode 100644
index 0000000..6866a61
--- /dev/null
+++ b/templates/src/python/grpcio/grpc/_cython/imports.generated.h.template
@@ -0,0 +1,70 @@
+%YAML 1.2
+--- |
+  /*
+   *
+   * Copyright 2016, Google Inc.
+   * All rights reserved.
+   *
+   * Redistribution and use in source and binary forms, with or without
+   * modification, are permitted provided that the following conditions are
+   * met:
+   *
+   *     * Redistributions of source code must retain the above copyright
+   * notice, this list of conditions and the following disclaimer.
+   *     * Redistributions in binary form must reproduce the above
+   * copyright notice, this list of conditions and the following disclaimer
+   * in the documentation and/or other materials provided with the
+   * distribution.
+   *     * Neither the name of Google Inc. nor the names of its
+   * contributors may be used to endorse or promote products derived from
+   * this software without specific prior written permission.
+   *
+   * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+   * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+   * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+   * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+   * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+   * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+   * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+   * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+   * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+   * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+   *
+   */
+
+  #ifndef PYGRPC_CYTHON_WINDOWS_IMPORTS_H_
+  #define PYGRPC_CYTHON_WINDOWS_IMPORTS_H_
+
+  #include <grpc/support/port_platform.h>
+
+  #ifdef GPR_WIN32
+
+  #include <windows.h>
+
+  %for header in sorted(set(api.header for api in c_apis)):
+  #include <${'/'.join(header.split('/')[1:])}>
+  %endfor
+
+  %for api in c_apis:
+  typedef ${api.return_type}(*${api.name}_type)(${api.arguments});
+  extern ${api.name}_type ${api.name}_import;
+  #define ${api.name} ${api.name}_import
+  %endfor
+
+  void pygrpc_load_imports(HMODULE library);
+
+  #else /* !GPR_WIN32 */
+
+  #include <grpc/support/alloc.h>
+  #include <grpc/support/slice.h>
+  #include <grpc/support/time.h>
+  #include <grpc/status.h>
+  #include <grpc/byte_buffer.h>
+  #include <grpc/byte_buffer_reader.h>
+  #include <grpc/grpc.h>
+  #include <grpc/grpc_security.h>
+
+  #endif /* !GPR_WIN32 */
+
+  #endif
diff --git a/templates/src/python/grpcio/grpc_version.py.template b/templates/src/python/grpcio/grpc_version.py.template
new file mode 100644
index 0000000..aaacab1
--- /dev/null
+++ b/templates/src/python/grpcio/grpc_version.py.template
@@ -0,0 +1,34 @@
+%YAML 1.2
+--- |
+  # Copyright 2015-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.
+
+  # AUTO-GENERATED FROM `$REPO_ROOT/templates/src/python/grpcio/grpc_version.py.template`!!!
+
+  VERSION='${settings.python_version.pep440()}'
diff --git a/templates/src/ruby/ext/grpc/rb_grpc_imports.generated.c.template b/templates/src/ruby/ext/grpc/rb_grpc_imports.generated.c.template
new file mode 100644
index 0000000..e09a587
--- /dev/null
+++ b/templates/src/ruby/ext/grpc/rb_grpc_imports.generated.c.template
@@ -0,0 +1,52 @@
+%YAML 1.2
+--- |
+  /*
+   *
+   * Copyright 2016, Google Inc.
+   * All rights reserved.
+   *
+   * Redistribution and use in source and binary forms, with or without
+   * modification, are permitted provided that the following conditions are
+   * met:
+   *
+   *     * Redistributions of source code must retain the above copyright
+   * notice, this list of conditions and the following disclaimer.
+   *     * Redistributions in binary form must reproduce the above
+   * copyright notice, this list of conditions and the following disclaimer
+   * in the documentation and/or other materials provided with the
+   * distribution.
+   *     * Neither the name of Google Inc. nor the names of its
+   * contributors may be used to endorse or promote products derived from
+   * this software without specific prior written permission.
+   *
+   * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+   * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+   * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+   * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+   * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+   * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+   * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+   * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+   * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+   * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+   *
+   */
+
+  #include <grpc/support/port_platform.h>
+
+  #ifdef GPR_WIN32
+
+  #include "rb_grpc_imports.generated.h"
+
+  %for api in c_apis:
+  ${api.name}_type ${api.name}_import;
+  %endfor
+
+  void grpc_rb_load_imports(HMODULE library) {
+  %for api in c_apis:
+    ${api.name}_import = (${api.name}_type) GetProcAddress(library, "${api.name}");
+  %endfor
+  }
+
+  #endif /* GPR_WIN32 */
diff --git a/templates/src/ruby/ext/grpc/rb_grpc_imports.generated.h.template b/templates/src/ruby/ext/grpc/rb_grpc_imports.generated.h.template
new file mode 100644
index 0000000..9f17ede
--- /dev/null
+++ b/templates/src/ruby/ext/grpc/rb_grpc_imports.generated.h.template
@@ -0,0 +1,59 @@
+%YAML 1.2
+--- |
+  /*
+   *
+   * Copyright 2016, Google Inc.
+   * All rights reserved.
+   *
+   * Redistribution and use in source and binary forms, with or without
+   * modification, are permitted provided that the following conditions are
+   * met:
+   *
+   *     * Redistributions of source code must retain the above copyright
+   * notice, this list of conditions and the following disclaimer.
+   *     * Redistributions in binary form must reproduce the above
+   * copyright notice, this list of conditions and the following disclaimer
+   * in the documentation and/or other materials provided with the
+   * distribution.
+   *     * Neither the name of Google Inc. nor the names of its
+   * contributors may be used to endorse or promote products derived from
+   * this software without specific prior written permission.
+   *
+   * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+   * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+   * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+   * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+   * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+   * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+   * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+   * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+   * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+   * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+   *
+   */
+
+  #ifndef GRPC_RB_GRPC_IMPORTS_H_
+  #define GRPC_RB_GRPC_IMPORTS_H_
+
+  #include <grpc/support/port_platform.h>
+
+  #ifdef GPR_WIN32
+
+  #include <windows.h>
+
+  %for header in sorted(set(api.header for api in c_apis)):
+  #include <${'/'.join(header.split('/')[1:])}>
+  %endfor
+
+  %for api in c_apis:
+  typedef ${api.return_type}(*${api.name}_type)(${api.arguments});
+  extern ${api.name}_type ${api.name}_import;
+  #define ${api.name} ${api.name}_import
+  %endfor
+
+  void grpc_rb_load_imports(HMODULE library);
+
+  #endif /* GPR_WIN32 */
+
+  #endif
diff --git a/templates/src/ruby/lib/grpc/version.rb.template b/templates/src/ruby/lib/grpc/version.rb.template
new file mode 100644
index 0000000..6488614
--- /dev/null
+++ b/templates/src/ruby/lib/grpc/version.rb.template
@@ -0,0 +1,35 @@
+%YAML 1.2
+--- |
+  # Copyright 2015-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.
+
+  # GRPC contains the General RPC module.
+  module GRPC
+    VERSION = '${settings.ruby_version.ruby()}'
+  end
diff --git a/templates/tools/dockerfile/apt_get_basic.include b/templates/tools/dockerfile/apt_get_basic.include
new file mode 100644
index 0000000..9237e7d
--- /dev/null
+++ b/templates/tools/dockerfile/apt_get_basic.include
@@ -0,0 +1,33 @@
+# Install Git and basic packages.
+RUN apt-get update && apt-get install -y ${'\\'}
+  autoconf ${'\\'}
+  autotools-dev ${'\\'}
+  build-essential ${'\\'}
+  bzip2 ${'\\'}
+  ccache ${'\\'}
+  curl ${'\\'}
+  gcc ${'\\'}
+  gcc-multilib ${'\\'}
+  git ${'\\'}
+  golang ${'\\'}
+  gyp ${'\\'}
+  lcov ${'\\'}
+  libc6 ${'\\'}
+  libc6-dbg ${'\\'}
+  libc6-dev ${'\\'}
+  libgtest-dev ${'\\'}
+  libtool ${'\\'}
+  make ${'\\'}
+  perl ${'\\'}
+  strace ${'\\'}
+  python-dev ${'\\'}
+  python-setuptools ${'\\'}
+  python-yaml ${'\\'}
+  telnet ${'\\'}
+  unzip ${'\\'}
+  wget ${'\\'}
+  zip && apt-get clean
+
+#================
+# Build profiling
+RUN apt-get update && apt-get install -y time && apt-get clean
diff --git a/templates/tools/dockerfile/ccache_setup.include b/templates/tools/dockerfile/ccache_setup.include
new file mode 100644
index 0000000..2a2de7f
--- /dev/null
+++ b/templates/tools/dockerfile/ccache_setup.include
@@ -0,0 +1,7 @@
+# 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 ln -s /usr/bin/ccache /usr/local/bin/clang
+RUN ln -s /usr/bin/ccache /usr/local/bin/clang++
diff --git a/templates/tools/dockerfile/csharp_deps.include b/templates/tools/dockerfile/csharp_deps.include
new file mode 100644
index 0000000..489dc44
--- /dev/null
+++ b/templates/tools/dockerfile/csharp_deps.include
@@ -0,0 +1,16 @@
+#================
+# C# dependencies
+
+# Update to a newer version of mono
+RUN apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 3FA7E0328081BFF6A14DA29AA6A19B38D3D831EF
+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 ${'\\'}
+    mono-devel ${'\\'}
+    ca-certificates-mono ${'\\'}
+    nuget ${'\\'}
+    && apt-get clean
diff --git a/templates/tools/dockerfile/cxx_deps.include b/templates/tools/dockerfile/cxx_deps.include
new file mode 100644
index 0000000..14831c1
--- /dev/null
+++ b/templates/tools/dockerfile/cxx_deps.include
@@ -0,0 +1,3 @@
+#=================
+# C++ dependencies
+RUN apt-get update && apt-get -y install libgflags-dev libgtest-dev libc++-dev clang && apt-get clean
diff --git a/templates/tools/dockerfile/node_deps.include b/templates/tools/dockerfile/node_deps.include
new file mode 100644
index 0000000..7d37d67
--- /dev/null
+++ b/templates/tools/dockerfile/node_deps.include
@@ -0,0 +1,7 @@
+#==================
+# Node dependencies
+
+# Install nvm
+RUN touch .profile
+RUN curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.25.4/install.sh | bash
+RUN /bin/bash -l -c "nvm install 0.12 && npm config set cache /tmp/npm-cache"
diff --git a/templates/tools/dockerfile/php_deps.include b/templates/tools/dockerfile/php_deps.include
new file mode 100644
index 0000000..739049b
--- /dev/null
+++ b/templates/tools/dockerfile/php_deps.include
@@ -0,0 +1,13 @@
+#=================
+# PHP dependencies
+
+# Install dependencies
+
+RUN /bin/bash -l -c "echo 'deb http://packages.dotdeb.org wheezy-php55 all' ${'\\'}
+    >> /etc/apt/sources.list.d/dotdeb.list"
+RUN /bin/bash -l -c "echo 'deb-src http://packages.dotdeb.org wheezy-php55 all' ${'\\'}
+    >> /etc/apt/sources.list.d/dotdeb.list"
+RUN wget http://www.dotdeb.org/dotdeb.gpg -O- | apt-key add -
+
+RUN apt-get update && apt-get install -y ${'\\'}
+    git php5 php5-dev phpunit unzip
diff --git a/templates/tools/dockerfile/python_deps.include b/templates/tools/dockerfile/python_deps.include
new file mode 100644
index 0000000..a559f96
--- /dev/null
+++ b/templates/tools/dockerfile/python_deps.include
@@ -0,0 +1,14 @@
+#====================
+# Python dependencies
+
+# Install dependencies
+
+RUN apt-get update && apt-get install -y ${'\\'}
+    python-all-dev ${'\\'}
+    python3-all-dev ${'\\'}
+    python-pip
+
+# 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.0.0a2 tox
diff --git a/templates/tools/dockerfile/ruby_deps.include b/templates/tools/dockerfile/ruby_deps.include
new file mode 100644
index 0000000..a8ee3ec
--- /dev/null
+++ b/templates/tools/dockerfile/ruby_deps.include
@@ -0,0 +1,14 @@
+#==================
+# Ruby dependencies
+
+# Install rvm
+RUN gpg --keyserver hkp://keys.gnupg.net --recv-keys 409B6B1796C275462A1703113804BB82D39DC0E3
+RUN \curl -sSL https://get.rvm.io | bash -s stable
+
+# Install Ruby 2.1
+RUN /bin/bash -l -c "rvm install ruby-2.1"
+RUN /bin/bash -l -c "rvm use --default ruby-2.1"
+RUN /bin/bash -l -c "echo 'gem: --no-ri --no-rdoc' > ~/.gemrc"
+RUN /bin/bash -l -c "echo 'export PATH=/usr/local/rvm/bin:$PATH' >> ~/.bashrc"
+RUN /bin/bash -l -c "echo 'rvm --default use ruby-2.1' >> ~/.bashrc"
+RUN /bin/bash -l -c "gem install bundler --no-ri --no-rdoc"
diff --git a/templates/tools/dockerfile/run_tests_addons.include b/templates/tools/dockerfile/run_tests_addons.include
new file mode 100644
index 0000000..27ac67f
--- /dev/null
+++ b/templates/tools/dockerfile/run_tests_addons.include
@@ -0,0 +1,7 @@
+<%include file="ccache_setup.include"/>
+#======================
+# Zookeeper dependencies
+# TODO(jtattermusch): is zookeeper still needed?
+RUN apt-get install -y libzookeeper-mt-dev
+
+RUN mkdir /var/local/jenkins
diff --git a/templates/tools/dockerfile/test/csharp_jessie_x64/Dockerfile.template b/templates/tools/dockerfile/test/csharp_jessie_x64/Dockerfile.template
new file mode 100644
index 0000000..1c01dea
--- /dev/null
+++ b/templates/tools/dockerfile/test/csharp_jessie_x64/Dockerfile.template
@@ -0,0 +1,39 @@
+%YAML 1.2
+--- |
+  # Copyright 2015-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.
+  
+  FROM debian:jessie
+  
+  <%include file="../../apt_get_basic.include"/>
+  <%include file="../../csharp_deps.include"/>
+  <%include file="../../run_tests_addons.include"/>
+  # Define the default command.
+  CMD ["bash"]
+  
diff --git a/templates/tools/dockerfile/test/cxx_jessie_x64/Dockerfile.template b/templates/tools/dockerfile/test/cxx_jessie_x64/Dockerfile.template
new file mode 100644
index 0000000..842c534
--- /dev/null
+++ b/templates/tools/dockerfile/test/cxx_jessie_x64/Dockerfile.template
@@ -0,0 +1,39 @@
+%YAML 1.2
+--- |
+  # Copyright 2015-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.
+  
+  FROM debian:jessie
+  
+  <%include file="../../apt_get_basic.include"/>
+  <%include file="../../cxx_deps.include"/>
+  <%include file="../../run_tests_addons.include"/>
+  # Define the default command.
+  CMD ["bash"]
+  
\ No newline at end of file
diff --git a/templates/tools/dockerfile/test/cxx_jessie_x86/Dockerfile.template b/templates/tools/dockerfile/test/cxx_jessie_x86/Dockerfile.template
new file mode 100644
index 0000000..4e95cdd
--- /dev/null
+++ b/templates/tools/dockerfile/test/cxx_jessie_x86/Dockerfile.template
@@ -0,0 +1,39 @@
+%YAML 1.2
+--- |
+  # Copyright 2015-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.
+  
+  FROM 32bit/debian:jessie
+  
+  <%include file="../../apt_get_basic.include"/>
+  <%include file="../../cxx_deps.include"/>
+  <%include file="../../run_tests_addons.include"/>
+  # Define the default command.
+  CMD ["bash"]
+  
\ No newline at end of file
diff --git a/templates/tools/dockerfile/test/node_jessie_x64/Dockerfile.template b/templates/tools/dockerfile/test/node_jessie_x64/Dockerfile.template
new file mode 100644
index 0000000..10551a5
--- /dev/null
+++ b/templates/tools/dockerfile/test/node_jessie_x64/Dockerfile.template
@@ -0,0 +1,39 @@
+%YAML 1.2
+--- |
+  # Copyright 2015-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.
+  
+  FROM debian:jessie
+  
+  <%include file="../../apt_get_basic.include"/>
+  <%include file="../../node_deps.include"/>
+  <%include file="../../run_tests_addons.include"/>
+  # Define the default command.
+  CMD ["bash"]
+  
\ No newline at end of file
diff --git a/templates/tools/dockerfile/test/php_jessie_x64/Dockerfile.template b/templates/tools/dockerfile/test/php_jessie_x64/Dockerfile.template
new file mode 100644
index 0000000..d717239
--- /dev/null
+++ b/templates/tools/dockerfile/test/php_jessie_x64/Dockerfile.template
@@ -0,0 +1,39 @@
+%YAML 1.2
+--- |
+  # Copyright 2015-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.
+  
+  FROM debian:jessie
+  
+  <%include file="../../apt_get_basic.include"/>
+  <%include file="../../php_deps.include"/>
+  <%include file="../../run_tests_addons.include"/>
+  # Define the default command.
+  CMD ["bash"]
+  
\ No newline at end of file
diff --git a/templates/tools/dockerfile/test/python_jessie_x64/Dockerfile.template b/templates/tools/dockerfile/test/python_jessie_x64/Dockerfile.template
new file mode 100644
index 0000000..9e68b3e
--- /dev/null
+++ b/templates/tools/dockerfile/test/python_jessie_x64/Dockerfile.template
@@ -0,0 +1,39 @@
+%YAML 1.2
+--- |
+  # Copyright 2015-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.
+  
+  FROM debian:jessie
+  
+  <%include file="../../apt_get_basic.include"/>
+  <%include file="../../python_deps.include"/>
+  <%include file="../../run_tests_addons.include"/>
+  # Define the default command.
+  CMD ["bash"]
+  
\ No newline at end of file
diff --git a/templates/tools/dockerfile/test/ruby_jessie_x64/Dockerfile.template b/templates/tools/dockerfile/test/ruby_jessie_x64/Dockerfile.template
new file mode 100644
index 0000000..db777be
--- /dev/null
+++ b/templates/tools/dockerfile/test/ruby_jessie_x64/Dockerfile.template
@@ -0,0 +1,39 @@
+%YAML 1.2
+--- |
+  # Copyright 2015-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.
+  
+  FROM debian:jessie
+  
+  <%include file="../../apt_get_basic.include"/>
+  <%include file="../../ruby_deps.include"/>
+  <%include file="../../run_tests_addons.include"/>
+  # Define the default command.
+  CMD ["bash"]
+  
\ No newline at end of file
diff --git a/templates/tools/dockerfile/test/sanity/Dockerfile.template b/templates/tools/dockerfile/test/sanity/Dockerfile.template
new file mode 100644
index 0000000..ad1d92e
--- /dev/null
+++ b/templates/tools/dockerfile/test/sanity/Dockerfile.template
@@ -0,0 +1,52 @@
+%YAML 1.2
+--- |
+  # Copyright 2015-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.
+  
+  FROM debian:jessie
+  
+  <%include file="../../apt_get_basic.include"/>
+  #========================
+  # Sanity test dependencies
+  RUN apt-get update && apt-get install -y python-pip
+  RUN pip install simplejson mako
+
+  #===================
+  # Docker "inception"
+  # Note this is quite the ugly hack.
+  # This makes sure that the docker binary we inject has its dependencies.
+  RUN apt-get install libsystemd-journal0
+  RUN curl https://get.docker.com/ | sh
+  RUN apt-get remove --purge -y docker-engine
+  
+  RUN mkdir /var/local/jenkins
+  
+  # Define the default command.
+  CMD ["bash"]
+  
diff --git a/templates/tools/doxygen/Doxyfile.include b/templates/tools/doxygen/Doxyfile.include
index 21ef8a8..8b0c528 100644
--- a/templates/tools/doxygen/Doxyfile.include
+++ b/templates/tools/doxygen/Doxyfile.include
@@ -57,7 +57,7 @@
 # could be handy for archiving the generated documentation or if some version
 # control system is used.
 
-PROJECT_NUMBER         = ${settings.version.major}.${settings.version.minor}.${settings.version.micro}.${settings.version.build}
+PROJECT_NUMBER         = ${settings.core_version if packagename=='Core' else settings.cpp_version}
 
 # Using the PROJECT_BRIEF tag one can provide an optional one line description
 # for a project that appears at the top of each page and should give viewer a
diff --git a/test/core/bad_client/bad_client.c b/test/core/bad_client/bad_client.c
index 832570a..1a2ca6f 100644
--- a/test/core/bad_client/bad_client.c
+++ b/test/core/bad_client/bad_client.c
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -60,7 +60,7 @@
   gpr_event_set(&a->done_thd, (void *)1);
 }
 
-static void done_write(grpc_exec_ctx *exec_ctx, void *arg, int success) {
+static void done_write(grpc_exec_ctx *exec_ctx, void *arg, bool success) {
   thd_args *a = arg;
   gpr_event_set(&a->done_write, (void *)1);
 }
diff --git a/test/core/census/context_test.c b/test/core/census/context_test.c
new file mode 100644
index 0000000..63e7103
--- /dev/null
+++ b/test/core/census/context_test.c
@@ -0,0 +1,373 @@
+/*
+ *
+ * Copyright 2015-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.
+ *
+ */
+
+// Test census_context functions, including encoding/decoding
+
+#include <grpc/census.h>
+#include <grpc/support/log.h>
+#include <grpc/support/time.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "test/core/util/test_config.h"
+
+static uint8_t one_byte_val = 7;
+static uint32_t four_byte_val = 0x12345678;
+static uint64_t eight_byte_val = 0x1234567890abcdef;
+
+// A set of tags Used to create a basic context for testing. Each tag has a
+// unique set of flags. Note that replace_add_delete_test() relies on specific
+// offsets into this array - if you add or delete entries, you will also need
+// to change the test.
+#define BASIC_TAG_COUNT 8
+static census_tag basic_tags[BASIC_TAG_COUNT] = {
+    /* 0 */ {"key0", "printable", 10, 0},
+    /* 1 */ {"k1", "a", 2, CENSUS_TAG_PROPAGATE},
+    /* 2 */ {"k2", "longer printable string", 24, CENSUS_TAG_STATS},
+    /* 3 */ {"key_three", (char *)&one_byte_val, 1, CENSUS_TAG_BINARY},
+    /* 4 */ {"really_long_key_4", "random", 7,
+             CENSUS_TAG_PROPAGATE | CENSUS_TAG_STATS},
+    /* 5 */ {"k5", (char *)&four_byte_val, 4,
+             CENSUS_TAG_PROPAGATE | CENSUS_TAG_BINARY},
+    /* 6 */ {"k6", (char *)&eight_byte_val, 8,
+             CENSUS_TAG_STATS | CENSUS_TAG_BINARY},
+    /* 7 */ {"k7", (char *)&four_byte_val, 4,
+             CENSUS_TAG_PROPAGATE | CENSUS_TAG_STATS | CENSUS_TAG_BINARY}};
+
+// Set of tags used to modify the basic context. Note that
+// replace_add_delete_test() relies on specific offsets into this array - if
+// you add or delete entries, you will also need to change the test. Other
+// tests that rely on specific instances have XXX_XXX_OFFSET definitions (also
+// change the defines below if you add/delete entires).
+#define MODIFY_TAG_COUNT 11
+static census_tag modify_tags[MODIFY_TAG_COUNT] = {
+#define REPLACE_VALUE_OFFSET 0
+    /* 0 */ {"key0", "replace printable", 18, 0},  // replaces tag value only
+#define ADD_TAG_OFFSET 1
+    /* 1 */ {"new_key", "xyzzy", 6, CENSUS_TAG_STATS},  // new tag
+#define DELETE_TAG_OFFSET 2
+    /* 2 */ {"k5", NULL, 5,
+             0},  // should delete tag, despite bogus value length
+    /* 3 */ {"k6", "foo", 0, 0},  // should delete tag, despite bogus value
+    /* 4 */ {"k6", "foo", 0, 0},  // try deleting already-deleted tag
+    /* 5 */ {"non-existent", NULL, 0, 0},  // another non-existent tag
+#define REPLACE_FLAG_OFFSET 6
+    /* 6 */ {"k1", "a", 2, 0},                   // change flags only
+    /* 7 */ {"k7", "bar", 4, CENSUS_TAG_STATS},  // change flags and value
+    /* 8 */ {"k2", (char *)&eight_byte_val, 8,
+             CENSUS_TAG_BINARY | CENSUS_TAG_PROPAGATE},  // more flags change
+                                                         // non-binary -> binary
+    /* 9 */ {"k6", "bar", 4, 0},  // add back tag, with different value
+    /* 10 */ {"foo", "bar", 4, CENSUS_TAG_PROPAGATE},  // another new tag
+};
+
+// Utility function to compare tags. Returns true if all fields match.
+static bool compare_tag(const census_tag *t1, const census_tag *t2) {
+  return (strcmp(t1->key, t2->key) == 0 && t1->value_len == t2->value_len &&
+          memcmp(t1->value, t2->value, t1->value_len) == 0 &&
+          t1->flags == t2->flags);
+}
+
+// Utility function to validate a tag exists in context.
+static bool validate_tag(const census_context *context, const census_tag *tag) {
+  census_tag tag2;
+  if (census_context_get_tag(context, tag->key, &tag2) != 1) return false;
+  return compare_tag(tag, &tag2);
+}
+
+// Create an empty context.
+static void empty_test(void) {
+  struct census_context *context = census_context_create(NULL, NULL, 0, NULL);
+  GPR_ASSERT(context != NULL);
+  const census_context_status *status = census_context_get_status(context);
+  census_context_status expected = {0, 0, 0, 0, 0, 0, 0, 0};
+  GPR_ASSERT(memcmp(status, &expected, sizeof(expected)) == 0);
+  census_context_destroy(context);
+}
+
+// Test create and iteration over basic context.
+static void basic_test(void) {
+  const census_context_status *status;
+  struct census_context *context =
+      census_context_create(NULL, basic_tags, BASIC_TAG_COUNT, &status);
+  census_context_status expected = {2, 2, 4, 0, 8, 0, 0, 0};
+  GPR_ASSERT(memcmp(status, &expected, sizeof(expected)) == 0);
+  census_context_iterator it;
+  census_context_initialize_iterator(context, &it);
+  census_tag tag;
+  while (census_context_next_tag(&it, &tag)) {
+    // can't rely on tag return order: make sure it matches exactly one.
+    int matches = 0;
+    for (int i = 0; i < BASIC_TAG_COUNT; i++) {
+      if (compare_tag(&tag, &basic_tags[i])) matches++;
+    }
+    GPR_ASSERT(matches == 1);
+  }
+  census_context_destroy(context);
+}
+
+// Test census_context_get_tag().
+static void lookup_by_key_test(void) {
+  struct census_context *context =
+      census_context_create(NULL, basic_tags, BASIC_TAG_COUNT, NULL);
+  census_tag tag;
+  for (int i = 0; i < BASIC_TAG_COUNT; i++) {
+    GPR_ASSERT(census_context_get_tag(context, basic_tags[i].key, &tag) == 1);
+    GPR_ASSERT(compare_tag(&tag, &basic_tags[i]));
+  }
+  // non-existent keys
+  GPR_ASSERT(census_context_get_tag(context, "key", &tag) == 0);
+  GPR_ASSERT(census_context_get_tag(context, "key01", &tag) == 0);
+  GPR_ASSERT(census_context_get_tag(context, "k9", &tag) == 0);
+  GPR_ASSERT(census_context_get_tag(context, "random", &tag) == 0);
+  GPR_ASSERT(census_context_get_tag(context, "", &tag) == 0);
+  census_context_destroy(context);
+}
+
+// Try creating context with invalid entries.
+static void invalid_test(void) {
+  char key[300];
+  memset(key, 'k', 299);
+  key[299] = 0;
+  char value[300];
+  memset(value, 'v', 300);
+  census_tag tag = {key, value, 3, CENSUS_TAG_BINARY};
+  // long keys, short value. Key lengths (including terminator) should be
+  // <= 255 (CENSUS_MAX_TAG_KV_LEN)
+  GPR_ASSERT(strlen(key) == 299);
+  const census_context_status *status;
+  struct census_context *context =
+      census_context_create(NULL, &tag, 1, &status);
+  census_context_status expected = {0, 0, 0, 0, 0, 0, 1, 0};
+  GPR_ASSERT(memcmp(status, &expected, sizeof(expected)) == 0);
+  census_context_destroy(context);
+  key[CENSUS_MAX_TAG_KV_LEN] = 0;
+  GPR_ASSERT(strlen(key) == CENSUS_MAX_TAG_KV_LEN);
+  context = census_context_create(NULL, &tag, 1, &status);
+  GPR_ASSERT(memcmp(status, &expected, sizeof(expected)) == 0);
+  census_context_destroy(context);
+  key[CENSUS_MAX_TAG_KV_LEN - 1] = 0;
+  GPR_ASSERT(strlen(key) == CENSUS_MAX_TAG_KV_LEN - 1);
+  context = census_context_create(NULL, &tag, 1, &status);
+  census_context_status expected2 = {0, 0, 1, 0, 1, 0, 0, 0};
+  GPR_ASSERT(memcmp(status, &expected2, sizeof(expected2)) == 0);
+  census_context_destroy(context);
+  // now try with long values
+  tag.value_len = 300;
+  context = census_context_create(NULL, &tag, 1, &status);
+  GPR_ASSERT(memcmp(status, &expected, sizeof(expected)) == 0);
+  census_context_destroy(context);
+  tag.value_len = CENSUS_MAX_TAG_KV_LEN + 1;
+  context = census_context_create(NULL, &tag, 1, &status);
+  GPR_ASSERT(memcmp(status, &expected, sizeof(expected)) == 0);
+  census_context_destroy(context);
+  tag.value_len = CENSUS_MAX_TAG_KV_LEN;
+  context = census_context_create(NULL, &tag, 1, &status);
+  GPR_ASSERT(memcmp(status, &expected2, sizeof(expected2)) == 0);
+  census_context_destroy(context);
+  // 0 length key.
+  key[0] = 0;
+  context = census_context_create(NULL, &tag, 1, &status);
+  GPR_ASSERT(memcmp(status, &expected, sizeof(expected)) == 0);
+  census_context_destroy(context);
+}
+
+// Make a copy of a context
+static void copy_test(void) {
+  struct census_context *context =
+      census_context_create(NULL, basic_tags, BASIC_TAG_COUNT, NULL);
+  const census_context_status *status;
+  struct census_context *context2 =
+      census_context_create(context, NULL, 0, &status);
+  census_context_status expected = {2, 2, 4, 0, 0, 0, 0, 0};
+  GPR_ASSERT(memcmp(status, &expected, sizeof(expected)) == 0);
+  for (int i = 0; i < BASIC_TAG_COUNT; i++) {
+    census_tag tag;
+    GPR_ASSERT(census_context_get_tag(context2, basic_tags[i].key, &tag) == 1);
+    GPR_ASSERT(compare_tag(&tag, &basic_tags[i]));
+  }
+  census_context_destroy(context);
+  census_context_destroy(context2);
+}
+
+// replace a single tag value
+static void replace_value_test(void) {
+  struct census_context *context =
+      census_context_create(NULL, basic_tags, BASIC_TAG_COUNT, NULL);
+  const census_context_status *status;
+  struct census_context *context2 = census_context_create(
+      context, modify_tags + REPLACE_VALUE_OFFSET, 1, &status);
+  census_context_status expected = {2, 2, 4, 0, 0, 1, 0, 0};
+  GPR_ASSERT(memcmp(status, &expected, sizeof(expected)) == 0);
+  census_tag tag;
+  GPR_ASSERT(census_context_get_tag(
+                 context2, modify_tags[REPLACE_VALUE_OFFSET].key, &tag) == 1);
+  GPR_ASSERT(compare_tag(&tag, &modify_tags[REPLACE_VALUE_OFFSET]));
+  census_context_destroy(context);
+  census_context_destroy(context2);
+}
+
+// replace a single tags flags
+static void replace_flags_test(void) {
+  struct census_context *context =
+      census_context_create(NULL, basic_tags, BASIC_TAG_COUNT, NULL);
+  const census_context_status *status;
+  struct census_context *context2 = census_context_create(
+      context, modify_tags + REPLACE_FLAG_OFFSET, 1, &status);
+  census_context_status expected = {1, 2, 5, 0, 0, 1, 0, 0};
+  GPR_ASSERT(memcmp(status, &expected, sizeof(expected)) == 0);
+  census_tag tag;
+  GPR_ASSERT(census_context_get_tag(
+                 context2, modify_tags[REPLACE_FLAG_OFFSET].key, &tag) == 1);
+  GPR_ASSERT(compare_tag(&tag, &modify_tags[REPLACE_FLAG_OFFSET]));
+  census_context_destroy(context);
+  census_context_destroy(context2);
+}
+
+// delete a single tag.
+static void delete_tag_test(void) {
+  struct census_context *context =
+      census_context_create(NULL, basic_tags, BASIC_TAG_COUNT, NULL);
+  const census_context_status *status;
+  struct census_context *context2 = census_context_create(
+      context, modify_tags + DELETE_TAG_OFFSET, 1, &status);
+  census_context_status expected = {2, 1, 4, 1, 0, 0, 0, 0};
+  GPR_ASSERT(memcmp(status, &expected, sizeof(expected)) == 0);
+  census_tag tag;
+  GPR_ASSERT(census_context_get_tag(
+                 context2, modify_tags[DELETE_TAG_OFFSET].key, &tag) == 0);
+  census_context_destroy(context);
+  census_context_destroy(context2);
+}
+
+// add a single new tag.
+static void add_tag_test(void) {
+  struct census_context *context =
+      census_context_create(NULL, basic_tags, BASIC_TAG_COUNT, NULL);
+  const census_context_status *status;
+  struct census_context *context2 =
+      census_context_create(context, modify_tags + ADD_TAG_OFFSET, 1, &status);
+  census_context_status expected = {2, 2, 5, 0, 1, 0, 0, 0};
+  GPR_ASSERT(memcmp(status, &expected, sizeof(expected)) == 0);
+  census_tag tag;
+  GPR_ASSERT(census_context_get_tag(context2, modify_tags[ADD_TAG_OFFSET].key,
+                                    &tag) == 1);
+  GPR_ASSERT(compare_tag(&tag, &modify_tags[ADD_TAG_OFFSET]));
+  census_context_destroy(context);
+  census_context_destroy(context2);
+}
+
+// test many changes at once.
+static void replace_add_delete_test(void) {
+  struct census_context *context =
+      census_context_create(NULL, basic_tags, BASIC_TAG_COUNT, NULL);
+  const census_context_status *status;
+  struct census_context *context2 =
+      census_context_create(context, modify_tags, MODIFY_TAG_COUNT, &status);
+  census_context_status expected = {2, 1, 6, 2, 3, 4, 0, 2};
+  GPR_ASSERT(memcmp(status, &expected, sizeof(expected)) == 0);
+  // validate context contents. Use specific indices into the two arrays
+  // holding tag values.
+  GPR_ASSERT(validate_tag(context2, &basic_tags[3]));
+  GPR_ASSERT(validate_tag(context2, &basic_tags[4]));
+  GPR_ASSERT(validate_tag(context2, &modify_tags[0]));
+  GPR_ASSERT(validate_tag(context2, &modify_tags[1]));
+  GPR_ASSERT(validate_tag(context2, &modify_tags[6]));
+  GPR_ASSERT(validate_tag(context2, &modify_tags[7]));
+  GPR_ASSERT(validate_tag(context2, &modify_tags[8]));
+  GPR_ASSERT(validate_tag(context2, &modify_tags[9]));
+  GPR_ASSERT(validate_tag(context2, &modify_tags[10]));
+  GPR_ASSERT(!validate_tag(context2, &basic_tags[0]));
+  GPR_ASSERT(!validate_tag(context2, &basic_tags[1]));
+  GPR_ASSERT(!validate_tag(context2, &basic_tags[2]));
+  GPR_ASSERT(!validate_tag(context2, &basic_tags[5]));
+  GPR_ASSERT(!validate_tag(context2, &basic_tags[6]));
+  GPR_ASSERT(!validate_tag(context2, &basic_tags[7]));
+  census_context_destroy(context);
+  census_context_destroy(context2);
+}
+
+#define BUF_SIZE 200
+
+// test encode/decode.
+static void encode_decode_test(void) {
+  char buffer[BUF_SIZE];
+  struct census_context *context =
+      census_context_create(NULL, basic_tags, BASIC_TAG_COUNT, NULL);
+  size_t print_bsize;
+  size_t bin_bsize;
+  // Test with too small a buffer
+  GPR_ASSERT(census_context_encode(context, buffer, 2, &print_bsize,
+                                   &bin_bsize) == NULL);
+  char *b_buffer = census_context_encode(context, buffer, BUF_SIZE,
+                                         &print_bsize, &bin_bsize);
+  GPR_ASSERT(b_buffer != NULL && print_bsize > 0 && bin_bsize > 0 &&
+             print_bsize + bin_bsize <= BUF_SIZE &&
+             b_buffer == buffer + print_bsize);
+  census_context *context2 =
+      census_context_decode(buffer, print_bsize, b_buffer, bin_bsize);
+  GPR_ASSERT(context2 != NULL);
+  const census_context_status *status = census_context_get_status(context2);
+  census_context_status expected = {2, 2, 0, 0, 0, 0, 0, 0};
+  GPR_ASSERT(memcmp(status, &expected, sizeof(expected)) == 0);
+  for (int i = 0; i < BASIC_TAG_COUNT; i++) {
+    census_tag tag;
+    if (CENSUS_TAG_IS_PROPAGATED(basic_tags[i].flags)) {
+      GPR_ASSERT(census_context_get_tag(context2, basic_tags[i].key, &tag) ==
+                 1);
+      GPR_ASSERT(compare_tag(&tag, &basic_tags[i]));
+    } else {
+      GPR_ASSERT(census_context_get_tag(context2, basic_tags[i].key, &tag) ==
+                 0);
+    }
+  }
+  census_context_destroy(context2);
+  census_context_destroy(context);
+}
+
+int main(int argc, char *argv[]) {
+  grpc_test_init(argc, argv);
+  empty_test();
+  basic_test();
+  lookup_by_key_test();
+  invalid_test();
+  copy_test();
+  replace_value_test();
+  replace_flags_test();
+  delete_tag_test();
+  add_tag_test();
+  replace_add_delete_test();
+  encode_decode_test();
+  return 0;
+}
diff --git a/test/core/census/tag_set_test.c b/test/core/census/tag_set_test.c
deleted file mode 100644
index 1056e98..0000000
--- a/test/core/census/tag_set_test.c
+++ /dev/null
@@ -1,375 +0,0 @@
-/*
- *
- * Copyright 2015-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.
- *
- */
-
-// Test census_tag_set functions, including encoding/decoding
-
-#include <grpc/census.h>
-#include <grpc/support/log.h>
-#include <grpc/support/time.h>
-#include <stdbool.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include "test/core/util/test_config.h"
-
-static uint8_t one_byte_val = 7;
-static uint32_t four_byte_val = 0x12345678;
-static uint64_t eight_byte_val = 0x1234567890abcdef;
-
-// A set of tags Used to create a basic tag_set for testing. Each tag has a
-// unique set of flags. Note that replace_add_delete_test() relies on specific
-// offsets into this array - if you add or delete entries, you will also need
-// to change the test.
-#define BASIC_TAG_COUNT 8
-static census_tag basic_tags[BASIC_TAG_COUNT] = {
-    /* 0 */ {"key0", "printable", 10, 0},
-    /* 1 */ {"k1", "a", 2, CENSUS_TAG_PROPAGATE},
-    /* 2 */ {"k2", "longer printable string", 24, CENSUS_TAG_STATS},
-    /* 3 */ {"key_three", (char *)&one_byte_val, 1, CENSUS_TAG_BINARY},
-    /* 4 */ {"really_long_key_4", "random", 7,
-             CENSUS_TAG_PROPAGATE | CENSUS_TAG_STATS},
-    /* 5 */ {"k5", (char *)&four_byte_val, 4,
-             CENSUS_TAG_PROPAGATE | CENSUS_TAG_BINARY},
-    /* 6 */ {"k6", (char *)&eight_byte_val, 8,
-             CENSUS_TAG_STATS | CENSUS_TAG_BINARY},
-    /* 7 */ {"k7", (char *)&four_byte_val, 4,
-             CENSUS_TAG_PROPAGATE | CENSUS_TAG_STATS | CENSUS_TAG_BINARY}};
-
-// Set of tags used to modify the basic tag_set. Note that
-// replace_add_delete_test() relies on specific offsets into this array - if
-// you add or delete entries, you will also need to change the test. Other
-// tests that rely on specific instances have XXX_XXX_OFFSET definitions (also
-// change the defines below if you add/delete entires).
-#define MODIFY_TAG_COUNT 11
-static census_tag modify_tags[MODIFY_TAG_COUNT] = {
-#define REPLACE_VALUE_OFFSET 0
-    /* 0 */ {"key0", "replace printable", 18, 0},  // replaces tag value only
-#define ADD_TAG_OFFSET 1
-    /* 1 */ {"new_key", "xyzzy", 6, CENSUS_TAG_STATS},  // new tag
-#define DELETE_TAG_OFFSET 2
-    /* 2 */ {"k5", NULL, 5,
-             0},  // should delete tag, despite bogus value length
-    /* 3 */ {"k6", "foo", 0, 0},  // should delete tag, despite bogus value
-    /* 4 */ {"k6", "foo", 0, 0},  // try deleting already-deleted tag
-    /* 5 */ {"non-existent", NULL, 0, 0},  // another non-existent tag
-#define REPLACE_FLAG_OFFSET 6
-    /* 6 */ {"k1", "a", 2, 0},                   // change flags only
-    /* 7 */ {"k7", "bar", 4, CENSUS_TAG_STATS},  // change flags and value
-    /* 8 */ {"k2", (char *)&eight_byte_val, 8,
-             CENSUS_TAG_BINARY | CENSUS_TAG_PROPAGATE},  // more flags change
-                                                         // non-binary -> binary
-    /* 9 */ {"k6", "bar", 4, 0},  // add back tag, with different value
-    /* 10 */ {"foo", "bar", 4, CENSUS_TAG_PROPAGATE},  // another new tag
-};
-
-// Utility function to compare tags. Returns true if all fields match.
-static bool compare_tag(const census_tag *t1, const census_tag *t2) {
-  return (strcmp(t1->key, t2->key) == 0 && t1->value_len == t2->value_len &&
-          memcmp(t1->value, t2->value, t1->value_len) == 0 &&
-          t1->flags == t2->flags);
-}
-
-// Utility function to validate a tag exists in tag set.
-static bool validate_tag(const census_tag_set *cts, const census_tag *tag) {
-  census_tag tag2;
-  if (census_tag_set_get_tag_by_key(cts, tag->key, &tag2) != 1) return false;
-  return compare_tag(tag, &tag2);
-}
-
-// Create an empty tag_set.
-static void empty_test(void) {
-  struct census_tag_set *cts = census_tag_set_create(NULL, NULL, 0, NULL);
-  GPR_ASSERT(cts != NULL);
-  const census_tag_set_create_status *status =
-      census_tag_set_get_create_status(cts);
-  census_tag_set_create_status expected = {0, 0, 0, 0, 0, 0, 0, 0};
-  GPR_ASSERT(memcmp(status, &expected, sizeof(expected)) == 0);
-  census_tag_set_destroy(cts);
-}
-
-// Test create and iteration over basic tag set.
-static void basic_test(void) {
-  const census_tag_set_create_status *status;
-  struct census_tag_set *cts =
-      census_tag_set_create(NULL, basic_tags, BASIC_TAG_COUNT, &status);
-  census_tag_set_create_status expected = {2, 2, 4, 0, 8, 0, 0, 0};
-  GPR_ASSERT(memcmp(status, &expected, sizeof(expected)) == 0);
-  census_tag_set_iterator it;
-  census_tag_set_initialize_iterator(cts, &it);
-  census_tag tag;
-  while (census_tag_set_next_tag(&it, &tag)) {
-    // can't rely on tag return order: make sure it matches exactly one.
-    int matches = 0;
-    for (int i = 0; i < BASIC_TAG_COUNT; i++) {
-      if (compare_tag(&tag, &basic_tags[i])) matches++;
-    }
-    GPR_ASSERT(matches == 1);
-  }
-  census_tag_set_destroy(cts);
-}
-
-// Test that census_tag_set_get_tag_by_key().
-static void lookup_by_key_test(void) {
-  struct census_tag_set *cts =
-      census_tag_set_create(NULL, basic_tags, BASIC_TAG_COUNT, NULL);
-  census_tag tag;
-  for (int i = 0; i < BASIC_TAG_COUNT; i++) {
-    GPR_ASSERT(census_tag_set_get_tag_by_key(cts, basic_tags[i].key, &tag) ==
-               1);
-    GPR_ASSERT(compare_tag(&tag, &basic_tags[i]));
-  }
-  // non-existent keys
-  GPR_ASSERT(census_tag_set_get_tag_by_key(cts, "key", &tag) == 0);
-  GPR_ASSERT(census_tag_set_get_tag_by_key(cts, "key01", &tag) == 0);
-  GPR_ASSERT(census_tag_set_get_tag_by_key(cts, "k9", &tag) == 0);
-  GPR_ASSERT(census_tag_set_get_tag_by_key(cts, "random", &tag) == 0);
-  GPR_ASSERT(census_tag_set_get_tag_by_key(cts, "", &tag) == 0);
-  census_tag_set_destroy(cts);
-}
-
-// Try creating tag set with invalid entries.
-static void invalid_test(void) {
-  char key[300];
-  memset(key, 'k', 299);
-  key[299] = 0;
-  char value[300];
-  memset(value, 'v', 300);
-  census_tag tag = {key, value, 3, CENSUS_TAG_BINARY};
-  // long keys, short value. Key lengths (including terminator) should be
-  // <= 255 (CENSUS_MAX_TAG_KV_LEN)
-  GPR_ASSERT(strlen(key) == 299);
-  const census_tag_set_create_status *status;
-  struct census_tag_set *cts = census_tag_set_create(NULL, &tag, 1, &status);
-  census_tag_set_create_status expected = {0, 0, 0, 0, 0, 0, 1, 0};
-  GPR_ASSERT(memcmp(status, &expected, sizeof(expected)) == 0);
-  census_tag_set_destroy(cts);
-  key[CENSUS_MAX_TAG_KV_LEN] = 0;
-  GPR_ASSERT(strlen(key) == CENSUS_MAX_TAG_KV_LEN);
-  cts = census_tag_set_create(NULL, &tag, 1, &status);
-  GPR_ASSERT(memcmp(status, &expected, sizeof(expected)) == 0);
-  census_tag_set_destroy(cts);
-  key[CENSUS_MAX_TAG_KV_LEN - 1] = 0;
-  GPR_ASSERT(strlen(key) == CENSUS_MAX_TAG_KV_LEN - 1);
-  cts = census_tag_set_create(NULL, &tag, 1, &status);
-  census_tag_set_create_status expected2 = {0, 0, 1, 0, 1, 0, 0, 0};
-  GPR_ASSERT(memcmp(status, &expected2, sizeof(expected2)) == 0);
-  census_tag_set_destroy(cts);
-  // now try with long values
-  tag.value_len = 300;
-  cts = census_tag_set_create(NULL, &tag, 1, &status);
-  GPR_ASSERT(memcmp(status, &expected, sizeof(expected)) == 0);
-  census_tag_set_destroy(cts);
-  tag.value_len = CENSUS_MAX_TAG_KV_LEN + 1;
-  cts = census_tag_set_create(NULL, &tag, 1, &status);
-  GPR_ASSERT(memcmp(status, &expected, sizeof(expected)) == 0);
-  census_tag_set_destroy(cts);
-  tag.value_len = CENSUS_MAX_TAG_KV_LEN;
-  cts = census_tag_set_create(NULL, &tag, 1, &status);
-  GPR_ASSERT(memcmp(status, &expected2, sizeof(expected2)) == 0);
-  census_tag_set_destroy(cts);
-  // 0 length key.
-  key[0] = 0;
-  cts = census_tag_set_create(NULL, &tag, 1, &status);
-  GPR_ASSERT(memcmp(status, &expected, sizeof(expected)) == 0);
-  census_tag_set_destroy(cts);
-}
-
-// Make a copy of a tag set
-static void copy_test(void) {
-  struct census_tag_set *cts =
-      census_tag_set_create(NULL, basic_tags, BASIC_TAG_COUNT, NULL);
-  const census_tag_set_create_status *status;
-  struct census_tag_set *cts2 = census_tag_set_create(cts, NULL, 0, &status);
-  census_tag_set_create_status expected = {2, 2, 4, 0, 0, 0, 0, 0};
-  GPR_ASSERT(memcmp(status, &expected, sizeof(expected)) == 0);
-  for (int i = 0; i < BASIC_TAG_COUNT; i++) {
-    census_tag tag;
-    GPR_ASSERT(census_tag_set_get_tag_by_key(cts2, basic_tags[i].key, &tag) ==
-               1);
-    GPR_ASSERT(compare_tag(&tag, &basic_tags[i]));
-  }
-  census_tag_set_destroy(cts);
-  census_tag_set_destroy(cts2);
-}
-
-// replace a single tag value
-static void replace_value_test(void) {
-  struct census_tag_set *cts =
-      census_tag_set_create(NULL, basic_tags, BASIC_TAG_COUNT, NULL);
-  const census_tag_set_create_status *status;
-  struct census_tag_set *cts2 = census_tag_set_create(
-      cts, modify_tags + REPLACE_VALUE_OFFSET, 1, &status);
-  census_tag_set_create_status expected = {2, 2, 4, 0, 0, 1, 0, 0};
-  GPR_ASSERT(memcmp(status, &expected, sizeof(expected)) == 0);
-  census_tag tag;
-  GPR_ASSERT(census_tag_set_get_tag_by_key(
-                 cts2, modify_tags[REPLACE_VALUE_OFFSET].key, &tag) == 1);
-  GPR_ASSERT(compare_tag(&tag, &modify_tags[REPLACE_VALUE_OFFSET]));
-  census_tag_set_destroy(cts);
-  census_tag_set_destroy(cts2);
-}
-
-// replace a single tags flags
-static void replace_flags_test(void) {
-  struct census_tag_set *cts =
-      census_tag_set_create(NULL, basic_tags, BASIC_TAG_COUNT, NULL);
-  const census_tag_set_create_status *status;
-  struct census_tag_set *cts2 =
-      census_tag_set_create(cts, modify_tags + REPLACE_FLAG_OFFSET, 1, &status);
-  census_tag_set_create_status expected = {1, 2, 5, 0, 0, 1, 0, 0};
-  GPR_ASSERT(memcmp(status, &expected, sizeof(expected)) == 0);
-  census_tag tag;
-  GPR_ASSERT(census_tag_set_get_tag_by_key(
-                 cts2, modify_tags[REPLACE_FLAG_OFFSET].key, &tag) == 1);
-  GPR_ASSERT(compare_tag(&tag, &modify_tags[REPLACE_FLAG_OFFSET]));
-  census_tag_set_destroy(cts);
-  census_tag_set_destroy(cts2);
-}
-
-// delete a single tag.
-static void delete_tag_test(void) {
-  struct census_tag_set *cts =
-      census_tag_set_create(NULL, basic_tags, BASIC_TAG_COUNT, NULL);
-  const census_tag_set_create_status *status;
-  struct census_tag_set *cts2 =
-      census_tag_set_create(cts, modify_tags + DELETE_TAG_OFFSET, 1, &status);
-  census_tag_set_create_status expected = {2, 1, 4, 1, 0, 0, 0, 0};
-  GPR_ASSERT(memcmp(status, &expected, sizeof(expected)) == 0);
-  census_tag tag;
-  GPR_ASSERT(census_tag_set_get_tag_by_key(
-                 cts2, modify_tags[DELETE_TAG_OFFSET].key, &tag) == 0);
-  census_tag_set_destroy(cts);
-  census_tag_set_destroy(cts2);
-}
-
-// add a single new tag.
-static void add_tag_test(void) {
-  struct census_tag_set *cts =
-      census_tag_set_create(NULL, basic_tags, BASIC_TAG_COUNT, NULL);
-  const census_tag_set_create_status *status;
-  struct census_tag_set *cts2 =
-      census_tag_set_create(cts, modify_tags + ADD_TAG_OFFSET, 1, &status);
-  census_tag_set_create_status expected = {2, 2, 5, 0, 1, 0, 0, 0};
-  GPR_ASSERT(memcmp(status, &expected, sizeof(expected)) == 0);
-  census_tag tag;
-  GPR_ASSERT(census_tag_set_get_tag_by_key(
-                 cts2, modify_tags[ADD_TAG_OFFSET].key, &tag) == 1);
-  GPR_ASSERT(compare_tag(&tag, &modify_tags[ADD_TAG_OFFSET]));
-  census_tag_set_destroy(cts);
-  census_tag_set_destroy(cts2);
-}
-
-// test many changes at once.
-static void replace_add_delete_test(void) {
-  struct census_tag_set *cts =
-      census_tag_set_create(NULL, basic_tags, BASIC_TAG_COUNT, NULL);
-  const census_tag_set_create_status *status;
-  struct census_tag_set *cts2 =
-      census_tag_set_create(cts, modify_tags, MODIFY_TAG_COUNT, &status);
-  census_tag_set_create_status expected = {2, 1, 6, 2, 3, 4, 0, 2};
-  GPR_ASSERT(memcmp(status, &expected, sizeof(expected)) == 0);
-  // validate tag set contents. Use specific indices into the two arrays
-  // holding tag values.
-  GPR_ASSERT(validate_tag(cts2, &basic_tags[3]));
-  GPR_ASSERT(validate_tag(cts2, &basic_tags[4]));
-  GPR_ASSERT(validate_tag(cts2, &modify_tags[0]));
-  GPR_ASSERT(validate_tag(cts2, &modify_tags[1]));
-  GPR_ASSERT(validate_tag(cts2, &modify_tags[6]));
-  GPR_ASSERT(validate_tag(cts2, &modify_tags[7]));
-  GPR_ASSERT(validate_tag(cts2, &modify_tags[8]));
-  GPR_ASSERT(validate_tag(cts2, &modify_tags[9]));
-  GPR_ASSERT(validate_tag(cts2, &modify_tags[10]));
-  GPR_ASSERT(!validate_tag(cts2, &basic_tags[0]));
-  GPR_ASSERT(!validate_tag(cts2, &basic_tags[1]));
-  GPR_ASSERT(!validate_tag(cts2, &basic_tags[2]));
-  GPR_ASSERT(!validate_tag(cts2, &basic_tags[5]));
-  GPR_ASSERT(!validate_tag(cts2, &basic_tags[6]));
-  GPR_ASSERT(!validate_tag(cts2, &basic_tags[7]));
-  census_tag_set_destroy(cts);
-  census_tag_set_destroy(cts2);
-}
-
-#define BUF_SIZE 200
-
-// test encode/decode.
-static void encode_decode_test(void) {
-  char buffer[BUF_SIZE];
-  struct census_tag_set *cts =
-      census_tag_set_create(NULL, basic_tags, BASIC_TAG_COUNT, NULL);
-  size_t print_bsize;
-  size_t bin_bsize;
-  // Test with too small a buffer
-  GPR_ASSERT(census_tag_set_encode(cts, buffer, 2, &print_bsize, &bin_bsize) ==
-             NULL);
-  char *b_buffer =
-      census_tag_set_encode(cts, buffer, BUF_SIZE, &print_bsize, &bin_bsize);
-  GPR_ASSERT(b_buffer != NULL && print_bsize > 0 && bin_bsize > 0 &&
-             print_bsize + bin_bsize <= BUF_SIZE &&
-             b_buffer == buffer + print_bsize);
-  census_tag_set *cts2 =
-      census_tag_set_decode(buffer, print_bsize, b_buffer, bin_bsize);
-  GPR_ASSERT(cts2 != NULL);
-  const census_tag_set_create_status *status =
-      census_tag_set_get_create_status(cts2);
-  census_tag_set_create_status expected = {2, 2, 0, 0, 0, 0, 0, 0};
-  GPR_ASSERT(memcmp(status, &expected, sizeof(expected)) == 0);
-  for (int i = 0; i < BASIC_TAG_COUNT; i++) {
-    census_tag tag;
-    if (CENSUS_TAG_IS_PROPAGATED(basic_tags[i].flags)) {
-      GPR_ASSERT(census_tag_set_get_tag_by_key(cts2, basic_tags[i].key, &tag) ==
-                 1);
-      GPR_ASSERT(compare_tag(&tag, &basic_tags[i]));
-    } else {
-      GPR_ASSERT(census_tag_set_get_tag_by_key(cts2, basic_tags[i].key, &tag) ==
-                 0);
-    }
-  }
-  census_tag_set_destroy(cts2);
-  census_tag_set_destroy(cts);
-}
-
-int main(int argc, char *argv[]) {
-  grpc_test_init(argc, argv);
-  empty_test();
-  basic_test();
-  lookup_by_key_test();
-  invalid_test();
-  copy_test();
-  replace_value_test();
-  replace_flags_test();
-  delete_tag_test();
-  add_tag_test();
-  replace_add_delete_test();
-  encode_decode_test();
-  return 0;
-}
diff --git a/test/core/channel/channel_stack_test.c b/test/core/channel/channel_stack_test.c
index f1bb37c..e19e9a5 100644
--- a/test/core/channel/channel_stack_test.c
+++ b/test/core/channel/channel_stack_test.c
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -81,12 +81,12 @@
   return gpr_strdup("peer");
 }
 
-static void free_channel(grpc_exec_ctx *exec_ctx, void *arg, int success) {
+static void free_channel(grpc_exec_ctx *exec_ctx, void *arg, bool success) {
   grpc_channel_stack_destroy(exec_ctx, arg);
   gpr_free(arg);
 }
 
-static void free_call(grpc_exec_ctx *exec_ctx, void *arg, int success) {
+static void free_call(grpc_exec_ctx *exec_ctx, void *arg, bool success) {
   grpc_call_stack_destroy(exec_ctx, arg);
   gpr_free(arg);
 }
diff --git a/test/core/client_config/set_initial_connect_string_test.c b/test/core/client_config/set_initial_connect_string_test.c
index 33cab71..bcd1f26 100644
--- a/test/core/client_config/set_initial_connect_string_test.c
+++ b/test/core/client_config/set_initial_connect_string_test.c
@@ -64,7 +64,7 @@
 static struct rpc_state state;
 static grpc_closure on_read;
 
-static void handle_read(grpc_exec_ctx *exec_ctx, void *arg, int success) {
+static void handle_read(grpc_exec_ctx *exec_ctx, void *arg, bool success) {
   GPR_ASSERT(success);
   gpr_slice_buffer_move_into(&state.temp_incoming_buffer,
                              &state.incoming_buffer);
diff --git a/test/core/end2end/fixtures/h2_uchannel.c b/test/core/end2end/fixtures/h2_uchannel.c
index 9b622e8..5ab64f9 100644
--- a/test/core/end2end/fixtures/h2_uchannel.c
+++ b/test/core/end2end/fixtures/h2_uchannel.c
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -81,7 +81,7 @@
   }
 }
 
-static void connected(grpc_exec_ctx *exec_ctx, void *arg, int success) {
+static void connected(grpc_exec_ctx *exec_ctx, void *arg, bool success) {
   connector *c = arg;
   grpc_closure *notify;
   grpc_endpoint *tcp = c->tcp;
@@ -240,7 +240,7 @@
 grpc_connectivity_state g_state = GRPC_CHANNEL_IDLE;
 grpc_pollset_set g_interested_parties;
 
-static void state_changed(grpc_exec_ctx *exec_ctx, void *arg, int success) {
+static void state_changed(grpc_exec_ctx *exec_ctx, void *arg, bool success) {
   if (g_state != GRPC_CHANNEL_READY) {
     grpc_subchannel_notify_on_state_change(
         exec_ctx, arg, &g_interested_parties, &g_state,
@@ -248,7 +248,7 @@
   }
 }
 
-static void destroy_pollset(grpc_exec_ctx *exec_ctx, void *arg, int success) {
+static void destroy_pollset(grpc_exec_ctx *exec_ctx, void *arg, bool success) {
   grpc_pollset_destroy(arg);
 }
 
diff --git a/test/core/fling/client.c b/test/core/fling/client.c
index 02db681..b36aef3 100644
--- a/test/core/fling/client.c
+++ b/test/core/fling/client.c
@@ -51,7 +51,7 @@
 static grpc_completion_queue *cq;
 static grpc_call *call;
 static grpc_op ops[6];
-static grpc_op stream_init_op;
+static grpc_op stream_init_ops[2];
 static grpc_op stream_step_ops[2];
 static grpc_metadata_array initial_metadata_recv;
 static grpc_metadata_array trailing_metadata_recv;
@@ -105,13 +105,17 @@
 }
 
 static void init_ping_pong_stream(void) {
+  grpc_metadata_array_init(&initial_metadata_recv);
+
   grpc_call_error error;
   call = grpc_channel_create_call(channel, NULL, GRPC_PROPAGATE_DEFAULTS, cq,
                                   "/Reflector/reflectStream", "localhost",
                                   gpr_inf_future(GPR_CLOCK_REALTIME), NULL);
-  stream_init_op.op = GRPC_OP_SEND_INITIAL_METADATA;
-  stream_init_op.data.send_initial_metadata.count = 0;
-  error = grpc_call_start_batch(call, &stream_init_op, 1, (void *)1, NULL);
+  stream_init_ops[0].op = GRPC_OP_SEND_INITIAL_METADATA;
+  stream_init_ops[0].data.send_initial_metadata.count = 0;
+  stream_init_ops[1].op = GRPC_OP_RECV_INITIAL_METADATA;
+  stream_init_ops[1].data.recv_initial_metadata = &initial_metadata_recv;
+  error = grpc_call_start_batch(call, stream_init_ops, 2, (void *)1, NULL);
   GPR_ASSERT(GRPC_CALL_OK == error);
   grpc_completion_queue_next(cq, gpr_inf_future(GPR_CLOCK_REALTIME), NULL);
 
diff --git a/test/core/httpcli/httpcli_test.c b/test/core/httpcli/httpcli_test.c
index 612388c..651ef1f 100644
--- a/test/core/httpcli/httpcli_test.c
+++ b/test/core/httpcli/httpcli_test.c
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -131,7 +131,7 @@
   gpr_free(host);
 }
 
-static void destroy_pollset(grpc_exec_ctx *exec_ctx, void *p, int success) {
+static void destroy_pollset(grpc_exec_ctx *exec_ctx, void *p, bool success) {
   grpc_pollset_destroy(p);
 }
 
diff --git a/test/core/httpcli/httpscli_test.c b/test/core/httpcli/httpscli_test.c
index ba5660b..db41be1 100644
--- a/test/core/httpcli/httpscli_test.c
+++ b/test/core/httpcli/httpscli_test.c
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -133,7 +133,7 @@
   gpr_free(host);
 }
 
-static void destroy_pollset(grpc_exec_ctx *exec_ctx, void *p, int success) {
+static void destroy_pollset(grpc_exec_ctx *exec_ctx, void *p, bool success) {
   grpc_pollset_destroy(p);
 }
 
diff --git a/test/core/iomgr/endpoint_pair_test.c b/test/core/iomgr/endpoint_pair_test.c
index ff590cf..7e266eb 100644
--- a/test/core/iomgr/endpoint_pair_test.c
+++ b/test/core/iomgr/endpoint_pair_test.c
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -65,7 +65,7 @@
     {"tcp/tcp_socketpair", create_fixture_endpoint_pair, clean_up},
 };
 
-static void destroy_pollset(grpc_exec_ctx *exec_ctx, void *p, int success) {
+static void destroy_pollset(grpc_exec_ctx *exec_ctx, void *p, bool success) {
   grpc_pollset_destroy(p);
 }
 
diff --git a/test/core/iomgr/endpoint_tests.c b/test/core/iomgr/endpoint_tests.c
index a66fe32..1b6a78d 100644
--- a/test/core/iomgr/endpoint_tests.c
+++ b/test/core/iomgr/endpoint_tests.c
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -127,7 +127,7 @@
 };
 
 static void read_and_write_test_read_handler(grpc_exec_ctx *exec_ctx,
-                                             void *data, int success) {
+                                             void *data, bool success) {
   struct read_and_write_test_state *state = data;
 
   state->bytes_read += count_slices(
@@ -145,7 +145,7 @@
 }
 
 static void read_and_write_test_write_handler(grpc_exec_ctx *exec_ctx,
-                                              void *data, int success) {
+                                              void *data, bool success) {
   struct read_and_write_test_state *state = data;
   gpr_slice *slices = NULL;
   size_t nslices;
diff --git a/test/core/iomgr/fd_posix_test.c b/test/core/iomgr/fd_posix_test.c
index b186520..347a86a 100644
--- a/test/core/iomgr/fd_posix_test.c
+++ b/test/core/iomgr/fd_posix_test.c
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -118,7 +118,7 @@
 /* Called when an upload session can be safely shutdown.
    Close session FD and start to shutdown listen FD. */
 static void session_shutdown_cb(grpc_exec_ctx *exec_ctx, void *arg, /*session */
-                                int success) {
+                                bool success) {
   session *se = arg;
   server *sv = se->sv;
   grpc_fd_orphan(exec_ctx, se->em_fd, NULL, NULL, "a");
@@ -129,7 +129,7 @@
 
 /* Called when data become readable in a session. */
 static void session_read_cb(grpc_exec_ctx *exec_ctx, void *arg, /*session */
-                            int success) {
+                            bool success) {
   session *se = arg;
   int fd = se->em_fd->fd;
 
@@ -187,7 +187,7 @@
 
 /* Called when a new TCP connection request arrives in the listening port. */
 static void listen_cb(grpc_exec_ctx *exec_ctx, void *arg, /*=sv_arg*/
-                      int success) {
+                      bool success) {
   server *sv = arg;
   int fd;
   int flags;
@@ -301,7 +301,7 @@
 
 /* Write as much as possible, then register notify_on_write. */
 static void client_session_write(grpc_exec_ctx *exec_ctx, void *arg, /*client */
-                                 int success) {
+                                 bool success) {
   client *cl = arg;
   int fd = cl->em_fd->fd;
   ssize_t write_once = 0;
@@ -399,7 +399,7 @@
 }
 
 typedef struct fd_change_data {
-  void (*cb_that_ran)(grpc_exec_ctx *exec_ctx, void *, int success);
+  grpc_iomgr_cb_func cb_that_ran;
 } fd_change_data;
 
 void init_change_data(fd_change_data *fdc) { fdc->cb_that_ran = NULL; }
@@ -407,7 +407,7 @@
 void destroy_change_data(fd_change_data *fdc) {}
 
 static void first_read_callback(grpc_exec_ctx *exec_ctx,
-                                void *arg /* fd_change_data */, int success) {
+                                void *arg /* fd_change_data */, bool success) {
   fd_change_data *fdc = arg;
 
   gpr_mu_lock(GRPC_POLLSET_MU(&g_pollset));
@@ -417,7 +417,7 @@
 }
 
 static void second_read_callback(grpc_exec_ctx *exec_ctx,
-                                 void *arg /* fd_change_data */, int success) {
+                                 void *arg /* fd_change_data */, bool success) {
   fd_change_data *fdc = arg;
 
   gpr_mu_lock(GRPC_POLLSET_MU(&g_pollset));
@@ -510,7 +510,7 @@
   close(sv[1]);
 }
 
-static void destroy_pollset(grpc_exec_ctx *exec_ctx, void *p, int success) {
+static void destroy_pollset(grpc_exec_ctx *exec_ctx, void *p, bool success) {
   grpc_pollset_destroy(p);
 }
 
diff --git a/test/core/iomgr/tcp_client_posix_test.c b/test/core/iomgr/tcp_client_posix_test.c
index 833ceac..9725d8a 100644
--- a/test/core/iomgr/tcp_client_posix_test.c
+++ b/test/core/iomgr/tcp_client_posix_test.c
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -63,7 +63,7 @@
   gpr_mu_unlock(GRPC_POLLSET_MU(&g_pollset));
 }
 
-static void must_succeed(grpc_exec_ctx *exec_ctx, void *arg, int success) {
+static void must_succeed(grpc_exec_ctx *exec_ctx, void *arg, bool success) {
   GPR_ASSERT(g_connecting != NULL);
   GPR_ASSERT(success);
   grpc_endpoint_shutdown(exec_ctx, g_connecting);
@@ -72,7 +72,7 @@
   finish_connection();
 }
 
-static void must_fail(grpc_exec_ctx *exec_ctx, void *arg, int success) {
+static void must_fail(grpc_exec_ctx *exec_ctx, void *arg, bool success) {
   GPR_ASSERT(g_connecting == NULL);
   GPR_ASSERT(!success);
   finish_connection();
@@ -258,7 +258,7 @@
   }
 }
 
-static void destroy_pollset(grpc_exec_ctx *exec_ctx, void *p, int success) {
+static void destroy_pollset(grpc_exec_ctx *exec_ctx, void *p, bool success) {
   grpc_pollset_destroy(p);
 }
 
diff --git a/test/core/iomgr/tcp_posix_test.c b/test/core/iomgr/tcp_posix_test.c
index e0136b3..d290c6b 100644
--- a/test/core/iomgr/tcp_posix_test.c
+++ b/test/core/iomgr/tcp_posix_test.c
@@ -138,7 +138,7 @@
   return num_bytes;
 }
 
-static void read_cb(grpc_exec_ctx *exec_ctx, void *user_data, int success) {
+static void read_cb(grpc_exec_ctx *exec_ctx, void *user_data, bool success) {
   struct read_socket_state *state = (struct read_socket_state *)user_data;
   size_t read_bytes;
   int current_data;
@@ -280,7 +280,7 @@
 }
 
 static void write_done(grpc_exec_ctx *exec_ctx,
-                       void *user_data /* write_socket_state */, int success) {
+                       void *user_data /* write_socket_state */, bool success) {
   struct write_socket_state *state = (struct write_socket_state *)user_data;
   gpr_log(GPR_INFO, "Write done callback called");
   gpr_mu_lock(GRPC_POLLSET_MU(&g_pollset));
@@ -383,7 +383,7 @@
   grpc_exec_ctx_finish(&exec_ctx);
 }
 
-void on_fd_released(grpc_exec_ctx *exec_ctx, void *arg, int success) {
+void on_fd_released(grpc_exec_ctx *exec_ctx, void *arg, bool success) {
   int *done = arg;
   *done = 1;
   grpc_pollset_kick(&g_pollset, NULL);
@@ -503,7 +503,7 @@
     {"tcp/tcp_socketpair", create_fixture_tcp_socketpair, clean_up},
 };
 
-static void destroy_pollset(grpc_exec_ctx *exec_ctx, void *p, int success) {
+static void destroy_pollset(grpc_exec_ctx *exec_ctx, void *p, bool success) {
   grpc_pollset_destroy(p);
 }
 
diff --git a/test/core/iomgr/tcp_server_posix_test.c b/test/core/iomgr/tcp_server_posix_test.c
index f7097ac..272d97b 100644
--- a/test/core/iomgr/tcp_server_posix_test.c
+++ b/test/core/iomgr/tcp_server_posix_test.c
@@ -86,7 +86,7 @@
 }
 
 static void server_weak_ref_shutdown(grpc_exec_ctx *exec_ctx, void *arg,
-                                     int success) {
+                                     bool success) {
   server_weak_ref *weak_ref = arg;
   weak_ref->server = NULL;
 }
@@ -303,7 +303,7 @@
   grpc_exec_ctx_finish(&exec_ctx);
 }
 
-static void destroy_pollset(grpc_exec_ctx *exec_ctx, void *p, int success) {
+static void destroy_pollset(grpc_exec_ctx *exec_ctx, void *p, bool success) {
   grpc_pollset_destroy(p);
 }
 
diff --git a/test/core/iomgr/timer_list_test.c b/test/core/iomgr/timer_list_test.c
index 63014c3..15de87c 100644
--- a/test/core/iomgr/timer_list_test.c
+++ b/test/core/iomgr/timer_list_test.c
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -43,7 +43,7 @@
 
 static int cb_called[MAX_CB][2];
 
-static void cb(grpc_exec_ctx *exec_ctx, void *arg, int success) {
+static void cb(grpc_exec_ctx *exec_ctx, void *arg, bool success) {
   cb_called[(intptr_t)arg][success]++;
 }
 
diff --git a/test/core/iomgr/workqueue_test.c b/test/core/iomgr/workqueue_test.c
index d1f9dab..500170b 100644
--- a/test/core/iomgr/workqueue_test.c
+++ b/test/core/iomgr/workqueue_test.c
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -40,7 +40,7 @@
 
 static grpc_pollset g_pollset;
 
-static void must_succeed(grpc_exec_ctx *exec_ctx, void *p, int success) {
+static void must_succeed(grpc_exec_ctx *exec_ctx, void *p, bool success) {
   GPR_ASSERT(success == 1);
   gpr_mu_lock(GRPC_POLLSET_MU(&g_pollset));
   *(int *)p = 1;
@@ -90,7 +90,7 @@
   grpc_pollset_worker worker;
   grpc_closure_init(&c, must_succeed, &done);
 
-  grpc_exec_ctx_enqueue(&exec_ctx, &c, 1);
+  grpc_exec_ctx_enqueue(&exec_ctx, &c, true, NULL);
   grpc_workqueue_flush(&exec_ctx, wq);
   grpc_workqueue_add_to_pollset(&exec_ctx, wq, &g_pollset);
 
@@ -106,7 +106,7 @@
   grpc_exec_ctx_finish(&exec_ctx);
 }
 
-static void destroy_pollset(grpc_exec_ctx *exec_ctx, void *p, int success) {
+static void destroy_pollset(grpc_exec_ctx *exec_ctx, void *p, bool success) {
   grpc_pollset_destroy(p);
 }
 
diff --git a/test/core/security/create_jwt.c b/test/core/security/create_jwt.c
index b02469f..237dc9a 100644
--- a/test/core/security/create_jwt.c
+++ b/test/core/security/create_jwt.c
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -62,7 +62,7 @@
   }
   jwt = grpc_jwt_encode_and_sign(
       &key, service_url == NULL ? GRPC_JWT_OAUTH2_AUDIENCE : service_url,
-      grpc_max_auth_token_lifetime, scope);
+      grpc_max_auth_token_lifetime(), scope);
   grpc_auth_json_key_destruct(&key);
   if (jwt == NULL) {
     fprintf(stderr, "Could not create JWT.\n");
diff --git a/test/core/security/credentials_test.c b/test/core/security/credentials_test.c
index a32ddd2..8a210bb 100644
--- a/test/core/security/credentials_test.c
+++ b/test/core/security/credentials_test.c
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -734,7 +734,7 @@
                     "777-abaslkan11hlb6nmim3bpspl31ud@developer."
                     "gserviceaccount.com") == 0);
   if (scope != NULL) GPR_ASSERT(strcmp(scope, test_scope) == 0);
-  GPR_ASSERT(!gpr_time_cmp(token_lifetime, grpc_max_auth_token_lifetime));
+  GPR_ASSERT(!gpr_time_cmp(token_lifetime, grpc_max_auth_token_lifetime()));
 }
 
 static char *encode_and_sign_jwt_success(const grpc_auth_json_key *json_key,
@@ -794,7 +794,7 @@
                                             NULL};
   grpc_call_credentials *jwt_creds =
       grpc_service_account_jwt_access_credentials_create(
-          json_key_string, grpc_max_auth_token_lifetime, NULL);
+          json_key_string, grpc_max_auth_token_lifetime(), NULL);
 
   /* First request: jwt_encode_and_sign should be called. */
   grpc_jwt_encode_and_sign_set_override(encode_and_sign_jwt_success);
@@ -832,7 +832,7 @@
                                             NULL};
   grpc_call_credentials *jwt_creds =
       grpc_service_account_jwt_access_credentials_create(
-          json_key_string, grpc_max_auth_token_lifetime, NULL);
+          json_key_string, grpc_max_auth_token_lifetime(), NULL);
 
   grpc_jwt_encode_and_sign_set_override(encode_and_sign_jwt_failure);
   grpc_call_credentials_get_request_metadata(
diff --git a/test/core/security/json_token_test.c b/test/core/security/json_token_test.c
index 740fd01..7c01a9c 100644
--- a/test/core/security/json_token_test.c
+++ b/test/core/security/json_token_test.c
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -330,7 +330,7 @@
   issue_time.tv_sec = strtol(iat->value, NULL, 10);
 
   parsed_lifetime = gpr_time_sub(expiration, issue_time);
-  GPR_ASSERT(parsed_lifetime.tv_sec == grpc_max_auth_token_lifetime.tv_sec);
+  GPR_ASSERT(parsed_lifetime.tv_sec == grpc_max_auth_token_lifetime().tv_sec);
 }
 
 static void check_jwt_signature(const char *b64_signature, RSA *rsa_key,
@@ -361,12 +361,12 @@
 static char *service_account_creds_jwt_encode_and_sign(
     const grpc_auth_json_key *key) {
   return grpc_jwt_encode_and_sign(key, GRPC_JWT_OAUTH2_AUDIENCE,
-                                  grpc_max_auth_token_lifetime, test_scope);
+                                  grpc_max_auth_token_lifetime(), test_scope);
 }
 
 static char *jwt_creds_jwt_encode_and_sign(const grpc_auth_json_key *key) {
   return grpc_jwt_encode_and_sign(key, test_service_url,
-                                  grpc_max_auth_token_lifetime, NULL);
+                                  grpc_max_auth_token_lifetime(), NULL);
 }
 
 static void service_account_creds_check_jwt_claim(grpc_json *claim) {
diff --git a/test/core/security/oauth2_utils.c b/test/core/security/oauth2_utils.c
index fb62bf4..55ac31e 100644
--- a/test/core/security/oauth2_utils.c
+++ b/test/core/security/oauth2_utils.c
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -73,7 +73,7 @@
   gpr_mu_unlock(GRPC_POLLSET_MU(&request->pollset));
 }
 
-static void do_nothing(grpc_exec_ctx *exec_ctx, void *unused, int success) {}
+static void do_nothing(grpc_exec_ctx *exec_ctx, void *unused, bool success) {}
 
 char *grpc_test_fetch_oauth2_token_with_credentials(
     grpc_call_credentials *creds) {
diff --git a/test/core/security/secure_endpoint_test.c b/test/core/security/secure_endpoint_test.c
index 240c459..fb4bd30 100644
--- a/test/core/security/secure_endpoint_test.c
+++ b/test/core/security/secure_endpoint_test.c
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -138,7 +138,7 @@
      secure_endpoint_create_fixture_tcp_socketpair_leftover, clean_up},
 };
 
-static void inc_call_ctr(grpc_exec_ctx *exec_ctx, void *arg, int success) {
+static void inc_call_ctr(grpc_exec_ctx *exec_ctx, void *arg, bool success) {
   ++*(int *)arg;
 }
 
@@ -171,7 +171,7 @@
   clean_up();
 }
 
-static void destroy_pollset(grpc_exec_ctx *exec_ctx, void *p, int success) {
+static void destroy_pollset(grpc_exec_ctx *exec_ctx, void *p, bool success) {
   grpc_pollset_destroy(p);
 }
 
diff --git a/test/core/security/security_connector_test.c b/test/core/security/security_connector_test.c
index 0dcffa4..ee5435f 100644
--- a/test/core/security/security_connector_test.c
+++ b/test/core/security/security_connector_test.c
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -36,6 +36,9 @@
 
 #include "src/core/security/security_connector.h"
 #include "src/core/security/security_context.h"
+#include "src/core/support/env.h"
+#include "src/core/support/file.h"
+#include "src/core/support/string.h"
 #include "src/core/tsi/ssl_transport_security.h"
 #include "src/core/tsi/transport_security.h"
 #include "test/core/util/test_config.h"
@@ -44,6 +47,7 @@
 
 #include <grpc/support/alloc.h>
 #include <grpc/support/log.h>
+#include <grpc/support/string_util.h>
 #include <grpc/support/useful.h>
 
 static int check_transport_security_type(const grpc_auth_context *ctx) {
@@ -297,7 +301,66 @@
   GRPC_AUTH_CONTEXT_UNREF(ctx, "test");
 }
 
-/* TODO(jboeuf): Unit-test tsi_shallow_peer_from_auth_context. */
+static const char *roots_for_override_api = "roots for override api";
+
+static grpc_ssl_roots_override_result override_roots_success(
+    char **pem_root_certs) {
+  *pem_root_certs = gpr_strdup(roots_for_override_api);
+  return GRPC_SSL_ROOTS_OVERRIDE_OK;
+}
+
+static grpc_ssl_roots_override_result override_roots_permanent_failure(
+    char **pem_root_certs) {
+  return GRPC_SSL_ROOTS_OVERRIDE_FAIL_PERMANENTLY;
+}
+
+static void test_default_ssl_roots(void) {
+  const char *roots_for_env_var = "roots for env var";
+
+  char *roots_env_var_file_path;
+  FILE *roots_env_var_file =
+      gpr_tmpfile("test_roots_for_env_var", &roots_env_var_file_path);
+  fwrite(roots_for_env_var, 1, strlen(roots_for_env_var), roots_env_var_file);
+  fclose(roots_env_var_file);
+
+  /* First let's get the root through the override: set the env to an invalid
+     value. */
+  gpr_setenv(GRPC_DEFAULT_SSL_ROOTS_FILE_PATH_ENV_VAR, "");
+  grpc_set_ssl_roots_override_callback(override_roots_success);
+  gpr_slice roots = grpc_get_default_ssl_roots_for_testing();
+  char *roots_contents = gpr_dump_slice(roots, GPR_DUMP_ASCII);
+  gpr_slice_unref(roots);
+  GPR_ASSERT(strcmp(roots_contents, roots_for_override_api) == 0);
+  gpr_free(roots_contents);
+
+  /* Now let's set the env var: We should get the contents pointed value
+     instead. */
+  gpr_setenv(GRPC_DEFAULT_SSL_ROOTS_FILE_PATH_ENV_VAR, roots_env_var_file_path);
+  roots = grpc_get_default_ssl_roots_for_testing();
+  roots_contents = gpr_dump_slice(roots, GPR_DUMP_ASCII);
+  gpr_slice_unref(roots);
+  GPR_ASSERT(strcmp(roots_contents, roots_for_env_var) == 0);
+  gpr_free(roots_contents);
+
+  /* Now reset the env var. We should fall back to the value overridden using
+     the api. */
+  gpr_setenv(GRPC_DEFAULT_SSL_ROOTS_FILE_PATH_ENV_VAR, "");
+  roots = grpc_get_default_ssl_roots_for_testing();
+  roots_contents = gpr_dump_slice(roots, GPR_DUMP_ASCII);
+  gpr_slice_unref(roots);
+  GPR_ASSERT(strcmp(roots_contents, roots_for_override_api) == 0);
+  gpr_free(roots_contents);
+
+  /* Now setup a permanent failure for the overridden roots and we should get
+     an empty slice. */
+  grpc_set_ssl_roots_override_callback(override_roots_permanent_failure);
+  roots = grpc_get_default_ssl_roots_for_testing();
+  GPR_ASSERT(GPR_SLICE_IS_EMPTY(roots));
+
+  /* Cleanup. */
+  remove(roots_env_var_file_path);
+  gpr_free(roots_env_var_file_path);
+}
 
 int main(int argc, char **argv) {
   grpc_test_init(argc, argv);
@@ -308,6 +371,7 @@
   test_cn_and_one_san_ssl_peer_to_auth_context();
   test_cn_and_multiple_sans_ssl_peer_to_auth_context();
   test_cn_and_multiple_sans_and_others_ssl_peer_to_auth_context();
+  test_default_ssl_roots();
 
   grpc_shutdown();
   return 0;
diff --git a/test/core/statistics/census_log_tests.c b/test/core/statistics/census_log_tests.c
index aac20fd..77cc57d 100644
--- a/test/core/statistics/census_log_tests.c
+++ b/test/core/statistics/census_log_tests.c
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -237,8 +237,8 @@
   gpr_timespec interval;
   int counter = 0;
   printf("   Reader starting\n");
-  interval = gpr_time_from_micros(args->read_iteration_interval_in_msec * 1000,
-                                  GPR_TIMESPAN);
+  interval = gpr_time_from_micros(
+      (int64_t)args->read_iteration_interval_in_msec * 1000, GPR_TIMESPAN);
   gpr_mu_lock(args->mu);
   while (!args->stop_flag && records_read < args->total_records) {
     gpr_cv_wait(&args->stop, args->mu, interval);
diff --git a/test/core/support/alloc_test.c b/test/core/support/alloc_test.c
index a7051a4..6bdba8c 100644
--- a/test/core/support/alloc_test.c
+++ b/test/core/support/alloc_test.c
@@ -39,7 +39,9 @@
 
 static void *fake_realloc(void *addr, size_t size) { return (void *)size; }
 
-static void fake_free(void *addr) { *((intptr_t *)addr) = 0xdeadd00d; }
+static void fake_free(void *addr) {
+  *((intptr_t *)addr) = (intptr_t)0xdeadd00d;
+}
 
 static void test_custom_allocs() {
   const gpr_allocation_functions default_fns = gpr_get_allocation_functions();
@@ -52,7 +54,7 @@
   GPR_ASSERT((void *)(size_t)0xcafed00d == gpr_realloc(0, 0xcafed00d));
 
   gpr_free(&addr_to_free);
-  GPR_ASSERT(addr_to_free == 0xdeadd00d);
+  GPR_ASSERT(addr_to_free == (intptr_t)0xdeadd00d);
 
   /* Restore and check we don't get funky values and that we don't leak */
   gpr_set_allocation_functions(default_fns);
diff --git a/test/core/support/sync_test.c b/test/core/support/sync_test.c
index 0149bc3..d311eb1 100644
--- a/test/core/support/sync_test.c
+++ b/test/core/support/sync_test.c
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -251,7 +251,7 @@
   gpr_timespec start = gpr_now(GPR_CLOCK_REALTIME);
   gpr_timespec time_taken;
   gpr_timespec deadline = gpr_time_add(
-      start, gpr_time_from_micros(timeout_s * 1000000, GPR_TIMESPAN));
+      start, gpr_time_from_micros((int64_t)timeout_s * 1000000, GPR_TIMESPAN));
   fprintf(stderr, "%s:", name);
   while (gpr_time_cmp(gpr_now(GPR_CLOCK_REALTIME), deadline) < 0) {
     iterations <<= 1;
diff --git a/test/core/support/time_test.c b/test/core/support/time_test.c
index fc26f94..6cc3786 100644
--- a/test/core/support/time_test.c
+++ b/test/core/support/time_test.c
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -125,15 +125,15 @@
   }
 
   /* Test possible overflow in conversion of -ve values. */
-  x = gpr_time_from_micros(-(LONG_MAX - 999997), GPR_TIMESPAN);
+  x = gpr_time_from_micros(-(INT64_MAX - 999997), GPR_TIMESPAN);
   GPR_ASSERT(x.tv_sec < 0);
   GPR_ASSERT(x.tv_nsec >= 0 && x.tv_nsec < GPR_NS_PER_SEC);
 
-  x = gpr_time_from_nanos(-(LONG_MAX - 999999997), GPR_TIMESPAN);
+  x = gpr_time_from_nanos(-(INT64_MAX - 999999997), GPR_TIMESPAN);
   GPR_ASSERT(x.tv_sec < 0);
   GPR_ASSERT(x.tv_nsec >= 0 && x.tv_nsec < GPR_NS_PER_SEC);
 
-  x = gpr_time_from_millis(-(LONG_MAX - 997), GPR_TIMESPAN);
+  x = gpr_time_from_millis(-(INT64_MAX - 997), GPR_TIMESPAN);
   GPR_ASSERT(x.tv_sec < 0);
   GPR_ASSERT(x.tv_nsec >= 0 && x.tv_nsec < GPR_NS_PER_SEC);
 
diff --git a/test/core/surface/lame_client_test.c b/test/core/surface/lame_client_test.c
index e03cce1..79e53cb 100644
--- a/test/core/surface/lame_client_test.c
+++ b/test/core/surface/lame_client_test.c
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -47,13 +47,13 @@
 
 static void *tag(intptr_t x) { return (void *)x; }
 
-void verify_connectivity(grpc_exec_ctx *exec_ctx, void *arg, int success) {
+void verify_connectivity(grpc_exec_ctx *exec_ctx, void *arg, bool success) {
   grpc_transport_op *op = arg;
   GPR_ASSERT(GRPC_CHANNEL_FATAL_FAILURE == *op->connectivity_state);
   GPR_ASSERT(success);
 }
 
-void do_nothing(grpc_exec_ctx *exec_ctx, void *arg, int success) {}
+void do_nothing(grpc_exec_ctx *exec_ctx, void *arg, bool success) {}
 
 void test_transport_op(grpc_channel *channel) {
   grpc_transport_op op;
diff --git a/test/core/surface/public_headers_must_be_c89.c b/test/core/surface/public_headers_must_be_c89.c
index 1e1524d..579faa4 100644
--- a/test/core/surface/public_headers_must_be_c89.c
+++ b/test/core/surface/public_headers_must_be_c89.c
@@ -37,6 +37,21 @@
 #include <grpc/compression.h>
 #include <grpc/grpc.h>
 #include <grpc/grpc_security.h>
+#include <grpc/impl/codegen/alloc.h>
+#include <grpc/impl/codegen/atm.h>
+#include <grpc/impl/codegen/byte_buffer.h>
+#include <grpc/impl/codegen/compression_types.h>
+#include <grpc/impl/codegen/connectivity_state.h>
+#include <grpc/impl/codegen/grpc_types.h>
+#include <grpc/impl/codegen/log.h>
+#include <grpc/impl/codegen/port_platform.h>
+#include <grpc/impl/codegen/propagation_bits.h>
+#include <grpc/impl/codegen/slice.h>
+#include <grpc/impl/codegen/slice_buffer.h>
+#include <grpc/impl/codegen/status.h>
+#include <grpc/impl/codegen/sync.h>
+#include <grpc/impl/codegen/sync_generic.h>
+#include <grpc/impl/codegen/time.h>
 #include <grpc/status.h>
 #include <grpc/support/alloc.h>
 #include <grpc/support/atm.h>
diff --git a/test/core/surface/server_chttp2_test.c b/test/core/surface/server_chttp2_test.c
index ec7df6f..84b345b 100644
--- a/test/core/surface/server_chttp2_test.c
+++ b/test/core/surface/server_chttp2_test.c
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -32,7 +32,14 @@
  */
 
 #include <grpc/grpc.h>
+#include <grpc/grpc_security.h>
+#include <grpc/support/alloc.h>
+#include <grpc/support/host_port.h>
 #include <grpc/support/log.h>
+#include <grpc/support/time.h>
+#include "src/core/security/credentials.h"
+#include "src/core/tsi/fake_transport_security.h"
+#include "test/core/util/port.h"
 #include "test/core/util/test_config.h"
 
 void test_unparsable_target(void) {
@@ -40,10 +47,31 @@
   GPR_ASSERT(port == 0);
 }
 
+void test_add_same_port_twice() {
+  int port = grpc_pick_unused_port_or_die();
+  char *addr = NULL;
+  grpc_completion_queue *cq = grpc_completion_queue_create(NULL);
+  grpc_server *server = grpc_server_create(NULL, NULL);
+  grpc_server_credentials *fake_creds =
+      grpc_fake_transport_security_server_credentials_create();
+  gpr_join_host_port(&addr, "localhost", port);
+  GPR_ASSERT(grpc_server_add_secure_http2_port(server, addr, fake_creds));
+  GPR_ASSERT(grpc_server_add_secure_http2_port(server, addr, fake_creds) == 0);
+
+  grpc_server_credentials_release(fake_creds);
+  gpr_free(addr);
+  grpc_server_shutdown_and_notify(server, cq, NULL);
+  grpc_completion_queue_pluck(cq, NULL, gpr_inf_future(GPR_CLOCK_REALTIME),
+                              NULL);
+  grpc_server_destroy(server);
+  grpc_completion_queue_destroy(cq);
+}
+
 int main(int argc, char **argv) {
   grpc_test_init(argc, argv);
   grpc_init();
   test_unparsable_target();
+  test_add_same_port_twice();
   grpc_shutdown();
   return 0;
 }
diff --git a/test/core/transport/chttp2/hpack_table_test.c b/test/core/transport/chttp2/hpack_table_test.c
index 39f4174..3c5f2e4 100644
--- a/test/core/transport/chttp2/hpack_table_test.c
+++ b/test/core/transport/chttp2/hpack_table_test.c
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -236,7 +236,7 @@
 
   /* overflow the string buffer, check find still works */
   for (i = 0; i < 10000; i++) {
-    gpr_ltoa(i, buffer);
+    int64_ttoa(i, buffer);
     elem = grpc_mdelem_from_strings("test", buffer);
     GPR_ASSERT(grpc_chttp2_hptbl_add(&tbl, elem));
     GRPC_MDELEM_UNREF(elem);
@@ -256,7 +256,7 @@
 
   for (i = 0; i < tbl.num_ents; i++) {
     uint32_t expect = 9999 - i;
-    gpr_ltoa(expect, buffer);
+    int64_ttoa(expect, buffer);
 
     r = find_simple(&tbl, "test", buffer);
     GPR_ASSERT(r.index == i + 1 + GRPC_CHTTP2_LAST_STATIC_ENTRY);
diff --git a/test/core/transport/chttp2/timeout_encoding_test.c b/test/core/transport/chttp2/timeout_encoding_test.c
index f0e8ec3..483e79f 100644
--- a/test/core/transport/chttp2/timeout_encoding_test.c
+++ b/test/core/transport/chttp2/timeout_encoding_test.c
@@ -93,7 +93,7 @@
 }
 
 void decode_suite(char ext,
-                  gpr_timespec (*answer)(long x, gpr_clock_type clock)) {
+                  gpr_timespec (*answer)(int64_t x, gpr_clock_type clock)) {
   long test_vals[] = {1,       12,       123,       1234,     12345,   123456,
                       1234567, 12345678, 123456789, 98765432, 9876543, 987654,
                       98765,   9876,     987,       98,       9};
diff --git a/test/core/transport/connectivity_state_test.c b/test/core/transport/connectivity_state_test.c
index 34ab45d..4b2d0aa 100644
--- a/test/core/transport/connectivity_state_test.c
+++ b/test/core/transport/connectivity_state_test.c
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -43,13 +43,13 @@
 
 int g_counter;
 
-static void must_succeed(grpc_exec_ctx *exec_ctx, void *arg, int success) {
+static void must_succeed(grpc_exec_ctx *exec_ctx, void *arg, bool success) {
   GPR_ASSERT(success);
   GPR_ASSERT(arg == THE_ARG);
   g_counter++;
 }
 
-static void must_fail(grpc_exec_ctx *exec_ctx, void *arg, int success) {
+static void must_fail(grpc_exec_ctx *exec_ctx, void *arg, bool success) {
   GPR_ASSERT(!success);
   GPR_ASSERT(arg == THE_ARG);
   g_counter++;
diff --git a/test/core/util/port_posix.c b/test/core/util/port_posix.c
index 732a51c..4b31f81 100644
--- a/test/core/util/port_posix.c
+++ b/test/core/util/port_posix.c
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -37,11 +37,12 @@
 
 #include "test/core/util/port.h"
 
-#include <netinet/in.h>
-#include <sys/socket.h>
-#include <stdio.h>
 #include <errno.h>
+#include <math.h>
+#include <netinet/in.h>
+#include <stdio.h>
 #include <string.h>
+#include <sys/socket.h>
 #include <unistd.h>
 
 #include <grpc/grpc.h>
@@ -73,7 +74,7 @@
 } freereq;
 
 static void destroy_pollset_and_shutdown(grpc_exec_ctx *exec_ctx, void *p,
-                                         int success) {
+                                         bool success) {
   grpc_pollset_destroy(p);
   grpc_shutdown();
 }
@@ -229,10 +230,10 @@
     grpc_httpcli_request req;
     memset(&req, 0, sizeof(req));
     GPR_ASSERT(pr->retries < 10);
+    sleep(1 + (unsigned)(pow(1.3, pr->retries) * rand() / RAND_MAX));
     pr->retries++;
     req.host = pr->server;
     req.path = "/get";
-    sleep(1);
     grpc_httpcli_get(exec_ctx, pr->ctx, &pr->pollset, &req,
                      GRPC_TIMEOUT_SECONDS_TO_DEADLINE(10), got_port_from_server,
                      pr);
diff --git a/test/core/util/port_windows.c b/test/core/util/port_windows.c
index 60ad9b4..85d7c0c 100644
--- a/test/core/util/port_windows.c
+++ b/test/core/util/port_windows.c
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -152,7 +152,7 @@
 }
 
 static void destroy_pollset_and_shutdown(grpc_exec_ctx *exec_ctx, void *p,
-                                         int success) {
+                                         bool success) {
   grpc_pollset_destroy(p);
   grpc_shutdown();
 }
diff --git a/test/core/util/test_config.h b/test/core/util/test_config.h
index 15b7174..f6bb2e1 100644
--- a/test/core/util/test_config.h
+++ b/test/core/util/test_config.h
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -54,16 +54,16 @@
   (GRPC_TEST_SLOWDOWN_BUILD_FACTOR * GRPC_TEST_SLOWDOWN_MACHINE_FACTOR * \
    g_fixture_slowdown_factor)
 
-#define GRPC_TIMEOUT_SECONDS_TO_DEADLINE(x)                               \
-  gpr_time_add(                                                           \
-      gpr_now(GPR_CLOCK_MONOTONIC),                                       \
-      gpr_time_from_millis((long)(GRPC_TEST_SLOWDOWN_FACTOR * 1e3 * (x)), \
+#define GRPC_TIMEOUT_SECONDS_TO_DEADLINE(x)                                  \
+  gpr_time_add(                                                              \
+      gpr_now(GPR_CLOCK_MONOTONIC),                                          \
+      gpr_time_from_millis((int64_t)(GRPC_TEST_SLOWDOWN_FACTOR * 1e3 * (x)), \
                            GPR_TIMESPAN))
 
-#define GRPC_TIMEOUT_MILLIS_TO_DEADLINE(x)                                \
-  gpr_time_add(                                                           \
-      gpr_now(GPR_CLOCK_MONOTONIC),                                       \
-      gpr_time_from_micros((long)(GRPC_TEST_SLOWDOWN_FACTOR * 1e3 * (x)), \
+#define GRPC_TIMEOUT_MILLIS_TO_DEADLINE(x)                                   \
+  gpr_time_add(                                                              \
+      gpr_now(GPR_CLOCK_MONOTONIC),                                          \
+      gpr_time_from_micros((int64_t)(GRPC_TEST_SLOWDOWN_FACTOR * 1e3 * (x)), \
                            GPR_TIMESPAN))
 
 #ifndef GRPC_TEST_CUSTOM_PICK_PORT
diff --git a/test/core/util/test_tcp_server.c b/test/core/util/test_tcp_server.c
index aaba7be..66470c02 100644
--- a/test/core/util/test_tcp_server.c
+++ b/test/core/util/test_tcp_server.c
@@ -46,7 +46,7 @@
 #include "test/core/util/port.h"
 
 static void on_server_destroyed(grpc_exec_ctx *exec_ctx, void *data,
-                                int success) {
+                                bool success) {
   test_tcp_server *server = data;
   server->shutdown = 1;
 }
@@ -97,7 +97,7 @@
   grpc_exec_ctx_finish(&exec_ctx);
 }
 
-static void do_nothing(grpc_exec_ctx *exec_ctx, void *arg, int success) {}
+static void do_nothing(grpc_exec_ctx *exec_ctx, void *arg, bool success) {}
 
 void test_tcp_server_destroy(test_tcp_server *server) {
   grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
diff --git a/test/cpp/common/alarm_test.cc b/test/cpp/common/alarm_cpp_test.cc
similarity index 79%
rename from test/cpp/common/alarm_test.cc
rename to test/cpp/common/alarm_cpp_test.cc
index d41a25a..4745ef1 100644
--- a/test/cpp/common/alarm_test.cc
+++ b/test/cpp/common/alarm_cpp_test.cc
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -40,52 +40,42 @@
 namespace grpc {
 namespace {
 
-class TestTag : public CompletionQueueTag {
- public:
-  TestTag() : tag_(0) {}
-  TestTag(intptr_t tag) : tag_(tag) {}
-  bool FinalizeResult(void** tag, bool* status) { return true; }
-  intptr_t tag() { return tag_; }
-
- private:
-  intptr_t tag_;
-};
-
 TEST(AlarmTest, RegularExpiry) {
   CompletionQueue cq;
-  TestTag input_tag(1618033);
-  Alarm alarm(&cq, GRPC_TIMEOUT_SECONDS_TO_DEADLINE(1), &input_tag);
+  void* junk = reinterpret_cast<void*>(1618033);
+  Alarm alarm(&cq, GRPC_TIMEOUT_SECONDS_TO_DEADLINE(1), junk);
 
-  TestTag* output_tag;
+  void* output_tag;
   bool ok;
   const CompletionQueue::NextStatus status = cq.AsyncNext(
       (void**)&output_tag, &ok, GRPC_TIMEOUT_SECONDS_TO_DEADLINE(2));
 
   EXPECT_EQ(status, CompletionQueue::GOT_EVENT);
   EXPECT_TRUE(ok);
-  EXPECT_EQ(output_tag->tag(), input_tag.tag());
+  EXPECT_EQ(junk, output_tag);
 }
 
 TEST(AlarmTest, Cancellation) {
   CompletionQueue cq;
-  TestTag input_tag(1618033);
-  Alarm alarm(&cq, GRPC_TIMEOUT_SECONDS_TO_DEADLINE(2), &input_tag);
+  void* junk = reinterpret_cast<void*>(1618033);
+  Alarm alarm(&cq, GRPC_TIMEOUT_SECONDS_TO_DEADLINE(2), junk);
   alarm.Cancel();
 
-  TestTag* output_tag;
+  void* output_tag;
   bool ok;
   const CompletionQueue::NextStatus status = cq.AsyncNext(
       (void**)&output_tag, &ok, GRPC_TIMEOUT_SECONDS_TO_DEADLINE(1));
 
   EXPECT_EQ(status, CompletionQueue::GOT_EVENT);
   EXPECT_FALSE(ok);
-  EXPECT_EQ(output_tag->tag(), input_tag.tag());
+  EXPECT_EQ(junk, output_tag);
 }
 
 }  // namespace
 }  // namespace grpc
 
 int main(int argc, char** argv) {
+  grpc_test_init(argc, argv);
   ::testing::InitGoogleTest(&argc, argv);
   return RUN_ALL_TESTS();
 }
diff --git a/test/cpp/end2end/async_end2end_test.cc b/test/cpp/end2end/async_end2end_test.cc
index cfda571..252bda3 100644
--- a/test/cpp/end2end/async_end2end_test.cc
+++ b/test/cpp/end2end/async_end2end_test.cc
@@ -32,6 +32,7 @@
  */
 
 #include <memory>
+#include <thread>
 
 #include <grpc++/channel.h>
 #include <grpc++/client_context.h>
@@ -104,7 +105,10 @@
     expectations_[tag(i)] = expect_ok;
     return *this;
   }
-  void Verify(CompletionQueue* cq) {
+
+  void Verify(CompletionQueue* cq) { Verify(cq, false); }
+
+  void Verify(CompletionQueue* cq, bool ignore_ok) {
     GPR_ASSERT(!expectations_.empty());
     while (!expectations_.empty()) {
       bool ok;
@@ -122,7 +126,9 @@
       }
       auto it = expectations_.find(got_tag);
       EXPECT_TRUE(it != expectations_.end());
-      EXPECT_EQ(it->second, ok);
+      if (!ignore_ok) {
+        EXPECT_EQ(it->second, ok);
+      }
       expectations_.erase(it);
     }
   }
@@ -180,21 +186,11 @@
     int port = grpc_pick_unused_port_or_die();
     server_address_ << "localhost:" << port;
 
-    // It is currently unsupported to mix sync and async services
-    // in the same server, so first test that (for coverage)
-    ServerBuilder build_bad;
-    build_bad.AddListeningPort(server_address_.str(),
-                               grpc::InsecureServerCredentials());
-    build_bad.RegisterAsyncService(&service_);
-    grpc::testing::EchoTestService::Service sync_service;
-    build_bad.RegisterService(&sync_service);
-    GPR_ASSERT(build_bad.BuildAndStart() == nullptr);
-
     // Setup server
     ServerBuilder builder;
     builder.AddListeningPort(server_address_.str(),
                              grpc::InsecureServerCredentials());
-    builder.RegisterAsyncService(&service_);
+    builder.RegisterService(&service_);
     cq_ = builder.AddCompletionQueue();
     server_ = builder.BuildAndStart();
   }
@@ -227,7 +223,7 @@
       grpc::ServerAsyncResponseWriter<EchoResponse> response_writer(&srv_ctx);
 
       send_request.set_message("Hello");
-      std::unique_ptr<ClientAsyncResponseReader<EchoResponse> > response_reader(
+      std::unique_ptr<ClientAsyncResponseReader<EchoResponse>> response_reader(
           stub_->AsyncEcho(&cli_ctx, send_request, cq_.get()));
 
       service_.RequestEcho(&srv_ctx, &recv_request, &response_writer, cq_.get(),
@@ -280,7 +276,7 @@
   grpc::ServerAsyncResponseWriter<EchoResponse> response_writer(&srv_ctx);
 
   send_request.set_message("Hello");
-  std::unique_ptr<ClientAsyncResponseReader<EchoResponse> > response_reader(
+  std::unique_ptr<ClientAsyncResponseReader<EchoResponse>> response_reader(
       stub_->AsyncEcho(&cli_ctx, send_request, cq_.get()));
 
   std::chrono::system_clock::time_point time_now(
@@ -325,7 +321,7 @@
   ServerAsyncReader<EchoResponse, EchoRequest> srv_stream(&srv_ctx);
 
   send_request.set_message("Hello");
-  std::unique_ptr<ClientAsyncWriter<EchoRequest> > cli_stream(
+  std::unique_ptr<ClientAsyncWriter<EchoRequest>> cli_stream(
       stub_->AsyncRequestStream(&cli_ctx, &recv_response, cq_.get(), tag(1)));
 
   service_.RequestRequestStream(&srv_ctx, &srv_stream, cq_.get(), cq_.get(),
@@ -378,7 +374,7 @@
   ServerAsyncWriter<EchoResponse> srv_stream(&srv_ctx);
 
   send_request.set_message("Hello");
-  std::unique_ptr<ClientAsyncReader<EchoResponse> > cli_stream(
+  std::unique_ptr<ClientAsyncReader<EchoResponse>> cli_stream(
       stub_->AsyncResponseStream(&cli_ctx, send_request, cq_.get(), tag(1)));
 
   service_.RequestResponseStream(&srv_ctx, &recv_request, &srv_stream,
@@ -428,7 +424,7 @@
   ServerAsyncReaderWriter<EchoResponse, EchoRequest> srv_stream(&srv_ctx);
 
   send_request.set_message("Hello");
-  std::unique_ptr<ClientAsyncReaderWriter<EchoRequest, EchoResponse> >
+  std::unique_ptr<ClientAsyncReaderWriter<EchoRequest, EchoResponse>>
       cli_stream(stub_->AsyncBidiStream(&cli_ctx, cq_.get(), tag(1)));
 
   service_.RequestBidiStream(&srv_ctx, &srv_stream, cq_.get(), cq_.get(),
@@ -486,7 +482,7 @@
   cli_ctx.AddMetadata(meta1.first, meta1.second);
   cli_ctx.AddMetadata(meta2.first, meta2.second);
 
-  std::unique_ptr<ClientAsyncResponseReader<EchoResponse> > response_reader(
+  std::unique_ptr<ClientAsyncResponseReader<EchoResponse>> response_reader(
       stub_->AsyncEcho(&cli_ctx, send_request, cq_.get()));
 
   service_.RequestEcho(&srv_ctx, &recv_request, &response_writer, cq_.get(),
@@ -529,7 +525,7 @@
   std::pair<grpc::string, grpc::string> meta1("key1", "val1");
   std::pair<grpc::string, grpc::string> meta2("key2", "val2");
 
-  std::unique_ptr<ClientAsyncResponseReader<EchoResponse> > response_reader(
+  std::unique_ptr<ClientAsyncResponseReader<EchoResponse>> response_reader(
       stub_->AsyncEcho(&cli_ctx, send_request, cq_.get()));
 
   service_.RequestEcho(&srv_ctx, &recv_request, &response_writer, cq_.get(),
@@ -578,7 +574,7 @@
   std::pair<grpc::string, grpc::string> meta1("key1", "val1");
   std::pair<grpc::string, grpc::string> meta2("key2", "val2");
 
-  std::unique_ptr<ClientAsyncResponseReader<EchoResponse> > response_reader(
+  std::unique_ptr<ClientAsyncResponseReader<EchoResponse>> response_reader(
       stub_->AsyncEcho(&cli_ctx, send_request, cq_.get()));
 
   service_.RequestEcho(&srv_ctx, &recv_request, &response_writer, cq_.get(),
@@ -639,7 +635,7 @@
   cli_ctx.AddMetadata(meta1.first, meta1.second);
   cli_ctx.AddMetadata(meta2.first, meta2.second);
 
-  std::unique_ptr<ClientAsyncResponseReader<EchoResponse> > response_reader(
+  std::unique_ptr<ClientAsyncResponseReader<EchoResponse>> response_reader(
       stub_->AsyncEcho(&cli_ctx, send_request, cq_.get()));
 
   service_.RequestEcho(&srv_ctx, &recv_request, &response_writer, cq_.get(),
@@ -700,7 +696,7 @@
   grpc::ServerAsyncResponseWriter<EchoResponse> response_writer(&srv_ctx);
 
   send_request.set_message("Hello");
-  std::unique_ptr<ClientAsyncResponseReader<EchoResponse> > response_reader(
+  std::unique_ptr<ClientAsyncResponseReader<EchoResponse>> response_reader(
       stub_->AsyncEcho(&cli_ctx, send_request, cq_.get()));
 
   srv_ctx.AsyncNotifyWhenDone(tag(5));
@@ -735,7 +731,7 @@
   grpc::ServerAsyncResponseWriter<EchoResponse> response_writer(&srv_ctx);
 
   send_request.set_message("Hello");
-  std::unique_ptr<ClientAsyncResponseReader<EchoResponse> > response_reader(
+  std::unique_ptr<ClientAsyncResponseReader<EchoResponse>> response_reader(
       stub_->AsyncEcho(&cli_ctx, send_request, cq_.get()));
 
   srv_ctx.AsyncNotifyWhenDone(tag(5));
@@ -769,7 +765,7 @@
 
   ClientContext cli_ctx;
   send_request.set_message("Hello");
-  std::unique_ptr<ClientAsyncResponseReader<EchoResponse> > response_reader(
+  std::unique_ptr<ClientAsyncResponseReader<EchoResponse>> response_reader(
       stub->AsyncUnimplemented(&cli_ctx, send_request, cq_.get()));
 
   response_reader->Finish(&recv_response, &recv_status, tag(4));
@@ -779,8 +775,384 @@
   EXPECT_EQ("", recv_status.error_message());
 }
 
+// This class is for testing scenarios where RPCs are cancelled on the server
+// by calling ServerContext::TryCancel()
+class AsyncEnd2endServerTryCancelTest : public AsyncEnd2endTest {
+ protected:
+  typedef enum {
+    DO_NOT_CANCEL = 0,
+    CANCEL_BEFORE_PROCESSING,
+    CANCEL_DURING_PROCESSING,
+    CANCEL_AFTER_PROCESSING
+  } ServerTryCancelRequestPhase;
+
+  void ServerTryCancel(ServerContext* context) {
+    EXPECT_FALSE(context->IsCancelled());
+    context->TryCancel();
+    gpr_log(GPR_INFO, "Server called TryCancel()");
+    EXPECT_TRUE(context->IsCancelled());
+  }
+
+  // Helper for testing client-streaming RPCs which are cancelled on the server.
+  // Depending on the value of server_try_cancel parameter, this will test one
+  // of the following three scenarios:
+  //   CANCEL_BEFORE_PROCESSING: Rpc is cancelled by the server before reading
+  //   any messages from the client
+  //
+  //   CANCEL_DURING_PROCESSING: Rpc is cancelled by the server while reading
+  //   messages from the client
+  //
+  //   CANCEL_AFTER PROCESSING: Rpc is cancelled by server after reading all
+  //   messages from the client (but before sending any status back to the
+  //   client)
+  void TestClientStreamingServerCancel(
+      ServerTryCancelRequestPhase server_try_cancel) {
+    ResetStub();
+
+    EchoRequest send_request;
+    EchoRequest recv_request;
+    EchoResponse send_response;
+    EchoResponse recv_response;
+    Status recv_status;
+
+    ClientContext cli_ctx;
+    ServerContext srv_ctx;
+    ServerAsyncReader<EchoResponse, EchoRequest> srv_stream(&srv_ctx);
+
+    // Initiate the 'RequestStream' call on client
+    std::unique_ptr<ClientAsyncWriter<EchoRequest>> cli_stream(
+        stub_->AsyncRequestStream(&cli_ctx, &recv_response, cq_.get(), tag(1)));
+    Verifier(GetParam()).Expect(1, true).Verify(cq_.get());
+
+    // On the server, request to be notified of 'RequestStream' calls
+    // and receive the 'RequestStream' call just made by the client
+    service_.RequestRequestStream(&srv_ctx, &srv_stream, cq_.get(), cq_.get(),
+                                  tag(2));
+    Verifier(GetParam()).Expect(2, true).Verify(cq_.get());
+
+    // Client sends 3 messages (tags 3, 4 and 5)
+    for (int tag_idx = 3; tag_idx <= 5; tag_idx++) {
+      send_request.set_message("Ping " + std::to_string(tag_idx));
+      cli_stream->Write(send_request, tag(tag_idx));
+      Verifier(GetParam()).Expect(tag_idx, true).Verify(cq_.get());
+    }
+    cli_stream->WritesDone(tag(6));
+    Verifier(GetParam()).Expect(6, true).Verify(cq_.get());
+
+    bool expected_server_cq_result = true;
+    bool ignore_cq_result = false;
+
+    if (server_try_cancel == CANCEL_BEFORE_PROCESSING) {
+      ServerTryCancel(&srv_ctx);
+
+      // Since cancellation is done before server reads any results, we know
+      // for sure that all cq results will return false from this point forward
+      expected_server_cq_result = false;
+    }
+
+    std::thread* server_try_cancel_thd = NULL;
+    if (server_try_cancel == CANCEL_DURING_PROCESSING) {
+      server_try_cancel_thd = new std::thread(
+          &AsyncEnd2endServerTryCancelTest::ServerTryCancel, this, &srv_ctx);
+      // Server will cancel the RPC in a parallel thread while reading the
+      // requests from the client. Since the cancellation can happen at anytime,
+      // some of the cq results (i.e those until cancellation) might be true but
+      // its non deterministic. So better to ignore the cq results
+      ignore_cq_result = true;
+    }
+
+    // Server reads 3 messages (tags 6, 7 and 8)
+    for (int tag_idx = 6; tag_idx <= 8; tag_idx++) {
+      srv_stream.Read(&recv_request, tag(tag_idx));
+      Verifier(GetParam())
+          .Expect(tag_idx, expected_server_cq_result)
+          .Verify(cq_.get(), ignore_cq_result);
+    }
+
+    if (server_try_cancel_thd != NULL) {
+      server_try_cancel_thd->join();
+      delete server_try_cancel_thd;
+    }
+
+    if (server_try_cancel == CANCEL_AFTER_PROCESSING) {
+      ServerTryCancel(&srv_ctx);
+    }
+
+    // The RPC has been cancelled at this point for sure (i.e irrespective of
+    // the value of `server_try_cancel` is). So, from this point forward, we
+    // know that cq results are supposed to return false on server.
+
+    // Server sends the final message and cancelled status (but the RPC is
+    // already cancelled at this point. So we expect the operation to fail)
+    srv_stream.Finish(send_response, Status::CANCELLED, tag(9));
+    Verifier(GetParam()).Expect(9, false).Verify(cq_.get());
+
+    // Client will see the cancellation
+    cli_stream->Finish(&recv_status, tag(10));
+    // TODO(sreek): The expectation here should be true. This is a bug (github
+    // issue #4972)
+    Verifier(GetParam()).Expect(10, false).Verify(cq_.get());
+    EXPECT_FALSE(recv_status.ok());
+    EXPECT_EQ(::grpc::StatusCode::CANCELLED, recv_status.error_code());
+  }
+
+  // Helper for testing server-streaming RPCs which are cancelled on the server.
+  // Depending on the value of server_try_cancel parameter, this will test one
+  // of the following three scenarios:
+  //   CANCEL_BEFORE_PROCESSING: Rpc is cancelled by the server before sending
+  //   any messages to the client
+  //
+  //   CANCEL_DURING_PROCESSING: Rpc is cancelled by the server while sending
+  //   messages to the client
+  //
+  //   CANCEL_AFTER PROCESSING: Rpc is cancelled by server after sending all
+  //   messages to the client (but before sending any status back to the
+  //   client)
+  void TestServerStreamingServerCancel(
+      ServerTryCancelRequestPhase server_try_cancel) {
+    ResetStub();
+
+    EchoRequest send_request;
+    EchoRequest recv_request;
+    EchoResponse send_response;
+    EchoResponse recv_response;
+    Status recv_status;
+    ClientContext cli_ctx;
+    ServerContext srv_ctx;
+    ServerAsyncWriter<EchoResponse> srv_stream(&srv_ctx);
+
+    send_request.set_message("Ping");
+    // Initiate the 'ResponseStream' call on the client
+    std::unique_ptr<ClientAsyncReader<EchoResponse>> cli_stream(
+        stub_->AsyncResponseStream(&cli_ctx, send_request, cq_.get(), tag(1)));
+    Verifier(GetParam()).Expect(1, true).Verify(cq_.get());
+    // On the server, request to be notified of 'ResponseStream' calls and
+    // receive the call just made by the client
+    service_.RequestResponseStream(&srv_ctx, &recv_request, &srv_stream,
+                                   cq_.get(), cq_.get(), tag(2));
+    Verifier(GetParam()).Expect(2, true).Verify(cq_.get());
+    EXPECT_EQ(send_request.message(), recv_request.message());
+
+    bool expected_cq_result = true;
+    bool ignore_cq_result = false;
+
+    if (server_try_cancel == CANCEL_BEFORE_PROCESSING) {
+      ServerTryCancel(&srv_ctx);
+
+      // We know for sure that all cq results will be false from this point
+      // since the server cancelled the RPC
+      expected_cq_result = false;
+    }
+
+    std::thread* server_try_cancel_thd = NULL;
+    if (server_try_cancel == CANCEL_DURING_PROCESSING) {
+      server_try_cancel_thd = new std::thread(
+          &AsyncEnd2endServerTryCancelTest::ServerTryCancel, this, &srv_ctx);
+
+      // Server will cancel the RPC in a parallel thread while writing responses
+      // to the client. Since the cancellation can happen at anytime, some of
+      // the cq results (i.e those until cancellation) might be true but it is
+      // non deterministic. So better to ignore the cq results
+      ignore_cq_result = true;
+    }
+
+    // Server sends three messages (tags 3, 4 and 5)
+    for (int tag_idx = 3; tag_idx <= 5; tag_idx++) {
+      send_response.set_message("Pong " + std::to_string(tag_idx));
+      srv_stream.Write(send_response, tag(tag_idx));
+      Verifier(GetParam())
+          .Expect(tag_idx, expected_cq_result)
+          .Verify(cq_.get(), ignore_cq_result);
+    }
+
+    if (server_try_cancel_thd != NULL) {
+      server_try_cancel_thd->join();
+      delete server_try_cancel_thd;
+    }
+
+    if (server_try_cancel == CANCEL_AFTER_PROCESSING) {
+      ServerTryCancel(&srv_ctx);
+    }
+
+    // Client attemts to read the three messages from the server
+    for (int tag_idx = 6; tag_idx <= 8; tag_idx++) {
+      cli_stream->Read(&recv_response, tag(tag_idx));
+      Verifier(GetParam())
+          .Expect(tag_idx, expected_cq_result)
+          .Verify(cq_.get(), ignore_cq_result);
+    }
+
+    // The RPC has been cancelled at this point for sure (i.e irrespective of
+    // the value of `server_try_cancel` is). So, from this point forward, we
+    // know that cq results are supposed to return false on server.
+
+    // Server finishes the stream (but the RPC is already cancelled)
+    srv_stream.Finish(Status::CANCELLED, tag(9));
+    Verifier(GetParam()).Expect(9, false).Verify(cq_.get());
+
+    // Client will see the cancellation
+    cli_stream->Finish(&recv_status, tag(10));
+    Verifier(GetParam()).Expect(10, true).Verify(cq_.get());
+    EXPECT_FALSE(recv_status.ok());
+    EXPECT_EQ(::grpc::StatusCode::CANCELLED, recv_status.error_code());
+  }
+
+  // Helper for testing bidirectinal-streaming RPCs which are cancelled on the
+  // server.
+  //
+  // Depending on the value of server_try_cancel parameter, this will
+  // test one of the following three scenarios:
+  //   CANCEL_BEFORE_PROCESSING: Rpc is cancelled by the server before reading/
+  //   writing any messages from/to the client
+  //
+  //   CANCEL_DURING_PROCESSING: Rpc is cancelled by the server while reading
+  //   messages from the client
+  //
+  //   CANCEL_AFTER PROCESSING: Rpc is cancelled by server after reading all
+  //   messages from the client (but before sending any status back to the
+  //   client)
+  void TestBidiStreamingServerCancel(
+      ServerTryCancelRequestPhase server_try_cancel) {
+    ResetStub();
+
+    EchoRequest send_request;
+    EchoRequest recv_request;
+    EchoResponse send_response;
+    EchoResponse recv_response;
+    Status recv_status;
+    ClientContext cli_ctx;
+    ServerContext srv_ctx;
+    ServerAsyncReaderWriter<EchoResponse, EchoRequest> srv_stream(&srv_ctx);
+
+    // Initiate the call from the client side
+    std::unique_ptr<ClientAsyncReaderWriter<EchoRequest, EchoResponse>>
+        cli_stream(stub_->AsyncBidiStream(&cli_ctx, cq_.get(), tag(1)));
+    Verifier(GetParam()).Expect(1, true).Verify(cq_.get());
+
+    // On the server, request to be notified of the 'BidiStream' call and
+    // receive the call just made by the client
+    service_.RequestBidiStream(&srv_ctx, &srv_stream, cq_.get(), cq_.get(),
+                               tag(2));
+    Verifier(GetParam()).Expect(2, true).Verify(cq_.get());
+
+    // Client sends the first and the only message
+    send_request.set_message("Ping");
+    cli_stream->Write(send_request, tag(3));
+    Verifier(GetParam()).Expect(3, true).Verify(cq_.get());
+
+    bool expected_cq_result = true;
+    bool ignore_cq_result = false;
+
+    if (server_try_cancel == CANCEL_BEFORE_PROCESSING) {
+      ServerTryCancel(&srv_ctx);
+
+      // We know for sure that all cq results will be false from this point
+      // since the server cancelled the RPC
+      expected_cq_result = false;
+    }
+
+    std::thread* server_try_cancel_thd = NULL;
+    if (server_try_cancel == CANCEL_DURING_PROCESSING) {
+      server_try_cancel_thd = new std::thread(
+          &AsyncEnd2endServerTryCancelTest::ServerTryCancel, this, &srv_ctx);
+
+      // Since server is going to cancel the RPC in a parallel thread, some of
+      // the cq results (i.e those until the cancellation) might be true. Since
+      // that number is non-deterministic, it is better to ignore the cq results
+      ignore_cq_result = true;
+    }
+
+    srv_stream.Read(&recv_request, tag(4));
+    Verifier(GetParam())
+        .Expect(4, expected_cq_result)
+        .Verify(cq_.get(), ignore_cq_result);
+
+    send_response.set_message("Pong");
+    srv_stream.Write(send_response, tag(5));
+    Verifier(GetParam())
+        .Expect(5, expected_cq_result)
+        .Verify(cq_.get(), ignore_cq_result);
+
+    cli_stream->Read(&recv_response, tag(6));
+    Verifier(GetParam())
+        .Expect(6, expected_cq_result)
+        .Verify(cq_.get(), ignore_cq_result);
+
+    // This is expected to succeed in all cases
+    cli_stream->WritesDone(tag(7));
+    Verifier(GetParam()).Expect(7, true).Verify(cq_.get());
+
+    // This is expected to fail in all cases i.e for all values of
+    // server_try_cancel. This is becasue at this point, either there are no
+    // more msgs from the client (because client called WritesDone) or the RPC
+    // is cancelled on the server
+    srv_stream.Read(&recv_request, tag(8));
+    Verifier(GetParam()).Expect(8, false).Verify(cq_.get());
+
+    if (server_try_cancel_thd != NULL) {
+      server_try_cancel_thd->join();
+      delete server_try_cancel_thd;
+    }
+
+    if (server_try_cancel == CANCEL_AFTER_PROCESSING) {
+      ServerTryCancel(&srv_ctx);
+    }
+
+    // The RPC has been cancelled at this point for sure (i.e irrespective of
+    // the value of `server_try_cancel` is). So, from this point forward, we
+    // know that cq results are supposed to return false on server.
+
+    srv_stream.Finish(Status::CANCELLED, tag(9));
+    Verifier(GetParam()).Expect(9, false).Verify(cq_.get());
+
+    cli_stream->Finish(&recv_status, tag(10));
+    Verifier(GetParam()).Expect(10, true).Verify(cq_.get());
+    EXPECT_FALSE(recv_status.ok());
+    EXPECT_EQ(grpc::StatusCode::CANCELLED, recv_status.error_code());
+  }
+};
+
+TEST_P(AsyncEnd2endServerTryCancelTest, ClientStreamingServerTryCancelBefore) {
+  TestClientStreamingServerCancel(CANCEL_BEFORE_PROCESSING);
+}
+
+TEST_P(AsyncEnd2endServerTryCancelTest, ClientStreamingServerTryCancelDuring) {
+  TestClientStreamingServerCancel(CANCEL_DURING_PROCESSING);
+}
+
+TEST_P(AsyncEnd2endServerTryCancelTest, ClientStreamingServerTryCancelAfter) {
+  TestClientStreamingServerCancel(CANCEL_AFTER_PROCESSING);
+}
+
+TEST_P(AsyncEnd2endServerTryCancelTest, ServerStreamingServerTryCancelBefore) {
+  TestServerStreamingServerCancel(CANCEL_BEFORE_PROCESSING);
+}
+
+TEST_P(AsyncEnd2endServerTryCancelTest, ServerStreamingServerTryCancelDuring) {
+  TestServerStreamingServerCancel(CANCEL_DURING_PROCESSING);
+}
+
+TEST_P(AsyncEnd2endServerTryCancelTest, ServerStreamingServerTryCancelAfter) {
+  TestServerStreamingServerCancel(CANCEL_AFTER_PROCESSING);
+}
+
+TEST_P(AsyncEnd2endServerTryCancelTest, ServerBidiStreamingTryCancelBefore) {
+  TestBidiStreamingServerCancel(CANCEL_BEFORE_PROCESSING);
+}
+
+TEST_P(AsyncEnd2endServerTryCancelTest, ServerBidiStreamingTryCancelDuring) {
+  TestBidiStreamingServerCancel(CANCEL_DURING_PROCESSING);
+}
+
+TEST_P(AsyncEnd2endServerTryCancelTest, ServerBidiStreamingTryCancelAfter) {
+  TestBidiStreamingServerCancel(CANCEL_AFTER_PROCESSING);
+}
+
 INSTANTIATE_TEST_CASE_P(AsyncEnd2end, AsyncEnd2endTest,
                         ::testing::Values(false, true));
+INSTANTIATE_TEST_CASE_P(AsyncEnd2endServerTryCancel,
+                        AsyncEnd2endServerTryCancelTest,
+                        ::testing::Values(false));
 
 }  // namespace
 }  // namespace testing
diff --git a/test/cpp/end2end/end2end_test.cc b/test/cpp/end2end/end2end_test.cc
index f8027bc..65da71b 100644
--- a/test/cpp/end2end/end2end_test.cc
+++ b/test/cpp/end2end/end2end_test.cc
@@ -54,6 +54,7 @@
 #include "test/core/end2end/data/ssl_test_data.h"
 #include "test/core/util/port.h"
 #include "test/core/util/test_config.h"
+#include "test/cpp/end2end/test_service_impl.h"
 #include "test/cpp/util/string_ref_helper.h"
 
 using grpc::testing::EchoRequest;
@@ -64,40 +65,6 @@
 namespace testing {
 namespace {
 
-const char* kServerCancelAfterReads = "cancel_after_reads";
-
-// When echo_deadline is requested, deadline seen in the ServerContext is set in
-// the response in seconds.
-void MaybeEchoDeadline(ServerContext* context, const EchoRequest* request,
-                       EchoResponse* response) {
-  if (request->has_param() && request->param().echo_deadline()) {
-    gpr_timespec deadline = gpr_inf_future(GPR_CLOCK_REALTIME);
-    if (context->deadline() != system_clock::time_point::max()) {
-      Timepoint2Timespec(context->deadline(), &deadline);
-    }
-    response->mutable_param()->set_request_deadline(deadline.tv_sec);
-  }
-}
-
-void CheckServerAuthContext(const ServerContext* context,
-                            const grpc::string& expected_client_identity) {
-  std::shared_ptr<const AuthContext> auth_ctx = context->auth_context();
-  std::vector<grpc::string_ref> ssl =
-      auth_ctx->FindPropertyValues("transport_security_type");
-  EXPECT_EQ(1u, ssl.size());
-  EXPECT_EQ("ssl", ToString(ssl[0]));
-  if (expected_client_identity.length() == 0) {
-    EXPECT_TRUE(auth_ctx->GetPeerIdentityPropertyName().empty());
-    EXPECT_TRUE(auth_ctx->GetPeerIdentity().empty());
-    EXPECT_FALSE(auth_ctx->IsPeerAuthenticated());
-  } else {
-    auto identity = auth_ctx->GetPeerIdentity();
-    EXPECT_TRUE(auth_ctx->IsPeerAuthenticated());
-    EXPECT_EQ(1u, identity.size());
-    EXPECT_EQ(expected_client_identity, identity[0]);
-  }
-}
-
 bool CheckIsLocalhost(const grpc::string& addr) {
   const grpc::string kIpv6("ipv6:[::1]:");
   const grpc::string kIpv4MappedIpv6("ipv6:[::ffff:127.0.0.1]:");
@@ -212,137 +179,6 @@
   std::unique_ptr< ::grpc::testing::EchoTestService::Stub> stub_;
 };
 
-class TestServiceImpl : public ::grpc::testing::EchoTestService::Service {
- public:
-  TestServiceImpl() : signal_client_(false), host_() {}
-  explicit TestServiceImpl(const grpc::string& host)
-      : signal_client_(false), host_(new grpc::string(host)) {}
-
-  Status Echo(ServerContext* context, const EchoRequest* request,
-              EchoResponse* response) GRPC_OVERRIDE {
-    response->set_message(request->message());
-    MaybeEchoDeadline(context, request, response);
-    if (host_) {
-      response->mutable_param()->set_host(*host_);
-    }
-    if (request->has_param() && request->param().client_cancel_after_us()) {
-      {
-        std::unique_lock<std::mutex> lock(mu_);
-        signal_client_ = true;
-      }
-      while (!context->IsCancelled()) {
-        gpr_sleep_until(gpr_time_add(
-            gpr_now(GPR_CLOCK_REALTIME),
-            gpr_time_from_micros(request->param().client_cancel_after_us(),
-                                 GPR_TIMESPAN)));
-      }
-      return Status::CANCELLED;
-    } else if (request->has_param() &&
-               request->param().server_cancel_after_us()) {
-      gpr_sleep_until(gpr_time_add(
-          gpr_now(GPR_CLOCK_REALTIME),
-          gpr_time_from_micros(request->param().server_cancel_after_us(),
-                               GPR_TIMESPAN)));
-      return Status::CANCELLED;
-    } else {
-      EXPECT_FALSE(context->IsCancelled());
-    }
-
-    if (request->has_param() && request->param().echo_metadata()) {
-      const std::multimap<grpc::string_ref, grpc::string_ref>& client_metadata =
-          context->client_metadata();
-      for (std::multimap<grpc::string_ref, grpc::string_ref>::const_iterator
-               iter = client_metadata.begin();
-           iter != client_metadata.end(); ++iter) {
-        context->AddTrailingMetadata(ToString(iter->first),
-                                     ToString(iter->second));
-      }
-    }
-    if (request->has_param() &&
-        (request->param().expected_client_identity().length() > 0 ||
-         request->param().check_auth_context())) {
-      CheckServerAuthContext(context,
-                             request->param().expected_client_identity());
-    }
-    if (request->has_param() &&
-        request->param().response_message_length() > 0) {
-      response->set_message(
-          grpc::string(request->param().response_message_length(), '\0'));
-    }
-    if (request->has_param() && request->param().echo_peer()) {
-      response->mutable_param()->set_peer(context->peer());
-    }
-    return Status::OK;
-  }
-
-  // Unimplemented is left unimplemented to test the returned error.
-
-  Status RequestStream(ServerContext* context,
-                       ServerReader<EchoRequest>* reader,
-                       EchoResponse* response) GRPC_OVERRIDE {
-    EchoRequest request;
-    response->set_message("");
-    int cancel_after_reads = 0;
-    const std::multimap<grpc::string_ref, grpc::string_ref>&
-        client_initial_metadata = context->client_metadata();
-    if (client_initial_metadata.find(kServerCancelAfterReads) !=
-        client_initial_metadata.end()) {
-      std::istringstream iss(ToString(
-          client_initial_metadata.find(kServerCancelAfterReads)->second));
-      iss >> cancel_after_reads;
-      gpr_log(GPR_INFO, "cancel_after_reads %d", cancel_after_reads);
-    }
-    while (reader->Read(&request)) {
-      if (cancel_after_reads == 1) {
-        gpr_log(GPR_INFO, "return cancel status");
-        return Status::CANCELLED;
-      } else if (cancel_after_reads > 0) {
-        cancel_after_reads--;
-      }
-      response->mutable_message()->append(request.message());
-    }
-    return Status::OK;
-  }
-
-  // Return 3 messages.
-  // TODO(yangg) make it generic by adding a parameter into EchoRequest
-  Status ResponseStream(ServerContext* context, const EchoRequest* request,
-                        ServerWriter<EchoResponse>* writer) GRPC_OVERRIDE {
-    EchoResponse response;
-    response.set_message(request->message() + "0");
-    writer->Write(response);
-    response.set_message(request->message() + "1");
-    writer->Write(response);
-    response.set_message(request->message() + "2");
-    writer->Write(response);
-
-    return Status::OK;
-  }
-
-  Status BidiStream(ServerContext* context,
-                    ServerReaderWriter<EchoResponse, EchoRequest>* stream)
-      GRPC_OVERRIDE {
-    EchoRequest request;
-    EchoResponse response;
-    while (stream->Read(&request)) {
-      gpr_log(GPR_INFO, "recv msg %s", request.message().c_str());
-      response.set_message(request.message());
-      stream->Write(response);
-    }
-    return Status::OK;
-  }
-
-  bool signal_client() {
-    std::unique_lock<std::mutex> lock(mu_);
-    return signal_client_;
-  }
-
- private:
-  bool signal_client_;
-  std::mutex mu_;
-  std::unique_ptr<grpc::string> host_;
-};
-
 class TestServiceImplDupPkg
     : public ::grpc::testing::duplicate::EchoTestService::Service {
  public:
@@ -451,13 +287,18 @@
   TestServiceImplDupPkg dup_pkg_service_;
 };
 
-static void SendRpc(grpc::testing::EchoTestService::Stub* stub, int num_rpcs) {
+static void SendRpc(grpc::testing::EchoTestService::Stub* stub, int num_rpcs,
+                    bool with_binary_metadata) {
   EchoRequest request;
   EchoResponse response;
   request.set_message("Hello hello hello hello");
 
   for (int i = 0; i < num_rpcs; ++i) {
     ClientContext context;
+    if (with_binary_metadata) {
+      char bytes[8] = {'\0', '\1', '\2', '\3', '\4', '\5', '\6', (char)i};
+      context.AddMetadata("custom-bin", grpc::string(bytes, 8));
+    }
     context.set_compression_algorithm(GRPC_COMPRESS_GZIP);
     Status s = stub->Echo(&context, request, &response);
     EXPECT_EQ(response.message(), request.message());
@@ -465,6 +306,325 @@
   }
 }
 
+// This class is for testing scenarios where RPCs are cancelled on the server
+// by calling ServerContext::TryCancel()
+class End2endServerTryCancelTest : public End2endTest {
+ protected:
+  // Helper for testing client-streaming RPCs which are cancelled on the server.
+  // Depending on the value of server_try_cancel parameter, this will test one
+  // of the following three scenarios:
+  //   CANCEL_BEFORE_PROCESSING: Rpc is cancelled by the server before reading
+  //   any messages from the client
+  //
+  //   CANCEL_DURING_PROCESSING: Rpc is cancelled by the server while reading
+  //   messages from the client
+  //
+  //   CANCEL_AFTER PROCESSING: Rpc is cancelled by server after reading all
+  //   the messages from the client
+  //
+  // NOTE: Do not call this function with server_try_cancel == DO_NOT_CANCEL.
+  void TestRequestStreamServerCancel(
+      ServerTryCancelRequestPhase server_try_cancel, int num_msgs_to_send) {
+    ResetStub();
+    EchoRequest request;
+    EchoResponse response;
+    ClientContext context;
+
+    // Send server_try_cancel value in the client metadata
+    context.AddMetadata(kServerTryCancelRequest,
+                        std::to_string(server_try_cancel));
+
+    auto stream = stub_->RequestStream(&context, &response);
+
+    int num_msgs_sent = 0;
+    while (num_msgs_sent < num_msgs_to_send) {
+      request.set_message("hello");
+      if (!stream->Write(request)) {
+        break;
+      }
+      num_msgs_sent++;
+    }
+    gpr_log(GPR_INFO, "Sent %d messages", num_msgs_sent);
+
+    stream->WritesDone();
+    Status s = stream->Finish();
+
+    // At this point, we know for sure that RPC was cancelled by the server
+    // since we passed server_try_cancel value in the metadata. Depending on the
+    // value of server_try_cancel, the RPC might have been cancelled by the
+    // server at different stages. The following validates our expectations of
+    // number of messages sent in various cancellation scenarios:
+
+    switch (server_try_cancel) {
+      case CANCEL_BEFORE_PROCESSING:
+      case CANCEL_DURING_PROCESSING:
+        // If the RPC is cancelled by server before / during messages from the
+        // client, it means that the client most likely did not get a chance to
+        // send all the messages it wanted to send. i.e num_msgs_sent <=
+        // num_msgs_to_send
+        EXPECT_LE(num_msgs_sent, num_msgs_to_send);
+        break;
+
+      case CANCEL_AFTER_PROCESSING:
+        // If the RPC was cancelled after all messages were read by the server,
+        // the client did get a chance to send all its messages
+        EXPECT_EQ(num_msgs_sent, num_msgs_to_send);
+        break;
+
+      default:
+        gpr_log(GPR_ERROR, "Invalid server_try_cancel value: %d",
+                server_try_cancel);
+        EXPECT_TRUE(server_try_cancel > DO_NOT_CANCEL &&
+                    server_try_cancel <= CANCEL_AFTER_PROCESSING);
+        break;
+    }
+
+    EXPECT_FALSE(s.ok());
+    EXPECT_EQ(grpc::StatusCode::CANCELLED, s.error_code());
+  }
+
+  // Helper for testing server-streaming RPCs which are cancelled on the server.
+  // Depending on the value of server_try_cancel parameter, this will test one
+  // of the following three scenarios:
+  //   CANCEL_BEFORE_PROCESSING: Rpc is cancelled by the server before writing
+  //   any messages to the client
+  //
+  //   CANCEL_DURING_PROCESSING: Rpc is cancelled by the server while writing
+  //   messages to the client
+  //
+  //   CANCEL_AFTER PROCESSING: Rpc is cancelled by server after writing all
+  //   the messages to the client
+  //
+  // NOTE: Do not call this function with server_try_cancel == DO_NOT_CANCEL.
+  void TestResponseStreamServerCancel(
+      ServerTryCancelRequestPhase server_try_cancel) {
+    ResetStub();
+    EchoRequest request;
+    EchoResponse response;
+    ClientContext context;
+
+    // Send server_try_cancel in the client metadata
+    context.AddMetadata(kServerTryCancelRequest,
+                        std::to_string(server_try_cancel));
+
+    request.set_message("hello");
+    auto stream = stub_->ResponseStream(&context, request);
+
+    int num_msgs_read = 0;
+    while (num_msgs_read < kNumResponseStreamsMsgs) {
+      if (!stream->Read(&response)) {
+        break;
+      }
+      EXPECT_EQ(response.message(),
+                request.message() + std::to_string(num_msgs_read));
+      num_msgs_read++;
+    }
+    gpr_log(GPR_INFO, "Read %d messages", num_msgs_read);
+
+    Status s = stream->Finish();
+
+    // Depending on the value of server_try_cancel, the RPC might have been
+    // cancelled by the server at different stages. The following validates our
+    // expectations of number of messages read in various cancellation
+    // scenarios:
+    switch (server_try_cancel) {
+      case CANCEL_BEFORE_PROCESSING:
+        // Server cancelled before sending any messages. Which means the client
+        // wouldn't have read any
+        EXPECT_EQ(num_msgs_read, 0);
+        break;
+
+      case CANCEL_DURING_PROCESSING:
+        // Server cancelled while writing messages. Client must have read less
+        // than or equal to the expected number of messages
+        EXPECT_LE(num_msgs_read, kNumResponseStreamsMsgs);
+        break;
+
+      case CANCEL_AFTER_PROCESSING:
+        // Server cancelled after writing all messages. Client must have read
+        // all messages
+        EXPECT_EQ(num_msgs_read, kNumResponseStreamsMsgs);
+        break;
+
+      default: {
+        gpr_log(GPR_ERROR, "Invalid server_try_cancel value: %d",
+                server_try_cancel);
+        EXPECT_TRUE(server_try_cancel > DO_NOT_CANCEL &&
+                    server_try_cancel <= CANCEL_AFTER_PROCESSING);
+        break;
+      }
+    }
+
+    EXPECT_FALSE(s.ok());
+    EXPECT_EQ(grpc::StatusCode::CANCELLED, s.error_code());
+  }
+
+  // Helper for testing bidirectional-streaming RPCs which are cancelled on the
+  // server. Depending on the value of server_try_cancel parameter, this will
+  // test one of the following three scenarios:
+  //   CANCEL_BEFORE_PROCESSING: Rpc is cancelled by the server before reading/
+  //   writing any messages from/to the client
+  //
+  //   CANCEL_DURING_PROCESSING: Rpc is cancelled by the server while reading/
+  //   writing messages from/to the client
+  //
+  //   CANCEL_AFTER PROCESSING: Rpc is cancelled by server after reading/writing
+  //   all the messages from/to the client
+  //
+  // NOTE: Do not call this function with server_try_cancel == DO_NOT_CANCEL.
+  void TestBidiStreamServerCancel(ServerTryCancelRequestPhase server_try_cancel,
+                                  int num_messages) {
+    ResetStub();
+    EchoRequest request;
+    EchoResponse response;
+    ClientContext context;
+
+    // Send server_try_cancel in the client metadata
+    context.AddMetadata(kServerTryCancelRequest,
+                        std::to_string(server_try_cancel));
+
+    auto stream = stub_->BidiStream(&context);
+
+    int num_msgs_read = 0;
+    int num_msgs_sent = 0;
+    while (num_msgs_sent < num_messages) {
+      request.set_message("hello " + std::to_string(num_msgs_sent));
+      if (!stream->Write(request)) {
+        break;
+      }
+      num_msgs_sent++;
+
+      if (!stream->Read(&response)) {
+        break;
+      }
+      num_msgs_read++;
+
+      EXPECT_EQ(response.message(), request.message());
+    }
+    gpr_log(GPR_INFO, "Sent %d messages", num_msgs_sent);
+    gpr_log(GPR_INFO, "Read %d messages", num_msgs_read);
+
+    stream->WritesDone();
+    Status s = stream->Finish();
+
+    // Depending on the value of server_try_cancel, the RPC might have been
+    // cancelled by the server at different stages. The following validates our
+    // expectations of number of messages read in various cancellation
+    // scenarios:
+    switch (server_try_cancel) {
+      case CANCEL_BEFORE_PROCESSING:
+        EXPECT_EQ(num_msgs_read, 0);
+        break;
+
+      case CANCEL_DURING_PROCESSING:
+        EXPECT_LE(num_msgs_sent, num_messages);
+        EXPECT_LE(num_msgs_read, num_msgs_sent);
+        break;
+
+      case CANCEL_AFTER_PROCESSING:
+        EXPECT_EQ(num_msgs_sent, num_messages);
+        EXPECT_EQ(num_msgs_read, num_msgs_sent);
+        break;
+
+      default:
+        gpr_log(GPR_ERROR, "Invalid server_try_cancel value: %d",
+                server_try_cancel);
+        EXPECT_TRUE(server_try_cancel > DO_NOT_CANCEL &&
+                    server_try_cancel <= CANCEL_AFTER_PROCESSING);
+        break;
+    }
+
+    EXPECT_FALSE(s.ok());
+    EXPECT_EQ(grpc::StatusCode::CANCELLED, s.error_code());
+  }
+};
+
+TEST_P(End2endServerTryCancelTest, RequestEchoServerCancel) {
+  ResetStub();
+  EchoRequest request;
+  EchoResponse response;
+  ClientContext context;
+
+  context.AddMetadata(kServerTryCancelRequest,
+                      std::to_string(CANCEL_BEFORE_PROCESSING));
+  Status s = stub_->Echo(&context, request, &response);
+  EXPECT_FALSE(s.ok());
+  EXPECT_EQ(grpc::StatusCode::CANCELLED, s.error_code());
+}
+
+// Server to cancel before doing reading the request
+TEST_P(End2endServerTryCancelTest, RequestStreamServerCancelBeforeReads) {
+  TestRequestStreamServerCancel(CANCEL_BEFORE_PROCESSING, 1);
+}
+
+// Server to cancel while reading a request from the stream in parallel
+TEST_P(End2endServerTryCancelTest, RequestStreamServerCancelDuringRead) {
+  TestRequestStreamServerCancel(CANCEL_DURING_PROCESSING, 10);
+}
+
+// Server to cancel after reading all the requests but before returning to the
+// client
+TEST_P(End2endServerTryCancelTest, RequestStreamServerCancelAfterReads) {
+  TestRequestStreamServerCancel(CANCEL_AFTER_PROCESSING, 4);
+}
+
+// Server to cancel before sending any response messages
+TEST_P(End2endServerTryCancelTest, ResponseStreamServerCancelBefore) {
+  TestResponseStreamServerCancel(CANCEL_BEFORE_PROCESSING);
+}
+
+// Server to cancel while writing a response to the stream in parallel
+TEST_P(End2endServerTryCancelTest, ResponseStreamServerCancelDuring) {
+  TestResponseStreamServerCancel(CANCEL_DURING_PROCESSING);
+}
+
+// Server to cancel after writing all the respones to the stream but before
+// returning to the client
+TEST_P(End2endServerTryCancelTest, ResponseStreamServerCancelAfter) {
+  TestResponseStreamServerCancel(CANCEL_AFTER_PROCESSING);
+}
+
+// Server to cancel before reading/writing any requests/responses on the stream
+TEST_P(End2endServerTryCancelTest, BidiStreamServerCancelBefore) {
+  TestBidiStreamServerCancel(CANCEL_BEFORE_PROCESSING, 2);
+}
+
+// Server to cancel while reading/writing requests/responses on the stream in
+// parallel
+TEST_P(End2endServerTryCancelTest, BidiStreamServerCancelDuring) {
+  TestBidiStreamServerCancel(CANCEL_DURING_PROCESSING, 10);
+}
+
+// Server to cancel after reading/writing all requests/responses on the stream
+// but before returning to the client
+TEST_P(End2endServerTryCancelTest, BidiStreamServerCancelAfter) {
+  TestBidiStreamServerCancel(CANCEL_AFTER_PROCESSING, 5);
+}
+
+TEST_P(End2endTest, MultipleRpcsWithVariedBinaryMetadataValue) {
+  ResetStub();
+  std::vector<std::thread*> threads;
+  for (int i = 0; i < 10; ++i) {
+    threads.push_back(new std::thread(SendRpc, stub_.get(), 10, true));
+  }
+  for (int i = 0; i < 10; ++i) {
+    threads[i]->join();
+    delete threads[i];
+  }
+}
+
+TEST_P(End2endTest, MultipleRpcs) {
+  ResetStub();
+  std::vector<std::thread*> threads;
+  for (int i = 0; i < 10; ++i) {
+    threads.push_back(new std::thread(SendRpc, stub_.get(), 10, false));
+  }
+  for (int i = 0; i < 10; ++i) {
+    threads[i]->join();
+    delete threads[i];
+  }
+}
+
 TEST_P(End2endTest, RequestStreamOneRequest) {
   ResetStub();
   EchoRequest request;
@@ -802,14 +962,14 @@
 
 TEST_P(ProxyEnd2endTest, SimpleRpc) {
   ResetStub();
-  SendRpc(stub_.get(), 1);
+  SendRpc(stub_.get(), 1, false);
 }
 
 TEST_P(ProxyEnd2endTest, MultipleRpcs) {
   ResetStub();
   std::vector<std::thread*> threads;
   for (int i = 0; i < 10; ++i) {
-    threads.push_back(new std::thread(SendRpc, stub_.get(), 10));
+    threads.push_back(new std::thread(SendRpc, stub_.get(), 10, false));
   }
   for (int i = 0; i < 10; ++i) {
     threads[i]->join();
@@ -823,6 +983,7 @@
   EchoRequest request;
   EchoResponse response;
   request.set_message("Hello");
+  request.mutable_param()->set_skip_cancelled_check(true);
 
   ClientContext context;
   std::chrono::system_clock::time_point deadline =
@@ -1193,6 +1354,9 @@
                         ::testing::Values(TestScenario(false, false),
                                           TestScenario(false, true)));
 
+INSTANTIATE_TEST_CASE_P(End2endServerTryCancel, End2endServerTryCancelTest,
+                        ::testing::Values(TestScenario(false, false)));
+
 INSTANTIATE_TEST_CASE_P(ProxyEnd2end, ProxyEnd2endTest,
                         ::testing::Values(TestScenario(false, false),
                                           TestScenario(false, true),
diff --git a/test/cpp/end2end/generic_end2end_test.cc b/test/cpp/end2end/generic_end2end_test.cc
index c5d9de3..4e6d50e 100644
--- a/test/cpp/end2end/generic_end2end_test.cc
+++ b/test/cpp/end2end/generic_end2end_test.cc
@@ -51,6 +51,7 @@
 #include "src/proto/grpc/testing/echo.grpc.pb.h"
 #include "test/core/util/port.h"
 #include "test/core/util/test_config.h"
+#include "test/cpp/util/byte_buffer_proto_helper.h"
 
 using grpc::testing::EchoRequest;
 using grpc::testing::EchoResponse;
@@ -70,29 +71,9 @@
   EXPECT_EQ(tag(i), got_tag);
 }
 
-bool ParseFromByteBuffer(ByteBuffer* buffer, grpc::protobuf::Message* message) {
-  std::vector<Slice> slices;
-  buffer->Dump(&slices);
-  grpc::string buf;
-  buf.reserve(buffer->Length());
-  for (auto s = slices.begin(); s != slices.end(); s++) {
-    buf.append(reinterpret_cast<const char*>(s->begin()), s->size());
-  }
-  return message->ParseFromString(buf);
-}
-
-std::unique_ptr<ByteBuffer> SerializeToByteBuffer(
-    grpc::protobuf::Message* message) {
-  grpc::string buf;
-  message->SerializeToString(&buf);
-  gpr_slice s = gpr_slice_from_copied_string(buf.c_str());
-  Slice slice(s, Slice::STEAL_REF);
-  return std::unique_ptr<ByteBuffer>(new ByteBuffer(&slice, 1));
-}
-
 class GenericEnd2endTest : public ::testing::Test {
  protected:
-  GenericEnd2endTest() : generic_service_("*"), server_host_("localhost") {}
+  GenericEnd2endTest() : server_host_("localhost") {}
 
   void SetUp() GRPC_OVERRIDE {
     int port = grpc_pick_unused_port_or_die();
diff --git a/test/cpp/end2end/hybrid_end2end_test.cc b/test/cpp/end2end/hybrid_end2end_test.cc
new file mode 100644
index 0000000..c72e206
--- /dev/null
+++ b/test/cpp/end2end/hybrid_end2end_test.cc
@@ -0,0 +1,556 @@
+/*
+ *
+ * Copyright 2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <memory>
+#include <thread>
+
+#include <grpc++/channel.h>
+#include <grpc++/client_context.h>
+#include <grpc++/create_channel.h>
+#include <grpc++/generic/async_generic_service.h>
+#include <grpc++/server.h>
+#include <grpc++/server_builder.h>
+#include <grpc++/server_context.h>
+#include <grpc/grpc.h>
+#include <gtest/gtest.h>
+
+#include "src/proto/grpc/testing/duplicate/echo_duplicate.grpc.pb.h"
+#include "src/proto/grpc/testing/echo.grpc.pb.h"
+#include "test/core/util/port.h"
+#include "test/core/util/test_config.h"
+#include "test/cpp/end2end/test_service_impl.h"
+#include "test/cpp/util/byte_buffer_proto_helper.h"
+
+namespace grpc {
+namespace testing {
+
+namespace {
+
+void* tag(int i) { return (void*)(intptr_t)i; }
+
+bool VerifyReturnSuccess(CompletionQueue* cq, int i) {
+  void* got_tag;
+  bool ok;
+  EXPECT_TRUE(cq->Next(&got_tag, &ok));
+  EXPECT_EQ(tag(i), got_tag);
+  return ok;
+}
+
+void Verify(CompletionQueue* cq, int i, bool expect_ok) {
+  EXPECT_EQ(expect_ok, VerifyReturnSuccess(cq, i));
+}
+
+// Handlers to handle async request at a server. To be run in a separate thread.
+template <class Service>
+void HandleEcho(Service* service, ServerCompletionQueue* cq, bool dup_service) {
+  ServerContext srv_ctx;
+  grpc::ServerAsyncResponseWriter<EchoResponse> response_writer(&srv_ctx);
+  EchoRequest recv_request;
+  EchoResponse send_response;
+  service->RequestEcho(&srv_ctx, &recv_request, &response_writer, cq, cq,
+                       tag(1));
+  Verify(cq, 1, true);
+  send_response.set_message(recv_request.message());
+  if (dup_service) {
+    send_response.mutable_message()->append("_dup");
+  }
+  response_writer.Finish(send_response, Status::OK, tag(2));
+  Verify(cq, 2, true);
+}
+
+template <class Service>
+void HandleClientStreaming(Service* service, ServerCompletionQueue* cq) {
+  ServerContext srv_ctx;
+  EchoRequest recv_request;
+  EchoResponse send_response;
+  ServerAsyncReader<EchoResponse, EchoRequest> srv_stream(&srv_ctx);
+  service->RequestRequestStream(&srv_ctx, &srv_stream, cq, cq, tag(1));
+  Verify(cq, 1, true);
+  int i = 1;
+  do {
+    i++;
+    send_response.mutable_message()->append(recv_request.message());
+    srv_stream.Read(&recv_request, tag(i));
+  } while (VerifyReturnSuccess(cq, i));
+  srv_stream.Finish(send_response, Status::OK, tag(100));
+  Verify(cq, 100, true);
+}
+
+template <class Service>
+void HandleServerStreaming(Service* service, ServerCompletionQueue* cq) {
+  ServerContext srv_ctx;
+  EchoRequest recv_request;
+  EchoResponse send_response;
+  ServerAsyncWriter<EchoResponse> srv_stream(&srv_ctx);
+  service->RequestResponseStream(&srv_ctx, &recv_request, &srv_stream, cq, cq,
+                                 tag(1));
+  Verify(cq, 1, true);
+  send_response.set_message(recv_request.message() + "0");
+  srv_stream.Write(send_response, tag(2));
+  Verify(cq, 2, true);
+  send_response.set_message(recv_request.message() + "1");
+  srv_stream.Write(send_response, tag(3));
+  Verify(cq, 3, true);
+  send_response.set_message(recv_request.message() + "2");
+  srv_stream.Write(send_response, tag(4));
+  Verify(cq, 4, true);
+  srv_stream.Finish(Status::OK, tag(5));
+  Verify(cq, 5, true);
+}
+
+void HandleGenericEcho(GenericServerAsyncReaderWriter* stream,
+                       CompletionQueue* cq) {
+  ByteBuffer recv_buffer;
+  stream->Read(&recv_buffer, tag(2));
+  Verify(cq, 2, true);
+  EchoRequest recv_request;
+  EXPECT_TRUE(ParseFromByteBuffer(&recv_buffer, &recv_request));
+  EchoResponse send_response;
+  send_response.set_message(recv_request.message());
+  auto send_buffer = SerializeToByteBuffer(&send_response);
+  stream->Write(*send_buffer, tag(3));
+  Verify(cq, 3, true);
+  stream->Finish(Status::OK, tag(4));
+  Verify(cq, 4, true);
+}
+
+void HandleGenericRequestStream(GenericServerAsyncReaderWriter* stream,
+                                CompletionQueue* cq) {
+  ByteBuffer recv_buffer;
+  EchoRequest recv_request;
+  EchoResponse send_response;
+  int i = 1;
+  while (true) {
+    i++;
+    stream->Read(&recv_buffer, tag(i));
+    if (!VerifyReturnSuccess(cq, i)) {
+      break;
+    }
+    EXPECT_TRUE(ParseFromByteBuffer(&recv_buffer, &recv_request));
+    send_response.mutable_message()->append(recv_request.message());
+  }
+  auto send_buffer = SerializeToByteBuffer(&send_response);
+  stream->Write(*send_buffer, tag(99));
+  Verify(cq, 99, true);
+  stream->Finish(Status::OK, tag(100));
+  Verify(cq, 100, true);
+}
+
+// Request and handle one generic call.
+void HandleGenericCall(AsyncGenericService* service,
+                       ServerCompletionQueue* cq) {
+  GenericServerContext srv_ctx;
+  GenericServerAsyncReaderWriter stream(&srv_ctx);
+  service->RequestCall(&srv_ctx, &stream, cq, cq, tag(1));
+  Verify(cq, 1, true);
+  if (srv_ctx.method() == "/grpc.testing.EchoTestService/Echo") {
+    HandleGenericEcho(&stream, cq);
+  } else if (srv_ctx.method() ==
+             "/grpc.testing.EchoTestService/RequestStream") {
+    HandleGenericRequestStream(&stream, cq);
+  } else {  // other methods not handled yet.
+    gpr_log(GPR_ERROR, "method: %s", srv_ctx.method().c_str());
+    GPR_ASSERT(0);
+  }
+}
+
+class TestServiceImplDupPkg
+    : public ::grpc::testing::duplicate::EchoTestService::Service {
+ public:
+  Status Echo(ServerContext* context, const EchoRequest* request,
+              EchoResponse* response) GRPC_OVERRIDE {
+    response->set_message(request->message() + "_dup");
+    return Status::OK;
+  }
+};
+
+class HybridEnd2endTest : public ::testing::Test {
+ protected:
+  HybridEnd2endTest() {}
+
+  void SetUpServer(::grpc::Service* service1, ::grpc::Service* service2,
+                   AsyncGenericService* generic_service) {
+    int port = grpc_pick_unused_port_or_die();
+    server_address_ << "localhost:" << port;
+
+    // Setup server
+    ServerBuilder builder;
+    builder.AddListeningPort(server_address_.str(),
+                             grpc::InsecureServerCredentials());
+    builder.RegisterService(service1);
+    if (service2) {
+      builder.RegisterService(service2);
+    }
+    if (generic_service) {
+      builder.RegisterAsyncGenericService(generic_service);
+    }
+    // Create a separate cq for each potential handler.
+    for (int i = 0; i < 5; i++) {
+      cqs_.push_back(builder.AddCompletionQueue());
+    }
+    server_ = builder.BuildAndStart();
+  }
+
+  void TearDown() GRPC_OVERRIDE {
+    if (server_) {
+      server_->Shutdown();
+    }
+    void* ignored_tag;
+    bool ignored_ok;
+    for (auto it = cqs_.begin(); it != cqs_.end(); ++it) {
+      (*it)->Shutdown();
+      while ((*it)->Next(&ignored_tag, &ignored_ok))
+        ;
+    }
+  }
+
+  void ResetStub() {
+    std::shared_ptr<Channel> channel =
+        CreateChannel(server_address_.str(), InsecureChannelCredentials());
+    stub_ = grpc::testing::EchoTestService::NewStub(channel);
+  }
+
+  // Test all rpc methods.
+  void TestAllMethods() {
+    SendEcho();
+    SendSimpleClientStreaming();
+    SendSimpleServerStreaming();
+    SendBidiStreaming();
+  }
+
+  void SendEcho() {
+    EchoRequest send_request;
+    EchoResponse recv_response;
+    ClientContext cli_ctx;
+    send_request.set_message("Hello");
+    Status recv_status = stub_->Echo(&cli_ctx, send_request, &recv_response);
+    EXPECT_EQ(send_request.message(), recv_response.message());
+    EXPECT_TRUE(recv_status.ok());
+  }
+
+  void SendEchoToDupService() {
+    std::shared_ptr<Channel> channel =
+        CreateChannel(server_address_.str(), InsecureChannelCredentials());
+    auto stub = grpc::testing::duplicate::EchoTestService::NewStub(channel);
+    EchoRequest send_request;
+    EchoResponse recv_response;
+    ClientContext cli_ctx;
+    send_request.set_message("Hello");
+    Status recv_status = stub->Echo(&cli_ctx, send_request, &recv_response);
+    EXPECT_EQ(send_request.message() + "_dup", recv_response.message());
+    EXPECT_TRUE(recv_status.ok());
+  }
+
+  void SendSimpleClientStreaming() {
+    EchoRequest send_request;
+    EchoResponse recv_response;
+    grpc::string expected_message;
+    ClientContext cli_ctx;
+    send_request.set_message("Hello");
+    auto stream = stub_->RequestStream(&cli_ctx, &recv_response);
+    for (int i = 0; i < 5; i++) {
+      EXPECT_TRUE(stream->Write(send_request));
+      expected_message.append(send_request.message());
+    }
+    stream->WritesDone();
+    Status recv_status = stream->Finish();
+    EXPECT_EQ(expected_message, recv_response.message());
+    EXPECT_TRUE(recv_status.ok());
+  }
+
+  void SendSimpleServerStreaming() {
+    EchoRequest request;
+    EchoResponse response;
+    ClientContext context;
+    request.set_message("hello");
+
+    auto stream = stub_->ResponseStream(&context, request);
+    EXPECT_TRUE(stream->Read(&response));
+    EXPECT_EQ(response.message(), request.message() + "0");
+    EXPECT_TRUE(stream->Read(&response));
+    EXPECT_EQ(response.message(), request.message() + "1");
+    EXPECT_TRUE(stream->Read(&response));
+    EXPECT_EQ(response.message(), request.message() + "2");
+    EXPECT_FALSE(stream->Read(&response));
+
+    Status s = stream->Finish();
+    EXPECT_TRUE(s.ok());
+  }
+
+  void SendBidiStreaming() {
+    EchoRequest request;
+    EchoResponse response;
+    ClientContext context;
+    grpc::string msg("hello");
+
+    auto stream = stub_->BidiStream(&context);
+
+    request.set_message(msg + "0");
+    EXPECT_TRUE(stream->Write(request));
+    EXPECT_TRUE(stream->Read(&response));
+    EXPECT_EQ(response.message(), request.message());
+
+    request.set_message(msg + "1");
+    EXPECT_TRUE(stream->Write(request));
+    EXPECT_TRUE(stream->Read(&response));
+    EXPECT_EQ(response.message(), request.message());
+
+    request.set_message(msg + "2");
+    EXPECT_TRUE(stream->Write(request));
+    EXPECT_TRUE(stream->Read(&response));
+    EXPECT_EQ(response.message(), request.message());
+
+    stream->WritesDone();
+    EXPECT_FALSE(stream->Read(&response));
+    EXPECT_FALSE(stream->Read(&response));
+
+    Status s = stream->Finish();
+    EXPECT_TRUE(s.ok());
+  }
+
+  std::vector<std::unique_ptr<ServerCompletionQueue> > cqs_;
+  std::unique_ptr<grpc::testing::EchoTestService::Stub> stub_;
+  std::unique_ptr<Server> server_;
+  std::ostringstream server_address_;
+};
+
+TEST_F(HybridEnd2endTest, AsyncEcho) {
+  EchoTestService::WithAsyncMethod_Echo<TestServiceImpl> service;
+  SetUpServer(&service, nullptr, nullptr);
+  ResetStub();
+  std::thread echo_handler_thread(
+      [this, &service] { HandleEcho(&service, cqs_[0].get(), false); });
+  TestAllMethods();
+  echo_handler_thread.join();
+}
+
+TEST_F(HybridEnd2endTest, AsyncEchoRequestStream) {
+  EchoTestService::WithAsyncMethod_RequestStream<
+      EchoTestService::WithAsyncMethod_Echo<TestServiceImpl> > service;
+  SetUpServer(&service, nullptr, nullptr);
+  ResetStub();
+  std::thread echo_handler_thread(
+      [this, &service] { HandleEcho(&service, cqs_[0].get(), false); });
+  std::thread request_stream_handler_thread(
+      [this, &service] { HandleClientStreaming(&service, cqs_[1].get()); });
+  TestAllMethods();
+  echo_handler_thread.join();
+  request_stream_handler_thread.join();
+}
+
+TEST_F(HybridEnd2endTest, AsyncRequestStreamResponseStream) {
+  EchoTestService::WithAsyncMethod_RequestStream<
+      EchoTestService::WithAsyncMethod_ResponseStream<TestServiceImpl> >
+      service;
+  SetUpServer(&service, nullptr, nullptr);
+  ResetStub();
+  std::thread response_stream_handler_thread(
+      [this, &service] { HandleServerStreaming(&service, cqs_[0].get()); });
+  std::thread request_stream_handler_thread(
+      [this, &service] { HandleClientStreaming(&service, cqs_[1].get()); });
+  TestAllMethods();
+  response_stream_handler_thread.join();
+  request_stream_handler_thread.join();
+}
+
+// Add a second service with one sync method.
+TEST_F(HybridEnd2endTest, AsyncRequestStreamResponseStream_SyncDupService) {
+  EchoTestService::WithAsyncMethod_RequestStream<
+      EchoTestService::WithAsyncMethod_ResponseStream<TestServiceImpl> >
+      service;
+  TestServiceImplDupPkg dup_service;
+  SetUpServer(&service, &dup_service, nullptr);
+  ResetStub();
+  std::thread response_stream_handler_thread(
+      [this, &service] { HandleServerStreaming(&service, cqs_[0].get()); });
+  std::thread request_stream_handler_thread(
+      [this, &service] { HandleClientStreaming(&service, cqs_[1].get()); });
+  TestAllMethods();
+  SendEchoToDupService();
+  response_stream_handler_thread.join();
+  request_stream_handler_thread.join();
+}
+
+// Add a second service with one async method.
+TEST_F(HybridEnd2endTest, AsyncRequestStreamResponseStream_AsyncDupService) {
+  EchoTestService::WithAsyncMethod_RequestStream<
+      EchoTestService::WithAsyncMethod_ResponseStream<TestServiceImpl> >
+      service;
+  duplicate::EchoTestService::AsyncService dup_service;
+  SetUpServer(&service, &dup_service, nullptr);
+  ResetStub();
+  std::thread response_stream_handler_thread(
+      [this, &service] { HandleServerStreaming(&service, cqs_[0].get()); });
+  std::thread request_stream_handler_thread(
+      [this, &service] { HandleClientStreaming(&service, cqs_[1].get()); });
+  std::thread echo_handler_thread(
+      [this, &dup_service] { HandleEcho(&dup_service, cqs_[2].get(), true); });
+  TestAllMethods();
+  SendEchoToDupService();
+  response_stream_handler_thread.join();
+  request_stream_handler_thread.join();
+  echo_handler_thread.join();
+}
+
+TEST_F(HybridEnd2endTest, GenericEcho) {
+  EchoTestService::WithGenericMethod_Echo<TestServiceImpl> service;
+  AsyncGenericService generic_service;
+  SetUpServer(&service, nullptr, &generic_service);
+  ResetStub();
+  std::thread generic_handler_thread([this, &generic_service] {
+    HandleGenericCall(&generic_service, cqs_[0].get());
+  });
+  TestAllMethods();
+  generic_handler_thread.join();
+}
+
+TEST_F(HybridEnd2endTest, GenericEchoAsyncRequestStream) {
+  EchoTestService::WithAsyncMethod_RequestStream<
+      EchoTestService::WithGenericMethod_Echo<TestServiceImpl> > service;
+  AsyncGenericService generic_service;
+  SetUpServer(&service, nullptr, &generic_service);
+  ResetStub();
+  std::thread generic_handler_thread([this, &generic_service] {
+    HandleGenericCall(&generic_service, cqs_[0].get());
+  });
+  std::thread request_stream_handler_thread(
+      [this, &service] { HandleClientStreaming(&service, cqs_[1].get()); });
+  TestAllMethods();
+  generic_handler_thread.join();
+  request_stream_handler_thread.join();
+}
+
+// Add a second service with one sync method.
+TEST_F(HybridEnd2endTest, GenericEchoAsyncRequestStream_SyncDupService) {
+  EchoTestService::WithAsyncMethod_RequestStream<
+      EchoTestService::WithGenericMethod_Echo<TestServiceImpl> > service;
+  AsyncGenericService generic_service;
+  TestServiceImplDupPkg dup_service;
+  SetUpServer(&service, &dup_service, &generic_service);
+  ResetStub();
+  std::thread generic_handler_thread([this, &generic_service] {
+    HandleGenericCall(&generic_service, cqs_[0].get());
+  });
+  std::thread request_stream_handler_thread(
+      [this, &service] { HandleClientStreaming(&service, cqs_[1].get()); });
+  TestAllMethods();
+  SendEchoToDupService();
+  generic_handler_thread.join();
+  request_stream_handler_thread.join();
+}
+
+// Add a second service with one async method.
+TEST_F(HybridEnd2endTest, GenericEchoAsyncRequestStream_AsyncDupService) {
+  EchoTestService::WithAsyncMethod_RequestStream<
+      EchoTestService::WithGenericMethod_Echo<TestServiceImpl> > service;
+  AsyncGenericService generic_service;
+  duplicate::EchoTestService::AsyncService dup_service;
+  SetUpServer(&service, &dup_service, &generic_service);
+  ResetStub();
+  std::thread generic_handler_thread([this, &generic_service] {
+    HandleGenericCall(&generic_service, cqs_[0].get());
+  });
+  std::thread request_stream_handler_thread(
+      [this, &service] { HandleClientStreaming(&service, cqs_[1].get()); });
+  std::thread echo_handler_thread(
+      [this, &dup_service] { HandleEcho(&dup_service, cqs_[2].get(), true); });
+  TestAllMethods();
+  SendEchoToDupService();
+  generic_handler_thread.join();
+  request_stream_handler_thread.join();
+  echo_handler_thread.join();
+}
+
+TEST_F(HybridEnd2endTest, GenericEchoAsyncRequestStreamResponseStream) {
+  EchoTestService::WithAsyncMethod_RequestStream<
+      EchoTestService::WithGenericMethod_Echo<
+          EchoTestService::WithAsyncMethod_ResponseStream<TestServiceImpl> > >
+      service;
+  AsyncGenericService generic_service;
+  SetUpServer(&service, nullptr, &generic_service);
+  ResetStub();
+  std::thread generic_handler_thread([this, &generic_service] {
+    HandleGenericCall(&generic_service, cqs_[0].get());
+  });
+  std::thread request_stream_handler_thread(
+      [this, &service] { HandleClientStreaming(&service, cqs_[1].get()); });
+  std::thread response_stream_handler_thread(
+      [this, &service] { HandleServerStreaming(&service, cqs_[2].get()); });
+  TestAllMethods();
+  generic_handler_thread.join();
+  request_stream_handler_thread.join();
+  response_stream_handler_thread.join();
+}
+
+TEST_F(HybridEnd2endTest, GenericEchoRequestStreamAsyncResponseStream) {
+  EchoTestService::WithGenericMethod_RequestStream<
+      EchoTestService::WithGenericMethod_Echo<
+          EchoTestService::WithAsyncMethod_ResponseStream<TestServiceImpl> > >
+      service;
+  AsyncGenericService generic_service;
+  SetUpServer(&service, nullptr, &generic_service);
+  ResetStub();
+  std::thread generic_handler_thread([this, &generic_service] {
+    HandleGenericCall(&generic_service, cqs_[0].get());
+  });
+  std::thread generic_handler_thread2([this, &generic_service] {
+    HandleGenericCall(&generic_service, cqs_[1].get());
+  });
+  std::thread response_stream_handler_thread(
+      [this, &service] { HandleServerStreaming(&service, cqs_[2].get()); });
+  TestAllMethods();
+  generic_handler_thread.join();
+  generic_handler_thread2.join();
+  response_stream_handler_thread.join();
+}
+
+// If WithGenericMethod is called and no generic service is registered, the
+// server will fail to build.
+TEST_F(HybridEnd2endTest, GenericMethodWithoutGenericService) {
+  EchoTestService::WithGenericMethod_RequestStream<
+      EchoTestService::WithGenericMethod_Echo<
+          EchoTestService::WithAsyncMethod_ResponseStream<TestServiceImpl> > >
+      service;
+  SetUpServer(&service, nullptr, nullptr);
+  EXPECT_EQ(nullptr, server_.get());
+}
+
+}  // namespace
+}  // namespace testing
+}  // namespace grpc
+
+int main(int argc, char** argv) {
+  grpc_test_init(argc, argv);
+  ::testing::InitGoogleTest(&argc, argv);
+  return RUN_ALL_TESTS();
+}
diff --git a/test/cpp/end2end/test_service_impl.cc b/test/cpp/end2end/test_service_impl.cc
new file mode 100644
index 0000000..66d11d0
--- /dev/null
+++ b/test/cpp/end2end/test_service_impl.cc
@@ -0,0 +1,333 @@
+/*
+ *
+ * Copyright 2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "test/cpp/end2end/test_service_impl.h"
+
+#include <thread>
+
+#include <grpc++/security/credentials.h>
+#include <grpc++/server_context.h>
+#include <grpc/grpc.h>
+#include <gtest/gtest.h>
+
+#include "src/proto/grpc/testing/echo.grpc.pb.h"
+#include "test/cpp/util/string_ref_helper.h"
+
+using std::chrono::system_clock;
+
+namespace grpc {
+namespace testing {
+namespace {
+
+// When echo_deadline is requested, deadline seen in the ServerContext is set in
+// the response in seconds.
+void MaybeEchoDeadline(ServerContext* context, const EchoRequest* request,
+                       EchoResponse* response) {
+  if (request->has_param() && request->param().echo_deadline()) {
+    gpr_timespec deadline = gpr_inf_future(GPR_CLOCK_REALTIME);
+    if (context->deadline() != system_clock::time_point::max()) {
+      Timepoint2Timespec(context->deadline(), &deadline);
+    }
+    response->mutable_param()->set_request_deadline(deadline.tv_sec);
+  }
+}
+
+void CheckServerAuthContext(const ServerContext* context,
+                            const grpc::string& expected_client_identity) {
+  std::shared_ptr<const AuthContext> auth_ctx = context->auth_context();
+  std::vector<grpc::string_ref> ssl =
+      auth_ctx->FindPropertyValues("transport_security_type");
+  EXPECT_EQ(1u, ssl.size());
+  EXPECT_EQ("ssl", ToString(ssl[0]));
+  if (expected_client_identity.length() == 0) {
+    EXPECT_TRUE(auth_ctx->GetPeerIdentityPropertyName().empty());
+    EXPECT_TRUE(auth_ctx->GetPeerIdentity().empty());
+    EXPECT_FALSE(auth_ctx->IsPeerAuthenticated());
+  } else {
+    auto identity = auth_ctx->GetPeerIdentity();
+    EXPECT_TRUE(auth_ctx->IsPeerAuthenticated());
+    EXPECT_EQ(1u, identity.size());
+    EXPECT_EQ(expected_client_identity, identity[0]);
+  }
+}
+}  // namespace
+
+Status TestServiceImpl::Echo(ServerContext* context, const EchoRequest* request,
+                             EchoResponse* response) {
+  int server_try_cancel = GetIntValueFromMetadata(
+      kServerTryCancelRequest, context->client_metadata(), DO_NOT_CANCEL);
+  if (server_try_cancel > DO_NOT_CANCEL) {
+    // Since this is a unary RPC, by the time this server handler is called,
+    // the 'request' message is already read from the client. So the scenarios
+    // in server_try_cancel don't make much sense. Just cancel the RPC as long
+    // as server_try_cancel is not DO_NOT_CANCEL
+    ServerTryCancel(context);
+    return Status::CANCELLED;
+  }
+
+  response->set_message(request->message());
+  MaybeEchoDeadline(context, request, response);
+  if (host_) {
+    response->mutable_param()->set_host(*host_);
+  }
+  if (request->has_param() && request->param().client_cancel_after_us()) {
+    {
+      std::unique_lock<std::mutex> lock(mu_);
+      signal_client_ = true;
+    }
+    while (!context->IsCancelled()) {
+      gpr_sleep_until(gpr_time_add(
+          gpr_now(GPR_CLOCK_REALTIME),
+          gpr_time_from_micros(request->param().client_cancel_after_us(),
+                               GPR_TIMESPAN)));
+    }
+    return Status::CANCELLED;
+  } else if (request->has_param() &&
+             request->param().server_cancel_after_us()) {
+    gpr_sleep_until(gpr_time_add(
+        gpr_now(GPR_CLOCK_REALTIME),
+        gpr_time_from_micros(request->param().server_cancel_after_us(),
+                             GPR_TIMESPAN)));
+    return Status::CANCELLED;
+  } else if (!request->has_param() ||
+             !request->param().skip_cancelled_check()) {
+    EXPECT_FALSE(context->IsCancelled());
+  }
+
+  if (request->has_param() && request->param().echo_metadata()) {
+    const std::multimap<grpc::string_ref, grpc::string_ref>& client_metadata =
+        context->client_metadata();
+    for (
+        std::multimap<grpc::string_ref, grpc::string_ref>::const_iterator iter =
+            client_metadata.begin();
+        iter != client_metadata.end(); ++iter) {
+      context->AddTrailingMetadata(ToString(iter->first),
+                                   ToString(iter->second));
+    }
+  }
+  if (request->has_param() &&
+      (request->param().expected_client_identity().length() > 0 ||
+       request->param().check_auth_context())) {
+    CheckServerAuthContext(context,
+                           request->param().expected_client_identity());
+  }
+  if (request->has_param() && request->param().response_message_length() > 0) {
+    response->set_message(
+        grpc::string(request->param().response_message_length(), '\0'));
+  }
+  if (request->has_param() && request->param().echo_peer()) {
+    response->mutable_param()->set_peer(context->peer());
+  }
+  return Status::OK;
+}
+
+// Unimplemented is left unimplemented to test the returned error.
+
+Status TestServiceImpl::RequestStream(ServerContext* context,
+                                      ServerReader<EchoRequest>* reader,
+                                      EchoResponse* response) {
+  // If 'server_try_cancel' is set in the metadata, the RPC is cancelled by
+  // the server by calling ServerContext::TryCancel() depending on the value:
+  //   CANCEL_BEFORE_PROCESSING: The RPC is cancelled before the server reads
+  //   any message from the client
+  //   CANCEL_DURING_PROCESSING: The RPC is cancelled while the server is
+  //   reading messages from the client
+  //   CANCEL_AFTER_PROCESSING: The RPC is cancelled after the server reads
+  //   all the messages from the client
+  int server_try_cancel = GetIntValueFromMetadata(
+      kServerTryCancelRequest, context->client_metadata(), DO_NOT_CANCEL);
+
+  // If 'cancel_after_reads' is set in the metadata AND non-zero, the server
+  // will cancel the RPC (by just returning Status::CANCELLED - doesn't call
+  // ServerContext::TryCancel()) after reading the number of records specified
+  // by the 'cancel_after_reads' value set in the metadata.
+  int cancel_after_reads = GetIntValueFromMetadata(
+      kServerCancelAfterReads, context->client_metadata(), 0);
+
+  EchoRequest request;
+  response->set_message("");
+
+  if (server_try_cancel == CANCEL_BEFORE_PROCESSING) {
+    ServerTryCancel(context);
+    return Status::CANCELLED;
+  }
+
+  std::thread* server_try_cancel_thd = NULL;
+  if (server_try_cancel == CANCEL_DURING_PROCESSING) {
+    server_try_cancel_thd =
+        new std::thread(&TestServiceImpl::ServerTryCancel, this, context);
+  }
+
+  int num_msgs_read = 0;
+  while (reader->Read(&request)) {
+    if (cancel_after_reads == 1) {
+      gpr_log(GPR_INFO, "return cancel status");
+      return Status::CANCELLED;
+    } else if (cancel_after_reads > 0) {
+      cancel_after_reads--;
+    }
+    response->mutable_message()->append(request.message());
+  }
+  gpr_log(GPR_INFO, "Read: %d messages", num_msgs_read);
+
+  if (server_try_cancel_thd != NULL) {
+    server_try_cancel_thd->join();
+    delete server_try_cancel_thd;
+    return Status::CANCELLED;
+  }
+
+  if (server_try_cancel == CANCEL_AFTER_PROCESSING) {
+    ServerTryCancel(context);
+    return Status::CANCELLED;
+  }
+
+  return Status::OK;
+}
+
+// Return 'kNumResponseStreamMsgs' messages.
+// TODO(yangg) make it generic by adding a parameter into EchoRequest
+Status TestServiceImpl::ResponseStream(ServerContext* context,
+                                       const EchoRequest* request,
+                                       ServerWriter<EchoResponse>* writer) {
+  // If server_try_cancel is set in the metadata, the RPC is cancelled by the
+  // server by calling ServerContext::TryCancel() depending on the value:
+  //   CANCEL_BEFORE_PROCESSING: The RPC is cancelled before the server writes
+  //   any messages to the client
+  //   CANCEL_DURING_PROCESSING: The RPC is cancelled while the server is
+  //   writing messages to the client
+  //   CANCEL_AFTER_PROCESSING: The RPC is cancelled after the server writes
+  //   all the messages to the client
+  int server_try_cancel = GetIntValueFromMetadata(
+      kServerTryCancelRequest, context->client_metadata(), DO_NOT_CANCEL);
+
+  if (server_try_cancel == CANCEL_BEFORE_PROCESSING) {
+    ServerTryCancel(context);
+    return Status::CANCELLED;
+  }
+
+  EchoResponse response;
+  std::thread* server_try_cancel_thd = NULL;
+  if (server_try_cancel == CANCEL_DURING_PROCESSING) {
+    server_try_cancel_thd =
+        new std::thread(&TestServiceImpl::ServerTryCancel, this, context);
+  }
+
+  for (int i = 0; i < kNumResponseStreamsMsgs; i++) {
+    response.set_message(request->message() + std::to_string(i));
+    writer->Write(response);
+  }
+
+  if (server_try_cancel_thd != NULL) {
+    server_try_cancel_thd->join();
+    delete server_try_cancel_thd;
+    return Status::CANCELLED;
+  }
+
+  if (server_try_cancel == CANCEL_AFTER_PROCESSING) {
+    ServerTryCancel(context);
+    return Status::CANCELLED;
+  }
+
+  return Status::OK;
+}
+
+Status TestServiceImpl::BidiStream(
+    ServerContext* context,
+    ServerReaderWriter<EchoResponse, EchoRequest>* stream) {
+  // If server_try_cancel is set in the metadata, the RPC is cancelled by the
+  // server by calling ServerContext::TryCancel() depending on the value:
+  //   CANCEL_BEFORE_PROCESSING: The RPC is cancelled before the server reads/
+  //   writes any messages from/to the client
+  //   CANCEL_DURING_PROCESSING: The RPC is cancelled while the server is
+  //   reading/writing messages from/to the client
+  //   CANCEL_AFTER_PROCESSING: The RPC is cancelled after the server
+  //   reads/writes all messages from/to the client
+  int server_try_cancel = GetIntValueFromMetadata(
+      kServerTryCancelRequest, context->client_metadata(), DO_NOT_CANCEL);
+
+  EchoRequest request;
+  EchoResponse response;
+
+  if (server_try_cancel == CANCEL_BEFORE_PROCESSING) {
+    ServerTryCancel(context);
+    return Status::CANCELLED;
+  }
+
+  std::thread* server_try_cancel_thd = NULL;
+  if (server_try_cancel == CANCEL_DURING_PROCESSING) {
+    server_try_cancel_thd =
+        new std::thread(&TestServiceImpl::ServerTryCancel, this, context);
+  }
+
+  while (stream->Read(&request)) {
+    gpr_log(GPR_INFO, "recv msg %s", request.message().c_str());
+    response.set_message(request.message());
+    stream->Write(response);
+  }
+
+  if (server_try_cancel_thd != NULL) {
+    server_try_cancel_thd->join();
+    delete server_try_cancel_thd;
+    return Status::CANCELLED;
+  }
+
+  if (server_try_cancel == CANCEL_AFTER_PROCESSING) {
+    ServerTryCancel(context);
+    return Status::CANCELLED;
+  }
+
+  return Status::OK;
+}
+
+int TestServiceImpl::GetIntValueFromMetadata(
+    const char* key,
+    const std::multimap<grpc::string_ref, grpc::string_ref>& metadata,
+    int default_value) {
+  if (metadata.find(key) != metadata.end()) {
+    std::istringstream iss(ToString(metadata.find(key)->second));
+    iss >> default_value;
+    gpr_log(GPR_INFO, "%s : %d", key, default_value);
+  }
+
+  return default_value;
+}
+
+void TestServiceImpl::ServerTryCancel(ServerContext* context) {
+  EXPECT_FALSE(context->IsCancelled());
+  context->TryCancel();
+  gpr_log(GPR_INFO, "Server called TryCancel() to cancel the request");
+  EXPECT_TRUE(context->IsCancelled());
+}
+
+}  // namespace testing
+}  // namespace grpc
diff --git a/test/cpp/end2end/test_service_impl.h b/test/cpp/end2end/test_service_impl.h
new file mode 100644
index 0000000..1ab6ced
--- /dev/null
+++ b/test/cpp/end2end/test_service_impl.h
@@ -0,0 +1,102 @@
+/*
+ *
+ * Copyright 2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+#ifndef GRPC_TEST_CPP_END2END_TEST_SERVICE_IMPL_H
+#define GRPC_TEST_CPP_END2END_TEST_SERVICE_IMPL_H
+
+#include <memory>
+#include <mutex>
+
+#include <grpc++/server_context.h>
+#include <grpc/grpc.h>
+
+#include "src/proto/grpc/testing/echo.grpc.pb.h"
+
+namespace grpc {
+namespace testing {
+
+const int kNumResponseStreamsMsgs = 3;
+const char* const kServerCancelAfterReads = "cancel_after_reads";
+const char* const kServerTryCancelRequest = "server_try_cancel";
+
+typedef enum {
+  DO_NOT_CANCEL = 0,
+  CANCEL_BEFORE_PROCESSING,
+  CANCEL_DURING_PROCESSING,
+  CANCEL_AFTER_PROCESSING
+} ServerTryCancelRequestPhase;
+
+class TestServiceImpl : public ::grpc::testing::EchoTestService::Service {
+ public:
+  TestServiceImpl() : signal_client_(false), host_() {}
+  explicit TestServiceImpl(const grpc::string& host)
+      : signal_client_(false), host_(new grpc::string(host)) {}
+
+  Status Echo(ServerContext* context, const EchoRequest* request,
+              EchoResponse* response) GRPC_OVERRIDE;
+
+  // Unimplemented is left unimplemented to test the returned error.
+
+  Status RequestStream(ServerContext* context,
+                       ServerReader<EchoRequest>* reader,
+                       EchoResponse* response) GRPC_OVERRIDE;
+
+  Status ResponseStream(ServerContext* context, const EchoRequest* request,
+                        ServerWriter<EchoResponse>* writer) GRPC_OVERRIDE;
+
+  Status BidiStream(ServerContext* context,
+                    ServerReaderWriter<EchoResponse, EchoRequest>* stream)
+      GRPC_OVERRIDE;
+
+  bool signal_client() {
+    std::unique_lock<std::mutex> lock(mu_);
+    return signal_client_;
+  }
+
+ private:
+  int GetIntValueFromMetadata(
+      const char* key,
+      const std::multimap<grpc::string_ref, grpc::string_ref>& metadata,
+      int default_value);
+
+  void ServerTryCancel(ServerContext* context);
+
+ private:
+  bool signal_client_;
+  std::mutex mu_;
+  std::unique_ptr<grpc::string> host_;
+};
+
+}  // namespace testing
+}  // namespace grpc
+
+#endif  // GRPC_TEST_CPP_END2END_TEST_SERVICE_IMPL_H
diff --git a/test/cpp/end2end/thread_stress_test.cc b/test/cpp/end2end/thread_stress_test.cc
index 4e8860e..e246c0b 100644
--- a/test/cpp/end2end/thread_stress_test.cc
+++ b/test/cpp/end2end/thread_stress_test.cc
@@ -45,6 +45,7 @@
 #include <grpc/support/time.h>
 #include <gtest/gtest.h>
 
+#include "src/core/surface/api_trace.h"
 #include "src/proto/grpc/testing/duplicate/echo_duplicate.grpc.pb.h"
 #include "src/proto/grpc/testing/echo.grpc.pb.h"
 #include "test/core/util/port.h"
@@ -54,6 +55,11 @@
 using grpc::testing::EchoResponse;
 using std::chrono::system_clock;
 
+const int kNumThreads = 100;  // Number of threads
+const int kNumAsyncSendThreads = 2;
+const int kNumAsyncReceiveThreads = 50;
+const int kNumRpcs = 1000;  // Number of RPCs per thread
+
 namespace grpc {
 namespace testing {
 
@@ -84,7 +90,7 @@
     MaybeEchoDeadline(context, request, response);
     if (request->has_param() && request->param().client_cancel_after_us()) {
       {
-        std::unique_lock<std::mutex> lock(mu_);
+        unique_lock<mutex> lock(mu_);
         signal_client_ = true;
       }
       while (!context->IsCancelled()) {
@@ -149,13 +155,13 @@
   }
 
   bool signal_client() {
-    std::unique_lock<std::mutex> lock(mu_);
+    unique_lock<mutex> lock(mu_);
     return signal_client_;
   }
 
  private:
   bool signal_client_;
-  std::mutex mu_;
+  mutex mu_;
 };
 
 class TestServiceImplDupPkg
@@ -168,11 +174,10 @@
   }
 };
 
-class End2endTest : public ::testing::Test {
- protected:
-  End2endTest() : kMaxMessageSize_(8192) {}
-
-  void SetUp() GRPC_OVERRIDE {
+class CommonStressTest {
+ public:
+  CommonStressTest() : kMaxMessageSize_(8192) {}
+  void SetUp() {
     int port = grpc_pick_unused_port_or_die();
     server_address_ << "localhost:" << port;
     // Setup server
@@ -185,15 +190,15 @@
     builder.RegisterService(&dup_pkg_service_);
     server_ = builder.BuildAndStart();
   }
-
-  void TearDown() GRPC_OVERRIDE { server_->Shutdown(); }
-
+  void TearDown() { server_->Shutdown(); }
   void ResetStub() {
     std::shared_ptr<Channel> channel =
         CreateChannel(server_address_.str(), InsecureChannelCredentials());
     stub_ = grpc::testing::EchoTestService::NewStub(channel);
   }
+  grpc::testing::EchoTestService::Stub* GetStub() { return stub_.get(); }
 
+ private:
   std::unique_ptr<grpc::testing::EchoTestService::Stub> stub_;
   std::unique_ptr<Server> server_;
   std::ostringstream server_address_;
@@ -202,6 +207,16 @@
   TestServiceImplDupPkg dup_pkg_service_;
 };
 
+class End2endTest : public ::testing::Test {
+ protected:
+  End2endTest() {}
+  void SetUp() GRPC_OVERRIDE { common_.SetUp(); }
+  void TearDown() GRPC_OVERRIDE { common_.TearDown(); }
+  void ResetStub() { common_.ResetStub(); }
+
+  CommonStressTest common_;
+};
+
 static void SendRpc(grpc::testing::EchoTestService::Stub* stub, int num_rpcs) {
   EchoRequest request;
   EchoResponse response;
@@ -216,17 +231,115 @@
 }
 
 TEST_F(End2endTest, ThreadStress) {
-  ResetStub();
+  common_.ResetStub();
   std::vector<std::thread*> threads;
-  for (int i = 0; i < 100; ++i) {
-    threads.push_back(new std::thread(SendRpc, stub_.get(), 1000));
+  for (int i = 0; i < kNumThreads; ++i) {
+    threads.push_back(new std::thread(SendRpc, common_.GetStub(), kNumRpcs));
   }
-  for (int i = 0; i < 100; ++i) {
+  for (int i = 0; i < kNumThreads; ++i) {
     threads[i]->join();
     delete threads[i];
   }
 }
 
+class AsyncClientEnd2endTest : public ::testing::Test {
+ protected:
+  AsyncClientEnd2endTest() : rpcs_outstanding_(0) {}
+
+  void SetUp() GRPC_OVERRIDE { common_.SetUp(); }
+  void TearDown() GRPC_OVERRIDE {
+    void* ignored_tag;
+    bool ignored_ok;
+    while (cq_.Next(&ignored_tag, &ignored_ok))
+      ;
+    common_.TearDown();
+  }
+
+  void Wait() {
+    unique_lock<mutex> l(mu_);
+    while (rpcs_outstanding_ != 0) {
+      cv_.wait(l);
+    }
+
+    cq_.Shutdown();
+  }
+
+  struct AsyncClientCall {
+    EchoResponse response;
+    ClientContext context;
+    Status status;
+    std::unique_ptr<ClientAsyncResponseReader<EchoResponse>> response_reader;
+  };
+
+  void AsyncSendRpc(int num_rpcs) {
+    for (int i = 0; i < num_rpcs; ++i) {
+      AsyncClientCall* call = new AsyncClientCall;
+      EchoRequest request;
+      request.set_message("Hello: " + std::to_string(i));
+      call->response_reader =
+          common_.GetStub()->AsyncEcho(&call->context, request, &cq_);
+      call->response_reader->Finish(&call->response, &call->status,
+                                    (void*)call);
+
+      unique_lock<mutex> l(mu_);
+      rpcs_outstanding_++;
+    }
+  }
+
+  void AsyncCompleteRpc() {
+    while (true) {
+      void* got_tag;
+      bool ok = false;
+      if (!cq_.Next(&got_tag, &ok)) break;
+      AsyncClientCall* call = static_cast<AsyncClientCall*>(got_tag);
+      if (!ok) {
+        gpr_log(GPR_DEBUG, "Error: %d", call->status.error_code());
+      }
+      delete call;
+
+      bool notify;
+      {
+        unique_lock<mutex> l(mu_);
+        rpcs_outstanding_--;
+        notify = (rpcs_outstanding_ == 0);
+      }
+      if (notify) {
+        cv_.notify_all();
+      }
+    }
+  }
+
+  CommonStressTest common_;
+  CompletionQueue cq_;
+  mutex mu_;
+  condition_variable cv_;
+  int rpcs_outstanding_;
+};
+
+TEST_F(AsyncClientEnd2endTest, ThreadStress) {
+  common_.ResetStub();
+  std::vector<std::thread*> send_threads, completion_threads;
+  for (int i = 0; i < kNumAsyncReceiveThreads; ++i) {
+    completion_threads.push_back(new std::thread(
+        &AsyncClientEnd2endTest_ThreadStress_Test::AsyncCompleteRpc, this));
+  }
+  for (int i = 0; i < kNumAsyncSendThreads; ++i) {
+    send_threads.push_back(
+        new std::thread(&AsyncClientEnd2endTest_ThreadStress_Test::AsyncSendRpc,
+                        this, kNumRpcs));
+  }
+  for (int i = 0; i < kNumAsyncSendThreads; ++i) {
+    send_threads[i]->join();
+    delete send_threads[i];
+  }
+
+  Wait();
+  for (int i = 0; i < kNumAsyncReceiveThreads; ++i) {
+    completion_threads[i]->join();
+    delete completion_threads[i];
+  }
+}
+
 }  // namespace testing
 }  // namespace grpc
 
diff --git a/test/cpp/qps/async_streaming_ping_pong_test.cc b/test/cpp/qps/async_streaming_ping_pong_test.cc
index 0acdf3a..9749932 100644
--- a/test/cpp/qps/async_streaming_ping_pong_test.cc
+++ b/test/cpp/qps/async_streaming_ping_pong_test.cc
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -58,7 +58,6 @@
 
   ServerConfig server_config;
   server_config.set_server_type(ASYNC_SERVER);
-  server_config.set_host("localhost");
   server_config.set_async_server_threads(1);
 
   const auto result =
diff --git a/test/cpp/qps/async_unary_ping_pong_test.cc b/test/cpp/qps/async_unary_ping_pong_test.cc
index d21e116..d801bdd 100644
--- a/test/cpp/qps/async_unary_ping_pong_test.cc
+++ b/test/cpp/qps/async_unary_ping_pong_test.cc
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -58,7 +58,6 @@
 
   ServerConfig server_config;
   server_config.set_server_type(ASYNC_SERVER);
-  server_config.set_host("localhost");
   server_config.set_async_server_threads(1);
 
   const auto result =
diff --git a/test/cpp/qps/client.h b/test/cpp/qps/client.h
index 97487fd..50b2bf2 100644
--- a/test/cpp/qps/client.h
+++ b/test/cpp/qps/client.h
@@ -36,16 +36,20 @@
 
 #include <condition_variable>
 #include <mutex>
+#include <vector>
 
 #include <grpc++/support/byte_buffer.h>
 #include <grpc++/support/slice.h>
+#include <grpc/support/log.h>
 
+#include "src/proto/grpc/testing/payloads.grpc.pb.h"
+#include "src/proto/grpc/testing/services.grpc.pb.h"
+
+#include "test/cpp/qps/limit_cores.h"
 #include "test/cpp/qps/histogram.h"
 #include "test/cpp/qps/interarrival.h"
 #include "test/cpp/qps/timer.h"
 #include "test/cpp/util/create_test_channel.h"
-#include "src/proto/grpc/testing/payloads.grpc.pb.h"
-#include "src/proto/grpc/testing/services.grpc.pb.h"
 
 namespace grpc {
 
@@ -320,6 +324,8 @@
              std::function<std::unique_ptr<StubType>(std::shared_ptr<Channel>)>
                  create_stub)
       : channels_(config.client_channels()), create_stub_(create_stub) {
+    cores_ = LimitCores(config.core_list().data(), config.core_list_size());
+
     for (int i = 0; i < config.client_channels(); i++) {
       channels_[i].init(config.server_targets(i % config.server_targets_size()),
                         config, create_stub_);
@@ -331,6 +337,7 @@
   virtual ~ClientImpl() {}
 
  protected:
+  int cores_;
   RequestType request_;
 
   class ClientChannelInfo {
diff --git a/test/cpp/qps/client_async.cc b/test/cpp/qps/client_async.cc
index f270cd0..f3f8f37 100644
--- a/test/cpp/qps/client_async.cc
+++ b/test/cpp/qps/client_async.cc
@@ -43,16 +43,19 @@
 #include <vector>
 
 #include <gflags/gflags.h>
+#include <grpc++/channel.h>
+#include <grpc++/client_context.h>
 #include <grpc++/client_context.h>
 #include <grpc++/generic/generic_stub.h>
 #include <grpc/grpc.h>
+#include <grpc/support/cpu.h>
 #include <grpc/support/histogram.h>
 #include <grpc/support/log.h>
 
+#include "src/proto/grpc/testing/services.grpc.pb.h"
 #include "test/cpp/qps/client.h"
 #include "test/cpp/qps/timer.h"
 #include "test/cpp/util/create_test_channel.h"
-#include "src/proto/grpc/testing/services.grpc.pb.h"
 
 namespace grpc {
 namespace testing {
@@ -156,6 +159,7 @@
   using Client::SetupLoadTest;
   using Client::NextIssueTime;
   using Client::closed_loop_;
+  using ClientImpl<StubType, RequestType>::cores_;
   using ClientImpl<StubType, RequestType>::channels_;
   using ClientImpl<StubType, RequestType>::request_;
   AsyncClient(const ClientConfig& config,
@@ -164,14 +168,15 @@
               std::function<std::unique_ptr<StubType>(std::shared_ptr<Channel>)>
                   create_stub)
       : ClientImpl<StubType, RequestType>(config, create_stub),
+        num_async_threads_(NumThreads(config)),
         channel_lock_(new std::mutex[config.client_channels()]),
         contexts_(config.client_channels()),
         max_outstanding_per_channel_(config.outstanding_rpcs_per_channel()),
         channel_count_(config.client_channels()),
-        pref_channel_inc_(config.async_client_threads()) {
-    SetupLoadTest(config, config.async_client_threads());
+        pref_channel_inc_(num_async_threads_) {
+    SetupLoadTest(config, num_async_threads_);
 
-    for (int i = 0; i < config.async_client_threads(); i++) {
+    for (int i = 0; i < num_async_threads_; i++) {
       cli_cqs_.emplace_back(new CompletionQueue);
       if (!closed_loop_) {
         rpc_deadlines_.emplace_back();
@@ -324,6 +329,9 @@
     return true;
   }
 
+ protected:
+  int num_async_threads_;
+
  private:
   class boolean {  // exists only to avoid data-race on vector<bool>
    public:
@@ -338,6 +346,15 @@
    private:
     bool val_;
   };
+  int NumThreads(const ClientConfig& config) {
+    int num_threads = config.async_client_threads();
+    if (num_threads <= 0) {  // Use dynamic sizing
+      num_threads = cores_;
+      gpr_log(GPR_INFO, "Sizing async client to %d threads", num_threads);
+    }
+    return num_threads;
+  }
+
   std::vector<std::unique_ptr<CompletionQueue>> cli_cqs_;
 
   std::vector<deadline_list> rpc_deadlines_;  // per thread deadlines
@@ -363,7 +380,7 @@
  public:
   explicit AsyncUnaryClient(const ClientConfig& config)
       : AsyncClient(config, SetupCtx, BenchmarkStubCreator) {
-    StartThreads(config.async_client_threads());
+    StartThreads(num_async_threads_);
   }
   ~AsyncUnaryClient() GRPC_OVERRIDE { EndThreads(); }
 
@@ -461,7 +478,7 @@
     // async streaming currently only supports closed loop
     GPR_ASSERT(closed_loop_);
 
-    StartThreads(config.async_client_threads());
+    StartThreads(num_async_threads_);
   }
 
   ~AsyncStreamingClient() GRPC_OVERRIDE { EndThreads(); }
@@ -566,7 +583,7 @@
     // async streaming currently only supports closed loop
     GPR_ASSERT(closed_loop_);
 
-    StartThreads(config.async_client_threads());
+    StartThreads(num_async_threads_);
   }
 
   ~GenericAsyncStreamingClient() GRPC_OVERRIDE { EndThreads(); }
diff --git a/test/cpp/qps/client_sync.cc b/test/cpp/qps/client_sync.cc
index 92fbf24..d93537b 100644
--- a/test/cpp/qps/client_sync.cc
+++ b/test/cpp/qps/client_sync.cc
@@ -41,6 +41,7 @@
 #include <vector>
 
 #include <gflags/gflags.h>
+#include <grpc++/channel.h>
 #include <grpc++/client_context.h>
 #include <grpc++/server.h>
 #include <grpc++/server_builder.h>
diff --git a/test/cpp/qps/driver.cc b/test/cpp/qps/driver.cc
index 66269ae..80f6ada 100644
--- a/test/cpp/qps/driver.cc
+++ b/test/cpp/qps/driver.cc
@@ -31,24 +31,26 @@
  *
  */
 
+#include <deque>
 #include <list>
 #include <thread>
-#include <deque>
+#include <unordered_map>
 #include <vector>
 
-#include <grpc/support/alloc.h>
-#include <grpc/support/log.h>
-#include <grpc/support/host_port.h>
+#include <grpc++/channel.h>
 #include <grpc++/client_context.h>
 #include <grpc++/create_channel.h>
+#include <grpc/support/alloc.h>
+#include <grpc/support/host_port.h>
+#include <grpc/support/log.h>
 
 #include "src/core/support/env.h"
+#include "src/proto/grpc/testing/services.grpc.pb.h"
 #include "test/core/util/port.h"
 #include "test/core/util/test_config.h"
 #include "test/cpp/qps/driver.h"
 #include "test/cpp/qps/histogram.h"
 #include "test/cpp/qps/qps_worker.h"
-#include "src/proto/grpc/testing/services.grpc.pb.h"
 
 using std::list;
 using std::thread;
@@ -58,7 +60,42 @@
 
 namespace grpc {
 namespace testing {
-static deque<string> get_hosts(const string& name) {
+static std::string get_host(const std::string& worker) {
+  char* host;
+  char* port;
+
+  gpr_split_host_port(worker.c_str(), &host, &port);
+  const string s(host);
+
+  gpr_free(host);
+  gpr_free(port);
+  return s;
+}
+
+static std::unordered_map<string, std::deque<int>> get_hosts_and_cores(
+    const deque<string>& workers) {
+  std::unordered_map<string, std::deque<int>> hosts;
+  for (auto it = workers.begin(); it != workers.end(); it++) {
+    const string host = get_host(*it);
+    if (hosts.find(host) == hosts.end()) {
+      auto stub = WorkerService::NewStub(
+          CreateChannel(*it, InsecureChannelCredentials()));
+      grpc::ClientContext ctx;
+      CoreRequest dummy;
+      CoreResponse cores;
+      grpc::Status s = stub->CoreCount(&ctx, dummy, &cores);
+      assert(s.ok());
+      std::deque<int> dq;
+      for (int i = 0; i < cores.cores(); i++) {
+        dq.push_back(i);
+      }
+      hosts[host] = dq;
+    }
+  }
+  return hosts;
+}
+
+static deque<string> get_workers(const string& name) {
   char* env = gpr_getenv(name.c_str());
   if (!env) return deque<string>();
 
@@ -104,18 +141,18 @@
 
 std::unique_ptr<ScenarioResult> RunScenario(
     const ClientConfig& initial_client_config, size_t num_clients,
-    const ServerConfig& server_config, size_t num_servers, int warmup_seconds,
-    int benchmark_seconds, int spawn_local_worker_count) {
+    const ServerConfig& initial_server_config, size_t num_servers,
+    int warmup_seconds, int benchmark_seconds, int spawn_local_worker_count) {
   // ClientContext allocations (all are destroyed at scope exit)
   list<ClientContext> contexts;
 
   // To be added to the result, containing the final configuration used for
   // client and config (including host, etc.)
   ClientConfig result_client_config;
-  ServerConfig result_server_config;
+  const ServerConfig result_server_config = initial_server_config;
 
   // Get client, server lists
-  auto workers = get_hosts("QPS_WORKERS");
+  auto workers = get_workers("QPS_WORKERS");
   ClientConfig client_config = initial_client_config;
 
   // Spawn some local workers if desired
@@ -142,6 +179,15 @@
     }
   }
 
+  // Setup the hosts and core counts
+  auto hosts_cores = get_hosts_and_cores(workers);
+
+  // if num_clients is set to <=0, do dynamic sizing: all workers
+  // except for servers are clients
+  if (num_clients <= 0) {
+    num_clients = workers.size() - num_servers;
+  }
+
   // TODO(ctiller): support running multiple configurations, and binpack
   // client/server pairs
   // to available workers
@@ -165,18 +211,49 @@
             i);
     servers[i].stub = WorkerService::NewStub(
         CreateChannel(workers[i], InsecureChannelCredentials()));
+
+    ServerConfig server_config = initial_server_config;
+    char* host;
+    char* driver_port;
+    char* cli_target;
+    gpr_split_host_port(workers[i].c_str(), &host, &driver_port);
+    string host_str(host);
+    int server_core_limit = initial_server_config.core_limit();
+    int client_core_limit = initial_client_config.core_limit();
+
+    if (server_core_limit == 0 && client_core_limit > 0) {
+      // In this case, limit the server cores if it matches the
+      // same host as one or more clients
+      const auto& dq = hosts_cores.at(host_str);
+      bool match = false;
+      int limit = dq.size();
+      for (size_t cli = 0; cli < num_clients; cli++) {
+        if (host_str == get_host(workers[cli + num_servers])) {
+          limit -= client_core_limit;
+          match = true;
+        }
+      }
+      if (match) {
+        GPR_ASSERT(limit > 0);
+        server_core_limit = limit;
+      }
+    }
+    if (server_core_limit > 0) {
+      auto& dq = hosts_cores.at(host_str);
+      GPR_ASSERT(dq.size() >= static_cast<size_t>(server_core_limit));
+      for (int core = 0; core < server_core_limit; core++) {
+        server_config.add_core_list(dq.front());
+        dq.pop_front();
+      }
+    }
+
     ServerArgs args;
-    result_server_config = server_config;
     *args.mutable_setup() = server_config;
     servers[i].stream =
         servers[i].stub->RunServer(runsc::AllocContext(&contexts, deadline));
     GPR_ASSERT(servers[i].stream->Write(args));
     ServerStatus init_status;
     GPR_ASSERT(servers[i].stream->Read(&init_status));
-    char* host;
-    char* driver_port;
-    char* cli_target;
-    gpr_split_host_port(workers[i].c_str(), &host, &driver_port);
     gpr_join_host_port(&cli_target, host, init_status.port());
     client_config.add_server_targets(cli_target);
     gpr_free(host);
@@ -184,19 +261,50 @@
     gpr_free(cli_target);
   }
 
+  // Targets are all set by now
+  result_client_config = client_config;
   // Start clients
   using runsc::ClientData;
   // clients is array rather than std::vector to avoid gcc-4.4 issues
   // where class contained in std::vector must have a copy constructor
   auto* clients = new ClientData[num_clients];
   for (size_t i = 0; i < num_clients; i++) {
-    gpr_log(GPR_INFO, "Starting client on %s (worker #%d)",
-            workers[i + num_servers].c_str(), i + num_servers);
+    const auto& worker = workers[i + num_servers];
+    gpr_log(GPR_INFO, "Starting client on %s (worker #%d)", worker.c_str(),
+            i + num_servers);
     clients[i].stub = WorkerService::NewStub(
-        CreateChannel(workers[i + num_servers], InsecureChannelCredentials()));
+        CreateChannel(worker, InsecureChannelCredentials()));
+    ClientConfig per_client_config = client_config;
+
+    int server_core_limit = initial_server_config.core_limit();
+    int client_core_limit = initial_client_config.core_limit();
+    if ((server_core_limit > 0) || (client_core_limit > 0)) {
+      auto& dq = hosts_cores.at(get_host(worker));
+      if (client_core_limit == 0) {
+        // limit client cores if it matches a server host
+        bool match = false;
+        int limit = dq.size();
+        for (size_t srv = 0; srv < num_servers; srv++) {
+          if (get_host(worker) == get_host(workers[srv])) {
+            match = true;
+          }
+        }
+        if (match) {
+          GPR_ASSERT(limit > 0);
+          client_core_limit = limit;
+        }
+      }
+      if (client_core_limit > 0) {
+        GPR_ASSERT(dq.size() >= static_cast<size_t>(client_core_limit));
+        for (int core = 0; core < client_core_limit; core++) {
+          per_client_config.add_core_list(dq.front());
+          dq.pop_front();
+        }
+      }
+    }
+
     ClientArgs args;
-    result_client_config = client_config;
-    *args.mutable_setup() = client_config;
+    *args.mutable_setup() = per_client_config;
     clients[i].stream =
         clients[i].stub->RunClient(runsc::AllocContext(&contexts, deadline));
     GPR_ASSERT(clients[i].stream->Write(args));
@@ -276,5 +384,18 @@
   delete[] servers;
   return result;
 }
+
+void RunQuit() {
+  // Get client, server lists
+  auto workers = get_workers("QPS_WORKERS");
+  for (size_t i = 0; i < workers.size(); i++) {
+    auto stub = WorkerService::NewStub(
+        CreateChannel(workers[i], InsecureChannelCredentials()));
+    Void dummy;
+    grpc::ClientContext ctx;
+    GPR_ASSERT(stub->QuitWorker(&ctx, dummy, &dummy).ok());
+  }
+}
+
 }  // namespace testing
 }  // namespace grpc
diff --git a/test/cpp/qps/driver.h b/test/cpp/qps/driver.h
index 2a7cf80..3af61f7 100644
--- a/test/cpp/qps/driver.h
+++ b/test/cpp/qps/driver.h
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -70,6 +70,7 @@
     const grpc::testing::ServerConfig& server_config, size_t num_servers,
     int warmup_seconds, int benchmark_seconds, int spawn_local_worker_count);
 
+void RunQuit();
 }  // namespace testing
 }  // namespace grpc
 
diff --git a/test/cpp/qps/generic_async_streaming_ping_pong_test.cc b/test/cpp/qps/generic_async_streaming_ping_pong_test.cc
index 81c0f24..d9166ae 100644
--- a/test/cpp/qps/generic_async_streaming_ping_pong_test.cc
+++ b/test/cpp/qps/generic_async_streaming_ping_pong_test.cc
@@ -61,7 +61,6 @@
 
   ServerConfig server_config;
   server_config.set_server_type(ASYNC_GENERIC_SERVER);
-  server_config.set_host("localhost");
   server_config.set_async_server_threads(1);
 
   const auto result =
diff --git a/test/cpp/qps/limit_cores.cc b/test/cpp/qps/limit_cores.cc
new file mode 100644
index 0000000..fad9a32
--- /dev/null
+++ b/test/cpp/qps/limit_cores.cc
@@ -0,0 +1,79 @@
+/*
+ *
+ * Copyright 2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "test/cpp/qps/limit_cores.h"
+
+#include <grpc/support/cpu.h>
+#include <grpc/support/log.h>
+#include <grpc/support/port_platform.h>
+
+namespace grpc {
+namespace testing {
+
+#ifdef GPR_CPU_LINUX
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE
+#endif
+#include <sched.h>
+int LimitCores(const int* cores, int cores_size) {
+  const int num_cores = gpr_cpu_num_cores();
+  int cores_set = 0;
+
+  cpu_set_t* cpup = CPU_ALLOC(num_cores);
+  GPR_ASSERT(cpup);
+  const size_t size = CPU_ALLOC_SIZE(num_cores);
+  CPU_ZERO_S(size, cpup);
+
+  if (cores_size > 0) {
+    for (int i = 0; i < cores_size; i++) {
+      if (cores[i] < num_cores) {
+        CPU_SET_S(cores[i], size, cpup);
+        cores_set++;
+      }
+    }
+  } else {
+    for (int i = 0; i < num_cores; i++) {
+      CPU_SET_S(i, size, cpup);
+      cores_set++;
+    }
+  }
+  GPR_ASSERT(sched_setaffinity(0, size, cpup) == 0);
+  CPU_FREE(cpup);
+  return cores_set;
+}
+#else
+// LimitCores is not currently supported for non-Linux platforms
+int LimitCores(const int*, int) { return gpr_cpu_num_cores(); }
+#endif
+}  // namespace testing
+}  // namespace grpc
diff --git a/src/objective-c/GRPCClient/private/GRPCUnsecuredChannel.h b/test/cpp/qps/limit_cores.h
similarity index 71%
copy from src/objective-c/GRPCClient/private/GRPCUnsecuredChannel.h
copy to test/cpp/qps/limit_cores.h
index 8528be4..5482904 100644
--- a/src/objective-c/GRPCClient/private/GRPCUnsecuredChannel.h
+++ b/test/cpp/qps/limit_cores.h
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -31,8 +31,19 @@
  *
  */
 
-#import "GRPCChannel.h"
+#ifndef TEST_QPS_LIMIT_CORES_H
+#define TEST_QPS_LIMIT_CORES_H
 
-@interface GRPCUnsecuredChannel : GRPCChannel
-- (instancetype)initWithHost:(NSString *)host NS_DESIGNATED_INITIALIZER;
-@end
+namespace grpc {
+namespace testing {
+/// LimitCores: allow this worker to only run on the cores specified in the
+/// array \a cores, which is of length \a cores_size.
+///
+/// LimitCores takes array and size arguments (instead of vector) for direct
+/// conversion from repeated field of protobuf. Use a cores_size of 0 to remove
+/// existing limits (from an empty repeated field)
+int LimitCores(const int *cores, int cores_size);
+}  // namespace testing
+}  // namespace grpc
+
+#endif  // TEST_QPS_LIMIT_CORES_H
diff --git a/test/cpp/qps/qps-sweep.sh b/test/cpp/qps/qps-sweep.sh
index 36ea974..539da1d 100755
--- a/test/cpp/qps/qps-sweep.sh
+++ b/test/cpp/qps/qps-sweep.sh
@@ -1,6 +1,6 @@
 #!/bin/sh
 
-# Copyright 2015, Google Inc.
+# Copyright 2015-2016, Google Inc.
 # All rights reserved.
 #
 # Redistribution and use in source and binary forms, with or without
@@ -37,22 +37,107 @@
 
 bins=`find . .. ../.. ../../.. -name bins | head -1`
 
-for secure in true false
-do
-  for channels in 1 2 4 8
-  do
-    for client in SYNC_CLIENT ASYNC_CLIENT
-    do
-      for server in SYNC_SERVER ASYNC_SERVER
-      do
-        for rpc in UNARY STREAMING
-        do
-          echo "Test $rpc $client $server, $channels channels, secure=$secure"
-          "$bins"/opt/qps_driver --rpc_type=$rpc \
-              --client_type=$client --server_type=$server \
-	      --secure_test=$secure
-	done
-      done
-    done
-  done
+set -x
+
+big=65536
+half=`echo $QPS_WORKERS | awk -F, '{print int(NF/2)}'`
+
+for secure in true false; do
+  # Scenario 1: generic async streaming ping-pong (contentionless latency)
+  "$bins"/opt/qps_driver --rpc_type=STREAMING --client_type=ASYNC_CLIENT \
+    --server_type=ASYNC_GENERIC_SERVER --outstanding_rpcs_per_channel=1 \
+    --client_channels=1 --bbuf_req_size=0 --bbuf_resp_size=0 \
+    --async_client_threads=1 --async_server_threads=1 --secure_test=$secure \
+    --num_servers=1 --num_clients=1
+
+  # Scenario 2: generic async streaming "unconstrained" (QPS)
+  "$bins"/opt/qps_driver --rpc_type=STREAMING --client_type=ASYNC_CLIENT \
+    --server_type=ASYNC_GENERIC_SERVER --outstanding_rpcs_per_channel=100 \
+    --client_channels=64 --bbuf_req_size=0 --bbuf_resp_size=0 \
+    --async_client_threads=0 --async_server_threads=0 --secure_test=$secure \
+    --num_servers=1 --num_clients=0
+
+  # Scenario 2b: QPS with a single server core
+  "$bins"/opt/qps_driver --rpc_type=STREAMING --client_type=ASYNC_CLIENT \
+    --server_type=ASYNC_GENERIC_SERVER --outstanding_rpcs_per_channel=100 \
+    --client_channels=64 --bbuf_req_size=0 --bbuf_resp_size=0 \
+    --async_client_threads=0 --async_server_threads=0 --secure_test=$secure \
+    --num_servers=1 --num_clients=0 --server_core_limit=1
+
+  # Scenario 2c: protobuf-based QPS
+  "$bins"/opt/qps_driver --rpc_type=STREAMING --client_type=ASYNC_CLIENT \
+    --server_type=ASYNC_SERVER --outstanding_rpcs_per_channel=100 \
+    --client_channels=64 --simple_req_size=0 --simple_resp_size=0 \
+    --async_client_threads=0 --async_server_threads=0 --secure_test=$secure \
+    --num_servers=1 --num_clients=0
+
+  # Scenario 3: Latency at near-peak load (TBD)
+
+  # Scenario 4: Single-channel bidirectional throughput test (like TCP_STREAM).
+  "$bins"/opt/qps_driver --rpc_type=STREAMING --client_type=ASYNC_CLIENT \
+    --server_type=ASYNC_GENERIC_SERVER --outstanding_rpcs_per_channel=100 \
+    --client_channels=1 --bbuf_req_size=$big --bbuf_resp_size=$big \
+    --async_client_threads=1 --async_server_threads=1 --secure_test=$secure \
+    --num_servers=1 --num_clients=1
+
+  # Scenario 5: Sync unary ping-pong with protobufs
+  "$bins"/opt/qps_driver --rpc_type=UNARY --client_type=SYNC_CLIENT \
+    --server_type=SYNC_SERVER --outstanding_rpcs_per_channel=1 \
+    --client_channels=1 --simple_req_size=0 --simple_resp_size=0 \
+    --secure_test=$secure --num_servers=1 --num_clients=1
+
+  # Scenario 6: Sync streaming ping-pong with protobufs
+  "$bins"/opt/qps_driver --rpc_type=STREAMING --client_type=SYNC_CLIENT \
+    --server_type=SYNC_SERVER --outstanding_rpcs_per_channel=1 \
+    --client_channels=1 --simple_req_size=0 --simple_resp_size=0 \
+    --secure_test=$secure --num_servers=1 --num_clients=1
+
+  # Scenario 7: Async unary ping-pong with protobufs
+  "$bins"/opt/qps_driver --rpc_type=UNARY --client_type=ASYNC_CLIENT \
+    --server_type=ASYNC_SERVER --outstanding_rpcs_per_channel=1 \
+    --client_channels=1 --simple_req_size=0 --simple_resp_size=0 \
+    --async_client_threads=1 --async_server_threads=1 --secure_test=$secure \
+    --num_servers=1 --num_clients=1
+
+  # Scenario 8: Async streaming ping-pong with protobufs
+  "$bins"/opt/qps_driver --rpc_type=STREAMING --client_type=ASYNC_CLIENT \
+    --server_type=ASYNC_SERVER --outstanding_rpcs_per_channel=1 \
+    --client_channels=1 --simple_req_size=0 --simple_resp_size=0 \
+    --async_client_threads=1 --async_server_threads=1 --secure_test=$secure \
+    --num_servers=1 --num_clients=1
+
+  # Scenario 9: Crossbar QPS test
+  "$bins"/opt/qps_driver --rpc_type=STREAMING --client_type=ASYNC_CLIENT \
+    --server_type=ASYNC_GENERIC_SERVER --outstanding_rpcs_per_channel=100 \
+    --client_channels=64 --bbuf_req_size=0 --bbuf_resp_size=0 \
+    --async_client_threads=0 --async_server_threads=0 --secure_test=$secure \
+    --num_servers=$half --num_clients=0
+
+  # Scenario 10: Multi-channel bidir throughput test
+  "$bins"/opt/qps_driver --rpc_type=STREAMING --client_type=ASYNC_CLIENT \
+    --server_type=ASYNC_GENERIC_SERVER --outstanding_rpcs_per_channel=100 \
+    --client_channels=64 --bbuf_req_size=$big --bbuf_resp_size=$big \
+    --async_client_threads=0 --async_server_threads=0 --secure_test=$secure \
+    --num_servers=1 --num_clients=1
+
+  # Scenario 11: Single-channel request throughput test
+  "$bins"/opt/qps_driver --rpc_type=STREAMING --client_type=ASYNC_CLIENT \
+    --server_type=ASYNC_GENERIC_SERVER --outstanding_rpcs_per_channel=100 \
+    --client_channels=1 --bbuf_req_size=$big --bbuf_resp_size=0 \
+    --async_client_threads=1 --async_server_threads=1 --secure_test=$secure \
+    --num_servers=1 --num_clients=1
+
+  # Scenario 12: Single-channel response throughput test
+  "$bins"/opt/qps_driver --rpc_type=STREAMING --client_type=ASYNC_CLIENT \
+    --server_type=ASYNC_GENERIC_SERVER --outstanding_rpcs_per_channel=100 \
+    --client_channels=1 --bbuf_req_size=0 --bbuf_resp_size=$big \
+    --async_client_threads=1 --async_server_threads=1 --secure_test=$secure \
+    --num_servers=1 --num_clients=1
+
+  # Scenario 13: Single-channel bidirectional protobuf throughput test
+  "$bins"/opt/qps_driver --rpc_type=STREAMING --client_type=ASYNC_CLIENT \
+    --server_type=ASYNC_SERVER --outstanding_rpcs_per_channel=100 \
+    --client_channels=1 --simple_req_size=$big --simple_resp_size=$big \
+    --async_client_threads=1 --async_server_threads=1 --secure_test=$secure \
+    --num_servers=1 --num_clients=1
 done
diff --git a/test/cpp/qps/qps_driver.cc b/test/cpp/qps/qps_driver.cc
index 680e4b1..69fb4d7 100644
--- a/test/cpp/qps/qps_driver.cc
+++ b/test/cpp/qps/qps_driver.cc
@@ -48,14 +48,13 @@
 DEFINE_int32(benchmark_seconds, 30, "Benchmark time (in seconds)");
 DEFINE_int32(local_workers, 0, "Number of local workers to start");
 
-// Common config
-DEFINE_string(rpc_type, "UNARY", "Type of RPC: UNARY or STREAMING");
-
 // Server config
 DEFINE_int32(async_server_threads, 1, "Number of threads for async servers");
 DEFINE_string(server_type, "SYNC_SERVER", "Server type");
+DEFINE_int32(server_core_limit, -1, "Limit on server cores to use");
 
 // Client config
+DEFINE_string(rpc_type, "UNARY", "Type of RPC: UNARY or STREAMING");
 DEFINE_int32(outstanding_rpcs_per_channel, 1,
              "Number of outstanding rpcs per channel");
 DEFINE_int32(client_channels, 1, "Number of client channels");
@@ -75,8 +74,12 @@
 DEFINE_double(pareto_base, -1.0, "Pareto base interarrival time (us)");
 DEFINE_double(pareto_alpha, -1.0, "Pareto alpha value");
 
+DEFINE_int32(client_core_limit, -1, "Limit on client cores to use");
+
 DEFINE_bool(secure_test, false, "Run a secure test");
 
+DEFINE_bool(quit, false, "Quit the workers");
+
 using grpc::testing::ClientConfig;
 using grpc::testing::ServerConfig;
 using grpc::testing::ClientType;
@@ -89,6 +92,11 @@
 namespace testing {
 
 static void QpsDriver() {
+  if (FLAGS_quit) {
+    RunQuit();
+    return;
+  }
+
   RpcType rpc_type;
   GPR_ASSERT(RpcType_Parse(FLAGS_rpc_type, &rpc_type));
 
@@ -151,11 +159,18 @@
   client_config.mutable_histogram_params()->set_max_possible(
       Histogram::default_max_possible());
 
+  if (FLAGS_client_core_limit > 0) {
+    client_config.set_core_limit(FLAGS_client_core_limit);
+  }
+
   ServerConfig server_config;
   server_config.set_server_type(server_type);
-  server_config.set_host("::");  // Use the wildcard server address
   server_config.set_async_server_threads(FLAGS_async_server_threads);
 
+  if (FLAGS_server_core_limit > 0) {
+    server_config.set_core_limit(FLAGS_server_core_limit);
+  }
+
   if (FLAGS_secure_test) {
     // Set up security params
     SecurityParams security;
diff --git a/test/cpp/qps/qps_openloop_test.cc b/test/cpp/qps/qps_openloop_test.cc
index 51df79e..fe5f685 100644
--- a/test/cpp/qps/qps_openloop_test.cc
+++ b/test/cpp/qps/qps_openloop_test.cc
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -59,7 +59,6 @@
 
   ServerConfig server_config;
   server_config.set_server_type(ASYNC_SERVER);
-  server_config.set_host("localhost");
   server_config.set_async_server_threads(4);
 
   const auto result =
diff --git a/test/cpp/qps/qps_test.cc b/test/cpp/qps/qps_test.cc
index 1f87d18..15054db 100644
--- a/test/cpp/qps/qps_test.cc
+++ b/test/cpp/qps/qps_test.cc
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -58,7 +58,6 @@
 
   ServerConfig server_config;
   server_config.set_server_type(ASYNC_SERVER);
-  server_config.set_host("localhost");
   server_config.set_async_server_threads(8);
 
   const auto result =
diff --git a/test/cpp/qps/qps_test_with_poll.cc b/test/cpp/qps/qps_test_with_poll.cc
index dc80009..8340a63 100644
--- a/test/cpp/qps/qps_test_with_poll.cc
+++ b/test/cpp/qps/qps_test_with_poll.cc
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -62,7 +62,6 @@
 
   ServerConfig server_config;
   server_config.set_server_type(ASYNC_SERVER);
-  server_config.set_host("localhost");
   server_config.set_async_server_threads(4);
 
   const auto result =
diff --git a/test/cpp/qps/qps_worker.cc b/test/cpp/qps/qps_worker.cc
index 6316605..9442017 100644
--- a/test/cpp/qps/qps_worker.cc
+++ b/test/cpp/qps/qps_worker.cc
@@ -47,6 +47,7 @@
 #include <grpc++/server_builder.h>
 #include <grpc/grpc.h>
 #include <grpc/support/alloc.h>
+#include <grpc/support/cpu.h>
 #include <grpc/support/histogram.h>
 #include <grpc/support/host_port.h>
 #include <grpc/support/log.h>
@@ -83,15 +84,10 @@
   abort();
 }
 
-static void LimitCores(int cores) {}
-
 static std::unique_ptr<Server> CreateServer(const ServerConfig& config) {
   gpr_log(GPR_INFO, "Starting server of type %s",
           ServerType_Name(config.server_type()).c_str());
 
-  if (config.core_limit() > 0) {
-    LimitCores(config.core_limit());
-  }
   switch (config.server_type()) {
     case ServerType::SYNC_SERVER:
       return CreateSynchronousServer(config);
@@ -107,8 +103,8 @@
 
 class WorkerServiceImpl GRPC_FINAL : public WorkerService::Service {
  public:
-  explicit WorkerServiceImpl(int server_port)
-      : acquired_(false), server_port_(server_port) {}
+  WorkerServiceImpl(int server_port, QpsWorker* worker)
+      : acquired_(false), server_port_(server_port), worker_(worker) {}
 
   Status RunClient(ServerContext* ctx,
                    ServerReaderWriter<ClientStatus, ClientArgs>* stream)
@@ -138,6 +134,22 @@
     return ret;
   }
 
+  Status CoreCount(ServerContext* ctx, const CoreRequest*,
+                   CoreResponse* resp) GRPC_OVERRIDE {
+    resp->set_cores(gpr_cpu_num_cores());
+    return Status::OK;
+  }
+
+  Status QuitWorker(ServerContext* ctx, const Void*, Void*) GRPC_OVERRIDE {
+    InstanceGuard g(this);
+    if (!g.Acquired()) {
+      return Status(StatusCode::RESOURCE_EXHAUSTED, "");
+    }
+
+    worker_->MarkDone();
+    return Status::OK;
+  }
+
  private:
   // Protect against multiple clients using this worker at once.
   class InstanceGuard {
@@ -248,10 +260,12 @@
   std::mutex mu_;
   bool acquired_;
   int server_port_;
+  QpsWorker* worker_;
 };
 
 QpsWorker::QpsWorker(int driver_port, int server_port) {
-  impl_.reset(new WorkerServiceImpl(server_port));
+  impl_.reset(new WorkerServiceImpl(server_port, this));
+  gpr_atm_rel_store(&done_, static_cast<gpr_atm>(0));
 
   char* server_address = NULL;
   gpr_join_host_port(&server_address, "::", driver_port);
@@ -267,5 +281,11 @@
 
 QpsWorker::~QpsWorker() {}
 
+bool QpsWorker::Done() const {
+  return (gpr_atm_acq_load(&done_) != static_cast<gpr_atm>(0));
+}
+void QpsWorker::MarkDone() {
+  gpr_atm_rel_store(&done_, static_cast<gpr_atm>(1));
+}
 }  // namespace testing
 }  // namespace grpc
diff --git a/test/cpp/qps/qps_worker.h b/test/cpp/qps/qps_worker.h
index 27de69f..624c182 100644
--- a/test/cpp/qps/qps_worker.h
+++ b/test/cpp/qps/qps_worker.h
@@ -36,6 +36,8 @@
 
 #include <memory>
 
+#include <grpc/support/atm.h>
+
 namespace grpc {
 
 class Server;
@@ -49,9 +51,14 @@
   explicit QpsWorker(int driver_port, int server_port = 0);
   ~QpsWorker();
 
+  bool Done() const;
+  void MarkDone();
+
  private:
   std::unique_ptr<WorkerServiceImpl> impl_;
   std::unique_ptr<Server> server_;
+
+  gpr_atm done_;
 };
 
 }  // namespace testing
diff --git a/test/cpp/qps/secure_sync_unary_ping_pong_test.cc b/test/cpp/qps/secure_sync_unary_ping_pong_test.cc
index ce9f02c..359310b 100644
--- a/test/cpp/qps/secure_sync_unary_ping_pong_test.cc
+++ b/test/cpp/qps/secure_sync_unary_ping_pong_test.cc
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -57,7 +57,6 @@
 
   ServerConfig server_config;
   server_config.set_server_type(SYNC_SERVER);
-  server_config.set_host("localhost");
 
   // Set up security params
   SecurityParams security;
diff --git a/test/cpp/qps/server.h b/test/cpp/qps/server.h
index 196fdac..94a6f8a 100644
--- a/test/cpp/qps/server.h
+++ b/test/cpp/qps/server.h
@@ -34,14 +34,16 @@
 #ifndef TEST_QPS_SERVER_H
 #define TEST_QPS_SERVER_H
 
-#include <grpc/support/cpu.h>
 #include <grpc++/security/server_credentials.h>
+#include <grpc/support/cpu.h>
+#include <vector>
 
+#include "src/proto/grpc/testing/control.grpc.pb.h"
+#include "src/proto/grpc/testing/messages.grpc.pb.h"
 #include "test/core/end2end/data/ssl_test_data.h"
 #include "test/core/util/port.h"
+#include "test/cpp/qps/limit_cores.h"
 #include "test/cpp/qps/timer.h"
-#include "src/proto/grpc/testing/messages.grpc.pb.h"
-#include "src/proto/grpc/testing/control.grpc.pb.h"
 
 namespace grpc {
 namespace testing {
@@ -49,8 +51,10 @@
 class Server {
  public:
   explicit Server(const ServerConfig& config) : timer_(new Timer) {
+    cores_ = LimitCores(config.core_list().data(), config.core_list_size());
     if (config.port()) {
       port_ = config.port();
+
     } else {
       port_ = grpc_pick_unused_port_or_die();
     }
@@ -86,7 +90,7 @@
   }
 
   int port() const { return port_; }
-  int cores() const { return gpr_cpu_num_cores(); }
+  int cores() const { return cores_; }
   static std::shared_ptr<ServerCredentials> CreateServerCredentials(
       const ServerConfig& config) {
     if (config.has_security_params()) {
@@ -103,6 +107,7 @@
 
  private:
   int port_;
+  int cores_;
   std::unique_ptr<Timer> timer_;
 };
 
diff --git a/test/cpp/qps/server_async.cc b/test/cpp/qps/server_async.cc
index cd8d546..1302d71 100644
--- a/test/cpp/qps/server_async.cc
+++ b/test/cpp/qps/server_async.cc
@@ -50,8 +50,8 @@
 #include <grpc/support/log.h>
 #include <gtest/gtest.h>
 
-#include "test/cpp/qps/server.h"
 #include "src/proto/grpc/testing/services.grpc.pb.h"
+#include "test/cpp/qps/server.h"
 
 namespace grpc {
 namespace testing {
@@ -76,7 +76,7 @@
       : Server(config) {
     char *server_address = NULL;
 
-    gpr_join_host_port(&server_address, config.host().c_str(), port());
+    gpr_join_host_port(&server_address, "::", port());
 
     ServerBuilder builder;
     builder.AddListeningPort(server_address,
@@ -85,7 +85,13 @@
 
     register_service(&builder, &async_service_);
 
-    for (int i = 0; i < config.async_server_threads(); i++) {
+    int num_threads = config.async_server_threads();
+    if (num_threads <= 0) {  // dynamic sizing
+      num_threads = cores();
+      gpr_log(GPR_INFO, "Sizing async server to %d threads", num_threads);
+    }
+
+    for (int i = 0; i < num_threads; i++) {
       srv_cqs_.emplace_back(builder.AddCompletionQueue());
     }
 
@@ -96,8 +102,8 @@
     auto process_rpc_bound =
         std::bind(process_rpc, config.payload_config(), _1, _2);
 
-    for (int i = 0; i < 10000 / config.async_server_threads(); i++) {
-      for (int j = 0; j < config.async_server_threads(); j++) {
+    for (int i = 0; i < 10000 / num_threads; i++) {
+      for (int j = 0; j < num_threads; j++) {
         if (request_unary_function) {
           auto request_unary =
               std::bind(request_unary_function, &async_service_, _1, _2, _3,
@@ -115,10 +121,10 @@
       }
     }
 
-    for (int i = 0; i < config.async_server_threads(); i++) {
+    for (int i = 0; i < num_threads; i++) {
       shutdown_state_.emplace_back(new PerThreadShutdownState());
     }
-    for (int i = 0; i < config.async_server_threads(); i++) {
+    for (int i = 0; i < num_threads; i++) {
       threads_.emplace_back(&AsyncQpsServerTest::ThreadFunc, this, i);
     }
   }
@@ -350,7 +356,7 @@
 
 static void RegisterBenchmarkService(ServerBuilder *builder,
                                      BenchmarkService::AsyncService *service) {
-  builder->RegisterAsyncService(service);
+  builder->RegisterService(service);
 }
 static void RegisterGenericService(ServerBuilder *builder,
                                    grpc::AsyncGenericService *service) {
diff --git a/test/cpp/qps/server_sync.cc b/test/cpp/qps/server_sync.cc
index 97a1ff5..4b77882 100644
--- a/test/cpp/qps/server_sync.cc
+++ b/test/cpp/qps/server_sync.cc
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -89,7 +89,7 @@
 
     char* server_address = NULL;
 
-    gpr_join_host_port(&server_address, config.host().c_str(), port());
+    gpr_join_host_port(&server_address, "::", port());
     builder.AddListeningPort(server_address,
                              Server::CreateServerCredentials(config));
     gpr_free(server_address);
diff --git a/test/cpp/qps/sync_streaming_ping_pong_test.cc b/test/cpp/qps/sync_streaming_ping_pong_test.cc
index dd8c682..e02c14c 100644
--- a/test/cpp/qps/sync_streaming_ping_pong_test.cc
+++ b/test/cpp/qps/sync_streaming_ping_pong_test.cc
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -57,7 +57,6 @@
 
   ServerConfig server_config;
   server_config.set_server_type(SYNC_SERVER);
-  server_config.set_host("localhost");
 
   const auto result =
       RunScenario(client_config, 1, server_config, 1, WARMUP, BENCHMARK, -2);
diff --git a/test/cpp/qps/sync_unary_ping_pong_test.cc b/test/cpp/qps/sync_unary_ping_pong_test.cc
index 2edb33e..9d363c0 100644
--- a/test/cpp/qps/sync_unary_ping_pong_test.cc
+++ b/test/cpp/qps/sync_unary_ping_pong_test.cc
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -57,7 +57,6 @@
 
   ServerConfig server_config;
   server_config.set_server_type(SYNC_SERVER);
-  server_config.set_host("localhost");
 
   const auto result =
       RunScenario(client_config, 1, server_config, 1, WARMUP, BENCHMARK, -2);
diff --git a/test/cpp/qps/worker.cc b/test/cpp/qps/worker.cc
index a1e73e9..f42cfe3 100644
--- a/test/cpp/qps/worker.cc
+++ b/test/cpp/qps/worker.cc
@@ -56,7 +56,7 @@
 static void RunServer() {
   QpsWorker worker(FLAGS_driver_port, FLAGS_server_port);
 
-  while (!got_sigint) {
+  while (!got_sigint && !worker.Done()) {
     gpr_sleep_until(gpr_time_add(gpr_now(GPR_CLOCK_REALTIME),
                                  gpr_time_from_seconds(5, GPR_TIMESPAN)));
   }
diff --git a/src/objective-c/GRPCClient/private/GRPCUnsecuredChannel.h b/test/cpp/util/byte_buffer_proto_helper.cc
similarity index 64%
copy from src/objective-c/GRPCClient/private/GRPCUnsecuredChannel.h
copy to test/cpp/util/byte_buffer_proto_helper.cc
index 8528be4..2512c9b 100644
--- a/src/objective-c/GRPCClient/private/GRPCUnsecuredChannel.h
+++ b/test/cpp/util/byte_buffer_proto_helper.cc
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -31,8 +31,30 @@
  *
  */
 
-#import "GRPCChannel.h"
+#include "test/cpp/util/byte_buffer_proto_helper.h"
 
-@interface GRPCUnsecuredChannel : GRPCChannel
-- (instancetype)initWithHost:(NSString *)host NS_DESIGNATED_INITIALIZER;
-@end
+namespace grpc {
+namespace testing {
+
+bool ParseFromByteBuffer(ByteBuffer* buffer, grpc::protobuf::Message* message) {
+  std::vector<Slice> slices;
+  buffer->Dump(&slices);
+  grpc::string buf;
+  buf.reserve(buffer->Length());
+  for (auto s = slices.begin(); s != slices.end(); s++) {
+    buf.append(reinterpret_cast<const char*>(s->begin()), s->size());
+  }
+  return message->ParseFromString(buf);
+}
+
+std::unique_ptr<ByteBuffer> SerializeToByteBuffer(
+    grpc::protobuf::Message* message) {
+  grpc::string buf;
+  message->SerializeToString(&buf);
+  gpr_slice s = gpr_slice_from_copied_string(buf.c_str());
+  Slice slice(s, Slice::STEAL_REF);
+  return std::unique_ptr<ByteBuffer>(new ByteBuffer(&slice, 1));
+}
+
+}  // namespace testing
+}  // namespace grpc
diff --git a/src/objective-c/GRPCClient/private/GRPCUnsecuredChannel.h b/test/cpp/util/byte_buffer_proto_helper.h
similarity index 72%
copy from src/objective-c/GRPCClient/private/GRPCUnsecuredChannel.h
copy to test/cpp/util/byte_buffer_proto_helper.h
index 8528be4..42cea59 100644
--- a/src/objective-c/GRPCClient/private/GRPCUnsecuredChannel.h
+++ b/test/cpp/util/byte_buffer_proto_helper.h
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -31,8 +31,23 @@
  *
  */
 
-#import "GRPCChannel.h"
+#ifndef GRPC_TEST_CPP_UTIL_BYTE_BUFFER_PROTO_HELPER_H
+#define GRPC_TEST_CPP_UTIL_BYTE_BUFFER_PROTO_HELPER_H
 
-@interface GRPCUnsecuredChannel : GRPCChannel
-- (instancetype)initWithHost:(NSString *)host NS_DESIGNATED_INITIALIZER;
-@end
+#include <memory>
+
+#include <grpc++/support/byte_buffer.h>
+#include <grpc++/support/config_protobuf.h>
+
+namespace grpc {
+namespace testing {
+
+bool ParseFromByteBuffer(ByteBuffer* buffer, grpc::protobuf::Message* message);
+
+std::unique_ptr<ByteBuffer> SerializeToByteBuffer(
+    grpc::protobuf::Message* message);
+
+}  // namespace testing
+}  // namespace grpc
+
+#endif  // GRPC_TEST_CPP_UTIL_BYTE_BUFFER_PROTO_HELPER_H
diff --git a/test/cpp/util/cli_call.cc b/test/cpp/util/cli_call.cc
index 5e29e7a..d452be3 100644
--- a/test/cpp/util/cli_call.cc
+++ b/test/cpp/util/cli_call.cc
@@ -37,6 +37,7 @@
 
 #include <grpc++/channel.h>
 #include <grpc++/client_context.h>
+#include <grpc++/completion_queue.h>
 #include <grpc++/generic/generic_stub.h>
 #include <grpc++/support/byte_buffer.h>
 #include <grpc/grpc.h>
diff --git a/test/cpp/util/metrics_server.cc b/test/cpp/util/metrics_server.cc
index 40028d3..07978d0 100644
--- a/test/cpp/util/metrics_server.cc
+++ b/test/cpp/util/metrics_server.cc
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -33,6 +33,7 @@
 
 #include "test/cpp/util/metrics_server.h"
 
+#include <grpc++/server.h>
 #include <grpc++/server_builder.h>
 
 #include "src/proto/grpc/testing/metrics.grpc.pb.h"
diff --git a/test/cpp/util/time_test.cc b/test/cpp/util/time_test.cc
index 1e501df..48c6ce7 100644
--- a/test/cpp/util/time_test.cc
+++ b/test/cpp/util/time_test.cc
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -45,7 +45,7 @@
 class TimeTest : public ::testing::Test {};
 
 TEST_F(TimeTest, AbsolutePointTest) {
-  long us = 10000000L;
+  int64_t us = 10000000L;
   gpr_timespec ts = gpr_time_from_micros(us, GPR_TIMESPAN);
   ts.clock_type = GPR_CLOCK_REALTIME;
   system_clock::time_point tp{microseconds(us)};
diff --git a/test/distrib/csharp/.gitignore b/test/distrib/csharp/.gitignore
new file mode 100644
index 0000000..52503c7
--- /dev/null
+++ b/test/distrib/csharp/.gitignore
@@ -0,0 +1,6 @@
+packages
+*.userprefs
+*.csproj.user
+*.suo
+/TestNugetFeed
+
diff --git a/test/distrib/csharp/DistribTest.sln b/test/distrib/csharp/DistribTest.sln
new file mode 100644
index 0000000..0eca35c
--- /dev/null
+++ b/test/distrib/csharp/DistribTest.sln
@@ -0,0 +1,22 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio 2013
+VisualStudioVersion = 12.0.31101.0
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DistribTest", "DistribTest\DistribTest.csproj", "{A3E61CC3-3710-49A3-A830-A0066EDBCE2F}"
+EndProject
+Global
+	GlobalSection(SolutionConfigurationPlatforms) = preSolution
+		Debug|Any CPU = Debug|Any CPU
+		Release|Any CPU = Release|Any CPU
+	EndGlobalSection
+	GlobalSection(ProjectConfigurationPlatforms) = postSolution
+		{A3E61CC3-3710-49A3-A830-A0066EDBCE2F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{A3E61CC3-3710-49A3-A830-A0066EDBCE2F}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{A3E61CC3-3710-49A3-A830-A0066EDBCE2F}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{A3E61CC3-3710-49A3-A830-A0066EDBCE2F}.Release|Any CPU.Build.0 = Release|Any CPU
+	EndGlobalSection
+	GlobalSection(SolutionProperties) = preSolution
+		HideSolutionNode = FALSE
+	EndGlobalSection
+EndGlobal
diff --git a/test/distrib/csharp/DistribTest/.gitignore b/test/distrib/csharp/DistribTest/.gitignore
new file mode 100644
index 0000000..1746e32
--- /dev/null
+++ b/test/distrib/csharp/DistribTest/.gitignore
@@ -0,0 +1,2 @@
+bin
+obj
diff --git a/test/distrib/csharp/DistribTest/App.config b/test/distrib/csharp/DistribTest/App.config
new file mode 100644
index 0000000..30d3e09
--- /dev/null
+++ b/test/distrib/csharp/DistribTest/App.config
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="utf-8"?>
+<configuration>
+    <startup> 
+        <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
+    </startup>
+  <runtime>
+    <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
+      <dependentAssembly>
+        <assemblyIdentity name="System.Net.Http.Primitives" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
+        <bindingRedirect oldVersion="0.0.0.0-4.2.29.0" newVersion="4.2.29.0" />
+      </dependentAssembly>
+    </assemblyBinding>
+  </runtime>
+</configuration>
\ No newline at end of file
diff --git a/test/distrib/csharp/DistribTest/DistribTest.csproj b/test/distrib/csharp/DistribTest/DistribTest.csproj
new file mode 100644
index 0000000..124fc1b
--- /dev/null
+++ b/test/distrib/csharp/DistribTest/DistribTest.csproj
@@ -0,0 +1,112 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="12.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')" />
+  <PropertyGroup>
+    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+    <ProjectGuid>{A3E61CC3-3710-49A3-A830-A0066EDBCE2F}</ProjectGuid>
+    <OutputType>Exe</OutputType>
+    <AppDesignerFolder>Properties</AppDesignerFolder>
+    <RootNamespace>DistribTest</RootNamespace>
+    <AssemblyName>DistribTest</AssemblyName>
+    <TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
+    <FileAlignment>512</FileAlignment>
+    <NuGetPackageImportStamp>b86d820c</NuGetPackageImportStamp>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+    <PlatformTarget>AnyCPU</PlatformTarget>
+    <DebugSymbols>true</DebugSymbols>
+    <DebugType>full</DebugType>
+    <Optimize>false</Optimize>
+    <OutputPath>bin\Debug\</OutputPath>
+    <DefineConstants>DEBUG;TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+    <PlatformTarget>AnyCPU</PlatformTarget>
+    <DebugType>pdbonly</DebugType>
+    <Optimize>true</Optimize>
+    <OutputPath>bin\Release\</OutputPath>
+    <DefineConstants>TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+  </PropertyGroup>
+  <ItemGroup>
+    <Reference Include="BouncyCastle.Crypto">
+      <HintPath>..\packages\BouncyCastle.1.7.0\lib\Net40-Client\BouncyCastle.Crypto.dll</HintPath>
+    </Reference>
+    <Reference Include="Google.Apis.Auth">
+      <HintPath>..\packages\Google.Apis.Auth.1.9.3\lib\net40\Google.Apis.Auth.dll</HintPath>
+    </Reference>
+    <Reference Include="Google.Apis.Auth.PlatformServices">
+      <HintPath>..\packages\Google.Apis.Auth.1.9.3\lib\net40\Google.Apis.Auth.PlatformServices.dll</HintPath>
+    </Reference>
+    <Reference Include="Google.Apis.Core">
+      <HintPath>..\packages\Google.Apis.Core.1.9.3\lib\portable-net40+sl50+win+wpa81+wp80\Google.Apis.Core.dll</HintPath>
+    </Reference>
+    <Reference Include="Grpc.Auth">
+      <HintPath>..\packages\Grpc.Auth.__GRPC_NUGET_VERSION__\lib\net45\Grpc.Auth.dll</HintPath>
+    </Reference>
+    <Reference Include="Grpc.Core">
+      <HintPath>..\packages\Grpc.Core.__GRPC_NUGET_VERSION__\lib\net45\Grpc.Core.dll</HintPath>
+    </Reference>
+    <Reference Include="Microsoft.Threading.Tasks">
+      <HintPath>..\packages\Microsoft.Bcl.Async.1.0.168\lib\net40\Microsoft.Threading.Tasks.dll</HintPath>
+    </Reference>
+    <Reference Include="Microsoft.Threading.Tasks.Extensions">
+      <HintPath>..\packages\Microsoft.Bcl.Async.1.0.168\lib\net40\Microsoft.Threading.Tasks.Extensions.dll</HintPath>
+    </Reference>
+    <Reference Include="Microsoft.Threading.Tasks.Extensions.Desktop">
+      <HintPath>..\packages\Microsoft.Bcl.Async.1.0.168\lib\net40\Microsoft.Threading.Tasks.Extensions.Desktop.dll</HintPath>
+    </Reference>
+    <Reference Include="Newtonsoft.Json, Version=7.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
+      <SpecificVersion>False</SpecificVersion>
+      <HintPath>..\packages\Newtonsoft.Json.7.0.1\lib\net45\Newtonsoft.Json.dll</HintPath>
+    </Reference>
+    <Reference Include="System" />
+    <Reference Include="System.Core" />
+    <Reference Include="System.Interactive.Async">
+      <HintPath>..\packages\Ix-Async.1.2.3\lib\net45\System.Interactive.Async.dll</HintPath>
+    </Reference>
+    <Reference Include="System.Net" />
+    <Reference Include="System.Net.Http" />
+    <Reference Include="System.Net.Http.Extensions">
+      <HintPath>..\packages\Microsoft.Net.Http.2.2.29\lib\net45\System.Net.Http.Extensions.dll</HintPath>
+    </Reference>
+    <Reference Include="System.Net.Http.Primitives">
+      <HintPath>..\packages\Microsoft.Net.Http.2.2.29\lib\net45\System.Net.Http.Primitives.dll</HintPath>
+    </Reference>
+    <Reference Include="System.Net.Http.WebRequest" />
+    <Reference Include="System.Xml.Linq" />
+    <Reference Include="System.Data.DataSetExtensions" />
+    <Reference Include="Microsoft.CSharp" />
+    <Reference Include="System.Data" />
+    <Reference Include="System.Xml" />
+  </ItemGroup>
+  <ItemGroup>
+    <Compile Include="Program.cs" />
+    <Compile Include="Properties\AssemblyInfo.cs" />
+  </ItemGroup>
+  <ItemGroup>
+    <None Include="App.config" />
+    <None Include="packages.config" />
+  </ItemGroup>
+  <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
+  <Import Project="..\packages\grpc.native.csharp.__GRPC_NUGET_VERSION__\build\portable-net45+netcore45+wpa81+wp8\grpc.native.csharp.targets" Condition="Exists('..\packages\grpc.native.csharp.__GRPC_NUGET_VERSION__\build\portable-net45+netcore45+wpa81+wp8\grpc.native.csharp.targets')" />
+  <Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
+    <PropertyGroup>
+      <ErrorText>This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them.  For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
+    </PropertyGroup>
+    <Error Condition="!Exists('..\packages\grpc.native.csharp.__GRPC_NUGET_VERSION__\build\portable-net45+netcore45+wpa81+wp8\grpc.native.csharp.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\grpc.native.csharp.__GRPC_NUGET_VERSION__\build\portable-net45+netcore45+wpa81+wp8\grpc.native.csharp.targets'))" />
+    <Error Condition="!Exists('..\packages\Microsoft.Bcl.Build.1.0.21\build\Microsoft.Bcl.Build.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Microsoft.Bcl.Build.1.0.21\build\Microsoft.Bcl.Build.targets'))" />
+  </Target>
+  <Import Project="..\packages\Microsoft.Bcl.Build.1.0.21\build\Microsoft.Bcl.Build.targets" Condition="Exists('..\packages\Microsoft.Bcl.Build.1.0.21\build\Microsoft.Bcl.Build.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
diff --git a/test/distrib/csharp/DistribTest/Program.cs b/test/distrib/csharp/DistribTest/Program.cs
new file mode 100644
index 0000000..e944648
--- /dev/null
+++ b/test/distrib/csharp/DistribTest/Program.cs
@@ -0,0 +1,50 @@
+#region Copyright notice and license
+
+// Copyright 2015-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.
+
+#endregion
+
+using System;
+using Grpc.Core;
+
+namespace TestGrpcPackage
+{
+    class MainClass
+    {
+        public static void Main(string[] args)
+        {
+            // This code doesn't do much but makes sure the native extension is loaded
+            // which is what we are testing here.
+            Channel c = new Channel("127.0.0.1:1000", ChannelCredentials.Insecure);
+            c.ShutdownAsync().Wait();
+            Console.WriteLine("Success!");
+        }
+    }
+}
diff --git a/test/distrib/csharp/DistribTest/Properties/AssemblyInfo.cs b/test/distrib/csharp/DistribTest/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000..bc25b26
--- /dev/null
+++ b/test/distrib/csharp/DistribTest/Properties/AssemblyInfo.cs
@@ -0,0 +1,36 @@
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+// General Information about an assembly is controlled through the following 
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+[assembly: AssemblyTitle("DistribTest")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("DistribTest")]
+[assembly: AssemblyCopyright("Copyright ©  2016")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// Setting ComVisible to false makes the types in this assembly not visible 
+// to COM components.  If you need to access a type in this assembly from 
+// COM, set the ComVisible attribute to true on that type.
+[assembly: ComVisible(false)]
+
+// The following GUID is for the ID of the typelib if this project is exposed to COM
+[assembly: Guid("68755789-f103-4134-9027-b80a2fc9e21a")]
+
+// Version information for an assembly consists of the following four values:
+//
+//      Major Version
+//      Minor Version 
+//      Build Number
+//      Revision
+//
+// You can specify all the values or you can default the Build and Revision Numbers 
+// by using the '*' as shown below:
+// [assembly: AssemblyVersion("1.0.*")]
+[assembly: AssemblyVersion("1.0.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]
diff --git a/test/distrib/csharp/DistribTest/packages.config b/test/distrib/csharp/DistribTest/packages.config
new file mode 100644
index 0000000..aca09f6
--- /dev/null
+++ b/test/distrib/csharp/DistribTest/packages.config
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="utf-8"?>
+<packages>
+  <package id="BouncyCastle" version="1.7.0" targetFramework="net45" />
+  <package id="Google.Apis.Auth" version="1.9.3" targetFramework="net45" />
+  <package id="Google.Apis.Core" version="1.9.3" targetFramework="net45" />
+  <package id="Grpc" version="__GRPC_NUGET_VERSION__" targetFramework="net45" />
+  <package id="Grpc.Auth" version="__GRPC_NUGET_VERSION__" targetFramework="net45" />
+  <package id="Grpc.Core" version="__GRPC_NUGET_VERSION__" targetFramework="net45" />
+  <package id="grpc.native.csharp" version="__GRPC_NUGET_VERSION__" targetFramework="net45" />
+  <package id="Ix-Async" version="1.2.3" targetFramework="net45" />
+  <package id="Microsoft.Bcl" version="1.1.10" targetFramework="net45" />
+  <package id="Microsoft.Bcl.Async" version="1.0.168" targetFramework="net45" />
+  <package id="Microsoft.Bcl.Build" version="1.0.21" targetFramework="net45" />
+  <package id="Microsoft.Net.Http" version="2.2.29" targetFramework="net45" />
+  <package id="Newtonsoft.Json" version="7.0.1" targetFramework="net45" />
+</packages>
\ No newline at end of file
diff --git a/test/distrib/csharp/NuGet.Config b/test/distrib/csharp/NuGet.Config
new file mode 100644
index 0000000..e3b63c5
--- /dev/null
+++ b/test/distrib/csharp/NuGet.Config
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="utf-8"?>
+<configuration>
+  <packageSources>
+    <add key="https://www.nuget.org/api/v2/" value="https://www.nuget.org/api/v2/" />
+    <add key="TestNugetFeed" value="TestNugetFeed" />
+  </packageSources>
+</configuration>
+
diff --git a/test/distrib/csharp/build_vs2015.bat b/test/distrib/csharp/build_vs2015.bat
new file mode 100644
index 0000000..50485a3
--- /dev/null
+++ b/test/distrib/csharp/build_vs2015.bat
@@ -0,0 +1,10 @@
+@rem Convenience wrapper that runs specified gRPC target using msbuild
+@rem Usage: build.bat TARGET_NAME
+
+setlocal
+@rem Set VS variables (uses Visual Studio 2015)
+@call "%VS140COMNTOOLS%\..\..\vc\vcvarsall.bat" x86
+
+msbuild %*
+exit /b %ERRORLEVEL%
+endlocal
diff --git a/tools/run_tests/check_submodules.sh b/test/distrib/csharp/run_distrib_test.sh
similarity index 67%
copy from tools/run_tests/check_submodules.sh
copy to test/distrib/csharp/run_distrib_test.sh
index b4ca4fa..1de6204 100755
--- a/tools/run_tests/check_submodules.sh
+++ b/test/distrib/csharp/run_distrib_test.sh
@@ -1,5 +1,4 @@
-#!/bin/sh
-
+#!/bin/bash
 # Copyright 2015-2016, Google Inc.
 # All rights reserved.
 #
@@ -29,26 +28,18 @@
 # (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
 
-set -e
+cd $(dirname $0)
 
-export TEST=true
+unzip -o "$EXTERNAL_GIT_ROOT/input_artifacts/csharp_nugets.zip" -d TestNugetFeed
 
-cd `dirname $0`/../..
+# Extract the version number from Grpc nuget package name.
+CSHARP_VERSION=$(ls TestNugetFeed | grep '^Grpc\.[0-9].*\.nupkg$' | sed s/^Grpc\.// | sed s/\.nupkg$//)
+./update_version.sh $CSHARP_VERSION
 
-submodules=`mktemp /tmp/submXXXXXX`
-want_submodules=`mktemp /tmp/submXXXXXX`
+nuget restore
 
-git submodule | awk '{ print $1 }' | sort > $submodules
-cat << EOF | awk '{ print $1 }' | sort > $want_submodules
- 9f897b25800d2f54f5c442ef01a60721aeca6d87 third_party/boringssl (version_for_cocoapods_1.0-67-g9f897b2)
- 05b155ff59114735ec8cd089f669c4c3d8f59029 third_party/gflags (v2.1.0-45-g05b155f)
- c99458533a9b4c743ed51537e25989ea55944908 third_party/googletest (release-1.7.0)
- d5fb408ddc281ffcadeb08699e65bb694656d0bd third_party/protobuf (v3.0.0-beta-2)
- 50893291621658f355bc5b4d450a8d06a563053d third_party/zlib (v1.2.8)
-EOF
+xbuild DistribTest.sln
 
-diff -u $submodules $want_submodules
-
-rm $submodules $want_submodules
-
+mono DistribTest/bin/Debug/DistribTest.exe
diff --git a/tools/run_tests/check_submodules.sh b/test/distrib/csharp/update_version.sh
similarity index 67%
copy from tools/run_tests/check_submodules.sh
copy to test/distrib/csharp/update_version.sh
index b4ca4fa..f2554e8 100755
--- a/tools/run_tests/check_submodules.sh
+++ b/test/distrib/csharp/update_version.sh
@@ -1,5 +1,4 @@
-#!/bin/sh
-
+#!/bin/bash
 # Copyright 2015-2016, Google Inc.
 # All rights reserved.
 #
@@ -29,26 +28,9 @@
 # (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 -e
 
-export TEST=true
+cd $(dirname $0)
 
-cd `dirname $0`/../..
-
-submodules=`mktemp /tmp/submXXXXXX`
-want_submodules=`mktemp /tmp/submXXXXXX`
-
-git submodule | awk '{ print $1 }' | sort > $submodules
-cat << EOF | awk '{ print $1 }' | sort > $want_submodules
- 9f897b25800d2f54f5c442ef01a60721aeca6d87 third_party/boringssl (version_for_cocoapods_1.0-67-g9f897b2)
- 05b155ff59114735ec8cd089f669c4c3d8f59029 third_party/gflags (v2.1.0-45-g05b155f)
- c99458533a9b4c743ed51537e25989ea55944908 third_party/googletest (release-1.7.0)
- d5fb408ddc281ffcadeb08699e65bb694656d0bd third_party/protobuf (v3.0.0-beta-2)
- 50893291621658f355bc5b4d450a8d06a563053d third_party/zlib (v1.2.8)
-EOF
-
-diff -u $submodules $want_submodules
-
-rm $submodules $want_submodules
-
+# Replaces version placeholder with value provided as first argument.
+sed -ibak "s/__GRPC_NUGET_VERSION__/$1/g" DistribTest/packages.config DistribTest/DistribTest.csproj
diff --git a/src/objective-c/GRPCClient/private/GRPCUnsecuredChannel.h b/test/distrib/node/distrib_test.js
old mode 100644
new mode 100755
similarity index 73%
copy from src/objective-c/GRPCClient/private/GRPCUnsecuredChannel.h
copy to test/distrib/node/distrib_test.js
index 8528be4..cdd8eba
--- a/src/objective-c/GRPCClient/private/GRPCUnsecuredChannel.h
+++ b/test/distrib/node/distrib_test.js
@@ -1,6 +1,7 @@
+#!/usr/bin/env node
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -31,8 +32,26 @@
  *
  */
 
-#import "GRPCChannel.h"
+var grpc = require('grpc');
 
-@interface GRPCUnsecuredChannel : GRPCChannel
-- (instancetype)initWithHost:(NSString *)host NS_DESIGNATED_INITIALIZER;
-@end
+function identity(x) {
+  return x;
+}
+
+var Client = grpc.makeGenericClientConstructor({
+  'echo' : {
+    path: '/buffer/echo',
+    requestStream: false,
+    responseStream: false,
+    requestSerialize: identity,
+    requestDeserialize: identity,
+    responseSerialize: identity,
+    responseDeserialize: identity
+  }
+});
+
+var client = new Client("localhost:1000", grpc.credentials.createInsecure());
+
+client.$channel.close();
+
+console.log("Success!");
diff --git a/test/distrib/node/package.json b/test/distrib/node/package.json
new file mode 100644
index 0000000..b02a796
--- /dev/null
+++ b/test/distrib/node/package.json
@@ -0,0 +1,7 @@
+{
+  "name": "grpc-distrib-test",
+  "version": "0.0.1",
+  "dependencies": {
+    "grpc": "*"
+  }
+}
diff --git a/tools/run_tests/check_submodules.sh b/test/distrib/node/run_distrib_test.sh
similarity index 67%
copy from tools/run_tests/check_submodules.sh
copy to test/distrib/node/run_distrib_test.sh
index b4ca4fa..99a51f0 100755
--- a/tools/run_tests/check_submodules.sh
+++ b/test/distrib/node/run_distrib_test.sh
@@ -1,5 +1,4 @@
-#!/bin/sh
-
+#!/bin/bash
 # Copyright 2015-2016, Google Inc.
 # All rights reserved.
 #
@@ -29,26 +28,27 @@
 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
+NODE_VERSION=$1
+source ~/.nvm/nvm.sh
+set -ex
 
-set -e
+cd $(dirname $0)
 
-export TEST=true
+nvm install $NODE_VERSION
 
-cd `dirname $0`/../..
+npm install -g node-static
 
-submodules=`mktemp /tmp/submXXXXXX`
-want_submodules=`mktemp /tmp/submXXXXXX`
+STATIC_SERVER=127.0.0.1
+STATIC_PORT=8080
 
-git submodule | awk '{ print $1 }' | sort > $submodules
-cat << EOF | awk '{ print $1 }' | sort > $want_submodules
- 9f897b25800d2f54f5c442ef01a60721aeca6d87 third_party/boringssl (version_for_cocoapods_1.0-67-g9f897b2)
- 05b155ff59114735ec8cd089f669c4c3d8f59029 third_party/gflags (v2.1.0-45-g05b155f)
- c99458533a9b4c743ed51537e25989ea55944908 third_party/googletest (release-1.7.0)
- d5fb408ddc281ffcadeb08699e65bb694656d0bd third_party/protobuf (v3.0.0-beta-2)
- 50893291621658f355bc5b4d450a8d06a563053d third_party/zlib (v1.2.8)
-EOF
+# Serves the input_artifacts directory statically at localhost:8080
+static "$EXTERNAL_GIT_ROOT/input_artifacts" -a $STATIC_SERVER -p $STATIC_PORT &
+STATIC_PID=$!
 
-diff -u $submodules $want_submodules
+STATIC_URL="http://$STATIC_SERVER:$STATIC_PORT/"
 
-rm $submodules $want_submodules
+npm install --unsafe-perm $STATIC_URL/grpc.tgz --grpc_node_binary_host_mirror=$STATIC_URL
 
+kill -9 $STATIC_PID
+
+./distrib_test.js
diff --git a/tools/run_tests/check_submodules.sh b/test/distrib/python/distribtest.py
old mode 100755
new mode 100644
similarity index 65%
copy from tools/run_tests/check_submodules.sh
copy to test/distrib/python/distribtest.py
index b4ca4fa..dc20688
--- a/tools/run_tests/check_submodules.sh
+++ b/test/distrib/python/distribtest.py
@@ -1,6 +1,4 @@
-#!/bin/sh
-
-# Copyright 2015-2016, Google Inc.
+# Copyright 2016, Google Inc.
 # All rights reserved.
 #
 # Redistribution and use in source and binary forms, with or without
@@ -29,26 +27,10 @@
 # (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 grpc.beta import implementations
 
-set -e
-
-export TEST=true
-
-cd `dirname $0`/../..
-
-submodules=`mktemp /tmp/submXXXXXX`
-want_submodules=`mktemp /tmp/submXXXXXX`
-
-git submodule | awk '{ print $1 }' | sort > $submodules
-cat << EOF | awk '{ print $1 }' | sort > $want_submodules
- 9f897b25800d2f54f5c442ef01a60721aeca6d87 third_party/boringssl (version_for_cocoapods_1.0-67-g9f897b2)
- 05b155ff59114735ec8cd089f669c4c3d8f59029 third_party/gflags (v2.1.0-45-g05b155f)
- c99458533a9b4c743ed51537e25989ea55944908 third_party/googletest (release-1.7.0)
- d5fb408ddc281ffcadeb08699e65bb694656d0bd third_party/protobuf (v3.0.0-beta-2)
- 50893291621658f355bc5b4d450a8d06a563053d third_party/zlib (v1.2.8)
-EOF
-
-diff -u $submodules $want_submodules
-
-rm $submodules $want_submodules
-
+# This code doesn't do much but makes sure the native extension is loaded
+# which is what we are testing here.
+channel = implementations.insecure_channel('localhost', 1000)
+del channel
+print 'Success!'
diff --git a/tools/run_tests/check_submodules.sh b/test/distrib/python/run_distrib_test.sh
similarity index 67%
copy from tools/run_tests/check_submodules.sh
copy to test/distrib/python/run_distrib_test.sh
index b4ca4fa..8fd7ffb 100755
--- a/tools/run_tests/check_submodules.sh
+++ b/test/distrib/python/run_distrib_test.sh
@@ -1,5 +1,4 @@
-#!/bin/sh
-
+#!/bin/bash
 # Copyright 2015-2016, Google Inc.
 # All rights reserved.
 #
@@ -29,26 +28,31 @@
 # (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
 
-set -e
+cd $(dirname $0)
 
-export TEST=true
+# Pick up the source dist archive whatever its version is
+SDIST_ARCHIVE=$EXTERNAL_GIT_ROOT/input_artifacts/grpcio-*.tar.gz
+BDIST_DIR="file://$EXTERNAL_GIT_ROOT/input_artifacts"
 
-cd `dirname $0`/../..
+if [ ! -f ${SDIST_ARCHIVE} ]
+then
+  echo "Archive ${SDIST_ARCHIVE} does not exist."
+  exit 1
+fi
 
-submodules=`mktemp /tmp/submXXXXXX`
-want_submodules=`mktemp /tmp/submXXXXXX`
+PIP=pip2
+which $PIP || PIP=pip
+PYTHON=python2
+which $PYTHON || PYTHON=python
 
-git submodule | awk '{ print $1 }' | sort > $submodules
-cat << EOF | awk '{ print $1 }' | sort > $want_submodules
- 9f897b25800d2f54f5c442ef01a60721aeca6d87 third_party/boringssl (version_for_cocoapods_1.0-67-g9f897b2)
- 05b155ff59114735ec8cd089f669c4c3d8f59029 third_party/gflags (v2.1.0-45-g05b155f)
- c99458533a9b4c743ed51537e25989ea55944908 third_party/googletest (release-1.7.0)
- d5fb408ddc281ffcadeb08699e65bb694656d0bd third_party/protobuf (v3.0.0-beta-2)
- 50893291621658f355bc5b4d450a8d06a563053d third_party/zlib (v1.2.8)
-EOF
+# TODO(jtattermusch): this shouldn't be required
+$PIP install --upgrade six
 
-diff -u $submodules $want_submodules
+GRPC_PYTHON_BINARIES_REPOSITORY="${BDIST_DIR}" \
+    $PIP install \
+    ${SDIST_ARCHIVE}
 
-rm $submodules $want_submodules
+$PYTHON distribtest.py
 
diff --git a/test/distrib/ruby/Gemfile b/test/distrib/ruby/Gemfile
new file mode 100644
index 0000000..96e68e9
--- /dev/null
+++ b/test/distrib/ruby/Gemfile
@@ -0,0 +1,11 @@
+# -*- ruby -*-
+# encoding: utf-8
+
+source 'https://rubygems.org/'
+
+# TODO(jtattermusch): don't hardcode the absolute path the local gem source
+source "file:///var/local/git/grpc/gem_source" do
+  gem 'grpc'
+end
+
+gemspec
diff --git a/test/distrib/ruby/distribtest.gemspec b/test/distrib/ruby/distribtest.gemspec
new file mode 100644
index 0000000..d72892f
--- /dev/null
+++ b/test/distrib/ruby/distribtest.gemspec
@@ -0,0 +1,19 @@
+# -*- ruby -*-
+# encoding: utf-8
+
+Gem::Specification.new do |s|
+  s.name          = 'distribtest'
+  s.version       = '0.0.1'
+  s.authors       = ['gRPC Authors']
+  s.email         = 'jtattermusch@google.com'
+  s.homepage      = 'https://github.com/grpc/grpc'
+  s.summary       = 'gRPC Distribution test'
+
+  s.files         = ['distribtest.rb']
+  s.executables   = ['distribtest.rb']
+  s.platform      = Gem::Platform::RUBY
+
+  s.add_dependency 'grpc', '>=0'
+
+  s.add_development_dependency 'bundler', '~> 1.7'
+end
diff --git a/tools/run_tests/check_submodules.sh b/test/distrib/ruby/distribtest.rb
similarity index 65%
copy from tools/run_tests/check_submodules.sh
copy to test/distrib/ruby/distribtest.rb
index b4ca4fa..3f656a8 100755
--- a/tools/run_tests/check_submodules.sh
+++ b/test/distrib/ruby/distribtest.rb
@@ -1,6 +1,6 @@
-#!/bin/sh
+#!/usr/bin/env ruby
 
-# Copyright 2015-2016, Google Inc.
+# Copyright 2016, Google Inc.
 # All rights reserved.
 #
 # Redistribution and use in source and binary forms, with or without
@@ -29,26 +29,11 @@
 # (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 'grpc'
 
-set -e
+# This code doesn't do much but makes sure the native extension is loaded
+# which is what we are testing here.
+ch = GRPC::Core::Channel.new('localhost:1000', nil, :this_channel_is_insecure)
+ch.destroy
 
-export TEST=true
-
-cd `dirname $0`/../..
-
-submodules=`mktemp /tmp/submXXXXXX`
-want_submodules=`mktemp /tmp/submXXXXXX`
-
-git submodule | awk '{ print $1 }' | sort > $submodules
-cat << EOF | awk '{ print $1 }' | sort > $want_submodules
- 9f897b25800d2f54f5c442ef01a60721aeca6d87 third_party/boringssl (version_for_cocoapods_1.0-67-g9f897b2)
- 05b155ff59114735ec8cd089f669c4c3d8f59029 third_party/gflags (v2.1.0-45-g05b155f)
- c99458533a9b4c743ed51537e25989ea55944908 third_party/googletest (release-1.7.0)
- d5fb408ddc281ffcadeb08699e65bb694656d0bd third_party/protobuf (v3.0.0-beta-2)
- 50893291621658f355bc5b4d450a8d06a563053d third_party/zlib (v1.2.8)
-EOF
-
-diff -u $submodules $want_submodules
-
-rm $submodules $want_submodules
-
+puts "Success!"
diff --git a/tools/run_tests/check_submodules.sh b/test/distrib/ruby/run_distrib_test.sh
similarity index 66%
copy from tools/run_tests/check_submodules.sh
copy to test/distrib/ruby/run_distrib_test.sh
index b4ca4fa..be60e44 100755
--- a/tools/run_tests/check_submodules.sh
+++ b/test/distrib/ruby/run_distrib_test.sh
@@ -1,5 +1,4 @@
-#!/bin/sh
-
+#!/bin/bash
 # Copyright 2015-2016, Google Inc.
 # All rights reserved.
 #
@@ -29,26 +28,17 @@
 # (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
 
-set -e
+cd $(dirname $0)
 
-export TEST=true
+# Create an indexed local gem source with gRPC gems to test
+GEM_SOURCE=../../../gem_source
+mkdir -p ${GEM_SOURCE}/gems
+cp -r $EXTERNAL_GIT_ROOT/input_artifacts/*.gem ${GEM_SOURCE}/gems
+gem install builder
+gem generate_index --directory ${GEM_SOURCE}
 
-cd `dirname $0`/../..
+bundle install
 
-submodules=`mktemp /tmp/submXXXXXX`
-want_submodules=`mktemp /tmp/submXXXXXX`
-
-git submodule | awk '{ print $1 }' | sort > $submodules
-cat << EOF | awk '{ print $1 }' | sort > $want_submodules
- 9f897b25800d2f54f5c442ef01a60721aeca6d87 third_party/boringssl (version_for_cocoapods_1.0-67-g9f897b2)
- 05b155ff59114735ec8cd089f669c4c3d8f59029 third_party/gflags (v2.1.0-45-g05b155f)
- c99458533a9b4c743ed51537e25989ea55944908 third_party/googletest (release-1.7.0)
- d5fb408ddc281ffcadeb08699e65bb694656d0bd third_party/protobuf (v3.0.0-beta-2)
- 50893291621658f355bc5b4d450a8d06a563053d third_party/zlib (v1.2.8)
-EOF
-
-diff -u $submodules $want_submodules
-
-rm $submodules $want_submodules
-
+bundle exec ./distribtest.rb
diff --git a/third_party/rake-compiler-dock/Dockerfile b/third_party/rake-compiler-dock/Dockerfile
new file mode 100644
index 0000000..c7a6657
--- /dev/null
+++ b/third_party/rake-compiler-dock/Dockerfile
@@ -0,0 +1,201 @@
+FROM ubuntu:14.04
+
+RUN apt-get -y update && \
+    apt-get install -y curl git-core mingw-w64 xz-utils build-essential gcc-multilib wget unzip
+
+RUN mkdir -p /opt/mingw && \
+    curl -SL http://downloads.sourceforge.net/mingw-w64/i686-w64-mingw32-gcc-4.7.2-release-linux64_rubenvb.tar.xz | \
+    tar -xJC /opt/mingw && \
+    echo "export PATH=\$PATH:/opt/mingw/mingw32/bin" >> /etc/rubybashrc
+
+RUN mkdir -p /opt/mingw && \
+    curl -SL http://downloads.sourceforge.net/mingw-w64/x86_64-w64-mingw32-gcc-4.7.2-release-linux64_rubenvb.tar.xz | \
+    tar -xJC /opt/mingw && \
+    echo "export PATH=\$PATH:/opt/mingw/mingw64/bin" >> /etc/rubybashrc
+
+# Add "rvm" as system group, to avoid conflicts with host GIDs typically starting with 1000
+RUN groupadd -r rvm && useradd -r -g rvm -G sudo -p "" --create-home rvm && \
+    echo "source /etc/profile.d/rvm.sh" >> /etc/rubybashrc
+USER rvm
+
+# install rvm, RVM 1.26.0+ has signed releases, source rvm for usage outside of package scripts
+RUN gpg --keyserver hkp://keys.gnupg.net --recv-keys D39DC0E3 && \
+    (curl -L http://get.rvm.io | sudo bash -s stable) && \
+    bash -c " \
+        source /etc/rubybashrc && \
+        rvmsudo rvm cleanup all "
+
+# Regenerate the following using build.sh if the build folder changes.
+RUN echo \
+H4sIAJSZulYAA+07a1fbSLL5evUragxnbAdLtvwEApnJAMmwN68DJHPvGbLattSyNZYlbXfLhpuw\
+v/1WtSS/gBB2EnZn1n3AbvWjqrqqurqq1O6nQejVH33T0sDS63Xo2+51GovfRXlkN7uddrPd67a7\
+jxq23Wy2HkHn25KVlVQqJgAeJcEFDz8z7q7+P2jpa/nLYOBPLfcb4SABd7vt2+Rvd5ur8m92Gp1H\
+0PhG9CyV/3D51x8b8BjOhoGERMQDwcYwZJEXcgmnxy+OX58BPoEfiykTnoRAgYqxKVZDLmiGy6W0\
+CMSxAoQRRIpHHvdoVJ+DSCNgEt4eH4JNo2jgYeyOcC6xXckCBKKbBmoIJS/rxYmlpZnwJoKXQZRe\
+1ABRg8d9loYKUHEjFuYkC6IzmwLYHguEyqLLfFBG5hnSzXEYhwMlQvMA2IgVKyX69TQPEgSW46Bp\
+dcPYCCI3TD0Oexk4a/h0se1S1tVlwuX15ikLFLUayBtIAg/2ofHEMCZx4BkZ3Q5CpM4KfRD0dFw1\
+PhoAgV/BCVWsAYyCMKSnWk5t9YlxlcEcsyDSU5kYuDVwh6jPj7E++fVDlaBIJVJXA2auCuIIIj51\
+suoTQkJIFVOpRMpMG0kDqD+GU64gTTSzMwAp8gylKhPuBv6l7kBAkAGyiEewANmSzCmksg9L6ySk\
+WOPjRF1KxFL5fnnamMlR9ck1aH7IBjJnHiysppLxowYLYGpQIf4+rjaqenTGdhT7qKIh54z9qDlL\
+Aqp8n7FA9wIIjsuN4Jej/zk+Oz17dvbutLLQf8VDybO5M8bxC+5Okopmu/0BiclrOUDUJxGLSomG\
+lZaRZCA0XJToQ+//zP4nTLlDLr+RH3D/8x8fmuvz/yHKsvxF2r80bWvb6plJq9f+Svpwf/m3e73e\
+Wv4PUT4v/yhOLN33u3Dc4f817Ia9Iv9ut9Fe+38PUbzA98E0B+jYsbobR34woIO+P6+jj+HxC+h0\
+7E6P+ZbV7bYavM/Axk3d6Tz4gbUuX7XcsP+bVstqfE1X4J+w/82evbb/D1FulX8UOxJDOT8I+e89\
+Au6y/+1ua0X+vW6jubb/D1G+2P7zPm95265lsVar2++1CvtvmubiTGNra2tp9o8/YlC5vdNu1Xqw\
+lVW6gI1eDLsUBjHX8SPHdVD/3JHjp5ELpc2Xx6+PXr8pQalQQaziQHeiB8wUs2RgJAeKSwWli82b\
+BmBkdnHJ5RMKV6MMocsUPH1KBGKAj/E67O05zw6O3jw3zA1sCSIOPz97f+ScHr0+fH788ghsA/IB\
+YIAf/LlOvBv9vx2r9S+2/63G2v4/SLlV/g9n/+2m3b5u/9f53wcpX2z/t3e2e60G2n/X591m5372\
+v93d6Wj7n1ewkVK1ZPvJ4AcR+OPY0znOZKATcm39SXk7ytqBTNg0moC8lC4LQ3CcouYORRwrGHAD\
+/gt0kVxJnKZ4GHqBwEc+om/fHRIKN5ZDkEE0BMXwI4wHTRBxGnnniwBSBIBfA/zyGB/HET6F3FVO\
+yMSAO75HeUv850hTGmWVcwOWy3ikgjEH+hiMYTCmiiPADWM86AZc6d78O/Y9dglJjCtK6PPcMJeB\
+JYIzoinbkSCHqfLiaaTzoKFCHXZH4IVOoLhgijvJ0BPG1o0gvmTm/HSWDgppwsT+3zaxzt1hvHQS\
+b+YiLMEnoAFKOHL4N+OOU30+q7Q5w1D6cx2sf5DyGfv/NVI/uvwT+R+70V3b/4co6/zPf3ZZ2f9s\
+xE03Hid4xgizgYag8xUCgS/1/7sd9A8aPdr/jfY6//8g5W7503v5OFUmv1DSInNxbxx32f9es7ls\
+/5t2q7fO/zxIWbL/ismRrPeDqO6KWEqT3AGLdALPg1v78vOhy1x32+7i+cBYk7V36Hzottt5fHD7\
+7CxeuL1fxw+tTm0bo4dWETuQC1za+Pju9OjE+fnNq6OrutZjWd/4+Or49YtfsPH07AqfTt799L/O\
+wYHz/ujk9PjN66v6K4SZZ4aewq85jMxzL5mmhrKfT/vp3fHLw6tSLestmyaPWD/kphwywb3yvN0L\
+pO4IItSlMDS92MVeM+8t9o8a3dTohuXMT88baZvtlwn0B7q4ABvwPBYuh18QOMYNTR03nSB3wLa2\
+a/ixU9xTkXQ7I1D3PJDv3v/0yFRGXD/VNzruaQZu2P9YaT0qvL9Oq7ts/5vNnt37N9v/2cWkh6Do\
+QctzEY+hbfvbrXa7veO77Vaz1W/6Ozsdvt2zO4x1tttNb8f3dlqtNrzCSPiUJ2D3oNHY1X/QRBEa\
+BGYXXjIh4b9ZFEjYw0hZ/jgQPPg/Ez8i6cXCtzz+1DjEKHMXTpmqQasBf2ERQrC70Njepb8ebKFG\
+NIzTtP8bBty78OvbZ2cHP3+AgyGLBlxfO/LJIo0xFiVM4/yqWaamAe7D7CZZoaqGcYZTMPadBHEq\
+V+dOYzHiHuB2GsbxKIgGEEcID7EYJcH/ngboC5dFP3OGyyWgnINl6Oty2Y05xDdGtC6S4LJU8gKv\
+vgknIhx+CTkgCQWgGo5SGGNzGZWVQTQg+UJwhYODCJim0gMeTQIRR2MeKcs4VlkO22dBqLd6GGM0\
+P+BjfBgyuvzFgYUyhoQJBbGf39xikceEB2HQF0xc1rCCNvU3iXKke30CtTpfDtKnjQjiD6RMkVoa\
+CkOlErlbr+MBMUz7FnJ52UismAzaJfVsfn07Y/0KxxFVFE/plhqKU98TJM7P2A5zto9Hop+zvGZM\
+h4E7pMnqMglczdbFhaLVJNbqk6Gmlxbo+4hTuu43UxoPkpAptKBjY8JCWqPmmqtSDTDi3OMe8QP5\
+OWWXOQxiNE5lPgq0EG+dkkRJDWSccZ8w5DxGutRQQzYoS4THYiw80qx8gS/4WCdVKQ1UKxoj1KEJ\
+z2445oACLlFP9F1FY6b1CypBpNFttwlHHX8bcobKF8WK1+YUaeMOHnLTVTFShsxiMMAZESmOXq8s\
+tg8CwFOthqc5IL24Umwf6DuAHm5YL0NPhEsLTmNKEDGUFe6+cQLJaACm8EsWnfYG0a/Voo5S4ZEM\
+ULZ4vFuiD5+g1YGtpWLeVAyws0M+VxM86NqomZILut0nK1vVGjRtPPlCnjWYVcNYcmVup6F/e1/u\
+yjRaDebvoCvj79jtHXvFlbl9dubK3N6vXZnujnZl9Bc2/IVNGMxGgkSvAEXW1xbL52gTUB9nGbwN\
+vXWY5y3pvHRFkKj5KHfswd4esL508iGW4KFWMId00/HRWFeoG2WnW6oGzPONGzMzRdyaBmGYkyO1\
+0vkw5XrbaEcNsp2P6j0HQK/kLByvN7IMFGpMfiH2hwo6XAXSq/oCnlJVW7d5ynJDK9z9KNi6NwU5\
+jgL7QrI0TrRiWUkqh5XHGpOTUevkXRVtS6rV+SweechIknKr26m1dmBLfzfuKecNyF9DZitj+par\
+dpC185etujBk3xWzsjlObokdPb6CI5xiZA3IqXYmXCyIe4N2GKXfM0bUlmRPZnQ8GvtUR2tQuM5o\
+FiLKFSNZBctXwHzJzJzswpWfy+Sah35dXLXV7Pht5VZ1q60m678IQr6k0oclBsZJdhtaL4X2ln6a\
+xzF4gLjZms3b1rxIml520eDQ2A9kbT+pTwvcLnAW4z6Ll8Qxn0sywJOTz4RFSkW2E7cLbi89E5WE\
+1FQWs65TXIjiM9TOePicjrs44VFFWREb4wlVnparepj/aVGUvjUVuFsXfIAcTfk8Oo9Kiy80iqE0\
+wBH92zX9+hRNDr0LqawaCT8QUq1u6IXqfIdqAZA6ZIy/SdgF1musK7RIs44eltk244ebXLNimkA8\
+4DUblyxusWLYgxIGhSX4/vu8srcPOpzNQ+BFft8gGLGlbhQNkhPTbzsU3aPX3JtL4/Py3boJxJ0y\
+uD7Lkmn/u0r9r5WZclQLvauUq5t1xHp+bpM+nJ83y0sQ7sWfxTVfw5219pHyEVTPH1eK2HuGH3Fn\
+SyhX74aU/wLg9wLS/uS5VU0EBh0VKDL3Wg3PK1K4dMYEF+fVGfAkVTLj0pKISbBT9IFWW7N9kyNe\
+7VQijVDleQWrPAyXqOWLsBYedHVuQu9lkm41ojOTtLqR7m1/7jIqN9ihgjlLS1+sar+gvaMTWe3t\
+bs2+r1tAjCq5LEIfP4v9ZIoRkWYD+qUotlazji5SHE5KFPZEefSS7xYMARnFL3G0BPCUZ1Hj7k2B\
+nvpNusMUA7qVGI9PzH58UYR5nTm8ecSs6SjPGXU9lp5bU1TpkKFL80ZH/IvMFXwcT8iniaSC3ZP+\
+gZ66qGArI2gfv3357Oz5m5NXdwy7YbvfMOrw6PTg5PjtGY4kK5I5Wd4PldVO3EgmGE2rYzUs2kHx\
+VFq28Qd4OZb//jP1Ytxf3wjHXfn/ZqN77fc/rca/Wf7vT5r/PyySxzNbNXFGnCewtQ8lsglOIuKL\
+y8w85HV/1npycKhT7c7Szltpzneabj1+9ezFEaxk5dc3P/51Jd//SgSJMxUsSb5BjvuO97+2bfdW\
+7382Ouv3fw9SNr6rp1LoN290mY18HMNAv4AUInMu0C2hmCZEpyz0dGJbKrpIppOJ7wNByVN0ByB7\
+LZaPQhAY9+vMNtPX6zA2RWeknw7mnsZ0OrUms/lWLAZ1Fbgjrurb7W7LMGY+g+LjhEgpz5voMVVB\
+KMuGoZUXYwp0BrWn12eSk5tX2WxUryxcWckwdOISxzw7efEenVxyND6i8wf+/j/qfzXrcGWNWaI9\
+QiYGFLpSWnMfznLMFv3SuawRlbNOyw1jyY3MuXxHlFgYr+Hkmu4ljxQ7f8V6jVo/GOQEGnnqqCAk\
+u1S4TAhs5VlWJOjjJ1WLP1EUiODgyjDSCHskXYNEnlRAE1SDxwVY8r35Bfp9drOnEbqxxxHZ5g8W\
+NWe/NM6ZYXGG7qN2lYnGWAR63fPliLFuXF1isbpsSrYsjZNwrQ35H61k9h9DOPatvL+77/+026v3\
+/5qtxtr/e5CC9p9sP9rMoWEM0FQn9HrBHEBp88XxIV3QfXHy5t3bkjHWt6jNBOpoAerDeMyNVHKx\
+PNpMsfZO116AmIxrFFjQpBK29OdTwRzTwNOjE7TNdIFjf7NCJMDe3h6U9C3jf2TdVSOMwJSgTyl9\
+Di1HowiG5pfq1lIzngoac1qgwRhZcmVq5NlN7Z+enf7sHL1+v1/nytU3X4kC4ebdGM+VNn9cu6br\
+si7rsi7r8qcs/w8AInVFAFAAAA==\
+| base64 -d | tar xzC /tmp
+
+# Import patch files for ruby and gems
+RUN cp -r /tmp/build/patches /home/rvm/patches/
+ENV BASH_ENV /etc/rubybashrc
+
+# install rubies and fix permissions on
+RUN bash -c " \
+    export CFLAGS='-s -O3 -fno-fast-math -fPIC' && \
+    for v in 2.3.0 ; do \
+        rvm install \$v --patch \$(echo ~/patches/ruby-\$v/* | tr ' ' ','); \
+    done && \
+    rvm cleanup all && \
+    find /usr/local/rvm -type d -print0 | sudo xargs -0 chmod g+sw "
+
+# Install rake-compiler and typical gems in all Rubies
+# do not generate documentation for gems
+RUN echo "gem: --no-ri --no-rdoc" >> ~/.gemrc && \
+    bash -c " \
+        rvm all do gem install bundler rake-compiler hoe mini_portile rubygems-tasks && \
+        rvm 2.3.0 do gem install mini_portile2 && \
+        find /usr/local/rvm -type d -print0 | sudo xargs -0 chmod g+sw "
+
+# Install rake-compiler's cross rubies in global dir instead of /root
+RUN sudo mkdir -p /usr/local/rake-compiler && \
+    sudo chown rvm.rvm /usr/local/rake-compiler && \
+    ln -s /usr/local/rake-compiler ~/.rake-compiler
+
+# Patch rake-compiler to avoid build of ruby extensions
+RUN cd /usr/local/rvm/gems/ruby-2.3.0/gems/rake-compiler-0.9.5 && git apply /home/rvm/patches/rake-compiler-0.9.5/*.diff ; \
+    true
+
+RUN bash -c "rvm use 2.3.0 --default && \
+    export MAKE=\"make -j`nproc`\" CFLAGS='-s -O1 -fno-omit-frame-pointer -fno-fast-math' && \
+    rake-compiler cross-ruby VERSION=2.3.0 HOST=i686-w64-mingw32 && \
+    rake-compiler cross-ruby VERSION=2.3.0 HOST=x86_64-w64-mingw32 && \
+    rake-compiler cross-ruby VERSION=2.3.0 HOST=x86_64-linux-gnu && \
+    rake-compiler cross-ruby VERSION=2.2.2 HOST=i686-w64-mingw32 && \
+    rake-compiler cross-ruby VERSION=2.2.2 HOST=x86_64-w64-mingw32 && \
+    rake-compiler cross-ruby VERSION=2.2.2 HOST=x86_64-linux-gnu && \
+    rake-compiler cross-ruby VERSION=2.1.5 HOST=i686-w64-mingw32 && \
+    rake-compiler cross-ruby VERSION=2.1.5 HOST=x86_64-w64-mingw32 && \
+    rake-compiler cross-ruby VERSION=2.1.5 HOST=x86_64-linux-gnu && \
+    rake-compiler cross-ruby VERSION=2.0.0-p645 HOST=i686-w64-mingw32 && \
+    rake-compiler cross-ruby VERSION=2.0.0-p645 HOST=x86_64-w64-mingw32 && \
+    rake-compiler cross-ruby VERSION=2.0.0-p645 HOST=x86_64-linux-gnu && \
+    rm -rf ~/.rake-compiler/tmp/builds ~/.rake-compiler/sources && \
+    find /usr/local/rvm -type d -print0 | sudo xargs -0 chmod g+sw "
+
+RUN bash -c "rvm use 2.3.0 --default && \
+    export MAKE=\"make -j`nproc`\" CFLAGS='-m32 -s -O1 -fno-omit-frame-pointer -fno-fast-math' LDFLAGS='-m32' && \
+    rake-compiler cross-ruby VERSION=2.3.0 HOST=i686-linux-gnu && \
+    rake-compiler cross-ruby VERSION=2.2.2 HOST=i686-linux-gnu && \
+    rake-compiler cross-ruby VERSION=2.1.5 HOST=i686-linux-gnu && \
+    rake-compiler cross-ruby VERSION=2.0.0-p645 HOST=i686-linux-gnu && \
+    rm -rf ~/.rake-compiler/tmp/builds ~/.rake-compiler/sources && \
+    find /usr/local/rvm -type d -print0 | sudo xargs -0 chmod g+sw "
+
+RUN bash -c " \
+    rvm alias create 2.3 2.3.0 "
+
+USER root
+
+# Fix paths in rake-compiler/config.yml and add rvm and mingw-tools to the global bashrc
+RUN sed -i -- "s:/root/.rake-compiler:/usr/local/rake-compiler:g" /usr/local/rake-compiler/config.yml && \
+    echo "source /etc/profile.d/rvm.sh" >> /etc/bash.bashrc && \
+    echo "export PATH=\$PATH:/opt/mingw/mingw32/bin" >> /etc/bash.bashrc && \
+    echo "export PATH=\$PATH:/opt/mingw/mingw64/bin" >> /etc/bash.bashrc
+
+# Install wrappers for strip commands as a workaround for "Protocol error" in boot2docker.
+RUN cp /tmp/build/strip_wrapper /root/
+RUN mv /opt/mingw/mingw32/bin/i686-w64-mingw32-strip /opt/mingw/mingw32/bin/i686-w64-mingw32-strip.bin && \
+    mv /opt/mingw/mingw64/bin/x86_64-w64-mingw32-strip /opt/mingw/mingw64/bin/x86_64-w64-mingw32-strip.bin && \
+    mv /usr/bin/i686-w64-mingw32-strip /usr/bin/i686-w64-mingw32-strip.bin && \
+    mv /usr/bin/x86_64-w64-mingw32-strip /usr/bin/x86_64-w64-mingw32-strip.bin && \
+    ln /root/strip_wrapper /opt/mingw/mingw32/bin/i686-w64-mingw32-strip && \
+    ln /root/strip_wrapper /opt/mingw/mingw64/bin/x86_64-w64-mingw32-strip && \
+    ln /root/strip_wrapper /usr/bin/i686-w64-mingw32-strip && \
+    ln /root/strip_wrapper /usr/bin/x86_64-w64-mingw32-strip
+
+RUN find / -name rbconfig.rb | while read f ; do sed -i 's/0x0501/0x0600/' $f ; done
+RUN find / -name win32.h | while read f ; do sed -i 's/gettimeofday/rb_gettimeofday/' $f ; done
+RUN sed -i 's/defined.__MINGW64__.$/1/' /usr/local/rake-compiler/ruby/i686-w64-mingw32/ruby-2.0.0-p645/include/ruby-2.0.0/ruby/win32.h
+RUN find / -name libwinpthread.dll.a | xargs rm
+RUN find / -name libwinpthread-1.dll | xargs rm
+RUN find / -name *msvcrt-ruby*.dll.a | while read f ; do n=`echo $f | sed s/.dll//` ; mv $f $n ; done
+RUN find /usr/local/rake-compiler/ruby -name libruby.so | xargs rm
+RUN find /usr/local/rake-compiler/ruby -name libruby-static.a | while read f ; do ar t $f | xargs ar d $f ; done
+RUN find /usr/local/rake-compiler/ruby -name libruby-static.a | while read f ; do mv $f `echo $f | sed s/-static//` ; done
+
+# Install SIGINT forwarder
+RUN cp /tmp/build/sigfw.c /root/
+RUN gcc $HOME/sigfw.c -o /usr/local/bin/sigfw
+
+# Install user mapper
+RUN cp /tmp/build/runas /usr/local/bin/
+
+# Install sudoers configuration
+RUN cp /tmp/build/sudoers /etc/sudoers.d/rake-compiler-dock
+
+ENV RUBY_CC_VERSION 2.3.0:2.2.2:2.1.5:2.0.0
+
+CMD bash
diff --git a/third_party/rake-compiler-dock/LICENSE.txt b/third_party/rake-compiler-dock/LICENSE.txt
new file mode 100644
index 0000000..b884ba5
--- /dev/null
+++ b/third_party/rake-compiler-dock/LICENSE.txt
@@ -0,0 +1,22 @@
+Copyright (c) 2015 Lars Kanis
+
+MIT License
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/third_party/rake-compiler-dock/README.md b/third_party/rake-compiler-dock/README.md
new file mode 100644
index 0000000..0a9aa8b
--- /dev/null
+++ b/third_party/rake-compiler-dock/README.md
@@ -0,0 +1 @@
+This is a modified Dockerfile taken from [rake-compiler-dock](https://github.com/rake-compiler/rake-compiler-dock) for the purpose of building gRPC's ruby gem.
diff --git a/third_party/rake-compiler-dock/build.sh b/third_party/rake-compiler-dock/build.sh
new file mode 100755
index 0000000..ca01fa6
--- /dev/null
+++ b/third_party/rake-compiler-dock/build.sh
@@ -0,0 +1,7 @@
+#!/bin/sh
+
+# Run this to produce the snipplet of data to insert in the Dockerfile.
+
+echo 'RUN echo \\'
+tar cz build | base64 | sed 's/$/\\/'
+echo '| base64 -d | tar xzC /tmp'
diff --git a/third_party/rake-compiler-dock/build/patches/rake-compiler-0.9.5/compat-with-bundler.diff b/third_party/rake-compiler-dock/build/patches/rake-compiler-0.9.5/compat-with-bundler.diff
new file mode 100644
index 0000000..ea22bd9
--- /dev/null
+++ b/third_party/rake-compiler-dock/build/patches/rake-compiler-0.9.5/compat-with-bundler.diff
@@ -0,0 +1,105 @@
+From 41f834449fc4323b2f995e8715aa5842d9fd9334 Mon Sep 17 00:00:00 2001
+From: Lars Kanis <lars@greiz-reinsdorf.de>
+Date: Sat, 30 Jan 2016 08:08:07 +0100
+Subject: [PATCH] Change the fake mechanism to be compatible with bundler.
+
+The previous fake mechanism worked by hooking onto the
+"require 'rbconfig'" call.
+This is problematic because bundler internally requires rbconfig, but doesn't
+work corretly in a faked environment.
+It then fails to load gems that are also part of the standard library, like
+json and rdoc.
+This results in issues like https://github.com/rake-compiler/rake-compiler-dock/issues/8
+
+The fake mechanism is now changed to hook onto the "require 'mkrb'" call,
+which is typically part of the extconf file, and it is where the faked platform
+values are actually needed.
+That way it is loaded after bundler/setup, so that the library paths are
+set according to the Gemfile.lock, to the native Linux libraries, before
+the fake environment is active.
+
+Please note, that the build directory of a given gem needs to be cleared,
+in order to get updated fake files. So do a "rm tmp pkg -rf".
+---
+ lib/rake/extensiontask.rb | 35 ++++++++++++++---------------------
+ 1 file changed, 14 insertions(+), 21 deletions(-)
+
+diff --git a/lib/rake/extensiontask.rb b/lib/rake/extensiontask.rb
+index 030af96..f914919 100644
+--- a/lib/rake/extensiontask.rb
++++ b/lib/rake/extensiontask.rb
+@@ -169,8 +169,8 @@ Java extension should be preferred.
+         # now add the extconf script
+         cmd << abs_extconf.relative_path_from(abs_tmp_path)
+ 
+-        # rbconfig.rb will be present if we are cross compiling
+-        if t.prerequisites.include?("#{tmp_path}/rbconfig.rb") then
++        # fake.rb will be present if we are cross compiling
++        if t.prerequisites.include?("#{tmp_path}/fake.rb") then
+           options.push(*cross_config_options(platf))
+         end
+ 
+@@ -365,39 +365,30 @@ Java extension should be preferred.
+       # define compilation tasks for cross platform!
+       define_compile_tasks(for_platform, ruby_ver)
+ 
+-      # chain fake.rb, rbconfig.rb and mkmf.rb to Makefile generation
++      # chain fake.rb and mkmf.rb to Makefile generation
+       file "#{tmp_path}/Makefile" => ["#{tmp_path}/fake.rb",
+-                                      "#{tmp_path}/rbconfig.rb",
+                                       "#{tmp_path}/mkmf.rb"]
+ 
+-      # copy the file from the cross-ruby location
+-      file "#{tmp_path}/rbconfig.rb" => [rbconfig_file] do |t|
++      # copy the rbconfig from the cross-ruby location and
++      # genearte fake.rb for different ruby versions
++      file "#{tmp_path}/fake.rb" => [rbconfig_file] do |t|
+         File.open(t.name, 'w') do |f|
+-          f.write "require 'fake.rb'\n\n"
++          f.write fake_rb(for_platform, ruby_ver)
+           f.write File.read(t.prerequisites.first)
+         end
+       end
+ 
+       # copy mkmf from cross-ruby location
+       file "#{tmp_path}/mkmf.rb" => [mkmf_file] do |t|
+-        cp t.prerequisites.first, t.name
+-        if ruby_ver < "1.9" && "1.9" <= RUBY_VERSION
+-          File.open(t.name, 'r+t') do |f|
+-            content = f.read
++        File.open(t.name, 'w') do |f|
++          content = File.read(t.prerequisites.first)
++          content.sub!(/^(require ')rbconfig(')$/, '\\1fake\\2')
++          if ruby_ver < "1.9" && "1.9" <= RUBY_VERSION
+             content.sub!(/^(      break )\*(defaults)$/, '\\1\\2.first')
+             content.sub!(/^(    return )\*(defaults)$/, '\\1\\2.first')
+             content.sub!(/^(  mfile\.)print( configuration\(srcprefix\))$/, '\\1puts\\2')
+-            f.rewind
+-            f.write content
+-            f.truncate(f.tell)
+           end
+-        end
+-      end
+-
+-      # genearte fake.rb for different ruby versions
+-      file "#{tmp_path}/fake.rb" do |t|
+-        File.open(t.name, 'w') do |f|
+-          f.write fake_rb(for_platform, ruby_ver)
++          f.write content
+         end
+       end
+ 
+@@ -495,8 +486,10 @@ Java extension should be preferred.
+         # "cannot load such file -- win32/resolv" when it is required later on.
+         # See also: https://github.com/tjschuck/rake-compiler-dev-box/issues/5
+         require 'resolv'
++        require 'rbconfig'
+ 
+         class Object
++          remove_const :RbConfig
+           remove_const :RUBY_PLATFORM
+           remove_const :RUBY_VERSION
+           remove_const :RUBY_DESCRIPTION if defined?(RUBY_DESCRIPTION)
+-- 
+2.5.0.windows.1
+
diff --git a/third_party/rake-compiler-dock/build/patches/rake-compiler-0.9.5/without-exts.diff b/third_party/rake-compiler-dock/build/patches/rake-compiler-0.9.5/without-exts.diff
new file mode 100644
index 0000000..07739d3
--- /dev/null
+++ b/third_party/rake-compiler-dock/build/patches/rake-compiler-0.9.5/without-exts.diff
@@ -0,0 +1,14 @@
+diff --git a/tasks/bin/cross-ruby.rake b/tasks/bin/cross-ruby.rake
+index 6acc816..6aa2a49 100644
+--- a/tasks/bin/cross-ruby.rake
++++ b/tasks/bin/cross-ruby.rake
+@@ -135,8 +135,7 @@ file "#{USER_HOME}/builds/#{MINGW_HOST}/#{RUBY_CC_VERSION}/Makefile" => ["#{USER
+     "--build=#{RUBY_BUILD}",
+     '--enable-shared',
+     '--disable-install-doc',
+-    '--without-tk',
+-    '--without-tcl'
++    '--with-ext='
+   ]
+
+   # Force Winsock2 for Ruby 1.8, 1.9 defaults to it
diff --git a/third_party/rake-compiler-dock/build/patches/ruby-1.8.7-p374/nop.patch b/third_party/rake-compiler-dock/build/patches/ruby-1.8.7-p374/nop.patch
new file mode 100644
index 0000000..fac8525
--- /dev/null
+++ b/third_party/rake-compiler-dock/build/patches/ruby-1.8.7-p374/nop.patch
@@ -0,0 +1,2 @@
+diff --git a/configure b/configure
+index 55157af..6630eba 100755
diff --git a/third_party/rake-compiler-dock/build/patches/ruby-1.9.3/no_sendfile.patch b/third_party/rake-compiler-dock/build/patches/ruby-1.9.3/no_sendfile.patch
new file mode 100644
index 0000000..d8f339e
--- /dev/null
+++ b/third_party/rake-compiler-dock/build/patches/ruby-1.9.3/no_sendfile.patch
@@ -0,0 +1,13 @@
+diff --git a/configure b/configure
+index 898730c..cfe6253 100755
+--- a/configure
++++ b/configure
+@@ -14695,7 +14695,7 @@ for ac_func in fmod killpg wait4 waitpid fork spawnv syscall __syscall chroot ge
+ 	      setsid telldir seekdir fchmod cosh sinh tanh log2 round\
+ 	      setuid setgid daemon select_large_fdset setenv unsetenv\
+               mktime timegm gmtime_r clock_gettime gettimeofday poll ppoll\
+-              pread sendfile shutdown sigaltstack dl_iterate_phdr
++              pread shutdown sigaltstack dl_iterate_phdr
+ do :
+   as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh`
+ ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var"
diff --git a/third_party/rake-compiler-dock/build/patches/ruby-1.9.3/nop.patch b/third_party/rake-compiler-dock/build/patches/ruby-1.9.3/nop.patch
new file mode 100644
index 0000000..fac8525
--- /dev/null
+++ b/third_party/rake-compiler-dock/build/patches/ruby-1.9.3/nop.patch
@@ -0,0 +1,2 @@
+diff --git a/configure b/configure
+index 55157af..6630eba 100755
diff --git a/third_party/rake-compiler-dock/build/patches/ruby-2.3.0/no_sendfile.patch b/third_party/rake-compiler-dock/build/patches/ruby-2.3.0/no_sendfile.patch
new file mode 100644
index 0000000..915fc7b
--- /dev/null
+++ b/third_party/rake-compiler-dock/build/patches/ruby-2.3.0/no_sendfile.patch
@@ -0,0 +1,12 @@
+diff --git a/configure b/configure
+index ebe3d8c..a336b73 100755
+--- a/configure
++++ b/configure
+@@ -18943,7 +18943,6 @@ do :
+   ac_fn_c_check_func "$LINENO" "sendfile" "ac_cv_func_sendfile"
+ if test "x$ac_cv_func_sendfile" = xyes; then :
+   cat >>confdefs.h <<_ACEOF
+-#define HAVE_SENDFILE 1
+ _ACEOF
+ 
+ fi
diff --git a/third_party/rake-compiler-dock/build/runas b/third_party/rake-compiler-dock/build/runas
new file mode 100755
index 0000000..b29ce31
--- /dev/null
+++ b/third_party/rake-compiler-dock/build/runas
@@ -0,0 +1,12 @@
+#!/bin/bash
+
+groupadd -g "$GID" "$GROUP"
+mkdir -p /tmp/home
+useradd -g "$GID" -u "$UID" -G rvm,sudo -p "" -b /tmp/home -m "$USER"
+
+HOME=$(bash <<< "echo ~$USER")
+ln -s /usr/local/rake-compiler "$HOME"/.rake-compiler
+
+sudo -u "$USER" --set-home \
+    BASH_ENV=/etc/rubybashrc \
+    -- "$@"
diff --git a/third_party/rake-compiler-dock/build/sigfw.c b/third_party/rake-compiler-dock/build/sigfw.c
new file mode 100644
index 0000000..291d76c
--- /dev/null
+++ b/third_party/rake-compiler-dock/build/sigfw.c
@@ -0,0 +1,43 @@
+/*
+ * This program handles SIGINT and forwards it to another process.
+ * It is intended to be run as PID 1.
+ *
+ * Docker starts processes with "docker run" as PID 1.
+ * On Linux, the default signal handler for PID 1 ignores any signals.
+ * Therefore Ctrl-C aka SIGINT is ignored per default.
+ */
+
+#include <signal.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+
+int pid = 0;
+
+void
+handle_sigint (int signum)
+{
+  if(pid)
+    kill(pid, SIGINT);
+}
+
+int main(int argc, char *argv[]){
+  struct sigaction new_action;
+  int status = -1;
+
+  /* Set up the structure to specify the new action. */
+  new_action.sa_handler = handle_sigint;
+  sigemptyset (&new_action.sa_mask);
+  new_action.sa_flags = 0;
+
+  sigaction (SIGINT, &new_action, (void*)0);
+
+  pid = fork();
+  if(pid){
+    wait(&status);
+    return WEXITSTATUS(status);
+  }else{
+    status = execvp(argv[1], &argv[1]);
+    perror("exec");
+    return status;
+  }
+}
diff --git a/third_party/rake-compiler-dock/build/strip_wrapper b/third_party/rake-compiler-dock/build/strip_wrapper
new file mode 100755
index 0000000..7f8a134
--- /dev/null
+++ b/third_party/rake-compiler-dock/build/strip_wrapper
@@ -0,0 +1,30 @@
+#!/usr/bin/env ruby
+
+# Strip file on local folder instead of a Virtualbox shared folder
+# to work around this bug: https://www.virtualbox.org/ticket/8463
+
+require 'tempfile'
+require 'fileutils'
+
+strip = "#{File.basename($0)}.bin"
+
+files = ARGV.reject{|f| f=~/^-/ }.map do |arg|
+  tmp = Tempfile.new 'strip'
+  tmp.close
+  FileUtils.cp arg, tmp.path
+  [tmp, arg]
+end
+
+options = ARGV.select{|f| f=~/^-/ } + files.map{|t,o| t.path }
+
+unless system( strip, *options )
+  exit 127
+end
+code = $?.exitstatus
+
+files.each do |tmp, orig|
+  FileUtils.rm orig
+  FileUtils.cp tmp.path, orig
+end
+
+exit code
diff --git a/third_party/rake-compiler-dock/build/sudoers b/third_party/rake-compiler-dock/build/sudoers
new file mode 100644
index 0000000..f9f9b97
--- /dev/null
+++ b/third_party/rake-compiler-dock/build/sudoers
@@ -0,0 +1 @@
+Defaults        env_keep += "http_proxy https_proxy ftp_proxy RCD_HOST_RUBY_PLATFORM RCD_HOST_RUBY_VERSION RCD_IMAGE RUBY_CC_VERSION"
diff --git a/tools/buildgen/build-cleaner.py b/tools/buildgen/build-cleaner.py
index 37fedec..49a3644 100755
--- a/tools/buildgen/build-cleaner.py
+++ b/tools/buildgen/build-cleaner.py
@@ -38,7 +38,6 @@
 TEST = (os.environ.get('TEST', 'false') == 'true')
 
 _TOP_LEVEL_KEYS = ['settings', 'proto_deps', 'filegroups', 'libs', 'targets', 'vspackages']
-_VERSION_KEYS = ['major', 'minor', 'micro', 'build']
 _ELEM_KEYS = [
     'name',
     'cpu_cost',
@@ -83,8 +82,6 @@
   with open(filename) as f:
     js = yaml.load(f)
   js = rebuild_as_ordered_dict(js, _TOP_LEVEL_KEYS)
-  js['settings']['version'] = rebuild_as_ordered_dict(
-      js['settings']['version'], _VERSION_KEYS)
   for grp in ['filegroups', 'libs', 'targets']:
     if grp not in js: continue
     js[grp] = sorted([clean_elem(x) for x in js[grp]],
diff --git a/tools/buildgen/plugins/expand_version.py b/tools/buildgen/plugins/expand_version.py
new file mode 100755
index 0000000..b55e1b1
--- /dev/null
+++ b/tools/buildgen/plugins/expand_version.py
@@ -0,0 +1,102 @@
+# 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.
+
+"""Buildgen .proto files list plugin.
+
+This parses the list of targets from the yaml build file, and creates
+a list called "protos" that contains all of the proto file names.
+
+"""
+
+
+import re
+
+LANGUAGES = [
+  'core', 
+  'cpp', 
+  'csharp', 
+  'node', 
+  'objc', 
+  'php',
+  'python', 
+  'ruby', 
+  ]
+
+class Version:
+
+  def __init__(self, s):
+    self.tag = None
+    if '-' in s:
+      s, self.tag = s.split('-')
+    self.major, self.minor, self.patch = [int(x) for x in s.split('.')]
+
+  def __str__(self):
+    """Version string in a somewhat idiomatic style for most languages"""
+    s = '%d.%d.%d' % (self.major, self.minor, self.patch)
+    if self.tag:
+      s += '-%s' % self.tag
+    return s
+
+  def pep440(self):
+    """Version string in Python PEP440 style"""
+    s = '%d.%d.%d' % (self.major, self.minor, self.patch)
+    if self.tag:
+      # we need to translate from grpc version tags to pep440 version
+      # tags; this code is likely to be a little ad-hoc
+      if self.tag == 'dev':
+        s += '.dev0'
+      elif len(self.tag) >= 3 and self.tag[0:3] == 'pre':
+        s += 'rc%d' % int(self.tag[3:])
+      else:
+        raise Exception('Don\'t know how to translate version tag "%s" to pep440' % self.tag)
+    return s
+
+  def ruby(self):
+    """Version string in Ruby style"""
+    if self.tag:
+      return '%d.%d.%d.%s' % (self.major, self.minor, self.patch, self.tag)
+    else:
+      return '%d.%d.%d' % (self.major, self.minor, self.patch)
+
+def mako_plugin(dictionary):
+  """Expand version numbers:
+     - for each language, ensure there's a language_version tag in
+       settings (defaulting to the master version tag)
+     - expand version strings to major, minor, patch, and tag
+  """
+
+  settings = dictionary['settings']
+  master_version = Version(settings['version'])
+  settings['version'] = master_version
+  for language in LANGUAGES:
+    version_tag = '%s_version' % language
+    if version_tag in settings:
+      settings[version_tag] = Version(settings[version_tag])
+    else:
+      settings[version_tag] = master_version
diff --git a/tools/buildgen/plugins/list_api.py b/tools/buildgen/plugins/list_api.py
new file mode 100755
index 0000000..ff937a0
--- /dev/null
+++ b/tools/buildgen/plugins/list_api.py
@@ -0,0 +1,78 @@
+#!/usr/bin/env python2.7
+
+# 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.
+
+import collections
+import fnmatch
+import os
+import re
+import sys
+import yaml
+
+
+_RE_API = r'(?:GPRAPI|GRPCAPI|CENSUSAPI)([^;]*);'
+
+
+def list_c_apis(filenames):
+  for filename in filenames:
+    with open(filename, 'r') as f:
+      text = f.read()
+    for m in re.finditer(_RE_API, text):
+      api_declaration = re.sub('[ \r\n\t]+', ' ', m.group(1))
+      type_and_name, args_and_close = api_declaration.split('(', 1)
+      args = args_and_close[:args_and_close.rfind(')')].strip()
+      last_space = type_and_name.rfind(' ')
+      last_star = type_and_name.rfind('*')
+      type_end = max(last_space, last_star)
+      return_type = type_and_name[0:type_end+1].strip()
+      name = type_and_name[type_end+1:].strip()
+      yield {'return_type': return_type, 'name': name, 'arguments': args, 'header': filename}
+
+
+def headers_under(directory):
+  for root, dirnames, filenames in os.walk(directory):
+    for filename in fnmatch.filter(filenames, '*.h'):
+      yield os.path.join(root, filename)
+
+
+def mako_plugin(dictionary):
+  apis = []
+
+#  for lib in dictionary['libs']:
+#    if lib['name'] == 'grpc':
+#      apis.extend(list_c_apis(lib['public_headers']))
+  apis.extend(list_c_apis(sorted(headers_under('include/grpc'))))
+
+  dictionary['c_apis'] = apis
+
+
+if __name__ == '__main__':
+  print yaml.dump([api for api in list_c_apis(headers_under('include/grpc'))])
+
diff --git a/tools/codegen/core/gen_static_metadata.py b/tools/codegen/core/gen_static_metadata.py
index 3e47d7f..e6ae00e 100755
--- a/tools/codegen/core/gen_static_metadata.py
+++ b/tools/codegen/core/gen_static_metadata.py
@@ -1,6 +1,6 @@
 #!/usr/bin/env python2.7
 
-# Copyright 2015, Google Inc.
+# Copyright 2015-2016, Google Inc.
 # All rights reserved.
 #
 # Redistribution and use in source and binary forms, with or without
@@ -50,8 +50,8 @@
     'host',
     'grpc-message',
     'grpc-status',
-    'census',
     'census-bin',
+    'census-binary-bin',
     '',
     ('grpc-status', '0'),
     ('grpc-status', '1'),
diff --git a/tools/run_tests/check_submodules.sh b/tools/distrib/build_ruby_environment_macos.sh
old mode 100755
new mode 100644
similarity index 63%
copy from tools/run_tests/check_submodules.sh
copy to tools/distrib/build_ruby_environment_macos.sh
index b4ca4fa..ff3a388
--- a/tools/run_tests/check_submodules.sh
+++ b/tools/distrib/build_ruby_environment_macos.sh
@@ -1,5 +1,4 @@
-#!/bin/sh
-
+#!/bin/bash
 # Copyright 2015-2016, Google Inc.
 # All rights reserved.
 #
@@ -29,26 +28,34 @@
 # (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
 
-set -e
+rm -rf ~/.rake-compiler
 
-export TEST=true
+CROSS_RUBY=`mktemp tmpfile.XXXXXXXX`
 
-cd `dirname $0`/../..
+curl https://raw.githubusercontent.com/rake-compiler/rake-compiler/v0.9.5/tasks/bin/cross-ruby.rake > $CROSS_RUBY
 
-submodules=`mktemp /tmp/submXXXXXX`
-want_submodules=`mktemp /tmp/submXXXXXX`
-
-git submodule | awk '{ print $1 }' | sort > $submodules
-cat << EOF | awk '{ print $1 }' | sort > $want_submodules
- 9f897b25800d2f54f5c442ef01a60721aeca6d87 third_party/boringssl (version_for_cocoapods_1.0-67-g9f897b2)
- 05b155ff59114735ec8cd089f669c4c3d8f59029 third_party/gflags (v2.1.0-45-g05b155f)
- c99458533a9b4c743ed51537e25989ea55944908 third_party/googletest (release-1.7.0)
- d5fb408ddc281ffcadeb08699e65bb694656d0bd third_party/protobuf (v3.0.0-beta-2)
- 50893291621658f355bc5b4d450a8d06a563053d third_party/zlib (v1.2.8)
+patch $CROSS_RUBY << EOF
+--- cross-ruby.rake	2016-02-05 16:26:53.000000000 -0800
++++ cross-ruby.rake.patched	2016-02-05 16:27:33.000000000 -0800
+@@ -133,7 +133,8 @@
+     "--host=#{MINGW_HOST}",
+     "--target=#{MINGW_TARGET}",
+     "--build=#{RUBY_BUILD}",
+-    '--enable-shared',
++    '--enable-static',
++    '--disable-shared',
+     '--disable-install-doc',
+     '--without-tk',
+     '--without-tcl'
 EOF
 
-diff -u $submodules $want_submodules
+MAKE="make -j8"
 
-rm $submodules $want_submodules
+for v in 2.3.0 2.2.2 2.1.5 2.0.0-p645 ; do
+  rake -f $CROSS_RUBY cross-ruby VERSION=$v HOST=x86_64-darwin11
+done
 
+sed 's/x86_64-darwin-11/universal-darwin/' ~/.rake-compiler/config.yml > $CROSS_RUBY
+mv $CROSS_RUBY ~/.rake-compiler/config.yml
diff --git a/tools/distrib/check_copyright.py b/tools/distrib/check_copyright.py
index 935acf5..a7efdc8 100755
--- a/tools/distrib/check_copyright.py
+++ b/tools/distrib/check_copyright.py
@@ -124,7 +124,7 @@
 
 # scan files, validate the text
 ok = True
-for filename in subprocess.check_output('git ls-tree -r --name-only -r HEAD',
+for filename in subprocess.check_output('git ls-tree -r --name-only -r HEAD | grep -v ^third_party/',
                                         shell=True).splitlines():
   if filename in KNOWN_BAD: continue
   ext = os.path.splitext(filename)[1]
diff --git a/tools/run_tests/check_submodules.sh b/tools/distrib/check_windows_dlls.sh
similarity index 66%
copy from tools/run_tests/check_submodules.sh
copy to tools/distrib/check_windows_dlls.sh
index b4ca4fa..efb66e9 100755
--- a/tools/run_tests/check_submodules.sh
+++ b/tools/distrib/check_windows_dlls.sh
@@ -1,5 +1,4 @@
-#!/bin/sh
-
+#!/bin/bash
 # Copyright 2015-2016, Google Inc.
 # All rights reserved.
 #
@@ -29,26 +28,10 @@
 # (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
 
-set -e
+# change to root directory
+cd $(dirname $0)/../..
 
-export TEST=true
-
-cd `dirname $0`/../..
-
-submodules=`mktemp /tmp/submXXXXXX`
-want_submodules=`mktemp /tmp/submXXXXXX`
-
-git submodule | awk '{ print $1 }' | sort > $submodules
-cat << EOF | awk '{ print $1 }' | sort > $want_submodules
- 9f897b25800d2f54f5c442ef01a60721aeca6d87 third_party/boringssl (version_for_cocoapods_1.0-67-g9f897b2)
- 05b155ff59114735ec8cd089f669c4c3d8f59029 third_party/gflags (v2.1.0-45-g05b155f)
- c99458533a9b4c743ed51537e25989ea55944908 third_party/googletest (release-1.7.0)
- d5fb408ddc281ffcadeb08699e65bb694656d0bd third_party/protobuf (v3.0.0-beta-2)
- 50893291621658f355bc5b4d450a8d06a563053d third_party/zlib (v1.2.8)
-EOF
-
-diff -u $submodules $want_submodules
-
-rm $submodules $want_submodules
-
+bundle
+rake dlls
diff --git a/tools/run_tests/check_submodules.sh b/tools/distrib/docker_for_windows.rb
similarity index 63%
copy from tools/run_tests/check_submodules.sh
copy to tools/distrib/docker_for_windows.rb
index b4ca4fa..d72765d 100755
--- a/tools/run_tests/check_submodules.sh
+++ b/tools/distrib/docker_for_windows.rb
@@ -1,6 +1,5 @@
-#!/bin/sh
-
-# Copyright 2015-2016, Google Inc.
+#!/usr/bin/env ruby
+# Copyright 2016, Google Inc.
 # All rights reserved.
 #
 # Redistribution and use in source and binary forms, with or without
@@ -29,26 +28,34 @@
 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
+def grpc_root()
+  File.expand_path(File.join(File.dirname(__FILE__), '..', '..'))
+end
 
-set -e
+def docker_for_windows_image()
+  require 'digest'
 
-export TEST=true
+  dockerfile = File.join(grpc_root, 'third_party', 'rake-compiler-dock', 'Dockerfile') 
+  dockerpath = File.dirname(dockerfile)
+  version = Digest::SHA1.file(dockerfile).hexdigest
+  image_name = 'grpc/rake-compiler-dock:' + version
+  cmd = "docker build -t #{image_name} --file #{dockerfile} #{dockerpath}"
+  puts cmd
+  system cmd
+  raise "Failed to build the docker image." unless $? == 0
+  image_name
+end
 
-cd `dirname $0`/../..
+def docker_for_windows(args)
+  require 'rake_compiler_dock'
 
-submodules=`mktemp /tmp/submXXXXXX`
-want_submodules=`mktemp /tmp/submXXXXXX`
+  args = 'bash -l' if args.empty?
 
-git submodule | awk '{ print $1 }' | sort > $submodules
-cat << EOF | awk '{ print $1 }' | sort > $want_submodules
- 9f897b25800d2f54f5c442ef01a60721aeca6d87 third_party/boringssl (version_for_cocoapods_1.0-67-g9f897b2)
- 05b155ff59114735ec8cd089f669c4c3d8f59029 third_party/gflags (v2.1.0-45-g05b155f)
- c99458533a9b4c743ed51537e25989ea55944908 third_party/googletest (release-1.7.0)
- d5fb408ddc281ffcadeb08699e65bb694656d0bd third_party/protobuf (v3.0.0-beta-2)
- 50893291621658f355bc5b4d450a8d06a563053d third_party/zlib (v1.2.8)
-EOF
+  ENV['RAKE_COMPILER_DOCK_IMAGE'] = docker_for_windows_image
 
-diff -u $submodules $want_submodules
+  RakeCompilerDock.sh args
+end
 
-rm $submodules $want_submodules
-
+if __FILE__ == $0
+  docker_for_windows $*.join(' ')
+end
diff --git a/tools/run_tests/check_submodules.sh b/tools/dockerfile/distribtest/csharp_centos7_x64/Dockerfile
old mode 100755
new mode 100644
similarity index 66%
copy from tools/run_tests/check_submodules.sh
copy to tools/dockerfile/distribtest/csharp_centos7_x64/Dockerfile
index b4ca4fa..03b5b36
--- a/tools/run_tests/check_submodules.sh
+++ b/tools/dockerfile/distribtest/csharp_centos7_x64/Dockerfile
@@ -1,5 +1,3 @@
-#!/bin/sh
-
 # Copyright 2015-2016, Google Inc.
 # All rights reserved.
 #
@@ -29,26 +27,11 @@
 # (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 centos:7
 
-set -e
+RUN rpm --import "http://keyserver.ubuntu.com/pks/lookup?op=get&search=0x3FA7E0328081BFF6A14DA29AA6A19B38D3D831EF"
+RUN yum-config-manager --add-repo http://download.mono-project.com/repo/centos/
 
-export TEST=true
-
-cd `dirname $0`/../..
-
-submodules=`mktemp /tmp/submXXXXXX`
-want_submodules=`mktemp /tmp/submXXXXXX`
-
-git submodule | awk '{ print $1 }' | sort > $submodules
-cat << EOF | awk '{ print $1 }' | sort > $want_submodules
- 9f897b25800d2f54f5c442ef01a60721aeca6d87 third_party/boringssl (version_for_cocoapods_1.0-67-g9f897b2)
- 05b155ff59114735ec8cd089f669c4c3d8f59029 third_party/gflags (v2.1.0-45-g05b155f)
- c99458533a9b4c743ed51537e25989ea55944908 third_party/googletest (release-1.7.0)
- d5fb408ddc281ffcadeb08699e65bb694656d0bd third_party/protobuf (v3.0.0-beta-2)
- 50893291621658f355bc5b4d450a8d06a563053d third_party/zlib (v1.2.8)
-EOF
-
-diff -u $submodules $want_submodules
-
-rm $submodules $want_submodules
-
+RUN yum install -y mono
+RUN yum install -y unzip
+RUN yum install -y nuget
diff --git a/tools/run_tests/check_submodules.sh b/tools/dockerfile/distribtest/csharp_jessie_x64/Dockerfile
old mode 100755
new mode 100644
similarity index 65%
copy from tools/run_tests/check_submodules.sh
copy to tools/dockerfile/distribtest/csharp_jessie_x64/Dockerfile
index b4ca4fa..1cadba3
--- a/tools/run_tests/check_submodules.sh
+++ b/tools/dockerfile/distribtest/csharp_jessie_x64/Dockerfile
@@ -1,5 +1,3 @@
-#!/bin/sh
-
 # Copyright 2015-2016, Google Inc.
 # All rights reserved.
 #
@@ -29,26 +27,17 @@
 # (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
 
-set -e
+RUN apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 3FA7E0328081BFF6A14DA29AA6A19B38D3D831EF
+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
 
-export TEST=true
+RUN apt-get update && apt-get install -y \
+    mono-devel \
+    ca-certificates-mono \
+    nuget
 
-cd `dirname $0`/../..
-
-submodules=`mktemp /tmp/submXXXXXX`
-want_submodules=`mktemp /tmp/submXXXXXX`
-
-git submodule | awk '{ print $1 }' | sort > $submodules
-cat << EOF | awk '{ print $1 }' | sort > $want_submodules
- 9f897b25800d2f54f5c442ef01a60721aeca6d87 third_party/boringssl (version_for_cocoapods_1.0-67-g9f897b2)
- 05b155ff59114735ec8cd089f669c4c3d8f59029 third_party/gflags (v2.1.0-45-g05b155f)
- c99458533a9b4c743ed51537e25989ea55944908 third_party/googletest (release-1.7.0)
- d5fb408ddc281ffcadeb08699e65bb694656d0bd third_party/protobuf (v3.0.0-beta-2)
- 50893291621658f355bc5b4d450a8d06a563053d third_party/zlib (v1.2.8)
-EOF
-
-diff -u $submodules $want_submodules
-
-rm $submodules $want_submodules
-
+RUN apt-get update && apt-get install -y unzip
diff --git a/tools/run_tests/check_submodules.sh b/tools/dockerfile/distribtest/csharp_jessie_x86/Dockerfile
old mode 100755
new mode 100644
similarity index 64%
copy from tools/run_tests/check_submodules.sh
copy to tools/dockerfile/distribtest/csharp_jessie_x86/Dockerfile
index b4ca4fa..be96282
--- a/tools/run_tests/check_submodules.sh
+++ b/tools/dockerfile/distribtest/csharp_jessie_x86/Dockerfile
@@ -1,5 +1,3 @@
-#!/bin/sh
-
 # Copyright 2015-2016, Google Inc.
 # All rights reserved.
 #
@@ -29,26 +27,17 @@
 # (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 32bit/debian:jessie
 
-set -e
+RUN apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 3FA7E0328081BFF6A14DA29AA6A19B38D3D831EF
+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
 
-export TEST=true
+RUN apt-get update && apt-get install -y \
+    mono-devel \
+    ca-certificates-mono \
+    nuget
 
-cd `dirname $0`/../..
-
-submodules=`mktemp /tmp/submXXXXXX`
-want_submodules=`mktemp /tmp/submXXXXXX`
-
-git submodule | awk '{ print $1 }' | sort > $submodules
-cat << EOF | awk '{ print $1 }' | sort > $want_submodules
- 9f897b25800d2f54f5c442ef01a60721aeca6d87 third_party/boringssl (version_for_cocoapods_1.0-67-g9f897b2)
- 05b155ff59114735ec8cd089f669c4c3d8f59029 third_party/gflags (v2.1.0-45-g05b155f)
- c99458533a9b4c743ed51537e25989ea55944908 third_party/googletest (release-1.7.0)
- d5fb408ddc281ffcadeb08699e65bb694656d0bd third_party/protobuf (v3.0.0-beta-2)
- 50893291621658f355bc5b4d450a8d06a563053d third_party/zlib (v1.2.8)
-EOF
-
-diff -u $submodules $want_submodules
-
-rm $submodules $want_submodules
-
+RUN apt-get update && apt-get install -y unzip
diff --git a/tools/run_tests/check_submodules.sh b/tools/dockerfile/distribtest/csharp_ubuntu1404_x64/Dockerfile
old mode 100755
new mode 100644
similarity index 66%
copy from tools/run_tests/check_submodules.sh
copy to tools/dockerfile/distribtest/csharp_ubuntu1404_x64/Dockerfile
index b4ca4fa..3d04d03
--- a/tools/run_tests/check_submodules.sh
+++ b/tools/dockerfile/distribtest/csharp_ubuntu1404_x64/Dockerfile
@@ -1,5 +1,3 @@
-#!/bin/sh
-
 # Copyright 2015-2016, Google Inc.
 # All rights reserved.
 #
@@ -29,26 +27,14 @@
 # (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 ubuntu:14.04
 
-set -e
+RUN apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 3FA7E0328081BFF6A14DA29AA6A19B38D3D831EF
+RUN echo "deb http://download.mono-project.com/repo/debian wheezy main" | tee /etc/apt/sources.list.d/mono-xamarin.list
 
-export TEST=true
+RUN apt-get update && apt-get install -y \
+    mono-devel \
+    ca-certificates-mono \
+    nuget
 
-cd `dirname $0`/../..
-
-submodules=`mktemp /tmp/submXXXXXX`
-want_submodules=`mktemp /tmp/submXXXXXX`
-
-git submodule | awk '{ print $1 }' | sort > $submodules
-cat << EOF | awk '{ print $1 }' | sort > $want_submodules
- 9f897b25800d2f54f5c442ef01a60721aeca6d87 third_party/boringssl (version_for_cocoapods_1.0-67-g9f897b2)
- 05b155ff59114735ec8cd089f669c4c3d8f59029 third_party/gflags (v2.1.0-45-g05b155f)
- c99458533a9b4c743ed51537e25989ea55944908 third_party/googletest (release-1.7.0)
- d5fb408ddc281ffcadeb08699e65bb694656d0bd third_party/protobuf (v3.0.0-beta-2)
- 50893291621658f355bc5b4d450a8d06a563053d third_party/zlib (v1.2.8)
-EOF
-
-diff -u $submodules $want_submodules
-
-rm $submodules $want_submodules
-
+RUN apt-get update && apt-get install -y unzip
diff --git a/tools/run_tests/check_submodules.sh b/tools/dockerfile/distribtest/csharp_ubuntu1504_x64/Dockerfile
old mode 100755
new mode 100644
similarity index 66%
copy from tools/run_tests/check_submodules.sh
copy to tools/dockerfile/distribtest/csharp_ubuntu1504_x64/Dockerfile
index b4ca4fa..5eec570
--- a/tools/run_tests/check_submodules.sh
+++ b/tools/dockerfile/distribtest/csharp_ubuntu1504_x64/Dockerfile
@@ -1,5 +1,3 @@
-#!/bin/sh
-
 # Copyright 2015-2016, Google Inc.
 # All rights reserved.
 #
@@ -29,26 +27,14 @@
 # (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 ubuntu:15.04
 
-set -e
+RUN apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 3FA7E0328081BFF6A14DA29AA6A19B38D3D831EF
+RUN echo "deb http://download.mono-project.com/repo/debian wheezy main" | tee /etc/apt/sources.list.d/mono-xamarin.list
 
-export TEST=true
+RUN apt-get update && apt-get install -y \
+    mono-devel \
+    ca-certificates-mono \
+    nuget
 
-cd `dirname $0`/../..
-
-submodules=`mktemp /tmp/submXXXXXX`
-want_submodules=`mktemp /tmp/submXXXXXX`
-
-git submodule | awk '{ print $1 }' | sort > $submodules
-cat << EOF | awk '{ print $1 }' | sort > $want_submodules
- 9f897b25800d2f54f5c442ef01a60721aeca6d87 third_party/boringssl (version_for_cocoapods_1.0-67-g9f897b2)
- 05b155ff59114735ec8cd089f669c4c3d8f59029 third_party/gflags (v2.1.0-45-g05b155f)
- c99458533a9b4c743ed51537e25989ea55944908 third_party/googletest (release-1.7.0)
- d5fb408ddc281ffcadeb08699e65bb694656d0bd third_party/protobuf (v3.0.0-beta-2)
- 50893291621658f355bc5b4d450a8d06a563053d third_party/zlib (v1.2.8)
-EOF
-
-diff -u $submodules $want_submodules
-
-rm $submodules $want_submodules
-
+RUN apt-get update && apt-get install -y unzip
diff --git a/tools/run_tests/check_submodules.sh b/tools/dockerfile/distribtest/csharp_ubuntu1510_x64/Dockerfile
old mode 100755
new mode 100644
similarity index 66%
copy from tools/run_tests/check_submodules.sh
copy to tools/dockerfile/distribtest/csharp_ubuntu1510_x64/Dockerfile
index b4ca4fa..a6d60fb
--- a/tools/run_tests/check_submodules.sh
+++ b/tools/dockerfile/distribtest/csharp_ubuntu1510_x64/Dockerfile
@@ -1,5 +1,3 @@
-#!/bin/sh
-
 # Copyright 2015-2016, Google Inc.
 # All rights reserved.
 #
@@ -29,26 +27,14 @@
 # (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 ubuntu:15.10
 
-set -e
+RUN apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 3FA7E0328081BFF6A14DA29AA6A19B38D3D831EF
+RUN echo "deb http://download.mono-project.com/repo/debian wheezy main" | tee /etc/apt/sources.list.d/mono-xamarin.list
 
-export TEST=true
+RUN apt-get update && apt-get install -y \
+    mono-devel \
+    ca-certificates-mono \
+    nuget
 
-cd `dirname $0`/../..
-
-submodules=`mktemp /tmp/submXXXXXX`
-want_submodules=`mktemp /tmp/submXXXXXX`
-
-git submodule | awk '{ print $1 }' | sort > $submodules
-cat << EOF | awk '{ print $1 }' | sort > $want_submodules
- 9f897b25800d2f54f5c442ef01a60721aeca6d87 third_party/boringssl (version_for_cocoapods_1.0-67-g9f897b2)
- 05b155ff59114735ec8cd089f669c4c3d8f59029 third_party/gflags (v2.1.0-45-g05b155f)
- c99458533a9b4c743ed51537e25989ea55944908 third_party/googletest (release-1.7.0)
- d5fb408ddc281ffcadeb08699e65bb694656d0bd third_party/protobuf (v3.0.0-beta-2)
- 50893291621658f355bc5b4d450a8d06a563053d third_party/zlib (v1.2.8)
-EOF
-
-diff -u $submodules $want_submodules
-
-rm $submodules $want_submodules
-
+RUN apt-get update && apt-get install -y unzip
diff --git a/tools/run_tests/check_submodules.sh b/tools/dockerfile/distribtest/csharp_ubuntu1604_x64/Dockerfile
old mode 100755
new mode 100644
similarity index 66%
copy from tools/run_tests/check_submodules.sh
copy to tools/dockerfile/distribtest/csharp_ubuntu1604_x64/Dockerfile
index b4ca4fa..6147270
--- a/tools/run_tests/check_submodules.sh
+++ b/tools/dockerfile/distribtest/csharp_ubuntu1604_x64/Dockerfile
@@ -1,5 +1,3 @@
-#!/bin/sh
-
 # Copyright 2015-2016, Google Inc.
 # All rights reserved.
 #
@@ -29,26 +27,11 @@
 # (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 ubuntu:16.04
 
-set -e
+RUN apt-get update && apt-get install -y \
+    mono-devel \
+    ca-certificates-mono \
+    nuget
 
-export TEST=true
-
-cd `dirname $0`/../..
-
-submodules=`mktemp /tmp/submXXXXXX`
-want_submodules=`mktemp /tmp/submXXXXXX`
-
-git submodule | awk '{ print $1 }' | sort > $submodules
-cat << EOF | awk '{ print $1 }' | sort > $want_submodules
- 9f897b25800d2f54f5c442ef01a60721aeca6d87 third_party/boringssl (version_for_cocoapods_1.0-67-g9f897b2)
- 05b155ff59114735ec8cd089f669c4c3d8f59029 third_party/gflags (v2.1.0-45-g05b155f)
- c99458533a9b4c743ed51537e25989ea55944908 third_party/googletest (release-1.7.0)
- d5fb408ddc281ffcadeb08699e65bb694656d0bd third_party/protobuf (v3.0.0-beta-2)
- 50893291621658f355bc5b4d450a8d06a563053d third_party/zlib (v1.2.8)
-EOF
-
-diff -u $submodules $want_submodules
-
-rm $submodules $want_submodules
-
+RUN apt-get update && apt-get install -y unzip
diff --git a/tools/run_tests/check_submodules.sh b/tools/dockerfile/distribtest/csharp_wheezy_x64/Dockerfile
old mode 100755
new mode 100644
similarity index 66%
copy from tools/run_tests/check_submodules.sh
copy to tools/dockerfile/distribtest/csharp_wheezy_x64/Dockerfile
index b4ca4fa..9039c3c
--- a/tools/run_tests/check_submodules.sh
+++ b/tools/dockerfile/distribtest/csharp_wheezy_x64/Dockerfile
@@ -1,5 +1,3 @@
-#!/bin/sh
-
 # Copyright 2015-2016, Google Inc.
 # All rights reserved.
 #
@@ -29,26 +27,6 @@
 # (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 mono:4.2.2.30
 
-set -e
-
-export TEST=true
-
-cd `dirname $0`/../..
-
-submodules=`mktemp /tmp/submXXXXXX`
-want_submodules=`mktemp /tmp/submXXXXXX`
-
-git submodule | awk '{ print $1 }' | sort > $submodules
-cat << EOF | awk '{ print $1 }' | sort > $want_submodules
- 9f897b25800d2f54f5c442ef01a60721aeca6d87 third_party/boringssl (version_for_cocoapods_1.0-67-g9f897b2)
- 05b155ff59114735ec8cd089f669c4c3d8f59029 third_party/gflags (v2.1.0-45-g05b155f)
- c99458533a9b4c743ed51537e25989ea55944908 third_party/googletest (release-1.7.0)
- d5fb408ddc281ffcadeb08699e65bb694656d0bd third_party/protobuf (v3.0.0-beta-2)
- 50893291621658f355bc5b4d450a8d06a563053d third_party/zlib (v1.2.8)
-EOF
-
-diff -u $submodules $want_submodules
-
-rm $submodules $want_submodules
-
+RUN apt-get update && apt-get install -y unzip
diff --git a/tools/run_tests/check_submodules.sh b/tools/dockerfile/distribtest/node_centos7_x64/Dockerfile
old mode 100755
new mode 100644
similarity index 65%
copy from tools/run_tests/check_submodules.sh
copy to tools/dockerfile/distribtest/node_centos7_x64/Dockerfile
index b4ca4fa..f6e1664
--- a/tools/run_tests/check_submodules.sh
+++ b/tools/dockerfile/distribtest/node_centos7_x64/Dockerfile
@@ -1,6 +1,4 @@
-#!/bin/sh
-
-# Copyright 2015-2016, Google Inc.
+# Copyright 2016, Google Inc.
 # All rights reserved.
 #
 # Redistribution and use in source and binary forms, with or without
@@ -29,26 +27,10 @@
 # (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 centos:7
 
-set -e
+RUN yum install -y curl
 
-export TEST=true
-
-cd `dirname $0`/../..
-
-submodules=`mktemp /tmp/submXXXXXX`
-want_submodules=`mktemp /tmp/submXXXXXX`
-
-git submodule | awk '{ print $1 }' | sort > $submodules
-cat << EOF | awk '{ print $1 }' | sort > $want_submodules
- 9f897b25800d2f54f5c442ef01a60721aeca6d87 third_party/boringssl (version_for_cocoapods_1.0-67-g9f897b2)
- 05b155ff59114735ec8cd089f669c4c3d8f59029 third_party/gflags (v2.1.0-45-g05b155f)
- c99458533a9b4c743ed51537e25989ea55944908 third_party/googletest (release-1.7.0)
- d5fb408ddc281ffcadeb08699e65bb694656d0bd third_party/protobuf (v3.0.0-beta-2)
- 50893291621658f355bc5b4d450a8d06a563053d third_party/zlib (v1.2.8)
-EOF
-
-diff -u $submodules $want_submodules
-
-rm $submodules $want_submodules
-
+# Install nvm
+RUN touch .profile
+RUN curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.30.2/install.sh | bash
\ No newline at end of file
diff --git a/tools/run_tests/check_submodules.sh b/tools/dockerfile/distribtest/node_jessie_x64/Dockerfile
old mode 100755
new mode 100644
similarity index 65%
copy from tools/run_tests/check_submodules.sh
copy to tools/dockerfile/distribtest/node_jessie_x64/Dockerfile
index b4ca4fa..4ca5e86
--- a/tools/run_tests/check_submodules.sh
+++ b/tools/dockerfile/distribtest/node_jessie_x64/Dockerfile
@@ -1,6 +1,4 @@
-#!/bin/sh
-
-# Copyright 2015-2016, Google Inc.
+# Copyright 2016, Google Inc.
 # All rights reserved.
 #
 # Redistribution and use in source and binary forms, with or without
@@ -29,26 +27,10 @@
 # (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
 
-set -e
+RUN apt-get update && apt-get install -y curl
 
-export TEST=true
-
-cd `dirname $0`/../..
-
-submodules=`mktemp /tmp/submXXXXXX`
-want_submodules=`mktemp /tmp/submXXXXXX`
-
-git submodule | awk '{ print $1 }' | sort > $submodules
-cat << EOF | awk '{ print $1 }' | sort > $want_submodules
- 9f897b25800d2f54f5c442ef01a60721aeca6d87 third_party/boringssl (version_for_cocoapods_1.0-67-g9f897b2)
- 05b155ff59114735ec8cd089f669c4c3d8f59029 third_party/gflags (v2.1.0-45-g05b155f)
- c99458533a9b4c743ed51537e25989ea55944908 third_party/googletest (release-1.7.0)
- d5fb408ddc281ffcadeb08699e65bb694656d0bd third_party/protobuf (v3.0.0-beta-2)
- 50893291621658f355bc5b4d450a8d06a563053d third_party/zlib (v1.2.8)
-EOF
-
-diff -u $submodules $want_submodules
-
-rm $submodules $want_submodules
-
+# Install nvm
+RUN touch .profile
+RUN curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.30.2/install.sh | bash
\ No newline at end of file
diff --git a/tools/run_tests/check_submodules.sh b/tools/dockerfile/distribtest/node_jessie_x86/Dockerfile
old mode 100755
new mode 100644
similarity index 65%
copy from tools/run_tests/check_submodules.sh
copy to tools/dockerfile/distribtest/node_jessie_x86/Dockerfile
index b4ca4fa..8b97d8b
--- a/tools/run_tests/check_submodules.sh
+++ b/tools/dockerfile/distribtest/node_jessie_x86/Dockerfile
@@ -1,6 +1,4 @@
-#!/bin/sh
-
-# Copyright 2015-2016, Google Inc.
+# Copyright 2016, Google Inc.
 # All rights reserved.
 #
 # Redistribution and use in source and binary forms, with or without
@@ -29,26 +27,10 @@
 # (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 32bit/debian:jessie
 
-set -e
+RUN apt-get update && apt-get install -y curl
 
-export TEST=true
-
-cd `dirname $0`/../..
-
-submodules=`mktemp /tmp/submXXXXXX`
-want_submodules=`mktemp /tmp/submXXXXXX`
-
-git submodule | awk '{ print $1 }' | sort > $submodules
-cat << EOF | awk '{ print $1 }' | sort > $want_submodules
- 9f897b25800d2f54f5c442ef01a60721aeca6d87 third_party/boringssl (version_for_cocoapods_1.0-67-g9f897b2)
- 05b155ff59114735ec8cd089f669c4c3d8f59029 third_party/gflags (v2.1.0-45-g05b155f)
- c99458533a9b4c743ed51537e25989ea55944908 third_party/googletest (release-1.7.0)
- d5fb408ddc281ffcadeb08699e65bb694656d0bd third_party/protobuf (v3.0.0-beta-2)
- 50893291621658f355bc5b4d450a8d06a563053d third_party/zlib (v1.2.8)
-EOF
-
-diff -u $submodules $want_submodules
-
-rm $submodules $want_submodules
-
+# Install nvm
+RUN touch .profile
+RUN curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.30.2/install.sh | bash
diff --git a/tools/run_tests/check_submodules.sh b/tools/dockerfile/distribtest/node_ubuntu1204_x64/Dockerfile
old mode 100755
new mode 100644
similarity index 65%
copy from tools/run_tests/check_submodules.sh
copy to tools/dockerfile/distribtest/node_ubuntu1204_x64/Dockerfile
index b4ca4fa..0134dc9
--- a/tools/run_tests/check_submodules.sh
+++ b/tools/dockerfile/distribtest/node_ubuntu1204_x64/Dockerfile
@@ -1,6 +1,4 @@
-#!/bin/sh
-
-# Copyright 2015-2016, Google Inc.
+# Copyright 2016, Google Inc.
 # All rights reserved.
 #
 # Redistribution and use in source and binary forms, with or without
@@ -29,26 +27,10 @@
 # (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 ubuntu:12.04
 
-set -e
+RUN apt-get update && apt-get install -y curl
 
-export TEST=true
-
-cd `dirname $0`/../..
-
-submodules=`mktemp /tmp/submXXXXXX`
-want_submodules=`mktemp /tmp/submXXXXXX`
-
-git submodule | awk '{ print $1 }' | sort > $submodules
-cat << EOF | awk '{ print $1 }' | sort > $want_submodules
- 9f897b25800d2f54f5c442ef01a60721aeca6d87 third_party/boringssl (version_for_cocoapods_1.0-67-g9f897b2)
- 05b155ff59114735ec8cd089f669c4c3d8f59029 third_party/gflags (v2.1.0-45-g05b155f)
- c99458533a9b4c743ed51537e25989ea55944908 third_party/googletest (release-1.7.0)
- d5fb408ddc281ffcadeb08699e65bb694656d0bd third_party/protobuf (v3.0.0-beta-2)
- 50893291621658f355bc5b4d450a8d06a563053d third_party/zlib (v1.2.8)
-EOF
-
-diff -u $submodules $want_submodules
-
-rm $submodules $want_submodules
-
+# Install nvm
+RUN touch .profile
+RUN curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.30.2/install.sh | bash
\ No newline at end of file
diff --git a/tools/run_tests/check_submodules.sh b/tools/dockerfile/distribtest/node_ubuntu1404_x64/Dockerfile
old mode 100755
new mode 100644
similarity index 65%
copy from tools/run_tests/check_submodules.sh
copy to tools/dockerfile/distribtest/node_ubuntu1404_x64/Dockerfile
index b4ca4fa..0fae447
--- a/tools/run_tests/check_submodules.sh
+++ b/tools/dockerfile/distribtest/node_ubuntu1404_x64/Dockerfile
@@ -1,6 +1,4 @@
-#!/bin/sh
-
-# Copyright 2015-2016, Google Inc.
+# Copyright 2016, Google Inc.
 # All rights reserved.
 #
 # Redistribution and use in source and binary forms, with or without
@@ -29,26 +27,10 @@
 # (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 ubuntu:14.04
 
-set -e
+RUN apt-get update && apt-get install -y curl
 
-export TEST=true
-
-cd `dirname $0`/../..
-
-submodules=`mktemp /tmp/submXXXXXX`
-want_submodules=`mktemp /tmp/submXXXXXX`
-
-git submodule | awk '{ print $1 }' | sort > $submodules
-cat << EOF | awk '{ print $1 }' | sort > $want_submodules
- 9f897b25800d2f54f5c442ef01a60721aeca6d87 third_party/boringssl (version_for_cocoapods_1.0-67-g9f897b2)
- 05b155ff59114735ec8cd089f669c4c3d8f59029 third_party/gflags (v2.1.0-45-g05b155f)
- c99458533a9b4c743ed51537e25989ea55944908 third_party/googletest (release-1.7.0)
- d5fb408ddc281ffcadeb08699e65bb694656d0bd third_party/protobuf (v3.0.0-beta-2)
- 50893291621658f355bc5b4d450a8d06a563053d third_party/zlib (v1.2.8)
-EOF
-
-diff -u $submodules $want_submodules
-
-rm $submodules $want_submodules
-
+# Install nvm
+RUN touch .profile
+RUN curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.30.2/install.sh | bash
\ No newline at end of file
diff --git a/tools/run_tests/check_submodules.sh b/tools/dockerfile/distribtest/node_ubuntu1504_x64/Dockerfile
old mode 100755
new mode 100644
similarity index 65%
copy from tools/run_tests/check_submodules.sh
copy to tools/dockerfile/distribtest/node_ubuntu1504_x64/Dockerfile
index b4ca4fa..55da46c
--- a/tools/run_tests/check_submodules.sh
+++ b/tools/dockerfile/distribtest/node_ubuntu1504_x64/Dockerfile
@@ -1,6 +1,4 @@
-#!/bin/sh
-
-# Copyright 2015-2016, Google Inc.
+# Copyright 2016, Google Inc.
 # All rights reserved.
 #
 # Redistribution and use in source and binary forms, with or without
@@ -29,26 +27,10 @@
 # (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 ubuntu:15.04
 
-set -e
+RUN apt-get update && apt-get install -y curl
 
-export TEST=true
-
-cd `dirname $0`/../..
-
-submodules=`mktemp /tmp/submXXXXXX`
-want_submodules=`mktemp /tmp/submXXXXXX`
-
-git submodule | awk '{ print $1 }' | sort > $submodules
-cat << EOF | awk '{ print $1 }' | sort > $want_submodules
- 9f897b25800d2f54f5c442ef01a60721aeca6d87 third_party/boringssl (version_for_cocoapods_1.0-67-g9f897b2)
- 05b155ff59114735ec8cd089f669c4c3d8f59029 third_party/gflags (v2.1.0-45-g05b155f)
- c99458533a9b4c743ed51537e25989ea55944908 third_party/googletest (release-1.7.0)
- d5fb408ddc281ffcadeb08699e65bb694656d0bd third_party/protobuf (v3.0.0-beta-2)
- 50893291621658f355bc5b4d450a8d06a563053d third_party/zlib (v1.2.8)
-EOF
-
-diff -u $submodules $want_submodules
-
-rm $submodules $want_submodules
-
+# Install nvm
+RUN touch .profile
+RUN curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.30.2/install.sh | bash
\ No newline at end of file
diff --git a/tools/run_tests/check_submodules.sh b/tools/dockerfile/distribtest/node_ubuntu1510_x64/Dockerfile
old mode 100755
new mode 100644
similarity index 65%
copy from tools/run_tests/check_submodules.sh
copy to tools/dockerfile/distribtest/node_ubuntu1510_x64/Dockerfile
index b4ca4fa..c050cab
--- a/tools/run_tests/check_submodules.sh
+++ b/tools/dockerfile/distribtest/node_ubuntu1510_x64/Dockerfile
@@ -1,6 +1,4 @@
-#!/bin/sh
-
-# Copyright 2015-2016, Google Inc.
+# Copyright 2016, Google Inc.
 # All rights reserved.
 #
 # Redistribution and use in source and binary forms, with or without
@@ -29,26 +27,10 @@
 # (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 ubuntu:15.10
 
-set -e
+RUN apt-get update && apt-get install -y curl
 
-export TEST=true
-
-cd `dirname $0`/../..
-
-submodules=`mktemp /tmp/submXXXXXX`
-want_submodules=`mktemp /tmp/submXXXXXX`
-
-git submodule | awk '{ print $1 }' | sort > $submodules
-cat << EOF | awk '{ print $1 }' | sort > $want_submodules
- 9f897b25800d2f54f5c442ef01a60721aeca6d87 third_party/boringssl (version_for_cocoapods_1.0-67-g9f897b2)
- 05b155ff59114735ec8cd089f669c4c3d8f59029 third_party/gflags (v2.1.0-45-g05b155f)
- c99458533a9b4c743ed51537e25989ea55944908 third_party/googletest (release-1.7.0)
- d5fb408ddc281ffcadeb08699e65bb694656d0bd third_party/protobuf (v3.0.0-beta-2)
- 50893291621658f355bc5b4d450a8d06a563053d third_party/zlib (v1.2.8)
-EOF
-
-diff -u $submodules $want_submodules
-
-rm $submodules $want_submodules
-
+# Install nvm
+RUN touch .profile
+RUN curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.30.2/install.sh | bash
\ No newline at end of file
diff --git a/tools/run_tests/check_submodules.sh b/tools/dockerfile/distribtest/node_ubuntu1604_x64/Dockerfile
old mode 100755
new mode 100644
similarity index 65%
copy from tools/run_tests/check_submodules.sh
copy to tools/dockerfile/distribtest/node_ubuntu1604_x64/Dockerfile
index b4ca4fa..ab9e8a3
--- a/tools/run_tests/check_submodules.sh
+++ b/tools/dockerfile/distribtest/node_ubuntu1604_x64/Dockerfile
@@ -1,6 +1,4 @@
-#!/bin/sh
-
-# Copyright 2015-2016, Google Inc.
+# Copyright 2016, Google Inc.
 # All rights reserved.
 #
 # Redistribution and use in source and binary forms, with or without
@@ -29,26 +27,10 @@
 # (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 ubuntu:16.04
 
-set -e
+RUN apt-get update && apt-get install -y curl
 
-export TEST=true
-
-cd `dirname $0`/../..
-
-submodules=`mktemp /tmp/submXXXXXX`
-want_submodules=`mktemp /tmp/submXXXXXX`
-
-git submodule | awk '{ print $1 }' | sort > $submodules
-cat << EOF | awk '{ print $1 }' | sort > $want_submodules
- 9f897b25800d2f54f5c442ef01a60721aeca6d87 third_party/boringssl (version_for_cocoapods_1.0-67-g9f897b2)
- 05b155ff59114735ec8cd089f669c4c3d8f59029 third_party/gflags (v2.1.0-45-g05b155f)
- c99458533a9b4c743ed51537e25989ea55944908 third_party/googletest (release-1.7.0)
- d5fb408ddc281ffcadeb08699e65bb694656d0bd third_party/protobuf (v3.0.0-beta-2)
- 50893291621658f355bc5b4d450a8d06a563053d third_party/zlib (v1.2.8)
-EOF
-
-diff -u $submodules $want_submodules
-
-rm $submodules $want_submodules
-
+# Install nvm
+RUN touch .profile
+RUN curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.30.2/install.sh | bash
\ No newline at end of file
diff --git a/tools/run_tests/check_submodules.sh b/tools/dockerfile/distribtest/node_wheezy_x64/Dockerfile
old mode 100755
new mode 100644
similarity index 65%
copy from tools/run_tests/check_submodules.sh
copy to tools/dockerfile/distribtest/node_wheezy_x64/Dockerfile
index b4ca4fa..20ef27b
--- a/tools/run_tests/check_submodules.sh
+++ b/tools/dockerfile/distribtest/node_wheezy_x64/Dockerfile
@@ -1,6 +1,4 @@
-#!/bin/sh
-
-# Copyright 2015-2016, Google Inc.
+# Copyright 2016, Google Inc.
 # All rights reserved.
 #
 # Redistribution and use in source and binary forms, with or without
@@ -29,26 +27,10 @@
 # (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:wheezy
 
-set -e
+RUN apt-get update && apt-get install -y curl
 
-export TEST=true
-
-cd `dirname $0`/../..
-
-submodules=`mktemp /tmp/submXXXXXX`
-want_submodules=`mktemp /tmp/submXXXXXX`
-
-git submodule | awk '{ print $1 }' | sort > $submodules
-cat << EOF | awk '{ print $1 }' | sort > $want_submodules
- 9f897b25800d2f54f5c442ef01a60721aeca6d87 third_party/boringssl (version_for_cocoapods_1.0-67-g9f897b2)
- 05b155ff59114735ec8cd089f669c4c3d8f59029 third_party/gflags (v2.1.0-45-g05b155f)
- c99458533a9b4c743ed51537e25989ea55944908 third_party/googletest (release-1.7.0)
- d5fb408ddc281ffcadeb08699e65bb694656d0bd third_party/protobuf (v3.0.0-beta-2)
- 50893291621658f355bc5b4d450a8d06a563053d third_party/zlib (v1.2.8)
-EOF
-
-diff -u $submodules $want_submodules
-
-rm $submodules $want_submodules
-
+# Install nvm
+RUN touch .profile
+RUN curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.30.2/install.sh | bash
\ No newline at end of file
diff --git a/tools/run_tests/check_submodules.sh b/tools/dockerfile/distribtest/python_arch_x64/Dockerfile
old mode 100755
new mode 100644
similarity index 66%
copy from tools/run_tests/check_submodules.sh
copy to tools/dockerfile/distribtest/python_arch_x64/Dockerfile
index b4ca4fa..c4f2431
--- a/tools/run_tests/check_submodules.sh
+++ b/tools/dockerfile/distribtest/python_arch_x64/Dockerfile
@@ -1,5 +1,3 @@
-#!/bin/sh
-
 # Copyright 2015-2016, Google Inc.
 # All rights reserved.
 #
@@ -29,26 +27,10 @@
 # (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 base/archlinux
 
-set -e
-
-export TEST=true
-
-cd `dirname $0`/../..
-
-submodules=`mktemp /tmp/submXXXXXX`
-want_submodules=`mktemp /tmp/submXXXXXX`
-
-git submodule | awk '{ print $1 }' | sort > $submodules
-cat << EOF | awk '{ print $1 }' | sort > $want_submodules
- 9f897b25800d2f54f5c442ef01a60721aeca6d87 third_party/boringssl (version_for_cocoapods_1.0-67-g9f897b2)
- 05b155ff59114735ec8cd089f669c4c3d8f59029 third_party/gflags (v2.1.0-45-g05b155f)
- c99458533a9b4c743ed51537e25989ea55944908 third_party/googletest (release-1.7.0)
- d5fb408ddc281ffcadeb08699e65bb694656d0bd third_party/protobuf (v3.0.0-beta-2)
- 50893291621658f355bc5b4d450a8d06a563053d third_party/zlib (v1.2.8)
-EOF
-
-diff -u $submodules $want_submodules
-
-rm $submodules $want_submodules
+RUN pacman --noconfirm -Syy
+RUN pacman --noconfirm -S openssl
+RUN pacman --noconfirm -S python2
+RUN pacman --noconfirm -S python2-pip
 
diff --git a/tools/run_tests/check_submodules.sh b/tools/dockerfile/distribtest/python_centos6_x64/Dockerfile
old mode 100755
new mode 100644
similarity index 66%
copy from tools/run_tests/check_submodules.sh
copy to tools/dockerfile/distribtest/python_centos6_x64/Dockerfile
index b4ca4fa..79dae07
--- a/tools/run_tests/check_submodules.sh
+++ b/tools/dockerfile/distribtest/python_centos6_x64/Dockerfile
@@ -1,5 +1,3 @@
-#!/bin/sh
-
 # Copyright 2015-2016, Google Inc.
 # All rights reserved.
 #
@@ -29,26 +27,20 @@
 # (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 centos:6
 
-set -e
+RUN yum -y install https://dl.fedoraproject.org/pub/epel/epel-release-latest-6.noarch.rpm
 
-export TEST=true
+# Vanilla CentOS6 only has python 2.6 and we don't support that.
+RUN yum -y install yum -y install https://centos6.iuscommunity.org/ius-release.rpm
+RUN yum install -y python27
 
-cd `dirname $0`/../..
+# Override python2.6
+RUN ln -s /usr/bin/python2.7 /usr/local/bin/python
+RUN ln -s /usr/bin/python2.7 /usr/local/bin/python2
 
-submodules=`mktemp /tmp/submXXXXXX`
-want_submodules=`mktemp /tmp/submXXXXXX`
+# Install pip
+RUN curl https://bootstrap.pypa.io/get-pip.py | python -
 
-git submodule | awk '{ print $1 }' | sort > $submodules
-cat << EOF | awk '{ print $1 }' | sort > $want_submodules
- 9f897b25800d2f54f5c442ef01a60721aeca6d87 third_party/boringssl (version_for_cocoapods_1.0-67-g9f897b2)
- 05b155ff59114735ec8cd089f669c4c3d8f59029 third_party/gflags (v2.1.0-45-g05b155f)
- c99458533a9b4c743ed51537e25989ea55944908 third_party/googletest (release-1.7.0)
- d5fb408ddc281ffcadeb08699e65bb694656d0bd third_party/protobuf (v3.0.0-beta-2)
- 50893291621658f355bc5b4d450a8d06a563053d third_party/zlib (v1.2.8)
-EOF
-
-diff -u $submodules $want_submodules
-
-rm $submodules $want_submodules
-
+# "which" command required by python's run_distrib_test.sh
+RUN yum install -y which
diff --git a/tools/run_tests/check_submodules.sh b/tools/dockerfile/distribtest/python_centos7_x64/Dockerfile
old mode 100755
new mode 100644
similarity index 66%
copy from tools/run_tests/check_submodules.sh
copy to tools/dockerfile/distribtest/python_centos7_x64/Dockerfile
index b4ca4fa..114957b
--- a/tools/run_tests/check_submodules.sh
+++ b/tools/dockerfile/distribtest/python_centos7_x64/Dockerfile
@@ -1,5 +1,3 @@
-#!/bin/sh
-
 # Copyright 2015-2016, Google Inc.
 # All rights reserved.
 #
@@ -29,26 +27,9 @@
 # (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 centos:7
 
-set -e
-
-export TEST=true
-
-cd `dirname $0`/../..
-
-submodules=`mktemp /tmp/submXXXXXX`
-want_submodules=`mktemp /tmp/submXXXXXX`
-
-git submodule | awk '{ print $1 }' | sort > $submodules
-cat << EOF | awk '{ print $1 }' | sort > $want_submodules
- 9f897b25800d2f54f5c442ef01a60721aeca6d87 third_party/boringssl (version_for_cocoapods_1.0-67-g9f897b2)
- 05b155ff59114735ec8cd089f669c4c3d8f59029 third_party/gflags (v2.1.0-45-g05b155f)
- c99458533a9b4c743ed51537e25989ea55944908 third_party/googletest (release-1.7.0)
- d5fb408ddc281ffcadeb08699e65bb694656d0bd third_party/protobuf (v3.0.0-beta-2)
- 50893291621658f355bc5b4d450a8d06a563053d third_party/zlib (v1.2.8)
-EOF
-
-diff -u $submodules $want_submodules
-
-rm $submodules $want_submodules
+RUN yum install -y python
+RUN yum install -y epel-release
+RUN yum install -y python-pip
 
diff --git a/tools/run_tests/check_submodules.sh b/tools/dockerfile/distribtest/python_fedora20_x64/Dockerfile
old mode 100755
new mode 100644
similarity index 66%
copy from tools/run_tests/check_submodules.sh
copy to tools/dockerfile/distribtest/python_fedora20_x64/Dockerfile
index b4ca4fa..d580364
--- a/tools/run_tests/check_submodules.sh
+++ b/tools/dockerfile/distribtest/python_fedora20_x64/Dockerfile
@@ -1,5 +1,3 @@
-#!/bin/sh
-
 # Copyright 2015-2016, Google Inc.
 # All rights reserved.
 #
@@ -29,26 +27,6 @@
 # (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 fedora:20
 
-set -e
-
-export TEST=true
-
-cd `dirname $0`/../..
-
-submodules=`mktemp /tmp/submXXXXXX`
-want_submodules=`mktemp /tmp/submXXXXXX`
-
-git submodule | awk '{ print $1 }' | sort > $submodules
-cat << EOF | awk '{ print $1 }' | sort > $want_submodules
- 9f897b25800d2f54f5c442ef01a60721aeca6d87 third_party/boringssl (version_for_cocoapods_1.0-67-g9f897b2)
- 05b155ff59114735ec8cd089f669c4c3d8f59029 third_party/gflags (v2.1.0-45-g05b155f)
- c99458533a9b4c743ed51537e25989ea55944908 third_party/googletest (release-1.7.0)
- d5fb408ddc281ffcadeb08699e65bb694656d0bd third_party/protobuf (v3.0.0-beta-2)
- 50893291621658f355bc5b4d450a8d06a563053d third_party/zlib (v1.2.8)
-EOF
-
-diff -u $submodules $want_submodules
-
-rm $submodules $want_submodules
-
+RUN yum clean all && yum update -y && yum install -y python python-pip
diff --git a/tools/run_tests/check_submodules.sh b/tools/dockerfile/distribtest/python_fedora21_x64/Dockerfile
old mode 100755
new mode 100644
similarity index 66%
copy from tools/run_tests/check_submodules.sh
copy to tools/dockerfile/distribtest/python_fedora21_x64/Dockerfile
index b4ca4fa..b44fcff
--- a/tools/run_tests/check_submodules.sh
+++ b/tools/dockerfile/distribtest/python_fedora21_x64/Dockerfile
@@ -1,5 +1,3 @@
-#!/bin/sh
-
 # Copyright 2015-2016, Google Inc.
 # All rights reserved.
 #
@@ -29,26 +27,6 @@
 # (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 fedora:21
 
-set -e
-
-export TEST=true
-
-cd `dirname $0`/../..
-
-submodules=`mktemp /tmp/submXXXXXX`
-want_submodules=`mktemp /tmp/submXXXXXX`
-
-git submodule | awk '{ print $1 }' | sort > $submodules
-cat << EOF | awk '{ print $1 }' | sort > $want_submodules
- 9f897b25800d2f54f5c442ef01a60721aeca6d87 third_party/boringssl (version_for_cocoapods_1.0-67-g9f897b2)
- 05b155ff59114735ec8cd089f669c4c3d8f59029 third_party/gflags (v2.1.0-45-g05b155f)
- c99458533a9b4c743ed51537e25989ea55944908 third_party/googletest (release-1.7.0)
- d5fb408ddc281ffcadeb08699e65bb694656d0bd third_party/protobuf (v3.0.0-beta-2)
- 50893291621658f355bc5b4d450a8d06a563053d third_party/zlib (v1.2.8)
-EOF
-
-diff -u $submodules $want_submodules
-
-rm $submodules $want_submodules
-
+RUN yum clean all && yum update -y && yum install -y python python-pip
diff --git a/tools/run_tests/check_submodules.sh b/tools/dockerfile/distribtest/python_fedora22_x64/Dockerfile
old mode 100755
new mode 100644
similarity index 66%
copy from tools/run_tests/check_submodules.sh
copy to tools/dockerfile/distribtest/python_fedora22_x64/Dockerfile
index b4ca4fa..c641594
--- a/tools/run_tests/check_submodules.sh
+++ b/tools/dockerfile/distribtest/python_fedora22_x64/Dockerfile
@@ -1,5 +1,3 @@
-#!/bin/sh
-
 # Copyright 2015-2016, Google Inc.
 # All rights reserved.
 #
@@ -29,26 +27,6 @@
 # (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 fedora:22
 
-set -e
-
-export TEST=true
-
-cd `dirname $0`/../..
-
-submodules=`mktemp /tmp/submXXXXXX`
-want_submodules=`mktemp /tmp/submXXXXXX`
-
-git submodule | awk '{ print $1 }' | sort > $submodules
-cat << EOF | awk '{ print $1 }' | sort > $want_submodules
- 9f897b25800d2f54f5c442ef01a60721aeca6d87 third_party/boringssl (version_for_cocoapods_1.0-67-g9f897b2)
- 05b155ff59114735ec8cd089f669c4c3d8f59029 third_party/gflags (v2.1.0-45-g05b155f)
- c99458533a9b4c743ed51537e25989ea55944908 third_party/googletest (release-1.7.0)
- d5fb408ddc281ffcadeb08699e65bb694656d0bd third_party/protobuf (v3.0.0-beta-2)
- 50893291621658f355bc5b4d450a8d06a563053d third_party/zlib (v1.2.8)
-EOF
-
-diff -u $submodules $want_submodules
-
-rm $submodules $want_submodules
-
+RUN yum clean all && yum update -y && yum install -y python python-pip
diff --git a/tools/run_tests/check_submodules.sh b/tools/dockerfile/distribtest/python_fedora23_x64/Dockerfile
old mode 100755
new mode 100644
similarity index 66%
copy from tools/run_tests/check_submodules.sh
copy to tools/dockerfile/distribtest/python_fedora23_x64/Dockerfile
index b4ca4fa..6c834d2
--- a/tools/run_tests/check_submodules.sh
+++ b/tools/dockerfile/distribtest/python_fedora23_x64/Dockerfile
@@ -1,5 +1,3 @@
-#!/bin/sh
-
 # Copyright 2015-2016, Google Inc.
 # All rights reserved.
 #
@@ -29,26 +27,6 @@
 # (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 fedora:23
 
-set -e
-
-export TEST=true
-
-cd `dirname $0`/../..
-
-submodules=`mktemp /tmp/submXXXXXX`
-want_submodules=`mktemp /tmp/submXXXXXX`
-
-git submodule | awk '{ print $1 }' | sort > $submodules
-cat << EOF | awk '{ print $1 }' | sort > $want_submodules
- 9f897b25800d2f54f5c442ef01a60721aeca6d87 third_party/boringssl (version_for_cocoapods_1.0-67-g9f897b2)
- 05b155ff59114735ec8cd089f669c4c3d8f59029 third_party/gflags (v2.1.0-45-g05b155f)
- c99458533a9b4c743ed51537e25989ea55944908 third_party/googletest (release-1.7.0)
- d5fb408ddc281ffcadeb08699e65bb694656d0bd third_party/protobuf (v3.0.0-beta-2)
- 50893291621658f355bc5b4d450a8d06a563053d third_party/zlib (v1.2.8)
-EOF
-
-diff -u $submodules $want_submodules
-
-rm $submodules $want_submodules
-
+RUN yum clean all && yum update -y && yum install -y python python-pip
diff --git a/tools/run_tests/check_submodules.sh b/tools/dockerfile/distribtest/python_jessie_x64/Dockerfile
old mode 100755
new mode 100644
similarity index 66%
copy from tools/run_tests/check_submodules.sh
copy to tools/dockerfile/distribtest/python_jessie_x64/Dockerfile
index b4ca4fa..5778d60
--- a/tools/run_tests/check_submodules.sh
+++ b/tools/dockerfile/distribtest/python_jessie_x64/Dockerfile
@@ -1,5 +1,3 @@
-#!/bin/sh
-
 # Copyright 2015-2016, Google Inc.
 # All rights reserved.
 #
@@ -29,26 +27,6 @@
 # (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
 
-set -e
-
-export TEST=true
-
-cd `dirname $0`/../..
-
-submodules=`mktemp /tmp/submXXXXXX`
-want_submodules=`mktemp /tmp/submXXXXXX`
-
-git submodule | awk '{ print $1 }' | sort > $submodules
-cat << EOF | awk '{ print $1 }' | sort > $want_submodules
- 9f897b25800d2f54f5c442ef01a60721aeca6d87 third_party/boringssl (version_for_cocoapods_1.0-67-g9f897b2)
- 05b155ff59114735ec8cd089f669c4c3d8f59029 third_party/gflags (v2.1.0-45-g05b155f)
- c99458533a9b4c743ed51537e25989ea55944908 third_party/googletest (release-1.7.0)
- d5fb408ddc281ffcadeb08699e65bb694656d0bd third_party/protobuf (v3.0.0-beta-2)
- 50893291621658f355bc5b4d450a8d06a563053d third_party/zlib (v1.2.8)
-EOF
-
-diff -u $submodules $want_submodules
-
-rm $submodules $want_submodules
-
+RUN apt-get update && apt-get install -y python python-pip
diff --git a/tools/run_tests/check_submodules.sh b/tools/dockerfile/distribtest/python_jessie_x86/Dockerfile
old mode 100755
new mode 100644
similarity index 66%
copy from tools/run_tests/check_submodules.sh
copy to tools/dockerfile/distribtest/python_jessie_x86/Dockerfile
index b4ca4fa..e9cf991
--- a/tools/run_tests/check_submodules.sh
+++ b/tools/dockerfile/distribtest/python_jessie_x86/Dockerfile
@@ -1,5 +1,3 @@
-#!/bin/sh
-
 # Copyright 2015-2016, Google Inc.
 # All rights reserved.
 #
@@ -29,26 +27,11 @@
 # (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 32bit/debian:jessie
 
-set -e
+RUN apt-get update && apt-get install -y python python-pip
 
-export TEST=true
-
-cd `dirname $0`/../..
-
-submodules=`mktemp /tmp/submXXXXXX`
-want_submodules=`mktemp /tmp/submXXXXXX`
-
-git submodule | awk '{ print $1 }' | sort > $submodules
-cat << EOF | awk '{ print $1 }' | sort > $want_submodules
- 9f897b25800d2f54f5c442ef01a60721aeca6d87 third_party/boringssl (version_for_cocoapods_1.0-67-g9f897b2)
- 05b155ff59114735ec8cd089f669c4c3d8f59029 third_party/gflags (v2.1.0-45-g05b155f)
- c99458533a9b4c743ed51537e25989ea55944908 third_party/googletest (release-1.7.0)
- d5fb408ddc281ffcadeb08699e65bb694656d0bd third_party/protobuf (v3.0.0-beta-2)
- 50893291621658f355bc5b4d450a8d06a563053d third_party/zlib (v1.2.8)
-EOF
-
-diff -u $submodules $want_submodules
-
-rm $submodules $want_submodules
-
+# docker is running on a 64-bit machine, so we need to
+# override "uname -m" to report i686 instead of x86_64, otherwise
+# python will choose a wrong binary package to install.
+ENTRYPOINT ["linux32"]
diff --git a/tools/run_tests/check_submodules.sh b/tools/dockerfile/distribtest/python_opensuse_x64/Dockerfile
old mode 100755
new mode 100644
similarity index 66%
copy from tools/run_tests/check_submodules.sh
copy to tools/dockerfile/distribtest/python_opensuse_x64/Dockerfile
index b4ca4fa..ea5d4c7
--- a/tools/run_tests/check_submodules.sh
+++ b/tools/dockerfile/distribtest/python_opensuse_x64/Dockerfile
@@ -1,5 +1,3 @@
-#!/bin/sh
-
 # Copyright 2015-2016, Google Inc.
 # All rights reserved.
 #
@@ -29,26 +27,14 @@
 # (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 opensuse:42.1
 
-set -e
+RUN zypper --non-interactive install python
+RUN zypper --non-interactive install python-pip
 
-export TEST=true
+# "which" command required by python's run_distrib_test.sh
+RUN zypper --non-interactive install which
 
-cd `dirname $0`/../..
-
-submodules=`mktemp /tmp/submXXXXXX`
-want_submodules=`mktemp /tmp/submXXXXXX`
-
-git submodule | awk '{ print $1 }' | sort > $submodules
-cat << EOF | awk '{ print $1 }' | sort > $want_submodules
- 9f897b25800d2f54f5c442ef01a60721aeca6d87 third_party/boringssl (version_for_cocoapods_1.0-67-g9f897b2)
- 05b155ff59114735ec8cd089f669c4c3d8f59029 third_party/gflags (v2.1.0-45-g05b155f)
- c99458533a9b4c743ed51537e25989ea55944908 third_party/googletest (release-1.7.0)
- d5fb408ddc281ffcadeb08699e65bb694656d0bd third_party/protobuf (v3.0.0-beta-2)
- 50893291621658f355bc5b4d450a8d06a563053d third_party/zlib (v1.2.8)
-EOF
-
-diff -u $submodules $want_submodules
-
-rm $submodules $want_submodules
-
+# Without this, pip won't be able to connect to
+# https://pypi.python.org/simple/
+RUN zypper --non-interactive install ca-certificates-mozilla
diff --git a/tools/run_tests/check_submodules.sh b/tools/dockerfile/distribtest/python_ubuntu1204_x64/Dockerfile
old mode 100755
new mode 100644
similarity index 66%
copy from tools/run_tests/check_submodules.sh
copy to tools/dockerfile/distribtest/python_ubuntu1204_x64/Dockerfile
index b4ca4fa..a48ce0e
--- a/tools/run_tests/check_submodules.sh
+++ b/tools/dockerfile/distribtest/python_ubuntu1204_x64/Dockerfile
@@ -1,5 +1,3 @@
-#!/bin/sh
-
 # Copyright 2015-2016, Google Inc.
 # All rights reserved.
 #
@@ -29,26 +27,6 @@
 # (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 ubuntu:12.04
 
-set -e
-
-export TEST=true
-
-cd `dirname $0`/../..
-
-submodules=`mktemp /tmp/submXXXXXX`
-want_submodules=`mktemp /tmp/submXXXXXX`
-
-git submodule | awk '{ print $1 }' | sort > $submodules
-cat << EOF | awk '{ print $1 }' | sort > $want_submodules
- 9f897b25800d2f54f5c442ef01a60721aeca6d87 third_party/boringssl (version_for_cocoapods_1.0-67-g9f897b2)
- 05b155ff59114735ec8cd089f669c4c3d8f59029 third_party/gflags (v2.1.0-45-g05b155f)
- c99458533a9b4c743ed51537e25989ea55944908 third_party/googletest (release-1.7.0)
- d5fb408ddc281ffcadeb08699e65bb694656d0bd third_party/protobuf (v3.0.0-beta-2)
- 50893291621658f355bc5b4d450a8d06a563053d third_party/zlib (v1.2.8)
-EOF
-
-diff -u $submodules $want_submodules
-
-rm $submodules $want_submodules
-
+RUN apt-get update -y && apt-get install -y python python-pip
diff --git a/tools/run_tests/check_submodules.sh b/tools/dockerfile/distribtest/python_ubuntu1404_x64/Dockerfile
old mode 100755
new mode 100644
similarity index 66%
copy from tools/run_tests/check_submodules.sh
copy to tools/dockerfile/distribtest/python_ubuntu1404_x64/Dockerfile
index b4ca4fa..18dbfd4
--- a/tools/run_tests/check_submodules.sh
+++ b/tools/dockerfile/distribtest/python_ubuntu1404_x64/Dockerfile
@@ -1,5 +1,3 @@
-#!/bin/sh
-
 # Copyright 2015-2016, Google Inc.
 # All rights reserved.
 #
@@ -29,26 +27,6 @@
 # (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 ubuntu:14.04
 
-set -e
-
-export TEST=true
-
-cd `dirname $0`/../..
-
-submodules=`mktemp /tmp/submXXXXXX`
-want_submodules=`mktemp /tmp/submXXXXXX`
-
-git submodule | awk '{ print $1 }' | sort > $submodules
-cat << EOF | awk '{ print $1 }' | sort > $want_submodules
- 9f897b25800d2f54f5c442ef01a60721aeca6d87 third_party/boringssl (version_for_cocoapods_1.0-67-g9f897b2)
- 05b155ff59114735ec8cd089f669c4c3d8f59029 third_party/gflags (v2.1.0-45-g05b155f)
- c99458533a9b4c743ed51537e25989ea55944908 third_party/googletest (release-1.7.0)
- d5fb408ddc281ffcadeb08699e65bb694656d0bd third_party/protobuf (v3.0.0-beta-2)
- 50893291621658f355bc5b4d450a8d06a563053d third_party/zlib (v1.2.8)
-EOF
-
-diff -u $submodules $want_submodules
-
-rm $submodules $want_submodules
-
+RUN apt-get update -y && apt-get install -y python python-pip
diff --git a/tools/run_tests/check_submodules.sh b/tools/dockerfile/distribtest/python_ubuntu1504_x64/Dockerfile
old mode 100755
new mode 100644
similarity index 66%
copy from tools/run_tests/check_submodules.sh
copy to tools/dockerfile/distribtest/python_ubuntu1504_x64/Dockerfile
index b4ca4fa..444a54d
--- a/tools/run_tests/check_submodules.sh
+++ b/tools/dockerfile/distribtest/python_ubuntu1504_x64/Dockerfile
@@ -1,5 +1,3 @@
-#!/bin/sh
-
 # Copyright 2015-2016, Google Inc.
 # All rights reserved.
 #
@@ -29,26 +27,6 @@
 # (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 ubuntu:15.04
 
-set -e
-
-export TEST=true
-
-cd `dirname $0`/../..
-
-submodules=`mktemp /tmp/submXXXXXX`
-want_submodules=`mktemp /tmp/submXXXXXX`
-
-git submodule | awk '{ print $1 }' | sort > $submodules
-cat << EOF | awk '{ print $1 }' | sort > $want_submodules
- 9f897b25800d2f54f5c442ef01a60721aeca6d87 third_party/boringssl (version_for_cocoapods_1.0-67-g9f897b2)
- 05b155ff59114735ec8cd089f669c4c3d8f59029 third_party/gflags (v2.1.0-45-g05b155f)
- c99458533a9b4c743ed51537e25989ea55944908 third_party/googletest (release-1.7.0)
- d5fb408ddc281ffcadeb08699e65bb694656d0bd third_party/protobuf (v3.0.0-beta-2)
- 50893291621658f355bc5b4d450a8d06a563053d third_party/zlib (v1.2.8)
-EOF
-
-diff -u $submodules $want_submodules
-
-rm $submodules $want_submodules
-
+RUN apt-get update -y && apt-get install -y python python-pip
diff --git a/tools/run_tests/check_submodules.sh b/tools/dockerfile/distribtest/python_ubuntu1510_x64/Dockerfile
old mode 100755
new mode 100644
similarity index 66%
copy from tools/run_tests/check_submodules.sh
copy to tools/dockerfile/distribtest/python_ubuntu1510_x64/Dockerfile
index b4ca4fa..245ffb9
--- a/tools/run_tests/check_submodules.sh
+++ b/tools/dockerfile/distribtest/python_ubuntu1510_x64/Dockerfile
@@ -1,5 +1,3 @@
-#!/bin/sh
-
 # Copyright 2015-2016, Google Inc.
 # All rights reserved.
 #
@@ -29,26 +27,6 @@
 # (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 ubuntu:15.10
 
-set -e
-
-export TEST=true
-
-cd `dirname $0`/../..
-
-submodules=`mktemp /tmp/submXXXXXX`
-want_submodules=`mktemp /tmp/submXXXXXX`
-
-git submodule | awk '{ print $1 }' | sort > $submodules
-cat << EOF | awk '{ print $1 }' | sort > $want_submodules
- 9f897b25800d2f54f5c442ef01a60721aeca6d87 third_party/boringssl (version_for_cocoapods_1.0-67-g9f897b2)
- 05b155ff59114735ec8cd089f669c4c3d8f59029 third_party/gflags (v2.1.0-45-g05b155f)
- c99458533a9b4c743ed51537e25989ea55944908 third_party/googletest (release-1.7.0)
- d5fb408ddc281ffcadeb08699e65bb694656d0bd third_party/protobuf (v3.0.0-beta-2)
- 50893291621658f355bc5b4d450a8d06a563053d third_party/zlib (v1.2.8)
-EOF
-
-diff -u $submodules $want_submodules
-
-rm $submodules $want_submodules
-
+RUN apt-get update -y && apt-get install -y python python-pip
diff --git a/tools/run_tests/check_submodules.sh b/tools/dockerfile/distribtest/python_ubuntu1604_x64/Dockerfile
old mode 100755
new mode 100644
similarity index 66%
copy from tools/run_tests/check_submodules.sh
copy to tools/dockerfile/distribtest/python_ubuntu1604_x64/Dockerfile
index b4ca4fa..a1ac305
--- a/tools/run_tests/check_submodules.sh
+++ b/tools/dockerfile/distribtest/python_ubuntu1604_x64/Dockerfile
@@ -1,5 +1,3 @@
-#!/bin/sh
-
 # Copyright 2015-2016, Google Inc.
 # All rights reserved.
 #
@@ -29,26 +27,6 @@
 # (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 ubuntu:16.04
 
-set -e
-
-export TEST=true
-
-cd `dirname $0`/../..
-
-submodules=`mktemp /tmp/submXXXXXX`
-want_submodules=`mktemp /tmp/submXXXXXX`
-
-git submodule | awk '{ print $1 }' | sort > $submodules
-cat << EOF | awk '{ print $1 }' | sort > $want_submodules
- 9f897b25800d2f54f5c442ef01a60721aeca6d87 third_party/boringssl (version_for_cocoapods_1.0-67-g9f897b2)
- 05b155ff59114735ec8cd089f669c4c3d8f59029 third_party/gflags (v2.1.0-45-g05b155f)
- c99458533a9b4c743ed51537e25989ea55944908 third_party/googletest (release-1.7.0)
- d5fb408ddc281ffcadeb08699e65bb694656d0bd third_party/protobuf (v3.0.0-beta-2)
- 50893291621658f355bc5b4d450a8d06a563053d third_party/zlib (v1.2.8)
-EOF
-
-diff -u $submodules $want_submodules
-
-rm $submodules $want_submodules
-
+RUN apt-get update -y && apt-get install -y python python-pip
diff --git a/tools/run_tests/check_submodules.sh b/tools/dockerfile/distribtest/python_wheezy_x64/Dockerfile
old mode 100755
new mode 100644
similarity index 66%
copy from tools/run_tests/check_submodules.sh
copy to tools/dockerfile/distribtest/python_wheezy_x64/Dockerfile
index b4ca4fa..46353b9
--- a/tools/run_tests/check_submodules.sh
+++ b/tools/dockerfile/distribtest/python_wheezy_x64/Dockerfile
@@ -1,5 +1,3 @@
-#!/bin/sh
-
 # Copyright 2015-2016, Google Inc.
 # All rights reserved.
 #
@@ -29,26 +27,6 @@
 # (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:wheezy
 
-set -e
-
-export TEST=true
-
-cd `dirname $0`/../..
-
-submodules=`mktemp /tmp/submXXXXXX`
-want_submodules=`mktemp /tmp/submXXXXXX`
-
-git submodule | awk '{ print $1 }' | sort > $submodules
-cat << EOF | awk '{ print $1 }' | sort > $want_submodules
- 9f897b25800d2f54f5c442ef01a60721aeca6d87 third_party/boringssl (version_for_cocoapods_1.0-67-g9f897b2)
- 05b155ff59114735ec8cd089f669c4c3d8f59029 third_party/gflags (v2.1.0-45-g05b155f)
- c99458533a9b4c743ed51537e25989ea55944908 third_party/googletest (release-1.7.0)
- d5fb408ddc281ffcadeb08699e65bb694656d0bd third_party/protobuf (v3.0.0-beta-2)
- 50893291621658f355bc5b4d450a8d06a563053d third_party/zlib (v1.2.8)
-EOF
-
-diff -u $submodules $want_submodules
-
-rm $submodules $want_submodules
-
+RUN apt-get update -y && apt-get install -y python python-pip
diff --git a/tools/run_tests/check_submodules.sh b/tools/dockerfile/distribtest/ruby_centos6_x64/Dockerfile
old mode 100755
new mode 100644
similarity index 66%
copy from tools/run_tests/check_submodules.sh
copy to tools/dockerfile/distribtest/ruby_centos6_x64/Dockerfile
index b4ca4fa..f65b869
--- a/tools/run_tests/check_submodules.sh
+++ b/tools/dockerfile/distribtest/ruby_centos6_x64/Dockerfile
@@ -1,5 +1,3 @@
-#!/bin/sh
-
 # Copyright 2015-2016, Google Inc.
 # All rights reserved.
 #
@@ -29,26 +27,15 @@
 # (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 centos:6
 
-set -e
+RUN yum install -y curl
 
-export TEST=true
+RUN yum install -y tar which
 
-cd `dirname $0`/../..
+# Install rvm
+RUN gpg --keyserver hkp://keys.gnupg.net --recv-keys 409B6B1796C275462A1703113804BB82D39DC0E3
+RUN \curl -sSL https://get.rvm.io | bash -s stable --ruby
 
-submodules=`mktemp /tmp/submXXXXXX`
-want_submodules=`mktemp /tmp/submXXXXXX`
-
-git submodule | awk '{ print $1 }' | sort > $submodules
-cat << EOF | awk '{ print $1 }' | sort > $want_submodules
- 9f897b25800d2f54f5c442ef01a60721aeca6d87 third_party/boringssl (version_for_cocoapods_1.0-67-g9f897b2)
- 05b155ff59114735ec8cd089f669c4c3d8f59029 third_party/gflags (v2.1.0-45-g05b155f)
- c99458533a9b4c743ed51537e25989ea55944908 third_party/googletest (release-1.7.0)
- d5fb408ddc281ffcadeb08699e65bb694656d0bd third_party/protobuf (v3.0.0-beta-2)
- 50893291621658f355bc5b4d450a8d06a563053d third_party/zlib (v1.2.8)
-EOF
-
-diff -u $submodules $want_submodules
-
-rm $submodules $want_submodules
-
+RUN /bin/bash -l -c "echo '. /etc/profile.d/rvm.sh' >> ~/.bashrc"
+RUN /bin/bash -l -c "gem install --update bundler"
diff --git a/tools/run_tests/check_submodules.sh b/tools/dockerfile/distribtest/ruby_centos7_x64/Dockerfile
old mode 100755
new mode 100644
similarity index 66%
copy from tools/run_tests/check_submodules.sh
copy to tools/dockerfile/distribtest/ruby_centos7_x64/Dockerfile
index b4ca4fa..8565020
--- a/tools/run_tests/check_submodules.sh
+++ b/tools/dockerfile/distribtest/ruby_centos7_x64/Dockerfile
@@ -1,5 +1,3 @@
-#!/bin/sh
-
 # Copyright 2015-2016, Google Inc.
 # All rights reserved.
 #
@@ -29,26 +27,8 @@
 # (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 centos:7
 
-set -e
+RUN yum install -y ruby
 
-export TEST=true
-
-cd `dirname $0`/../..
-
-submodules=`mktemp /tmp/submXXXXXX`
-want_submodules=`mktemp /tmp/submXXXXXX`
-
-git submodule | awk '{ print $1 }' | sort > $submodules
-cat << EOF | awk '{ print $1 }' | sort > $want_submodules
- 9f897b25800d2f54f5c442ef01a60721aeca6d87 third_party/boringssl (version_for_cocoapods_1.0-67-g9f897b2)
- 05b155ff59114735ec8cd089f669c4c3d8f59029 third_party/gflags (v2.1.0-45-g05b155f)
- c99458533a9b4c743ed51537e25989ea55944908 third_party/googletest (release-1.7.0)
- d5fb408ddc281ffcadeb08699e65bb694656d0bd third_party/protobuf (v3.0.0-beta-2)
- 50893291621658f355bc5b4d450a8d06a563053d third_party/zlib (v1.2.8)
-EOF
-
-diff -u $submodules $want_submodules
-
-rm $submodules $want_submodules
-
+RUN gem install bundler
diff --git a/tools/run_tests/check_submodules.sh b/tools/dockerfile/distribtest/ruby_fedora20_x64/Dockerfile
old mode 100755
new mode 100644
similarity index 66%
copy from tools/run_tests/check_submodules.sh
copy to tools/dockerfile/distribtest/ruby_fedora20_x64/Dockerfile
index b4ca4fa..437337e
--- a/tools/run_tests/check_submodules.sh
+++ b/tools/dockerfile/distribtest/ruby_fedora20_x64/Dockerfile
@@ -1,5 +1,3 @@
-#!/bin/sh
-
 # Copyright 2015-2016, Google Inc.
 # All rights reserved.
 #
@@ -29,26 +27,8 @@
 # (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 fedora:20
 
-set -e
+RUN yum clean all && yum update -y && yum install -y ruby
 
-export TEST=true
-
-cd `dirname $0`/../..
-
-submodules=`mktemp /tmp/submXXXXXX`
-want_submodules=`mktemp /tmp/submXXXXXX`
-
-git submodule | awk '{ print $1 }' | sort > $submodules
-cat << EOF | awk '{ print $1 }' | sort > $want_submodules
- 9f897b25800d2f54f5c442ef01a60721aeca6d87 third_party/boringssl (version_for_cocoapods_1.0-67-g9f897b2)
- 05b155ff59114735ec8cd089f669c4c3d8f59029 third_party/gflags (v2.1.0-45-g05b155f)
- c99458533a9b4c743ed51537e25989ea55944908 third_party/googletest (release-1.7.0)
- d5fb408ddc281ffcadeb08699e65bb694656d0bd third_party/protobuf (v3.0.0-beta-2)
- 50893291621658f355bc5b4d450a8d06a563053d third_party/zlib (v1.2.8)
-EOF
-
-diff -u $submodules $want_submodules
-
-rm $submodules $want_submodules
-
+RUN gem install bundler
diff --git a/tools/run_tests/check_submodules.sh b/tools/dockerfile/distribtest/ruby_fedora21_x64/Dockerfile
old mode 100755
new mode 100644
similarity index 66%
copy from tools/run_tests/check_submodules.sh
copy to tools/dockerfile/distribtest/ruby_fedora21_x64/Dockerfile
index b4ca4fa..598dac5
--- a/tools/run_tests/check_submodules.sh
+++ b/tools/dockerfile/distribtest/ruby_fedora21_x64/Dockerfile
@@ -1,5 +1,3 @@
-#!/bin/sh
-
 # Copyright 2015-2016, Google Inc.
 # All rights reserved.
 #
@@ -29,26 +27,8 @@
 # (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 fedora:21
 
-set -e
+RUN yum clean all && yum update -y && yum install -y ruby
 
-export TEST=true
-
-cd `dirname $0`/../..
-
-submodules=`mktemp /tmp/submXXXXXX`
-want_submodules=`mktemp /tmp/submXXXXXX`
-
-git submodule | awk '{ print $1 }' | sort > $submodules
-cat << EOF | awk '{ print $1 }' | sort > $want_submodules
- 9f897b25800d2f54f5c442ef01a60721aeca6d87 third_party/boringssl (version_for_cocoapods_1.0-67-g9f897b2)
- 05b155ff59114735ec8cd089f669c4c3d8f59029 third_party/gflags (v2.1.0-45-g05b155f)
- c99458533a9b4c743ed51537e25989ea55944908 third_party/googletest (release-1.7.0)
- d5fb408ddc281ffcadeb08699e65bb694656d0bd third_party/protobuf (v3.0.0-beta-2)
- 50893291621658f355bc5b4d450a8d06a563053d third_party/zlib (v1.2.8)
-EOF
-
-diff -u $submodules $want_submodules
-
-rm $submodules $want_submodules
-
+RUN gem install bundler
diff --git a/tools/run_tests/check_submodules.sh b/tools/dockerfile/distribtest/ruby_fedora22_x64/Dockerfile
old mode 100755
new mode 100644
similarity index 66%
copy from tools/run_tests/check_submodules.sh
copy to tools/dockerfile/distribtest/ruby_fedora22_x64/Dockerfile
index b4ca4fa..58d3d93
--- a/tools/run_tests/check_submodules.sh
+++ b/tools/dockerfile/distribtest/ruby_fedora22_x64/Dockerfile
@@ -1,5 +1,3 @@
-#!/bin/sh
-
 # Copyright 2015-2016, Google Inc.
 # All rights reserved.
 #
@@ -29,26 +27,8 @@
 # (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 fedora:22
 
-set -e
+RUN yum clean all && yum update -y && yum install -y ruby
 
-export TEST=true
-
-cd `dirname $0`/../..
-
-submodules=`mktemp /tmp/submXXXXXX`
-want_submodules=`mktemp /tmp/submXXXXXX`
-
-git submodule | awk '{ print $1 }' | sort > $submodules
-cat << EOF | awk '{ print $1 }' | sort > $want_submodules
- 9f897b25800d2f54f5c442ef01a60721aeca6d87 third_party/boringssl (version_for_cocoapods_1.0-67-g9f897b2)
- 05b155ff59114735ec8cd089f669c4c3d8f59029 third_party/gflags (v2.1.0-45-g05b155f)
- c99458533a9b4c743ed51537e25989ea55944908 third_party/googletest (release-1.7.0)
- d5fb408ddc281ffcadeb08699e65bb694656d0bd third_party/protobuf (v3.0.0-beta-2)
- 50893291621658f355bc5b4d450a8d06a563053d third_party/zlib (v1.2.8)
-EOF
-
-diff -u $submodules $want_submodules
-
-rm $submodules $want_submodules
-
+RUN gem install bundler
diff --git a/tools/run_tests/check_submodules.sh b/tools/dockerfile/distribtest/ruby_fedora23_x64/Dockerfile
old mode 100755
new mode 100644
similarity index 66%
copy from tools/run_tests/check_submodules.sh
copy to tools/dockerfile/distribtest/ruby_fedora23_x64/Dockerfile
index b4ca4fa..9f07f51
--- a/tools/run_tests/check_submodules.sh
+++ b/tools/dockerfile/distribtest/ruby_fedora23_x64/Dockerfile
@@ -1,5 +1,3 @@
-#!/bin/sh
-
 # Copyright 2015-2016, Google Inc.
 # All rights reserved.
 #
@@ -29,26 +27,8 @@
 # (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 fedora:23
 
-set -e
+RUN yum clean all && yum update -y && yum install -y ruby
 
-export TEST=true
-
-cd `dirname $0`/../..
-
-submodules=`mktemp /tmp/submXXXXXX`
-want_submodules=`mktemp /tmp/submXXXXXX`
-
-git submodule | awk '{ print $1 }' | sort > $submodules
-cat << EOF | awk '{ print $1 }' | sort > $want_submodules
- 9f897b25800d2f54f5c442ef01a60721aeca6d87 third_party/boringssl (version_for_cocoapods_1.0-67-g9f897b2)
- 05b155ff59114735ec8cd089f669c4c3d8f59029 third_party/gflags (v2.1.0-45-g05b155f)
- c99458533a9b4c743ed51537e25989ea55944908 third_party/googletest (release-1.7.0)
- d5fb408ddc281ffcadeb08699e65bb694656d0bd third_party/protobuf (v3.0.0-beta-2)
- 50893291621658f355bc5b4d450a8d06a563053d third_party/zlib (v1.2.8)
-EOF
-
-diff -u $submodules $want_submodules
-
-rm $submodules $want_submodules
-
+RUN gem install bundler
diff --git a/tools/run_tests/check_submodules.sh b/tools/dockerfile/distribtest/ruby_jessie_x64/Dockerfile
old mode 100755
new mode 100644
similarity index 66%
copy from tools/run_tests/check_submodules.sh
copy to tools/dockerfile/distribtest/ruby_jessie_x64/Dockerfile
index b4ca4fa..cc377b7
--- a/tools/run_tests/check_submodules.sh
+++ b/tools/dockerfile/distribtest/ruby_jessie_x64/Dockerfile
@@ -1,5 +1,3 @@
-#!/bin/sh
-
 # Copyright 2015-2016, Google Inc.
 # All rights reserved.
 #
@@ -29,26 +27,8 @@
 # (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
 
-set -e
+RUN apt-get update && apt-get install -y ruby-full
 
-export TEST=true
-
-cd `dirname $0`/../..
-
-submodules=`mktemp /tmp/submXXXXXX`
-want_submodules=`mktemp /tmp/submXXXXXX`
-
-git submodule | awk '{ print $1 }' | sort > $submodules
-cat << EOF | awk '{ print $1 }' | sort > $want_submodules
- 9f897b25800d2f54f5c442ef01a60721aeca6d87 third_party/boringssl (version_for_cocoapods_1.0-67-g9f897b2)
- 05b155ff59114735ec8cd089f669c4c3d8f59029 third_party/gflags (v2.1.0-45-g05b155f)
- c99458533a9b4c743ed51537e25989ea55944908 third_party/googletest (release-1.7.0)
- d5fb408ddc281ffcadeb08699e65bb694656d0bd third_party/protobuf (v3.0.0-beta-2)
- 50893291621658f355bc5b4d450a8d06a563053d third_party/zlib (v1.2.8)
-EOF
-
-diff -u $submodules $want_submodules
-
-rm $submodules $want_submodules
-
+RUN gem install bundler
diff --git a/tools/run_tests/check_submodules.sh b/tools/dockerfile/distribtest/ruby_jessie_x86/Dockerfile
old mode 100755
new mode 100644
similarity index 66%
copy from tools/run_tests/check_submodules.sh
copy to tools/dockerfile/distribtest/ruby_jessie_x86/Dockerfile
index b4ca4fa..3fe3e2b
--- a/tools/run_tests/check_submodules.sh
+++ b/tools/dockerfile/distribtest/ruby_jessie_x86/Dockerfile
@@ -1,5 +1,3 @@
-#!/bin/sh
-
 # Copyright 2015-2016, Google Inc.
 # All rights reserved.
 #
@@ -29,26 +27,8 @@
 # (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 32bit/debian:jessie
 
-set -e
+RUN apt-get update && apt-get install -y ruby-full
 
-export TEST=true
-
-cd `dirname $0`/../..
-
-submodules=`mktemp /tmp/submXXXXXX`
-want_submodules=`mktemp /tmp/submXXXXXX`
-
-git submodule | awk '{ print $1 }' | sort > $submodules
-cat << EOF | awk '{ print $1 }' | sort > $want_submodules
- 9f897b25800d2f54f5c442ef01a60721aeca6d87 third_party/boringssl (version_for_cocoapods_1.0-67-g9f897b2)
- 05b155ff59114735ec8cd089f669c4c3d8f59029 third_party/gflags (v2.1.0-45-g05b155f)
- c99458533a9b4c743ed51537e25989ea55944908 third_party/googletest (release-1.7.0)
- d5fb408ddc281ffcadeb08699e65bb694656d0bd third_party/protobuf (v3.0.0-beta-2)
- 50893291621658f355bc5b4d450a8d06a563053d third_party/zlib (v1.2.8)
-EOF
-
-diff -u $submodules $want_submodules
-
-rm $submodules $want_submodules
-
+RUN gem install bundler
diff --git a/tools/run_tests/check_submodules.sh b/tools/dockerfile/distribtest/ruby_opensuse_x64/Dockerfile
old mode 100755
new mode 100644
similarity index 66%
copy from tools/run_tests/check_submodules.sh
copy to tools/dockerfile/distribtest/ruby_opensuse_x64/Dockerfile
index b4ca4fa..c98d691
--- a/tools/run_tests/check_submodules.sh
+++ b/tools/dockerfile/distribtest/ruby_opensuse_x64/Dockerfile
@@ -1,5 +1,3 @@
-#!/bin/sh
-
 # Copyright 2015-2016, Google Inc.
 # All rights reserved.
 #
@@ -29,26 +27,19 @@
 # (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 opensuse:42.1
 
-set -e
+RUN zypper --non-interactive install curl
 
-export TEST=true
+RUN zypper --non-interactive install tar which
 
-cd `dirname $0`/../..
+RUN zypper --non-interactive install ca-certificates-mozilla
 
-submodules=`mktemp /tmp/submXXXXXX`
-want_submodules=`mktemp /tmp/submXXXXXX`
+# Install rvm
+RUN gpg --keyserver hkp://keys.gnupg.net --recv-keys 409B6B1796C275462A1703113804BB82D39DC0E3
+RUN \curl -sSL https://get.rvm.io | bash -s stable --ruby
 
-git submodule | awk '{ print $1 }' | sort > $submodules
-cat << EOF | awk '{ print $1 }' | sort > $want_submodules
- 9f897b25800d2f54f5c442ef01a60721aeca6d87 third_party/boringssl (version_for_cocoapods_1.0-67-g9f897b2)
- 05b155ff59114735ec8cd089f669c4c3d8f59029 third_party/gflags (v2.1.0-45-g05b155f)
- c99458533a9b4c743ed51537e25989ea55944908 third_party/googletest (release-1.7.0)
- d5fb408ddc281ffcadeb08699e65bb694656d0bd third_party/protobuf (v3.0.0-beta-2)
- 50893291621658f355bc5b4d450a8d06a563053d third_party/zlib (v1.2.8)
-EOF
+# OpenSUSE is a bit crazy and ignores .bashrc for login shell.
+RUN /bin/bash -l -c "echo '. /etc/profile.d/rvm.sh' >> ~/.profile"
 
-diff -u $submodules $want_submodules
-
-rm $submodules $want_submodules
-
+RUN /bin/bash -l -c 'gem install --update bundler'
diff --git a/tools/run_tests/check_submodules.sh b/tools/dockerfile/distribtest/ruby_ubuntu1204_x64/Dockerfile
old mode 100755
new mode 100644
similarity index 66%
copy from tools/run_tests/check_submodules.sh
copy to tools/dockerfile/distribtest/ruby_ubuntu1204_x64/Dockerfile
index b4ca4fa..782368b
--- a/tools/run_tests/check_submodules.sh
+++ b/tools/dockerfile/distribtest/ruby_ubuntu1204_x64/Dockerfile
@@ -1,5 +1,3 @@
-#!/bin/sh
-
 # Copyright 2015-2016, Google Inc.
 # All rights reserved.
 #
@@ -29,26 +27,13 @@
 # (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 ubuntu:12.04
 
-set -e
+RUN apt-get update -y && apt-get install -y curl
 
-export TEST=true
+# Install rvm
+RUN gpg --keyserver hkp://keys.gnupg.net --recv-keys 409B6B1796C275462A1703113804BB82D39DC0E3
+RUN \curl -sSL https://get.rvm.io | bash -s stable --ruby
 
-cd `dirname $0`/../..
-
-submodules=`mktemp /tmp/submXXXXXX`
-want_submodules=`mktemp /tmp/submXXXXXX`
-
-git submodule | awk '{ print $1 }' | sort > $submodules
-cat << EOF | awk '{ print $1 }' | sort > $want_submodules
- 9f897b25800d2f54f5c442ef01a60721aeca6d87 third_party/boringssl (version_for_cocoapods_1.0-67-g9f897b2)
- 05b155ff59114735ec8cd089f669c4c3d8f59029 third_party/gflags (v2.1.0-45-g05b155f)
- c99458533a9b4c743ed51537e25989ea55944908 third_party/googletest (release-1.7.0)
- d5fb408ddc281ffcadeb08699e65bb694656d0bd third_party/protobuf (v3.0.0-beta-2)
- 50893291621658f355bc5b4d450a8d06a563053d third_party/zlib (v1.2.8)
-EOF
-
-diff -u $submodules $want_submodules
-
-rm $submodules $want_submodules
-
+RUN /bin/bash -l -c "echo '. /etc/profile.d/rvm.sh' >> ~/.bashrc"
+RUN /bin/bash -l -c "gem install --update bundler"
diff --git a/tools/run_tests/check_submodules.sh b/tools/dockerfile/distribtest/ruby_ubuntu1404_x64/Dockerfile
old mode 100755
new mode 100644
similarity index 66%
copy from tools/run_tests/check_submodules.sh
copy to tools/dockerfile/distribtest/ruby_ubuntu1404_x64/Dockerfile
index b4ca4fa..53fb4d5
--- a/tools/run_tests/check_submodules.sh
+++ b/tools/dockerfile/distribtest/ruby_ubuntu1404_x64/Dockerfile
@@ -1,5 +1,3 @@
-#!/bin/sh
-
 # Copyright 2015-2016, Google Inc.
 # All rights reserved.
 #
@@ -29,26 +27,13 @@
 # (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 ubuntu:14.04
 
-set -e
+RUN apt-get update -y && apt-get install -y curl
 
-export TEST=true
+# Install rvm
+RUN gpg --keyserver hkp://keys.gnupg.net --recv-keys 409B6B1796C275462A1703113804BB82D39DC0E3
+RUN \curl -sSL https://get.rvm.io | bash -s stable --ruby
 
-cd `dirname $0`/../..
-
-submodules=`mktemp /tmp/submXXXXXX`
-want_submodules=`mktemp /tmp/submXXXXXX`
-
-git submodule | awk '{ print $1 }' | sort > $submodules
-cat << EOF | awk '{ print $1 }' | sort > $want_submodules
- 9f897b25800d2f54f5c442ef01a60721aeca6d87 third_party/boringssl (version_for_cocoapods_1.0-67-g9f897b2)
- 05b155ff59114735ec8cd089f669c4c3d8f59029 third_party/gflags (v2.1.0-45-g05b155f)
- c99458533a9b4c743ed51537e25989ea55944908 third_party/googletest (release-1.7.0)
- d5fb408ddc281ffcadeb08699e65bb694656d0bd third_party/protobuf (v3.0.0-beta-2)
- 50893291621658f355bc5b4d450a8d06a563053d third_party/zlib (v1.2.8)
-EOF
-
-diff -u $submodules $want_submodules
-
-rm $submodules $want_submodules
-
+RUN /bin/bash -l -c "echo '. /etc/profile.d/rvm.sh' >> ~/.bashrc"
+RUN /bin/bash -l -c "gem install --update bundler"
diff --git a/tools/run_tests/check_submodules.sh b/tools/dockerfile/distribtest/ruby_ubuntu1504_x64/Dockerfile
old mode 100755
new mode 100644
similarity index 66%
copy from tools/run_tests/check_submodules.sh
copy to tools/dockerfile/distribtest/ruby_ubuntu1504_x64/Dockerfile
index b4ca4fa..3225166
--- a/tools/run_tests/check_submodules.sh
+++ b/tools/dockerfile/distribtest/ruby_ubuntu1504_x64/Dockerfile
@@ -1,5 +1,3 @@
-#!/bin/sh
-
 # Copyright 2015-2016, Google Inc.
 # All rights reserved.
 #
@@ -29,26 +27,8 @@
 # (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 ubuntu:15.04
 
-set -e
+RUN apt-get update -y && apt-get install -y ruby-full
 
-export TEST=true
-
-cd `dirname $0`/../..
-
-submodules=`mktemp /tmp/submXXXXXX`
-want_submodules=`mktemp /tmp/submXXXXXX`
-
-git submodule | awk '{ print $1 }' | sort > $submodules
-cat << EOF | awk '{ print $1 }' | sort > $want_submodules
- 9f897b25800d2f54f5c442ef01a60721aeca6d87 third_party/boringssl (version_for_cocoapods_1.0-67-g9f897b2)
- 05b155ff59114735ec8cd089f669c4c3d8f59029 third_party/gflags (v2.1.0-45-g05b155f)
- c99458533a9b4c743ed51537e25989ea55944908 third_party/googletest (release-1.7.0)
- d5fb408ddc281ffcadeb08699e65bb694656d0bd third_party/protobuf (v3.0.0-beta-2)
- 50893291621658f355bc5b4d450a8d06a563053d third_party/zlib (v1.2.8)
-EOF
-
-diff -u $submodules $want_submodules
-
-rm $submodules $want_submodules
-
+RUN gem install bundler
diff --git a/tools/run_tests/check_submodules.sh b/tools/dockerfile/distribtest/ruby_ubuntu1510_x64/Dockerfile
old mode 100755
new mode 100644
similarity index 66%
copy from tools/run_tests/check_submodules.sh
copy to tools/dockerfile/distribtest/ruby_ubuntu1510_x64/Dockerfile
index b4ca4fa..df93360
--- a/tools/run_tests/check_submodules.sh
+++ b/tools/dockerfile/distribtest/ruby_ubuntu1510_x64/Dockerfile
@@ -1,5 +1,3 @@
-#!/bin/sh
-
 # Copyright 2015-2016, Google Inc.
 # All rights reserved.
 #
@@ -29,26 +27,8 @@
 # (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 ubuntu:15.10
 
-set -e
+RUN apt-get update -y && apt-get install -y ruby-full
 
-export TEST=true
-
-cd `dirname $0`/../..
-
-submodules=`mktemp /tmp/submXXXXXX`
-want_submodules=`mktemp /tmp/submXXXXXX`
-
-git submodule | awk '{ print $1 }' | sort > $submodules
-cat << EOF | awk '{ print $1 }' | sort > $want_submodules
- 9f897b25800d2f54f5c442ef01a60721aeca6d87 third_party/boringssl (version_for_cocoapods_1.0-67-g9f897b2)
- 05b155ff59114735ec8cd089f669c4c3d8f59029 third_party/gflags (v2.1.0-45-g05b155f)
- c99458533a9b4c743ed51537e25989ea55944908 third_party/googletest (release-1.7.0)
- d5fb408ddc281ffcadeb08699e65bb694656d0bd third_party/protobuf (v3.0.0-beta-2)
- 50893291621658f355bc5b4d450a8d06a563053d third_party/zlib (v1.2.8)
-EOF
-
-diff -u $submodules $want_submodules
-
-rm $submodules $want_submodules
-
+RUN gem install bundler
diff --git a/tools/run_tests/check_submodules.sh b/tools/dockerfile/distribtest/ruby_ubuntu1604_x64/Dockerfile
old mode 100755
new mode 100644
similarity index 66%
copy from tools/run_tests/check_submodules.sh
copy to tools/dockerfile/distribtest/ruby_ubuntu1604_x64/Dockerfile
index b4ca4fa..f0c2e80
--- a/tools/run_tests/check_submodules.sh
+++ b/tools/dockerfile/distribtest/ruby_ubuntu1604_x64/Dockerfile
@@ -1,5 +1,3 @@
-#!/bin/sh
-
 # Copyright 2015-2016, Google Inc.
 # All rights reserved.
 #
@@ -29,26 +27,8 @@
 # (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 ubuntu:16.04
 
-set -e
+RUN apt-get update -y && apt-get install -y ruby-full
 
-export TEST=true
-
-cd `dirname $0`/../..
-
-submodules=`mktemp /tmp/submXXXXXX`
-want_submodules=`mktemp /tmp/submXXXXXX`
-
-git submodule | awk '{ print $1 }' | sort > $submodules
-cat << EOF | awk '{ print $1 }' | sort > $want_submodules
- 9f897b25800d2f54f5c442ef01a60721aeca6d87 third_party/boringssl (version_for_cocoapods_1.0-67-g9f897b2)
- 05b155ff59114735ec8cd089f669c4c3d8f59029 third_party/gflags (v2.1.0-45-g05b155f)
- c99458533a9b4c743ed51537e25989ea55944908 third_party/googletest (release-1.7.0)
- d5fb408ddc281ffcadeb08699e65bb694656d0bd third_party/protobuf (v3.0.0-beta-2)
- 50893291621658f355bc5b4d450a8d06a563053d third_party/zlib (v1.2.8)
-EOF
-
-diff -u $submodules $want_submodules
-
-rm $submodules $want_submodules
-
+RUN gem install bundler
diff --git a/tools/run_tests/check_submodules.sh b/tools/dockerfile/distribtest/ruby_wheezy_x64/Dockerfile
old mode 100755
new mode 100644
similarity index 66%
copy from tools/run_tests/check_submodules.sh
copy to tools/dockerfile/distribtest/ruby_wheezy_x64/Dockerfile
index b4ca4fa..ee4e0fc
--- a/tools/run_tests/check_submodules.sh
+++ b/tools/dockerfile/distribtest/ruby_wheezy_x64/Dockerfile
@@ -1,5 +1,3 @@
-#!/bin/sh
-
 # Copyright 2015-2016, Google Inc.
 # All rights reserved.
 #
@@ -29,26 +27,15 @@
 # (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:wheezy
 
-set -e
+RUN apt-get update && apt-get install -y curl
 
-export TEST=true
+RUN apt-get update && apt-get install -y procps
 
-cd `dirname $0`/../..
+# Install rvm
+RUN gpg --keyserver hkp://keys.gnupg.net --recv-keys 409B6B1796C275462A1703113804BB82D39DC0E3
+RUN \curl -sSL https://get.rvm.io | bash -s stable --ruby
 
-submodules=`mktemp /tmp/submXXXXXX`
-want_submodules=`mktemp /tmp/submXXXXXX`
-
-git submodule | awk '{ print $1 }' | sort > $submodules
-cat << EOF | awk '{ print $1 }' | sort > $want_submodules
- 9f897b25800d2f54f5c442ef01a60721aeca6d87 third_party/boringssl (version_for_cocoapods_1.0-67-g9f897b2)
- 05b155ff59114735ec8cd089f669c4c3d8f59029 third_party/gflags (v2.1.0-45-g05b155f)
- c99458533a9b4c743ed51537e25989ea55944908 third_party/googletest (release-1.7.0)
- d5fb408ddc281ffcadeb08699e65bb694656d0bd third_party/protobuf (v3.0.0-beta-2)
- 50893291621658f355bc5b4d450a8d06a563053d third_party/zlib (v1.2.8)
-EOF
-
-diff -u $submodules $want_submodules
-
-rm $submodules $want_submodules
-
+RUN /bin/bash -l -c "echo '. /etc/profile.d/rvm.sh' >> ~/.bashrc"
+RUN /bin/bash -l -c "gem install --update bundler"
diff --git a/tools/dockerfile/grpc_artifact_linux_x64/Dockerfile b/tools/dockerfile/grpc_artifact_linux_x64/Dockerfile
index de40247..41dc427 100644
--- a/tools/dockerfile/grpc_artifact_linux_x64/Dockerfile
+++ b/tools/dockerfile/grpc_artifact_linux_x64/Dockerfile
@@ -58,6 +58,39 @@
   wget \
   zip && apt-get clean
 
+# Install Node dependencies
+RUN touch .profile
+RUN curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.25.4/install.sh | bash
+RUN /bin/bash -l -c "nvm install 4 && npm install -g node-pre-gyp"
+
+##################
+# Python dependencies
+
+RUN apt-get update && apt-get install -y \
+    python-all-dev \
+    python3-all-dev \
+    python-pip
+
+RUN pip install pip --upgrade
+RUN pip install virtualenv
+RUN pip install futures==2.2.0 enum34==1.0.4 protobuf==3.0.0a2 tox
+
+
+##################
+# Ruby dependencies
+
+# Install rvm
+RUN gpg --keyserver hkp://keys.gnupg.net --recv-keys 409B6B1796C275462A1703113804BB82D39DC0E3
+RUN \curl -sSL https://get.rvm.io | bash -s stable
+
+# Install Ruby 2.1
+RUN /bin/bash -l -c "rvm install ruby-2.1"
+RUN /bin/bash -l -c "rvm use --default ruby-2.1"
+RUN /bin/bash -l -c "echo 'gem: --no-ri --no-rdoc' > ~/.gemrc"
+RUN /bin/bash -l -c "echo 'export PATH=/usr/local/rvm/bin:$PATH' >> ~/.bashrc"
+RUN /bin/bash -l -c "echo 'rvm --default use ruby-2.1' >> ~/.bashrc"
+RUN /bin/bash -l -c "gem install bundler --no-ri --no-rdoc"
+
 RUN mkdir /var/local/jenkins
 
 # Define the default command.
diff --git a/tools/dockerfile/grpc_artifact_linux_x86/Dockerfile b/tools/dockerfile/grpc_artifact_linux_x86/Dockerfile
index 774b452..46bc9f8 100644
--- a/tools/dockerfile/grpc_artifact_linux_x86/Dockerfile
+++ b/tools/dockerfile/grpc_artifact_linux_x86/Dockerfile
@@ -58,6 +58,39 @@
   wget \
   zip && apt-get clean
 
+# Install Node dependencies
+RUN touch .profile
+RUN curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.25.4/install.sh | bash
+RUN /bin/bash -l -c "nvm install 4 && npm install -g node-pre-gyp"
+
+##################
+# Python dependencies
+
+RUN apt-get update && apt-get install -y \
+    python-all-dev \
+    python3-all-dev \
+    python-pip
+
+RUN pip install pip --upgrade
+RUN pip install virtualenv
+RUN pip install futures==2.2.0 enum34==1.0.4 protobuf==3.0.0a2 tox
+
+
+##################
+# Ruby dependencies
+
+# Install rvm
+RUN gpg --keyserver hkp://keys.gnupg.net --recv-keys 409B6B1796C275462A1703113804BB82D39DC0E3
+RUN \curl -sSL https://get.rvm.io | bash -s stable
+
+# Install Ruby 2.1
+RUN /bin/bash -l -c "rvm install ruby-2.1"
+RUN /bin/bash -l -c "rvm use --default ruby-2.1"
+RUN /bin/bash -l -c "echo 'gem: --no-ri --no-rdoc' > ~/.gemrc"
+RUN /bin/bash -l -c "echo 'export PATH=/usr/local/rvm/bin:$PATH' >> ~/.bashrc"
+RUN /bin/bash -l -c "echo 'rvm --default use ruby-2.1' >> ~/.bashrc"
+RUN /bin/bash -l -c "gem install bundler --no-ri --no-rdoc"
+
 RUN mkdir /var/local/jenkins
 
 # Define the default command.
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 87445c7..86ba8b2 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
@@ -44,7 +44,7 @@
 do
   for glob in $GLOB
   do
-    files="$files `find /local-code/$dir -name $glob`"
+    files="$files `find /local-code/$dir -name $glob -and -not -name *.generated.*`"
   done
 done
 
diff --git a/tools/dockerfile/grpc_interop_csharp/build_interop.sh b/tools/dockerfile/grpc_interop_csharp/build_interop.sh
index e87fe2f..5ad525f 100755
--- a/tools/dockerfile/grpc_interop_csharp/build_interop.sh
+++ b/tools/dockerfile/grpc_interop_csharp/build_interop.sh
@@ -39,8 +39,6 @@
 
 cd /var/local/git/grpc
 
-make install-certs
-
 # build C# interop client & server
 make CONFIG=dbg grpc_csharp_ext
 (cd src/csharp && mono /var/local/NuGet.exe restore Grpc.sln)
diff --git a/tools/dockerfile/grpc_interop_java/Dockerfile b/tools/dockerfile/grpc_interop_java/Dockerfile
index 5ba5324..8bfb796 100644
--- a/tools/dockerfile/grpc_interop_java/Dockerfile
+++ b/tools/dockerfile/grpc_interop_java/Dockerfile
@@ -51,7 +51,7 @@
 # Trigger download of as many Gradle artifacts as possible.
 RUN git clone --recursive --depth 1 https://github.com/grpc/grpc-java.git && \
   cd grpc-java && \
-  ./gradlew build -PskipCodegen=true && \
+  ./gradlew :grpc-interop-testing:installDist -PskipCodegen=true && \
   rm -r "$(pwd)"
 
 # Define the default command.
diff --git a/tools/dockerfile/grpc_interop_python/build_interop.sh b/tools/dockerfile/grpc_interop_python/build_interop.sh
index 203b012..ed73680 100755
--- a/tools/dockerfile/grpc_interop_python/build_interop.sh
+++ b/tools/dockerfile/grpc_interop_python/build_interop.sh
@@ -39,7 +39,6 @@
 
 cd /var/local/git/grpc
 
-make install-certs
 make
 
 # build Python interop client and server
diff --git a/tools/dockerfile/grpc_interop_ruby/build_interop.sh b/tools/dockerfile/grpc_interop_ruby/build_interop.sh
index 04288bf..84fd499 100755
--- a/tools/dockerfile/grpc_interop_ruby/build_interop.sh
+++ b/tools/dockerfile/grpc_interop_ruby/build_interop.sh
@@ -43,4 +43,4 @@
 make install-certs
 
 # build Ruby interop client and server
-(cd src/ruby && gem update bundler && bundle && rake compile:grpc)
+(cd src/ruby && gem update bundler && bundle && rake compile)
diff --git a/tools/dockerfile/grpc_jenkins_slave_x64/Dockerfile b/tools/dockerfile/grpc_jenkins_slave_x64/Dockerfile
deleted file mode 100644
index 48541b0..0000000
--- a/tools/dockerfile/grpc_jenkins_slave_x64/Dockerfile
+++ /dev/null
@@ -1,172 +0,0 @@
-# Copyright 2015-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.
-
-# A work-in-progress Dockerfile that allows running gRPC test suites
-# inside a docker container.
-
-FROM debian:jessie
-
-# Install Git and basic packages.
-RUN apt-get update && apt-get install -y \
-  autoconf \
-  autotools-dev \
-  build-essential \
-  bzip2 \
-  ccache \
-  curl \
-  gcc \
-  gcc-multilib \
-  git \
-  golang \
-  gyp \
-  lcov \
-  libc6 \
-  libc6-dbg \
-  libc6-dev \
-  libgtest-dev \
-  libtool \
-  make \
-  perl \
-  strace \
-  python-dev \
-  python-setuptools \
-  python-yaml \
-  telnet \
-  unzip \
-  wget \
-  zip && apt-get clean
-
-# 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 ln -s /usr/bin/ccache /usr/local/bin/clang
-RUN ln -s /usr/bin/ccache /usr/local/bin/clang++
-
-##################
-# C++ dependencies
-RUN apt-get update && apt-get -y install libgflags-dev libgtest-dev libc++-dev clang
-
-#################
-# C# dependencies
-
-# Update to a newer version of mono
-RUN apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 3FA7E0328081BFF6A14DA29AA6A19B38D3D831EF
-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 \
-    mono-devel \
-    nunit \
-    nunit-console \
-    monodevelop
-
-# Download NuGet
-RUN cd /var/local && wget www.nuget.org/NuGet.exe
-ENV NUGET mono /var/local/NuGet.exe
-
-# TODO(jtattermusch): add dependencies for other languages
-
-##################
-# Node dependencies
-
-# Install nvm
-RUN touch .profile
-RUN curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.25.4/install.sh | bash
-RUN /bin/bash -l -c "nvm install 0.12 && npm config set cache /tmp/npm-cache"
-
-##################
-# Ruby dependencies
-
-# Install rvm
-RUN gpg --keyserver hkp://keys.gnupg.net --recv-keys 409B6B1796C275462A1703113804BB82D39DC0E3
-RUN \curl -sSL https://get.rvm.io | bash -s stable
-
-# Install Ruby 2.1
-RUN /bin/bash -l -c "rvm install ruby-2.1"
-RUN /bin/bash -l -c "rvm use --default ruby-2.1"
-RUN /bin/bash -l -c "echo 'gem: --no-ri --no-rdoc' > ~/.gemrc"
-RUN /bin/bash -l -c "echo 'export PATH=/usr/local/rvm/bin:$PATH' >> ~/.bashrc"
-RUN /bin/bash -l -c "echo 'rvm --default use ruby-2.1' >> ~/.bashrc"
-RUN /bin/bash -l -c "gem install bundler --no-ri --no-rdoc"
-
-##################
-# Python dependencies
-
-# Install dependencies
-
-RUN apt-get update && apt-get install -y \
-    python-all-dev \
-    python3-all-dev \
-    python-pip
-
-# 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.0.0a2 tox
-
-# For sanity test
-RUN pip install simplejson mako
-
-##################
-# PHP dependencies
-
-# Install dependencies
-
-RUN /bin/bash -l -c "echo 'deb http://packages.dotdeb.org wheezy-php55 all' \
-    >> /etc/apt/sources.list.d/dotdeb.list"
-RUN /bin/bash -l -c "echo 'deb-src http://packages.dotdeb.org wheezy-php55 all' \
-    >> /etc/apt/sources.list.d/dotdeb.list"
-RUN wget http://www.dotdeb.org/dotdeb.gpg -O- | apt-key add -
-
-RUN apt-get update && apt-get install -y \
-    git php5 php5-dev phpunit unzip
-
-##################
-# Zookeeper dependencies
-
-# Install dependencies
-
-RUN apt-get install -y libzookeeper-mt-dev
-
-##################
-# Docker "inception".
-# Note this is quite the ugly hack.
-# This makes sure that the docker binary we inject has its dependencies.
-RUN curl https://get.docker.com/ | sh
-RUN apt-get remove --purge -y docker-engine
-
-RUN mkdir /var/local/jenkins
-
-# Define the default command.
-CMD ["bash"]
diff --git a/tools/dockerfile/grpc_jenkins_slave_x86/Dockerfile b/tools/dockerfile/grpc_jenkins_slave_x86/Dockerfile
deleted file mode 100644
index 2323f23..0000000
--- a/tools/dockerfile/grpc_jenkins_slave_x86/Dockerfile
+++ /dev/null
@@ -1,165 +0,0 @@
-# Copyright 2015-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.
-
-# A work-in-progress Dockerfile that allows running gRPC test suites
-# inside a docker container.
-
-FROM 32bit/debian:jessie
-
-# Install Git and basic packages.
-RUN apt-get update && apt-get install -y \
-  autoconf \
-  autotools-dev \
-  build-essential \
-  bzip2 \
-  ccache \
-  curl \
-  gcc \
-  gcc-multilib \
-  git \
-  golang \
-  gyp \
-  lcov \
-  libc6 \
-  libc6-dbg \
-  libc6-dev \
-  libgtest-dev \
-  libtool \
-  make \
-  perl \
-  strace \
-  python-dev \
-  python-setuptools \
-  python-yaml \
-  telnet \
-  unzip \
-  wget \
-  zip && apt-get clean
-
-# 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 ln -s /usr/bin/ccache /usr/local/bin/clang
-RUN ln -s /usr/bin/ccache /usr/local/bin/clang++
-
-##################
-# C++ dependencies
-RUN apt-get update && apt-get -y install libgflags-dev libgtest-dev libc++-dev clang
-
-#################
-# C# dependencies
-
-# Update to a newer version of mono
-RUN apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 3FA7E0328081BFF6A14DA29AA6A19B38D3D831EF
-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 \
-    mono-devel \
-    nunit \
-    nunit-console \
-    monodevelop
-
-# Download NuGet
-RUN cd /var/local && wget www.nuget.org/NuGet.exe
-ENV NUGET mono /var/local/NuGet.exe
-
-# TODO(jtattermusch): add dependencies for other languages
-
-##################
-# Node dependencies
-
-# Install nvm
-RUN touch .profile
-RUN curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.25.4/install.sh | bash
-RUN /bin/bash -l -c "nvm install 0.12 && npm config set cache /tmp/npm-cache"
-
-##################
-# Ruby dependencies
-
-# Install rvm
-RUN gpg --keyserver hkp://keys.gnupg.net --recv-keys 409B6B1796C275462A1703113804BB82D39DC0E3
-RUN \curl -sSL https://get.rvm.io | bash -s stable
-
-# Install Ruby 2.1
-RUN /bin/bash -l -c "rvm install ruby-2.1"
-RUN /bin/bash -l -c "rvm use --default ruby-2.1"
-RUN /bin/bash -l -c "echo 'gem: --no-ri --no-rdoc' > ~/.gemrc"
-RUN /bin/bash -l -c "echo 'export PATH=/usr/local/rvm/bin:$PATH' >> ~/.bashrc"
-RUN /bin/bash -l -c "echo 'rvm --default use ruby-2.1' >> ~/.bashrc"
-RUN /bin/bash -l -c "gem install bundler --no-ri --no-rdoc"
-
-##################
-# Python dependencies
-
-# Install dependencies
-
-RUN apt-get update && apt-get install -y \
-    python-all-dev \
-    python3-all-dev \
-    python-pip \
-    python-virtualenv
-
-# Install Python packages from PyPI
-RUN pip install futures==2.2.0 enum34==1.0.4 protobuf==3.0.0a2
-
-# For sanity test
-RUN pip install simplejson mako
-
-##################
-# PHP dependencies
-
-# Install dependencies
-
-RUN /bin/bash -l -c "echo 'deb http://packages.dotdeb.org wheezy-php55 all' \
-    >> /etc/apt/sources.list.d/dotdeb.list"
-RUN /bin/bash -l -c "echo 'deb-src http://packages.dotdeb.org wheezy-php55 all' \
-    >> /etc/apt/sources.list.d/dotdeb.list"
-RUN wget http://www.dotdeb.org/dotdeb.gpg -O- | apt-key add -
-
-RUN apt-get update && apt-get install -y \
-    git php5 php5-dev phpunit unzip
-
-##################
-# Zookeeper dependencies
-
-# Install dependencies
-
-RUN apt-get install -y libzookeeper-mt-dev
-
-
-RUN mkdir /var/local/jenkins
-
-# Define the default command.
-CMD ["bash"]
diff --git a/tools/dockerfile/test/csharp_jessie_x64/Dockerfile b/tools/dockerfile/test/csharp_jessie_x64/Dockerfile
new file mode 100644
index 0000000..0052de6
--- /dev/null
+++ b/tools/dockerfile/test/csharp_jessie_x64/Dockerfile
@@ -0,0 +1,99 @@
+# Copyright 2015-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.
+
+FROM debian:jessie
+
+# Install Git and basic packages.
+RUN apt-get update && apt-get install -y \
+  autoconf \
+  autotools-dev \
+  build-essential \
+  bzip2 \
+  ccache \
+  curl \
+  gcc \
+  gcc-multilib \
+  git \
+  golang \
+  gyp \
+  lcov \
+  libc6 \
+  libc6-dbg \
+  libc6-dev \
+  libgtest-dev \
+  libtool \
+  make \
+  perl \
+  strace \
+  python-dev \
+  python-setuptools \
+  python-yaml \
+  telnet \
+  unzip \
+  wget \
+  zip && apt-get clean
+
+#================
+# Build profiling
+RUN apt-get update && apt-get install -y time && apt-get clean
+
+#================
+# C# dependencies
+
+# Update to a newer version of mono
+RUN apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 3FA7E0328081BFF6A14DA29AA6A19B38D3D831EF
+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 \
+    mono-devel \
+    ca-certificates-mono \
+    nuget \
+    && apt-get clean
+
+# 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 ln -s /usr/bin/ccache /usr/local/bin/clang
+RUN ln -s /usr/bin/ccache /usr/local/bin/clang++
+
+#======================
+# Zookeeper dependencies
+# TODO(jtattermusch): is zookeeper still needed?
+RUN apt-get install -y libzookeeper-mt-dev
+
+RUN mkdir /var/local/jenkins
+
+# Define the default command.
+CMD ["bash"]
diff --git a/tools/dockerfile/test/cxx_jessie_x64/Dockerfile b/tools/dockerfile/test/cxx_jessie_x64/Dockerfile
new file mode 100644
index 0000000..e3ed39d
--- /dev/null
+++ b/tools/dockerfile/test/cxx_jessie_x64/Dockerfile
@@ -0,0 +1,86 @@
+# Copyright 2015-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.
+
+FROM debian:jessie
+
+# Install Git and basic packages.
+RUN apt-get update && apt-get install -y \
+  autoconf \
+  autotools-dev \
+  build-essential \
+  bzip2 \
+  ccache \
+  curl \
+  gcc \
+  gcc-multilib \
+  git \
+  golang \
+  gyp \
+  lcov \
+  libc6 \
+  libc6-dbg \
+  libc6-dev \
+  libgtest-dev \
+  libtool \
+  make \
+  perl \
+  strace \
+  python-dev \
+  python-setuptools \
+  python-yaml \
+  telnet \
+  unzip \
+  wget \
+  zip && apt-get clean
+
+#================
+# Build profiling
+RUN apt-get update && apt-get install -y time && apt-get clean
+
+#=================
+# C++ dependencies
+RUN apt-get update && apt-get -y install libgflags-dev libgtest-dev libc++-dev clang && apt-get clean
+
+# 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 ln -s /usr/bin/ccache /usr/local/bin/clang
+RUN ln -s /usr/bin/ccache /usr/local/bin/clang++
+
+#======================
+# Zookeeper dependencies
+# TODO(jtattermusch): is zookeeper still needed?
+RUN apt-get install -y libzookeeper-mt-dev
+
+RUN mkdir /var/local/jenkins
+
+# Define the default command.
+CMD ["bash"]
diff --git a/tools/dockerfile/test/cxx_jessie_x86/Dockerfile b/tools/dockerfile/test/cxx_jessie_x86/Dockerfile
new file mode 100644
index 0000000..9a8f2b1
--- /dev/null
+++ b/tools/dockerfile/test/cxx_jessie_x86/Dockerfile
@@ -0,0 +1,86 @@
+# Copyright 2015-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.
+
+FROM 32bit/debian:jessie
+
+# Install Git and basic packages.
+RUN apt-get update && apt-get install -y \
+  autoconf \
+  autotools-dev \
+  build-essential \
+  bzip2 \
+  ccache \
+  curl \
+  gcc \
+  gcc-multilib \
+  git \
+  golang \
+  gyp \
+  lcov \
+  libc6 \
+  libc6-dbg \
+  libc6-dev \
+  libgtest-dev \
+  libtool \
+  make \
+  perl \
+  strace \
+  python-dev \
+  python-setuptools \
+  python-yaml \
+  telnet \
+  unzip \
+  wget \
+  zip && apt-get clean
+
+#================
+# Build profiling
+RUN apt-get update && apt-get install -y time && apt-get clean
+
+#=================
+# C++ dependencies
+RUN apt-get update && apt-get -y install libgflags-dev libgtest-dev libc++-dev clang && apt-get clean
+
+# 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 ln -s /usr/bin/ccache /usr/local/bin/clang
+RUN ln -s /usr/bin/ccache /usr/local/bin/clang++
+
+#======================
+# Zookeeper dependencies
+# TODO(jtattermusch): is zookeeper still needed?
+RUN apt-get install -y libzookeeper-mt-dev
+
+RUN mkdir /var/local/jenkins
+
+# Define the default command.
+CMD ["bash"]
diff --git a/tools/dockerfile/test/node_jessie_x64/Dockerfile b/tools/dockerfile/test/node_jessie_x64/Dockerfile
new file mode 100644
index 0000000..0655bf7
--- /dev/null
+++ b/tools/dockerfile/test/node_jessie_x64/Dockerfile
@@ -0,0 +1,90 @@
+# Copyright 2015-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.
+
+FROM debian:jessie
+
+# Install Git and basic packages.
+RUN apt-get update && apt-get install -y \
+  autoconf \
+  autotools-dev \
+  build-essential \
+  bzip2 \
+  ccache \
+  curl \
+  gcc \
+  gcc-multilib \
+  git \
+  golang \
+  gyp \
+  lcov \
+  libc6 \
+  libc6-dbg \
+  libc6-dev \
+  libgtest-dev \
+  libtool \
+  make \
+  perl \
+  strace \
+  python-dev \
+  python-setuptools \
+  python-yaml \
+  telnet \
+  unzip \
+  wget \
+  zip && apt-get clean
+
+#================
+# Build profiling
+RUN apt-get update && apt-get install -y time && apt-get clean
+
+#==================
+# Node dependencies
+
+# Install nvm
+RUN touch .profile
+RUN curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.25.4/install.sh | bash
+RUN /bin/bash -l -c "nvm install 0.12 && npm config set cache /tmp/npm-cache"
+
+# 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 ln -s /usr/bin/ccache /usr/local/bin/clang
+RUN ln -s /usr/bin/ccache /usr/local/bin/clang++
+
+#======================
+# Zookeeper dependencies
+# TODO(jtattermusch): is zookeeper still needed?
+RUN apt-get install -y libzookeeper-mt-dev
+
+RUN mkdir /var/local/jenkins
+
+# Define the default command.
+CMD ["bash"]
diff --git a/tools/dockerfile/test/php_jessie_x64/Dockerfile b/tools/dockerfile/test/php_jessie_x64/Dockerfile
new file mode 100644
index 0000000..43081e7
--- /dev/null
+++ b/tools/dockerfile/test/php_jessie_x64/Dockerfile
@@ -0,0 +1,96 @@
+# Copyright 2015-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.
+
+FROM debian:jessie
+
+# Install Git and basic packages.
+RUN apt-get update && apt-get install -y \
+  autoconf \
+  autotools-dev \
+  build-essential \
+  bzip2 \
+  ccache \
+  curl \
+  gcc \
+  gcc-multilib \
+  git \
+  golang \
+  gyp \
+  lcov \
+  libc6 \
+  libc6-dbg \
+  libc6-dev \
+  libgtest-dev \
+  libtool \
+  make \
+  perl \
+  strace \
+  python-dev \
+  python-setuptools \
+  python-yaml \
+  telnet \
+  unzip \
+  wget \
+  zip && apt-get clean
+
+#================
+# Build profiling
+RUN apt-get update && apt-get install -y time && apt-get clean
+
+#=================
+# PHP dependencies
+
+# Install dependencies
+
+RUN /bin/bash -l -c "echo 'deb http://packages.dotdeb.org wheezy-php55 all' \
+    >> /etc/apt/sources.list.d/dotdeb.list"
+RUN /bin/bash -l -c "echo 'deb-src http://packages.dotdeb.org wheezy-php55 all' \
+    >> /etc/apt/sources.list.d/dotdeb.list"
+RUN wget http://www.dotdeb.org/dotdeb.gpg -O- | apt-key add -
+
+RUN apt-get update && apt-get install -y \
+    git php5 php5-dev phpunit unzip
+
+# 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 ln -s /usr/bin/ccache /usr/local/bin/clang
+RUN ln -s /usr/bin/ccache /usr/local/bin/clang++
+
+#======================
+# Zookeeper dependencies
+# TODO(jtattermusch): is zookeeper still needed?
+RUN apt-get install -y libzookeeper-mt-dev
+
+RUN mkdir /var/local/jenkins
+
+# Define the default command.
+CMD ["bash"]
diff --git a/tools/dockerfile/test/python_jessie_x64/Dockerfile b/tools/dockerfile/test/python_jessie_x64/Dockerfile
new file mode 100644
index 0000000..7ed8b4c
--- /dev/null
+++ b/tools/dockerfile/test/python_jessie_x64/Dockerfile
@@ -0,0 +1,97 @@
+# Copyright 2015-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.
+
+FROM debian:jessie
+
+# Install Git and basic packages.
+RUN apt-get update && apt-get install -y \
+  autoconf \
+  autotools-dev \
+  build-essential \
+  bzip2 \
+  ccache \
+  curl \
+  gcc \
+  gcc-multilib \
+  git \
+  golang \
+  gyp \
+  lcov \
+  libc6 \
+  libc6-dbg \
+  libc6-dev \
+  libgtest-dev \
+  libtool \
+  make \
+  perl \
+  strace \
+  python-dev \
+  python-setuptools \
+  python-yaml \
+  telnet \
+  unzip \
+  wget \
+  zip && apt-get clean
+
+#================
+# Build profiling
+RUN apt-get update && apt-get install -y time && apt-get clean
+
+#====================
+# Python dependencies
+
+# Install dependencies
+
+RUN apt-get update && apt-get install -y \
+    python-all-dev \
+    python3-all-dev \
+    python-pip
+
+# 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.0.0a2 tox
+
+# 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 ln -s /usr/bin/ccache /usr/local/bin/clang
+RUN ln -s /usr/bin/ccache /usr/local/bin/clang++
+
+#======================
+# Zookeeper dependencies
+# TODO(jtattermusch): is zookeeper still needed?
+RUN apt-get install -y libzookeeper-mt-dev
+
+RUN mkdir /var/local/jenkins
+
+# Define the default command.
+CMD ["bash"]
diff --git a/tools/dockerfile/test/ruby_jessie_x64/Dockerfile b/tools/dockerfile/test/ruby_jessie_x64/Dockerfile
new file mode 100644
index 0000000..91af772
--- /dev/null
+++ b/tools/dockerfile/test/ruby_jessie_x64/Dockerfile
@@ -0,0 +1,97 @@
+# Copyright 2015-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.
+
+FROM debian:jessie
+
+# Install Git and basic packages.
+RUN apt-get update && apt-get install -y \
+  autoconf \
+  autotools-dev \
+  build-essential \
+  bzip2 \
+  ccache \
+  curl \
+  gcc \
+  gcc-multilib \
+  git \
+  golang \
+  gyp \
+  lcov \
+  libc6 \
+  libc6-dbg \
+  libc6-dev \
+  libgtest-dev \
+  libtool \
+  make \
+  perl \
+  strace \
+  python-dev \
+  python-setuptools \
+  python-yaml \
+  telnet \
+  unzip \
+  wget \
+  zip && apt-get clean
+
+#================
+# Build profiling
+RUN apt-get update && apt-get install -y time && apt-get clean
+
+#==================
+# Ruby dependencies
+
+# Install rvm
+RUN gpg --keyserver hkp://keys.gnupg.net --recv-keys 409B6B1796C275462A1703113804BB82D39DC0E3
+RUN \curl -sSL https://get.rvm.io | bash -s stable
+
+# Install Ruby 2.1
+RUN /bin/bash -l -c "rvm install ruby-2.1"
+RUN /bin/bash -l -c "rvm use --default ruby-2.1"
+RUN /bin/bash -l -c "echo 'gem: --no-ri --no-rdoc' > ~/.gemrc"
+RUN /bin/bash -l -c "echo 'export PATH=/usr/local/rvm/bin:$PATH' >> ~/.bashrc"
+RUN /bin/bash -l -c "echo 'rvm --default use ruby-2.1' >> ~/.bashrc"
+RUN /bin/bash -l -c "gem install bundler --no-ri --no-rdoc"
+
+# 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 ln -s /usr/bin/ccache /usr/local/bin/clang
+RUN ln -s /usr/bin/ccache /usr/local/bin/clang++
+
+#======================
+# Zookeeper dependencies
+# TODO(jtattermusch): is zookeeper still needed?
+RUN apt-get install -y libzookeeper-mt-dev
+
+RUN mkdir /var/local/jenkins
+
+# Define the default command.
+CMD ["bash"]
diff --git a/tools/dockerfile/test/sanity/Dockerfile b/tools/dockerfile/test/sanity/Dockerfile
new file mode 100644
index 0000000..1935f67
--- /dev/null
+++ b/tools/dockerfile/test/sanity/Dockerfile
@@ -0,0 +1,82 @@
+# Copyright 2015-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.
+
+FROM debian:jessie
+
+# Install Git and basic packages.
+RUN apt-get update && apt-get install -y \
+  autoconf \
+  autotools-dev \
+  build-essential \
+  bzip2 \
+  ccache \
+  curl \
+  gcc \
+  gcc-multilib \
+  git \
+  golang \
+  gyp \
+  lcov \
+  libc6 \
+  libc6-dbg \
+  libc6-dev \
+  libgtest-dev \
+  libtool \
+  make \
+  perl \
+  strace \
+  python-dev \
+  python-setuptools \
+  python-yaml \
+  telnet \
+  unzip \
+  wget \
+  zip && apt-get clean
+
+#================
+# Build profiling
+RUN apt-get update && apt-get install -y time && apt-get clean
+
+#========================
+# Sanity test dependencies
+RUN apt-get update && apt-get install -y python-pip
+RUN pip install simplejson mako
+
+#===================
+# Docker "inception"
+# Note this is quite the ugly hack.
+# This makes sure that the docker binary we inject has its dependencies.
+RUN apt-get install libsystemd-journal0
+RUN curl https://get.docker.com/ | sh
+RUN apt-get remove --purge -y docker-engine
+
+RUN mkdir /var/local/jenkins
+
+# Define the default command.
+CMD ["bash"]
diff --git a/tools/doxygen/Doxyfile.c++ b/tools/doxygen/Doxyfile.c++
index ad0ad65..dd5c8ec 100644
--- a/tools/doxygen/Doxyfile.c++
+++ b/tools/doxygen/Doxyfile.c++
@@ -40,7 +40,7 @@
 # could be handy for archiving the generated documentation or if some version
 # control system is used.
 
-PROJECT_NUMBER         = 0.13.0.0
+PROJECT_NUMBER         = 0.14.0-dev
 
 # Using the PROJECT_BRIEF tag one can provide an optional one line description
 # for a project that appears at the top of each page and should give viewer a
@@ -760,7 +760,8 @@
 # spaces.
 # Note: If this tag is empty the current directory is searched.
 
-INPUT                  = include/grpc++/channel.h \
+INPUT                  = include/grpc++/alarm.h \
+include/grpc++/channel.h \
 include/grpc++/client_context.h \
 include/grpc++/completion_queue.h \
 include/grpc++/create_channel.h \
@@ -770,6 +771,7 @@
 include/grpc++/impl/call.h \
 include/grpc++/impl/client_unary_call.h \
 include/grpc++/impl/grpc_library.h \
+include/grpc++/impl/method_handler_impl.h \
 include/grpc++/impl/proto_utils.h \
 include/grpc++/impl/rpc_method.h \
 include/grpc++/impl/rpc_service_method.h \
@@ -801,7 +803,37 @@
 include/grpc++/support/string_ref.h \
 include/grpc++/support/stub_options.h \
 include/grpc++/support/sync_stream.h \
-include/grpc++/support/time.h
+include/grpc++/support/time.h \
+include/grpc++/impl/codegen/async_stream.h \
+include/grpc++/impl/codegen/async_unary_call.h \
+include/grpc++/impl/codegen/call.h \
+include/grpc++/impl/codegen/call_hook.h \
+include/grpc++/impl/codegen/channel_interface.h \
+include/grpc++/impl/codegen/client_context.h \
+include/grpc++/impl/codegen/client_unary_call.h \
+include/grpc++/impl/codegen/completion_queue.h \
+include/grpc++/impl/codegen/completion_queue_tag.h \
+include/grpc++/impl/codegen/config.h \
+include/grpc++/impl/codegen/config_protobuf.h \
+include/grpc++/impl/codegen/grpc_library.h \
+include/grpc++/impl/codegen/method_handler_impl.h \
+include/grpc++/impl/codegen/proto_utils.h \
+include/grpc++/impl/codegen/rpc_method.h \
+include/grpc++/impl/codegen/rpc_service_method.h \
+include/grpc++/impl/codegen/security/auth_context.h \
+include/grpc++/impl/codegen/serialization_traits.h \
+include/grpc++/impl/codegen/server_context.h \
+include/grpc++/impl/codegen/server_interface.h \
+include/grpc++/impl/codegen/service_type.h \
+include/grpc++/impl/codegen/status.h \
+include/grpc++/impl/codegen/status_code_enum.h \
+include/grpc++/impl/codegen/string_ref.h \
+include/grpc++/impl/codegen/stub_options.h \
+include/grpc++/impl/codegen/sync.h \
+include/grpc++/impl/codegen/sync_cxx11.h \
+include/grpc++/impl/codegen/sync_no_cxx11.h \
+include/grpc++/impl/codegen/sync_stream.h \
+include/grpc++/impl/codegen/time.h
 
 # This tag can be used to specify the character encoding of the source files
 # that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses
diff --git a/tools/doxygen/Doxyfile.c++.internal b/tools/doxygen/Doxyfile.c++.internal
index 1d4b0ce..e0650d7 100644
--- a/tools/doxygen/Doxyfile.c++.internal
+++ b/tools/doxygen/Doxyfile.c++.internal
@@ -40,7 +40,7 @@
 # could be handy for archiving the generated documentation or if some version
 # control system is used.
 
-PROJECT_NUMBER         = 0.13.0.0
+PROJECT_NUMBER         = 0.14.0-dev
 
 # Using the PROJECT_BRIEF tag one can provide an optional one line description
 # for a project that appears at the top of each page and should give viewer a
@@ -760,7 +760,8 @@
 # spaces.
 # Note: If this tag is empty the current directory is searched.
 
-INPUT                  = include/grpc++/channel.h \
+INPUT                  = include/grpc++/alarm.h \
+include/grpc++/channel.h \
 include/grpc++/client_context.h \
 include/grpc++/completion_queue.h \
 include/grpc++/create_channel.h \
@@ -770,6 +771,7 @@
 include/grpc++/impl/call.h \
 include/grpc++/impl/client_unary_call.h \
 include/grpc++/impl/grpc_library.h \
+include/grpc++/impl/method_handler_impl.h \
 include/grpc++/impl/proto_utils.h \
 include/grpc++/impl/rpc_method.h \
 include/grpc++/impl/rpc_service_method.h \
@@ -802,6 +804,36 @@
 include/grpc++/support/stub_options.h \
 include/grpc++/support/sync_stream.h \
 include/grpc++/support/time.h \
+include/grpc++/impl/codegen/async_stream.h \
+include/grpc++/impl/codegen/async_unary_call.h \
+include/grpc++/impl/codegen/call.h \
+include/grpc++/impl/codegen/call_hook.h \
+include/grpc++/impl/codegen/channel_interface.h \
+include/grpc++/impl/codegen/client_context.h \
+include/grpc++/impl/codegen/client_unary_call.h \
+include/grpc++/impl/codegen/completion_queue.h \
+include/grpc++/impl/codegen/completion_queue_tag.h \
+include/grpc++/impl/codegen/config.h \
+include/grpc++/impl/codegen/config_protobuf.h \
+include/grpc++/impl/codegen/grpc_library.h \
+include/grpc++/impl/codegen/method_handler_impl.h \
+include/grpc++/impl/codegen/proto_utils.h \
+include/grpc++/impl/codegen/rpc_method.h \
+include/grpc++/impl/codegen/rpc_service_method.h \
+include/grpc++/impl/codegen/security/auth_context.h \
+include/grpc++/impl/codegen/serialization_traits.h \
+include/grpc++/impl/codegen/server_context.h \
+include/grpc++/impl/codegen/server_interface.h \
+include/grpc++/impl/codegen/service_type.h \
+include/grpc++/impl/codegen/status.h \
+include/grpc++/impl/codegen/status_code_enum.h \
+include/grpc++/impl/codegen/string_ref.h \
+include/grpc++/impl/codegen/stub_options.h \
+include/grpc++/impl/codegen/sync.h \
+include/grpc++/impl/codegen/sync_cxx11.h \
+include/grpc++/impl/codegen/sync_no_cxx11.h \
+include/grpc++/impl/codegen/sync_stream.h \
+include/grpc++/impl/codegen/time.h \
 src/cpp/client/secure_credentials.h \
 src/cpp/common/secure_auth_context.h \
 src/cpp/server/secure_server_credentials.h \
@@ -823,6 +855,7 @@
 src/cpp/client/credentials.cc \
 src/cpp/client/generic_stub.cc \
 src/cpp/client/insecure_credentials.cc \
+src/cpp/common/alarm.cc \
 src/cpp/common/call.cc \
 src/cpp/common/channel_arguments.cc \
 src/cpp/common/completion_queue.cc \
@@ -841,7 +874,8 @@
 src/cpp/util/slice.cc \
 src/cpp/util/status.cc \
 src/cpp/util/string_ref.cc \
-src/cpp/util/time.cc
+src/cpp/util/time.cc \
+src/cpp/codegen/grpc_library.cc
 
 # This tag can be used to specify the character encoding of the source files
 # that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses
diff --git a/tools/doxygen/Doxyfile.core b/tools/doxygen/Doxyfile.core
index db3db4e..a9b14c8 100644
--- a/tools/doxygen/Doxyfile.core
+++ b/tools/doxygen/Doxyfile.core
@@ -40,7 +40,7 @@
 # could be handy for archiving the generated documentation or if some version
 # control system is used.
 
-PROJECT_NUMBER         = 0.13.0.0
+PROJECT_NUMBER         = 0.14.0-dev
 
 # Using the PROJECT_BRIEF tag one can provide an optional one line description
 # for a project that appears at the top of each page and should give viewer a
@@ -761,6 +761,12 @@
 # Note: If this tag is empty the current directory is searched.
 
 INPUT                  = include/grpc/grpc_security.h \
+include/grpc/impl/codegen/byte_buffer.h \
+include/grpc/impl/codegen/compression_types.h \
+include/grpc/impl/codegen/connectivity_state.h \
+include/grpc/impl/codegen/grpc_types.h \
+include/grpc/impl/codegen/propagation_bits.h \
+include/grpc/impl/codegen/status.h \
 include/grpc/byte_buffer.h \
 include/grpc/byte_buffer_reader.h \
 include/grpc/compression.h \
@@ -794,7 +800,21 @@
 include/grpc/support/tls_gcc.h \
 include/grpc/support/tls_msvc.h \
 include/grpc/support/tls_pthread.h \
-include/grpc/support/useful.h
+include/grpc/support/useful.h \
+include/grpc/impl/codegen/alloc.h \
+include/grpc/impl/codegen/atm.h \
+include/grpc/impl/codegen/atm_gcc_atomic.h \
+include/grpc/impl/codegen/atm_gcc_sync.h \
+include/grpc/impl/codegen/atm_win32.h \
+include/grpc/impl/codegen/log.h \
+include/grpc/impl/codegen/port_platform.h \
+include/grpc/impl/codegen/slice.h \
+include/grpc/impl/codegen/slice_buffer.h \
+include/grpc/impl/codegen/sync.h \
+include/grpc/impl/codegen/sync_generic.h \
+include/grpc/impl/codegen/sync_posix.h \
+include/grpc/impl/codegen/sync_win32.h \
+include/grpc/impl/codegen/time.h
 
 # This tag can be used to specify the character encoding of the source files
 # that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses
diff --git a/tools/doxygen/Doxyfile.core.internal b/tools/doxygen/Doxyfile.core.internal
index 97dd4a9..b626843 100644
--- a/tools/doxygen/Doxyfile.core.internal
+++ b/tools/doxygen/Doxyfile.core.internal
@@ -40,7 +40,7 @@
 # could be handy for archiving the generated documentation or if some version
 # control system is used.
 
-PROJECT_NUMBER         = 0.13.0.0
+PROJECT_NUMBER         = 0.14.0-dev
 
 # Using the PROJECT_BRIEF tag one can provide an optional one line description
 # for a project that appears at the top of each page and should give viewer a
@@ -761,6 +761,12 @@
 # Note: If this tag is empty the current directory is searched.
 
 INPUT                  = include/grpc/grpc_security.h \
+include/grpc/impl/codegen/byte_buffer.h \
+include/grpc/impl/codegen/compression_types.h \
+include/grpc/impl/codegen/connectivity_state.h \
+include/grpc/impl/codegen/grpc_types.h \
+include/grpc/impl/codegen/propagation_bits.h \
+include/grpc/impl/codegen/status.h \
 include/grpc/byte_buffer.h \
 include/grpc/byte_buffer_reader.h \
 include/grpc/compression.h \
@@ -895,7 +901,6 @@
 src/core/transport/transport.h \
 src/core/transport/transport_impl.h \
 src/core/census/aggregation.h \
-src/core/census/context.h \
 src/core/census/rpc_metric_id.h \
 src/core/httpcli/httpcli_security_connector.c \
 src/core/security/base64.c \
@@ -996,6 +1001,7 @@
 src/core/json/json_reader.c \
 src/core/json/json_string.c \
 src/core/json/json_writer.c \
+src/core/surface/alarm.c \
 src/core/surface/api_trace.c \
 src/core/surface/byte_buffer.c \
 src/core/surface/byte_buffer_reader.c \
@@ -1047,7 +1053,7 @@
 src/core/census/context.c \
 src/core/census/initialize.c \
 src/core/census/operation.c \
-src/core/census/tag_set.c \
+src/core/census/placeholders.c \
 src/core/census/tracing.c \
 include/grpc/support/alloc.h \
 include/grpc/support/atm.h \
@@ -1077,6 +1083,20 @@
 include/grpc/support/tls_msvc.h \
 include/grpc/support/tls_pthread.h \
 include/grpc/support/useful.h \
+include/grpc/impl/codegen/alloc.h \
+include/grpc/impl/codegen/atm.h \
+include/grpc/impl/codegen/atm_gcc_atomic.h \
+include/grpc/impl/codegen/atm_gcc_sync.h \
+include/grpc/impl/codegen/atm_win32.h \
+include/grpc/impl/codegen/log.h \
+include/grpc/impl/codegen/port_platform.h \
+include/grpc/impl/codegen/slice.h \
+include/grpc/impl/codegen/slice_buffer.h \
+include/grpc/impl/codegen/sync.h \
+include/grpc/impl/codegen/sync_generic.h \
+include/grpc/impl/codegen/sync_posix.h \
+include/grpc/impl/codegen/sync_win32.h \
+include/grpc/impl/codegen/time.h \
 src/core/profiling/timers.h \
 src/core/support/block_annotate.h \
 src/core/support/env.h \
@@ -1117,6 +1137,7 @@
 src/core/support/string_posix.c \
 src/core/support/string_win32.c \
 src/core/support/subprocess_posix.c \
+src/core/support/subprocess_windows.c \
 src/core/support/sync.c \
 src/core/support/sync_posix.c \
 src/core/support/sync_win32.c \
@@ -1127,7 +1148,8 @@
 src/core/support/time_posix.c \
 src/core/support/time_precise.c \
 src/core/support/time_win32.c \
-src/core/support/tls_pthread.c
+src/core/support/tls_pthread.c \
+src/core/support/wrap_memcpy.c
 
 # This tag can be used to specify the character encoding of the source files
 # that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses
diff --git a/tools/jenkins/build_and_run_docker.sh b/tools/jenkins/build_and_run_docker.sh
index c48f58e..92dbbc6 100755
--- a/tools/jenkins/build_and_run_docker.sh
+++ b/tools/jenkins/build_and_run_docker.sh
@@ -37,12 +37,10 @@
 git_root=$(pwd)
 cd -
 
-# Create a local branch so the child Docker script won't complain
-git branch -f jenkins-docker
-
 # Inputs
 # DOCKERFILE_DIR - Directory in which Dockerfile file is located.
 # DOCKER_RUN_SCRIPT - Script to run under docker (relative to grpc repo root)
+# OUTPUT_DIR - Directory that will be copied from inside docker after finishing.
 # $@ - Extra args to pass to docker run
 
 # Use image name based on Dockerfile location checksum
@@ -57,6 +55,7 @@
 # Run command inside docker
 docker run \
   "$@" \
+  -e EXTERNAL_GIT_ROOT="/var/local/jenkins/grpc" \
   -e THIS_IS_REALLY_NEEDED='see https://github.com/docker/docker/issues/14203 for why docker is awful' \
   -v "$git_root:/var/local/jenkins/grpc:ro" \
   -w /var/local/git/grpc \
diff --git a/tools/jenkins/build_artifacts.sh b/tools/jenkins/build_artifacts.sh
index d591201..c0acbdf 100755
--- a/tools/jenkins/build_artifacts.sh
+++ b/tools/jenkins/build_artifacts.sh
@@ -36,4 +36,11 @@
 # NOTE: No empty lines should appear in this file before igncr is set!
 set -ex -o igncr || set -ex
 
-python tools/run_tests/build_artifacts.py $@
+curr_platform="$platform"
+unset platform  # variable named 'platform' breaks the windows build
+
+if [ "$curr_platform" == "linux" ] && [ "$language" == "ruby" ] ; then
+  ./tools/run_tests/build_artifact_ruby.sh
+else
+  python tools/run_tests/task_runner.py -f artifact $language $curr_platform $architecture
+fi
diff --git a/tools/jenkins/build_docker_and_run_tests.sh b/tools/jenkins/build_docker_and_run_tests.sh
index 58163bb..e2ac751 100755
--- a/tools/jenkins/build_docker_and_run_tests.sh
+++ b/tools/jenkins/build_docker_and_run_tests.sh
@@ -33,8 +33,8 @@
 
 set -ex
 
-cd `dirname $0`/../..
-git_root=`pwd`
+cd $(dirname $0)/../..
+git_root=$(pwd)
 cd -
 
 # Ensure existence of ccache directory
diff --git a/tools/run_tests/check_submodules.sh b/tools/jenkins/build_packages.sh
similarity index 65%
copy from tools/run_tests/check_submodules.sh
copy to tools/jenkins/build_packages.sh
index b4ca4fa..d795e35 100755
--- a/tools/run_tests/check_submodules.sh
+++ b/tools/jenkins/build_packages.sh
@@ -1,6 +1,5 @@
-#!/bin/sh
-
-# Copyright 2015-2016, Google Inc.
+#!/usr/bin/env bash
+# Copyright 2016, Google Inc.
 # All rights reserved.
 #
 # Redistribution and use in source and binary forms, with or without
@@ -28,27 +27,16 @@
 # 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.
+#
+# This script is invoked by Jenkins and triggers build of artifacts.
+#
+# To prevent cygwin bash complaining about empty lines ending with \r
+# we set the igncr option. The option doesn't exist on Linux, so we fallback
+# to just 'set -ex' there.
+# NOTE: No empty lines should appear in this file before igncr is set!
+set -ex -o igncr || set -ex
 
+curr_platform="$platform"
+unset platform  # variable named 'platform' breaks the windows build
 
-set -e
-
-export TEST=true
-
-cd `dirname $0`/../..
-
-submodules=`mktemp /tmp/submXXXXXX`
-want_submodules=`mktemp /tmp/submXXXXXX`
-
-git submodule | awk '{ print $1 }' | sort > $submodules
-cat << EOF | awk '{ print $1 }' | sort > $want_submodules
- 9f897b25800d2f54f5c442ef01a60721aeca6d87 third_party/boringssl (version_for_cocoapods_1.0-67-g9f897b2)
- 05b155ff59114735ec8cd089f669c4c3d8f59029 third_party/gflags (v2.1.0-45-g05b155f)
- c99458533a9b4c743ed51537e25989ea55944908 third_party/googletest (release-1.7.0)
- d5fb408ddc281ffcadeb08699e65bb694656d0bd third_party/protobuf (v3.0.0-beta-2)
- 50893291621658f355bc5b4d450a8d06a563053d third_party/zlib (v1.2.8)
-EOF
-
-diff -u $submodules $want_submodules
-
-rm $submodules $want_submodules
-
+python tools/run_tests/task_runner.py -f package $curr_platform
diff --git a/tools/jenkins/docker_run.sh b/tools/jenkins/docker_run.sh
index 1905926..df7b657 100755
--- a/tools/jenkins/docker_run.sh
+++ b/tools/jenkins/docker_run.sh
@@ -31,10 +31,21 @@
 # This script is invoked by build_docker_* inside a docker
 # container. You should never need to call this script on your own.
 
-set -e
+set -ex
 
-mkdir -p /var/local/git
-git clone --recursive /var/local/jenkins/grpc /var/local/git/grpc
+if [ "$RELATIVE_COPY_PATH" == "" ]
+then
+  mkdir -p /var/local/git
+  git clone --recursive "$EXTERNAL_GIT_ROOT" /var/local/git/grpc
+else
+  mkdir -p "/var/local/git/grpc/$RELATIVE_COPY_PATH"
+  cp -r "$EXTERNAL_GIT_ROOT/$RELATIVE_COPY_PATH"/* "/var/local/git/grpc/$RELATIVE_COPY_PATH"
+fi
+
+if [ -x "$(command -v rvm)" ]
+then
+  rvm use ruby-2.1
+fi
 
 cd /var/local/git/grpc
 
diff --git a/tools/jenkins/docker_run_tests.sh b/tools/jenkins/docker_run_tests.sh
index 148a0f5..282b857 100755
--- a/tools/jenkins/docker_run_tests.sh
+++ b/tools/jenkins/docker_run_tests.sh
@@ -1,5 +1,5 @@
 #!/bin/bash
-# Copyright 2015, Google Inc.
+# Copyright 2015-2016, Google Inc.
 # All rights reserved.
 #
 # Redistribution and use in source and binary forms, with or without
@@ -38,14 +38,11 @@
 
 # Ensure that programs depending on current-user-ownership of cache directories
 # are satisfied (it's being mounted from outside the image).
-chown `whoami` $XDG_CACHE_HOME
+chown $(whoami) $XDG_CACHE_HOME
 
 mkdir -p /var/local/git
 git clone --recursive /var/local/jenkins/grpc /var/local/git/grpc
 
-nvm use 0.12
-rvm use ruby-2.1
-
 mkdir -p reports
 
 exit_code=0
diff --git a/tools/run_tests/check_submodules.sh b/tools/jenkins/run_distribtest.sh
similarity index 64%
copy from tools/run_tests/check_submodules.sh
copy to tools/jenkins/run_distribtest.sh
index b4ca4fa..1564177 100755
--- a/tools/run_tests/check_submodules.sh
+++ b/tools/jenkins/run_distribtest.sh
@@ -1,6 +1,5 @@
-#!/bin/sh
-
-# Copyright 2015-2016, Google Inc.
+#!/usr/bin/env bash
+# Copyright 2016, Google Inc.
 # All rights reserved.
 #
 # Redistribution and use in source and binary forms, with or without
@@ -28,27 +27,23 @@
 # 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.
+#
+# This script is invoked by Jenkins and triggers run of distribution tests.
+#
+# To prevent cygwin bash complaining about empty lines ending with \r
+# we set the igncr option. The option doesn't exist on Linux, so we fallback
+# to just 'set -ex' there.
+# NOTE: No empty lines should appear in this file before igncr is set!
+set -ex -o igncr || set -ex
 
+curr_platform="$platform"
+unset platform  # variable named 'platform' breaks the windows build
 
-set -e
+# Try collecting the artifacts to test from previous Jenkins build step
+mkdir -p input_artifacts
+cp -r platform=windows/artifacts/* input_artifacts || true
+cp -r platform=linux/artifacts/* input_artifacts || true
 
-export TEST=true
-
-cd `dirname $0`/../..
-
-submodules=`mktemp /tmp/submXXXXXX`
-want_submodules=`mktemp /tmp/submXXXXXX`
-
-git submodule | awk '{ print $1 }' | sort > $submodules
-cat << EOF | awk '{ print $1 }' | sort > $want_submodules
- 9f897b25800d2f54f5c442ef01a60721aeca6d87 third_party/boringssl (version_for_cocoapods_1.0-67-g9f897b2)
- 05b155ff59114735ec8cd089f669c4c3d8f59029 third_party/gflags (v2.1.0-45-g05b155f)
- c99458533a9b4c743ed51537e25989ea55944908 third_party/googletest (release-1.7.0)
- d5fb408ddc281ffcadeb08699e65bb694656d0bd third_party/protobuf (v3.0.0-beta-2)
- 50893291621658f355bc5b4d450a8d06a563053d third_party/zlib (v1.2.8)
-EOF
-
-diff -u $submodules $want_submodules
-
-rm $submodules $want_submodules
-
+python tools/run_tests/task_runner.py -j 4 \
+    -f distribtest $language $curr_platform $architecture \
+    $@
diff --git a/tools/jenkins/run_jenkins.sh b/tools/jenkins/run_jenkins.sh
index 123b252..da6ca69 100755
--- a/tools/jenkins/run_jenkins.sh
+++ b/tools/jenkins/run_jenkins.sh
@@ -41,7 +41,7 @@
 
 if [ "$platform" == "linux" ]
 then
-  USE_DOCKER_MAYBE="--use_docker"
+  PLATFORM_SPECIFIC_ARGS="--use_docker --measure_cpu_costs"
 elif [ "$platform" == "freebsd" ]
 then
   export MAKE=gmake
@@ -49,7 +49,14 @@
 
 unset platform  # variable named 'platform' breaks the windows build
 
-python tools/run_tests/run_tests.py $USE_DOCKER_MAYBE -t -l $language -c $config -x report.xml -j 3 $@ || TESTS_FAILED="true"
+python tools/run_tests/run_tests.py \
+  $PLATFORM_SPECIFIC_ARGS           \
+  -t                                \
+  -l $language                      \
+  -c $config                        \
+  -x report.xml                     \
+  -j 2                              \
+  $@ || TESTS_FAILED="true"
 
 if [ ! -e reports/index.html ]
 then
diff --git a/tools/jenkins/run_portability.sh b/tools/jenkins/run_portability.sh
index f76dbd3..6f15da7 100755
--- a/tools/jenkins/run_portability.sh
+++ b/tools/jenkins/run_portability.sh
@@ -41,6 +41,14 @@
 
 echo "building $scenario"
 
+# If scenario has _bo suffix, add --build_only flag.
+# Short suffix name had to been chosen due to path length limit on Windows.
+if [ "$scenario" != "${scenario%_bo}" ]
+then
+  scenario="${scenario%_bo}"
+  BUILD_ONLY_MAYBE="--build_only"
+fi
+
 parts=($(echo $scenario | tr '_' ' '))  # split scenario into parts
 
 curr_platform=${parts[0]}  # variable named 'platform' breaks the windows build
@@ -48,12 +56,10 @@
 curr_compiler=${parts[2]}
 
 config='dbg'
-maybe_build_only='--build_only'
 
-if [ "$curr_platform" == "windows" ]
+if [ "$curr_platform" == "linux" ]
 then
-  python tools/run_tests/run_tests.py -t -l $language -c $config --arch ${curr_arch} --compiler ${curr_compiler} ${maybe_build_only} -x report.xml $@
-else
-  echo "Unsupported scenario."
-  exit 1
+  USE_DOCKER_MAYBE="--use_docker"
 fi
+
+python tools/run_tests/run_tests.py $USE_DOCKER_MAYBE $BUILD_ONLY_MAYBE -t -l $language -c $config --arch ${curr_arch} --compiler ${curr_compiler} -x report.xml -j 3 $@
diff --git a/tools/run_tests/artifact_targets.py b/tools/run_tests/artifact_targets.py
new file mode 100644
index 0000000..74d2a48
--- /dev/null
+++ b/tools/run_tests/artifact_targets.py
@@ -0,0 +1,239 @@
+#!/usr/bin/env python2.7
+# 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.
+
+"""Definition of targets to build artifacts."""
+
+import jobset
+
+
+def create_docker_jobspec(name, dockerfile_dir, shell_command, environ={},
+                   flake_retries=0, timeout_retries=0):
+  """Creates jobspec for a task running under docker."""
+  environ = environ.copy()
+  environ['RUN_COMMAND'] = shell_command
+
+  docker_args=[]
+  for k,v in environ.iteritems():
+    docker_args += ['-e', '%s=%s' % (k, v)]
+  docker_env = {'DOCKERFILE_DIR': dockerfile_dir,
+                'DOCKER_RUN_SCRIPT': 'tools/jenkins/docker_run.sh',
+                'OUTPUT_DIR': 'artifacts'}
+  jobspec = jobset.JobSpec(
+          cmdline=['tools/jenkins/build_and_run_docker.sh'] + docker_args,
+          environ=docker_env,
+          shortname='build_artifact.%s' % (name),
+          timeout_seconds=30*60,
+          flake_retries=flake_retries,
+          timeout_retries=timeout_retries)
+  return jobspec
+
+
+def create_jobspec(name, cmdline, environ=None, shell=False,
+                   flake_retries=0, timeout_retries=0):
+  """Creates jobspec."""
+  jobspec = jobset.JobSpec(
+          cmdline=cmdline,
+          environ=environ,
+          shortname='build_artifact.%s' % (name),
+          timeout_seconds=30*60,
+          flake_retries=flake_retries,
+          timeout_retries=timeout_retries,
+          shell=shell)
+  return jobspec
+
+
+def macos_arch_env(arch):
+  """Returns environ specifying -arch arguments for make."""
+  if arch == 'x86':
+    arch_arg = '-arch i386'
+  elif arch == 'x64':
+    arch_arg = '-arch x86_64'
+  else:
+    raise Exception('Unsupported arch')
+  return {'CFLAGS': arch_arg, 'LDFLAGS': arch_arg}
+
+
+class PythonArtifact:
+  """Builds Python artifacts."""
+
+  def __init__(self, platform, arch):
+    self.name = 'python_%s_%s' % (platform, arch)
+    self.platform = platform
+    self.arch = arch
+    self.labels = ['artifact', 'python', platform, arch]
+
+  def pre_build_jobspecs(self):
+      return []
+
+  def build_jobspec(self):
+    if self.platform == 'windows':
+      raise Exception('Not supported yet.')
+    else:
+      environ = {}
+      if self.platform == 'linux':
+        if self.arch == 'x86':
+          environ['SETARCH_CMD'] = 'linux32'
+        return create_docker_jobspec(self.name,
+            'tools/dockerfile/grpc_artifact_linux_%s' % self.arch,
+            'tools/run_tests/build_artifact_python.sh',
+            environ=environ)
+      else:
+        environ['SKIP_PIP_INSTALL'] = 'TRUE'
+        return create_jobspec(self.name,
+                              ['tools/run_tests/build_artifact_python.sh'],
+                              environ=environ)
+
+  def __str__(self):
+    return self.name
+
+
+class RubyArtifact:
+  """Builds ruby native gem."""
+
+  def __init__(self, platform, arch):
+    self.name = 'ruby_native_gem_%s_%s' % (platform, arch)
+    self.platform = platform
+    self.arch = arch
+    self.labels = ['artifact', 'ruby', platform, arch]
+
+  def pre_build_jobspecs(self):
+    return []
+
+  def build_jobspec(self):
+    if self.platform == 'windows':
+      raise Exception("Not supported yet")
+    else:
+      if self.platform == 'linux':
+        environ = {}
+        if self.arch == 'x86':
+          environ['SETARCH_CMD'] = 'linux32'
+        return create_docker_jobspec(self.name,
+            'tools/dockerfile/grpc_artifact_linux_%s' % self.arch,
+            'tools/run_tests/build_artifact_ruby.sh',
+            environ=environ)
+      else:
+        return create_jobspec(self.name,
+                              ['tools/run_tests/build_artifact_ruby.sh'])
+
+
+class CSharpExtArtifact:
+  """Builds C# native extension library"""
+
+  def __init__(self, platform, arch):
+    self.name = 'csharp_ext_%s_%s' % (platform, arch)
+    self.platform = platform
+    self.arch = arch
+    self.labels = ['artifact', 'csharp', platform, arch]
+
+  def pre_build_jobspecs(self):
+    if self.platform == 'windows':
+      return [create_jobspec('prebuild_%s' % self.name,
+                             ['tools\\run_tests\\pre_build_c.bat'],
+                             shell=True,
+                             flake_retries=5,
+                             timeout_retries=2)]
+    else:
+      return []
+
+  def build_jobspec(self):
+    if self.platform == 'windows':
+      msbuild_platform = 'Win32' if self.arch == 'x86' else self.arch
+      return create_jobspec(self.name,
+                            ['tools\\run_tests\\build_artifact_csharp.bat',
+                             'vsprojects\\grpc_csharp_ext.sln',
+                             '/p:Configuration=Release',
+                             '/p:PlatformToolset=v120',
+                             '/p:Platform=%s' % msbuild_platform],
+                            shell=True)
+    else:
+      environ = {'CONFIG': 'opt',
+                 'EMBED_OPENSSL': 'true',
+                 'EMBED_ZLIB': 'true'}
+      if self.platform == 'linux':
+        return create_docker_jobspec(self.name,
+            'tools/dockerfile/grpc_artifact_linux_%s' % self.arch,
+            'tools/run_tests/build_artifact_csharp.sh')
+      else:
+        environ.update(macos_arch_env(self.arch))
+        return create_jobspec(self.name,
+                              ['tools/run_tests/build_artifact_csharp.sh'],
+                              environ=environ)
+
+  def __str__(self):
+    return self.name
+
+node_gyp_arch_map = {
+  'x86': 'ia32',
+  'x64': 'x64'
+}
+
+class NodeExtArtifact:
+  """Builds Node native extension"""
+
+  def __init__(self, platform, arch):
+    self.name = 'node_ext_{0}_{1}'.format(platform, arch)
+    self.platform = platform
+    self.arch = arch
+    self.gyp_arch = node_gyp_arch_map[arch]
+    self.labels = ['artifact', 'node', platform, arch]
+
+  def pre_build_jobspecs(self):
+    return []
+
+  def build_jobspec(self):
+    if self.platform == 'windows':
+      return create_jobspec(self.name,
+                            ['tools\\run_tests\\build_artifact_node.bat',
+                             self.gyp_arch],
+                            shell=True)
+    else:
+      if self.platform == 'linux':
+        return create_docker_jobspec(
+            self.name,
+            'tools/dockerfile/grpc_artifact_linux_{}'.format(self.arch),
+            'tools/run_tests/build_artifact_node.sh {}'.format(self.gyp_arch))
+      else:
+        return create_jobspec(self.name,
+                              ['tools/run_tests/build_artifact_node.sh',
+                               self.gyp_arch])
+
+
+def targets():
+  """Gets list of supported targets"""
+  return ([Cls(platform, arch)
+           for Cls in (CSharpExtArtifact, NodeExtArtifact)
+           for platform in ('linux', 'macos', 'windows')
+           for arch in ('x86', 'x64')] +
+          [PythonArtifact('linux', 'x86'),
+           PythonArtifact('linux', 'x64'),
+           PythonArtifact('macos', 'x64'),
+           RubyArtifact('linux', 'x86'),
+           RubyArtifact('linux', 'x64'),
+           RubyArtifact('macos', 'x64')])
diff --git a/tools/run_tests/build_artifact_node.bat b/tools/run_tests/build_artifact_node.bat
new file mode 100644
index 0000000..84c63c2
--- /dev/null
+++ b/tools/run_tests/build_artifact_node.bat
@@ -0,0 +1,55 @@
+@rem Copyright 2016, Google Inc.
+@rem All rights reserved.
+@rem
+@rem Redistribution and use in source and binary forms, with or without
+@rem modification, are permitted provided that the following conditions are
+@rem met:
+@rem
+@rem     * Redistributions of source code must retain the above copyright
+@rem notice, this list of conditions and the following disclaimer.
+@rem     * Redistributions in binary form must reproduce the above
+@rem copyright notice, this list of conditions and the following disclaimer
+@rem in the documentation and/or other materials provided with the
+@rem distribution.
+@rem     * Neither the name of Google Inc. nor the names of its
+@rem contributors may be used to endorse or promote products derived from
+@rem this software without specific prior written permission.
+@rem
+@rem THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+@rem "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+@rem LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+@rem A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+@rem OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+@rem SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+@rem LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+@rem DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+@rem THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+@rem (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+@rem OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+set node_versions=0.12.0 1.0.0 1.1.0 2.0.0 3.0.0 4.0.0 5.0.0
+
+set PATH=%PATH%;C:\Program Files\nodejs\;%APPDATA%\npm
+
+del /f /q BUILD || rmdir build /s /q
+
+call npm update || goto :error
+
+mkdir artifacts
+
+for %%v in (%node_versions%) do (
+  call node-pre-gyp configure build --target=%%v --target_arch=%1
+
+@rem Try again after removing openssl headers
+  rmdir "%HOMEDRIVE%%HOMEPATH%\.node-gyp\%%v\include\node\openssl" /S /Q
+  rmdir "%HOMEDRIVE%%HOMEPATH%\.node-gyp\iojs-%%v\include\node\openssl" /S /Q
+  call node-pre-gyp build package testpackage --target=%%v --target_arch=%1 || goto :error
+
+  xcopy /Y /I /S build\stage\* artifacts\ || goto :error
+)
+if %errorlevel% neq 0 exit /b %errorlevel%
+
+goto :EOF
+
+:error
+exit /b 1
\ No newline at end of file
diff --git a/tools/run_tests/check_submodules.sh b/tools/run_tests/build_artifact_node.sh
similarity index 66%
copy from tools/run_tests/check_submodules.sh
copy to tools/run_tests/build_artifact_node.sh
index b4ca4fa..9a3b9bd 100755
--- a/tools/run_tests/check_submodules.sh
+++ b/tools/run_tests/build_artifact_node.sh
@@ -1,6 +1,5 @@
-#!/bin/sh
-
-# Copyright 2015-2016, Google Inc.
+#!/bin/bash
+# Copyright 2016, Google Inc.
 # All rights reserved.
 #
 # Redistribution and use in source and binary forms, with or without
@@ -29,26 +28,24 @@
 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
+NODE_TARGET_ARCH=$1
+source ~/.nvm/nvm.sh
+set -ex
 
-set -e
+nvm use 4
 
-export TEST=true
+cd $(dirname $0)/../..
 
-cd `dirname $0`/../..
+rm -rf build
 
-submodules=`mktemp /tmp/submXXXXXX`
-want_submodules=`mktemp /tmp/submXXXXXX`
+mkdir -p artifacts
 
-git submodule | awk '{ print $1 }' | sort > $submodules
-cat << EOF | awk '{ print $1 }' | sort > $want_submodules
- 9f897b25800d2f54f5c442ef01a60721aeca6d87 third_party/boringssl (version_for_cocoapods_1.0-67-g9f897b2)
- 05b155ff59114735ec8cd089f669c4c3d8f59029 third_party/gflags (v2.1.0-45-g05b155f)
- c99458533a9b4c743ed51537e25989ea55944908 third_party/googletest (release-1.7.0)
- d5fb408ddc281ffcadeb08699e65bb694656d0bd third_party/protobuf (v3.0.0-beta-2)
- 50893291621658f355bc5b4d450a8d06a563053d third_party/zlib (v1.2.8)
-EOF
+npm update
 
-diff -u $submodules $want_submodules
+node_versions=( 0.12.0 1.0.0 1.1.0 2.0.0 3.0.0 4.0.0 5.0.0 )
 
-rm $submodules $want_submodules
-
+for version in ${node_versions[@]}
+do
+  node-pre-gyp configure rebuild package testpackage --target=$version --target_arch=$NODE_TARGET_ARCH
+  cp -r build/stage/* artifacts/
+done
diff --git a/tools/run_tests/check_submodules.sh b/tools/run_tests/build_artifact_python.sh
similarity index 65%
copy from tools/run_tests/check_submodules.sh
copy to tools/run_tests/build_artifact_python.sh
index b4ca4fa..835fad8 100755
--- a/tools/run_tests/check_submodules.sh
+++ b/tools/run_tests/build_artifact_python.sh
@@ -1,6 +1,5 @@
-#!/bin/sh
-
-# Copyright 2015-2016, Google Inc.
+#!/bin/bash
+# Copyright 2016, Google Inc.
 # All rights reserved.
 #
 # Redistribution and use in source and binary forms, with or without
@@ -29,26 +28,24 @@
 # (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
 
-set -e
+cd $(dirname $0)/../..
 
-export TEST=true
+if [ "$SKIP_PIP_INSTALL" == "" ]
+then
+  pip install --upgrade six
+  pip install --upgrade setuptools
+  pip install -rrequirements.txt
+fi
 
-cd `dirname $0`/../..
+GRPC_PYTHON_USE_CUSTOM_BDIST=0  \
+GRPC_PYTHON_BUILD_WITH_CYTHON=1 \
+${SETARCH_CMD} python setup.py  \
+    bdist_wheel                 \
+    sdist                       \
+    bdist_egg_grpc_custom
 
-submodules=`mktemp /tmp/submXXXXXX`
-want_submodules=`mktemp /tmp/submXXXXXX`
+mkdir -p artifacts
 
-git submodule | awk '{ print $1 }' | sort > $submodules
-cat << EOF | awk '{ print $1 }' | sort > $want_submodules
- 9f897b25800d2f54f5c442ef01a60721aeca6d87 third_party/boringssl (version_for_cocoapods_1.0-67-g9f897b2)
- 05b155ff59114735ec8cd089f669c4c3d8f59029 third_party/gflags (v2.1.0-45-g05b155f)
- c99458533a9b4c743ed51537e25989ea55944908 third_party/googletest (release-1.7.0)
- d5fb408ddc281ffcadeb08699e65bb694656d0bd third_party/protobuf (v3.0.0-beta-2)
- 50893291621658f355bc5b4d450a8d06a563053d third_party/zlib (v1.2.8)
-EOF
-
-diff -u $submodules $want_submodules
-
-rm $submodules $want_submodules
-
+cp -r dist/* artifacts
diff --git a/tools/run_tests/check_submodules.sh b/tools/run_tests/build_artifact_ruby.sh
similarity index 66%
copy from tools/run_tests/check_submodules.sh
copy to tools/run_tests/build_artifact_ruby.sh
index b4ca4fa..2d97b40 100755
--- a/tools/run_tests/check_submodules.sh
+++ b/tools/run_tests/build_artifact_ruby.sh
@@ -1,6 +1,5 @@
-#!/bin/sh
-
-# Copyright 2015-2016, Google Inc.
+#!/bin/bash
+# Copyright 2016, Google Inc.
 # All rights reserved.
 #
 # Redistribution and use in source and binary forms, with or without
@@ -28,27 +27,40 @@
 # 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.
+set -ex
 
+SYSTEM=`uname | cut -f 1 -d_`
 
-set -e
+cd $(dirname $0)/../..
+set +ex
+[[ -s /etc/profile.d/rvm.sh ]] && . /etc/profile.d/rvm.sh
+[[ -s "$HOME/.rvm/scripts/rvm" ]] && source "$HOME/.rvm/scripts/rvm"
+set -ex
 
-export TEST=true
+if [ "$SYSTEM" == "MSYS" ] ; then
+  SYSTEM=MINGW32
+fi
+if [ "$SYSTEM" == "MINGW64" ] ; then
+  SYSTEM=MINGW32
+fi
 
-cd `dirname $0`/../..
+if [ "$SYSTEM" == "MINGW32" ] ; then
+  echo "Need Linux to build the Windows ruby gem."
+  exit 1
+fi
 
-submodules=`mktemp /tmp/submXXXXXX`
-want_submodules=`mktemp /tmp/submXXXXXX`
+set +ex
+rvm use default
+gem install bundler --update
+bundle install
+set -ex
 
-git submodule | awk '{ print $1 }' | sort > $submodules
-cat << EOF | awk '{ print $1 }' | sort > $want_submodules
- 9f897b25800d2f54f5c442ef01a60721aeca6d87 third_party/boringssl (version_for_cocoapods_1.0-67-g9f897b2)
- 05b155ff59114735ec8cd089f669c4c3d8f59029 third_party/gflags (v2.1.0-45-g05b155f)
- c99458533a9b4c743ed51537e25989ea55944908 third_party/googletest (release-1.7.0)
- d5fb408ddc281ffcadeb08699e65bb694656d0bd third_party/protobuf (v3.0.0-beta-2)
- 50893291621658f355bc5b4d450a8d06a563053d third_party/zlib (v1.2.8)
-EOF
+rake gem:native
 
-diff -u $submodules $want_submodules
+if [ "$SYSTEM" == "Darwin" ] ; then
+  rm `ls pkg/*.gem | grep -v darwin`
+fi
 
-rm $submodules $want_submodules
+mkdir -p artifacts
 
+cp pkg/*.gem artifacts
diff --git a/tools/run_tests/build_artifacts.py b/tools/run_tests/build_artifacts.py
deleted file mode 100755
index 0337f1b..0000000
--- a/tools/run_tests/build_artifacts.py
+++ /dev/null
@@ -1,238 +0,0 @@
-#!/usr/bin/env python
-# 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.
-
-"""Builds gRPC distribution artifacts."""
-
-import argparse
-import atexit
-import dockerjob
-import itertools
-import jobset
-import json
-import multiprocessing
-import os
-import re
-import subprocess
-import sys
-import time
-import uuid
-
-# Docker doesn't clean up after itself, so we do it on exit.
-if jobset.platform_string() == 'linux':
-  atexit.register(lambda: subprocess.call(['stty', 'echo']))
-
-ROOT = os.path.abspath(os.path.join(os.path.dirname(sys.argv[0]), '../..'))
-os.chdir(ROOT)
-
-
-def create_docker_jobspec(name, dockerfile_dir, shell_command, environ={},
-                   flake_retries=0, timeout_retries=0):
-  """Creates jobspec for a task running under docker."""
-  environ = environ.copy()
-  environ['RUN_COMMAND'] = shell_command
-
-  #docker_args = ['-v', '%s/artifacts:/var/local/jenkins/grpc/artifacts' % ROOT]
-  docker_args=[]
-  for k,v in environ.iteritems():
-    docker_args += ['-e', '%s=%s' % (k, v)]
-  docker_env = {'DOCKERFILE_DIR': dockerfile_dir,
-                'DOCKER_RUN_SCRIPT': 'tools/jenkins/docker_run.sh',
-                'OUTPUT_DIR': 'artifacts'}
-  jobspec = jobset.JobSpec(
-          cmdline=['tools/jenkins/build_and_run_docker.sh'] + docker_args,
-          environ=docker_env,
-          shortname='build_artifact.%s' % (name),
-          timeout_seconds=30*60,
-          flake_retries=flake_retries,
-          timeout_retries=timeout_retries)
-  return jobspec
-
-
-def create_jobspec(name, cmdline, environ=None, shell=False,
-                   flake_retries=0, timeout_retries=0):
-  """Creates jobspec."""
-  jobspec = jobset.JobSpec(
-          cmdline=cmdline,
-          environ=environ,
-          shortname='build_artifact.%s' % (name),
-          timeout_seconds=5*60,
-          flake_retries=flake_retries,
-          timeout_retries=timeout_retries,
-          shell=shell)
-  return jobspec
-
-
-def macos_arch_env(arch):
-  """Returns environ specifying -arch arguments for make."""
-  if arch == 'x86':
-    arch_arg = '-arch i386'
-  elif arch == 'x64':
-    arch_arg = '-arch x86_64'
-  else:
-    raise Exception('Unsupported arch')
-  return {'CFLAGS': arch_arg, 'LDFLAGS': arch_arg}
-
-
-class CSharpExtArtifact:
-  """Builds C# native extension library"""
-
-  def __init__(self, platform, arch):
-    self.name = 'csharp_ext_%s_%s' % (platform, arch)
-    self.platform = platform
-    self.arch = arch
-    self.labels = ['csharp', platform, arch]
-
-  def pre_build_jobspecs(self):
-    if self.platform == 'windows':
-      return [create_jobspec('prebuild_%s' % self.name,
-                             ['tools\\run_tests\\pre_build_c.bat'],
-                             shell=True,
-                             flake_retries=5,
-                             timeout_retries=2)]
-    else:
-      return []
-
-  def build_jobspec(self):
-    if self.platform == 'windows':
-      msbuild_platform = 'Win32' if self.arch == 'x86' else self.arch
-      return create_jobspec(self.name,
-                            ['tools\\run_tests\\build_artifact_csharp.bat',
-                             'vsprojects\\grpc_csharp_ext.sln',
-                             '/p:Configuration=Release',
-                             '/p:PlatformToolset=v120',
-                             '/p:Platform=%s' % msbuild_platform],
-                            shell=True)
-    else:
-      environ = {'CONFIG': 'opt',
-                 'EMBED_OPENSSL': 'true',
-                 'EMBED_ZLIB': 'true'}
-      if self.platform == 'linux':
-        return create_docker_jobspec(self.name,
-            'tools/dockerfile/grpc_artifact_linux_%s' % self.arch,
-            'tools/run_tests/build_artifact_csharp.sh')
-      else:
-        environ.update(macos_arch_env(self.arch))
-        return create_jobspec(self.name,
-                              ['tools/run_tests/build_artifact_csharp.sh'],
-                              environ=environ)
-
-  def __str__(self):
-    return self.name
-
-
-_ARTIFACTS = [
-    CSharpExtArtifact('linux', 'x86'),
-    CSharpExtArtifact('linux', 'x64'),
-    CSharpExtArtifact('macos', 'x86'),
-    CSharpExtArtifact('macos', 'x64'),
-    CSharpExtArtifact('windows', 'x86'),
-    CSharpExtArtifact('windows', 'x64')
-]
-
-
-def _create_build_map():
-  """Maps artifact names and labels to list of artifacts to be built."""
-  artifact_build_map = dict([(artifact.name, [artifact])
-                             for artifact in _ARTIFACTS])
-  if len(_ARTIFACTS) > len(artifact_build_map.keys()):
-    raise Exception('Artifact names need to be unique')
-
-  label_build_map = {}
-  label_build_map['all'] = [a for a in _ARTIFACTS]  # to build all artifacts
-  for artifact in _ARTIFACTS:
-    for label in artifact.labels:
-      if label in label_build_map:
-        label_build_map[label].append(artifact)
-      else:
-        label_build_map[label] = [artifact]
-
-  if set(artifact_build_map.keys()).intersection(label_build_map.keys()):
-    raise Exception('Artifact names need to be distinct from label names')
-  return dict( artifact_build_map.items() + label_build_map.items())
-
-
-_BUILD_MAP = _create_build_map()
-
-argp = argparse.ArgumentParser(description='Builds distribution artifacts.')
-argp.add_argument('-b', '--build',
-                  choices=sorted(_BUILD_MAP.keys()),
-                  nargs='+',
-                  default=['all'],
-                  help='Artifact name or artifact label to build.')
-argp.add_argument('-f', '--filter',
-                  choices=sorted(_BUILD_MAP.keys()),
-                  nargs='+',
-                  default=[],
-                  help='Filter artifacts to build with AND semantics.')
-argp.add_argument('-j', '--jobs', default=multiprocessing.cpu_count(), type=int)
-argp.add_argument('-t', '--travis',
-                  default=False,
-                  action='store_const',
-                  const=True)
-
-args = argp.parse_args()
-
-# Figure out which artifacts to build
-artifacts = []
-for label in args.build:
-  artifacts += _BUILD_MAP[label]
-
-# Among target selected by -b, filter out those that don't match the filter
-artifacts = [a for a in artifacts if all(f in a.labels for f in args.filter)]
-artifacts = sorted(set(artifacts))
-
-# Execute pre-build phase
-prebuild_jobs = []
-for artifact in artifacts:
-  prebuild_jobs += artifact.pre_build_jobspecs()
-if prebuild_jobs:
-  num_failures, _ = jobset.run(
-    prebuild_jobs, newline_on_success=True, maxjobs=args.jobs)
-  if num_failures != 0:
-    jobset.message('FAILED', 'Pre-build phase failed.', do_newline=True)
-    sys.exit(1)
-
-build_jobs = []
-for artifact in artifacts:
-  build_jobs.append(artifact.build_jobspec())
-if not build_jobs:
-  print 'Nothing to build.'
-  sys.exit(1)
-
-jobset.message('START', 'Building artifacts.', do_newline=True)
-num_failures, _ = jobset.run(
-    build_jobs, newline_on_success=True, maxjobs=args.jobs)
-if num_failures == 0:
-  jobset.message('SUCCESS', 'All artifacts built successfully.',
-                 do_newline=True)
-else:
-  jobset.message('FAILED', 'Failed to build artifacts.',
-                 do_newline=True)
-  sys.exit(1)
diff --git a/tools/run_tests/build_node.bat b/tools/run_tests/build_node.bat
new file mode 100644
index 0000000..6896bc1
--- /dev/null
+++ b/tools/run_tests/build_node.bat
@@ -0,0 +1,30 @@
+@rem Copyright 2016, Google Inc.
+@rem All rights reserved.
+@rem
+@rem Redistribution and use in source and binary forms, with or without
+@rem modification, are permitted provided that the following conditions are
+@rem met:
+@rem
+@rem     * Redistributions of source code must retain the above copyright
+@rem notice, this list of conditions and the following disclaimer.
+@rem     * Redistributions in binary form must reproduce the above
+@rem copyright notice, this list of conditions and the following disclaimer
+@rem in the documentation and/or other materials provided with the
+@rem distribution.
+@rem     * Neither the name of Google Inc. nor the names of its
+@rem contributors may be used to endorse or promote products derived from
+@rem this software without specific prior written permission.
+@rem
+@rem THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+@rem "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+@rem LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+@rem A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+@rem OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+@rem SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+@rem LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+@rem DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+@rem THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+@rem (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+@rem OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+npm install --build-from-source
\ No newline at end of file
diff --git a/tools/run_tests/build_node.sh b/tools/run_tests/build_node.sh
index 8f2ab44..9c4af07 100755
--- a/tools/run_tests/build_node.sh
+++ b/tools/run_tests/build_node.sh
@@ -29,8 +29,12 @@
 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
+NODE_VERSION=$1
+source ~/.nvm/nvm.sh
 set -ex
 
+nvm use $NODE_VERSION
+
 CONFIG=${CONFIG:-opt}
 
 # change to grpc repo root
diff --git a/tools/run_tests/check_submodules.sh b/tools/run_tests/build_package_node.sh
similarity index 65%
copy from tools/run_tests/check_submodules.sh
copy to tools/run_tests/build_package_node.sh
index b4ca4fa..a8b9448 100755
--- a/tools/run_tests/check_submodules.sh
+++ b/tools/run_tests/build_package_node.sh
@@ -1,6 +1,5 @@
-#!/bin/sh
-
-# Copyright 2015-2016, Google Inc.
+#!/bin/bash
+# Copyright 2016, Google Inc.
 # All rights reserved.
 #
 # Redistribution and use in source and binary forms, with or without
@@ -29,26 +28,16 @@
 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
+source ~/.nvm/nvm.sh
+set -ex
 
-set -e
+nvm use 4
 
-export TEST=true
+cd $(dirname $0)/../..
 
-cd `dirname $0`/../..
+mkdir -p artifacts/
+cp -r $EXTERNAL_GIT_ROOT/architecture={x86,x64},language=node,platform={windows,linux,macos}/artifacts/* artifacts/ || true
 
-submodules=`mktemp /tmp/submXXXXXX`
-want_submodules=`mktemp /tmp/submXXXXXX`
+npm pack
 
-git submodule | awk '{ print $1 }' | sort > $submodules
-cat << EOF | awk '{ print $1 }' | sort > $want_submodules
- 9f897b25800d2f54f5c442ef01a60721aeca6d87 third_party/boringssl (version_for_cocoapods_1.0-67-g9f897b2)
- 05b155ff59114735ec8cd089f669c4c3d8f59029 third_party/gflags (v2.1.0-45-g05b155f)
- c99458533a9b4c743ed51537e25989ea55944908 third_party/googletest (release-1.7.0)
- d5fb408ddc281ffcadeb08699e65bb694656d0bd third_party/protobuf (v3.0.0-beta-2)
- 50893291621658f355bc5b4d450a8d06a563053d third_party/zlib (v1.2.8)
-EOF
-
-diff -u $submodules $want_submodules
-
-rm $submodules $want_submodules
-
+cp grpc-*.tgz artifacts/grpc.tgz
diff --git a/tools/run_tests/check_submodules.sh b/tools/run_tests/build_package_python.sh
similarity index 65%
copy from tools/run_tests/check_submodules.sh
copy to tools/run_tests/build_package_python.sh
index b4ca4fa..2511a6a 100755
--- a/tools/run_tests/check_submodules.sh
+++ b/tools/run_tests/build_package_python.sh
@@ -1,6 +1,5 @@
-#!/bin/sh
-
-# Copyright 2015-2016, Google Inc.
+#!/bin/bash
+# Copyright 2016, Google Inc.
 # All rights reserved.
 #
 # Redistribution and use in source and binary forms, with or without
@@ -29,26 +28,16 @@
 # (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
 
-set -e
+cd $(dirname $0)/../..
 
-export TEST=true
+mkdir -p artifacts/
 
-cd `dirname $0`/../..
+# All the python packages have been built in the artifact phase already
+# and we only collect them here to deliver them to the distribtest phase.
+cp -r $EXTERNAL_GIT_ROOT/architecture={x86,x64},language=python,platform={windows,linux,macos}/artifacts/* artifacts/ || true
 
-submodules=`mktemp /tmp/submXXXXXX`
-want_submodules=`mktemp /tmp/submXXXXXX`
-
-git submodule | awk '{ print $1 }' | sort > $submodules
-cat << EOF | awk '{ print $1 }' | sort > $want_submodules
- 9f897b25800d2f54f5c442ef01a60721aeca6d87 third_party/boringssl (version_for_cocoapods_1.0-67-g9f897b2)
- 05b155ff59114735ec8cd089f669c4c3d8f59029 third_party/gflags (v2.1.0-45-g05b155f)
- c99458533a9b4c743ed51537e25989ea55944908 third_party/googletest (release-1.7.0)
- d5fb408ddc281ffcadeb08699e65bb694656d0bd third_party/protobuf (v3.0.0-beta-2)
- 50893291621658f355bc5b4d450a8d06a563053d third_party/zlib (v1.2.8)
-EOF
-
-diff -u $submodules $want_submodules
-
-rm $submodules $want_submodules
-
+# TODO: all the artifact builder configurations generate a grpcio-VERSION.tar.gz
+# source distribution package, and only one of them will end up
+# in the artifacts/ directory. They should be all equivalent though.
diff --git a/tools/run_tests/check_submodules.sh b/tools/run_tests/build_package_ruby.sh
similarity index 65%
copy from tools/run_tests/check_submodules.sh
copy to tools/run_tests/build_package_ruby.sh
index b4ca4fa..1a5b943 100755
--- a/tools/run_tests/check_submodules.sh
+++ b/tools/run_tests/build_package_ruby.sh
@@ -1,6 +1,5 @@
-#!/bin/sh
-
-# Copyright 2015-2016, Google Inc.
+#!/bin/bash
+# Copyright 2016, Google Inc.
 # All rights reserved.
 #
 # Redistribution and use in source and binary forms, with or without
@@ -29,26 +28,16 @@
 # (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
 
-set -e
+cd $(dirname $0)/../..
 
-export TEST=true
+mkdir -p artifacts/
 
-cd `dirname $0`/../..
+# All the ruby packages have been built in the artifact phase already
+# and we only collect them here to deliver them to the distribtest phase.
+cp -r $EXTERNAL_GIT_ROOT/architecture={x86,x64},language=ruby,platform={windows,linux,macos}/artifacts/* artifacts/ || true
 
-submodules=`mktemp /tmp/submXXXXXX`
-want_submodules=`mktemp /tmp/submXXXXXX`
-
-git submodule | awk '{ print $1 }' | sort > $submodules
-cat << EOF | awk '{ print $1 }' | sort > $want_submodules
- 9f897b25800d2f54f5c442ef01a60721aeca6d87 third_party/boringssl (version_for_cocoapods_1.0-67-g9f897b2)
- 05b155ff59114735ec8cd089f669c4c3d8f59029 third_party/gflags (v2.1.0-45-g05b155f)
- c99458533a9b4c743ed51537e25989ea55944908 third_party/googletest (release-1.7.0)
- d5fb408ddc281ffcadeb08699e65bb694656d0bd third_party/protobuf (v3.0.0-beta-2)
- 50893291621658f355bc5b4d450a8d06a563053d third_party/zlib (v1.2.8)
-EOF
-
-diff -u $submodules $want_submodules
-
-rm $submodules $want_submodules
-
+# TODO: all the artifact builder configurations generate a grpc-VERSION.gem
+# source distribution package, and only one of them will end up
+# in the artifacts/ directory. They should be all equivalent though.
diff --git a/tools/run_tests/build_ruby.sh b/tools/run_tests/build_ruby.sh
index 8acb40d..ebd27f6 100755
--- a/tools/run_tests/build_ruby.sh
+++ b/tools/run_tests/build_ruby.sh
@@ -1,6 +1,6 @@
 #!/bin/bash
 
-# Copyright 2015, Google Inc.
+# Copyright 2015-2016, Google Inc.
 # All rights reserved.
 #
 # Redistribution and use in source and binary forms, with or without
@@ -37,4 +37,4 @@
 cd $(dirname $0)/../..
 
 rm -rf ./tmp
-rake compile:grpc
+rake compile
diff --git a/tools/run_tests/configs.json b/tools/run_tests/configs.json
index 769942d..d508c63 100644
--- a/tools/run_tests/configs.json
+++ b/tools/run_tests/configs.json
@@ -59,7 +59,7 @@
   }, 
   {
     "config": "msan", 
-    "timeout_multiplier": 1.5
+    "timeout_multiplier": 2
   }, 
   {
     "config": "mutrace"
diff --git a/tools/run_tests/distribtest_targets.py b/tools/run_tests/distribtest_targets.py
new file mode 100644
index 0000000..b26a870
--- /dev/null
+++ b/tools/run_tests/distribtest_targets.py
@@ -0,0 +1,250 @@
+#!/usr/bin/env python2.7
+# 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.
+
+"""Definition of targets run distribution package tests."""
+
+import jobset
+
+
+def create_docker_jobspec(name, dockerfile_dir, shell_command, environ={},
+                   flake_retries=0, timeout_retries=0):
+  """Creates jobspec for a task running under docker."""
+  environ = environ.copy()
+  environ['RUN_COMMAND'] = shell_command
+  environ['RELATIVE_COPY_PATH'] = 'test/distrib'
+
+  docker_args=[]
+  for k,v in environ.iteritems():
+    docker_args += ['-e', '%s=%s' % (k, v)]
+  docker_env = {'DOCKERFILE_DIR': dockerfile_dir,
+                'DOCKER_RUN_SCRIPT': 'tools/jenkins/docker_run.sh'}
+  jobspec = jobset.JobSpec(
+          cmdline=['tools/jenkins/build_and_run_docker.sh'] + docker_args,
+          environ=docker_env,
+          shortname='distribtest.%s' % (name),
+          timeout_seconds=30*60,
+          flake_retries=flake_retries,
+          timeout_retries=timeout_retries)
+  return jobspec
+
+
+def create_jobspec(name, cmdline, environ=None, shell=False,
+                   flake_retries=0, timeout_retries=0):
+  """Creates jobspec."""
+  jobspec = jobset.JobSpec(
+          cmdline=cmdline,
+          environ=environ,
+          shortname='distribtest.%s' % (name),
+          timeout_seconds=10*60,
+          flake_retries=flake_retries,
+          timeout_retries=timeout_retries,
+          shell=shell)
+  return jobspec
+
+
+class CSharpDistribTest(object):
+  """Tests C# NuGet package"""
+
+  def __init__(self, platform, arch, docker_suffix=None):
+    self.name = 'csharp_nuget_%s_%s' % (platform, arch)
+    self.platform = platform
+    self.arch = arch
+    self.docker_suffix = docker_suffix
+    self.labels = ['distribtest', 'csharp', platform, arch]
+    if docker_suffix:
+      self.name += '_%s' % docker_suffix
+      self.labels.append(docker_suffix)
+
+  def pre_build_jobspecs(self):
+    return []
+
+  def build_jobspec(self):
+    if self.platform == 'linux':
+      return create_docker_jobspec(self.name,
+          'tools/dockerfile/distribtest/csharp_%s_%s' % (
+              self.docker_suffix,
+              self.arch),
+          'test/distrib/csharp/run_distrib_test.sh')
+    elif self.platform == 'macos':
+      return create_jobspec(self.name,
+          ['test/distrib/csharp/run_distrib_test.sh'],
+          environ={'EXTERNAL_GIT_ROOT': '../../..'})
+    else:
+      raise Exception("Not supported yet.")
+
+  def __str__(self):
+    return self.name
+
+class NodeDistribTest(object):
+  """Tests Node package"""
+
+  def __init__(self, platform, arch, docker_suffix, node_version):
+    self.name = 'node_npm_%s_%s_%s' % (platform, arch, node_version)
+    self.platform = platform
+    self.arch = arch
+    self.node_version = node_version
+    self.labels = ['distribtest', 'node', platform, arch,
+                   'node-%s' % node_version]
+    if docker_suffix is not None:
+      self.name += '_%s' % docker_suffix
+      self.docker_suffix = docker_suffix
+      self.labels.append(docker_suffix)
+
+  def pre_build_jobspecs(self):
+    return []
+
+  def build_jobspec(self):
+    if self.platform == 'linux':
+      return create_docker_jobspec(self.name,
+                                   'tools/dockerfile/distribtest/node_%s_%s' % (
+                                       self.docker_suffix,
+                                       self.arch),
+                                   'test/distrib/node/run_distrib_test.sh %s' % (
+                                       self.node_version))
+    elif self.platform == 'macos':
+      return create_jobspec(self.name,
+                            ['test/distrib/node/run_distrib_test.sh',
+                             str(self.node_version)],
+                            environ={'EXTERNAL_GIT_ROOT': '../../..'})
+    else:
+      raise Exception("Not supported yet.")
+
+    def __str__(self):
+      return self.name
+
+
+class PythonDistribTest(object):
+  """Tests Python package"""
+
+  def __init__(self, platform, arch, docker_suffix):
+    self.name = 'python_%s_%s_%s' % (platform, arch, docker_suffix)
+    self.platform = platform
+    self.arch = arch
+    self.docker_suffix = docker_suffix
+    self.labels = ['distribtest', 'python', platform, arch, docker_suffix]
+
+  def pre_build_jobspecs(self):
+    return []
+
+  def build_jobspec(self):
+    if not self.platform == 'linux':
+      raise Exception("Not supported yet.")
+
+    return create_docker_jobspec(self.name,
+          'tools/dockerfile/distribtest/python_%s_%s' % (
+              self.docker_suffix,
+              self.arch),
+          'test/distrib/python/run_distrib_test.sh')
+
+  def __str__(self):
+    return self.name
+
+
+class RubyDistribTest(object):
+  """Tests Ruby package"""
+
+  def __init__(self, platform, arch, docker_suffix):
+    self.name = 'ruby_%s_%s_%s' % (platform, arch, docker_suffix)
+    self.platform = platform
+    self.arch = arch
+    self.docker_suffix = docker_suffix
+    self.labels = ['distribtest', 'ruby', platform, arch, docker_suffix]
+
+  def pre_build_jobspecs(self):
+    return []
+
+  def build_jobspec(self):
+    if not self.platform == 'linux':
+      raise Exception("Not supported yet.")
+
+    return create_docker_jobspec(self.name,
+          'tools/dockerfile/distribtest/ruby_%s_%s' % (
+              self.docker_suffix,
+              self.arch),
+          'test/distrib/ruby/run_distrib_test.sh')
+
+  def __str__(self):
+    return self.name
+
+
+def targets():
+  """Gets list of supported targets"""
+  return [CSharpDistribTest('linux', 'x64', 'wheezy'),
+          CSharpDistribTest('linux', 'x64', 'jessie'),
+          CSharpDistribTest('linux', 'x86', 'jessie'),
+          CSharpDistribTest('linux', 'x64', 'centos7'),
+          CSharpDistribTest('linux', 'x64', 'ubuntu1404'),
+          CSharpDistribTest('linux', 'x64', 'ubuntu1504'),
+          CSharpDistribTest('linux', 'x64', 'ubuntu1510'),
+          CSharpDistribTest('linux', 'x64', 'ubuntu1604'),
+          CSharpDistribTest('macos', 'x86'),
+          PythonDistribTest('linux', 'x64', 'wheezy'),
+          PythonDistribTest('linux', 'x64', 'jessie'),
+          PythonDistribTest('linux', 'x86', 'jessie'),
+          PythonDistribTest('linux', 'x64', 'centos6'),
+          PythonDistribTest('linux', 'x64', 'centos7'),
+          PythonDistribTest('linux', 'x64', 'fedora20'),
+          PythonDistribTest('linux', 'x64', 'fedora21'),
+          PythonDistribTest('linux', 'x64', 'fedora22'),
+          PythonDistribTest('linux', 'x64', 'fedora23'),
+          PythonDistribTest('linux', 'x64', 'opensuse'),
+          PythonDistribTest('linux', 'x64', 'arch'),
+          PythonDistribTest('linux', 'x64', 'ubuntu1204'),
+          PythonDistribTest('linux', 'x64', 'ubuntu1404'),
+          PythonDistribTest('linux', 'x64', 'ubuntu1504'),
+          PythonDistribTest('linux', 'x64', 'ubuntu1510'),
+          PythonDistribTest('linux', 'x64', 'ubuntu1604'),
+          RubyDistribTest('linux', 'x64', 'wheezy'),
+          RubyDistribTest('linux', 'x64', 'jessie'),
+          RubyDistribTest('linux', 'x86', 'jessie'),
+          RubyDistribTest('linux', 'x64', 'centos6'),
+          RubyDistribTest('linux', 'x64', 'centos7'),
+          RubyDistribTest('linux', 'x64', 'fedora20'),
+          RubyDistribTest('linux', 'x64', 'fedora21'),
+          RubyDistribTest('linux', 'x64', 'fedora22'),
+          RubyDistribTest('linux', 'x64', 'fedora23'),
+          RubyDistribTest('linux', 'x64', 'opensuse'),
+          RubyDistribTest('linux', 'x64', 'ubuntu1204'),
+          RubyDistribTest('linux', 'x64', 'ubuntu1404'),
+          RubyDistribTest('linux', 'x64', 'ubuntu1504'),
+          RubyDistribTest('linux', 'x64', 'ubuntu1510'),
+          RubyDistribTest('linux', 'x64', 'ubuntu1604'),
+          NodeDistribTest('macos', 'x64', None, '0.10'),
+          NodeDistribTest('macos', 'x64', None, '0.12'),
+          NodeDistribTest('macos', 'x64', None, '3'),
+          NodeDistribTest('macos', 'x64', None, '4'),
+          NodeDistribTest('macos', 'x64', None, '5'),
+          NodeDistribTest('linux', 'x86', 'jessie', '4')
+          ] + [
+            NodeDistribTest('linux', 'x64', os, version)
+            for os in ('wheezy', 'jessie', 'ubuntu1204', 'ubuntu1404',
+                       'ubuntu1504', 'ubuntu1510', 'ubuntu1604')
+            for version in ('0.12', '3', '4', '5')
+          ]
diff --git a/tools/run_tests/interop_html_report.template b/tools/run_tests/interop_html_report.template
index c01bdf7..46cce42 100644
--- a/tools/run_tests/interop_html_report.template
+++ b/tools/run_tests/interop_html_report.template
@@ -46,31 +46,26 @@
     ## Because interop tests does not have runs_per_test flag, each test is 
     ## run once. So there should only be one element for each result.
     <% result = resultset[shortname][0] %>
-    <td bgcolor="white">
-      <div style="width:95%; border: 1px solid black; position: relative; padding: 3px;">
-        <span style="position: absolute; left: 45%;">${int(result.http2results['percent'] * 100)}&#37;</span>
-        <div style="height: 20px; 
-          background-color: hsl(${result.http2results['percent'] * 120}, 100%, 50%); 
-          width: ${result.http2results['percent'] * 100}%;"
-          title="${result.http2results['failed_cases'] | h}"></div>
-      </div>
-    </td>
+    % if result.http2results:
+      <td bgcolor="white">
+        <div style="width:95%; border: 1px solid black; position: relative; padding: 3px;">
+          <span style="position: absolute; left: 45%;">${int(result.http2results['percent'] * 100)}&#37;</span>
+          <div style="height: 20px; 
+            background-color: hsl(${result.http2results['percent'] * 120}, 100%, 50%); 
+            width: ${result.http2results['percent'] * 100}%;"
+            title="${result.http2results['failed_cases'] | h}"></div>
+        </div>
+      </td>
+    % else: 
+      <td bgcolor="red">No result is found!</td>
+    % endif
   % else:
      <td bgcolor="magenta">Not implemented</td>
   % endif
 </%def>
 
-% if num_failures > 1:
-  <p><h2><font color="red">${num_failures} tests failed!</font></h2></p>
-% elif num_failures:
-  <p><h2><font color="red">${num_failures} test failed!</font></h2></p>
-% else:
-  <p><h2><font color="green">All tests passed!</font></h2></p>
-% endif
-
-% if cloud_to_prod:
+<%def name="display_cloud_to_prod_result(prod_server)">
   ## Each column header is the client language.
-  <h2>Cloud to Prod</h2>
   <table style="width:100%" border="1">
   <tr bgcolor="#00BFFF">
   <th>Client languages &#9658;<br/>Test Cases &#9660;</th>
@@ -83,15 +78,32 @@
     % for client_lang in client_langs:
       <% 
         if test_case in auth_test_cases:
-          shortname = 'cloud_to_prod_auth:%s:%s' % (client_lang, test_case)
+          shortname = 'cloud_to_prod_auth:%s:%s:%s' % (
+              prod_server, client_lang, test_case)
         else:
-          shortname = 'cloud_to_prod:%s:%s' % (client_lang, test_case)
+          shortname = 'cloud_to_prod:%s:%s:%s' % (
+              prod_server, client_lang, test_case)
       %>
       ${fill_one_test_result(shortname, resultset)}
     % endfor
     </tr> 
   % endfor
   </table>
+</%def>
+
+% if num_failures > 1:
+  <p><h2><font color="red">${num_failures} tests failed!</font></h2></p>
+% elif num_failures:
+  <p><h2><font color="red">${num_failures} test failed!</font></h2></p>
+% else:
+  <p><h2><font color="green">All tests passed!</font></h2></p>
+% endif
+
+% if cloud_to_prod:
+  % for prod_server in prod_servers:
+    <h2>Cloud to ${prod_server}</h2>
+    ${display_cloud_to_prod_result(prod_server)}
+  % endfor
 % endif
 
 % if http2_interop:
@@ -104,7 +116,9 @@
     <th>${server_lang}</th>
   % endfor
   % if cloud_to_prod:
-    <th>prod</th>
+    % for prod_server in prod_servers:
+      <th>${prod_server}</th>
+    % endfor
   % endif
   </tr>
   % for test_case in http2_cases:
@@ -118,8 +132,10 @@
       ${fill_one_http2_test_result(shortname, resultset)}
     % endfor
     % if cloud_to_prod:
-      <% shortname = 'cloud_to_prod:http2:%s' % test_case %>
-      ${fill_one_http2_test_result(shortname, resultset)}
+      % for prod_server in prod_servers:
+        <% shortname = 'cloud_to_prod:%s:http2:%s' % (prod_server, test_case) %>
+        ${fill_one_http2_test_result(shortname, resultset)}
+      % endfor
     % endif
     </tr>
   % endfor
diff --git a/tools/run_tests/jobset.py b/tools/run_tests/jobset.py
index beeb99c..adf178b 100755
--- a/tools/run_tests/jobset.py
+++ b/tools/run_tests/jobset.py
@@ -360,7 +360,7 @@
       if self.cancelled(): return False
       current_cpu_cost = self.cpu_cost()
       if current_cpu_cost == 0: break
-      if current_cpu_cost + spec.cpu_cost < self._maxjobs: break
+      if current_cpu_cost + spec.cpu_cost <= self._maxjobs: break
       self.reap()
     if self.cancelled(): return False
     if spec.hash_targets:
diff --git a/tools/run_tests/package_targets.py b/tools/run_tests/package_targets.py
new file mode 100644
index 0000000..4ca8279
--- /dev/null
+++ b/tools/run_tests/package_targets.py
@@ -0,0 +1,147 @@
+#!/usr/bin/env python2.7
+# 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.
+
+"""Definition of targets to build distribution packages."""
+
+import jobset
+
+def create_docker_jobspec(name, dockerfile_dir, shell_command, environ={},
+                   flake_retries=0, timeout_retries=0):
+  """Creates jobspec for a task running under docker."""
+  environ = environ.copy()
+  environ['RUN_COMMAND'] = shell_command
+
+  docker_args=[]
+  for k,v in environ.iteritems():
+    docker_args += ['-e', '%s=%s' % (k, v)]
+  docker_env = {'DOCKERFILE_DIR': dockerfile_dir,
+                'DOCKER_RUN_SCRIPT': 'tools/jenkins/docker_run.sh',
+                'OUTPUT_DIR': 'artifacts'}
+  jobspec = jobset.JobSpec(
+          cmdline=['tools/jenkins/build_and_run_docker.sh'] + docker_args,
+          environ=docker_env,
+          shortname='build_package.%s' % (name),
+          timeout_seconds=30*60,
+          flake_retries=flake_retries,
+          timeout_retries=timeout_retries)
+  return jobspec
+
+def create_jobspec(name, cmdline, environ=None, cwd=None, shell=False,
+                   flake_retries=0, timeout_retries=0):
+  """Creates jobspec."""
+  jobspec = jobset.JobSpec(
+          cmdline=cmdline,
+          environ=environ,
+          cwd=cwd,
+          shortname='build_package.%s' % (name),
+          timeout_seconds=10*60,
+          flake_retries=flake_retries,
+          timeout_retries=timeout_retries,
+          shell=shell)
+  return jobspec
+
+
+class CSharpPackage:
+  """Builds C# nuget packages."""
+
+  def __init__(self):
+    self.name = 'csharp_package'
+    self.labels = ['package', 'csharp', 'windows']
+
+  def pre_build_jobspecs(self):
+    return []
+
+  def build_jobspec(self):
+    return create_jobspec(self.name,
+                          ['build_packages.bat'],
+                          cwd='src\\csharp',
+                          shell=True)
+
+  def __str__(self):
+    return self.name
+
+
+class NodePackage:
+  """Builds Node NPM package and collects precompiled binaries"""
+
+  def __init__(self):
+    self.name = 'node_package'
+    self.labels = ['package', 'node', 'linux']
+
+  def pre_build_jobspecs(self):
+    return []
+
+  def build_jobspec(self):
+    return create_docker_jobspec(
+        self.name,
+        'tools/dockerfile/grpc_artifact_linux_x64',
+        'tools/run_tests/build_package_node.sh')
+
+
+class RubyPackage:
+  """Collects ruby gems created in the artifact phase"""
+
+  def __init__(self):
+    self.name = 'ruby_package'
+    self.labels = ['package', 'ruby', 'linux']
+
+  def pre_build_jobspecs(self):
+    return []
+
+  def build_jobspec(self):
+    return create_docker_jobspec(
+        self.name,
+        'tools/dockerfile/grpc_artifact_linux_x64',
+        'tools/run_tests/build_package_ruby.sh')
+
+
+class PythonPackage:
+  """Collects python eggs and wheels created in the artifact phase"""
+
+  def __init__(self):
+    self.name = 'python_package'
+    self.labels = ['package', 'python', 'linux']
+
+  def pre_build_jobspecs(self):
+    return []
+
+  def build_jobspec(self):
+    return create_docker_jobspec(
+        self.name,
+        'tools/dockerfile/grpc_artifact_linux_x64',
+        'tools/run_tests/build_package_python.sh')
+
+
+def targets():
+  """Gets list of supported targets"""
+  return [CSharpPackage(),
+          NodePackage(),
+          RubyPackage(),
+          PythonPackage()]
diff --git a/tools/run_tests/pre_build_csharp.sh b/tools/run_tests/pre_build_csharp.sh
index 4341c02..32466c2 100755
--- a/tools/run_tests/pre_build_csharp.sh
+++ b/tools/run_tests/pre_build_csharp.sh
@@ -39,8 +39,3 @@
 then
   nuget restore Grpc.sln
 fi
-
-if [ -n "$NUGET" ]
-then
-  $NUGET restore Grpc.sln
-fi
diff --git a/tools/run_tests/pre_build_node.bat b/tools/run_tests/pre_build_node.bat
new file mode 100644
index 0000000..6e7cbe5
--- /dev/null
+++ b/tools/run_tests/pre_build_node.bat
@@ -0,0 +1,39 @@
+@rem Copyright 2016, Google Inc.
+@rem All rights reserved.
+@rem
+@rem Redistribution and use in source and binary forms, with or without
+@rem modification, are permitted provided that the following conditions are
+@rem met:
+@rem
+@rem     * Redistributions of source code must retain the above copyright
+@rem notice, this list of conditions and the following disclaimer.
+@rem     * Redistributions in binary form must reproduce the above
+@rem copyright notice, this list of conditions and the following disclaimer
+@rem in the documentation and/or other materials provided with the
+@rem distribution.
+@rem     * Neither the name of Google Inc. nor the names of its
+@rem contributors may be used to endorse or promote products derived from
+@rem this software without specific prior written permission.
+@rem
+@rem THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+@rem "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+@rem LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+@rem A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+@rem OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+@rem SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+@rem LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+@rem DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+@rem THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+@rem (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+@rem OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+@rem Expire cache after 1 week
+npm update --cache-min 604800
+
+npm install node-gyp-install
+.\node_modules\.bin\node-gyp-install.cmd
+
+@rem delete the redundant openssl headers
+for /f "delims=v" %%v in ('node --version') do (
+  rmdir "%HOMEDRIVE%%HOMEPATH%\.node-gyp\%%v\include\node\openssl" /S /Q
+)
\ No newline at end of file
diff --git a/tools/run_tests/pre_build_node.sh b/tools/run_tests/pre_build_node.sh
index 28ce354..11f46d6 100755
--- a/tools/run_tests/pre_build_node.sh
+++ b/tools/run_tests/pre_build_node.sh
@@ -1,6 +1,6 @@
 #!/bin/bash
 
-# Copyright 2015, Google Inc.
+# Copyright 2015-2016, Google Inc.
 # All rights reserved.
 #
 # Redistribution and use in source and binary forms, with or without
@@ -29,8 +29,12 @@
 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
+NODE_VERSION=$1
+source ~/.nvm/nvm.sh
 set -ex
 
+nvm use $NODE_VERSION
+
 export GRPC_CONFIG=${CONFIG:-opt}
 
 # Expire cache after 1 week
diff --git a/tools/run_tests/report_utils.py b/tools/run_tests/report_utils.py
index 35f2069..0032a98 100644
--- a/tools/run_tests/report_utils.py
+++ b/tools/run_tests/report_utils.py
@@ -1,4 +1,4 @@
-# Copyright 2015, Google Inc.
+# Copyright 2015-2016, Google Inc.
 # All rights reserved.
 #
 # Redistribution and use in source and binary forms, with or without
@@ -77,7 +77,7 @@
 
 def render_interop_html_report(
   client_langs, server_langs, test_cases, auth_test_cases, http2_cases, 
-  resultset, num_failures, cloud_to_prod, http2_interop):
+  resultset, num_failures, cloud_to_prod, prod_servers, http2_interop):
   """Generate HTML report for interop tests."""
   template_file = 'tools/run_tests/interop_html_report.template'
   try:
@@ -94,6 +94,7 @@
   sorted_http2_cases = sorted(http2_cases)
   sorted_client_langs = sorted(client_langs)
   sorted_server_langs = sorted(server_langs)
+  sorted_prod_servers = sorted(prod_servers)
 
   args = {'client_langs': sorted_client_langs, 
           'server_langs': sorted_server_langs,
@@ -103,6 +104,7 @@
           'resultset': resultset,
           'num_failures': num_failures,
           'cloud_to_prod': cloud_to_prod,
+          'prod_servers': sorted_prod_servers,
           'http2_interop': http2_interop}
 
   html_report_out_dir = 'reports' 
diff --git a/tools/run_tests/run_interop_tests.py b/tools/run_tests/run_interop_tests.py
index 6ce618e..76be932 100755
--- a/tools/run_tests/run_interop_tests.py
+++ b/tools/run_tests/run_interop_tests.py
@@ -1,4 +1,4 @@
-#!/usr/bin/env python
+#!/usr/bin/env python2.7
 # Copyright 2015-2016, Google Inc.
 # All rights reserved.
 #
@@ -422,12 +422,13 @@
     time.sleep(2)
 
 
-def cloud_to_prod_jobspec(language, test_case, docker_image=None, auth=False):
+def cloud_to_prod_jobspec(language, test_case, server_host_name, 
+                          server_host_detail, docker_image=None, auth=False):
   """Creates jobspec for cloud-to-prod interop test"""
   container_name = None
   cmdargs = [
-      '--server_host_override=grpc-test.sandbox.googleapis.com',
-      '--server_host=grpc-test.sandbox.googleapis.com',
+      '--server_host=%s' % server_host_detail[0],
+      '--server_host_override=%s' % server_host_detail[1],
       '--server_port=443',
       '--use_tls=true',
       '--test_case=%s' % test_case]
@@ -440,7 +441,8 @@
   cwd = language.client_cwd
 
   if docker_image:
-    container_name = dockerjob.random_name('interop_client_%s' % language.safename)
+    container_name = dockerjob.random_name('interop_client_%s' % 
+                                           language.safename)
     cmdline = docker_run_cmdline(cmdline,
                                  image=docker_image,
                                  cwd=cwd,
@@ -455,7 +457,8 @@
           cmdline=cmdline,
           cwd=cwd,
           environ=environ,
-          shortname='%s:%s:%s' % (suite_name, language, test_case),
+          shortname='%s:%s:%s:%s' % (suite_name, server_host_name, language, 
+                                     test_case),
           timeout_seconds=90,
           flake_retries=5 if args.allow_flakes else 0,
           timeout_retries=2 if args.allow_flakes else 0,
@@ -491,7 +494,7 @@
           cwd=cwd,
           environ=environ,
           shortname='cloud_to_cloud:%s:%s_server:%s' % (language, server_name,
-                                                 test_case),
+                                                        test_case),
           timeout_seconds=90,
           flake_retries=5 if args.allow_flakes else 0,
           timeout_retries=2 if args.allow_flakes else 0,
@@ -532,10 +535,10 @@
     env['TTY_FLAG'] = '-t'
   # This env variable is used to get around the github rate limit
   # error when running the PHP `composer install` command
-  # TODO(stanleycheung): find a more elegant way to do this
-  if language.safename == 'php' and os.path.exists('/var/local/.composer/auth.json'):
+  host_file = '%s/.composer/auth.json' % os.environ['HOME']
+  if language.safename == 'php' and os.path.exists(host_file):
     env['BUILD_INTEROP_DOCKER_EXTRA_ARGS'] = \
-      '-v /var/local/.composer/auth.json:/root/.composer/auth.json:ro'
+      '-v %s:/root/.composer/auth.json:ro' % host_file
   build_job = jobset.JobSpec(
           cmdline=['tools/jenkins/build_interop_image.sh'],
           environ=env,
@@ -572,6 +575,21 @@
     'percent': 1.0 * passed / (passed + failed)
   }
 
+# A dictionary of prod servers to test. 
+# Format: server_name: (server_host, server_host_override, errors_allowed)
+# TODO(adelez): implement logic for errors_allowed where if the indicated tests
+# fail, they don't impact the overall test result.
+prod_servers = {
+    'default': ('grpc-test.sandbox.googleapis.com', 
+                'grpc-test.sandbox.googleapis.com', False),
+    'gateway_v2': ('grpc-test2.sandbox.googleapis.com', 
+                   'grpc-test2.sandbox.googleapis.com', True),
+    'cloud_gateway': ('216.239.32.255', 'grpc-test.sandbox.googleapis.com', 
+                      False),
+    'cloud_gateway_v2': ('216.239.32.255', 'grpc-test2.sandbox.googleapis.com', 
+                         True)
+}
+
 argp = argparse.ArgumentParser(description='Run interop tests.')
 argp.add_argument('-l', '--language',
                   choices=['all'] + sorted(_LANGUAGES),
@@ -589,6 +607,12 @@
                   action='store_const',
                   const=True,
                   help='Run cloud_to_prod_auth tests.')
+argp.add_argument('--prod_servers',
+                  choices=prod_servers.keys(),
+                  default=['default'],
+                  nargs='+',
+                  help=('The servers to run cloud_to_prod and '
+                        'cloud_to_prod_auth tests against.'))
 argp.add_argument('-s', '--server',
                   choices=['all'] + sorted(_SERVERS),
                   action='append',
@@ -688,32 +712,37 @@
     server_jobs[lang] = job
     server_addresses[lang] = ('localhost', job.mapped_port(_DEFAULT_SERVER_PORT))
 
-
   jobs = []
   if args.cloud_to_prod:
-    for language in languages:
-      for test_case in _TEST_CASES:
-        if not test_case in language.unimplemented_test_cases():
-          if not test_case in _SKIP_ADVANCED + _SKIP_COMPRESSION:
-            test_job = cloud_to_prod_jobspec(language, test_case,
-                                             docker_image=docker_images.get(str(language)))
-            jobs.append(test_job)
+    for server_host_name in args.prod_servers:
+      for language in languages:
+        for test_case in _TEST_CASES:
+          if not test_case in language.unimplemented_test_cases():
+            if not test_case in _SKIP_ADVANCED + _SKIP_COMPRESSION:
+              test_job = cloud_to_prod_jobspec(
+                  language, test_case, server_host_name, 
+                  prod_servers[server_host_name],
+                  docker_image=docker_images.get(str(language)))
+              jobs.append(test_job)
 
-    if args.http2_interop:
-      for test_case in _HTTP2_TEST_CASES:
-        test_job = cloud_to_prod_jobspec(http2Interop, test_case,
-                                         docker_image=docker_images.get(str(http2Interop)))
-        jobs.append(test_job)
-
+      if args.http2_interop:
+        for test_case in _HTTP2_TEST_CASES:
+          test_job = cloud_to_prod_jobspec(
+              http2Interop, test_case, server_host_name, 
+              prod_servers[server_host_name],
+              docker_image=docker_images.get(str(http2Interop)))
+          jobs.append(test_job)
 
   if args.cloud_to_prod_auth:
-    for language in languages:
-      for test_case in _AUTH_TEST_CASES:
-        if not test_case in language.unimplemented_test_cases():
-          test_job = cloud_to_prod_jobspec(language, test_case,
-                                           docker_image=docker_images.get(str(language)),
-                                           auth=True)
-          jobs.append(test_job)
+    for server_host_name in args.prod_servers:
+      for language in languages:
+        for test_case in _AUTH_TEST_CASES:
+          if not test_case in language.unimplemented_test_cases():
+            test_job = cloud_to_prod_jobspec(
+                language, test_case, server_host_name, 
+                prod_servers[server_host_name],
+                docker_image=docker_images.get(str(language)), auth=True)
+            jobs.append(test_job)
 
   for server in args.override_server:
     server_name = server[0]
@@ -773,7 +802,8 @@
   report_utils.render_interop_html_report(
       set([str(l) for l in languages]), servers, _TEST_CASES, _AUTH_TEST_CASES,
       _HTTP2_TEST_CASES, resultset, num_failures,
-      args.cloud_to_prod_auth or args.cloud_to_prod, args.http2_interop)
+      args.cloud_to_prod_auth or args.cloud_to_prod, args.prod_servers, 
+      args.http2_interop)
 
 finally:
   # Check if servers are still running.
diff --git a/tools/run_tests/run_node.bat b/tools/run_tests/run_node.bat
new file mode 100644
index 0000000..f5cf01f
--- /dev/null
+++ b/tools/run_tests/run_node.bat
@@ -0,0 +1,32 @@
+@rem Copyright 2016, Google Inc.
+@rem All rights reserved.
+@rem
+@rem Redistribution and use in source and binary forms, with or without
+@rem modification, are permitted provided that the following conditions are
+@rem met:
+@rem
+@rem     * Redistributions of source code must retain the above copyright
+@rem notice, this list of conditions and the following disclaimer.
+@rem     * Redistributions in binary form must reproduce the above
+@rem copyright notice, this list of conditions and the following disclaimer
+@rem in the documentation and/or other materials provided with the
+@rem distribution.
+@rem     * Neither the name of Google Inc. nor the names of its
+@rem contributors may be used to endorse or promote products derived from
+@rem this software without specific prior written permission.
+@rem
+@rem THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+@rem "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+@rem LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+@rem A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+@rem OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+@rem SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+@rem LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+@rem DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+@rem THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+@rem (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+@rem OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+set JUNIT_REPORT_PATH=src\node\reports.xml
+set JUNIT_REPORT_STACK=1
+.\node_modules\.bin\mocha.cmd --reporter mocha-jenkins-reporter src\node\test
\ No newline at end of file
diff --git a/tools/run_tests/run_node.sh b/tools/run_tests/run_node.sh
index f93c9c3..40f61d7 100755
--- a/tools/run_tests/run_node.sh
+++ b/tools/run_tests/run_node.sh
@@ -28,8 +28,12 @@
 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
+NODE_VERSION=$1
+source ~/.nvm/nvm.sh
 set -ex
 
+nvm use $NODE_VERSION
+
 CONFIG=${CONFIG:-opt}
 
 # change to grpc repo root
diff --git a/tools/run_tests/run_stress_tests.py b/tools/run_tests/run_stress_tests.py
index 193ff2e..d1faf7d 100755
--- a/tools/run_tests/run_stress_tests.py
+++ b/tools/run_tests/run_stress_tests.py
@@ -1,4 +1,4 @@
-#!/usr/bin/env python
+#!/usr/bin/env python2.7
 # Copyright 2015-2016, Google Inc.
 # All rights reserved.
 #
diff --git a/tools/run_tests/run_tests.py b/tools/run_tests/run_tests.py
index 488af3b..de3716b 100755
--- a/tools/run_tests/run_tests.py
+++ b/tools/run_tests/run_tests.py
@@ -132,8 +132,10 @@
       if config.build_config in target['exclude_configs']:
         continue
       if self.platform == 'windows':
-        binary = 'vsprojects/%s/%s.exe' % (
-            _WINDOWS_CONFIG[config.build_config], target['name'])
+        binary = 'vsprojects/%s%s/%s.exe' % (
+            'x64/' if args.arch == 'x64' else '',
+            _WINDOWS_CONFIG[config.build_config],
+            target['name'])
       else:
         binary = 'bins/%s/%s' % (config.build_config, target['name'])
       if os.path.isfile(binary):
@@ -151,9 +153,9 @@
   def make_targets(self, test_regex):
     if platform_string() != 'windows' and test_regex != '.*':
       # use the regex to minimize the number of things to build
-      return [target['name']
+      return [os.path.basename(target['name'])
               for target in get_c_tests(False, self.test_lang)
-              if re.search(test_regex, target['name'])]
+              if re.search(test_regex, '/' + target['name'])]
     if platform_string() == 'windows':
       # don't build tools on windows just yet
       return ['buildtests_%s' % self.make_target]
@@ -183,19 +185,32 @@
   def supports_multi_config(self):
     return True
 
+  def dockerfile_dir(self, config, arch):
+    return 'tools/dockerfile/test/cxx_jessie_%s' % _docker_arch_suffix(arch)
+
   def __str__(self):
     return self.make_target
 
 
 class NodeLanguage(object):
 
+  def __init__(self):
+    self.platform = platform_string()
+    self.node_version = '0.12'
+
   def test_specs(self, config, args):
-    return [config.job_spec(['tools/run_tests/run_node.sh'], None,
-                            environ=_FORCE_ENVIRON_FOR_WRAPPERS)]
+    if self.platform == 'windows':
+      return [config.job_spec(['tools\\run_tests\\run_node.bat'], None)]
+    else:
+      return [config.job_spec(['tools/run_tests/run_node.sh', self.node_version],
+                              None,
+                              environ=_FORCE_ENVIRON_FOR_WRAPPERS)]
 
   def pre_build_steps(self):
-    # Default to 1 week cache expiration
-    return [['tools/run_tests/pre_build_node.sh']]
+    if self.platform == 'windows':
+      return [['tools\\run_tests\\pre_build_node.bat']]
+    else:
+      return [['tools/run_tests/pre_build_node.sh', self.node_version]]
 
   def make_targets(self, test_regex):
     return []
@@ -204,7 +219,10 @@
     return []
 
   def build_steps(self):
-    return [['tools/run_tests/build_node.sh']]
+    if self.platform == 'windows':
+      return [['tools\\run_tests\\build_node.bat']]
+    else:
+      return [['tools/run_tests/build_node.sh', self.node_version]]
 
   def post_tests_steps(self):
     return []
@@ -215,6 +233,9 @@
   def supports_multi_config(self):
     return False
 
+  def dockerfile_dir(self, config, arch):
+    return 'tools/dockerfile/test/node_jessie_%s' % _docker_arch_suffix(arch)
+
   def __str__(self):
     return 'node'
 
@@ -246,6 +267,9 @@
   def supports_multi_config(self):
     return False
 
+  def dockerfile_dir(self, config, arch):
+    return 'tools/dockerfile/test/php_jessie_%s' % _docker_arch_suffix(arch)
+
   def __str__(self):
     return 'php'
 
@@ -299,6 +323,9 @@
   def supports_multi_config(self):
     return False
 
+  def dockerfile_dir(self, config, arch):
+    return 'tools/dockerfile/test/python_jessie_%s' % _docker_arch_suffix(arch)
+
   def __str__(self):
     return 'python'
 
@@ -330,6 +357,9 @@
   def supports_multi_config(self):
     return False
 
+  def dockerfile_dir(self, config, arch):
+    return 'tools/dockerfile/test/ruby_jessie_%s' % _docker_arch_suffix(arch)
+
   def __str__(self):
     return 'ruby'
 
@@ -412,6 +442,9 @@
   def supports_multi_config(self):
     return False
 
+  def dockerfile_dir(self, config, arch):
+    return 'tools/dockerfile/test/csharp_jessie_%s' % _docker_arch_suffix(arch)
+
   def __str__(self):
     return 'csharp'
 
@@ -443,6 +476,9 @@
   def supports_multi_config(self):
     return False
 
+  def dockerfile_dir(self, config, arch):
+    return None
+
   def __str__(self):
     return 'objc'
 
@@ -451,8 +487,10 @@
 
   def test_specs(self, config, args):
     import yaml
-    with open('tools/run_tests/sanity_tests.yaml', 'r') as f:
-      return [config.job_spec(cmd['script'].split(), None, timeout_seconds=None, environ={'TEST': 'true'}, cpu_cost=cmd.get('cpu_cost', 1))
+    with open('tools/run_tests/sanity/sanity_tests.yaml', 'r') as f:
+      return [config.job_spec(cmd['script'].split(), None,
+                              timeout_seconds=None, environ={'TEST': 'true'},
+                              cpu_cost=cmd.get('cpu_cost', 1))
               for cmd in yaml.load(f)]
 
   def pre_build_steps(self):
@@ -476,6 +514,9 @@
   def supports_multi_config(self):
     return False
 
+  def dockerfile_dir(self, config, arch):
+    return 'tools/dockerfile/test/sanity'
+
   def __str__(self):
     return 'sanity'
 
@@ -506,6 +547,9 @@
   def supports_multi_config(self):
     return True
 
+  def dockerfile_dir(self, config, arch):
+    return None
+
   def __str__(self):
     return self.make_target
 
@@ -545,7 +589,7 @@
   else:
     print 'Architecture %s not supported.' % arch
     sys.exit(1)
-    
+
 
 def _check_arch_option(arch):
   """Checks that architecture option is valid."""
@@ -595,16 +639,25 @@
     sys.exit(1)
 
 
-def _get_dockerfile_dir(arch):
-  """Returns dockerfile to use"""
+def _docker_arch_suffix(arch):
+  """Returns suffix to dockerfile dir to use."""
   if arch == 'default' or arch == 'x64':
-    return 'tools/dockerfile/grpc_jenkins_slave_x64'
+    return 'x64'
   elif arch == 'x86':
-    return 'tools/dockerfile/grpc_jenkins_slave_x86'
+    return 'x86'
   else:
     print 'Architecture %s not supported with current settings.' % arch
     sys.exit(1)
 
+
+def _get_dockerfile_dir(language, cfg, arch):
+  """Returns dockerfile to use"""
+  custom = language.dockerfile_dir(cfg, arch)
+  if custom:
+    return custom
+  else:
+    return 'tools/dockerfile/grpc_tests_multilang_%s' % _docker_arch_suffix(arch)
+
 def runs_per_test_type(arg_str):
     """Auxilary function to parse the "runs_per_test" flag.
 
@@ -771,11 +824,13 @@
     time.sleep(5)
 
   child_argv = [ arg for arg in sys.argv if not arg == '--use_docker' ]
-  run_tests_cmd = 'tools/run_tests/run_tests.py %s' % ' '.join(child_argv[1:])
+  run_tests_cmd = 'python tools/run_tests/run_tests.py %s' % ' '.join(child_argv[1:])
 
   env = os.environ.copy()
   env['RUN_TESTS_COMMAND'] = run_tests_cmd
-  env['DOCKERFILE_DIR'] = _get_dockerfile_dir(args.arch)
+  env['DOCKERFILE_DIR'] = _get_dockerfile_dir(next(iter(languages)),
+                                              next(iter(build_configs)),
+                                              args.arch)
   env['DOCKER_RUN_SCRIPT'] = 'tools/jenkins/docker_run_tests.sh'
   if args.xml_report:
     env['XML_REPORT'] = args.xml_report
@@ -786,7 +841,7 @@
                         shell=True,
                         env=env)
   sys.exit(0)
-  
+
 if platform_string() != 'windows' and args.compiler != 'default':
     print 'Compiler %s not supported on current platform.' % args.compiler
     sys.exit(1)
@@ -1024,13 +1079,15 @@
     check_cancelled, newline_on_success, cache, xml_report=None, build_only=False):
   """Do one pass of building & running tests."""
   # build latest sequentially
-  num_failures, _ = jobset.run(
+  num_failures, resultset = jobset.run(
       build_steps, maxjobs=1, stop_on_failure=True,
       newline_on_success=newline_on_success, travis=args.travis)
   if num_failures:
     return [BuildAndRunError.BUILD]
 
   if build_only:
+    if xml_report:
+      report_utils.render_junit_xml_report(resultset, xml_report)
     return []
 
   # start antagonists
diff --git a/tools/run_tests/check_cache_mk.sh b/tools/run_tests/sanity/check_cache_mk.sh
similarity index 100%
rename from tools/run_tests/check_cache_mk.sh
rename to tools/run_tests/sanity/check_cache_mk.sh
diff --git a/tools/run_tests/check_sources_and_headers.py b/tools/run_tests/sanity/check_sources_and_headers.py
similarity index 66%
rename from tools/run_tests/check_sources_and_headers.py
rename to tools/run_tests/sanity/check_sources_and_headers.py
index 50574f4..3974af0 100755
--- a/tools/run_tests/check_sources_and_headers.py
+++ b/tools/run_tests/sanity/check_sources_and_headers.py
@@ -33,9 +33,9 @@
 import re
 import sys
 
-root = os.path.abspath(os.path.join(os.path.dirname(sys.argv[0]), '../..'))
+root = os.path.abspath(os.path.join(os.path.dirname(sys.argv[0]), '../../..'))
 with open(os.path.join(root, 'tools', 'run_tests', 'sources_and_headers.json')) as f:
-	js = json.loads(f.read())
+  js = json.loads(f.read())
 
 re_inc1 = re.compile(r'^#\s*include\s*"([^"]*)"')
 assert re_inc1.match('#include "foo"').group(1) == 'foo'
@@ -43,41 +43,41 @@
 assert re_inc2.match('#include <grpc++/foo>').group(1) == 'grpc++/foo'
 
 def get_target(name):
-	for target in js:
-		if target['name'] == name:
-			return target
-	assert False, 'no target %s' % name
+  for target in js:
+    if target['name'] == name:
+      return target
+  assert False, 'no target %s' % name
 
 def target_has_header(target, name):
-#	print target['name'], name
-	if name in target['headers']:
-		return True
-	for dep in target['deps']:
-		if target_has_header(get_target(dep), name):
-			return True
-	if name == 'src/core/profiling/stap_probes.h':
-		return True
-	return False
+  # print target['name'], name
+  if name in target['headers']:
+    return True
+  for dep in target['deps']:
+    if target_has_header(get_target(dep), name):
+      return True
+  if name == 'src/core/profiling/stap_probes.h':
+    return True
+  return False
 
 errors = 0
 for target in js:
-	for fn in target['src']:
-		with open(os.path.join(root, fn)) as f:
-			src = f.read().splitlines()
-		for line in src:
-			m = re_inc1.match(line)
-			if m:
-				if not target_has_header(target, m.group(1)):
-					print (
-						'target %s (%s) does not name header %s as a dependency' % (
-							target['name'], fn, m.group(1)))
-					errors += 1
-			m = re_inc2.match(line)
-			if m:
-				if not target_has_header(target, 'include/' + m.group(1)):
-					print (
-						'target %s (%s) does not name header %s as a dependency' % (
-							target['name'], fn, m.group(1)))
-					errors += 1
+  for fn in target['src']:
+    with open(os.path.join(root, fn)) as f:
+      src = f.read().splitlines()
+    for line in src:
+      m = re_inc1.match(line)
+      if m:
+        if not target_has_header(target, m.group(1)):
+          print (
+            'target %s (%s) does not name header %s as a dependency' % (
+              target['name'], fn, m.group(1)))
+          errors += 1
+      m = re_inc2.match(line)
+      if m:
+        if not target_has_header(target, 'include/' + m.group(1)):
+          print (
+            'target %s (%s) does not name header %s as a dependency' % (
+              target['name'], fn, m.group(1)))
+          errors += 1
 
 assert errors == 0
diff --git a/tools/run_tests/check_submodules.sh b/tools/run_tests/sanity/check_submodules.sh
similarity index 98%
rename from tools/run_tests/check_submodules.sh
rename to tools/run_tests/sanity/check_submodules.sh
index b4ca4fa..f49230e 100755
--- a/tools/run_tests/check_submodules.sh
+++ b/tools/run_tests/sanity/check_submodules.sh
@@ -34,7 +34,7 @@
 
 export TEST=true
 
-cd `dirname $0`/../..
+cd `dirname $0`/../../..
 
 submodules=`mktemp /tmp/submXXXXXX`
 want_submodules=`mktemp /tmp/submXXXXXX`
diff --git a/tools/run_tests/sanity_tests.yaml b/tools/run_tests/sanity/sanity_tests.yaml
similarity index 61%
rename from tools/run_tests/sanity_tests.yaml
rename to tools/run_tests/sanity/sanity_tests.yaml
index 757bcd9..809e6ce 100644
--- a/tools/run_tests/sanity_tests.yaml
+++ b/tools/run_tests/sanity/sanity_tests.yaml
@@ -1,7 +1,7 @@
 # a set of tests that are run in parallel for sanity tests
-- script: tools/run_tests/check_sources_and_headers.py
-- script: tools/run_tests/check_submodules.sh
-- script: tools/run_tests/check_cache_mk.sh
+- script: tools/run_tests/sanity/check_sources_and_headers.py
+- script: tools/run_tests/sanity/check_submodules.sh
+- script: tools/run_tests/sanity/check_cache_mk.sh
 - script: tools/buildgen/generate_projects.sh -j 3
   cpu_cost: 3
 - script: tools/distrib/check_copyright.py
diff --git a/tools/run_tests/sources_and_headers.json b/tools/run_tests/sources_and_headers.json
index a311a04..6538ddc 100644
--- a/tools/run_tests/sources_and_headers.json
+++ b/tools/run_tests/sources_and_headers.json
@@ -10,6 +10,20 @@
     ], 
     "headers": [], 
     "language": "c", 
+    "name": "alarm_test", 
+    "src": [
+      "test/core/surface/alarm_test.c"
+    ]
+  }, 
+  {
+    "deps": [
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
     "name": "algorithm_test", 
     "src": [
       "test/core/compression/algorithm_test.c"
@@ -43,8 +57,6 @@
   }, 
   {
     "deps": [
-      "gpr", 
-      "gpr_test_util", 
       "grpc", 
       "grpc_test_util"
     ], 
@@ -64,6 +76,20 @@
     ], 
     "headers": [], 
     "language": "c", 
+    "name": "census_context_test", 
+    "src": [
+      "test/core/census/context_test.c"
+    ]
+  }, 
+  {
+    "deps": [
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
     "name": "channel_create_test", 
     "src": [
       "test/core/surface/channel_create_test.c"
@@ -1098,20 +1124,6 @@
     ], 
     "headers": [], 
     "language": "c", 
-    "name": "tag_set_test", 
-    "src": [
-      "test/core/census/tag_set_test.c"
-    ]
-  }, 
-  {
-    "deps": [
-      "gpr", 
-      "gpr_test_util", 
-      "grpc", 
-      "grpc_test_util"
-    ], 
-    "headers": [], 
-    "language": "c", 
     "name": "tcp_client_posix_test", 
     "src": [
       "test/core/iomgr/tcp_client_posix_test.c"
@@ -1310,6 +1322,22 @@
     ], 
     "headers": [], 
     "language": "c++", 
+    "name": "alarm_cpp_test", 
+    "src": [
+      "test/cpp/common/alarm_cpp_test.cc"
+    ]
+  }, 
+  {
+    "deps": [
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc++", 
+      "grpc++_test_util", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c++", 
     "name": "async_end2end_test", 
     "src": [
       "test/cpp/end2end/async_end2end_test.cc"
@@ -1622,6 +1650,22 @@
       "gpr_test_util", 
       "grpc", 
       "grpc++", 
+      "grpc++_test_util", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c++", 
+    "name": "hybrid_end2end_test", 
+    "src": [
+      "test/cpp/end2end/hybrid_end2end_test.cc"
+    ]
+  }, 
+  {
+    "deps": [
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc++", 
       "grpc++_test_config", 
       "grpc++_test_util", 
       "grpc_test_util", 
@@ -2738,6 +2782,20 @@
   {
     "deps": [], 
     "headers": [
+      "include/grpc/impl/codegen/alloc.h", 
+      "include/grpc/impl/codegen/atm.h", 
+      "include/grpc/impl/codegen/atm_gcc_atomic.h", 
+      "include/grpc/impl/codegen/atm_gcc_sync.h", 
+      "include/grpc/impl/codegen/atm_win32.h", 
+      "include/grpc/impl/codegen/log.h", 
+      "include/grpc/impl/codegen/port_platform.h", 
+      "include/grpc/impl/codegen/slice.h", 
+      "include/grpc/impl/codegen/slice_buffer.h", 
+      "include/grpc/impl/codegen/sync.h", 
+      "include/grpc/impl/codegen/sync_generic.h", 
+      "include/grpc/impl/codegen/sync_posix.h", 
+      "include/grpc/impl/codegen/sync_win32.h", 
+      "include/grpc/impl/codegen/time.h", 
       "include/grpc/support/alloc.h", 
       "include/grpc/support/atm.h", 
       "include/grpc/support/atm_gcc_atomic.h", 
@@ -2780,6 +2838,20 @@
     "language": "c", 
     "name": "gpr", 
     "src": [
+      "include/grpc/impl/codegen/alloc.h", 
+      "include/grpc/impl/codegen/atm.h", 
+      "include/grpc/impl/codegen/atm_gcc_atomic.h", 
+      "include/grpc/impl/codegen/atm_gcc_sync.h", 
+      "include/grpc/impl/codegen/atm_win32.h", 
+      "include/grpc/impl/codegen/log.h", 
+      "include/grpc/impl/codegen/port_platform.h", 
+      "include/grpc/impl/codegen/slice.h", 
+      "include/grpc/impl/codegen/slice_buffer.h", 
+      "include/grpc/impl/codegen/sync.h", 
+      "include/grpc/impl/codegen/sync_generic.h", 
+      "include/grpc/impl/codegen/sync_posix.h", 
+      "include/grpc/impl/codegen/sync_win32.h", 
+      "include/grpc/impl/codegen/time.h", 
       "include/grpc/support/alloc.h", 
       "include/grpc/support/atm.h", 
       "include/grpc/support/atm_gcc_atomic.h", 
@@ -2846,6 +2918,7 @@
       "src/core/support/string_win32.c", 
       "src/core/support/string_win32.h", 
       "src/core/support/subprocess_posix.c", 
+      "src/core/support/subprocess_windows.c", 
       "src/core/support/sync.c", 
       "src/core/support/sync_posix.c", 
       "src/core/support/sync_win32.c", 
@@ -2858,7 +2931,8 @@
       "src/core/support/time_precise.c", 
       "src/core/support/time_precise.h", 
       "src/core/support/time_win32.c", 
-      "src/core/support/tls_pthread.c"
+      "src/core/support/tls_pthread.c", 
+      "src/core/support/wrap_memcpy.c"
     ]
   }, 
   {
@@ -2886,9 +2960,14 @@
       "include/grpc/compression.h", 
       "include/grpc/grpc.h", 
       "include/grpc/grpc_security.h", 
+      "include/grpc/impl/codegen/byte_buffer.h", 
+      "include/grpc/impl/codegen/compression_types.h", 
+      "include/grpc/impl/codegen/connectivity_state.h", 
+      "include/grpc/impl/codegen/grpc_types.h", 
+      "include/grpc/impl/codegen/propagation_bits.h", 
+      "include/grpc/impl/codegen/status.h", 
       "include/grpc/status.h", 
       "src/core/census/aggregation.h", 
-      "src/core/census/context.h", 
       "src/core/census/grpc_filter.h", 
       "src/core/census/rpc_metric_id.h", 
       "src/core/channel/channel_args.h", 
@@ -3027,17 +3106,22 @@
       "include/grpc/compression.h", 
       "include/grpc/grpc.h", 
       "include/grpc/grpc_security.h", 
+      "include/grpc/impl/codegen/byte_buffer.h", 
+      "include/grpc/impl/codegen/compression_types.h", 
+      "include/grpc/impl/codegen/connectivity_state.h", 
+      "include/grpc/impl/codegen/grpc_types.h", 
+      "include/grpc/impl/codegen/propagation_bits.h", 
+      "include/grpc/impl/codegen/status.h", 
       "include/grpc/status.h", 
       "src/core/census/aggregation.h", 
       "src/core/census/context.c", 
-      "src/core/census/context.h", 
       "src/core/census/grpc_context.c", 
       "src/core/census/grpc_filter.c", 
       "src/core/census/grpc_filter.h", 
       "src/core/census/initialize.c", 
       "src/core/census/operation.c", 
+      "src/core/census/placeholders.c", 
       "src/core/census/rpc_metric_id.h", 
-      "src/core/census/tag_set.c", 
       "src/core/census/tracing.c", 
       "src/core/channel/channel_args.c", 
       "src/core/channel/channel_args.h", 
@@ -3215,6 +3299,7 @@
       "src/core/security/server_secure_chttp2.c", 
       "src/core/statistics/census_interface.h", 
       "src/core/statistics/census_rpc_stats.h", 
+      "src/core/surface/alarm.c", 
       "src/core/surface/api_trace.c", 
       "src/core/surface/api_trace.h", 
       "src/core/surface/byte_buffer.c", 
@@ -3400,9 +3485,14 @@
       "include/grpc/census.h", 
       "include/grpc/compression.h", 
       "include/grpc/grpc.h", 
+      "include/grpc/impl/codegen/byte_buffer.h", 
+      "include/grpc/impl/codegen/compression_types.h", 
+      "include/grpc/impl/codegen/connectivity_state.h", 
+      "include/grpc/impl/codegen/grpc_types.h", 
+      "include/grpc/impl/codegen/propagation_bits.h", 
+      "include/grpc/impl/codegen/status.h", 
       "include/grpc/status.h", 
       "src/core/census/aggregation.h", 
-      "src/core/census/context.h", 
       "src/core/census/grpc_filter.h", 
       "src/core/census/rpc_metric_id.h", 
       "src/core/channel/channel_args.h", 
@@ -3526,17 +3616,22 @@
       "include/grpc/census.h", 
       "include/grpc/compression.h", 
       "include/grpc/grpc.h", 
+      "include/grpc/impl/codegen/byte_buffer.h", 
+      "include/grpc/impl/codegen/compression_types.h", 
+      "include/grpc/impl/codegen/connectivity_state.h", 
+      "include/grpc/impl/codegen/grpc_types.h", 
+      "include/grpc/impl/codegen/propagation_bits.h", 
+      "include/grpc/impl/codegen/status.h", 
       "include/grpc/status.h", 
       "src/core/census/aggregation.h", 
       "src/core/census/context.c", 
-      "src/core/census/context.h", 
       "src/core/census/grpc_context.c", 
       "src/core/census/grpc_filter.c", 
       "src/core/census/grpc_filter.h", 
       "src/core/census/initialize.c", 
       "src/core/census/operation.c", 
+      "src/core/census/placeholders.c", 
       "src/core/census/rpc_metric_id.h", 
-      "src/core/census/tag_set.c", 
       "src/core/census/tracing.c", 
       "src/core/channel/channel_args.c", 
       "src/core/channel/channel_args.h", 
@@ -3689,6 +3784,7 @@
       "src/core/json/json_writer.h", 
       "src/core/statistics/census_interface.h", 
       "src/core/statistics/census_rpc_stats.h", 
+      "src/core/surface/alarm.c", 
       "src/core/surface/api_trace.c", 
       "src/core/surface/api_trace.h", 
       "src/core/surface/byte_buffer.c", 
@@ -3831,10 +3927,10 @@
   }, 
   {
     "deps": [
-      "gpr", 
       "grpc"
     ], 
     "headers": [
+      "include/grpc++/alarm.h", 
       "include/grpc++/channel.h", 
       "include/grpc++/client_context.h", 
       "include/grpc++/completion_queue.h", 
@@ -3844,7 +3940,38 @@
       "include/grpc++/grpc++.h", 
       "include/grpc++/impl/call.h", 
       "include/grpc++/impl/client_unary_call.h", 
+      "include/grpc++/impl/codegen/async_stream.h", 
+      "include/grpc++/impl/codegen/async_unary_call.h", 
+      "include/grpc++/impl/codegen/call.h", 
+      "include/grpc++/impl/codegen/call_hook.h", 
+      "include/grpc++/impl/codegen/channel_interface.h", 
+      "include/grpc++/impl/codegen/client_context.h", 
+      "include/grpc++/impl/codegen/client_unary_call.h", 
+      "include/grpc++/impl/codegen/completion_queue.h", 
+      "include/grpc++/impl/codegen/completion_queue_tag.h", 
+      "include/grpc++/impl/codegen/config.h", 
+      "include/grpc++/impl/codegen/config_protobuf.h", 
+      "include/grpc++/impl/codegen/grpc_library.h", 
+      "include/grpc++/impl/codegen/method_handler_impl.h", 
+      "include/grpc++/impl/codegen/proto_utils.h", 
+      "include/grpc++/impl/codegen/rpc_method.h", 
+      "include/grpc++/impl/codegen/rpc_service_method.h", 
+      "include/grpc++/impl/codegen/security/auth_context.h", 
+      "include/grpc++/impl/codegen/serialization_traits.h", 
+      "include/grpc++/impl/codegen/server_context.h", 
+      "include/grpc++/impl/codegen/server_interface.h", 
+      "include/grpc++/impl/codegen/service_type.h", 
+      "include/grpc++/impl/codegen/status.h", 
+      "include/grpc++/impl/codegen/status_code_enum.h", 
+      "include/grpc++/impl/codegen/string_ref.h", 
+      "include/grpc++/impl/codegen/stub_options.h", 
+      "include/grpc++/impl/codegen/sync.h", 
+      "include/grpc++/impl/codegen/sync_cxx11.h", 
+      "include/grpc++/impl/codegen/sync_no_cxx11.h", 
+      "include/grpc++/impl/codegen/sync_stream.h", 
+      "include/grpc++/impl/codegen/time.h", 
       "include/grpc++/impl/grpc_library.h", 
+      "include/grpc++/impl/method_handler_impl.h", 
       "include/grpc++/impl/proto_utils.h", 
       "include/grpc++/impl/rpc_method.h", 
       "include/grpc++/impl/rpc_service_method.h", 
@@ -3889,6 +4016,7 @@
     "language": "c++", 
     "name": "grpc++", 
     "src": [
+      "include/grpc++/alarm.h", 
       "include/grpc++/channel.h", 
       "include/grpc++/client_context.h", 
       "include/grpc++/completion_queue.h", 
@@ -3898,7 +4026,38 @@
       "include/grpc++/grpc++.h", 
       "include/grpc++/impl/call.h", 
       "include/grpc++/impl/client_unary_call.h", 
+      "include/grpc++/impl/codegen/async_stream.h", 
+      "include/grpc++/impl/codegen/async_unary_call.h", 
+      "include/grpc++/impl/codegen/call.h", 
+      "include/grpc++/impl/codegen/call_hook.h", 
+      "include/grpc++/impl/codegen/channel_interface.h", 
+      "include/grpc++/impl/codegen/client_context.h", 
+      "include/grpc++/impl/codegen/client_unary_call.h", 
+      "include/grpc++/impl/codegen/completion_queue.h", 
+      "include/grpc++/impl/codegen/completion_queue_tag.h", 
+      "include/grpc++/impl/codegen/config.h", 
+      "include/grpc++/impl/codegen/config_protobuf.h", 
+      "include/grpc++/impl/codegen/grpc_library.h", 
+      "include/grpc++/impl/codegen/method_handler_impl.h", 
+      "include/grpc++/impl/codegen/proto_utils.h", 
+      "include/grpc++/impl/codegen/rpc_method.h", 
+      "include/grpc++/impl/codegen/rpc_service_method.h", 
+      "include/grpc++/impl/codegen/security/auth_context.h", 
+      "include/grpc++/impl/codegen/serialization_traits.h", 
+      "include/grpc++/impl/codegen/server_context.h", 
+      "include/grpc++/impl/codegen/server_interface.h", 
+      "include/grpc++/impl/codegen/service_type.h", 
+      "include/grpc++/impl/codegen/status.h", 
+      "include/grpc++/impl/codegen/status_code_enum.h", 
+      "include/grpc++/impl/codegen/string_ref.h", 
+      "include/grpc++/impl/codegen/stub_options.h", 
+      "include/grpc++/impl/codegen/sync.h", 
+      "include/grpc++/impl/codegen/sync_cxx11.h", 
+      "include/grpc++/impl/codegen/sync_no_cxx11.h", 
+      "include/grpc++/impl/codegen/sync_stream.h", 
+      "include/grpc++/impl/codegen/time.h", 
       "include/grpc++/impl/grpc_library.h", 
+      "include/grpc++/impl/method_handler_impl.h", 
       "include/grpc++/impl/proto_utils.h", 
       "include/grpc++/impl/rpc_method.h", 
       "include/grpc++/impl/rpc_service_method.h", 
@@ -3941,6 +4100,8 @@
       "src/cpp/client/insecure_credentials.cc", 
       "src/cpp/client/secure_credentials.cc", 
       "src/cpp/client/secure_credentials.h", 
+      "src/cpp/codegen/grpc_library.cc", 
+      "src/cpp/common/alarm.cc", 
       "src/cpp/common/auth_property_iterator.cc", 
       "src/cpp/common/call.cc", 
       "src/cpp/common/channel_arguments.cc", 
@@ -3997,6 +4158,8 @@
       "src/proto/grpc/testing/echo.pb.h", 
       "src/proto/grpc/testing/echo_messages.grpc.pb.h", 
       "src/proto/grpc/testing/echo_messages.pb.h", 
+      "test/cpp/end2end/test_service_impl.h", 
+      "test/cpp/util/byte_buffer_proto_helper.h", 
       "test/cpp/util/cli_call.h", 
       "test/cpp/util/create_test_channel.h", 
       "test/cpp/util/string_ref_helper.h", 
@@ -4005,6 +4168,10 @@
     "language": "c++", 
     "name": "grpc++_test_util", 
     "src": [
+      "test/cpp/end2end/test_service_impl.cc", 
+      "test/cpp/end2end/test_service_impl.h", 
+      "test/cpp/util/byte_buffer_proto_helper.cc", 
+      "test/cpp/util/byte_buffer_proto_helper.h", 
       "test/cpp/util/cli_call.cc", 
       "test/cpp/util/cli_call.h", 
       "test/cpp/util/create_test_channel.cc", 
@@ -4021,6 +4188,7 @@
       "grpc_unsecure"
     ], 
     "headers": [
+      "include/grpc++/alarm.h", 
       "include/grpc++/channel.h", 
       "include/grpc++/client_context.h", 
       "include/grpc++/completion_queue.h", 
@@ -4030,7 +4198,38 @@
       "include/grpc++/grpc++.h", 
       "include/grpc++/impl/call.h", 
       "include/grpc++/impl/client_unary_call.h", 
+      "include/grpc++/impl/codegen/async_stream.h", 
+      "include/grpc++/impl/codegen/async_unary_call.h", 
+      "include/grpc++/impl/codegen/call.h", 
+      "include/grpc++/impl/codegen/call_hook.h", 
+      "include/grpc++/impl/codegen/channel_interface.h", 
+      "include/grpc++/impl/codegen/client_context.h", 
+      "include/grpc++/impl/codegen/client_unary_call.h", 
+      "include/grpc++/impl/codegen/completion_queue.h", 
+      "include/grpc++/impl/codegen/completion_queue_tag.h", 
+      "include/grpc++/impl/codegen/config.h", 
+      "include/grpc++/impl/codegen/config_protobuf.h", 
+      "include/grpc++/impl/codegen/grpc_library.h", 
+      "include/grpc++/impl/codegen/method_handler_impl.h", 
+      "include/grpc++/impl/codegen/proto_utils.h", 
+      "include/grpc++/impl/codegen/rpc_method.h", 
+      "include/grpc++/impl/codegen/rpc_service_method.h", 
+      "include/grpc++/impl/codegen/security/auth_context.h", 
+      "include/grpc++/impl/codegen/serialization_traits.h", 
+      "include/grpc++/impl/codegen/server_context.h", 
+      "include/grpc++/impl/codegen/server_interface.h", 
+      "include/grpc++/impl/codegen/service_type.h", 
+      "include/grpc++/impl/codegen/status.h", 
+      "include/grpc++/impl/codegen/status_code_enum.h", 
+      "include/grpc++/impl/codegen/string_ref.h", 
+      "include/grpc++/impl/codegen/stub_options.h", 
+      "include/grpc++/impl/codegen/sync.h", 
+      "include/grpc++/impl/codegen/sync_cxx11.h", 
+      "include/grpc++/impl/codegen/sync_no_cxx11.h", 
+      "include/grpc++/impl/codegen/sync_stream.h", 
+      "include/grpc++/impl/codegen/time.h", 
       "include/grpc++/impl/grpc_library.h", 
+      "include/grpc++/impl/method_handler_impl.h", 
       "include/grpc++/impl/proto_utils.h", 
       "include/grpc++/impl/rpc_method.h", 
       "include/grpc++/impl/rpc_service_method.h", 
@@ -4072,6 +4271,7 @@
     "language": "c++", 
     "name": "grpc++_unsecure", 
     "src": [
+      "include/grpc++/alarm.h", 
       "include/grpc++/channel.h", 
       "include/grpc++/client_context.h", 
       "include/grpc++/completion_queue.h", 
@@ -4081,7 +4281,38 @@
       "include/grpc++/grpc++.h", 
       "include/grpc++/impl/call.h", 
       "include/grpc++/impl/client_unary_call.h", 
+      "include/grpc++/impl/codegen/async_stream.h", 
+      "include/grpc++/impl/codegen/async_unary_call.h", 
+      "include/grpc++/impl/codegen/call.h", 
+      "include/grpc++/impl/codegen/call_hook.h", 
+      "include/grpc++/impl/codegen/channel_interface.h", 
+      "include/grpc++/impl/codegen/client_context.h", 
+      "include/grpc++/impl/codegen/client_unary_call.h", 
+      "include/grpc++/impl/codegen/completion_queue.h", 
+      "include/grpc++/impl/codegen/completion_queue_tag.h", 
+      "include/grpc++/impl/codegen/config.h", 
+      "include/grpc++/impl/codegen/config_protobuf.h", 
+      "include/grpc++/impl/codegen/grpc_library.h", 
+      "include/grpc++/impl/codegen/method_handler_impl.h", 
+      "include/grpc++/impl/codegen/proto_utils.h", 
+      "include/grpc++/impl/codegen/rpc_method.h", 
+      "include/grpc++/impl/codegen/rpc_service_method.h", 
+      "include/grpc++/impl/codegen/security/auth_context.h", 
+      "include/grpc++/impl/codegen/serialization_traits.h", 
+      "include/grpc++/impl/codegen/server_context.h", 
+      "include/grpc++/impl/codegen/server_interface.h", 
+      "include/grpc++/impl/codegen/service_type.h", 
+      "include/grpc++/impl/codegen/status.h", 
+      "include/grpc++/impl/codegen/status_code_enum.h", 
+      "include/grpc++/impl/codegen/string_ref.h", 
+      "include/grpc++/impl/codegen/stub_options.h", 
+      "include/grpc++/impl/codegen/sync.h", 
+      "include/grpc++/impl/codegen/sync_cxx11.h", 
+      "include/grpc++/impl/codegen/sync_no_cxx11.h", 
+      "include/grpc++/impl/codegen/sync_stream.h", 
+      "include/grpc++/impl/codegen/time.h", 
       "include/grpc++/impl/grpc_library.h", 
+      "include/grpc++/impl/method_handler_impl.h", 
       "include/grpc++/impl/proto_utils.h", 
       "include/grpc++/impl/rpc_method.h", 
       "include/grpc++/impl/rpc_service_method.h", 
@@ -4122,6 +4353,8 @@
       "src/cpp/client/credentials.cc", 
       "src/cpp/client/generic_stub.cc", 
       "src/cpp/client/insecure_credentials.cc", 
+      "src/cpp/codegen/grpc_library.cc", 
+      "src/cpp/common/alarm.cc", 
       "src/cpp/common/call.cc", 
       "src/cpp/common/channel_arguments.cc", 
       "src/cpp/common/completion_queue.cc", 
@@ -4151,8 +4384,58 @@
   {
     "deps": [], 
     "headers": [
+      "include/grpc++/impl/codegen/async_stream.h", 
+      "include/grpc++/impl/codegen/async_unary_call.h", 
+      "include/grpc++/impl/codegen/call.h", 
+      "include/grpc++/impl/codegen/call_hook.h", 
+      "include/grpc++/impl/codegen/channel_interface.h", 
+      "include/grpc++/impl/codegen/client_context.h", 
+      "include/grpc++/impl/codegen/client_unary_call.h", 
+      "include/grpc++/impl/codegen/completion_queue.h", 
+      "include/grpc++/impl/codegen/completion_queue_tag.h", 
+      "include/grpc++/impl/codegen/config.h", 
+      "include/grpc++/impl/codegen/config_protobuf.h", 
+      "include/grpc++/impl/codegen/grpc_library.h", 
+      "include/grpc++/impl/codegen/method_handler_impl.h", 
+      "include/grpc++/impl/codegen/proto_utils.h", 
+      "include/grpc++/impl/codegen/rpc_method.h", 
+      "include/grpc++/impl/codegen/rpc_service_method.h", 
+      "include/grpc++/impl/codegen/security/auth_context.h", 
+      "include/grpc++/impl/codegen/serialization_traits.h", 
+      "include/grpc++/impl/codegen/server_context.h", 
+      "include/grpc++/impl/codegen/server_interface.h", 
+      "include/grpc++/impl/codegen/service_type.h", 
+      "include/grpc++/impl/codegen/status.h", 
+      "include/grpc++/impl/codegen/status_code_enum.h", 
+      "include/grpc++/impl/codegen/string_ref.h", 
+      "include/grpc++/impl/codegen/stub_options.h", 
+      "include/grpc++/impl/codegen/sync.h", 
+      "include/grpc++/impl/codegen/sync_cxx11.h", 
+      "include/grpc++/impl/codegen/sync_no_cxx11.h", 
+      "include/grpc++/impl/codegen/sync_stream.h", 
+      "include/grpc++/impl/codegen/time.h", 
       "include/grpc++/support/config.h", 
       "include/grpc++/support/config_protobuf.h", 
+      "include/grpc/impl/codegen/alloc.h", 
+      "include/grpc/impl/codegen/atm.h", 
+      "include/grpc/impl/codegen/atm_gcc_atomic.h", 
+      "include/grpc/impl/codegen/atm_gcc_sync.h", 
+      "include/grpc/impl/codegen/atm_win32.h", 
+      "include/grpc/impl/codegen/byte_buffer.h", 
+      "include/grpc/impl/codegen/compression_types.h", 
+      "include/grpc/impl/codegen/connectivity_state.h", 
+      "include/grpc/impl/codegen/grpc_types.h", 
+      "include/grpc/impl/codegen/log.h", 
+      "include/grpc/impl/codegen/port_platform.h", 
+      "include/grpc/impl/codegen/propagation_bits.h", 
+      "include/grpc/impl/codegen/slice.h", 
+      "include/grpc/impl/codegen/slice_buffer.h", 
+      "include/grpc/impl/codegen/status.h", 
+      "include/grpc/impl/codegen/sync.h", 
+      "include/grpc/impl/codegen/sync_generic.h", 
+      "include/grpc/impl/codegen/sync_posix.h", 
+      "include/grpc/impl/codegen/sync_win32.h", 
+      "include/grpc/impl/codegen/time.h", 
       "src/compiler/config.h", 
       "src/compiler/cpp_generator.h", 
       "src/compiler/cpp_generator_helpers.h", 
@@ -4170,8 +4453,58 @@
     "language": "c++", 
     "name": "grpc_plugin_support", 
     "src": [
+      "include/grpc++/impl/codegen/async_stream.h", 
+      "include/grpc++/impl/codegen/async_unary_call.h", 
+      "include/grpc++/impl/codegen/call.h", 
+      "include/grpc++/impl/codegen/call_hook.h", 
+      "include/grpc++/impl/codegen/channel_interface.h", 
+      "include/grpc++/impl/codegen/client_context.h", 
+      "include/grpc++/impl/codegen/client_unary_call.h", 
+      "include/grpc++/impl/codegen/completion_queue.h", 
+      "include/grpc++/impl/codegen/completion_queue_tag.h", 
+      "include/grpc++/impl/codegen/config.h", 
+      "include/grpc++/impl/codegen/config_protobuf.h", 
+      "include/grpc++/impl/codegen/grpc_library.h", 
+      "include/grpc++/impl/codegen/method_handler_impl.h", 
+      "include/grpc++/impl/codegen/proto_utils.h", 
+      "include/grpc++/impl/codegen/rpc_method.h", 
+      "include/grpc++/impl/codegen/rpc_service_method.h", 
+      "include/grpc++/impl/codegen/security/auth_context.h", 
+      "include/grpc++/impl/codegen/serialization_traits.h", 
+      "include/grpc++/impl/codegen/server_context.h", 
+      "include/grpc++/impl/codegen/server_interface.h", 
+      "include/grpc++/impl/codegen/service_type.h", 
+      "include/grpc++/impl/codegen/status.h", 
+      "include/grpc++/impl/codegen/status_code_enum.h", 
+      "include/grpc++/impl/codegen/string_ref.h", 
+      "include/grpc++/impl/codegen/stub_options.h", 
+      "include/grpc++/impl/codegen/sync.h", 
+      "include/grpc++/impl/codegen/sync_cxx11.h", 
+      "include/grpc++/impl/codegen/sync_no_cxx11.h", 
+      "include/grpc++/impl/codegen/sync_stream.h", 
+      "include/grpc++/impl/codegen/time.h", 
       "include/grpc++/support/config.h", 
       "include/grpc++/support/config_protobuf.h", 
+      "include/grpc/impl/codegen/alloc.h", 
+      "include/grpc/impl/codegen/atm.h", 
+      "include/grpc/impl/codegen/atm_gcc_atomic.h", 
+      "include/grpc/impl/codegen/atm_gcc_sync.h", 
+      "include/grpc/impl/codegen/atm_win32.h", 
+      "include/grpc/impl/codegen/byte_buffer.h", 
+      "include/grpc/impl/codegen/compression_types.h", 
+      "include/grpc/impl/codegen/connectivity_state.h", 
+      "include/grpc/impl/codegen/grpc_types.h", 
+      "include/grpc/impl/codegen/log.h", 
+      "include/grpc/impl/codegen/port_platform.h", 
+      "include/grpc/impl/codegen/propagation_bits.h", 
+      "include/grpc/impl/codegen/slice.h", 
+      "include/grpc/impl/codegen/slice_buffer.h", 
+      "include/grpc/impl/codegen/status.h", 
+      "include/grpc/impl/codegen/sync.h", 
+      "include/grpc/impl/codegen/sync_generic.h", 
+      "include/grpc/impl/codegen/sync_posix.h", 
+      "include/grpc/impl/codegen/sync_win32.h", 
+      "include/grpc/impl/codegen/time.h", 
       "src/compiler/config.h", 
       "src/compiler/cpp_generator.cc", 
       "src/compiler/cpp_generator.h", 
@@ -4189,7 +4522,8 @@
       "src/compiler/ruby_generator.h", 
       "src/compiler/ruby_generator_helpers-inl.h", 
       "src/compiler/ruby_generator_map-inl.h", 
-      "src/compiler/ruby_generator_string-inl.h"
+      "src/compiler/ruby_generator_string-inl.h", 
+      "src/cpp/codegen/grpc_library.cc"
     ]
   }, 
   {
@@ -4305,6 +4639,7 @@
       "test/cpp/qps/driver.h", 
       "test/cpp/qps/histogram.h", 
       "test/cpp/qps/interarrival.h", 
+      "test/cpp/qps/limit_cores.h", 
       "test/cpp/qps/perf_db_client.h", 
       "test/cpp/qps/qps_worker.h", 
       "test/cpp/qps/report.h", 
@@ -4323,6 +4658,8 @@
       "test/cpp/qps/driver.h", 
       "test/cpp/qps/histogram.h", 
       "test/cpp/qps/interarrival.h", 
+      "test/cpp/qps/limit_cores.cc", 
+      "test/cpp/qps/limit_cores.h", 
       "test/cpp/qps/perf_db_client.cc", 
       "test/cpp/qps/perf_db_client.h", 
       "test/cpp/qps/qps_worker.cc", 
diff --git a/tools/run_tests/task_runner.py b/tools/run_tests/task_runner.py
new file mode 100755
index 0000000..b42aa17
--- /dev/null
+++ b/tools/run_tests/task_runner.py
@@ -0,0 +1,126 @@
+#!/usr/bin/env python2.7
+# 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.
+
+"""Runs selected gRPC test/build tasks."""
+
+import argparse
+import atexit
+import jobset
+import multiprocessing
+import sys
+
+import artifact_targets
+import distribtest_targets
+import package_targets
+
+_TARGETS = []
+_TARGETS += artifact_targets.targets()
+_TARGETS += distribtest_targets.targets()
+_TARGETS += package_targets.targets()
+
+def _create_build_map():
+  """Maps task names and labels to list of tasks to be built."""
+  target_build_map = dict([(target.name, [target])
+                           for target in _TARGETS])
+  if len(_TARGETS) > len(target_build_map.keys()):
+    raise Exception('Target names need to be unique')
+
+  label_build_map = {}
+  label_build_map['all'] = [t for t in _TARGETS]  # to build all targets
+  for target in _TARGETS:
+    for label in target.labels:
+      if label in label_build_map:
+        label_build_map[label].append(target)
+      else:
+        label_build_map[label] = [target]
+
+  if set(target_build_map.keys()).intersection(label_build_map.keys()):
+    raise Exception('Target names need to be distinct from label names')
+  return dict( target_build_map.items() + label_build_map.items())
+
+
+_BUILD_MAP = _create_build_map()
+
+argp = argparse.ArgumentParser(description='Runs build/test targets.')
+argp.add_argument('-b', '--build',
+                  choices=sorted(_BUILD_MAP.keys()),
+                  nargs='+',
+                  default=['all'],
+                  help='Target name or target label to build.')
+argp.add_argument('-f', '--filter',
+                  choices=sorted(_BUILD_MAP.keys()),
+                  nargs='+',
+                  default=[],
+                  help='Filter targets to build with AND semantics.')
+argp.add_argument('-j', '--jobs', default=multiprocessing.cpu_count(), type=int)
+argp.add_argument('-t', '--travis',
+                  default=False,
+                  action='store_const',
+                  const=True)
+
+args = argp.parse_args()
+
+# Figure out which targets to build
+targets = []
+for label in args.build:
+  targets += _BUILD_MAP[label]
+
+# Among targets selected by -b, filter out those that don't match the filter
+targets = [t for t in targets if all(f in t.labels for f in args.filter)]
+targets = sorted(set(targets))
+
+# Execute pre-build phase
+prebuild_jobs = []
+for target in targets:
+  prebuild_jobs += target.pre_build_jobspecs()
+if prebuild_jobs:
+  num_failures, _ = jobset.run(
+    prebuild_jobs, newline_on_success=True, maxjobs=args.jobs)
+  if num_failures != 0:
+    jobset.message('FAILED', 'Pre-build phase failed.', do_newline=True)
+    sys.exit(1)
+
+build_jobs = []
+for target in targets:
+  build_jobs.append(target.build_jobspec())
+if not build_jobs:
+  print 'Nothing to build.'
+  sys.exit(1)
+
+jobset.message('START', 'Building targets.', do_newline=True)
+num_failures, _ = jobset.run(
+    build_jobs, newline_on_success=True, maxjobs=args.jobs)
+if num_failures == 0:
+  jobset.message('SUCCESS', 'All targets built successfully.',
+                 do_newline=True)
+else:
+  jobset.message('FAILED', 'Failed to build targets.',
+                 do_newline=True)
+  sys.exit(1)
diff --git a/tools/run_tests/tests.json b/tools/run_tests/tests.json
index 8c76b3f..2c73c40 100644
--- a/tools/run_tests/tests.json
+++ b/tools/run_tests/tests.json
@@ -13,6 +13,26 @@
     "exclude_configs": [], 
     "flaky": false, 
     "language": "c", 
+    "name": "alarm_test", 
+    "platforms": [
+      "linux", 
+      "mac", 
+      "posix", 
+      "windows"
+    ]
+  }, 
+  {
+    "args": [], 
+    "ci_platforms": [
+      "linux", 
+      "mac", 
+      "posix", 
+      "windows"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [], 
+    "flaky": false, 
+    "language": "c", 
     "name": "algorithm_test", 
     "platforms": [
       "linux", 
@@ -93,6 +113,26 @@
     "exclude_configs": [], 
     "flaky": false, 
     "language": "c", 
+    "name": "census_context_test", 
+    "platforms": [
+      "linux", 
+      "mac", 
+      "posix", 
+      "windows"
+    ]
+  }, 
+  {
+    "args": [], 
+    "ci_platforms": [
+      "linux", 
+      "mac", 
+      "posix", 
+      "windows"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [], 
+    "flaky": false, 
+    "language": "c", 
     "name": "channel_create_test", 
     "platforms": [
       "linux", 
@@ -1404,26 +1444,6 @@
     "ci_platforms": [
       "linux", 
       "mac", 
-      "posix", 
-      "windows"
-    ], 
-    "cpu_cost": 1.0, 
-    "exclude_configs": [], 
-    "flaky": false, 
-    "language": "c", 
-    "name": "tag_set_test", 
-    "platforms": [
-      "linux", 
-      "mac", 
-      "posix", 
-      "windows"
-    ]
-  }, 
-  {
-    "args": [], 
-    "ci_platforms": [
-      "linux", 
-      "mac", 
       "posix"
     ], 
     "cpu_cost": 0.5, 
@@ -1699,6 +1719,26 @@
     "exclude_configs": [], 
     "flaky": false, 
     "language": "c++", 
+    "name": "alarm_cpp_test", 
+    "platforms": [
+      "linux", 
+      "mac", 
+      "posix", 
+      "windows"
+    ]
+  }, 
+  {
+    "args": [], 
+    "ci_platforms": [
+      "linux", 
+      "mac", 
+      "posix", 
+      "windows"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [], 
+    "flaky": false, 
+    "language": "c++", 
     "name": "async_end2end_test", 
     "platforms": [
       "linux", 
@@ -1984,6 +2024,26 @@
     "ci_platforms": [
       "linux", 
       "mac", 
+      "posix", 
+      "windows"
+    ], 
+    "cpu_cost": 1.0, 
+    "exclude_configs": [], 
+    "flaky": false, 
+    "language": "c++", 
+    "name": "hybrid_end2end_test", 
+    "platforms": [
+      "linux", 
+      "mac", 
+      "posix", 
+      "windows"
+    ]
+  }, 
+  {
+    "args": [], 
+    "ci_platforms": [
+      "linux", 
+      "mac", 
       "posix"
     ], 
     "cpu_cost": 0.1, 
@@ -2433,6 +2493,7 @@
       "windows"
     ], 
     "cpu_cost": 1.0, 
+    "defaults": "boringssl", 
     "exclude_configs": [
       "asan"
     ], 
@@ -2456,6 +2517,7 @@
       "windows"
     ], 
     "cpu_cost": 1.0, 
+    "defaults": "boringssl", 
     "exclude_configs": [
       "asan"
     ], 
@@ -2479,6 +2541,7 @@
       "windows"
     ], 
     "cpu_cost": 1.0, 
+    "defaults": "boringssl", 
     "exclude_configs": [
       "asan"
     ], 
@@ -2502,6 +2565,7 @@
       "windows"
     ], 
     "cpu_cost": 1.0, 
+    "defaults": "boringssl", 
     "exclude_configs": [
       "asan"
     ], 
@@ -2525,6 +2589,7 @@
       "windows"
     ], 
     "cpu_cost": 1.0, 
+    "defaults": "boringssl", 
     "exclude_configs": [
       "asan"
     ], 
@@ -2551,6 +2616,7 @@
       "windows"
     ], 
     "cpu_cost": 1.0, 
+    "defaults": "boringssl", 
     "exclude_configs": [
       "asan"
     ], 
@@ -2577,6 +2643,7 @@
       "windows"
     ], 
     "cpu_cost": 1.0, 
+    "defaults": "boringssl", 
     "exclude_configs": [
       "asan"
     ], 
@@ -2603,6 +2670,7 @@
       "windows"
     ], 
     "cpu_cost": 1.0, 
+    "defaults": "boringssl", 
     "exclude_configs": [
       "asan"
     ], 
@@ -2629,6 +2697,7 @@
       "windows"
     ], 
     "cpu_cost": 1.0, 
+    "defaults": "boringssl", 
     "exclude_configs": [
       "asan"
     ], 
@@ -2655,6 +2724,7 @@
       "windows"
     ], 
     "cpu_cost": 1.0, 
+    "defaults": "boringssl", 
     "exclude_configs": [
       "asan"
     ], 
@@ -2681,6 +2751,7 @@
       "windows"
     ], 
     "cpu_cost": 1.0, 
+    "defaults": "boringssl", 
     "exclude_configs": [
       "asan"
     ], 
@@ -2707,6 +2778,7 @@
       "windows"
     ], 
     "cpu_cost": 1.0, 
+    "defaults": "boringssl", 
     "exclude_configs": [
       "asan"
     ], 
@@ -2733,6 +2805,7 @@
       "windows"
     ], 
     "cpu_cost": 1.0, 
+    "defaults": "boringssl", 
     "exclude_configs": [
       "asan"
     ], 
@@ -2759,6 +2832,7 @@
       "windows"
     ], 
     "cpu_cost": 1.0, 
+    "defaults": "boringssl", 
     "exclude_configs": [
       "asan"
     ], 
@@ -2785,6 +2859,7 @@
       "windows"
     ], 
     "cpu_cost": 1.0, 
+    "defaults": "boringssl", 
     "exclude_configs": [
       "asan"
     ], 
@@ -2811,6 +2886,7 @@
       "windows"
     ], 
     "cpu_cost": 1.0, 
+    "defaults": "boringssl", 
     "exclude_configs": [
       "asan"
     ], 
@@ -2837,6 +2913,7 @@
       "windows"
     ], 
     "cpu_cost": 1.0, 
+    "defaults": "boringssl", 
     "exclude_configs": [
       "asan"
     ], 
@@ -2863,6 +2940,7 @@
       "windows"
     ], 
     "cpu_cost": 1.0, 
+    "defaults": "boringssl", 
     "exclude_configs": [
       "asan"
     ], 
@@ -2889,6 +2967,7 @@
       "windows"
     ], 
     "cpu_cost": 1.0, 
+    "defaults": "boringssl", 
     "exclude_configs": [
       "asan"
     ], 
@@ -2915,6 +2994,7 @@
       "windows"
     ], 
     "cpu_cost": 1.0, 
+    "defaults": "boringssl", 
     "exclude_configs": [
       "asan"
     ], 
@@ -2941,6 +3021,7 @@
       "windows"
     ], 
     "cpu_cost": 1.0, 
+    "defaults": "boringssl", 
     "exclude_configs": [
       "asan"
     ], 
@@ -2967,6 +3048,7 @@
       "windows"
     ], 
     "cpu_cost": 1.0, 
+    "defaults": "boringssl", 
     "exclude_configs": [
       "asan"
     ], 
@@ -2993,6 +3075,7 @@
       "windows"
     ], 
     "cpu_cost": 1.0, 
+    "defaults": "boringssl", 
     "exclude_configs": [
       "asan"
     ], 
@@ -3019,6 +3102,7 @@
       "windows"
     ], 
     "cpu_cost": 1.0, 
+    "defaults": "boringssl", 
     "exclude_configs": [
       "asan"
     ], 
@@ -3045,6 +3129,7 @@
       "windows"
     ], 
     "cpu_cost": 1.0, 
+    "defaults": "boringssl", 
     "exclude_configs": [
       "asan"
     ], 
@@ -3071,6 +3156,7 @@
       "windows"
     ], 
     "cpu_cost": 1.0, 
+    "defaults": "boringssl", 
     "exclude_configs": [
       "asan"
     ], 
@@ -3097,6 +3183,7 @@
       "windows"
     ], 
     "cpu_cost": 1.0, 
+    "defaults": "boringssl", 
     "exclude_configs": [
       "asan"
     ], 
@@ -3123,6 +3210,7 @@
       "windows"
     ], 
     "cpu_cost": 1.0, 
+    "defaults": "boringssl", 
     "exclude_configs": [
       "asan"
     ], 
@@ -3149,6 +3237,7 @@
       "windows"
     ], 
     "cpu_cost": 1.0, 
+    "defaults": "boringssl", 
     "exclude_configs": [
       "asan"
     ], 
@@ -3174,6 +3263,7 @@
       "windows"
     ], 
     "cpu_cost": 1.0, 
+    "defaults": "boringssl", 
     "exclude_configs": [
       "asan"
     ], 
@@ -3197,6 +3287,7 @@
       "windows"
     ], 
     "cpu_cost": 1.0, 
+    "defaults": "boringssl", 
     "exclude_configs": [
       "asan"
     ], 
@@ -3220,6 +3311,7 @@
       "windows"
     ], 
     "cpu_cost": 1.0, 
+    "defaults": "boringssl", 
     "exclude_configs": [
       "asan"
     ], 
@@ -3245,6 +3337,7 @@
       "windows"
     ], 
     "cpu_cost": 1.0, 
+    "defaults": "boringssl", 
     "exclude_configs": [
       "asan"
     ], 
@@ -3268,6 +3361,7 @@
       "windows"
     ], 
     "cpu_cost": 1.0, 
+    "defaults": "boringssl", 
     "exclude_configs": [
       "asan"
     ], 
@@ -3291,6 +3385,7 @@
       "windows"
     ], 
     "cpu_cost": 1.0, 
+    "defaults": "boringssl", 
     "exclude_configs": [
       "asan"
     ], 
@@ -3314,6 +3409,7 @@
       "windows"
     ], 
     "cpu_cost": 1.0, 
+    "defaults": "boringssl", 
     "exclude_configs": [
       "asan"
     ], 
@@ -3337,6 +3433,7 @@
       "windows"
     ], 
     "cpu_cost": 1.0, 
+    "defaults": "boringssl", 
     "exclude_configs": [
       "asan"
     ], 
@@ -3360,6 +3457,7 @@
       "windows"
     ], 
     "cpu_cost": 1.0, 
+    "defaults": "boringssl", 
     "exclude_configs": [
       "asan"
     ], 
@@ -3383,6 +3481,7 @@
       "windows"
     ], 
     "cpu_cost": 1.0, 
+    "defaults": "boringssl", 
     "exclude_configs": [
       "asan"
     ], 
@@ -3406,6 +3505,7 @@
       "windows"
     ], 
     "cpu_cost": 1.0, 
+    "defaults": "boringssl", 
     "exclude_configs": [
       "asan"
     ], 
@@ -3429,6 +3529,7 @@
       "windows"
     ], 
     "cpu_cost": 1.0, 
+    "defaults": "boringssl", 
     "exclude_configs": [
       "asan"
     ], 
@@ -3452,6 +3553,7 @@
       "windows"
     ], 
     "cpu_cost": 1.0, 
+    "defaults": "boringssl", 
     "exclude_configs": [
       "asan"
     ], 
@@ -3477,6 +3579,7 @@
       "windows"
     ], 
     "cpu_cost": 1.0, 
+    "defaults": "boringssl", 
     "exclude_configs": [
       "asan"
     ], 
@@ -3500,6 +3603,7 @@
       "windows"
     ], 
     "cpu_cost": 1.0, 
+    "defaults": "boringssl", 
     "exclude_configs": [
       "asan"
     ], 
@@ -3523,6 +3627,7 @@
       "windows"
     ], 
     "cpu_cost": 1.0, 
+    "defaults": "boringssl", 
     "exclude_configs": [
       "asan"
     ], 
@@ -3548,6 +3653,7 @@
       "windows"
     ], 
     "cpu_cost": 1.0, 
+    "defaults": "boringssl", 
     "exclude_configs": [
       "asan"
     ], 
@@ -3571,6 +3677,7 @@
       "windows"
     ], 
     "cpu_cost": 1.0, 
+    "defaults": "boringssl", 
     "exclude_configs": [
       "asan"
     ], 
@@ -3594,6 +3701,7 @@
       "windows"
     ], 
     "cpu_cost": 1.0, 
+    "defaults": "boringssl", 
     "exclude_configs": [
       "asan"
     ], 
@@ -3617,6 +3725,7 @@
       "windows"
     ], 
     "cpu_cost": 1.0, 
+    "defaults": "boringssl", 
     "exclude_configs": [
       "asan"
     ], 
@@ -3640,6 +3749,7 @@
       "windows"
     ], 
     "cpu_cost": 1.0, 
+    "defaults": "boringssl", 
     "exclude_configs": [
       "asan"
     ], 
@@ -3665,6 +3775,7 @@
       "windows"
     ], 
     "cpu_cost": 1.0, 
+    "defaults": "boringssl", 
     "exclude_configs": [
       "asan"
     ], 
@@ -3688,6 +3799,7 @@
       "windows"
     ], 
     "cpu_cost": 1.0, 
+    "defaults": "boringssl", 
     "exclude_configs": [
       "asan"
     ], 
@@ -3711,6 +3823,7 @@
       "windows"
     ], 
     "cpu_cost": 1.0, 
+    "defaults": "boringssl", 
     "exclude_configs": [
       "asan"
     ], 
@@ -3734,6 +3847,7 @@
       "windows"
     ], 
     "cpu_cost": 1.0, 
+    "defaults": "boringssl", 
     "exclude_configs": [
       "asan"
     ], 
@@ -3757,6 +3871,7 @@
       "windows"
     ], 
     "cpu_cost": 1.0, 
+    "defaults": "boringssl", 
     "exclude_configs": [
       "asan"
     ], 
@@ -3780,6 +3895,7 @@
       "windows"
     ], 
     "cpu_cost": 1.0, 
+    "defaults": "boringssl", 
     "exclude_configs": [
       "asan"
     ], 
@@ -3803,6 +3919,7 @@
       "windows"
     ], 
     "cpu_cost": 1.0, 
+    "defaults": "boringssl", 
     "exclude_configs": [
       "asan"
     ], 
@@ -3826,6 +3943,7 @@
       "windows"
     ], 
     "cpu_cost": 1.0, 
+    "defaults": "boringssl", 
     "exclude_configs": [
       "asan"
     ], 
@@ -3849,6 +3967,7 @@
       "windows"
     ], 
     "cpu_cost": 1.0, 
+    "defaults": "boringssl", 
     "exclude_configs": [
       "asan"
     ], 
diff --git a/vsprojects/buildtests_c.sln b/vsprojects/buildtests_c.sln
index d8ecdea..ea8e504 100644
--- a/vsprojects/buildtests_c.sln
+++ b/vsprojects/buildtests_c.sln
@@ -29,8 +29,8 @@
         	lib = "True"
 	EndProjectSection
 	ProjectSection(ProjectDependencies) = postProject
-		{B23D3D1A-9438-4EDA-BEB6-9A0A03D17792} = {B23D3D1A-9438-4EDA-BEB6-9A0A03D17792}
 		{EAB0A629-17A9-44DB-B5FF-E91A721FE037} = {EAB0A629-17A9-44DB-B5FF-E91A721FE037}
+		{B23D3D1A-9438-4EDA-BEB6-9A0A03D17792} = {B23D3D1A-9438-4EDA-BEB6-9A0A03D17792}
 		{29D16885-7228-4C31-81ED-5F9187C7F2A9} = {29D16885-7228-4C31-81ED-5F9187C7F2A9}
 	EndProjectSection
 EndProject
@@ -114,6 +114,17 @@
         	lib = "True"
 	EndProjectSection
 EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "alarm_test", "vcxproj\test\alarm_test\alarm_test.vcxproj", "{AFD362D7-0E2A-E700-1F27-9D90F76166DF}"
+	ProjectSection(myProperties) = preProject
+        	lib = "False"
+	EndProjectSection
+	ProjectSection(ProjectDependencies) = postProject
+		{17BCAFC0-5FDC-4C94-AEB9-95F3E220614B} = {17BCAFC0-5FDC-4C94-AEB9-95F3E220614B}
+		{29D16885-7228-4C31-81ED-5F9187C7F2A9} = {29D16885-7228-4C31-81ED-5F9187C7F2A9}
+		{EAB0A629-17A9-44DB-B5FF-E91A721FE037} = {EAB0A629-17A9-44DB-B5FF-E91A721FE037}
+		{B23D3D1A-9438-4EDA-BEB6-9A0A03D17792} = {B23D3D1A-9438-4EDA-BEB6-9A0A03D17792}
+	EndProjectSection
+EndProject
 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "algorithm_test", "vcxproj\test\algorithm_test\algorithm_test.vcxproj", "{216FDCB2-9D93-0D86-F0F1-12E16312A191}"
 	ProjectSection(myProperties) = preProject
         	lib = "False"
@@ -152,6 +163,15 @@
 	ProjectSection(ProjectDependencies) = postProject
 		{17BCAFC0-5FDC-4C94-AEB9-95F3E220614B} = {17BCAFC0-5FDC-4C94-AEB9-95F3E220614B}
 		{29D16885-7228-4C31-81ED-5F9187C7F2A9} = {29D16885-7228-4C31-81ED-5F9187C7F2A9}
+	EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "census_context_test", "vcxproj\test\census_context_test\census_context_test.vcxproj", "{5C1CFC2D-AF3C-D7CB-BA74-D267E91CBC73}"
+	ProjectSection(myProperties) = preProject
+        	lib = "False"
+	EndProjectSection
+	ProjectSection(ProjectDependencies) = postProject
+		{17BCAFC0-5FDC-4C94-AEB9-95F3E220614B} = {17BCAFC0-5FDC-4C94-AEB9-95F3E220614B}
+		{29D16885-7228-4C31-81ED-5F9187C7F2A9} = {29D16885-7228-4C31-81ED-5F9187C7F2A9}
 		{EAB0A629-17A9-44DB-B5FF-E91A721FE037} = {EAB0A629-17A9-44DB-B5FF-E91A721FE037}
 		{B23D3D1A-9438-4EDA-BEB6-9A0A03D17792} = {B23D3D1A-9438-4EDA-BEB6-9A0A03D17792}
 	EndProjectSection
@@ -848,17 +868,6 @@
 		{B23D3D1A-9438-4EDA-BEB6-9A0A03D17792} = {B23D3D1A-9438-4EDA-BEB6-9A0A03D17792}
 	EndProjectSection
 EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "tag_set_test", "vcxproj\test\tag_set_test\tag_set_test.vcxproj", "{430F8F07-6AAD-0150-B35B-DB9E2E21941A}"
-	ProjectSection(myProperties) = preProject
-        	lib = "False"
-	EndProjectSection
-	ProjectSection(ProjectDependencies) = postProject
-		{17BCAFC0-5FDC-4C94-AEB9-95F3E220614B} = {17BCAFC0-5FDC-4C94-AEB9-95F3E220614B}
-		{29D16885-7228-4C31-81ED-5F9187C7F2A9} = {29D16885-7228-4C31-81ED-5F9187C7F2A9}
-		{EAB0A629-17A9-44DB-B5FF-E91A721FE037} = {EAB0A629-17A9-44DB-B5FF-E91A721FE037}
-		{B23D3D1A-9438-4EDA-BEB6-9A0A03D17792} = {B23D3D1A-9438-4EDA-BEB6-9A0A03D17792}
-	EndProjectSection
-EndProject
 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "time_averaged_stats_test", "vcxproj\test\time_averaged_stats_test\time_averaged_stats_test.vcxproj", "{D1EB2A9B-8508-62D7-8FC4-11A11B1CBFD3}"
 	ProjectSection(myProperties) = preProject
         	lib = "False"
@@ -1499,6 +1508,22 @@
 		{80EA2691-C037-6DD3-D3AB-21510BF0E64B}.Release-DLL|Win32.Build.0 = Release|Win32
 		{80EA2691-C037-6DD3-D3AB-21510BF0E64B}.Release-DLL|x64.ActiveCfg = Release|x64
 		{80EA2691-C037-6DD3-D3AB-21510BF0E64B}.Release-DLL|x64.Build.0 = Release|x64
+		{AFD362D7-0E2A-E700-1F27-9D90F76166DF}.Debug|Win32.ActiveCfg = Debug|Win32
+		{AFD362D7-0E2A-E700-1F27-9D90F76166DF}.Debug|x64.ActiveCfg = Debug|x64
+		{AFD362D7-0E2A-E700-1F27-9D90F76166DF}.Release|Win32.ActiveCfg = Release|Win32
+		{AFD362D7-0E2A-E700-1F27-9D90F76166DF}.Release|x64.ActiveCfg = Release|x64
+		{AFD362D7-0E2A-E700-1F27-9D90F76166DF}.Debug|Win32.Build.0 = Debug|Win32
+		{AFD362D7-0E2A-E700-1F27-9D90F76166DF}.Debug|x64.Build.0 = Debug|x64
+		{AFD362D7-0E2A-E700-1F27-9D90F76166DF}.Release|Win32.Build.0 = Release|Win32
+		{AFD362D7-0E2A-E700-1F27-9D90F76166DF}.Release|x64.Build.0 = Release|x64
+		{AFD362D7-0E2A-E700-1F27-9D90F76166DF}.Debug-DLL|Win32.ActiveCfg = Debug|Win32
+		{AFD362D7-0E2A-E700-1F27-9D90F76166DF}.Debug-DLL|Win32.Build.0 = Debug|Win32
+		{AFD362D7-0E2A-E700-1F27-9D90F76166DF}.Debug-DLL|x64.ActiveCfg = Debug|x64
+		{AFD362D7-0E2A-E700-1F27-9D90F76166DF}.Debug-DLL|x64.Build.0 = Debug|x64
+		{AFD362D7-0E2A-E700-1F27-9D90F76166DF}.Release-DLL|Win32.ActiveCfg = Release|Win32
+		{AFD362D7-0E2A-E700-1F27-9D90F76166DF}.Release-DLL|Win32.Build.0 = Release|Win32
+		{AFD362D7-0E2A-E700-1F27-9D90F76166DF}.Release-DLL|x64.ActiveCfg = Release|x64
+		{AFD362D7-0E2A-E700-1F27-9D90F76166DF}.Release-DLL|x64.Build.0 = Release|x64
 		{216FDCB2-9D93-0D86-F0F1-12E16312A191}.Debug|Win32.ActiveCfg = Debug|Win32
 		{216FDCB2-9D93-0D86-F0F1-12E16312A191}.Debug|x64.ActiveCfg = Debug|x64
 		{216FDCB2-9D93-0D86-F0F1-12E16312A191}.Release|Win32.ActiveCfg = Release|Win32
@@ -1563,6 +1588,22 @@
 		{D5C70922-D68E-0E9D-9988-995E0F9A79AE}.Release-DLL|Win32.Build.0 = Release|Win32
 		{D5C70922-D68E-0E9D-9988-995E0F9A79AE}.Release-DLL|x64.ActiveCfg = Release|x64
 		{D5C70922-D68E-0E9D-9988-995E0F9A79AE}.Release-DLL|x64.Build.0 = Release|x64
+		{5C1CFC2D-AF3C-D7CB-BA74-D267E91CBC73}.Debug|Win32.ActiveCfg = Debug|Win32
+		{5C1CFC2D-AF3C-D7CB-BA74-D267E91CBC73}.Debug|x64.ActiveCfg = Debug|x64
+		{5C1CFC2D-AF3C-D7CB-BA74-D267E91CBC73}.Release|Win32.ActiveCfg = Release|Win32
+		{5C1CFC2D-AF3C-D7CB-BA74-D267E91CBC73}.Release|x64.ActiveCfg = Release|x64
+		{5C1CFC2D-AF3C-D7CB-BA74-D267E91CBC73}.Debug|Win32.Build.0 = Debug|Win32
+		{5C1CFC2D-AF3C-D7CB-BA74-D267E91CBC73}.Debug|x64.Build.0 = Debug|x64
+		{5C1CFC2D-AF3C-D7CB-BA74-D267E91CBC73}.Release|Win32.Build.0 = Release|Win32
+		{5C1CFC2D-AF3C-D7CB-BA74-D267E91CBC73}.Release|x64.Build.0 = Release|x64
+		{5C1CFC2D-AF3C-D7CB-BA74-D267E91CBC73}.Debug-DLL|Win32.ActiveCfg = Debug|Win32
+		{5C1CFC2D-AF3C-D7CB-BA74-D267E91CBC73}.Debug-DLL|Win32.Build.0 = Debug|Win32
+		{5C1CFC2D-AF3C-D7CB-BA74-D267E91CBC73}.Debug-DLL|x64.ActiveCfg = Debug|x64
+		{5C1CFC2D-AF3C-D7CB-BA74-D267E91CBC73}.Debug-DLL|x64.Build.0 = Debug|x64
+		{5C1CFC2D-AF3C-D7CB-BA74-D267E91CBC73}.Release-DLL|Win32.ActiveCfg = Release|Win32
+		{5C1CFC2D-AF3C-D7CB-BA74-D267E91CBC73}.Release-DLL|Win32.Build.0 = Release|Win32
+		{5C1CFC2D-AF3C-D7CB-BA74-D267E91CBC73}.Release-DLL|x64.ActiveCfg = Release|x64
+		{5C1CFC2D-AF3C-D7CB-BA74-D267E91CBC73}.Release-DLL|x64.Build.0 = Release|x64
 		{AFC88484-3A2E-32BC-25B2-23DF741D4F3D}.Debug|Win32.ActiveCfg = Debug|Win32
 		{AFC88484-3A2E-32BC-25B2-23DF741D4F3D}.Debug|x64.ActiveCfg = Debug|x64
 		{AFC88484-3A2E-32BC-25B2-23DF741D4F3D}.Release|Win32.ActiveCfg = Release|Win32
@@ -2635,22 +2676,6 @@
 		{529771F0-10B0-9B1A-1E7E-8A8E01870348}.Release-DLL|Win32.Build.0 = Release|Win32
 		{529771F0-10B0-9B1A-1E7E-8A8E01870348}.Release-DLL|x64.ActiveCfg = Release|x64
 		{529771F0-10B0-9B1A-1E7E-8A8E01870348}.Release-DLL|x64.Build.0 = Release|x64
-		{430F8F07-6AAD-0150-B35B-DB9E2E21941A}.Debug|Win32.ActiveCfg = Debug|Win32
-		{430F8F07-6AAD-0150-B35B-DB9E2E21941A}.Debug|x64.ActiveCfg = Debug|x64
-		{430F8F07-6AAD-0150-B35B-DB9E2E21941A}.Release|Win32.ActiveCfg = Release|Win32
-		{430F8F07-6AAD-0150-B35B-DB9E2E21941A}.Release|x64.ActiveCfg = Release|x64
-		{430F8F07-6AAD-0150-B35B-DB9E2E21941A}.Debug|Win32.Build.0 = Debug|Win32
-		{430F8F07-6AAD-0150-B35B-DB9E2E21941A}.Debug|x64.Build.0 = Debug|x64
-		{430F8F07-6AAD-0150-B35B-DB9E2E21941A}.Release|Win32.Build.0 = Release|Win32
-		{430F8F07-6AAD-0150-B35B-DB9E2E21941A}.Release|x64.Build.0 = Release|x64
-		{430F8F07-6AAD-0150-B35B-DB9E2E21941A}.Debug-DLL|Win32.ActiveCfg = Debug|Win32
-		{430F8F07-6AAD-0150-B35B-DB9E2E21941A}.Debug-DLL|Win32.Build.0 = Debug|Win32
-		{430F8F07-6AAD-0150-B35B-DB9E2E21941A}.Debug-DLL|x64.ActiveCfg = Debug|x64
-		{430F8F07-6AAD-0150-B35B-DB9E2E21941A}.Debug-DLL|x64.Build.0 = Debug|x64
-		{430F8F07-6AAD-0150-B35B-DB9E2E21941A}.Release-DLL|Win32.ActiveCfg = Release|Win32
-		{430F8F07-6AAD-0150-B35B-DB9E2E21941A}.Release-DLL|Win32.Build.0 = Release|Win32
-		{430F8F07-6AAD-0150-B35B-DB9E2E21941A}.Release-DLL|x64.ActiveCfg = Release|x64
-		{430F8F07-6AAD-0150-B35B-DB9E2E21941A}.Release-DLL|x64.Build.0 = Release|x64
 		{D1EB2A9B-8508-62D7-8FC4-11A11B1CBFD3}.Debug|Win32.ActiveCfg = Debug|Win32
 		{D1EB2A9B-8508-62D7-8FC4-11A11B1CBFD3}.Debug|x64.ActiveCfg = Debug|x64
 		{D1EB2A9B-8508-62D7-8FC4-11A11B1CBFD3}.Release|Win32.ActiveCfg = Release|Win32
diff --git a/vsprojects/grpc.sln b/vsprojects/grpc.sln
index 4919641..ad91983 100644
--- a/vsprojects/grpc.sln
+++ b/vsprojects/grpc.sln
@@ -29,8 +29,8 @@
         	lib = "True"
 	EndProjectSection
 	ProjectSection(ProjectDependencies) = postProject
-		{B23D3D1A-9438-4EDA-BEB6-9A0A03D17792} = {B23D3D1A-9438-4EDA-BEB6-9A0A03D17792}
 		{EAB0A629-17A9-44DB-B5FF-E91A721FE037} = {EAB0A629-17A9-44DB-B5FF-E91A721FE037}
+		{B23D3D1A-9438-4EDA-BEB6-9A0A03D17792} = {B23D3D1A-9438-4EDA-BEB6-9A0A03D17792}
 		{29D16885-7228-4C31-81ED-5F9187C7F2A9} = {29D16885-7228-4C31-81ED-5F9187C7F2A9}
 	EndProjectSection
 EndProject
@@ -80,7 +80,6 @@
         	lib = "True"
 	EndProjectSection
 	ProjectSection(ProjectDependencies) = postProject
-		{B23D3D1A-9438-4EDA-BEB6-9A0A03D17792} = {B23D3D1A-9438-4EDA-BEB6-9A0A03D17792}
 		{29D16885-7228-4C31-81ED-5F9187C7F2A9} = {29D16885-7228-4C31-81ED-5F9187C7F2A9}
 	EndProjectSection
 EndProject
diff --git a/vsprojects/vcxproj/gpr/gpr.vcxproj b/vsprojects/vcxproj/gpr/gpr.vcxproj
index 270fc89..e1b3963 100644
--- a/vsprojects/vcxproj/gpr/gpr.vcxproj
+++ b/vsprojects/vcxproj/gpr/gpr.vcxproj
@@ -175,6 +175,20 @@
     <ClInclude Include="$(SolutionDir)\..\include\grpc\support\tls_msvc.h" />
     <ClInclude Include="$(SolutionDir)\..\include\grpc\support\tls_pthread.h" />
     <ClInclude Include="$(SolutionDir)\..\include\grpc\support\useful.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\alloc.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\atm.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\atm_gcc_atomic.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\atm_gcc_sync.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\atm_win32.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\log.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\port_platform.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\slice.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\slice_buffer.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\sync.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\sync_generic.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\sync_posix.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\sync_win32.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\time.h" />
   </ItemGroup>
   <ItemGroup>
     <ClInclude Include="$(SolutionDir)\..\src\core\profiling\timers.h" />
@@ -249,6 +263,8 @@
     </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\support\subprocess_posix.c">
     </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\support\subprocess_windows.c">
+    </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\support\sync.c">
     </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\support\sync_posix.c">
@@ -271,6 +287,8 @@
     </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\support\tls_pthread.c">
     </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\support\wrap_memcpy.c">
+    </ClCompile>
   </ItemGroup>
   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
   <ImportGroup Label="ExtensionTargets">
diff --git a/vsprojects/vcxproj/gpr/gpr.vcxproj.filters b/vsprojects/vcxproj/gpr/gpr.vcxproj.filters
index c92a92f..aedba93 100644
--- a/vsprojects/vcxproj/gpr/gpr.vcxproj.filters
+++ b/vsprojects/vcxproj/gpr/gpr.vcxproj.filters
@@ -91,6 +91,9 @@
     <ClCompile Include="$(SolutionDir)\..\src\core\support\subprocess_posix.c">
       <Filter>src\core\support</Filter>
     </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\support\subprocess_windows.c">
+      <Filter>src\core\support</Filter>
+    </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\support\sync.c">
       <Filter>src\core\support</Filter>
     </ClCompile>
@@ -124,6 +127,9 @@
     <ClCompile Include="$(SolutionDir)\..\src\core\support\tls_pthread.c">
       <Filter>src\core\support</Filter>
     </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\support\wrap_memcpy.c">
+      <Filter>src\core\support</Filter>
+    </ClCompile>
   </ItemGroup>
   <ItemGroup>
     <ClInclude Include="$(SolutionDir)\..\include\grpc\support\alloc.h">
@@ -210,6 +216,48 @@
     <ClInclude Include="$(SolutionDir)\..\include\grpc\support\useful.h">
       <Filter>include\grpc\support</Filter>
     </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\alloc.h">
+      <Filter>include\grpc\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\atm.h">
+      <Filter>include\grpc\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\atm_gcc_atomic.h">
+      <Filter>include\grpc\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\atm_gcc_sync.h">
+      <Filter>include\grpc\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\atm_win32.h">
+      <Filter>include\grpc\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\log.h">
+      <Filter>include\grpc\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\port_platform.h">
+      <Filter>include\grpc\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\slice.h">
+      <Filter>include\grpc\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\slice_buffer.h">
+      <Filter>include\grpc\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\sync.h">
+      <Filter>include\grpc\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\sync_generic.h">
+      <Filter>include\grpc\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\sync_posix.h">
+      <Filter>include\grpc\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\sync_win32.h">
+      <Filter>include\grpc\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\time.h">
+      <Filter>include\grpc\impl\codegen</Filter>
+    </ClInclude>
   </ItemGroup>
   <ItemGroup>
     <ClInclude Include="$(SolutionDir)\..\src\core\profiling\timers.h">
@@ -251,6 +299,12 @@
     <Filter Include="include\grpc">
       <UniqueIdentifier>{e6957ec1-85ba-6515-03c0-e12878045b1f}</UniqueIdentifier>
     </Filter>
+    <Filter Include="include\grpc\impl">
+      <UniqueIdentifier>{4c72091a-872d-10da-2694-ce5a7b069a1f}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="include\grpc\impl\codegen">
+      <UniqueIdentifier>{e52e0384-d0d3-1475-0d4e-11719aac8f2a}</UniqueIdentifier>
+    </Filter>
     <Filter Include="include\grpc\support">
       <UniqueIdentifier>{31c42000-3ed7-95e1-d076-df814b72cdee}</UniqueIdentifier>
     </Filter>
diff --git a/vsprojects/vcxproj/grpc++/grpc++.vcxproj b/vsprojects/vcxproj/grpc++/grpc++.vcxproj
index 886d415..bb2d0e7 100644
--- a/vsprojects/vcxproj/grpc++/grpc++.vcxproj
+++ b/vsprojects/vcxproj/grpc++/grpc++.vcxproj
@@ -258,6 +258,7 @@
   </ItemDefinitionGroup>
 
   <ItemGroup>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\alarm.h" />
     <ClInclude Include="$(SolutionDir)\..\include\grpc++\channel.h" />
     <ClInclude Include="$(SolutionDir)\..\include\grpc++\client_context.h" />
     <ClInclude Include="$(SolutionDir)\..\include\grpc++\completion_queue.h" />
@@ -268,6 +269,7 @@
     <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\call.h" />
     <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\client_unary_call.h" />
     <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\grpc_library.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\method_handler_impl.h" />
     <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\proto_utils.h" />
     <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\rpc_method.h" />
     <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\rpc_service_method.h" />
@@ -300,6 +302,36 @@
     <ClInclude Include="$(SolutionDir)\..\include\grpc++\support\stub_options.h" />
     <ClInclude Include="$(SolutionDir)\..\include\grpc++\support\sync_stream.h" />
     <ClInclude Include="$(SolutionDir)\..\include\grpc++\support\time.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\async_stream.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\async_unary_call.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\call.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\call_hook.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\channel_interface.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\client_context.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\client_unary_call.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\completion_queue.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\completion_queue_tag.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\config.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\config_protobuf.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\grpc_library.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\method_handler_impl.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\proto_utils.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\rpc_method.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\rpc_service_method.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\security\auth_context.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\serialization_traits.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\server_context.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\server_interface.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\service_type.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\status.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\status_code_enum.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\string_ref.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\stub_options.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\sync.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\sync_cxx11.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\sync_no_cxx11.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\sync_stream.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\time.h" />
   </ItemGroup>
   <ItemGroup>
     <ClInclude Include="$(SolutionDir)\..\src\cpp\client\secure_credentials.h" />
@@ -338,6 +370,8 @@
     </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\cpp\client\insecure_credentials.cc">
     </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\cpp\common\alarm.cc">
+    </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\cpp\common\call.cc">
     </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\cpp\common\channel_arguments.cc">
@@ -376,11 +410,10 @@
     </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\cpp\util\time.cc">
     </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\cpp\codegen\grpc_library.cc">
+    </ClCompile>
   </ItemGroup>
   <ItemGroup>
-    <ProjectReference Include="$(SolutionDir)\..\vsprojects\vcxproj\.\gpr\gpr.vcxproj">
-      <Project>{B23D3D1A-9438-4EDA-BEB6-9A0A03D17792}</Project>
-    </ProjectReference>
     <ProjectReference Include="$(SolutionDir)\..\vsprojects\vcxproj\.\grpc\grpc.vcxproj">
       <Project>{29D16885-7228-4C31-81ED-5F9187C7F2A9}</Project>
     </ProjectReference>
diff --git a/vsprojects/vcxproj/grpc++/grpc++.vcxproj.filters b/vsprojects/vcxproj/grpc++/grpc++.vcxproj.filters
index abd39c7..72ecfe2 100644
--- a/vsprojects/vcxproj/grpc++/grpc++.vcxproj.filters
+++ b/vsprojects/vcxproj/grpc++/grpc++.vcxproj.filters
@@ -40,6 +40,9 @@
     <ClCompile Include="$(SolutionDir)\..\src\cpp\client\insecure_credentials.cc">
       <Filter>src\cpp\client</Filter>
     </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\cpp\common\alarm.cc">
+      <Filter>src\cpp\common</Filter>
+    </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\cpp\common\call.cc">
       <Filter>src\cpp\common</Filter>
     </ClCompile>
@@ -97,8 +100,14 @@
     <ClCompile Include="$(SolutionDir)\..\src\cpp\util\time.cc">
       <Filter>src\cpp\util</Filter>
     </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\cpp\codegen\grpc_library.cc">
+      <Filter>src\cpp\codegen</Filter>
+    </ClCompile>
   </ItemGroup>
   <ItemGroup>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\alarm.h">
+      <Filter>include\grpc++</Filter>
+    </ClInclude>
     <ClInclude Include="$(SolutionDir)\..\include\grpc++\channel.h">
       <Filter>include\grpc++</Filter>
     </ClInclude>
@@ -129,6 +138,9 @@
     <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\grpc_library.h">
       <Filter>include\grpc++\impl</Filter>
     </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\method_handler_impl.h">
+      <Filter>include\grpc++\impl</Filter>
+    </ClInclude>
     <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\proto_utils.h">
       <Filter>include\grpc++\impl</Filter>
     </ClInclude>
@@ -225,6 +237,96 @@
     <ClInclude Include="$(SolutionDir)\..\include\grpc++\support\time.h">
       <Filter>include\grpc++\support</Filter>
     </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\async_stream.h">
+      <Filter>include\grpc++\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\async_unary_call.h">
+      <Filter>include\grpc++\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\call.h">
+      <Filter>include\grpc++\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\call_hook.h">
+      <Filter>include\grpc++\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\channel_interface.h">
+      <Filter>include\grpc++\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\client_context.h">
+      <Filter>include\grpc++\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\client_unary_call.h">
+      <Filter>include\grpc++\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\completion_queue.h">
+      <Filter>include\grpc++\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\completion_queue_tag.h">
+      <Filter>include\grpc++\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\config.h">
+      <Filter>include\grpc++\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\config_protobuf.h">
+      <Filter>include\grpc++\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\grpc_library.h">
+      <Filter>include\grpc++\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\method_handler_impl.h">
+      <Filter>include\grpc++\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\proto_utils.h">
+      <Filter>include\grpc++\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\rpc_method.h">
+      <Filter>include\grpc++\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\rpc_service_method.h">
+      <Filter>include\grpc++\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\security\auth_context.h">
+      <Filter>include\grpc++\impl\codegen\security</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\serialization_traits.h">
+      <Filter>include\grpc++\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\server_context.h">
+      <Filter>include\grpc++\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\server_interface.h">
+      <Filter>include\grpc++\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\service_type.h">
+      <Filter>include\grpc++\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\status.h">
+      <Filter>include\grpc++\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\status_code_enum.h">
+      <Filter>include\grpc++\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\string_ref.h">
+      <Filter>include\grpc++\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\stub_options.h">
+      <Filter>include\grpc++\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\sync.h">
+      <Filter>include\grpc++\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\sync_cxx11.h">
+      <Filter>include\grpc++\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\sync_no_cxx11.h">
+      <Filter>include\grpc++\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\sync_stream.h">
+      <Filter>include\grpc++\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\time.h">
+      <Filter>include\grpc++\impl\codegen</Filter>
+    </ClInclude>
   </ItemGroup>
   <ItemGroup>
     <ClInclude Include="$(SolutionDir)\..\src\cpp\client\secure_credentials.h">
@@ -266,6 +368,12 @@
     <Filter Include="include\grpc++\impl">
       <UniqueIdentifier>{0da8cd95-314f-da1b-5ce7-7791a5be1f1a}</UniqueIdentifier>
     </Filter>
+    <Filter Include="include\grpc++\impl\codegen">
+      <UniqueIdentifier>{a3e7f28b-a7c7-7364-d402-edb1bfa414a4}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="include\grpc++\impl\codegen\security">
+      <UniqueIdentifier>{20cbcf00-994a-300a-5184-bda96c6f45e4}</UniqueIdentifier>
+    </Filter>
     <Filter Include="include\grpc++\security">
       <UniqueIdentifier>{a80eb32b-1be9-1187-5f40-30d92accecc8}</UniqueIdentifier>
     </Filter>
@@ -281,6 +389,9 @@
     <Filter Include="src\cpp\client">
       <UniqueIdentifier>{7febf32a-d7a6-76fa-9e17-f189f591c062}</UniqueIdentifier>
     </Filter>
+    <Filter Include="src\cpp\codegen">
+      <UniqueIdentifier>{3c3e27f4-d3d9-3c42-5204-08b5e839f2de}</UniqueIdentifier>
+    </Filter>
     <Filter Include="src\cpp\common">
       <UniqueIdentifier>{2336e396-7e0b-8bf9-3b09-adc6ad1f0e5b}</UniqueIdentifier>
     </Filter>
diff --git a/vsprojects/vcxproj/grpc++_test_util/grpc++_test_util.vcxproj b/vsprojects/vcxproj/grpc++_test_util/grpc++_test_util.vcxproj
index 299fdaf..3d35371 100644
--- a/vsprojects/vcxproj/grpc++_test_util/grpc++_test_util.vcxproj
+++ b/vsprojects/vcxproj/grpc++_test_util/grpc++_test_util.vcxproj
@@ -147,6 +147,8 @@
   </ItemDefinitionGroup>
 
   <ItemGroup>
+    <ClInclude Include="$(SolutionDir)\..\test\cpp\end2end\test_service_impl.h" />
+    <ClInclude Include="$(SolutionDir)\..\test\cpp\util\byte_buffer_proto_helper.h" />
     <ClInclude Include="$(SolutionDir)\..\test\cpp\util\cli_call.h" />
     <ClInclude Include="$(SolutionDir)\..\test\cpp\util\create_test_channel.h" />
     <ClInclude Include="$(SolutionDir)\..\test\cpp\util\string_ref_helper.h" />
@@ -177,6 +179,10 @@
     </ClCompile>
     <ClInclude Include="$(SolutionDir)\..\src\proto\grpc\testing\duplicate\echo_duplicate.grpc.pb.h">
     </ClInclude>
+    <ClCompile Include="$(SolutionDir)\..\test\cpp\end2end\test_service_impl.cc">
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\test\cpp\util\byte_buffer_proto_helper.cc">
+    </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\test\cpp\util\cli_call.cc">
     </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\test\cpp\util\create_test_channel.cc">
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 70addd6..27ac675 100644
--- a/vsprojects/vcxproj/grpc++_test_util/grpc++_test_util.vcxproj.filters
+++ b/vsprojects/vcxproj/grpc++_test_util/grpc++_test_util.vcxproj.filters
@@ -10,6 +10,12 @@
     <ClCompile Include="$(SolutionDir)\..\src\proto\grpc\testing\duplicate\echo_duplicate.proto">
       <Filter>src\proto\grpc\testing\duplicate</Filter>
     </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\test\cpp\end2end\test_service_impl.cc">
+      <Filter>test\cpp\end2end</Filter>
+    </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\test\cpp\util\byte_buffer_proto_helper.cc">
+      <Filter>test\cpp\util</Filter>
+    </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\test\cpp\util\cli_call.cc">
       <Filter>test\cpp\util</Filter>
     </ClCompile>
@@ -24,6 +30,12 @@
     </ClCompile>
   </ItemGroup>
   <ItemGroup>
+    <ClInclude Include="$(SolutionDir)\..\test\cpp\end2end\test_service_impl.h">
+      <Filter>test\cpp\end2end</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\test\cpp\util\byte_buffer_proto_helper.h">
+      <Filter>test\cpp\util</Filter>
+    </ClInclude>
     <ClInclude Include="$(SolutionDir)\..\test\cpp\util\cli_call.h">
       <Filter>test\cpp\util</Filter>
     </ClInclude>
@@ -60,6 +72,9 @@
     <Filter Include="test\cpp">
       <UniqueIdentifier>{793efaa7-370f-c34a-d347-31fc4e0630e2}</UniqueIdentifier>
     </Filter>
+    <Filter Include="test\cpp\end2end">
+      <UniqueIdentifier>{1e6760f2-4cf7-1ecb-88a5-5faeec3c2150}</UniqueIdentifier>
+    </Filter>
     <Filter Include="test\cpp\util">
       <UniqueIdentifier>{bbe1e5b7-f4f9-8e32-ce7c-8c21afcf39d8}</UniqueIdentifier>
     </Filter>
diff --git a/vsprojects/vcxproj/grpc++_unsecure/grpc++_unsecure.vcxproj b/vsprojects/vcxproj/grpc++_unsecure/grpc++_unsecure.vcxproj
index 2193321..8ff8d8b 100644
--- a/vsprojects/vcxproj/grpc++_unsecure/grpc++_unsecure.vcxproj
+++ b/vsprojects/vcxproj/grpc++_unsecure/grpc++_unsecure.vcxproj
@@ -258,6 +258,7 @@
   </ItemDefinitionGroup>
 
   <ItemGroup>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\alarm.h" />
     <ClInclude Include="$(SolutionDir)\..\include\grpc++\channel.h" />
     <ClInclude Include="$(SolutionDir)\..\include\grpc++\client_context.h" />
     <ClInclude Include="$(SolutionDir)\..\include\grpc++\completion_queue.h" />
@@ -268,6 +269,7 @@
     <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\call.h" />
     <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\client_unary_call.h" />
     <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\grpc_library.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\method_handler_impl.h" />
     <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\proto_utils.h" />
     <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\rpc_method.h" />
     <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\rpc_service_method.h" />
@@ -300,6 +302,36 @@
     <ClInclude Include="$(SolutionDir)\..\include\grpc++\support\stub_options.h" />
     <ClInclude Include="$(SolutionDir)\..\include\grpc++\support\sync_stream.h" />
     <ClInclude Include="$(SolutionDir)\..\include\grpc++\support\time.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\async_stream.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\async_unary_call.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\call.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\call_hook.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\channel_interface.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\client_context.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\client_unary_call.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\completion_queue.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\completion_queue_tag.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\config.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\config_protobuf.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\grpc_library.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\method_handler_impl.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\proto_utils.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\rpc_method.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\rpc_service_method.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\security\auth_context.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\serialization_traits.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\server_context.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\server_interface.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\service_type.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\status.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\status_code_enum.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\string_ref.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\stub_options.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\sync.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\sync_cxx11.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\sync_no_cxx11.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\sync_stream.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\time.h" />
   </ItemGroup>
   <ItemGroup>
     <ClInclude Include="$(SolutionDir)\..\src\cpp\client\create_channel_internal.h" />
@@ -325,6 +357,8 @@
     </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\cpp\client\insecure_credentials.cc">
     </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\cpp\common\alarm.cc">
+    </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\cpp\common\call.cc">
     </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\cpp\common\channel_arguments.cc">
@@ -363,6 +397,8 @@
     </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\cpp\util\time.cc">
     </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\cpp\codegen\grpc_library.cc">
+    </ClCompile>
   </ItemGroup>
   <ItemGroup>
     <ProjectReference Include="$(SolutionDir)\..\vsprojects\vcxproj\.\gpr\gpr.vcxproj">
diff --git a/vsprojects/vcxproj/grpc++_unsecure/grpc++_unsecure.vcxproj.filters b/vsprojects/vcxproj/grpc++_unsecure/grpc++_unsecure.vcxproj.filters
index 073b181..316fdd7 100644
--- a/vsprojects/vcxproj/grpc++_unsecure/grpc++_unsecure.vcxproj.filters
+++ b/vsprojects/vcxproj/grpc++_unsecure/grpc++_unsecure.vcxproj.filters
@@ -25,6 +25,9 @@
     <ClCompile Include="$(SolutionDir)\..\src\cpp\client\insecure_credentials.cc">
       <Filter>src\cpp\client</Filter>
     </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\cpp\common\alarm.cc">
+      <Filter>src\cpp\common</Filter>
+    </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\cpp\common\call.cc">
       <Filter>src\cpp\common</Filter>
     </ClCompile>
@@ -82,8 +85,14 @@
     <ClCompile Include="$(SolutionDir)\..\src\cpp\util\time.cc">
       <Filter>src\cpp\util</Filter>
     </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\cpp\codegen\grpc_library.cc">
+      <Filter>src\cpp\codegen</Filter>
+    </ClCompile>
   </ItemGroup>
   <ItemGroup>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\alarm.h">
+      <Filter>include\grpc++</Filter>
+    </ClInclude>
     <ClInclude Include="$(SolutionDir)\..\include\grpc++\channel.h">
       <Filter>include\grpc++</Filter>
     </ClInclude>
@@ -114,6 +123,9 @@
     <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\grpc_library.h">
       <Filter>include\grpc++\impl</Filter>
     </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\method_handler_impl.h">
+      <Filter>include\grpc++\impl</Filter>
+    </ClInclude>
     <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\proto_utils.h">
       <Filter>include\grpc++\impl</Filter>
     </ClInclude>
@@ -210,6 +222,96 @@
     <ClInclude Include="$(SolutionDir)\..\include\grpc++\support\time.h">
       <Filter>include\grpc++\support</Filter>
     </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\async_stream.h">
+      <Filter>include\grpc++\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\async_unary_call.h">
+      <Filter>include\grpc++\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\call.h">
+      <Filter>include\grpc++\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\call_hook.h">
+      <Filter>include\grpc++\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\channel_interface.h">
+      <Filter>include\grpc++\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\client_context.h">
+      <Filter>include\grpc++\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\client_unary_call.h">
+      <Filter>include\grpc++\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\completion_queue.h">
+      <Filter>include\grpc++\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\completion_queue_tag.h">
+      <Filter>include\grpc++\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\config.h">
+      <Filter>include\grpc++\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\config_protobuf.h">
+      <Filter>include\grpc++\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\grpc_library.h">
+      <Filter>include\grpc++\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\method_handler_impl.h">
+      <Filter>include\grpc++\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\proto_utils.h">
+      <Filter>include\grpc++\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\rpc_method.h">
+      <Filter>include\grpc++\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\rpc_service_method.h">
+      <Filter>include\grpc++\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\security\auth_context.h">
+      <Filter>include\grpc++\impl\codegen\security</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\serialization_traits.h">
+      <Filter>include\grpc++\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\server_context.h">
+      <Filter>include\grpc++\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\server_interface.h">
+      <Filter>include\grpc++\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\service_type.h">
+      <Filter>include\grpc++\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\status.h">
+      <Filter>include\grpc++\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\status_code_enum.h">
+      <Filter>include\grpc++\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\string_ref.h">
+      <Filter>include\grpc++\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\stub_options.h">
+      <Filter>include\grpc++\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\sync.h">
+      <Filter>include\grpc++\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\sync_cxx11.h">
+      <Filter>include\grpc++\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\sync_no_cxx11.h">
+      <Filter>include\grpc++\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\sync_stream.h">
+      <Filter>include\grpc++\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\time.h">
+      <Filter>include\grpc++\impl\codegen</Filter>
+    </ClInclude>
   </ItemGroup>
   <ItemGroup>
     <ClInclude Include="$(SolutionDir)\..\src\cpp\client\create_channel_internal.h">
@@ -242,6 +344,12 @@
     <Filter Include="include\grpc++\impl">
       <UniqueIdentifier>{dadc0002-f2ac-451b-a9b8-33b8de10b5fc}</UniqueIdentifier>
     </Filter>
+    <Filter Include="include\grpc++\impl\codegen">
+      <UniqueIdentifier>{ccc364e2-3f28-8bfc-c26e-800dd6f9a9af}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="include\grpc++\impl\codegen\security">
+      <UniqueIdentifier>{87cae06e-f40c-8fb6-73d6-26c7482ed9da}</UniqueIdentifier>
+    </Filter>
     <Filter Include="include\grpc++\security">
       <UniqueIdentifier>{64bf60ff-9192-bb59-dcc8-8a0021e1d016}</UniqueIdentifier>
     </Filter>
@@ -257,6 +365,9 @@
     <Filter Include="src\cpp\client">
       <UniqueIdentifier>{ff72923a-6499-8d2a-e0fb-6d574b85d77e}</UniqueIdentifier>
     </Filter>
+    <Filter Include="src\cpp\codegen">
+      <UniqueIdentifier>{18e9c249-37f0-7f2c-f026-502d48ed8c92}</UniqueIdentifier>
+    </Filter>
     <Filter Include="src\cpp\common">
       <UniqueIdentifier>{ed8e4daa-825f-fbe5-2a45-846ad9165d3d}</UniqueIdentifier>
     </Filter>
diff --git a/vsprojects/vcxproj/grpc/grpc.vcxproj b/vsprojects/vcxproj/grpc/grpc.vcxproj
index 438667a..7697532 100644
--- a/vsprojects/vcxproj/grpc/grpc.vcxproj
+++ b/vsprojects/vcxproj/grpc/grpc.vcxproj
@@ -268,6 +268,12 @@
 
   <ItemGroup>
     <ClInclude Include="$(SolutionDir)\..\include\grpc\grpc_security.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\byte_buffer.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\compression_types.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\connectivity_state.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\grpc_types.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\propagation_bits.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\status.h" />
     <ClInclude Include="$(SolutionDir)\..\include\grpc\byte_buffer.h" />
     <ClInclude Include="$(SolutionDir)\..\include\grpc\byte_buffer_reader.h" />
     <ClInclude Include="$(SolutionDir)\..\include\grpc\compression.h" />
@@ -404,7 +410,6 @@
     <ClInclude Include="$(SolutionDir)\..\src\core\transport\transport.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\transport\transport_impl.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\census\aggregation.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\census\context.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\census\rpc_metric_id.h" />
   </ItemGroup>
   <ItemGroup>
@@ -606,6 +611,8 @@
     </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\json\json_writer.c">
     </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\surface\alarm.c">
+    </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\surface\api_trace.c">
     </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\surface\byte_buffer.c">
@@ -708,7 +715,7 @@
     </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\census\operation.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\census\tag_set.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\census\placeholders.c">
     </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\census\tracing.c">
     </ClCompile>
diff --git a/vsprojects/vcxproj/grpc/grpc.vcxproj.filters b/vsprojects/vcxproj/grpc/grpc.vcxproj.filters
index 90395ca..4660572 100644
--- a/vsprojects/vcxproj/grpc/grpc.vcxproj.filters
+++ b/vsprojects/vcxproj/grpc/grpc.vcxproj.filters
@@ -298,6 +298,9 @@
     <ClCompile Include="$(SolutionDir)\..\src\core\json\json_writer.c">
       <Filter>src\core\json</Filter>
     </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\surface\alarm.c">
+      <Filter>src\core\surface</Filter>
+    </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\surface\api_trace.c">
       <Filter>src\core\surface</Filter>
     </ClCompile>
@@ -451,7 +454,7 @@
     <ClCompile Include="$(SolutionDir)\..\src\core\census\operation.c">
       <Filter>src\core\census</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\census\tag_set.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\census\placeholders.c">
       <Filter>src\core\census</Filter>
     </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\census\tracing.c">
@@ -462,6 +465,24 @@
     <ClInclude Include="$(SolutionDir)\..\include\grpc\grpc_security.h">
       <Filter>include\grpc</Filter>
     </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\byte_buffer.h">
+      <Filter>include\grpc\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\compression_types.h">
+      <Filter>include\grpc\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\connectivity_state.h">
+      <Filter>include\grpc\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\grpc_types.h">
+      <Filter>include\grpc\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\propagation_bits.h">
+      <Filter>include\grpc\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\status.h">
+      <Filter>include\grpc\impl\codegen</Filter>
+    </ClInclude>
     <ClInclude Include="$(SolutionDir)\..\include\grpc\byte_buffer.h">
       <Filter>include\grpc</Filter>
     </ClInclude>
@@ -866,9 +887,6 @@
     <ClInclude Include="$(SolutionDir)\..\src\core\census\aggregation.h">
       <Filter>src\core\census</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\census\context.h">
-      <Filter>src\core\census</Filter>
-    </ClInclude>
     <ClInclude Include="$(SolutionDir)\..\src\core\census\rpc_metric_id.h">
       <Filter>src\core\census</Filter>
     </ClInclude>
@@ -881,6 +899,12 @@
     <Filter Include="include\grpc">
       <UniqueIdentifier>{880c644d-b84f-cfca-98bd-e145f36232ab}</UniqueIdentifier>
     </Filter>
+    <Filter Include="include\grpc\impl">
+      <UniqueIdentifier>{38832702-fee1-b2bc-75d3-923e748dcde9}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="include\grpc\impl\codegen">
+      <UniqueIdentifier>{def748f5-ed2a-a9bb-40d9-c31d00f0e13b}</UniqueIdentifier>
+    </Filter>
     <Filter Include="src">
       <UniqueIdentifier>{d538af37-07b2-062b-fa2a-d9f882cb2737}</UniqueIdentifier>
     </Filter>
diff --git a/vsprojects/vcxproj/grpc_plugin_support/grpc_plugin_support.vcxproj b/vsprojects/vcxproj/grpc_plugin_support/grpc_plugin_support.vcxproj
index 6a70001..8918390 100644
--- a/vsprojects/vcxproj/grpc_plugin_support/grpc_plugin_support.vcxproj
+++ b/vsprojects/vcxproj/grpc_plugin_support/grpc_plugin_support.vcxproj
@@ -147,6 +147,58 @@
   </ItemDefinitionGroup>
 
   <ItemGroup>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\async_stream.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\async_unary_call.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\call.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\call_hook.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\channel_interface.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\client_context.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\client_unary_call.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\completion_queue.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\completion_queue_tag.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\config.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\config_protobuf.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\grpc_library.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\method_handler_impl.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\proto_utils.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\rpc_method.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\rpc_service_method.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\security\auth_context.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\serialization_traits.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\server_context.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\server_interface.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\service_type.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\status.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\status_code_enum.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\string_ref.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\stub_options.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\sync.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\sync_cxx11.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\sync_no_cxx11.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\sync_stream.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\time.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\byte_buffer.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\compression_types.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\connectivity_state.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\grpc_types.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\propagation_bits.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\status.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\alloc.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\atm.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\atm_gcc_atomic.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\atm_gcc_sync.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\atm_win32.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\log.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\port_platform.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\slice.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\slice_buffer.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\sync.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\sync_generic.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\sync_posix.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\sync_win32.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\time.h" />
+  </ItemGroup>
+  <ItemGroup>
     <ClInclude Include="$(SolutionDir)\..\include\grpc++\support\config.h" />
     <ClInclude Include="$(SolutionDir)\..\include\grpc++\support\config_protobuf.h" />
     <ClInclude Include="$(SolutionDir)\..\src\compiler\config.h" />
@@ -174,6 +226,8 @@
     </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\compiler\ruby_generator.cc">
     </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\cpp\codegen\grpc_library.cc">
+    </ClCompile>
   </ItemGroup>
   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
   <ImportGroup Label="ExtensionTargets">
diff --git a/vsprojects/vcxproj/grpc_plugin_support/grpc_plugin_support.vcxproj.filters b/vsprojects/vcxproj/grpc_plugin_support/grpc_plugin_support.vcxproj.filters
index 133e1e3..de33d98 100644
--- a/vsprojects/vcxproj/grpc_plugin_support/grpc_plugin_support.vcxproj.filters
+++ b/vsprojects/vcxproj/grpc_plugin_support/grpc_plugin_support.vcxproj.filters
@@ -16,6 +16,161 @@
     <ClCompile Include="$(SolutionDir)\..\src\compiler\ruby_generator.cc">
       <Filter>src\compiler</Filter>
     </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\cpp\codegen\grpc_library.cc">
+      <Filter>src\cpp\codegen</Filter>
+    </ClCompile>
+  </ItemGroup>
+  <ItemGroup>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\async_stream.h">
+      <Filter>include\grpc++\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\async_unary_call.h">
+      <Filter>include\grpc++\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\call.h">
+      <Filter>include\grpc++\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\call_hook.h">
+      <Filter>include\grpc++\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\channel_interface.h">
+      <Filter>include\grpc++\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\client_context.h">
+      <Filter>include\grpc++\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\client_unary_call.h">
+      <Filter>include\grpc++\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\completion_queue.h">
+      <Filter>include\grpc++\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\completion_queue_tag.h">
+      <Filter>include\grpc++\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\config.h">
+      <Filter>include\grpc++\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\config_protobuf.h">
+      <Filter>include\grpc++\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\grpc_library.h">
+      <Filter>include\grpc++\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\method_handler_impl.h">
+      <Filter>include\grpc++\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\proto_utils.h">
+      <Filter>include\grpc++\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\rpc_method.h">
+      <Filter>include\grpc++\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\rpc_service_method.h">
+      <Filter>include\grpc++\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\security\auth_context.h">
+      <Filter>include\grpc++\impl\codegen\security</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\serialization_traits.h">
+      <Filter>include\grpc++\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\server_context.h">
+      <Filter>include\grpc++\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\server_interface.h">
+      <Filter>include\grpc++\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\service_type.h">
+      <Filter>include\grpc++\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\status.h">
+      <Filter>include\grpc++\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\status_code_enum.h">
+      <Filter>include\grpc++\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\string_ref.h">
+      <Filter>include\grpc++\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\stub_options.h">
+      <Filter>include\grpc++\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\sync.h">
+      <Filter>include\grpc++\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\sync_cxx11.h">
+      <Filter>include\grpc++\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\sync_no_cxx11.h">
+      <Filter>include\grpc++\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\sync_stream.h">
+      <Filter>include\grpc++\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc++\impl\codegen\time.h">
+      <Filter>include\grpc++\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\byte_buffer.h">
+      <Filter>include\grpc\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\compression_types.h">
+      <Filter>include\grpc\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\connectivity_state.h">
+      <Filter>include\grpc\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\grpc_types.h">
+      <Filter>include\grpc\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\propagation_bits.h">
+      <Filter>include\grpc\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\status.h">
+      <Filter>include\grpc\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\alloc.h">
+      <Filter>include\grpc\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\atm.h">
+      <Filter>include\grpc\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\atm_gcc_atomic.h">
+      <Filter>include\grpc\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\atm_gcc_sync.h">
+      <Filter>include\grpc\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\atm_win32.h">
+      <Filter>include\grpc\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\log.h">
+      <Filter>include\grpc\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\port_platform.h">
+      <Filter>include\grpc\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\slice.h">
+      <Filter>include\grpc\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\slice_buffer.h">
+      <Filter>include\grpc\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\sync.h">
+      <Filter>include\grpc\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\sync_generic.h">
+      <Filter>include\grpc\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\sync_posix.h">
+      <Filter>include\grpc\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\sync_win32.h">
+      <Filter>include\grpc\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\time.h">
+      <Filter>include\grpc\impl\codegen</Filter>
+    </ClInclude>
   </ItemGroup>
   <ItemGroup>
     <ClInclude Include="$(SolutionDir)\..\include\grpc++\support\config.h">
@@ -69,18 +224,42 @@
     <Filter Include="include">
       <UniqueIdentifier>{93ed419d-4540-7fa4-814d-3392745b77ff}</UniqueIdentifier>
     </Filter>
+    <Filter Include="include\grpc">
+      <UniqueIdentifier>{ae5560ea-77fe-ab95-c7a3-4538c66591a8}</UniqueIdentifier>
+    </Filter>
     <Filter Include="include\grpc++">
       <UniqueIdentifier>{893c09ee-e315-e763-9d9d-37522ba2f51c}</UniqueIdentifier>
     </Filter>
+    <Filter Include="include\grpc++\impl">
+      <UniqueIdentifier>{3e8c71a4-8a06-a577-2799-2224a1ad1f1b}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="include\grpc++\impl\codegen">
+      <UniqueIdentifier>{ec2a6e26-915b-ba1b-4f59-f361dc01105c}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="include\grpc++\impl\codegen\security">
+      <UniqueIdentifier>{c1593bf9-5ef8-cb28-e46b-543153918a3f}</UniqueIdentifier>
+    </Filter>
     <Filter Include="include\grpc++\support">
       <UniqueIdentifier>{1c34d005-1ffb-8a31-881a-c6bb431cda69}</UniqueIdentifier>
     </Filter>
+    <Filter Include="include\grpc\impl">
+      <UniqueIdentifier>{3c047248-00c2-4c59-fffd-9e313353e390}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="include\grpc\impl\codegen">
+      <UniqueIdentifier>{749ae941-63f0-c623-8b4b-a3114ec81bb7}</UniqueIdentifier>
+    </Filter>
     <Filter Include="src">
       <UniqueIdentifier>{94c9769a-a6cd-49fd-2b30-e52d2d02ed91}</UniqueIdentifier>
     </Filter>
     <Filter Include="src\compiler">
       <UniqueIdentifier>{0e6b1e6c-7299-59ce-d757-619bcddd5441}</UniqueIdentifier>
     </Filter>
+    <Filter Include="src\cpp">
+      <UniqueIdentifier>{29d80aab-9e9d-0417-6dfa-59dec47c9883}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="src\cpp\codegen">
+      <UniqueIdentifier>{c0d4a389-f341-8385-4534-fe9d8fb09952}</UniqueIdentifier>
+    </Filter>
   </ItemGroup>
 </Project>
 
diff --git a/vsprojects/vcxproj/grpc_test_util/grpc_test_util.vcxproj b/vsprojects/vcxproj/grpc_test_util/grpc_test_util.vcxproj
index 0cedf7d..5735327 100644
--- a/vsprojects/vcxproj/grpc_test_util/grpc_test_util.vcxproj
+++ b/vsprojects/vcxproj/grpc_test_util/grpc_test_util.vcxproj
@@ -184,12 +184,12 @@
     </ClCompile>
   </ItemGroup>
   <ItemGroup>
-    <ProjectReference Include="$(SolutionDir)\..\vsprojects\vcxproj\.\gpr\gpr.vcxproj">
-      <Project>{B23D3D1A-9438-4EDA-BEB6-9A0A03D17792}</Project>
-    </ProjectReference>
     <ProjectReference Include="$(SolutionDir)\..\vsprojects\vcxproj\.\gpr_test_util\gpr_test_util.vcxproj">
       <Project>{EAB0A629-17A9-44DB-B5FF-E91A721FE037}</Project>
     </ProjectReference>
+    <ProjectReference Include="$(SolutionDir)\..\vsprojects\vcxproj\.\gpr\gpr.vcxproj">
+      <Project>{B23D3D1A-9438-4EDA-BEB6-9A0A03D17792}</Project>
+    </ProjectReference>
     <ProjectReference Include="$(SolutionDir)\..\vsprojects\vcxproj\.\grpc\grpc.vcxproj">
       <Project>{29D16885-7228-4C31-81ED-5F9187C7F2A9}</Project>
     </ProjectReference>
diff --git a/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj b/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj
index 014e67f..541000a 100644
--- a/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj
+++ b/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj
@@ -263,6 +263,12 @@
     <ClInclude Include="$(SolutionDir)\..\include\grpc\compression.h" />
     <ClInclude Include="$(SolutionDir)\..\include\grpc\grpc.h" />
     <ClInclude Include="$(SolutionDir)\..\include\grpc\status.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\byte_buffer.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\compression_types.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\connectivity_state.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\grpc_types.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\propagation_bits.h" />
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\status.h" />
     <ClInclude Include="$(SolutionDir)\..\include\grpc\census.h" />
   </ItemGroup>
   <ItemGroup>
@@ -380,7 +386,6 @@
     <ClInclude Include="$(SolutionDir)\..\src\core\transport\transport.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\transport\transport_impl.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\census\aggregation.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\census\context.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\census\rpc_metric_id.h" />
   </ItemGroup>
   <ItemGroup>
@@ -542,6 +547,8 @@
     </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\json\json_writer.c">
     </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\surface\alarm.c">
+    </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\surface\api_trace.c">
     </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\surface\byte_buffer.c">
@@ -644,7 +651,7 @@
     </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\census\operation.c">
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\census\tag_set.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\census\placeholders.c">
     </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\census\tracing.c">
     </ClCompile>
diff --git a/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj.filters b/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj.filters
index 4f8a77d..48814f9 100644
--- a/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj.filters
+++ b/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj.filters
@@ -238,6 +238,9 @@
     <ClCompile Include="$(SolutionDir)\..\src\core\json\json_writer.c">
       <Filter>src\core\json</Filter>
     </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\src\core\surface\alarm.c">
+      <Filter>src\core\surface</Filter>
+    </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\surface\api_trace.c">
       <Filter>src\core\surface</Filter>
     </ClCompile>
@@ -391,7 +394,7 @@
     <ClCompile Include="$(SolutionDir)\..\src\core\census\operation.c">
       <Filter>src\core\census</Filter>
     </ClCompile>
-    <ClCompile Include="$(SolutionDir)\..\src\core\census\tag_set.c">
+    <ClCompile Include="$(SolutionDir)\..\src\core\census\placeholders.c">
       <Filter>src\core\census</Filter>
     </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\src\core\census\tracing.c">
@@ -414,6 +417,24 @@
     <ClInclude Include="$(SolutionDir)\..\include\grpc\status.h">
       <Filter>include\grpc</Filter>
     </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\byte_buffer.h">
+      <Filter>include\grpc\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\compression_types.h">
+      <Filter>include\grpc\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\connectivity_state.h">
+      <Filter>include\grpc\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\grpc_types.h">
+      <Filter>include\grpc\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\propagation_bits.h">
+      <Filter>include\grpc\impl\codegen</Filter>
+    </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\status.h">
+      <Filter>include\grpc\impl\codegen</Filter>
+    </ClInclude>
     <ClInclude Include="$(SolutionDir)\..\include\grpc\census.h">
       <Filter>include\grpc</Filter>
     </ClInclude>
@@ -761,9 +782,6 @@
     <ClInclude Include="$(SolutionDir)\..\src\core\census\aggregation.h">
       <Filter>src\core\census</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\census\context.h">
-      <Filter>src\core\census</Filter>
-    </ClInclude>
     <ClInclude Include="$(SolutionDir)\..\src\core\census\rpc_metric_id.h">
       <Filter>src\core\census</Filter>
     </ClInclude>
@@ -776,6 +794,12 @@
     <Filter Include="include\grpc">
       <UniqueIdentifier>{77b9717b-b8d8-dd5f-14bb-a3e96809a70a}</UniqueIdentifier>
     </Filter>
+    <Filter Include="include\grpc\impl">
+      <UniqueIdentifier>{10cfa248-c60f-376f-e7ae-2a7d7d8e81f5}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="include\grpc\impl\codegen">
+      <UniqueIdentifier>{03cc6735-c734-7017-4000-a435f29d55c3}</UniqueIdentifier>
+    </Filter>
     <Filter Include="src">
       <UniqueIdentifier>{aaf326a1-c884-46ea-875a-cbbd9983e539}</UniqueIdentifier>
     </Filter>
diff --git a/vsprojects/vcxproj/qps/qps.vcxproj b/vsprojects/vcxproj/qps/qps.vcxproj
index 7df2597..8306e2e 100644
--- a/vsprojects/vcxproj/qps/qps.vcxproj
+++ b/vsprojects/vcxproj/qps/qps.vcxproj
@@ -151,6 +151,7 @@
     <ClInclude Include="$(SolutionDir)\..\test\cpp\qps\driver.h" />
     <ClInclude Include="$(SolutionDir)\..\test\cpp\qps\histogram.h" />
     <ClInclude Include="$(SolutionDir)\..\test\cpp\qps\interarrival.h" />
+    <ClInclude Include="$(SolutionDir)\..\test\cpp\qps\limit_cores.h" />
     <ClInclude Include="$(SolutionDir)\..\test\cpp\qps\perf_db_client.h" />
     <ClInclude Include="$(SolutionDir)\..\test\cpp\qps\qps_worker.h" />
     <ClInclude Include="$(SolutionDir)\..\test\cpp\qps\report.h" />
@@ -214,6 +215,8 @@
     </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\test\cpp\qps\driver.cc">
     </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\test\cpp\qps\limit_cores.cc">
+    </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\test\cpp\qps\perf_db_client.cc">
     </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\test\cpp\qps\qps_worker.cc">
diff --git a/vsprojects/vcxproj/qps/qps.vcxproj.filters b/vsprojects/vcxproj/qps/qps.vcxproj.filters
index 14e18e2..650116a 100644
--- a/vsprojects/vcxproj/qps/qps.vcxproj.filters
+++ b/vsprojects/vcxproj/qps/qps.vcxproj.filters
@@ -28,6 +28,9 @@
     <ClCompile Include="$(SolutionDir)\..\test\cpp\qps\driver.cc">
       <Filter>test\cpp\qps</Filter>
     </ClCompile>
+    <ClCompile Include="$(SolutionDir)\..\test\cpp\qps\limit_cores.cc">
+      <Filter>test\cpp\qps</Filter>
+    </ClCompile>
     <ClCompile Include="$(SolutionDir)\..\test\cpp\qps\perf_db_client.cc">
       <Filter>test\cpp\qps</Filter>
     </ClCompile>
@@ -63,6 +66,9 @@
     <ClInclude Include="$(SolutionDir)\..\test\cpp\qps\interarrival.h">
       <Filter>test\cpp\qps</Filter>
     </ClInclude>
+    <ClInclude Include="$(SolutionDir)\..\test\cpp\qps\limit_cores.h">
+      <Filter>test\cpp\qps</Filter>
+    </ClInclude>
     <ClInclude Include="$(SolutionDir)\..\test\cpp\qps\perf_db_client.h">
       <Filter>test\cpp\qps</Filter>
     </ClInclude>
diff --git a/vsprojects/vcxproj/test/tag_set_test/tag_set_test.vcxproj b/vsprojects/vcxproj/test/alarm_cpp_test/alarm_cpp_test.vcxproj
similarity index 93%
copy from vsprojects/vcxproj/test/tag_set_test/tag_set_test.vcxproj
copy to vsprojects/vcxproj/test/alarm_cpp_test/alarm_cpp_test.vcxproj
index 9a468af..10541cb 100644
--- a/vsprojects/vcxproj/test/tag_set_test/tag_set_test.vcxproj
+++ b/vsprojects/vcxproj/test/alarm_cpp_test/alarm_cpp_test.vcxproj
@@ -20,7 +20,7 @@
     </ProjectConfiguration>
   </ItemGroup>
   <PropertyGroup Label="Globals">
-    <ProjectGuid>{430F8F07-6AAD-0150-B35B-DB9E2E21941A}</ProjectGuid>
+    <ProjectGuid>{6E5ADE15-9B8E-A040-0508-9F14F836B51B}</ProjectGuid>
     <IgnoreWarnIntDirInTempDetected>true</IgnoreWarnIntDirInTempDetected>
     <IntDir>$(SolutionDir)IntDir\$(MSBuildProjectName)\</IntDir>
   </PropertyGroup>
@@ -53,21 +53,23 @@
   </ImportGroup>
   <ImportGroup Label="PropertySheets">
     <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+    <Import Project="$(SolutionDir)\..\vsprojects\cpptest.props" />
     <Import Project="$(SolutionDir)\..\vsprojects\global.props" />
     <Import Project="$(SolutionDir)\..\vsprojects\openssl.props" />
+    <Import Project="$(SolutionDir)\..\vsprojects\protobuf.props" />
     <Import Project="$(SolutionDir)\..\vsprojects\winsock.props" />
     <Import Project="$(SolutionDir)\..\vsprojects\zlib.props" />
   </ImportGroup>
   <PropertyGroup Label="UserMacros" />
   <PropertyGroup Condition="'$(Configuration)'=='Debug'">
-    <TargetName>tag_set_test</TargetName>
+    <TargetName>alarm_cpp_test</TargetName>
     <Linkage-grpc_dependencies_zlib>static</Linkage-grpc_dependencies_zlib>
     <Configuration-grpc_dependencies_zlib>Debug</Configuration-grpc_dependencies_zlib>
     <Linkage-grpc_dependencies_openssl>static</Linkage-grpc_dependencies_openssl>
     <Configuration-grpc_dependencies_openssl>Debug</Configuration-grpc_dependencies_openssl>
   </PropertyGroup>
   <PropertyGroup Condition="'$(Configuration)'=='Release'">
-    <TargetName>tag_set_test</TargetName>
+    <TargetName>alarm_cpp_test</TargetName>
     <Linkage-grpc_dependencies_zlib>static</Linkage-grpc_dependencies_zlib>
     <Configuration-grpc_dependencies_zlib>Release</Configuration-grpc_dependencies_zlib>
     <Linkage-grpc_dependencies_openssl>static</Linkage-grpc_dependencies_openssl>
@@ -158,13 +160,19 @@
   </ItemDefinitionGroup>
 
   <ItemGroup>
-    <ClCompile Include="$(SolutionDir)\..\test\core\census\tag_set_test.c">
+    <ClCompile Include="$(SolutionDir)\..\test\cpp\common\alarm_cpp_test.cc">
     </ClCompile>
   </ItemGroup>
   <ItemGroup>
+    <ProjectReference Include="$(SolutionDir)\..\vsprojects\vcxproj\.\grpc++_test_util\grpc++_test_util.vcxproj">
+      <Project>{0BE77741-552A-929B-A497-4EF7ECE17A64}</Project>
+    </ProjectReference>
     <ProjectReference Include="$(SolutionDir)\..\vsprojects\vcxproj\.\grpc_test_util\grpc_test_util.vcxproj">
       <Project>{17BCAFC0-5FDC-4C94-AEB9-95F3E220614B}</Project>
     </ProjectReference>
+    <ProjectReference Include="$(SolutionDir)\..\vsprojects\vcxproj\.\grpc++\grpc++.vcxproj">
+      <Project>{C187A093-A0FE-489D-A40A-6E33DE0F9FEB}</Project>
+    </ProjectReference>
     <ProjectReference Include="$(SolutionDir)\..\vsprojects\vcxproj\.\grpc\grpc.vcxproj">
       <Project>{29D16885-7228-4C31-81ED-5F9187C7F2A9}</Project>
     </ProjectReference>
diff --git a/vsprojects/vcxproj/test/alarm_cpp_test/alarm_cpp_test.vcxproj.filters b/vsprojects/vcxproj/test/alarm_cpp_test/alarm_cpp_test.vcxproj.filters
new file mode 100644
index 0000000..fedcdb2
--- /dev/null
+++ b/vsprojects/vcxproj/test/alarm_cpp_test/alarm_cpp_test.vcxproj.filters
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <ItemGroup>
+    <ClCompile Include="$(SolutionDir)\..\test\cpp\common\alarm_cpp_test.cc">
+      <Filter>test\cpp\common</Filter>
+    </ClCompile>
+  </ItemGroup>
+
+  <ItemGroup>
+    <Filter Include="test">
+      <UniqueIdentifier>{ee2d2282-632f-e0ff-cd3e-cec1507e6831}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="test\cpp">
+      <UniqueIdentifier>{672815bb-fd6d-b5a2-b2b8-ee145fecd451}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="test\cpp\common">
+      <UniqueIdentifier>{6e1a5a97-6bd9-847e-afea-0ca2ac4cc6b7}</UniqueIdentifier>
+    </Filter>
+  </ItemGroup>
+</Project>
+
diff --git a/vsprojects/vcxproj/test/tag_set_test/tag_set_test.vcxproj b/vsprojects/vcxproj/test/alarm_test/alarm_test.vcxproj
similarity index 97%
copy from vsprojects/vcxproj/test/tag_set_test/tag_set_test.vcxproj
copy to vsprojects/vcxproj/test/alarm_test/alarm_test.vcxproj
index 9a468af..5f07a23 100644
--- a/vsprojects/vcxproj/test/tag_set_test/tag_set_test.vcxproj
+++ b/vsprojects/vcxproj/test/alarm_test/alarm_test.vcxproj
@@ -20,7 +20,7 @@
     </ProjectConfiguration>
   </ItemGroup>
   <PropertyGroup Label="Globals">
-    <ProjectGuid>{430F8F07-6AAD-0150-B35B-DB9E2E21941A}</ProjectGuid>
+    <ProjectGuid>{AFD362D7-0E2A-E700-1F27-9D90F76166DF}</ProjectGuid>
     <IgnoreWarnIntDirInTempDetected>true</IgnoreWarnIntDirInTempDetected>
     <IntDir>$(SolutionDir)IntDir\$(MSBuildProjectName)\</IntDir>
   </PropertyGroup>
@@ -60,14 +60,14 @@
   </ImportGroup>
   <PropertyGroup Label="UserMacros" />
   <PropertyGroup Condition="'$(Configuration)'=='Debug'">
-    <TargetName>tag_set_test</TargetName>
+    <TargetName>alarm_test</TargetName>
     <Linkage-grpc_dependencies_zlib>static</Linkage-grpc_dependencies_zlib>
     <Configuration-grpc_dependencies_zlib>Debug</Configuration-grpc_dependencies_zlib>
     <Linkage-grpc_dependencies_openssl>static</Linkage-grpc_dependencies_openssl>
     <Configuration-grpc_dependencies_openssl>Debug</Configuration-grpc_dependencies_openssl>
   </PropertyGroup>
   <PropertyGroup Condition="'$(Configuration)'=='Release'">
-    <TargetName>tag_set_test</TargetName>
+    <TargetName>alarm_test</TargetName>
     <Linkage-grpc_dependencies_zlib>static</Linkage-grpc_dependencies_zlib>
     <Configuration-grpc_dependencies_zlib>Release</Configuration-grpc_dependencies_zlib>
     <Linkage-grpc_dependencies_openssl>static</Linkage-grpc_dependencies_openssl>
@@ -158,7 +158,7 @@
   </ItemDefinitionGroup>
 
   <ItemGroup>
-    <ClCompile Include="$(SolutionDir)\..\test\core\census\tag_set_test.c">
+    <ClCompile Include="$(SolutionDir)\..\test\core\surface\alarm_test.c">
     </ClCompile>
   </ItemGroup>
   <ItemGroup>
diff --git a/vsprojects/vcxproj/test/alarm_test/alarm_test.vcxproj.filters b/vsprojects/vcxproj/test/alarm_test/alarm_test.vcxproj.filters
new file mode 100644
index 0000000..c8ac417
--- /dev/null
+++ b/vsprojects/vcxproj/test/alarm_test/alarm_test.vcxproj.filters
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <ItemGroup>
+    <ClCompile Include="$(SolutionDir)\..\test\core\surface\alarm_test.c">
+      <Filter>test\core\surface</Filter>
+    </ClCompile>
+  </ItemGroup>
+
+  <ItemGroup>
+    <Filter Include="test">
+      <UniqueIdentifier>{ce8dc749-635b-4486-70d6-6bdf52297d09}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="test\core">
+      <UniqueIdentifier>{c214d1e9-ebce-1040-28fa-e286dbb702d9}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="test\core\surface">
+      <UniqueIdentifier>{b260bb85-bedf-a6bf-c32e-3cd4b9d22bc8}</UniqueIdentifier>
+    </Filter>
+  </ItemGroup>
+</Project>
+
diff --git a/vsprojects/vcxproj/test/bin_encoder_test/bin_encoder_test.vcxproj b/vsprojects/vcxproj/test/bin_encoder_test/bin_encoder_test.vcxproj
index 82998be..7666604 100644
--- a/vsprojects/vcxproj/test/bin_encoder_test/bin_encoder_test.vcxproj
+++ b/vsprojects/vcxproj/test/bin_encoder_test/bin_encoder_test.vcxproj
@@ -168,12 +168,6 @@
     <ProjectReference Include="$(SolutionDir)\..\vsprojects\vcxproj\.\grpc\grpc.vcxproj">
       <Project>{29D16885-7228-4C31-81ED-5F9187C7F2A9}</Project>
     </ProjectReference>
-    <ProjectReference Include="$(SolutionDir)\..\vsprojects\vcxproj\.\gpr_test_util\gpr_test_util.vcxproj">
-      <Project>{EAB0A629-17A9-44DB-B5FF-E91A721FE037}</Project>
-    </ProjectReference>
-    <ProjectReference Include="$(SolutionDir)\..\vsprojects\vcxproj\.\gpr\gpr.vcxproj">
-      <Project>{B23D3D1A-9438-4EDA-BEB6-9A0A03D17792}</Project>
-    </ProjectReference>
   </ItemGroup>
   <ItemGroup>
     <None Include="packages.config" />
diff --git a/vsprojects/vcxproj/test/tag_set_test/tag_set_test.vcxproj b/vsprojects/vcxproj/test/census_context_test/census_context_test.vcxproj
similarity index 97%
rename from vsprojects/vcxproj/test/tag_set_test/tag_set_test.vcxproj
rename to vsprojects/vcxproj/test/census_context_test/census_context_test.vcxproj
index 9a468af..b4741e5 100644
--- a/vsprojects/vcxproj/test/tag_set_test/tag_set_test.vcxproj
+++ b/vsprojects/vcxproj/test/census_context_test/census_context_test.vcxproj
@@ -20,7 +20,7 @@
     </ProjectConfiguration>
   </ItemGroup>
   <PropertyGroup Label="Globals">
-    <ProjectGuid>{430F8F07-6AAD-0150-B35B-DB9E2E21941A}</ProjectGuid>
+    <ProjectGuid>{5C1CFC2D-AF3C-D7CB-BA74-D267E91CBC73}</ProjectGuid>
     <IgnoreWarnIntDirInTempDetected>true</IgnoreWarnIntDirInTempDetected>
     <IntDir>$(SolutionDir)IntDir\$(MSBuildProjectName)\</IntDir>
   </PropertyGroup>
@@ -60,14 +60,14 @@
   </ImportGroup>
   <PropertyGroup Label="UserMacros" />
   <PropertyGroup Condition="'$(Configuration)'=='Debug'">
-    <TargetName>tag_set_test</TargetName>
+    <TargetName>census_context_test</TargetName>
     <Linkage-grpc_dependencies_zlib>static</Linkage-grpc_dependencies_zlib>
     <Configuration-grpc_dependencies_zlib>Debug</Configuration-grpc_dependencies_zlib>
     <Linkage-grpc_dependencies_openssl>static</Linkage-grpc_dependencies_openssl>
     <Configuration-grpc_dependencies_openssl>Debug</Configuration-grpc_dependencies_openssl>
   </PropertyGroup>
   <PropertyGroup Condition="'$(Configuration)'=='Release'">
-    <TargetName>tag_set_test</TargetName>
+    <TargetName>census_context_test</TargetName>
     <Linkage-grpc_dependencies_zlib>static</Linkage-grpc_dependencies_zlib>
     <Configuration-grpc_dependencies_zlib>Release</Configuration-grpc_dependencies_zlib>
     <Linkage-grpc_dependencies_openssl>static</Linkage-grpc_dependencies_openssl>
@@ -158,7 +158,7 @@
   </ItemDefinitionGroup>
 
   <ItemGroup>
-    <ClCompile Include="$(SolutionDir)\..\test\core\census\tag_set_test.c">
+    <ClCompile Include="$(SolutionDir)\..\test\core\census\context_test.c">
     </ClCompile>
   </ItemGroup>
   <ItemGroup>
diff --git a/vsprojects/vcxproj/test/tag_set_test/tag_set_test.vcxproj.filters b/vsprojects/vcxproj/test/census_context_test/census_context_test.vcxproj.filters
similarity index 62%
rename from vsprojects/vcxproj/test/tag_set_test/tag_set_test.vcxproj.filters
rename to vsprojects/vcxproj/test/census_context_test/census_context_test.vcxproj.filters
index 6b31532..53a7a66 100644
--- a/vsprojects/vcxproj/test/tag_set_test/tag_set_test.vcxproj.filters
+++ b/vsprojects/vcxproj/test/census_context_test/census_context_test.vcxproj.filters
@@ -1,20 +1,20 @@
 <?xml version="1.0" encoding="utf-8"?>
 <Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
   <ItemGroup>
-    <ClCompile Include="$(SolutionDir)\..\test\core\census\tag_set_test.c">
+    <ClCompile Include="$(SolutionDir)\..\test\core\census\context_test.c">
       <Filter>test\core\census</Filter>
     </ClCompile>
   </ItemGroup>
 
   <ItemGroup>
     <Filter Include="test">
-      <UniqueIdentifier>{500aa440-5924-8047-996a-4c5096d1ef96}</UniqueIdentifier>
+      <UniqueIdentifier>{bc15bb31-7dbe-17f2-fb1c-4bc140ce1707}</UniqueIdentifier>
     </Filter>
     <Filter Include="test\core">
-      <UniqueIdentifier>{a3bf80f0-5b13-f623-277b-05f0231dd933}</UniqueIdentifier>
+      <UniqueIdentifier>{806f9b58-6a48-ae09-3cc6-bb36e3126f27}</UniqueIdentifier>
     </Filter>
     <Filter Include="test\core\census">
-      <UniqueIdentifier>{b6ed1b86-7795-4da9-a169-9eccf836852c}</UniqueIdentifier>
+      <UniqueIdentifier>{85e37a47-e797-dcd1-b1e0-df553a454d8f}</UniqueIdentifier>
     </Filter>
   </ItemGroup>
 </Project>
diff --git a/vsprojects/vcxproj/test/tag_set_test/tag_set_test.vcxproj b/vsprojects/vcxproj/test/hybrid_end2end_test/hybrid_end2end_test.vcxproj
similarity index 93%
copy from vsprojects/vcxproj/test/tag_set_test/tag_set_test.vcxproj
copy to vsprojects/vcxproj/test/hybrid_end2end_test/hybrid_end2end_test.vcxproj
index 9a468af..7bdc6c6 100644
--- a/vsprojects/vcxproj/test/tag_set_test/tag_set_test.vcxproj
+++ b/vsprojects/vcxproj/test/hybrid_end2end_test/hybrid_end2end_test.vcxproj
@@ -20,7 +20,7 @@
     </ProjectConfiguration>
   </ItemGroup>
   <PropertyGroup Label="Globals">
-    <ProjectGuid>{430F8F07-6AAD-0150-B35B-DB9E2E21941A}</ProjectGuid>
+    <ProjectGuid>{2DBA9954-A78A-6F68-5669-0370C6D6080C}</ProjectGuid>
     <IgnoreWarnIntDirInTempDetected>true</IgnoreWarnIntDirInTempDetected>
     <IntDir>$(SolutionDir)IntDir\$(MSBuildProjectName)\</IntDir>
   </PropertyGroup>
@@ -53,21 +53,23 @@
   </ImportGroup>
   <ImportGroup Label="PropertySheets">
     <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+    <Import Project="$(SolutionDir)\..\vsprojects\cpptest.props" />
     <Import Project="$(SolutionDir)\..\vsprojects\global.props" />
     <Import Project="$(SolutionDir)\..\vsprojects\openssl.props" />
+    <Import Project="$(SolutionDir)\..\vsprojects\protobuf.props" />
     <Import Project="$(SolutionDir)\..\vsprojects\winsock.props" />
     <Import Project="$(SolutionDir)\..\vsprojects\zlib.props" />
   </ImportGroup>
   <PropertyGroup Label="UserMacros" />
   <PropertyGroup Condition="'$(Configuration)'=='Debug'">
-    <TargetName>tag_set_test</TargetName>
+    <TargetName>hybrid_end2end_test</TargetName>
     <Linkage-grpc_dependencies_zlib>static</Linkage-grpc_dependencies_zlib>
     <Configuration-grpc_dependencies_zlib>Debug</Configuration-grpc_dependencies_zlib>
     <Linkage-grpc_dependencies_openssl>static</Linkage-grpc_dependencies_openssl>
     <Configuration-grpc_dependencies_openssl>Debug</Configuration-grpc_dependencies_openssl>
   </PropertyGroup>
   <PropertyGroup Condition="'$(Configuration)'=='Release'">
-    <TargetName>tag_set_test</TargetName>
+    <TargetName>hybrid_end2end_test</TargetName>
     <Linkage-grpc_dependencies_zlib>static</Linkage-grpc_dependencies_zlib>
     <Configuration-grpc_dependencies_zlib>Release</Configuration-grpc_dependencies_zlib>
     <Linkage-grpc_dependencies_openssl>static</Linkage-grpc_dependencies_openssl>
@@ -158,13 +160,19 @@
   </ItemDefinitionGroup>
 
   <ItemGroup>
-    <ClCompile Include="$(SolutionDir)\..\test\core\census\tag_set_test.c">
+    <ClCompile Include="$(SolutionDir)\..\test\cpp\end2end\hybrid_end2end_test.cc">
     </ClCompile>
   </ItemGroup>
   <ItemGroup>
+    <ProjectReference Include="$(SolutionDir)\..\vsprojects\vcxproj\.\grpc++_test_util\grpc++_test_util.vcxproj">
+      <Project>{0BE77741-552A-929B-A497-4EF7ECE17A64}</Project>
+    </ProjectReference>
     <ProjectReference Include="$(SolutionDir)\..\vsprojects\vcxproj\.\grpc_test_util\grpc_test_util.vcxproj">
       <Project>{17BCAFC0-5FDC-4C94-AEB9-95F3E220614B}</Project>
     </ProjectReference>
+    <ProjectReference Include="$(SolutionDir)\..\vsprojects\vcxproj\.\grpc++\grpc++.vcxproj">
+      <Project>{C187A093-A0FE-489D-A40A-6E33DE0F9FEB}</Project>
+    </ProjectReference>
     <ProjectReference Include="$(SolutionDir)\..\vsprojects\vcxproj\.\grpc\grpc.vcxproj">
       <Project>{29D16885-7228-4C31-81ED-5F9187C7F2A9}</Project>
     </ProjectReference>
diff --git a/vsprojects/vcxproj/test/hybrid_end2end_test/hybrid_end2end_test.vcxproj.filters b/vsprojects/vcxproj/test/hybrid_end2end_test/hybrid_end2end_test.vcxproj.filters
new file mode 100644
index 0000000..ebb9753
--- /dev/null
+++ b/vsprojects/vcxproj/test/hybrid_end2end_test/hybrid_end2end_test.vcxproj.filters
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <ItemGroup>
+    <ClCompile Include="$(SolutionDir)\..\test\cpp\end2end\hybrid_end2end_test.cc">
+      <Filter>test\cpp\end2end</Filter>
+    </ClCompile>
+  </ItemGroup>
+
+  <ItemGroup>
+    <Filter Include="test">
+      <UniqueIdentifier>{034a7201-59db-54c2-0af5-fd686ce948b6}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="test\cpp">
+      <UniqueIdentifier>{2bb7ef60-02e9-bb7c-6a37-4d8e2d8870ec}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="test\cpp\end2end">
+      <UniqueIdentifier>{d1b13ade-4b26-87da-a8a8-4c9766121e60}</UniqueIdentifier>
+    </Filter>
+  </ItemGroup>
+</Project>
+