Merge pull request #2371 from yang-g/security_context2

remove dead file
diff --git a/.gitignore b/.gitignore
index a6b34fd..89bd100 100644
--- a/.gitignore
+++ b/.gitignore
@@ -31,3 +31,5 @@
 # vim temp files
 .*.swp
 
+# Makefile's cache
+cache.mk
diff --git a/BUILD b/BUILD
index 13a8784..8366fa1 100644
--- a/BUILD
+++ b/BUILD
@@ -47,6 +47,7 @@
     "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",
@@ -73,6 +74,7 @@
     "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",
@@ -348,6 +350,7 @@
     "src/core/surface/server_chttp2.c",
     "src/core/surface/server_create.c",
     "src/core/surface/surface_trace.c",
+    "src/core/surface/version.c",
     "src/core/transport/chttp2/alpn.c",
     "src/core/transport/chttp2/bin_encoder.c",
     "src/core/transport/chttp2/frame_data.c",
@@ -578,6 +581,7 @@
     "src/core/surface/server_chttp2.c",
     "src/core/surface/server_create.c",
     "src/core/surface/surface_trace.c",
+    "src/core/surface/version.c",
     "src/core/transport/chttp2/alpn.c",
     "src/core/transport/chttp2/bin_encoder.c",
     "src/core/transport/chttp2/frame_data.c",
@@ -881,6 +885,7 @@
     "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",
@@ -928,6 +933,7 @@
     "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",
@@ -1049,6 +1055,7 @@
     "src/core/surface/server_chttp2.c",
     "src/core/surface/server_create.c",
     "src/core/surface/surface_trace.c",
+    "src/core/surface/version.c",
     "src/core/transport/chttp2/alpn.c",
     "src/core/transport/chttp2/bin_encoder.c",
     "src/core/transport/chttp2/frame_data.c",
diff --git a/Makefile b/Makefile
index 0817132..695f000 100644
--- a/Makefile
+++ b/Makefile
@@ -332,7 +332,15 @@
 # These are automatically computed variables.
 # There shouldn't be any need to change anything from now on.
 
-HAS_PKG_CONFIG = $(shell command -v $(PKG_CONFIG) >/dev/null 2>&1 && echo true || echo false)
+-include cache.mk
+
+CACHE_MK =
+
+HAS_PKG_CONFIG ?= $(shell command -v $(PKG_CONFIG) >/dev/null 2>&1 && echo true || echo false)
+
+ifeq ($(HAS_PKG_CONFIG), true)
+CACHE_MK += HAS_PKG_CONFIG = true\n
+endif
 
 PC_TEMPLATE = prefix=$(prefix)\nexec_prefix=\$${prefix}\nincludedir=\$${prefix}/include\nlibdir=\$${exec_prefix}/lib\n\nName: $(PC_NAME)\nDescription: $(PC_DESCRIPTION)\nVersion: $(VERSION)\nCflags: -I\$${includedir} $(PC_CFLAGS)\nRequires.private: $(PC_REQUIRES_PRIVATE)\nLibs: -L\$${libdir} $(PC_LIB)\nLibs.private: $(PC_LIBS_PRIVATE)
 
@@ -405,23 +413,34 @@
 SYSTEMTAP_HEADERS_CHECK_CMD = $(CC) $(CFLAGS) $(CPPFLAGS) -o $(TMPOUT) test/build/systemtap.c $(LDFLAGS)
 
 ifndef REQUIRE_CUSTOM_LIBRARIES_$(CONFIG)
-HAS_SYSTEM_PERFTOOLS = $(shell $(PERFTOOLS_CHECK_CMD) 2> /dev/null && echo true || echo false)
+HAS_SYSTEM_PERFTOOLS ?= $(shell $(PERFTOOLS_CHECK_CMD) 2> /dev/null && echo true || echo false)
 ifeq ($(HAS_SYSTEM_PERFTOOLS),true)
 DEFINES += GRPC_HAVE_PERFTOOLS
 LIBS += profiler
+CACHE_MK += HAS_SYSTEM_PERFTOOLS = true\n
 endif
 endif
 
 HAS_SYSTEM_PROTOBUF_VERIFY = $(shell $(PROTOBUF_CHECK_CMD) 2> /dev/null && echo true || echo false)
 ifndef REQUIRE_CUSTOM_LIBRARIES_$(CONFIG)
-HAS_SYSTEM_OPENSSL_ALPN = $(shell $(OPENSSL_ALPN_CHECK_CMD) 2> /dev/null && echo true || echo false)
+HAS_SYSTEM_OPENSSL_ALPN ?= $(shell $(OPENSSL_ALPN_CHECK_CMD) 2> /dev/null && echo true || echo false)
 ifeq ($(HAS_SYSTEM_OPENSSL_ALPN),true)
 HAS_SYSTEM_OPENSSL_NPN = true
+CACHE_MK += HAS_SYSTEM_OPENSSL_ALPN = true\n
 else
-HAS_SYSTEM_OPENSSL_NPN = $(shell $(OPENSSL_NPN_CHECK_CMD) 2> /dev/null && echo true || echo false)
+HAS_SYSTEM_OPENSSL_NPN ?= $(shell $(OPENSSL_NPN_CHECK_CMD) 2> /dev/null && echo true || echo false)
 endif
-HAS_SYSTEM_ZLIB = $(shell $(ZLIB_CHECK_CMD) 2> /dev/null && echo true || echo false)
-HAS_SYSTEM_PROTOBUF = $(HAS_SYSTEM_PROTOBUF_VERIFY)
+ifeq ($(HAS_SYSTEM_OPENSSL_NPN),true)
+CACHE_MK += HAS_SYSTEM_OPENSSL_NPN = true\n
+endif
+HAS_SYSTEM_ZLIB ?= $(shell $(ZLIB_CHECK_CMD) 2> /dev/null && echo true || echo false)
+ifeq ($(HAS_SYSTEM_ZLIB),true)
+CACHE_MK += HAS_SYSTEM_ZLIB = true\n
+endif
+HAS_SYSTEM_PROTOBUF ?= $(HAS_SYSTEM_PROTOBUF_VERIFY)
+ifeq ($(HAS_SYSTEM_PROTOBUF),true)
+CACHE_MK += HAS_SYSTEM_PROTOBUF = true\n
+endif
 else
 # override system libraries if the config requires a custom compiled library
 HAS_SYSTEM_OPENSSL_ALPN = false
@@ -430,9 +449,13 @@
 HAS_SYSTEM_PROTOBUF = false
 endif
 
-HAS_PROTOC = $(shell $(PROTOC_CHECK_CMD) 2> /dev/null && echo true || echo false)
+HAS_PROTOC ?= $(shell $(PROTOC_CHECK_CMD) 2> /dev/null && echo true || echo false)
 ifeq ($(HAS_PROTOC),true)
-HAS_VALID_PROTOC = $(shell $(PROTOC_CHECK_VERSION_CMD) 2> /dev/null && echo true || echo false)
+CACHE_MK += HAS_PROTOC = true\n
+HAS_VALID_PROTOC ?= $(shell $(PROTOC_CHECK_VERSION_CMD) 2> /dev/null && echo true || echo false)
+ifeq ($(HAS_VALID_PROTOC),true)
+CACHE_MK += HAS_VALID_PROTOC = true\n
+endif
 else
 HAS_VALID_PROTOC = false
 endif
@@ -440,6 +463,7 @@
 # Check for Systemtap (https://sourceware.org/systemtap/), first by making sure <sys/sdt.h> is present
 # in the system and secondly by checking for the "dtrace" binary (on Linux, this is part of the Systemtap
 # distribution. It's part of the base system on BSD/Solaris machines).
+ifndef HAS_SYSTEMTAP
 HAS_SYSTEMTAP_HEADERS = $(shell $(SYSTEMTAP_HEADERS_CHECK_CMD) 2> /dev/null && echo true || echo false)
 HAS_DTRACE = $(shell $(DTRACE_CHECK_CMD) 2> /dev/null && echo true || echo false)
 HAS_SYSTEMTAP = false
@@ -448,6 +472,11 @@
 HAS_SYSTEMTAP = true
 endif
 endif
+endif
+
+ifeq ($(HAS_SYSTEMTAP),true)
+CACHE_MK += HAS_SYSTEMTAP = true\n
+endif
 
 # Note that for testing purposes, one can do:
 #   make HAS_EMBEDDED_OPENSSL_ALPN=false
@@ -761,6 +790,7 @@
 gpr_log_test: $(BINDIR)/$(CONFIG)/gpr_log_test
 gpr_slice_buffer_test: $(BINDIR)/$(CONFIG)/gpr_slice_buffer_test
 gpr_slice_test: $(BINDIR)/$(CONFIG)/gpr_slice_test
+gpr_stack_lockfree_test: $(BINDIR)/$(CONFIG)/gpr_stack_lockfree_test
 gpr_string_test: $(BINDIR)/$(CONFIG)/gpr_string_test
 gpr_sync_test: $(BINDIR)/$(CONFIG)/gpr_sync_test
 gpr_thd_test: $(BINDIR)/$(CONFIG)/gpr_thd_test
@@ -838,8 +868,8 @@
 pubsub_subscriber_test: $(BINDIR)/$(CONFIG)/pubsub_subscriber_test
 qps_driver: $(BINDIR)/$(CONFIG)/qps_driver
 qps_interarrival_test: $(BINDIR)/$(CONFIG)/qps_interarrival_test
+qps_openloop_test: $(BINDIR)/$(CONFIG)/qps_openloop_test
 qps_test: $(BINDIR)/$(CONFIG)/qps_test
-qps_test_openloop: $(BINDIR)/$(CONFIG)/qps_test_openloop
 qps_worker: $(BINDIR)/$(CONFIG)/qps_worker
 secure_auth_context_test: $(BINDIR)/$(CONFIG)/secure_auth_context_test
 server_crash_test: $(BINDIR)/$(CONFIG)/server_crash_test
@@ -1391,15 +1421,15 @@
 
 static: static_c static_cxx
 
-static_c: pc_c pc_c_unsecure  $(LIBDIR)/$(CONFIG)/libgpr.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgrpc_unsecure.a
+static_c: pc_c pc_c_unsecure cache.mk  $(LIBDIR)/$(CONFIG)/libgpr.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgrpc_unsecure.a
 
-static_cxx: pc_cxx pc_cxx_unsecure pc_gpr $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc++_unsecure.a
+static_cxx: pc_cxx pc_cxx_unsecure pc_gpr 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 $(LIBDIR)/$(CONFIG)/libgpr.$(SHARED_EXT) $(LIBDIR)/$(CONFIG)/libgrpc.$(SHARED_EXT) $(LIBDIR)/$(CONFIG)/libgrpc_unsecure.$(SHARED_EXT)
+shared_c: pc_c pc_c_unsecure pc_gpr  cache.mk $(LIBDIR)/$(CONFIG)/libgpr.$(SHARED_EXT) $(LIBDIR)/$(CONFIG)/libgrpc.$(SHARED_EXT) $(LIBDIR)/$(CONFIG)/libgrpc_unsecure.$(SHARED_EXT)
 
-shared_cxx: pc_cxx pc_cxx_unsecure  $(LIBDIR)/$(CONFIG)/libgrpc++.$(SHARED_EXT) $(LIBDIR)/$(CONFIG)/libgrpc++_unsecure.$(SHARED_EXT)
+shared_cxx: pc_cxx pc_cxx_unsecure cache.mk $(LIBDIR)/$(CONFIG)/libgrpc++.$(SHARED_EXT) $(LIBDIR)/$(CONFIG)/libgrpc++_unsecure.$(SHARED_EXT)
 
 shared_csharp: shared_c  $(LIBDIR)/$(CONFIG)/libgrpc_csharp_ext.$(SHARED_EXT)
 grpc_csharp_ext: shared_csharp
@@ -1423,9 +1453,9 @@
 
 buildtests: buildtests_c buildtests_cxx
 
-buildtests_c: privatelibs_c $(BINDIR)/$(CONFIG)/alarm_heap_test $(BINDIR)/$(CONFIG)/alarm_list_test $(BINDIR)/$(CONFIG)/alarm_test $(BINDIR)/$(CONFIG)/alpn_test $(BINDIR)/$(CONFIG)/bin_encoder_test $(BINDIR)/$(CONFIG)/chttp2_status_conversion_test $(BINDIR)/$(CONFIG)/chttp2_stream_encoder_test $(BINDIR)/$(CONFIG)/chttp2_stream_map_test $(BINDIR)/$(CONFIG)/dualstack_socket_test $(BINDIR)/$(CONFIG)/fd_conservation_posix_test $(BINDIR)/$(CONFIG)/fd_posix_test $(BINDIR)/$(CONFIG)/fling_client $(BINDIR)/$(CONFIG)/fling_server $(BINDIR)/$(CONFIG)/fling_stream_test $(BINDIR)/$(CONFIG)/fling_test $(BINDIR)/$(CONFIG)/gpr_cancellable_test $(BINDIR)/$(CONFIG)/gpr_cmdline_test $(BINDIR)/$(CONFIG)/gpr_env_test $(BINDIR)/$(CONFIG)/gpr_file_test $(BINDIR)/$(CONFIG)/gpr_histogram_test $(BINDIR)/$(CONFIG)/gpr_host_port_test $(BINDIR)/$(CONFIG)/gpr_log_test $(BINDIR)/$(CONFIG)/gpr_slice_buffer_test $(BINDIR)/$(CONFIG)/gpr_slice_test $(BINDIR)/$(CONFIG)/gpr_string_test $(BINDIR)/$(CONFIG)/gpr_sync_test $(BINDIR)/$(CONFIG)/gpr_thd_test $(BINDIR)/$(CONFIG)/gpr_time_test $(BINDIR)/$(CONFIG)/gpr_tls_test $(BINDIR)/$(CONFIG)/gpr_useful_test $(BINDIR)/$(CONFIG)/grpc_auth_context_test $(BINDIR)/$(CONFIG)/grpc_base64_test $(BINDIR)/$(CONFIG)/grpc_byte_buffer_reader_test $(BINDIR)/$(CONFIG)/grpc_channel_stack_test $(BINDIR)/$(CONFIG)/grpc_completion_queue_test $(BINDIR)/$(CONFIG)/grpc_credentials_test $(BINDIR)/$(CONFIG)/grpc_json_token_test $(BINDIR)/$(CONFIG)/grpc_jwt_verifier_test $(BINDIR)/$(CONFIG)/grpc_security_connector_test $(BINDIR)/$(CONFIG)/grpc_stream_op_test $(BINDIR)/$(CONFIG)/hpack_parser_test $(BINDIR)/$(CONFIG)/hpack_table_test $(BINDIR)/$(CONFIG)/httpcli_format_request_test $(BINDIR)/$(CONFIG)/httpcli_parser_test $(BINDIR)/$(CONFIG)/httpcli_test $(BINDIR)/$(CONFIG)/json_rewrite $(BINDIR)/$(CONFIG)/json_rewrite_test $(BINDIR)/$(CONFIG)/json_test $(BINDIR)/$(CONFIG)/lame_client_test $(BINDIR)/$(CONFIG)/message_compress_test $(BINDIR)/$(CONFIG)/multi_init_test $(BINDIR)/$(CONFIG)/multiple_server_queues_test $(BINDIR)/$(CONFIG)/murmur_hash_test $(BINDIR)/$(CONFIG)/no_server_test $(BINDIR)/$(CONFIG)/poll_kick_posix_test $(BINDIR)/$(CONFIG)/resolve_address_test $(BINDIR)/$(CONFIG)/secure_endpoint_test $(BINDIR)/$(CONFIG)/sockaddr_utils_test $(BINDIR)/$(CONFIG)/tcp_client_posix_test $(BINDIR)/$(CONFIG)/tcp_posix_test $(BINDIR)/$(CONFIG)/tcp_server_posix_test $(BINDIR)/$(CONFIG)/time_averaged_stats_test $(BINDIR)/$(CONFIG)/time_test $(BINDIR)/$(CONFIG)/timeout_encoding_test $(BINDIR)/$(CONFIG)/timers_test $(BINDIR)/$(CONFIG)/transport_metadata_test $(BINDIR)/$(CONFIG)/transport_security_test $(BINDIR)/$(CONFIG)/uri_parser_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_bad_hostname_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_cancel_after_accept_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_cancel_after_accept_and_writes_closed_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_cancel_after_invoke_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_cancel_before_invoke_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_cancel_in_a_vacuum_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_census_simple_request_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_disappearing_server_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_early_server_shutdown_finishes_inflight_calls_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_early_server_shutdown_finishes_tags_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_empty_batch_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_graceful_server_shutdown_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_invoke_large_request_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_max_concurrent_streams_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_max_message_length_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_no_op_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_ping_pong_streaming_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_registered_call_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_request_response_with_binary_metadata_and_payload_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_request_response_with_metadata_and_payload_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_request_response_with_payload_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_request_response_with_payload_and_call_creds_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_request_response_with_trailing_metadata_and_payload_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_request_with_flags_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_request_with_large_metadata_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_request_with_payload_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_server_finishes_request_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_simple_delayed_request_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_simple_request_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_simple_request_with_high_initial_sequence_number_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_bad_hostname_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_cancel_after_accept_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_cancel_after_accept_and_writes_closed_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_cancel_after_invoke_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_cancel_before_invoke_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_cancel_in_a_vacuum_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_census_simple_request_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_disappearing_server_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_early_server_shutdown_finishes_inflight_calls_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_early_server_shutdown_finishes_tags_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_empty_batch_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_graceful_server_shutdown_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_invoke_large_request_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_max_concurrent_streams_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_max_message_length_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_no_op_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_ping_pong_streaming_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_registered_call_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_request_response_with_binary_metadata_and_payload_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_request_response_with_metadata_and_payload_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_request_response_with_payload_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_request_response_with_payload_and_call_creds_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_request_response_with_trailing_metadata_and_payload_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_request_with_flags_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_request_with_large_metadata_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_request_with_payload_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_server_finishes_request_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_simple_delayed_request_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_simple_request_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_simple_request_with_high_initial_sequence_number_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_bad_hostname_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_cancel_after_accept_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_cancel_after_accept_and_writes_closed_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_cancel_after_invoke_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_cancel_before_invoke_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_cancel_in_a_vacuum_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_census_simple_request_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_disappearing_server_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_early_server_shutdown_finishes_inflight_calls_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_early_server_shutdown_finishes_tags_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_empty_batch_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_graceful_server_shutdown_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_invoke_large_request_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_max_concurrent_streams_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_max_message_length_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_no_op_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_ping_pong_streaming_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_registered_call_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_request_response_with_binary_metadata_and_payload_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_request_response_with_metadata_and_payload_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_request_response_with_payload_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_request_response_with_payload_and_call_creds_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_request_response_with_trailing_metadata_and_payload_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_request_with_flags_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_request_with_large_metadata_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_request_with_payload_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_server_finishes_request_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_simple_delayed_request_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_simple_request_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_simple_request_with_high_initial_sequence_number_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_bad_hostname_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_cancel_after_accept_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_cancel_after_accept_and_writes_closed_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_cancel_after_invoke_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_cancel_before_invoke_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_cancel_in_a_vacuum_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_census_simple_request_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_disappearing_server_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_early_server_shutdown_finishes_inflight_calls_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_early_server_shutdown_finishes_tags_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_empty_batch_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_graceful_server_shutdown_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_invoke_large_request_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_max_concurrent_streams_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_max_message_length_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_no_op_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_ping_pong_streaming_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_registered_call_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_request_response_with_binary_metadata_and_payload_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_request_response_with_metadata_and_payload_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_request_response_with_payload_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_request_response_with_payload_and_call_creds_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_request_response_with_trailing_metadata_and_payload_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_request_with_flags_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_request_with_large_metadata_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_request_with_payload_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_server_finishes_request_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_simple_delayed_request_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_simple_request_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_simple_request_with_high_initial_sequence_number_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_bad_hostname_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_cancel_after_accept_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_cancel_after_accept_and_writes_closed_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_cancel_after_invoke_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_cancel_before_invoke_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_cancel_in_a_vacuum_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_census_simple_request_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_disappearing_server_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_early_server_shutdown_finishes_inflight_calls_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_early_server_shutdown_finishes_tags_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_empty_batch_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_graceful_server_shutdown_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_invoke_large_request_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_max_concurrent_streams_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_max_message_length_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_no_op_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_ping_pong_streaming_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_registered_call_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_request_response_with_binary_metadata_and_payload_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_request_response_with_metadata_and_payload_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_request_response_with_payload_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_request_response_with_payload_and_call_creds_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_request_response_with_trailing_metadata_and_payload_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_request_with_flags_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_request_with_large_metadata_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_request_with_payload_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_server_finishes_request_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_simple_delayed_request_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_simple_request_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_simple_request_with_high_initial_sequence_number_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_with_poll_bad_hostname_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_with_poll_cancel_after_accept_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_with_poll_cancel_after_accept_and_writes_closed_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_with_poll_cancel_after_invoke_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_with_poll_cancel_before_invoke_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_with_poll_cancel_in_a_vacuum_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_with_poll_census_simple_request_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_with_poll_disappearing_server_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_with_poll_early_server_shutdown_finishes_inflight_calls_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_with_poll_early_server_shutdown_finishes_tags_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_with_poll_empty_batch_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_with_poll_graceful_server_shutdown_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_with_poll_invoke_large_request_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_with_poll_max_concurrent_streams_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_with_poll_max_message_length_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_with_poll_no_op_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_with_poll_ping_pong_streaming_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_with_poll_registered_call_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_with_poll_request_response_with_binary_metadata_and_payload_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_with_poll_request_response_with_metadata_and_payload_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_with_poll_request_response_with_payload_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_with_poll_request_response_with_payload_and_call_creds_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_with_poll_request_response_with_trailing_metadata_and_payload_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_with_poll_request_with_flags_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_with_poll_request_with_large_metadata_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_with_poll_request_with_payload_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_with_poll_server_finishes_request_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_with_poll_simple_delayed_request_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_with_poll_simple_request_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_with_poll_simple_request_with_high_initial_sequence_number_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_bad_hostname_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_cancel_after_accept_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_cancel_after_accept_and_writes_closed_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_cancel_after_invoke_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_cancel_before_invoke_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_cancel_in_a_vacuum_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_census_simple_request_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_disappearing_server_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_early_server_shutdown_finishes_inflight_calls_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_early_server_shutdown_finishes_tags_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_empty_batch_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_graceful_server_shutdown_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_invoke_large_request_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_max_concurrent_streams_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_max_message_length_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_no_op_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_ping_pong_streaming_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_registered_call_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_request_response_with_binary_metadata_and_payload_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_request_response_with_metadata_and_payload_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_request_response_with_payload_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_request_response_with_payload_and_call_creds_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_request_response_with_trailing_metadata_and_payload_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_request_with_flags_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_request_with_large_metadata_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_request_with_payload_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_server_finishes_request_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_simple_delayed_request_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_simple_request_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_simple_request_with_high_initial_sequence_number_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_bad_hostname_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_cancel_after_accept_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_cancel_after_accept_and_writes_closed_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_cancel_after_invoke_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_cancel_before_invoke_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_cancel_in_a_vacuum_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_census_simple_request_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_disappearing_server_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_early_server_shutdown_finishes_inflight_calls_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_early_server_shutdown_finishes_tags_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_empty_batch_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_graceful_server_shutdown_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_invoke_large_request_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_max_concurrent_streams_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_max_message_length_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_no_op_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_ping_pong_streaming_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_registered_call_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_request_response_with_binary_metadata_and_payload_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_request_response_with_metadata_and_payload_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_request_response_with_payload_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_request_response_with_payload_and_call_creds_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_request_response_with_trailing_metadata_and_payload_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_request_with_flags_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_request_with_large_metadata_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_request_with_payload_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_server_finishes_request_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_simple_delayed_request_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_simple_request_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_simple_request_with_high_initial_sequence_number_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_bad_hostname_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_cancel_after_accept_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_cancel_after_accept_and_writes_closed_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_cancel_after_invoke_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_cancel_before_invoke_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_cancel_in_a_vacuum_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_census_simple_request_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_disappearing_server_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_early_server_shutdown_finishes_inflight_calls_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_early_server_shutdown_finishes_tags_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_empty_batch_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_graceful_server_shutdown_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_invoke_large_request_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_max_concurrent_streams_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_max_message_length_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_no_op_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_ping_pong_streaming_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_registered_call_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_request_response_with_binary_metadata_and_payload_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_request_response_with_metadata_and_payload_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_request_response_with_payload_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_request_response_with_payload_and_call_creds_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_request_response_with_trailing_metadata_and_payload_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_request_with_flags_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_request_with_large_metadata_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_request_with_payload_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_server_finishes_request_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_simple_delayed_request_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_simple_request_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_simple_request_with_high_initial_sequence_number_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_bad_hostname_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_cancel_after_accept_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_cancel_after_accept_and_writes_closed_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_cancel_after_invoke_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_cancel_before_invoke_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_cancel_in_a_vacuum_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_census_simple_request_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_disappearing_server_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_early_server_shutdown_finishes_inflight_calls_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_early_server_shutdown_finishes_tags_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_empty_batch_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_graceful_server_shutdown_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_invoke_large_request_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_max_concurrent_streams_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_max_message_length_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_no_op_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_ping_pong_streaming_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_registered_call_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_request_response_with_binary_metadata_and_payload_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_request_response_with_metadata_and_payload_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_request_response_with_payload_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_request_response_with_payload_and_call_creds_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_request_response_with_trailing_metadata_and_payload_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_request_with_flags_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_request_with_large_metadata_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_request_with_payload_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_server_finishes_request_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_simple_delayed_request_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_simple_request_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_simple_request_with_high_initial_sequence_number_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_bad_hostname_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_cancel_after_accept_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_cancel_after_accept_and_writes_closed_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_cancel_after_invoke_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_cancel_before_invoke_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_cancel_in_a_vacuum_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_census_simple_request_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_disappearing_server_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_early_server_shutdown_finishes_inflight_calls_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_early_server_shutdown_finishes_tags_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_empty_batch_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_graceful_server_shutdown_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_invoke_large_request_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_max_concurrent_streams_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_max_message_length_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_no_op_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_ping_pong_streaming_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_registered_call_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_request_response_with_binary_metadata_and_payload_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_request_response_with_metadata_and_payload_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_request_response_with_payload_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_request_response_with_trailing_metadata_and_payload_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_request_with_flags_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_request_with_large_metadata_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_request_with_payload_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_server_finishes_request_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_simple_delayed_request_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_simple_request_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_simple_request_with_high_initial_sequence_number_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_bad_hostname_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_cancel_after_accept_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_cancel_after_accept_and_writes_closed_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_cancel_after_invoke_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_cancel_before_invoke_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_cancel_in_a_vacuum_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_census_simple_request_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_disappearing_server_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_early_server_shutdown_finishes_inflight_calls_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_early_server_shutdown_finishes_tags_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_empty_batch_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_graceful_server_shutdown_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_invoke_large_request_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_max_concurrent_streams_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_max_message_length_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_no_op_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_ping_pong_streaming_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_registered_call_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_request_response_with_binary_metadata_and_payload_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_request_response_with_metadata_and_payload_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_request_response_with_payload_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_request_response_with_trailing_metadata_and_payload_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_request_with_flags_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_request_with_large_metadata_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_request_with_payload_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_server_finishes_request_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_simple_delayed_request_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_simple_request_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_simple_request_with_high_initial_sequence_number_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_bad_hostname_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_cancel_after_accept_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_cancel_after_accept_and_writes_closed_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_cancel_after_invoke_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_cancel_before_invoke_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_cancel_in_a_vacuum_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_census_simple_request_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_disappearing_server_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_early_server_shutdown_finishes_inflight_calls_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_early_server_shutdown_finishes_tags_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_empty_batch_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_graceful_server_shutdown_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_invoke_large_request_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_max_concurrent_streams_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_max_message_length_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_no_op_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_ping_pong_streaming_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_registered_call_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_request_response_with_binary_metadata_and_payload_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_request_response_with_metadata_and_payload_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_request_response_with_payload_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_request_response_with_trailing_metadata_and_payload_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_request_with_flags_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_request_with_large_metadata_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_request_with_payload_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_server_finishes_request_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_simple_delayed_request_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_simple_request_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_simple_request_with_high_initial_sequence_number_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_bad_hostname_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_cancel_after_accept_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_cancel_after_accept_and_writes_closed_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_cancel_after_invoke_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_cancel_before_invoke_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_cancel_in_a_vacuum_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_census_simple_request_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_disappearing_server_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_early_server_shutdown_finishes_inflight_calls_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_early_server_shutdown_finishes_tags_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_empty_batch_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_graceful_server_shutdown_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_invoke_large_request_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_max_concurrent_streams_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_max_message_length_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_no_op_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_ping_pong_streaming_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_registered_call_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_request_response_with_binary_metadata_and_payload_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_request_response_with_metadata_and_payload_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_request_response_with_payload_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_request_response_with_trailing_metadata_and_payload_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_request_with_flags_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_request_with_large_metadata_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_request_with_payload_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_server_finishes_request_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_simple_delayed_request_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_simple_request_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_simple_request_with_high_initial_sequence_number_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_bad_hostname_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_cancel_after_accept_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_cancel_after_accept_and_writes_closed_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_cancel_after_invoke_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_cancel_before_invoke_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_cancel_in_a_vacuum_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_census_simple_request_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_disappearing_server_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_early_server_shutdown_finishes_inflight_calls_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_early_server_shutdown_finishes_tags_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_empty_batch_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_graceful_server_shutdown_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_invoke_large_request_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_max_concurrent_streams_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_max_message_length_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_no_op_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_ping_pong_streaming_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_registered_call_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_request_response_with_binary_metadata_and_payload_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_request_response_with_metadata_and_payload_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_request_response_with_payload_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_request_response_with_trailing_metadata_and_payload_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_request_with_flags_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_request_with_large_metadata_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_request_with_payload_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_server_finishes_request_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_simple_delayed_request_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_simple_request_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_simple_request_with_high_initial_sequence_number_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_bad_hostname_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_cancel_after_accept_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_cancel_after_accept_and_writes_closed_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_cancel_after_invoke_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_cancel_before_invoke_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_cancel_in_a_vacuum_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_census_simple_request_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_disappearing_server_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_early_server_shutdown_finishes_inflight_calls_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_early_server_shutdown_finishes_tags_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_empty_batch_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_graceful_server_shutdown_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_invoke_large_request_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_max_concurrent_streams_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_max_message_length_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_no_op_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_ping_pong_streaming_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_registered_call_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_request_response_with_binary_metadata_and_payload_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_request_response_with_metadata_and_payload_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_request_response_with_payload_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_request_response_with_trailing_metadata_and_payload_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_request_with_flags_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_request_with_large_metadata_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_request_with_payload_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_server_finishes_request_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_simple_delayed_request_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_simple_request_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_simple_request_with_high_initial_sequence_number_unsecure_test $(BINDIR)/$(CONFIG)/connection_prefix_bad_client_test $(BINDIR)/$(CONFIG)/initial_settings_frame_bad_client_test
+buildtests_c: privatelibs_c $(BINDIR)/$(CONFIG)/alarm_heap_test $(BINDIR)/$(CONFIG)/alarm_list_test $(BINDIR)/$(CONFIG)/alarm_test $(BINDIR)/$(CONFIG)/alpn_test $(BINDIR)/$(CONFIG)/bin_encoder_test $(BINDIR)/$(CONFIG)/chttp2_status_conversion_test $(BINDIR)/$(CONFIG)/chttp2_stream_encoder_test $(BINDIR)/$(CONFIG)/chttp2_stream_map_test $(BINDIR)/$(CONFIG)/dualstack_socket_test $(BINDIR)/$(CONFIG)/fd_conservation_posix_test $(BINDIR)/$(CONFIG)/fd_posix_test $(BINDIR)/$(CONFIG)/fling_client $(BINDIR)/$(CONFIG)/fling_server $(BINDIR)/$(CONFIG)/fling_stream_test $(BINDIR)/$(CONFIG)/fling_test $(BINDIR)/$(CONFIG)/gpr_cancellable_test $(BINDIR)/$(CONFIG)/gpr_cmdline_test $(BINDIR)/$(CONFIG)/gpr_env_test $(BINDIR)/$(CONFIG)/gpr_file_test $(BINDIR)/$(CONFIG)/gpr_histogram_test $(BINDIR)/$(CONFIG)/gpr_host_port_test $(BINDIR)/$(CONFIG)/gpr_log_test $(BINDIR)/$(CONFIG)/gpr_slice_buffer_test $(BINDIR)/$(CONFIG)/gpr_slice_test $(BINDIR)/$(CONFIG)/gpr_stack_lockfree_test $(BINDIR)/$(CONFIG)/gpr_string_test $(BINDIR)/$(CONFIG)/gpr_sync_test $(BINDIR)/$(CONFIG)/gpr_thd_test $(BINDIR)/$(CONFIG)/gpr_time_test $(BINDIR)/$(CONFIG)/gpr_tls_test $(BINDIR)/$(CONFIG)/gpr_useful_test $(BINDIR)/$(CONFIG)/grpc_auth_context_test $(BINDIR)/$(CONFIG)/grpc_base64_test $(BINDIR)/$(CONFIG)/grpc_byte_buffer_reader_test $(BINDIR)/$(CONFIG)/grpc_channel_stack_test $(BINDIR)/$(CONFIG)/grpc_completion_queue_test $(BINDIR)/$(CONFIG)/grpc_credentials_test $(BINDIR)/$(CONFIG)/grpc_json_token_test $(BINDIR)/$(CONFIG)/grpc_jwt_verifier_test $(BINDIR)/$(CONFIG)/grpc_security_connector_test $(BINDIR)/$(CONFIG)/grpc_stream_op_test $(BINDIR)/$(CONFIG)/hpack_parser_test $(BINDIR)/$(CONFIG)/hpack_table_test $(BINDIR)/$(CONFIG)/httpcli_format_request_test $(BINDIR)/$(CONFIG)/httpcli_parser_test $(BINDIR)/$(CONFIG)/httpcli_test $(BINDIR)/$(CONFIG)/json_rewrite $(BINDIR)/$(CONFIG)/json_rewrite_test $(BINDIR)/$(CONFIG)/json_test $(BINDIR)/$(CONFIG)/lame_client_test $(BINDIR)/$(CONFIG)/message_compress_test $(BINDIR)/$(CONFIG)/multi_init_test $(BINDIR)/$(CONFIG)/multiple_server_queues_test $(BINDIR)/$(CONFIG)/murmur_hash_test $(BINDIR)/$(CONFIG)/no_server_test $(BINDIR)/$(CONFIG)/poll_kick_posix_test $(BINDIR)/$(CONFIG)/resolve_address_test $(BINDIR)/$(CONFIG)/secure_endpoint_test $(BINDIR)/$(CONFIG)/sockaddr_utils_test $(BINDIR)/$(CONFIG)/tcp_client_posix_test $(BINDIR)/$(CONFIG)/tcp_posix_test $(BINDIR)/$(CONFIG)/tcp_server_posix_test $(BINDIR)/$(CONFIG)/time_averaged_stats_test $(BINDIR)/$(CONFIG)/time_test $(BINDIR)/$(CONFIG)/timeout_encoding_test $(BINDIR)/$(CONFIG)/timers_test $(BINDIR)/$(CONFIG)/transport_metadata_test $(BINDIR)/$(CONFIG)/transport_security_test $(BINDIR)/$(CONFIG)/uri_parser_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_bad_hostname_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_cancel_after_accept_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_cancel_after_accept_and_writes_closed_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_cancel_after_invoke_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_cancel_before_invoke_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_cancel_in_a_vacuum_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_census_simple_request_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_disappearing_server_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_early_server_shutdown_finishes_inflight_calls_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_early_server_shutdown_finishes_tags_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_empty_batch_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_graceful_server_shutdown_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_invoke_large_request_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_max_concurrent_streams_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_max_message_length_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_no_op_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_ping_pong_streaming_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_registered_call_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_request_response_with_binary_metadata_and_payload_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_request_response_with_metadata_and_payload_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_request_response_with_payload_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_request_response_with_payload_and_call_creds_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_request_response_with_trailing_metadata_and_payload_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_request_with_flags_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_request_with_large_metadata_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_request_with_payload_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_server_finishes_request_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_simple_delayed_request_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_simple_request_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_simple_request_with_high_initial_sequence_number_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_bad_hostname_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_cancel_after_accept_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_cancel_after_accept_and_writes_closed_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_cancel_after_invoke_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_cancel_before_invoke_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_cancel_in_a_vacuum_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_census_simple_request_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_disappearing_server_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_early_server_shutdown_finishes_inflight_calls_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_early_server_shutdown_finishes_tags_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_empty_batch_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_graceful_server_shutdown_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_invoke_large_request_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_max_concurrent_streams_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_max_message_length_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_no_op_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_ping_pong_streaming_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_registered_call_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_request_response_with_binary_metadata_and_payload_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_request_response_with_metadata_and_payload_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_request_response_with_payload_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_request_response_with_payload_and_call_creds_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_request_response_with_trailing_metadata_and_payload_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_request_with_flags_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_request_with_large_metadata_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_request_with_payload_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_server_finishes_request_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_simple_delayed_request_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_simple_request_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_simple_request_with_high_initial_sequence_number_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_bad_hostname_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_cancel_after_accept_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_cancel_after_accept_and_writes_closed_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_cancel_after_invoke_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_cancel_before_invoke_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_cancel_in_a_vacuum_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_census_simple_request_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_disappearing_server_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_early_server_shutdown_finishes_inflight_calls_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_early_server_shutdown_finishes_tags_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_empty_batch_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_graceful_server_shutdown_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_invoke_large_request_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_max_concurrent_streams_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_max_message_length_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_no_op_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_ping_pong_streaming_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_registered_call_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_request_response_with_binary_metadata_and_payload_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_request_response_with_metadata_and_payload_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_request_response_with_payload_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_request_response_with_payload_and_call_creds_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_request_response_with_trailing_metadata_and_payload_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_request_with_flags_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_request_with_large_metadata_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_request_with_payload_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_server_finishes_request_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_simple_delayed_request_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_simple_request_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_simple_request_with_high_initial_sequence_number_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_bad_hostname_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_cancel_after_accept_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_cancel_after_accept_and_writes_closed_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_cancel_after_invoke_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_cancel_before_invoke_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_cancel_in_a_vacuum_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_census_simple_request_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_disappearing_server_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_early_server_shutdown_finishes_inflight_calls_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_early_server_shutdown_finishes_tags_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_empty_batch_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_graceful_server_shutdown_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_invoke_large_request_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_max_concurrent_streams_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_max_message_length_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_no_op_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_ping_pong_streaming_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_registered_call_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_request_response_with_binary_metadata_and_payload_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_request_response_with_metadata_and_payload_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_request_response_with_payload_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_request_response_with_payload_and_call_creds_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_request_response_with_trailing_metadata_and_payload_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_request_with_flags_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_request_with_large_metadata_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_request_with_payload_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_server_finishes_request_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_simple_delayed_request_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_simple_request_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_simple_request_with_high_initial_sequence_number_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_bad_hostname_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_cancel_after_accept_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_cancel_after_accept_and_writes_closed_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_cancel_after_invoke_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_cancel_before_invoke_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_cancel_in_a_vacuum_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_census_simple_request_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_disappearing_server_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_early_server_shutdown_finishes_inflight_calls_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_early_server_shutdown_finishes_tags_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_empty_batch_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_graceful_server_shutdown_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_invoke_large_request_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_max_concurrent_streams_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_max_message_length_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_no_op_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_ping_pong_streaming_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_registered_call_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_request_response_with_binary_metadata_and_payload_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_request_response_with_metadata_and_payload_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_request_response_with_payload_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_request_response_with_payload_and_call_creds_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_request_response_with_trailing_metadata_and_payload_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_request_with_flags_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_request_with_large_metadata_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_request_with_payload_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_server_finishes_request_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_simple_delayed_request_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_simple_request_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_simple_request_with_high_initial_sequence_number_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_with_poll_bad_hostname_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_with_poll_cancel_after_accept_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_with_poll_cancel_after_accept_and_writes_closed_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_with_poll_cancel_after_invoke_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_with_poll_cancel_before_invoke_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_with_poll_cancel_in_a_vacuum_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_with_poll_census_simple_request_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_with_poll_disappearing_server_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_with_poll_early_server_shutdown_finishes_inflight_calls_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_with_poll_early_server_shutdown_finishes_tags_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_with_poll_empty_batch_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_with_poll_graceful_server_shutdown_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_with_poll_invoke_large_request_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_with_poll_max_concurrent_streams_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_with_poll_max_message_length_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_with_poll_no_op_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_with_poll_ping_pong_streaming_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_with_poll_registered_call_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_with_poll_request_response_with_binary_metadata_and_payload_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_with_poll_request_response_with_metadata_and_payload_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_with_poll_request_response_with_payload_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_with_poll_request_response_with_payload_and_call_creds_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_with_poll_request_response_with_trailing_metadata_and_payload_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_with_poll_request_with_flags_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_with_poll_request_with_large_metadata_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_with_poll_request_with_payload_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_with_poll_server_finishes_request_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_with_poll_simple_delayed_request_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_with_poll_simple_request_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_with_poll_simple_request_with_high_initial_sequence_number_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_bad_hostname_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_cancel_after_accept_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_cancel_after_accept_and_writes_closed_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_cancel_after_invoke_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_cancel_before_invoke_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_cancel_in_a_vacuum_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_census_simple_request_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_disappearing_server_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_early_server_shutdown_finishes_inflight_calls_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_early_server_shutdown_finishes_tags_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_empty_batch_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_graceful_server_shutdown_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_invoke_large_request_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_max_concurrent_streams_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_max_message_length_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_no_op_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_ping_pong_streaming_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_registered_call_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_request_response_with_binary_metadata_and_payload_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_request_response_with_metadata_and_payload_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_request_response_with_payload_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_request_response_with_payload_and_call_creds_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_request_response_with_trailing_metadata_and_payload_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_request_with_flags_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_request_with_large_metadata_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_request_with_payload_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_server_finishes_request_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_simple_delayed_request_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_simple_request_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_simple_request_with_high_initial_sequence_number_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_bad_hostname_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_cancel_after_accept_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_cancel_after_accept_and_writes_closed_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_cancel_after_invoke_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_cancel_before_invoke_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_cancel_in_a_vacuum_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_census_simple_request_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_disappearing_server_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_early_server_shutdown_finishes_inflight_calls_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_early_server_shutdown_finishes_tags_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_empty_batch_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_graceful_server_shutdown_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_invoke_large_request_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_max_concurrent_streams_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_max_message_length_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_no_op_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_ping_pong_streaming_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_registered_call_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_request_response_with_binary_metadata_and_payload_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_request_response_with_metadata_and_payload_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_request_response_with_payload_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_request_response_with_payload_and_call_creds_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_request_response_with_trailing_metadata_and_payload_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_request_with_flags_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_request_with_large_metadata_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_request_with_payload_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_server_finishes_request_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_simple_delayed_request_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_simple_request_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_simple_request_with_high_initial_sequence_number_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_bad_hostname_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_cancel_after_accept_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_cancel_after_accept_and_writes_closed_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_cancel_after_invoke_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_cancel_before_invoke_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_cancel_in_a_vacuum_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_census_simple_request_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_disappearing_server_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_early_server_shutdown_finishes_inflight_calls_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_early_server_shutdown_finishes_tags_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_empty_batch_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_graceful_server_shutdown_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_invoke_large_request_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_max_concurrent_streams_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_max_message_length_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_no_op_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_ping_pong_streaming_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_registered_call_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_request_response_with_binary_metadata_and_payload_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_request_response_with_metadata_and_payload_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_request_response_with_payload_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_request_response_with_payload_and_call_creds_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_request_response_with_trailing_metadata_and_payload_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_request_with_flags_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_request_with_large_metadata_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_request_with_payload_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_server_finishes_request_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_simple_delayed_request_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_simple_request_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_simple_request_with_high_initial_sequence_number_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_bad_hostname_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_cancel_after_accept_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_cancel_after_accept_and_writes_closed_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_cancel_after_invoke_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_cancel_before_invoke_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_cancel_in_a_vacuum_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_census_simple_request_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_disappearing_server_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_early_server_shutdown_finishes_inflight_calls_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_early_server_shutdown_finishes_tags_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_empty_batch_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_graceful_server_shutdown_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_invoke_large_request_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_max_concurrent_streams_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_max_message_length_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_no_op_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_ping_pong_streaming_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_registered_call_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_request_response_with_binary_metadata_and_payload_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_request_response_with_metadata_and_payload_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_request_response_with_payload_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_request_response_with_payload_and_call_creds_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_request_response_with_trailing_metadata_and_payload_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_request_with_flags_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_request_with_large_metadata_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_request_with_payload_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_server_finishes_request_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_simple_delayed_request_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_simple_request_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_simple_request_with_high_initial_sequence_number_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_bad_hostname_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_cancel_after_accept_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_cancel_after_accept_and_writes_closed_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_cancel_after_invoke_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_cancel_before_invoke_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_cancel_in_a_vacuum_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_census_simple_request_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_disappearing_server_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_early_server_shutdown_finishes_inflight_calls_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_early_server_shutdown_finishes_tags_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_empty_batch_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_graceful_server_shutdown_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_invoke_large_request_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_max_concurrent_streams_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_max_message_length_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_no_op_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_ping_pong_streaming_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_registered_call_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_request_response_with_binary_metadata_and_payload_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_request_response_with_metadata_and_payload_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_request_response_with_payload_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_request_response_with_trailing_metadata_and_payload_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_request_with_flags_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_request_with_large_metadata_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_request_with_payload_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_server_finishes_request_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_simple_delayed_request_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_simple_request_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_simple_request_with_high_initial_sequence_number_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_bad_hostname_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_cancel_after_accept_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_cancel_after_accept_and_writes_closed_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_cancel_after_invoke_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_cancel_before_invoke_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_cancel_in_a_vacuum_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_census_simple_request_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_disappearing_server_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_early_server_shutdown_finishes_inflight_calls_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_early_server_shutdown_finishes_tags_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_empty_batch_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_graceful_server_shutdown_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_invoke_large_request_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_max_concurrent_streams_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_max_message_length_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_no_op_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_ping_pong_streaming_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_registered_call_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_request_response_with_binary_metadata_and_payload_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_request_response_with_metadata_and_payload_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_request_response_with_payload_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_request_response_with_trailing_metadata_and_payload_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_request_with_flags_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_request_with_large_metadata_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_request_with_payload_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_server_finishes_request_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_simple_delayed_request_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_simple_request_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_posix_simple_request_with_high_initial_sequence_number_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_bad_hostname_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_cancel_after_accept_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_cancel_after_accept_and_writes_closed_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_cancel_after_invoke_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_cancel_before_invoke_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_cancel_in_a_vacuum_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_census_simple_request_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_disappearing_server_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_early_server_shutdown_finishes_inflight_calls_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_early_server_shutdown_finishes_tags_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_empty_batch_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_graceful_server_shutdown_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_invoke_large_request_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_max_concurrent_streams_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_max_message_length_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_no_op_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_ping_pong_streaming_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_registered_call_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_request_response_with_binary_metadata_and_payload_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_request_response_with_metadata_and_payload_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_request_response_with_payload_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_request_response_with_trailing_metadata_and_payload_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_request_with_flags_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_request_with_large_metadata_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_request_with_payload_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_server_finishes_request_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_simple_delayed_request_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_simple_request_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_with_poll_simple_request_with_high_initial_sequence_number_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_bad_hostname_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_cancel_after_accept_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_cancel_after_accept_and_writes_closed_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_cancel_after_invoke_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_cancel_before_invoke_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_cancel_in_a_vacuum_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_census_simple_request_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_disappearing_server_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_early_server_shutdown_finishes_inflight_calls_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_early_server_shutdown_finishes_tags_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_empty_batch_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_graceful_server_shutdown_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_invoke_large_request_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_max_concurrent_streams_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_max_message_length_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_no_op_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_ping_pong_streaming_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_registered_call_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_request_response_with_binary_metadata_and_payload_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_request_response_with_metadata_and_payload_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_request_response_with_payload_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_request_response_with_trailing_metadata_and_payload_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_request_with_flags_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_request_with_large_metadata_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_request_with_payload_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_server_finishes_request_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_simple_delayed_request_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_simple_request_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_simple_request_with_high_initial_sequence_number_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_bad_hostname_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_cancel_after_accept_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_cancel_after_accept_and_writes_closed_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_cancel_after_invoke_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_cancel_before_invoke_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_cancel_in_a_vacuum_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_census_simple_request_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_disappearing_server_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_early_server_shutdown_finishes_inflight_calls_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_early_server_shutdown_finishes_tags_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_empty_batch_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_graceful_server_shutdown_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_invoke_large_request_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_max_concurrent_streams_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_max_message_length_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_no_op_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_ping_pong_streaming_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_registered_call_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_request_response_with_binary_metadata_and_payload_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_request_response_with_metadata_and_payload_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_request_response_with_payload_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_request_response_with_trailing_metadata_and_payload_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_request_with_flags_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_request_with_large_metadata_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_request_with_payload_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_server_finishes_request_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_simple_delayed_request_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_simple_request_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_simple_request_with_high_initial_sequence_number_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_bad_hostname_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_cancel_after_accept_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_cancel_after_accept_and_writes_closed_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_cancel_after_invoke_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_cancel_before_invoke_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_cancel_in_a_vacuum_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_census_simple_request_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_disappearing_server_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_early_server_shutdown_finishes_inflight_calls_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_early_server_shutdown_finishes_tags_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_empty_batch_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_graceful_server_shutdown_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_invoke_large_request_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_max_concurrent_streams_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_max_message_length_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_no_op_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_ping_pong_streaming_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_registered_call_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_request_response_with_binary_metadata_and_payload_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_request_response_with_metadata_and_payload_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_request_response_with_payload_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_request_response_with_trailing_metadata_and_payload_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_request_with_flags_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_request_with_large_metadata_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_request_with_payload_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_server_finishes_request_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_simple_delayed_request_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_simple_request_unsecure_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_with_grpc_trace_simple_request_with_high_initial_sequence_number_unsecure_test $(BINDIR)/$(CONFIG)/connection_prefix_bad_client_test $(BINDIR)/$(CONFIG)/initial_settings_frame_bad_client_test
 
-buildtests_cxx: privatelibs_cxx $(BINDIR)/$(CONFIG)/async_end2end_test $(BINDIR)/$(CONFIG)/async_streaming_ping_pong_test $(BINDIR)/$(CONFIG)/async_unary_ping_pong_test $(BINDIR)/$(CONFIG)/channel_arguments_test $(BINDIR)/$(CONFIG)/cli_call_test $(BINDIR)/$(CONFIG)/client_crash_test $(BINDIR)/$(CONFIG)/client_crash_test_server $(BINDIR)/$(CONFIG)/credentials_test $(BINDIR)/$(CONFIG)/cxx_byte_buffer_test $(BINDIR)/$(CONFIG)/cxx_slice_test $(BINDIR)/$(CONFIG)/cxx_time_test $(BINDIR)/$(CONFIG)/end2end_test $(BINDIR)/$(CONFIG)/generic_end2end_test $(BINDIR)/$(CONFIG)/grpc_cli $(BINDIR)/$(CONFIG)/interop_client $(BINDIR)/$(CONFIG)/interop_server $(BINDIR)/$(CONFIG)/interop_test $(BINDIR)/$(CONFIG)/mock_test $(BINDIR)/$(CONFIG)/qps_interarrival_test $(BINDIR)/$(CONFIG)/qps_test $(BINDIR)/$(CONFIG)/qps_test_openloop $(BINDIR)/$(CONFIG)/secure_auth_context_test $(BINDIR)/$(CONFIG)/server_crash_test $(BINDIR)/$(CONFIG)/server_crash_test_client $(BINDIR)/$(CONFIG)/status_test $(BINDIR)/$(CONFIG)/sync_streaming_ping_pong_test $(BINDIR)/$(CONFIG)/sync_unary_ping_pong_test $(BINDIR)/$(CONFIG)/thread_pool_test $(BINDIR)/$(CONFIG)/thread_stress_test
+buildtests_cxx: privatelibs_cxx $(BINDIR)/$(CONFIG)/async_end2end_test $(BINDIR)/$(CONFIG)/async_streaming_ping_pong_test $(BINDIR)/$(CONFIG)/async_unary_ping_pong_test $(BINDIR)/$(CONFIG)/channel_arguments_test $(BINDIR)/$(CONFIG)/cli_call_test $(BINDIR)/$(CONFIG)/client_crash_test $(BINDIR)/$(CONFIG)/client_crash_test_server $(BINDIR)/$(CONFIG)/credentials_test $(BINDIR)/$(CONFIG)/cxx_byte_buffer_test $(BINDIR)/$(CONFIG)/cxx_slice_test $(BINDIR)/$(CONFIG)/cxx_time_test $(BINDIR)/$(CONFIG)/end2end_test $(BINDIR)/$(CONFIG)/generic_end2end_test $(BINDIR)/$(CONFIG)/grpc_cli $(BINDIR)/$(CONFIG)/interop_client $(BINDIR)/$(CONFIG)/interop_server $(BINDIR)/$(CONFIG)/interop_test $(BINDIR)/$(CONFIG)/mock_test $(BINDIR)/$(CONFIG)/qps_interarrival_test $(BINDIR)/$(CONFIG)/qps_openloop_test $(BINDIR)/$(CONFIG)/qps_test $(BINDIR)/$(CONFIG)/secure_auth_context_test $(BINDIR)/$(CONFIG)/server_crash_test $(BINDIR)/$(CONFIG)/server_crash_test_client $(BINDIR)/$(CONFIG)/status_test $(BINDIR)/$(CONFIG)/sync_streaming_ping_pong_test $(BINDIR)/$(CONFIG)/sync_unary_ping_pong_test $(BINDIR)/$(CONFIG)/thread_pool_test $(BINDIR)/$(CONFIG)/thread_stress_test
 
 test: test_c test_cxx
 
@@ -1476,6 +1506,8 @@
 	$(Q) $(BINDIR)/$(CONFIG)/gpr_slice_buffer_test || ( echo test gpr_slice_buffer_test failed ; exit 1 )
 	$(E) "[RUN]     Testing gpr_slice_test"
 	$(Q) $(BINDIR)/$(CONFIG)/gpr_slice_test || ( echo test gpr_slice_test failed ; exit 1 )
+	$(E) "[RUN]     Testing gpr_stack_lockfree_test"
+	$(Q) $(BINDIR)/$(CONFIG)/gpr_stack_lockfree_test || ( echo test gpr_stack_lockfree_test failed ; exit 1 )
 	$(E) "[RUN]     Testing gpr_string_test"
 	$(Q) $(BINDIR)/$(CONFIG)/gpr_string_test || ( echo test gpr_string_test failed ; exit 1 )
 	$(E) "[RUN]     Testing gpr_sync_test"
@@ -2548,10 +2580,10 @@
 	$(Q) $(BINDIR)/$(CONFIG)/interop_test || ( echo test interop_test failed ; exit 1 )
 	$(E) "[RUN]     Testing mock_test"
 	$(Q) $(BINDIR)/$(CONFIG)/mock_test || ( echo test mock_test failed ; exit 1 )
+	$(E) "[RUN]     Testing qps_openloop_test"
+	$(Q) $(BINDIR)/$(CONFIG)/qps_openloop_test || ( echo test qps_openloop_test failed ; exit 1 )
 	$(E) "[RUN]     Testing qps_test"
 	$(Q) $(BINDIR)/$(CONFIG)/qps_test || ( echo test qps_test failed ; exit 1 )
-	$(E) "[RUN]     Testing qps_test_openloop"
-	$(Q) $(BINDIR)/$(CONFIG)/qps_test_openloop || ( echo test qps_test_openloop failed ; exit 1 )
 	$(E) "[RUN]     Testing secure_auth_context_test"
 	$(Q) $(BINDIR)/$(CONFIG)/secure_auth_context_test || ( echo test secure_auth_context_test failed ; exit 1 )
 	$(E) "[RUN]     Testing server_crash_test"
@@ -2640,6 +2672,10 @@
 	$(Q) $(STRIP) $(LIBDIR)/$(CONFIG)/libgrpc_csharp_ext.$(SHARED_EXT)
 endif
 
+cache.mk::
+	$(E) "[MAKE]    Generating $@"
+	$(Q) echo -e "$(CACHE_MK)" >$@
+
 $(LIBDIR)/$(CONFIG)/pkgconfig/gpr.pc:
 	$(E) "[MAKE]    Generating $@"
 	$(Q) mkdir -p $(@D)
@@ -3073,7 +3109,7 @@
 
 clean:
 	$(E) "[CLEAN]   Cleaning build directories."
-	$(Q) $(RM) -rf $(OBJDIR) $(LIBDIR) $(BINDIR) $(GENDIR)
+	$(Q) $(RM) -rf $(OBJDIR) $(LIBDIR) $(BINDIR) $(GENDIR) cache.mk
 
 
 # The various libraries
@@ -3103,6 +3139,7 @@
     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 \
@@ -3313,6 +3350,7 @@
     src/core/surface/server_chttp2.c \
     src/core/surface/server_create.c \
     src/core/surface/surface_trace.c \
+    src/core/surface/version.c \
     src/core/transport/chttp2/alpn.c \
     src/core/transport/chttp2/bin_encoder.c \
     src/core/transport/chttp2/frame_data.c \
@@ -3573,6 +3611,7 @@
     src/core/surface/server_chttp2.c \
     src/core/surface/server_create.c \
     src/core/surface/surface_trace.c \
+    src/core/surface/version.c \
     src/core/transport/chttp2/alpn.c \
     src/core/transport/chttp2/bin_encoder.c \
     src/core/transport/chttp2/frame_data.c \
@@ -6221,6 +6260,35 @@
 endif
 
 
+GPR_STACK_LOCKFREE_TEST_SRC = \
+    test/core/support/stack_lockfree_test.c \
+
+GPR_STACK_LOCKFREE_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(GPR_STACK_LOCKFREE_TEST_SRC))))
+ifeq ($(NO_SECURE),true)
+
+# You can't build secure targets if you don't have OpenSSL.
+
+$(BINDIR)/$(CONFIG)/gpr_stack_lockfree_test: openssl_dep_error
+
+else
+
+$(BINDIR)/$(CONFIG)/gpr_stack_lockfree_test: $(GPR_STACK_LOCKFREE_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
+	$(E) "[LD]      Linking $@"
+	$(Q) mkdir -p `dirname $@`
+	$(Q) $(LD) $(LDFLAGS) $(GPR_STACK_LOCKFREE_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBS) $(LDLIBS_SECURE) -o $(BINDIR)/$(CONFIG)/gpr_stack_lockfree_test
+
+endif
+
+$(OBJDIR)/$(CONFIG)/test/core/support/stack_lockfree_test.o:  $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
+deps_gpr_stack_lockfree_test: $(GPR_STACK_LOCKFREE_TEST_OBJS:.o=.dep)
+
+ifneq ($(NO_SECURE),true)
+ifneq ($(NO_DEPS),true)
+-include $(GPR_STACK_LOCKFREE_TEST_OBJS:.o=.dep)
+endif
+endif
+
+
 GPR_STRING_TEST_SRC = \
     test/core/support/string_test.c \
 
@@ -8680,6 +8748,46 @@
 endif
 
 
+QPS_OPENLOOP_TEST_SRC = \
+    test/cpp/qps/qps_openloop_test.cc \
+
+QPS_OPENLOOP_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(QPS_OPENLOOP_TEST_SRC))))
+ifeq ($(NO_SECURE),true)
+
+# You can't build secure targets if you don't have OpenSSL.
+
+$(BINDIR)/$(CONFIG)/qps_openloop_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)/qps_openloop_test: protobuf_dep_error
+
+else
+
+$(BINDIR)/$(CONFIG)/qps_openloop_test: $(PROTOBUF_DEP) $(QPS_OPENLOOP_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libqps.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_config.a
+	$(E) "[LD]      Linking $@"
+	$(Q) mkdir -p `dirname $@`
+	$(Q) $(LDXX) $(LDFLAGS) $(QPS_OPENLOOP_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libqps.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_config.a $(LDLIBSXX) $(LDLIBS_PROTOBUF) $(LDLIBS) $(LDLIBS_SECURE) $(GTEST_LIB) -o $(BINDIR)/$(CONFIG)/qps_openloop_test
+
+endif
+
+endif
+
+$(OBJDIR)/$(CONFIG)/test/cpp/qps/qps_openloop_test.o:  $(LIBDIR)/$(CONFIG)/libqps.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_config.a
+deps_qps_openloop_test: $(QPS_OPENLOOP_TEST_OBJS:.o=.dep)
+
+ifneq ($(NO_SECURE),true)
+ifneq ($(NO_DEPS),true)
+-include $(QPS_OPENLOOP_TEST_OBJS:.o=.dep)
+endif
+endif
+
+
 QPS_TEST_SRC = \
     test/cpp/qps/qps_test.cc \
 
@@ -8720,46 +8828,6 @@
 endif
 
 
-QPS_TEST_OPENLOOP_SRC = \
-    test/cpp/qps/qps_test_openloop.cc \
-
-QPS_TEST_OPENLOOP_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(QPS_TEST_OPENLOOP_SRC))))
-ifeq ($(NO_SECURE),true)
-
-# You can't build secure targets if you don't have OpenSSL.
-
-$(BINDIR)/$(CONFIG)/qps_test_openloop: 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)/qps_test_openloop: protobuf_dep_error
-
-else
-
-$(BINDIR)/$(CONFIG)/qps_test_openloop: $(PROTOBUF_DEP) $(QPS_TEST_OPENLOOP_OBJS) $(LIBDIR)/$(CONFIG)/libqps.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_config.a
-	$(E) "[LD]      Linking $@"
-	$(Q) mkdir -p `dirname $@`
-	$(Q) $(LDXX) $(LDFLAGS) $(QPS_TEST_OPENLOOP_OBJS) $(LIBDIR)/$(CONFIG)/libqps.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_config.a $(LDLIBSXX) $(LDLIBS_PROTOBUF) $(LDLIBS) $(LDLIBS_SECURE) $(GTEST_LIB) -o $(BINDIR)/$(CONFIG)/qps_test_openloop
-
-endif
-
-endif
-
-$(OBJDIR)/$(CONFIG)/test/cpp/qps/qps_test_openloop.o:  $(LIBDIR)/$(CONFIG)/libqps.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_config.a
-deps_qps_test_openloop: $(QPS_TEST_OPENLOOP_OBJS:.o=.dep)
-
-ifneq ($(NO_SECURE),true)
-ifneq ($(NO_DEPS),true)
--include $(QPS_TEST_OPENLOOP_OBJS:.o=.dep)
-endif
-endif
-
-
 QPS_WORKER_SRC = \
     test/cpp/qps/worker.cc \
 
diff --git a/build.json b/build.json
index 7d2242b..e21efde 100644
--- a/build.json
+++ b/build.json
@@ -287,6 +287,7 @@
         "src/core/surface/server_chttp2.c",
         "src/core/surface/server_create.c",
         "src/core/surface/surface_trace.c",
+        "src/core/surface/version.c",
         "src/core/transport/chttp2/alpn.c",
         "src/core/transport/chttp2/bin_encoder.c",
         "src/core/transport/chttp2/frame_data.c",
@@ -375,6 +376,7 @@
         "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"
@@ -403,6 +405,7 @@
         "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",
@@ -1169,6 +1172,18 @@
       ]
     },
     {
+      "name": "gpr_stack_lockfree_test",
+      "build": "test",
+      "language": "c",
+      "src": [
+        "test/core/support/stack_lockfree_test.c"
+      ],
+      "deps": [
+        "gpr_test_util",
+        "gpr"
+      ]
+    },
+    {
       "name": "gpr_string_test",
       "build": "test",
       "language": "c",
@@ -2294,11 +2309,11 @@
       ]
     },
     {
-      "name": "qps_test",
+      "name": "qps_openloop_test",
       "build": "test",
       "language": "c++",
       "src": [
-        "test/cpp/qps/qps_test.cc"
+        "test/cpp/qps/qps_openloop_test.cc"
       ],
       "deps": [
         "qps",
@@ -2312,11 +2327,11 @@
       ]
     },
     {
-      "name": "qps_test_openloop",
+      "name": "qps_test",
       "build": "test",
       "language": "c++",
       "src": [
-        "test/cpp/qps/qps_test_openloop.cc"
+        "test/cpp/qps/qps_test.cc"
       ],
       "deps": [
         "qps",
diff --git a/doc/connection-backoff.md b/doc/connection-backoff.md
index 47b71f9..7094e73 100644
--- a/doc/connection-backoff.md
+++ b/doc/connection-backoff.md
@@ -8,58 +8,39 @@
 We have several parameters:
  1. INITIAL_BACKOFF (how long to wait after the first failure before retrying)
  2. MULTIPLIER (factor with which to multiply backoff after a failed retry)
- 3. MAX_BACKOFF (Upper bound on backoff)
- 4. MIN_CONNECTION_TIMEOUT
+ 3. MAX_BACKOFF (upper bound on backoff)
+ 4. MIN_CONNECT_TIMEOUT (minimum time we're willing to give a connection to
+    complete)
 
 ## Proposed Backoff Algorithm
 
 Exponentially back off the start time of connection attempts up to a limit of
-MAX_BACKOFF.
+MAX_BACKOFF, with jitter.
 
 ```
 ConnectWithBackoff()
   current_backoff = INITIAL_BACKOFF
   current_deadline = now() + INITIAL_BACKOFF
-  while (TryConnect(Max(current_deadline, MIN_CONNECT_TIMEOUT))
+  while (TryConnect(Max(current_deadline, now() + MIN_CONNECT_TIMEOUT))
          != SUCCESS)
     SleepUntil(current_deadline)
     current_backoff = Min(current_backoff * MULTIPLIER, MAX_BACKOFF)
-    current_deadline = now() + current_backoff
-```
-
-## Historical Algorithm in Stubby
-
-Exponentially increase up to a limit of MAX_BACKOFF the intervals between
-connection attempts. This is what stubby 2 uses, and is equivalent if
-TryConnect() fails instantly.
+    current_deadline = now() + current_backoff +
+      UniformRandom(-JITTER * current_backoff, JITTER * current_backoff)
 
 ```
-LegacyConnectWithBackoff()
-  current_backoff = INITIAL_BACKOFF
-  while (TryConnect(MIN_CONNECT_TIMEOUT) != SUCCESS)
-    SleepFor(current_backoff)
-    current_backoff = Min(current_backoff * MULTIPLIER, MAX_BACKOFF)
-```
 
-The grpc C implementation currently uses this approach with an initial backoff
-of 1 second, multiplier of 2, and maximum backoff of 120 seconds. (This will
-change)
+With specific parameters of
+MIN_CONNECT_TIMEOUT = 20 seconds
+INITIAL_BACKOFF = 1 second
+MULTIPLIER = 1.6
+MAX_BACKOFF = 120 seconds
+JITTER = 0.2
 
-Stubby, or at least rpc2, uses exactly this algorithm with an initial backoff
-of 1 second, multiplier of 1.2, and a maximum backoff of 120 seconds.
+Implementations with pressing concerns (such as minimizing the number of wakeups
+on a mobile phone) may wish to use a different algorithm, and in particular
+different jitter logic.
 
-## Use Cases to Consider
-
-* Client tries to connect to a server which is down for multiple hours, eg for
-  maintenance
-* Client tries to connect to a server which is overloaded
-* User is bringing up both a client and a server at the same time
-    * In particular, we would like to avoid a large unnecessary delay if the
-      client connects to a server which is about to come up
-* Client/server are misconfigured such that connection attempts always fail
-    * We want to make sure these don’t put too much load on the server by
-      default.
-* Server is overloaded and wants to transiently make clients back off
-* Application has out of band reason to believe a server is back
-    * We should consider an out of band mechanism for the client to hint that
-      we should short circuit the backoff.
+Alternate implementations must ensure that connection backoffs started at the
+same time disperse, and must not attempt connections substantially more often
+than the above algorithm.
diff --git a/gRPC.podspec b/gRPC.podspec
index 921a4ab..34fbccf 100644
--- a/gRPC.podspec
+++ b/gRPC.podspec
@@ -64,6 +64,7 @@
     ss.source_files = '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/grpc_string.h',
                       'src/core/support/string_win32.h',
                       'src/core/support/thd_internal.h',
@@ -118,6 +119,7 @@
                       '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',
@@ -357,6 +359,7 @@
                       'src/core/surface/server_chttp2.c',
                       'src/core/surface/server_create.c',
                       'src/core/surface/surface_trace.c',
+                      'src/core/surface/version.c',
                       'src/core/transport/chttp2/alpn.c',
                       'src/core/transport/chttp2/bin_encoder.c',
                       'src/core/transport/chttp2/frame_data.c',
@@ -389,6 +392,7 @@
     ss.private_header_files = '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',
diff --git a/include/grpc++/impl/call.h b/include/grpc++/impl/call.h
index 64fa5d6..1fa4490 100644
--- a/include/grpc++/impl/call.h
+++ b/include/grpc++/impl/call.h
@@ -60,6 +60,93 @@
 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 gpr_uint32 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 gpr_int32 mask) {
+    flags_ |= mask;
+  }
+
+  void ClearBit(const gpr_int32 mask) {
+    flags_ &= ~mask;
+  }
+
+  bool GetBit(const gpr_int32 mask) const {
+    return flags_ & mask;
+  }
+
+  gpr_uint32 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>
@@ -104,6 +191,12 @@
  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;
 
@@ -112,8 +205,10 @@
     if (send_buf_ == nullptr) return;
     grpc_op* op = &ops[(*nops)++];
     op->op = GRPC_OP_SEND_MESSAGE;
-    op->flags = 0;
+    op->flags = write_options_.flags();
     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_);
@@ -122,14 +217,22 @@
 
  private:
   grpc_byte_buffer* send_buf_;
+  WriteOptions write_options_;
   bool own_buf_;
 };
 
 template <class M>
-Status CallOpSendMessage::SendMessage(const M& message) {
+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:
@@ -172,17 +275,34 @@
   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_ = [message](grpc_byte_buffer* buf,
-                             int max_message_size) -> Status {
-      return SerializationTraits<R>::Deserialize(buf, message,
-                                                 max_message_size);
-    };
+    deserialize_.reset(
+        new CallOpGenericRecvMessageHelper::DeserializeFuncType<R>(message));
   }
 
   bool got_message;
@@ -201,7 +321,7 @@
     if (recv_buf_) {
       if (*status) {
         got_message = true;
-        *status = deserialize_(recv_buf_, max_message_size).ok();
+        *status = deserialize_->Deserialize(recv_buf_, max_message_size).ok();
       } else {
         got_message = false;
         grpc_byte_buffer_destroy(recv_buf_);
@@ -210,12 +330,11 @@
       got_message = false;
       *status = false;
     }
-    deserialize_ = DeserializeFunc();
+    deserialize_.reset();
   }
 
  private:
-  typedef std::function<Status(grpc_byte_buffer*, int)> DeserializeFunc;
-  DeserializeFunc deserialize_;
+  std::unique_ptr<CallOpGenericRecvMessageHelper::DeserializeFunc> deserialize_;
   grpc_byte_buffer* recv_buf_;
 };
 
diff --git a/include/grpc++/server_context.h b/include/grpc++/server_context.h
index a4ee986..2123d03 100644
--- a/include/grpc++/server_context.h
+++ b/include/grpc++/server_context.h
@@ -99,9 +99,7 @@
     return client_metadata_;
   }
 
-  std::shared_ptr<const AuthContext> auth_context() const {
-    return auth_context_;
-  }
+  std::shared_ptr<const AuthContext> auth_context() const;
 
  private:
   friend class ::grpc::Server;
@@ -147,7 +145,7 @@
   grpc_call* call_;
   CompletionQueue* cq_;
   bool sent_initial_metadata_;
-  std::shared_ptr<const AuthContext> auth_context_;
+  mutable std::shared_ptr<const AuthContext> auth_context_;
   std::multimap<grpc::string, grpc::string> client_metadata_;
   std::multimap<grpc::string, grpc::string> initial_metadata_;
   std::multimap<grpc::string, grpc::string> trailing_metadata_;
diff --git a/include/grpc++/stream.h b/include/grpc++/stream.h
index dd5e52d..3903f2e 100644
--- a/include/grpc++/stream.h
+++ b/include/grpc++/stream.h
@@ -79,7 +79,11 @@
 
   // Blocking write msg to the stream. Returns true on success.
   // Returns false when the stream has been closed.
-  virtual bool Write(const W& msg) = 0;
+  virtual bool Write(const W& msg, const WriteOptions& options) = 0;
+
+  inline bool Write(const W& msg) {
+    return Write(msg, WriteOptions());
+  }
 };
 
 template <class R>
@@ -168,9 +172,10 @@
     cq_.Pluck(&ops);
   }
 
-  bool Write(const W& msg) GRPC_OVERRIDE {
+  using WriterInterface<W>::Write;
+  bool Write(const W& msg, const WriteOptions& options) GRPC_OVERRIDE {
     CallOpSet<CallOpSendMessage> ops;
-    if (!ops.SendMessage(msg).ok()) {
+    if (!ops.SendMessage(msg, options).ok()) {
       return false;
     }
     call_.PerformOps(&ops);
@@ -246,9 +251,10 @@
     return cq_.Pluck(&ops) && ops.got_message;
   }
 
-  bool Write(const W& msg) GRPC_OVERRIDE {
+  using WriterInterface<W>::Write;
+  bool Write(const W& msg, const WriteOptions& options) GRPC_OVERRIDE {
     CallOpSet<CallOpSendMessage> ops;
-    if (!ops.SendMessage(msg).ok()) return false;
+    if (!ops.SendMessage(msg, options).ok()) return false;
     call_.PerformOps(&ops);
     return cq_.Pluck(&ops);
   }
@@ -317,9 +323,10 @@
     call_->cq()->Pluck(&ops);
   }
 
-  bool Write(const W& msg) GRPC_OVERRIDE {
+  using WriterInterface<W>::Write;
+  bool Write(const W& msg, const WriteOptions& options) GRPC_OVERRIDE {
     CallOpSet<CallOpSendInitialMetadata, CallOpSendMessage> ops;
-    if (!ops.SendMessage(msg).ok()) {
+    if (!ops.SendMessage(msg, options).ok()) {
       return false;
     }
     if (!ctx_->sent_initial_metadata_) {
@@ -359,9 +366,10 @@
     return call_->cq()->Pluck(&ops) && ops.got_message;
   }
 
-  bool Write(const W& msg) GRPC_OVERRIDE {
+  using WriterInterface<W>::Write;
+  bool Write(const W& msg, const WriteOptions& options) GRPC_OVERRIDE {
     CallOpSet<CallOpSendInitialMetadata, CallOpSendMessage> ops;
-    if (!ops.SendMessage(msg).ok()) {
+    if (!ops.SendMessage(msg, options).ok()) {
       return false;
     }
     if (!ctx_->sent_initial_metadata_) {
diff --git a/include/grpc/grpc.h b/include/grpc/grpc.h
index 782923d..3c72c1d 100644
--- a/include/grpc/grpc.h
+++ b/include/grpc/grpc.h
@@ -351,6 +351,9 @@
     destroyed. */
 void grpc_shutdown(void);
 
+/** Return a string representing the current version of grpc */
+const char *grpc_version_string(void);
+
 /** Create a completion queue */
 grpc_completion_queue *grpc_completion_queue_create(void);
 
diff --git a/include/grpc/support/port_platform.h b/include/grpc/support/port_platform.h
index d3cfee1..a5d1b62 100644
--- a/include/grpc/support/port_platform.h
+++ b/include/grpc/support/port_platform.h
@@ -82,6 +82,7 @@
 #define GPR_WIN32_ATOMIC 1
 #define GPR_MSVC_TLS 1
 #endif
+#define GPR_WINDOWS_CRASH_HANDLER 1
 #elif defined(_WIN32) || defined(WIN32)
 #define GPR_ARCH_32 1
 #define GPR_WIN32 1
@@ -94,6 +95,7 @@
 #define GPR_WIN32_ATOMIC 1
 #define GPR_MSVC_TLS 1
 #endif
+#define GPR_WINDOWS_CRASH_HANDLER 1
 #elif defined(ANDROID) || defined(__ANDROID__)
 #define GPR_ANDROID 1
 #define GPR_ARCH_32 1
diff --git a/include/grpc/support/time.h b/include/grpc/support/time.h
index 1fd3181..a5c947d 100644
--- a/include/grpc/support/time.h
+++ b/include/grpc/support/time.h
@@ -46,8 +46,8 @@
 #endif
 
 typedef struct gpr_timespec {
-    time_t tv_sec;
-    int tv_nsec;
+  time_t tv_sec;
+  int tv_nsec;
 } gpr_timespec;
 
 /* Time constants. */
@@ -62,8 +62,20 @@
 #define GPR_NS_PER_US 1000
 #define GPR_US_PER_MS 1000
 
-/* Return the current time measured from the system's default epoch. */
-gpr_timespec gpr_now(void);
+/* 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
+} gpr_clock_type;
+
+/* 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);
 
 /* Return -ve, 0, or +ve according to whether a < b, a == b, or a > b
    respectively.  */
@@ -100,4 +112,4 @@
 }
 #endif
 
-#endif  /* GRPC_SUPPORT_TIME_H */
+#endif /* GRPC_SUPPORT_TIME_H */
diff --git a/src/compiler/objective_c_generator.cc b/src/compiler/objective_c_generator.cc
index 79a84b4..2a74a3b 100644
--- a/src/compiler/objective_c_generator.cc
+++ b/src/compiler/objective_c_generator.cc
@@ -57,13 +57,12 @@
   vars["server_stream"] = method->server_streaming() ? "stream " : "";
 
   printer->Print(vars,
-      "#pragma mark $method_name$($client_stream$$request_type$)"
-      " returns ($server_stream$$response_type$)\n\n");
+                 "#pragma mark $method_name$($client_stream$$request_type$)"
+                 " returns ($server_stream$$response_type$)\n\n");
 }
 
-void PrintMethodSignature(Printer *printer,
-                          const MethodDescriptor *method,
-                          const map<string, string>& vars) {
+void PrintMethodSignature(Printer *printer, const MethodDescriptor *method,
+                          const map<string, string> &vars) {
   // TODO(jcanizales): Print method comments.
 
   printer->Print(vars, "- ($return_type$)$method_name$With");
@@ -75,16 +74,17 @@
 
   // TODO(jcanizales): Put this on a new line and align colons.
   if (method->server_streaming()) {
-    printer->Print(vars, " eventHandler:(void(^)(BOOL done, "
-      "$response_class$ *response, NSError *error))eventHandler");
+    printer->Print(vars,
+                   " eventHandler:(void(^)(BOOL done, "
+                   "$response_class$ *response, NSError *error))eventHandler");
   } else {
-    printer->Print(vars, " handler:(void(^)($response_class$ *response, "
-      "NSError *error))handler");
+    printer->Print(vars,
+                   " handler:(void(^)($response_class$ *response, "
+                   "NSError *error))handler");
   }
 }
 
-void PrintSimpleSignature(Printer *printer,
-                          const MethodDescriptor *method,
+void PrintSimpleSignature(Printer *printer, const MethodDescriptor *method,
                           map<string, string> vars) {
   vars["method_name"] =
       grpc_generator::LowercaseFirstLetter(vars["method_name"]);
@@ -92,8 +92,7 @@
   PrintMethodSignature(printer, method, vars);
 }
 
-void PrintAdvancedSignature(Printer *printer,
-                            const MethodDescriptor *method,
+void PrintAdvancedSignature(Printer *printer, const MethodDescriptor *method,
                             map<string, string> vars) {
   vars["method_name"] = "RPCTo" + vars["method_name"];
   vars["return_type"] = "ProtoRPC *";
@@ -101,15 +100,16 @@
 }
 
 inline map<string, string> GetMethodVars(const MethodDescriptor *method) {
-  return {{ "method_name", method->name() },
-          { "request_type", method->input_type()->name() },
-          { "response_type", method->output_type()->name() },
-          { "request_class", ClassName(method->input_type()) },
-          { "response_class", ClassName(method->output_type()) }};
+  map<string, string> res;
+  res["method_name"] = method->name();
+  res["request_type"] = method->input_type()->name();
+  res["response_type"] = method->output_type()->name();
+  res["request_class"] = ClassName(method->input_type());
+  res["response_class"] = ClassName(method->output_type());
+  return res;
 }
 
-void PrintMethodDeclarations(Printer *printer,
-                             const MethodDescriptor *method) {
+void PrintMethodDeclarations(Printer *printer, const MethodDescriptor *method) {
   map<string, string> vars = GetMethodVars(method);
 
   PrintProtoRpcDeclarationAsPragma(printer, method, vars);
@@ -120,8 +120,7 @@
   printer->Print(";\n\n\n");
 }
 
-void PrintSimpleImplementation(Printer *printer,
-                               const MethodDescriptor *method,
+void PrintSimpleImplementation(Printer *printer, const MethodDescriptor *method,
                                map<string, string> vars) {
   printer->Print("{\n");
   printer->Print(vars, "  [[self RPCTo$method_name$With");
@@ -178,7 +177,7 @@
   PrintAdvancedImplementation(printer, method, vars);
 }
 
-} // namespace
+}  // namespace
 
 string GetHeader(const ServiceDescriptor *service) {
   string output;
@@ -186,7 +185,7 @@
     // Scope the output stream so it closes and finalizes output to the string.
     grpc::protobuf::io::StringOutputStream output_stream(&output);
     Printer printer(&output_stream, '$');
-  
+
     printer.Print("@protocol GRXWriteable;\n");
     printer.Print("@protocol GRXWriter;\n\n");
 
@@ -199,12 +198,15 @@
     }
     printer.Print("@end\n\n");
 
-    printer.Print("// Basic service implementation, over gRPC, that only does"
+    printer.Print(
+        "// Basic service implementation, over gRPC, that only does"
         " marshalling and parsing.\n");
-    printer.Print(vars, "@interface $service_class$ :"
-      " ProtoService<$service_class$>\n");
-    printer.Print("- (instancetype)initWithHost:(NSString *)host"
-      " NS_DESIGNATED_INITIALIZER;\n");
+    printer.Print(vars,
+                  "@interface $service_class$ :"
+                  " ProtoService<$service_class$>\n");
+    printer.Print(
+        "- (instancetype)initWithHost:(NSString *)host"
+        " NS_DESIGNATED_INITIALIZER;\n");
     printer.Print("@end\n");
   }
   return output;
@@ -222,18 +224,20 @@
                                 {"package", service->file()->package()}};
 
     printer.Print(vars,
-        "static NSString *const kPackageName = @\"$package$\";\n");
-    printer.Print(vars,
-        "static NSString *const kServiceName = @\"$service_name$\";\n\n");
+                  "static NSString *const kPackageName = @\"$package$\";\n");
+    printer.Print(
+        vars, "static NSString *const kServiceName = @\"$service_name$\";\n\n");
 
     printer.Print(vars, "@implementation $service_class$\n\n");
-  
+
     printer.Print("// Designated initializer\n");
     printer.Print("- (instancetype)initWithHost:(NSString *)host {\n");
-    printer.Print("  return (self = [super initWithHost:host"
+    printer.Print(
+        "  return (self = [super initWithHost:host"
         " packageName:kPackageName serviceName:kServiceName]);\n");
     printer.Print("}\n\n");
-    printer.Print("// Override superclass initializer to disallow different"
+    printer.Print(
+        "// Override superclass initializer to disallow different"
         " package and service names.\n");
     printer.Print("- (instancetype)initWithHost:(NSString *)host\n");
     printer.Print("                 packageName:(NSString *)packageName\n");
@@ -250,4 +254,4 @@
   return output;
 }
 
-} // namespace grpc_objective_c_generator
+}  // namespace grpc_objective_c_generator
diff --git a/src/core/channel/census_filter.c b/src/core/channel/census_filter.c
index 43ef5fb..d996c34 100644
--- a/src/core/channel/census_filter.c
+++ b/src/core/channel/census_filter.c
@@ -151,7 +151,7 @@
   call_data* d = elem->call_data;
   GPR_ASSERT(d != NULL);
   init_rpc_stats(&d->stats);
-  d->start_ts = gpr_now();
+  d->start_ts = gpr_now(GPR_CLOCK_REALTIME);
   d->op_id = census_tracing_start_op();
   if (initial_op) client_mutate_op(elem, initial_op);
 }
@@ -169,7 +169,7 @@
   call_data* d = elem->call_data;
   GPR_ASSERT(d != NULL);
   init_rpc_stats(&d->stats);
-  d->start_ts = gpr_now();
+  d->start_ts = gpr_now(GPR_CLOCK_REALTIME);
   d->op_id = census_tracing_start_op();
   if (initial_op) server_mutate_op(elem, initial_op);
 }
@@ -177,8 +177,8 @@
 static void server_destroy_call_elem(grpc_call_element* elem) {
   call_data* d = elem->call_data;
   GPR_ASSERT(d != NULL);
-  d->stats.elapsed_time_ms =
-      gpr_timespec_to_micros(gpr_time_sub(gpr_now(), d->start_ts));
+  d->stats.elapsed_time_ms = gpr_timespec_to_micros(
+      gpr_time_sub(gpr_now(GPR_CLOCK_REALTIME), d->start_ts));
   census_record_rpc_server_stats(d->op_id, &d->stats);
   census_tracing_end_op(d->op_id);
 }
diff --git a/src/core/client_config/subchannel.c b/src/core/client_config/subchannel.c
index 6cf9062..8cdad10 100644
--- a/src/core/client_config/subchannel.c
+++ b/src/core/client_config/subchannel.c
@@ -300,7 +300,7 @@
 }
 
 static void start_connect(grpc_subchannel *c) {
-  gpr_timespec now = gpr_now();
+  gpr_timespec now = gpr_now(GPR_CLOCK_REALTIME);
   c->next_attempt = now;
   c->backoff_delta = gpr_time_from_seconds(1);
 
@@ -585,7 +585,7 @@
     c->have_alarm = 1;
     c->next_attempt = gpr_time_add(c->next_attempt, c->backoff_delta);
     c->backoff_delta = gpr_time_add(c->backoff_delta, c->backoff_delta);
-    grpc_alarm_init(&c->alarm, c->next_attempt, on_alarm, c, gpr_now());
+    grpc_alarm_init(&c->alarm, c->next_attempt, on_alarm, c, gpr_now(GPR_CLOCK_REALTIME));
     gpr_mu_unlock(&c->mu);
   }
 }
diff --git a/src/core/iomgr/iocp_windows.c b/src/core/iomgr/iocp_windows.c
index 0c62bfc..3d3a193 100644
--- a/src/core/iomgr/iocp_windows.c
+++ b/src/core/iomgr/iocp_windows.c
@@ -127,7 +127,6 @@
     grpc_maybe_call_delayed_callbacks(NULL, 1);
     do_iocp_work();
   }
-  gpr_log(GPR_DEBUG, "iocp_loop is done");
 
   gpr_event_set(&g_iocp_done, (void *)1);
 }
diff --git a/src/core/iomgr/iomgr.c b/src/core/iomgr/iomgr.c
index 4a2c45a..cca92d3 100644
--- a/src/core/iomgr/iomgr.c
+++ b/src/core/iomgr/iomgr.c
@@ -59,7 +59,7 @@
   while (!g_shutdown) {
     gpr_timespec deadline = gpr_inf_future;
     gpr_timespec short_deadline =
-        gpr_time_add(gpr_now(), gpr_time_from_millis(100));
+        gpr_time_add(gpr_now(GPR_CLOCK_REALTIME), gpr_time_from_millis(100));
     if (g_cbs_head) {
       grpc_iomgr_closure *closure = g_cbs_head;
       g_cbs_head = closure->next;
@@ -67,7 +67,8 @@
       gpr_mu_unlock(&g_mu);
       closure->cb(closure->cb_arg, closure->success);
       gpr_mu_lock(&g_mu);
-    } else if (grpc_alarm_check(&g_mu, gpr_now(), &deadline)) {
+    } else if (grpc_alarm_check(&g_mu, gpr_now(GPR_CLOCK_REALTIME),
+                                &deadline)) {
     } else {
       gpr_mu_unlock(&g_mu);
       gpr_sleep_until(gpr_time_min(short_deadline, deadline));
@@ -89,7 +90,7 @@
   gpr_thd_id id;
   gpr_mu_init(&g_mu);
   gpr_cv_init(&g_rcv);
-  grpc_alarm_list_init(gpr_now());
+  grpc_alarm_list_init(gpr_now(GPR_CLOCK_REALTIME));
   g_root_object.next = g_root_object.prev = &g_root_object;
   g_root_object.name = "root";
   grpc_iomgr_platform_init();
@@ -110,26 +111,27 @@
   grpc_iomgr_object *obj;
   grpc_iomgr_closure *closure;
   gpr_timespec shutdown_deadline =
-      gpr_time_add(gpr_now(), gpr_time_from_seconds(10));
-  gpr_timespec last_warning_time = gpr_now();
+      gpr_time_add(gpr_now(GPR_CLOCK_REALTIME), gpr_time_from_seconds(10));
+  gpr_timespec last_warning_time = gpr_now(GPR_CLOCK_REALTIME);
 
   gpr_mu_lock(&g_mu);
   g_shutdown = 1;
   while (g_cbs_head != NULL || g_root_object.next != &g_root_object) {
-    if (gpr_time_cmp(gpr_time_sub(gpr_now(), last_warning_time),
-                     gpr_time_from_seconds(1)) >= 0) {
-    if (g_cbs_head != NULL && g_root_object.next != &g_root_object) {
-      gpr_log(GPR_DEBUG,
-              "Waiting for %d iomgr objects to be destroyed and executing "
-              "final callbacks",
-              count_objects());
-    } else if (g_cbs_head != NULL) {
-      gpr_log(GPR_DEBUG, "Executing final iomgr callbacks");
-    } else {
-      gpr_log(GPR_DEBUG, "Waiting for %d iomgr objects to be destroyed",
-              count_objects());
-    }
-    last_warning_time = gpr_now();
+    if (gpr_time_cmp(
+            gpr_time_sub(gpr_now(GPR_CLOCK_REALTIME), last_warning_time),
+            gpr_time_from_seconds(1)) >= 0) {
+      if (g_cbs_head != NULL && g_root_object.next != &g_root_object) {
+        gpr_log(GPR_DEBUG,
+                "Waiting for %d iomgr objects to be destroyed and executing "
+                "final callbacks",
+                count_objects());
+      } else if (g_cbs_head != NULL) {
+        gpr_log(GPR_DEBUG, "Executing final iomgr callbacks");
+      } else {
+        gpr_log(GPR_DEBUG, "Waiting for %d iomgr objects to be destroyed",
+                count_objects());
+      }
+      last_warning_time = gpr_now(GPR_CLOCK_REALTIME);
     }
     if (g_cbs_head) {
       do {
@@ -150,9 +152,9 @@
     if (g_root_object.next != &g_root_object) {
       int timeout = 0;
       gpr_timespec short_deadline =
-          gpr_time_add(gpr_now(), gpr_time_from_millis(100));
+          gpr_time_add(gpr_now(GPR_CLOCK_REALTIME), gpr_time_from_millis(100));
       while (gpr_cv_wait(&g_rcv, &g_mu, short_deadline) && g_cbs_head == NULL) {
-        if (gpr_time_cmp(gpr_now(), shutdown_deadline) > 0) {
+        if (gpr_time_cmp(gpr_now(GPR_CLOCK_REALTIME), shutdown_deadline) > 0) {
           timeout = 1;
           break;
         }
diff --git a/src/core/iomgr/pollset_multipoller_with_epoll.c b/src/core/iomgr/pollset_multipoller_with_epoll.c
index 1900bbf..3746c8e 100644
--- a/src/core/iomgr/pollset_multipoller_with_epoll.c
+++ b/src/core/iomgr/pollset_multipoller_with_epoll.c
@@ -105,10 +105,11 @@
    * here.
    */
 
-  timeout_ms = grpc_poll_deadline_to_millis_timeout(deadline, now);
   pollset->counter += 1;
   gpr_mu_unlock(&pollset->mu);
 
+  timeout_ms = grpc_poll_deadline_to_millis_timeout(deadline, now);
+
   do {
     ep_rv = epoll_wait(h->epoll_fd, ep_ev, GRPC_EPOLL_MAX_EVENTS, timeout_ms);
     if (ep_rv < 0) {
diff --git a/src/core/iomgr/pollset_posix.c b/src/core/iomgr/pollset_posix.c
index 1249644..8510176 100644
--- a/src/core/iomgr/pollset_posix.c
+++ b/src/core/iomgr/pollset_posix.c
@@ -122,7 +122,7 @@
 
 int grpc_pollset_work(grpc_pollset *pollset, gpr_timespec deadline) {
   /* pollset->mu already held */
-  gpr_timespec now = gpr_now();
+  gpr_timespec now = gpr_now(GPR_CLOCK_REALTIME);
   if (gpr_time_cmp(now, deadline) > 0) {
     return 0;
   }
@@ -187,15 +187,16 @@
   gpr_mu_destroy(&pollset->mu);
 }
 
-int grpc_poll_deadline_to_millis_timeout(gpr_timespec deadline, gpr_timespec now) {
+int grpc_poll_deadline_to_millis_timeout(gpr_timespec deadline,
+                                         gpr_timespec now) {
   gpr_timespec timeout;
   static const int max_spin_polling_us = 10;
   if (gpr_time_cmp(deadline, gpr_inf_future) == 0) {
     return -1;
   }
   if (gpr_time_cmp(
-        deadline, 
-        gpr_time_add(now, gpr_time_from_micros(max_spin_polling_us))) <= 0) {
+          deadline,
+          gpr_time_add(now, gpr_time_from_micros(max_spin_polling_us))) <= 0) {
     return 0;
   }
   timeout = gpr_time_sub(deadline, now);
diff --git a/src/core/iomgr/pollset_windows.c b/src/core/iomgr/pollset_windows.c
index 8d6bc79..24226cc 100644
--- a/src/core/iomgr/pollset_windows.c
+++ b/src/core/iomgr/pollset_windows.c
@@ -70,7 +70,7 @@
 
 int grpc_pollset_work(grpc_pollset *pollset, gpr_timespec deadline) {
   gpr_timespec now;
-  now = gpr_now();
+  now = gpr_now(GPR_CLOCK_REALTIME);
   if (gpr_time_cmp(now, deadline) > 0) {
     return 0 /* GPR_FALSE */;
   }
@@ -86,8 +86,6 @@
   return 1 /* GPR_TRUE */;
 }
 
-void grpc_pollset_kick(grpc_pollset *p) {
-  gpr_cv_signal(&p->cv);
-}
+void grpc_pollset_kick(grpc_pollset *p) { gpr_cv_signal(&p->cv); }
 
 #endif /* GPR_WINSOCK_SOCKET */
diff --git a/src/core/iomgr/socket_windows.c b/src/core/iomgr/socket_windows.c
index 897408d..f6ddfff 100644
--- a/src/core/iomgr/socket_windows.c
+++ b/src/core/iomgr/socket_windows.c
@@ -37,6 +37,7 @@
 
 #include <grpc/support/alloc.h>
 #include <grpc/support/log.h>
+#include <grpc/support/string_util.h>
 
 #include "src/core/iomgr/iocp_windows.h"
 #include "src/core/iomgr/iomgr_internal.h"
@@ -61,22 +62,27 @@
    operations to abort them. We need to do that this way because of the
    various callsites of that function, which happens to be in various
    mutex hold states, and that'd be unsafe to call them directly. */
-int grpc_winsocket_shutdown(grpc_winsocket *socket) {
+int grpc_winsocket_shutdown(grpc_winsocket *winsocket) {
   int callbacks_set = 0;
-  gpr_mu_lock(&socket->state_mu);
-  if (socket->read_info.cb) {
+  SOCKET socket;
+  gpr_mu_lock(&winsocket->state_mu);
+  socket = winsocket->socket;
+  if (winsocket->read_info.cb) {
     callbacks_set++;
-    grpc_iomgr_closure_init(&socket->shutdown_closure, socket->read_info.cb,
-                            socket->read_info.opaque);
-    grpc_iomgr_add_delayed_callback(&socket->shutdown_closure, 0);
+    grpc_iomgr_closure_init(&winsocket->shutdown_closure,
+                            winsocket->read_info.cb,
+                            winsocket->read_info.opaque);
+    grpc_iomgr_add_delayed_callback(&winsocket->shutdown_closure, 0);
   }
-  if (socket->write_info.cb) {
+  if (winsocket->write_info.cb) {
     callbacks_set++;
-    grpc_iomgr_closure_init(&socket->shutdown_closure, socket->write_info.cb,
-                            socket->write_info.opaque);
-    grpc_iomgr_add_delayed_callback(&socket->shutdown_closure, 0);
+    grpc_iomgr_closure_init(&winsocket->shutdown_closure,
+                            winsocket->write_info.cb,
+                            winsocket->write_info.opaque);
+    grpc_iomgr_add_delayed_callback(&winsocket->shutdown_closure, 0);
   }
-  gpr_mu_unlock(&socket->state_mu);
+  gpr_mu_unlock(&winsocket->state_mu);
+  closesocket(socket);
   return callbacks_set;
 }
 
@@ -87,14 +93,12 @@
    an "idle" socket which is neither trying to read or write, we'd start leaking
    both memory and sockets. */
 void grpc_winsocket_orphan(grpc_winsocket *winsocket) {
-  SOCKET socket = winsocket->socket;
   grpc_iomgr_unregister_object(&winsocket->iomgr_object);
   if (winsocket->read_info.outstanding || winsocket->write_info.outstanding) {
     grpc_iocp_socket_orphan(winsocket);
   } else {
     grpc_winsocket_destroy(winsocket);
   }
-  closesocket(socket);
 }
 
 void grpc_winsocket_destroy(grpc_winsocket *winsocket) {
diff --git a/src/core/iomgr/tcp_client_posix.c b/src/core/iomgr/tcp_client_posix.c
index d981aaf..dc0489e 100644
--- a/src/core/iomgr/tcp_client_posix.c
+++ b/src/core/iomgr/tcp_client_posix.c
@@ -114,6 +114,7 @@
   void (*cb)(void *arg, grpc_endpoint *tcp) = ac->cb;
   void *cb_arg = ac->cb_arg;
 
+  gpr_mu_lock(&ac->mu);
   if (success) {
     do {
       so_error_size = sizeof(so_error);
@@ -139,6 +140,7 @@
            opened too many network connections.  The "easy" fix:
            don't do that! */
         gpr_log(GPR_ERROR, "kernel out of buffers");
+        gpr_mu_unlock(&ac->mu);
         grpc_fd_notify_on_write(ac->fd, &ac->write_closure);
         return;
       } else {
@@ -165,10 +167,11 @@
   abort();
 
 finish:
-  gpr_mu_lock(&ac->mu);
-  if (!ep) {
+  if (ep == NULL) {
     grpc_pollset_set_del_fd(ac->interested_parties, ac->fd);
     grpc_fd_orphan(ac->fd, NULL, "tcp_client_orphan");
+  } else {
+    ac->fd = NULL;
   }
   done = (--ac->refs == 0);
   gpr_mu_unlock(&ac->mu);
@@ -250,7 +253,8 @@
   ac->write_closure.cb_arg = ac;
 
   gpr_mu_lock(&ac->mu);
-  grpc_alarm_init(&ac->alarm, deadline, on_alarm, ac, gpr_now());
+  grpc_alarm_init(&ac->alarm, deadline, on_alarm, ac,
+                  gpr_now(GPR_CLOCK_REALTIME));
   grpc_fd_notify_on_write(ac->fd, &ac->write_closure);
   gpr_mu_unlock(&ac->mu);
 
diff --git a/src/core/iomgr/tcp_client_windows.c b/src/core/iomgr/tcp_client_windows.c
index b1a169b..1674145 100644
--- a/src/core/iomgr/tcp_client_windows.c
+++ b/src/core/iomgr/tcp_client_windows.c
@@ -215,7 +215,8 @@
   ac->refs = 2;
   ac->aborted = 0;
 
-  grpc_alarm_init(&ac->alarm, deadline, on_alarm, ac, gpr_now());
+  grpc_alarm_init(&ac->alarm, deadline, on_alarm, ac,
+                  gpr_now(GPR_CLOCK_REALTIME));
   socket->write_info.outstanding = 1;
   grpc_socket_notify_on_write(socket, on_connect, ac);
   return;
diff --git a/src/core/iomgr/tcp_server_windows.c b/src/core/iomgr/tcp_server_windows.c
index d70968d..e6e1d14 100644
--- a/src/core/iomgr/tcp_server_windows.c
+++ b/src/core/iomgr/tcp_server_windows.c
@@ -108,9 +108,10 @@
   size_t i;
   gpr_mu_lock(&s->mu);
   /* First, shutdown all fd's. This will queue abortion calls for all
-     of the pending accepts. */
+     of the pending accepts due to the normal operation mechanism. */
   for (i = 0; i < s->nports; i++) {
     server_port *sp = &s->ports[i];
+    sp->shutting_down = 1;
     grpc_winsocket_shutdown(sp->socket);
   }
   /* This happens asynchronously. Wait while that happens. */
@@ -242,63 +243,52 @@
   SOCKET sock = sp->new_socket;
   grpc_winsocket_callback_info *info = &sp->socket->read_info;
   grpc_endpoint *ep = NULL;
+  DWORD transfered_bytes;
+  DWORD flags;
+  BOOL wsa_success;
 
-  /* The shutdown sequence is done in two parts. This is the second
-     part here, acknowledging the IOCP notification, and doing nothing
-     else, especially not queuing a new accept. */
-  if (sp->shutting_down) {
-    GPR_ASSERT(from_iocp);
-    sp->shutting_down = 0;
-    sp->socket->read_info.outstanding = 0;
-    gpr_mu_lock(&sp->server->mu);
-    if (0 == --sp->server->active_ports) {
-      gpr_cv_broadcast(&sp->server->cv);
-    }
-    gpr_mu_unlock(&sp->server->mu);
-    return;
-  }
+  /* The general mechanism for shutting down is to queue abortion calls. While
+     this is necessary in the read/write case, it's useless for the accept
+     case. Let's do nothing. */
+  if (!from_iocp) return;
 
-  if (from_iocp) {
-    /* The IOCP notified us of a completed operation. Let's grab the results,
-       and act accordingly. */
-    DWORD transfered_bytes = 0;
-    DWORD flags;
-    BOOL wsa_success = WSAGetOverlappedResult(sock, &info->overlapped,
-                                              &transfered_bytes, FALSE, &flags);
-    if (!wsa_success) {
+  /* The IOCP notified us of a completed operation. Let's grab the results,
+      and act accordingly. */
+  transfered_bytes = 0;
+  wsa_success = WSAGetOverlappedResult(sock, &info->overlapped,
+                                            &transfered_bytes, FALSE, &flags);
+  if (!wsa_success) {
+    if (sp->shutting_down) {
+      /* During the shutdown case, we ARE expecting an error. So that's swell,
+         and we can wake up the shutdown thread. */
+      sp->shutting_down = 0;
+      sp->socket->read_info.outstanding = 0;
+      gpr_mu_lock(&sp->server->mu);
+      if (0 == --sp->server->active_ports) {
+        gpr_cv_broadcast(&sp->server->cv);
+      }
+      gpr_mu_unlock(&sp->server->mu);
+      return;
+    } else {
       char *utf8_message = gpr_format_message(WSAGetLastError());
       gpr_log(GPR_ERROR, "on_accept error: %s", utf8_message);
       gpr_free(utf8_message);
       closesocket(sock);
-    } else {
-	  /* TODO(ctiller): add sockaddr address to label */
-      ep = grpc_tcp_create(grpc_winsocket_create(sock, "server"));
     }
   } else {
-    /* If we're not notified from the IOCP, it means we are asked to shutdown.
-       This will initiate that shutdown. Calling closesocket will trigger an
-       IOCP notification, that will call this function a second time, from
-       the IOCP thread. Of course, this only works if the socket was, in fact,
-       listening. If that's not the case, we'd wait indefinitely. That's a bit
-       of a degenerate case, but it can happen if you create a server, but
-       don't start it. So let's support that by recursing once. */
-    sp->shutting_down = 1;
-    sp->new_socket = INVALID_SOCKET;
-    if (sock != INVALID_SOCKET) {
-      closesocket(sock);
-    } else {
-      on_accept(sp, 1);
+    if (!sp->shutting_down) {
+      /* TODO(ctiller): add sockaddr address to label */
+      ep = grpc_tcp_create(grpc_winsocket_create(sock, "server"));
     }
-    return;
   }
 
   /* The only time we should call our callback, is where we successfully
      managed to accept a connection, and created an endpoint. */
   if (ep) sp->server->cb(sp->server->cb_arg, ep);
   /* As we were notified from the IOCP of one and exactly one accept,
-      the former socked we created has now either been destroy or assigned
-      to the new connection. We need to create a new one for the next
-      connection. */
+     the former socked we created has now either been destroy or assigned
+     to the new connection. We need to create a new one for the next
+     connection. */
   start_accept(sp);
 }
 
diff --git a/src/core/iomgr/tcp_windows.c b/src/core/iomgr/tcp_windows.c
index 15759c3..1bf81a7 100644
--- a/src/core/iomgr/tcp_windows.c
+++ b/src/core/iomgr/tcp_windows.c
@@ -148,9 +148,11 @@
   GPR_ASSERT(tcp->socket->read_info.outstanding);
 
   if (socket->read_info.wsa_error != 0) {
-    char *utf8_message = gpr_format_message(info->wsa_error);
-    gpr_log(GPR_ERROR, "ReadFile overlapped error: %s", utf8_message);
-    gpr_free(utf8_message);
+    if (socket->read_info.wsa_error != WSAECONNRESET) {
+      char *utf8_message = gpr_format_message(info->wsa_error);
+      gpr_log(GPR_ERROR, "ReadFile overlapped error: %s", utf8_message);
+      gpr_free(utf8_message);
+    }
     status = GRPC_ENDPOINT_CB_ERROR;
   } else {
     if (info->bytes_transfered != 0) {
@@ -259,9 +261,11 @@
   GPR_ASSERT(tcp->socket->write_info.outstanding);
 
   if (info->wsa_error != 0) {
-    char *utf8_message = gpr_format_message(info->wsa_error);
-    gpr_log(GPR_ERROR, "WSASend overlapped error: %s", utf8_message);
-    gpr_free(utf8_message);
+    if (info->wsa_error != WSAECONNRESET) {
+      char *utf8_message = gpr_format_message(info->wsa_error);
+      gpr_log(GPR_ERROR, "WSASend overlapped error: %s", utf8_message);
+      gpr_free(utf8_message);
+    }
     status = GRPC_ENDPOINT_CB_ERROR;
   } else {
     GPR_ASSERT(info->bytes_transfered == tcp->write_slices.length);
@@ -325,9 +329,11 @@
       ret = GRPC_ENDPOINT_WRITE_DONE;
       GPR_ASSERT(bytes_sent == tcp->write_slices.length);
     } else {
-      char *utf8_message = gpr_format_message(info->wsa_error);
-      gpr_log(GPR_ERROR, "WSASend error: %s", utf8_message);
-      gpr_free(utf8_message);
+      if (socket->read_info.wsa_error != WSAECONNRESET) {
+        char *utf8_message = gpr_format_message(info->wsa_error);
+        gpr_log(GPR_ERROR, "WSASend error: %s", utf8_message);
+        gpr_free(utf8_message);
+      }
     }
     if (allocated) gpr_free(allocated);
     gpr_slice_buffer_reset_and_unref(&tcp->write_slices);
diff --git a/src/core/profiling/timers_preciseclock.h b/src/core/profiling/timers_preciseclock.h
index 163d52b..5c251b4 100644
--- a/src/core/profiling/timers_preciseclock.h
+++ b/src/core/profiling/timers_preciseclock.h
@@ -82,7 +82,7 @@
   gpr_timespec clock;
 };
 static void grpc_precise_clock_now(grpc_precise_clock* clk) {
-  clk->clock = gpr_now();
+  clk->clock = gpr_now(GPR_CLOCK_REALTIME);
 }
 #define GRPC_PRECISE_CLOCK_FORMAT "%ld.%09d"
 #define GRPC_PRECISE_CLOCK_PRINTF_ARGS(clk) \
diff --git a/src/core/security/credentials.c b/src/core/security/credentials.c
index 52fd5a2..230f0df 100644
--- a/src/core/security/credentials.c
+++ b/src/core/security/credentials.c
@@ -357,7 +357,8 @@
     if (c->cached.service_url != NULL &&
         strcmp(c->cached.service_url, service_url) == 0 &&
         c->cached.jwt_md != NULL &&
-        (gpr_time_cmp(gpr_time_sub(c->cached.jwt_expiration, gpr_now()),
+        (gpr_time_cmp(gpr_time_sub(c->cached.jwt_expiration,
+                                   gpr_now(GPR_CLOCK_REALTIME)),
                       refresh_threshold) > 0)) {
       jwt_md = grpc_credentials_md_store_ref(c->cached.jwt_md);
     }
@@ -374,7 +375,8 @@
       char *md_value;
       gpr_asprintf(&md_value, "Bearer %s", jwt);
       gpr_free(jwt);
-      c->cached.jwt_expiration = gpr_time_add(gpr_now(), c->jwt_lifetime);
+      c->cached.jwt_expiration =
+          gpr_time_add(gpr_now(GPR_CLOCK_REALTIME), c->jwt_lifetime);
       c->cached.service_url = gpr_strdup(service_url);
       c->cached.jwt_md = grpc_credentials_md_store_create(1);
       grpc_credentials_md_store_add_cstrings(
@@ -545,7 +547,8 @@
   status = grpc_oauth2_token_fetcher_credentials_parse_server_response(
       response, &c->access_token_md, &token_lifetime);
   if (status == GRPC_CREDENTIALS_OK) {
-    c->token_expiration = gpr_time_add(gpr_now(), token_lifetime);
+    c->token_expiration =
+        gpr_time_add(gpr_now(GPR_CLOCK_REALTIME), token_lifetime);
     r->cb(r->user_data, c->access_token_md->entries,
           c->access_token_md->num_entries, status);
   } else {
@@ -567,8 +570,9 @@
   {
     gpr_mu_lock(&c->mu);
     if (c->access_token_md != NULL &&
-        (gpr_time_cmp(gpr_time_sub(c->token_expiration, gpr_now()),
-                      refresh_threshold) > 0)) {
+        (gpr_time_cmp(
+             gpr_time_sub(c->token_expiration, gpr_now(GPR_CLOCK_REALTIME)),
+             refresh_threshold) > 0)) {
       cached_access_token_md =
           grpc_credentials_md_store_ref(c->access_token_md);
     }
@@ -582,7 +586,7 @@
     c->fetch_func(
         grpc_credentials_metadata_request_create(creds, cb, user_data),
         &c->httpcli_context, pollset, on_oauth2_token_fetcher_http_response,
-        gpr_time_add(gpr_now(), refresh_threshold));
+        gpr_time_add(gpr_now(GPR_CLOCK_REALTIME), refresh_threshold));
   }
 }
 
diff --git a/src/core/security/google_default_credentials.c b/src/core/security/google_default_credentials.c
index cd92f9d..f622def 100644
--- a/src/core/security/google_default_credentials.c
+++ b/src/core/security/google_default_credentials.c
@@ -103,9 +103,10 @@
 
   grpc_httpcli_context_init(&context);
 
-  grpc_httpcli_get(&context, &detector.pollset, &request,
-                   gpr_time_add(gpr_now(), max_detection_delay),
-                   on_compute_engine_detection_http_response, &detector);
+  grpc_httpcli_get(
+      &context, &detector.pollset, &request,
+      gpr_time_add(gpr_now(GPR_CLOCK_REALTIME), max_detection_delay),
+      on_compute_engine_detection_http_response, &detector);
 
   /* Block until we get the response. This is not ideal but this should only be
      called once for the lifetime of the process by the default credentials. */
diff --git a/src/core/security/json_token.c b/src/core/security/json_token.c
index 2e2b980..9b1ea25 100644
--- a/src/core/security/json_token.c
+++ b/src/core/security/json_token.c
@@ -207,7 +207,7 @@
   grpc_json *child = NULL;
   char *json_str = NULL;
   char *result = NULL;
-  gpr_timespec now = gpr_now();
+  gpr_timespec now = gpr_now(GPR_CLOCK_REALTIME);
   gpr_timespec expiration = gpr_time_add(now, token_lifetime);
   char now_str[GPR_LTOA_MIN_BUFSIZE];
   char expiration_str[GPR_LTOA_MIN_BUFSIZE];
@@ -218,8 +218,8 @@
   gpr_ltoa(now.tv_sec, now_str);
   gpr_ltoa(expiration.tv_sec, expiration_str);
 
-  child = create_child(NULL, json, "iss", json_key->client_email,
-                       GRPC_JSON_STRING);
+  child =
+      create_child(NULL, json, "iss", json_key->client_email, GRPC_JSON_STRING);
   if (scope != NULL) {
     child = create_child(child, json, "scope", scope, GRPC_JSON_STRING);
   } else {
@@ -403,4 +403,3 @@
     refresh_token->refresh_token = NULL;
   }
 }
-
diff --git a/src/core/security/jwt_verifier.c b/src/core/security/jwt_verifier.c
index 01007a1..9140eb2 100644
--- a/src/core/security/jwt_verifier.c
+++ b/src/core/security/jwt_verifier.c
@@ -189,7 +189,6 @@
   gpr_slice buffer;
 };
 
-
 void grpc_jwt_claims_destroy(grpc_jwt_claims *claims) {
   grpc_json_destroy(claims->json);
   gpr_slice_unref(claims->buffer);
@@ -286,12 +285,14 @@
 
   GPR_ASSERT(claims != NULL);
 
-  skewed_now = gpr_time_add(gpr_now(), grpc_jwt_verifier_clock_skew);
+  skewed_now =
+      gpr_time_add(gpr_now(GPR_CLOCK_REALTIME), grpc_jwt_verifier_clock_skew);
   if (gpr_time_cmp(skewed_now, claims->nbf) < 0) {
     gpr_log(GPR_ERROR, "JWT is not valid yet.");
     return GRPC_JWT_VERIFIER_TIME_CONSTRAINT_FAILURE;
   }
-  skewed_now = gpr_time_sub(gpr_now(), grpc_jwt_verifier_clock_skew);
+  skewed_now =
+      gpr_time_sub(gpr_now(GPR_CLOCK_REALTIME), grpc_jwt_verifier_clock_skew);
   if (gpr_time_cmp(skewed_now, claims->exp) > 0) {
     gpr_log(GPR_ERROR, "JWT is expired.");
     return GRPC_JWT_VERIFIER_TIME_CONSTRAINT_FAILURE;
@@ -327,10 +328,10 @@
 
 /* Takes ownership of the header, claims and signature. */
 static verifier_cb_ctx *verifier_cb_ctx_create(
-    grpc_jwt_verifier *verifier, grpc_pollset *pollset,
-    jose_header * header, grpc_jwt_claims *claims, const char *audience,
-    gpr_slice signature, const char *signed_jwt, size_t signed_jwt_len,
-    void *user_data, grpc_jwt_verification_done_cb cb) {
+    grpc_jwt_verifier *verifier, grpc_pollset *pollset, jose_header *header,
+    grpc_jwt_claims *claims, const char *audience, gpr_slice signature,
+    const char *signed_jwt, size_t signed_jwt_len, void *user_data,
+    grpc_jwt_verification_done_cb cb) {
   verifier_cb_ctx *ctx = gpr_malloc(sizeof(verifier_cb_ctx));
   memset(ctx, 0, sizeof(verifier_cb_ctx));
   ctx->verifier = verifier;
@@ -604,7 +605,7 @@
 
 static void on_openid_config_retrieved(void *user_data,
                                        const grpc_httpcli_response *response) {
-  const grpc_json* cur;
+  const grpc_json *cur;
   grpc_json *json = json_from_http(response);
   verifier_cb_ctx *ctx = (verifier_cb_ctx *)user_data;
   grpc_httpcli_request req;
@@ -632,9 +633,10 @@
   } else {
     *(req.host + (req.path - jwks_uri)) = '\0';
   }
-  grpc_httpcli_get(&ctx->verifier->http_ctx, ctx->pollset, &req,
-                   gpr_time_add(gpr_now(), grpc_jwt_verifier_max_delay),
-                   on_keys_retrieved, ctx);
+  grpc_httpcli_get(
+      &ctx->verifier->http_ctx, ctx->pollset, &req,
+      gpr_time_add(gpr_now(GPR_CLOCK_REALTIME), grpc_jwt_verifier_max_delay),
+      on_keys_retrieved, ctx);
   grpc_json_destroy(json);
   gpr_free(req.host);
   return;
@@ -645,8 +647,8 @@
   verifier_cb_ctx_destroy(ctx);
 }
 
-static email_key_mapping *verifier_get_mapping(
-    grpc_jwt_verifier *v, const char *email_domain) {
+static email_key_mapping *verifier_get_mapping(grpc_jwt_verifier *v,
+                                               const char *email_domain) {
   size_t i;
   if (v->mappings == NULL) return NULL;
   for (i = 0; i < v->num_mappings; i++) {
@@ -733,9 +735,10 @@
     http_cb = on_openid_config_retrieved;
   }
 
-  grpc_httpcli_get(&ctx->verifier->http_ctx, ctx->pollset, &req,
-                   gpr_time_add(gpr_now(), grpc_jwt_verifier_max_delay),
-                   http_cb, ctx);
+  grpc_httpcli_get(
+      &ctx->verifier->http_ctx, ctx->pollset, &req,
+      gpr_time_add(gpr_now(GPR_CLOCK_REALTIME), grpc_jwt_verifier_max_delay),
+      http_cb, ctx);
   gpr_free(req.host);
   gpr_free(req.path);
   return;
@@ -764,7 +767,7 @@
   dot = strchr(cur, '.');
   if (dot == NULL) goto error;
   json = parse_json_part_from_jwt(cur, dot - cur, &header_buffer);
-  if (json == NULL)  goto error;
+  if (json == NULL) goto error;
   header = jose_header_from_json(json, header_buffer);
   if (header == NULL) goto error;
 
@@ -772,7 +775,7 @@
   dot = strchr(cur, '.');
   if (dot == NULL) goto error;
   json = parse_json_part_from_jwt(cur, dot - cur, &claims_buffer);
-  if (json == NULL)  goto error;
+  if (json == NULL) goto error;
   claims = grpc_jwt_claims_from_json(json, claims_buffer);
   if (claims == NULL) goto error;
 
@@ -827,4 +830,3 @@
   }
   gpr_free(v);
 }
-
diff --git a/src/core/statistics/census_rpc_stats.c b/src/core/statistics/census_rpc_stats.c
index 0491c91..3e571b1 100644
--- a/src/core/statistics/census_rpc_stats.c
+++ b/src/core/statistics/census_rpc_stats.c
@@ -157,7 +157,7 @@
         key.ptr = gpr_strdup(key.ptr);
         census_ht_insert(store, key, (void*)window_stats);
       }
-      census_window_stats_add(window_stats, gpr_now(), stats);
+      census_window_stats_add(window_stats, gpr_now(GPR_CLOCK_REALTIME), stats);
     } else {
       census_internal_unlock_trace_store();
     }
@@ -185,7 +185,7 @@
   if (store != NULL) {
     size_t n;
     unsigned i, j;
-    gpr_timespec now = gpr_now();
+    gpr_timespec now = gpr_now(GPR_CLOCK_REALTIME);
     census_ht_kv* kv = census_ht_get_all_elements(store, &n);
     if (kv != NULL) {
       data->num_entries = n;
diff --git a/src/core/statistics/census_tracing.c b/src/core/statistics/census_tracing.c
index 05e72b9..3036ba5 100644
--- a/src/core/statistics/census_tracing.c
+++ b/src/core/statistics/census_tracing.c
@@ -94,7 +94,7 @@
     g_id++;
     memcpy(&ret->id, &g_id, sizeof(census_op_id));
     ret->rpc_stats.cnt = 1;
-    ret->ts = gpr_now();
+    ret->ts = gpr_now(GPR_CLOCK_REALTIME);
     census_ht_insert(g_trace_store, op_id_as_key(&ret->id), (void*)ret);
     gpr_log(GPR_DEBUG, "Start tracing for id %lu", g_id);
     gpr_mu_unlock(&g_mu);
@@ -122,7 +122,7 @@
   trace = census_ht_find(g_trace_store, op_id_as_key(&op_id));
   if (trace != NULL) {
     census_trace_annotation* anno = gpr_malloc(sizeof(census_trace_annotation));
-    anno->ts = gpr_now();
+    anno->ts = gpr_now(GPR_CLOCK_REALTIME);
     {
       char* d = anno->txt;
       const char* s = anno_txt;
@@ -143,8 +143,8 @@
   gpr_mu_lock(&g_mu);
   trace = census_ht_find(g_trace_store, op_id_as_key(&op_id));
   if (trace != NULL) {
-    trace->rpc_stats.elapsed_time_ms =
-        gpr_timespec_to_micros(gpr_time_sub(gpr_now(), trace->ts));
+    trace->rpc_stats.elapsed_time_ms = gpr_timespec_to_micros(
+        gpr_time_sub(gpr_now(GPR_CLOCK_REALTIME), trace->ts));
     gpr_log(GPR_DEBUG, "End tracing for id %lu, method %s, latency %f us",
             op_id_2_uint64(&op_id), trace->method,
             trace->rpc_stats.elapsed_time_ms);
@@ -194,8 +194,8 @@
 
 static census_trace_annotation* dup_annotation_chain(
     census_trace_annotation* from) {
-  census_trace_annotation *ret = NULL;
-  census_trace_annotation **to = &ret;
+  census_trace_annotation* ret = NULL;
+  census_trace_annotation** to = &ret;
   for (; from != NULL; from = from->next) {
     *to = gpr_malloc(sizeof(census_trace_annotation));
     memcpy(*to, from, sizeof(census_trace_annotation));
@@ -223,9 +223,9 @@
     size_t n = 0;
     census_ht_kv* all_kvs = census_ht_get_all_elements(g_trace_store, &n);
     *num_active_ops = (int)n;
-    if (n != 0 ) {
+    if (n != 0) {
       size_t i = 0;
-      ret = gpr_malloc(sizeof(census_trace_obj *) * n);
+      ret = gpr_malloc(sizeof(census_trace_obj*) * n);
       for (i = 0; i < n; i++) {
         ret[i] = trace_obj_dup((census_trace_obj*)all_kvs[i].v);
       }
diff --git a/src/core/statistics/window_stats.h b/src/core/statistics/window_stats.h
index d733d8d..0020f6b 100644
--- a/src/core/statistics/window_stats.h
+++ b/src/core/statistics/window_stats.h
@@ -90,11 +90,11 @@
     // Record a new event, taking 15.3ms, transferring 1784 bytes.
     stat.latency = 0.153;
     stat.bytes = 1784;
-    census_window_stats_add(stats, gpr_now(), &stat);
+    census_window_stats_add(stats, gpr_now(GPR_CLOCK_REALTIME), &stat);
     // Get sums and print them out
     result[kMinInterval].statistic = &sums[kMinInterval];
     result[kHourInterval].statistic = &sums[kHourInterval];
-    census_window_stats_get_sums(stats, gpr_now(), result);
+    census_window_stats_get_sums(stats, gpr_now(GPR_CLOCK_REALTIME), result);
     printf("%d events/min, average time %gs, average bytes %g\n",
            result[kMinInterval].count,
            (my_stat*)result[kMinInterval].statistic->latency /
@@ -170,4 +170,4 @@
    assertion failure). This function is thread-compatible. */
 void census_window_stats_destroy(struct census_window_stats* wstats);
 
-#endif  /* GRPC_INTERNAL_CORE_STATISTICS_WINDOW_STATS_H */
+#endif /* GRPC_INTERNAL_CORE_STATISTICS_WINDOW_STATS_H */
diff --git a/src/core/support/cancellable.c b/src/core/support/cancellable.c
index 5a4d488..3cbb318 100644
--- a/src/core/support/cancellable.c
+++ b/src/core/support/cancellable.c
@@ -121,8 +121,8 @@
         } else {
           gpr_event ev;
           gpr_event_init(&ev);
-          gpr_event_wait(&ev,
-                         gpr_time_add(gpr_now(), gpr_time_from_micros(1000)));
+          gpr_event_wait(&ev, gpr_time_add(gpr_now(GPR_CLOCK_REALTIME),
+                                           gpr_time_from_micros(1000)));
         }
       }
     } while (failures != 0);
diff --git a/src/core/support/log_linux.c b/src/core/support/log_linux.c
index 7937466..5ac36e7 100644
--- a/src/core/support/log_linux.c
+++ b/src/core/support/log_linux.c
@@ -76,7 +76,7 @@
   char *prefix;
   const char *display_file;
   char time_buffer[64];
-  gpr_timespec now = gpr_now();
+  gpr_timespec now = gpr_now(GPR_CLOCK_REALTIME);
   struct tm tm;
 
   final_slash = strrchr(args->file, '/');
diff --git a/src/core/support/log_posix.c b/src/core/support/log_posix.c
index afca792..940ee20 100644
--- a/src/core/support/log_posix.c
+++ b/src/core/support/log_posix.c
@@ -75,7 +75,7 @@
   char *final_slash;
   const char *display_file;
   char time_buffer[64];
-  gpr_timespec now = gpr_now();
+  gpr_timespec now = gpr_now(GPR_CLOCK_REALTIME);
   struct tm tm;
 
   final_slash = strrchr(args->file, '/');
diff --git a/src/core/support/log_win32.c b/src/core/support/log_win32.c
index d249be7..629781d 100644
--- a/src/core/support/log_win32.c
+++ b/src/core/support/log_win32.c
@@ -82,7 +82,7 @@
 /* Simple starter implementation */
 void gpr_default_log(gpr_log_func_args *args) {
   char time_buffer[64];
-  gpr_timespec now = gpr_now();
+  gpr_timespec now = gpr_now(GPR_CLOCK_REALTIME);
   struct tm tm;
 
   if (localtime_s(&tm, &now.tv_sec)) {
diff --git a/src/core/support/stack_lockfree.c b/src/core/support/stack_lockfree.c
new file mode 100644
index 0000000..9497efb
--- /dev/null
+++ b/src/core/support/stack_lockfree.c
@@ -0,0 +1,130 @@
+/*
+ *
+ * Copyright 2015, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "src/core/support/stack_lockfree.h"
+
+#include <stdlib.h>
+#include <string.h>
+
+#include <grpc/support/port_platform.h>
+#include <grpc/support/alloc.h>
+#include <grpc/support/atm.h>
+#include <grpc/support/log.h>
+
+/* The lockfree node structure is a single architecture-level
+   word that allows for an atomic CAS to set it up. */
+struct lockfree_node_contents {
+  /* next thing to look at. Actual index for head, next index otherwise */
+  gpr_uint16 index;
+#ifdef GPR_ARCH_64
+  gpr_uint16 pad;
+  gpr_uint32 aba_ctr;
+#else
+#ifdef GPR_ARCH_32
+  gpr_uint16 aba_ctr;
+#else
+#error Unsupported bit width architecture
+#endif
+#endif
+};
+
+/* Use a union to make sure that these are in the same bits as an atm word */
+typedef union lockfree_node {
+  gpr_atm atm;
+  struct lockfree_node_contents contents;
+} lockfree_node;
+
+#define ENTRY_ALIGNMENT_BITS 3 /* make sure that entries aligned to 8-bytes */
+#define INVALID_ENTRY_INDEX ((1 << 16) - 1) /* reserve this entry as invalid \
+                                               */
+
+struct gpr_stack_lockfree {
+  lockfree_node *entries;
+  lockfree_node head; /* An atomic entry describing curr head */
+};
+
+gpr_stack_lockfree *gpr_stack_lockfree_create(int entries) {
+  gpr_stack_lockfree *stack;
+  stack = gpr_malloc(sizeof(*stack));
+  /* Since we only allocate 16 bits to represent an entry number,
+   * make sure that we are within the desired range */
+  /* Reserve the highest entry number as a dummy */
+  GPR_ASSERT(entries < INVALID_ENTRY_INDEX);
+  stack->entries = gpr_malloc_aligned(entries * sizeof(stack->entries[0]),
+                                      ENTRY_ALIGNMENT_BITS);
+  /* Clear out all entries */
+  memset(stack->entries, 0, entries * sizeof(stack->entries[0]));
+  memset(&stack->head, 0, sizeof(stack->head));
+
+  /* Point the head at reserved dummy entry */
+  stack->head.contents.index = INVALID_ENTRY_INDEX;
+  return stack;
+}
+
+void gpr_stack_lockfree_destroy(gpr_stack_lockfree *stack) {
+  gpr_free_aligned(stack->entries);
+  gpr_free(stack);
+}
+
+void gpr_stack_lockfree_push(gpr_stack_lockfree *stack, int entry) {
+  lockfree_node head;
+  lockfree_node newhead;
+
+  /* First fill in the entry's index and aba ctr for new head */
+  newhead.contents.index = (gpr_uint16)entry;
+  /* Also post-increment the aba_ctr */
+  newhead.contents.aba_ctr = stack->entries[entry].contents.aba_ctr++;
+
+  do {
+    /* Atomically get the existing head value for use */
+    head.atm = gpr_atm_no_barrier_load(&(stack->head.atm));
+    /* Point to it */
+    stack->entries[entry].contents.index = head.contents.index;
+  } while (!gpr_atm_rel_cas(&(stack->head.atm), head.atm, newhead.atm));
+  /* Use rel_cas above to make sure that entry index is set properly */
+}
+
+int gpr_stack_lockfree_pop(gpr_stack_lockfree *stack) {
+  lockfree_node head;
+  lockfree_node newhead;
+  do {
+    head.atm = gpr_atm_acq_load(&(stack->head.atm));
+    if (head.contents.index == INVALID_ENTRY_INDEX) {
+      return -1;
+    }
+    newhead.atm =
+        gpr_atm_no_barrier_load(&(stack->entries[head.contents.index].atm));
+
+  } while (!gpr_atm_no_barrier_cas(&(stack->head.atm), head.atm, newhead.atm));
+  return head.contents.index;
+}
diff --git a/src/core/support/stack_lockfree.h b/src/core/support/stack_lockfree.h
new file mode 100644
index 0000000..0bcf736
--- /dev/null
+++ b/src/core/support/stack_lockfree.h
@@ -0,0 +1,50 @@
+/*
+ *
+ * Copyright 2015, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef GRPC_INTERNAL_CORE_SUPPORT_STACK_LOCKFREE_H
+#define GRPC_INTERNAL_CORE_SUPPORT_STACK_LOCKFREE_H
+
+typedef struct gpr_stack_lockfree gpr_stack_lockfree;
+
+/* This stack must specify the maximum number of entries to track.
+   The current implementation only allows up to 65534 entries */
+gpr_stack_lockfree* gpr_stack_lockfree_create(int entries);
+void gpr_stack_lockfree_destroy(gpr_stack_lockfree* stack);
+
+/* Pass in a valid entry number for the next stack entry */
+void gpr_stack_lockfree_push(gpr_stack_lockfree* stack, int entry);
+
+/* Returns -1 on empty or the actual entry number */
+int gpr_stack_lockfree_pop(gpr_stack_lockfree* stack);
+
+#endif /* GRPC_INTERNAL_CORE_SUPPORT_STACK_LOCKFREE_H */
diff --git a/src/core/support/sync_win32.c b/src/core/support/sync_win32.c
index 72f39f8..29b77fc 100644
--- a/src/core/support/sync_win32.c
+++ b/src/core/support/sync_win32.c
@@ -86,7 +86,7 @@
   if (gpr_time_cmp(abs_deadline, gpr_inf_future) == 0) {
     SleepConditionVariableCS(cv, &mu->cs, INFINITE);
   } else {
-    gpr_timespec now = gpr_now();
+    gpr_timespec now = gpr_now(GPR_CLOCK_REALTIME);
     gpr_int64 now_ms = now.tv_sec * 1000 + now.tv_nsec / 1000000;
     gpr_int64 deadline_ms =
         abs_deadline.tv_sec * 1000 + abs_deadline.tv_nsec / 1000000;
diff --git a/src/core/support/time_posix.c b/src/core/support/time_posix.c
index afb58ef..f9b7958 100644
--- a/src/core/support/time_posix.c
+++ b/src/core/support/time_posix.c
@@ -55,22 +55,52 @@
   return rv;
 }
 
-gpr_timespec gpr_now(void) {
+/** maps gpr_clock_type --> clockid_t for clock_gettime */
+static clockid_t clockid_for_gpr_clock[] = {CLOCK_MONOTONIC, CLOCK_REALTIME};
+
+void gpr_time_init(void) {}
+
+gpr_timespec gpr_now(gpr_clock_type clock) {
   struct timespec now;
-  clock_gettime(CLOCK_REALTIME, &now);
+  clock_gettime(clockid_for_gpr_clock[clock], &now);
   return gpr_from_timespec(now);
 }
 #else
 /* For some reason Apple's OSes haven't implemented clock_gettime. */
 
 #include <sys/time.h>
+#include <mach/mach.h>
+#include <mach/mach_time.h>
 
-gpr_timespec gpr_now(void) {
+static double g_time_scale;
+static uint64_t g_time_start;
+
+void gpr_time_init(void) {
+  mach_timebase_info_data_t tb = {0, 1};
+  mach_timebase_info(&tb);
+  g_time_scale = tb.numer;
+  g_time_scale /= tb.denom;
+  g_time_start = mach_absolute_time();
+}
+
+gpr_timespec gpr_now(gpr_clock_type clock) {
   gpr_timespec now;
   struct timeval now_tv;
-  gettimeofday(&now_tv, NULL);
-  now.tv_sec = now_tv.tv_sec;
-  now.tv_nsec = now_tv.tv_usec * 1000;
+  double now_dbl;
+
+  switch (clock) {
+    case GPR_CLOCK_REALTIME:
+      gettimeofday(&now_tv, NULL);
+      now.tv_sec = now_tv.tv_sec;
+      now.tv_nsec = now_tv.tv_usec * 1000;
+      break;
+    case GPR_CLOCK_MONOTONIC:
+      now_dbl = (mach_absolute_time() - g_time_start) * g_time_scale;
+      now.tv_sec = now_dbl * 1e-9;
+      now.tv_nsec = now_dbl - now.tv_sec * 1e9;
+      break;
+  }
+
   return now;
 }
 #endif
@@ -83,7 +113,7 @@
   for (;;) {
     /* We could simplify by using clock_nanosleep instead, but it might be
      * slightly less portable. */
-    now = gpr_now();
+    now = gpr_now(GPR_CLOCK_REALTIME);
     if (gpr_time_cmp(until, now) <= 0) {
       return;
     }
diff --git a/src/core/support/time_win32.c b/src/core/support/time_win32.c
index 9db267c..fa77c74 100644
--- a/src/core/support/time_win32.c
+++ b/src/core/support/time_win32.c
@@ -40,12 +40,34 @@
 #include <grpc/support/time.h>
 #include <sys/timeb.h>
 
-gpr_timespec gpr_now(void) {
+static LARGE_INTEGER g_start_time;
+static double g_time_scale;
+
+void gpr_time_init(void) {
+  LARGE_INTEGER frequency;
+  QueryPerformanceFrequency(&frequency);
+  QueryPerformanceCounter(&g_start_time);
+  g_time_scale = 1.0 / frequency.QuadPart;
+}
+
+gpr_timespec gpr_now(gpr_clock_type clock) {
   gpr_timespec now_tv;
   struct _timeb now_tb;
-  _ftime_s(&now_tb);
-  now_tv.tv_sec = now_tb.time;
-  now_tv.tv_nsec = now_tb.millitm * 1000000;
+  LARGE_INTEGER timestamp;
+  double now_dbl;
+  switch (clock) {
+    case GPR_CLOCK_REALTIME:
+      _ftime_s(&now_tb);
+      now_tv.tv_sec = now_tb.time;
+      now_tv.tv_nsec = now_tb.millitm * 1000000;
+      break;
+    case GPR_CLOCK_MONOTONIC:
+      QueryPerformanceCounter(&timestamp);
+      now_dbl = (timestamp.QuadPart - g_start_time.QuadPart) * g_time_scale;
+      now_tv.tv_sec = (time_t)now_dbl;
+      now_tv.tv_nsec = (int)((now_dbl - (double)now_tv.tv_sec) * 1e9);
+      break;
+  }
   return now_tv;
 }
 
@@ -57,13 +79,14 @@
   for (;;) {
     /* We could simplify by using clock_nanosleep instead, but it might be
      * slightly less portable. */
-    now = gpr_now();
+    now = gpr_now(GPR_CLOCK_REALTIME);
     if (gpr_time_cmp(until, now) <= 0) {
       return;
     }
 
     delta = gpr_time_sub(until, now);
-    sleep_millis = (DWORD)delta.tv_sec * GPR_MS_PER_SEC + delta.tv_nsec / GPR_NS_PER_MS;
+    sleep_millis =
+        (DWORD)delta.tv_sec * GPR_MS_PER_SEC + delta.tv_nsec / GPR_NS_PER_MS;
     Sleep(sleep_millis);
   }
 }
diff --git a/src/core/surface/call.c b/src/core/surface/call.c
index fb3b0b1..0a551ac 100644
--- a/src/core/surface/call.c
+++ b/src/core/surface/call.c
@@ -49,6 +49,17 @@
 #include <stdlib.h>
 #include <string.h>
 
+/** The maximum number of completions possible.
+    Based upon the maximum number of individually queueable ops in the batch
+   api:
+      - initial metadata send
+      - message send
+      - status/close send (depending on client/server)
+      - initial metadata recv
+      - message recv
+      - status/close recv (depending on client/server) */
+#define MAX_CONCURRENT_COMPLETIONS 6
+
 typedef enum { REQ_INITIAL = 0, REQ_READY, REQ_DONE } req_state;
 
 typedef enum {
@@ -135,6 +146,7 @@
   grpc_mdctx *metadata_context;
   /* TODO(ctiller): share with cq if possible? */
   gpr_mu mu;
+  gpr_mu completion_mu;
 
   /* how far through the stream have we read? */
   read_state read_state;
@@ -162,6 +174,8 @@
   gpr_uint8 error_status_set;
   /** should the alarm be cancelled */
   gpr_uint8 cancel_alarm;
+  /** bitmask of allocated completion events in completions */
+  gpr_uint8 allocated_completions;
 
   /* flags with bits corresponding to write states allowing us to determine
      what was sent */
@@ -250,6 +264,9 @@
   grpc_iomgr_closure on_done_recv;
   grpc_iomgr_closure on_done_send;
   grpc_iomgr_closure on_done_bind;
+
+  /** completion events - for completion queue use */
+  grpc_cq_completion completions[MAX_CONCURRENT_COMPLETIONS];
 };
 
 #define CALL_STACK_FROM_CALL(call) ((grpc_call_stack *)((call) + 1))
@@ -286,6 +303,7 @@
       gpr_malloc(sizeof(grpc_call) + channel_stack->call_stack_size);
   memset(call, 0, sizeof(grpc_call));
   gpr_mu_init(&call->mu);
+  gpr_mu_init(&call->completion_mu);
   call->channel = channel;
   call->cq = cq;
   if (cq) {
@@ -349,6 +367,29 @@
   return call->cq;
 }
 
+static grpc_cq_completion *allocate_completion(grpc_call *call) {
+  gpr_uint8 i;
+  gpr_mu_lock(&call->completion_mu);
+  for (i = 0; i < GPR_ARRAY_SIZE(call->completions); i++) {
+    if (call->allocated_completions & (1u << i)) {
+      continue;
+    }
+    call->allocated_completions |= 1u << i;
+    gpr_mu_unlock(&call->completion_mu);
+    return &call->completions[i];
+  }
+  gpr_log(GPR_ERROR, "should never reach here");
+  abort();
+}
+
+static void done_completion(void *call, grpc_cq_completion *completion) {
+  grpc_call *c = call;
+  gpr_mu_lock(&c->completion_mu);
+  c->allocated_completions &= ~(1u << (completion - c->completions));
+  gpr_mu_unlock(&c->completion_mu);
+  GRPC_CALL_INTERNAL_UNREF(c, "completion", 1);
+}
+
 #ifdef GRPC_CALL_REF_COUNT_DEBUG
 void grpc_call_internal_ref(grpc_call *c, const char *reason) {
   gpr_log(GPR_DEBUG, "CALL:   ref %p %d -> %d [%s]", c,
@@ -365,6 +406,7 @@
   grpc_call_stack_destroy(CALL_STACK_FROM_CALL(c));
   GRPC_CHANNEL_INTERNAL_UNREF(c->channel, "call");
   gpr_mu_destroy(&c->mu);
+  gpr_mu_destroy(&c->completion_mu);
   for (i = 0; i < STATUS_SOURCE_COUNT; i++) {
     if (c->status[i].details) {
       GRPC_MDSTR_UNREF(c->status[i].details);
@@ -1188,7 +1230,8 @@
   }
   GRPC_CALL_INTERNAL_REF(call, "alarm");
   call->have_alarm = 1;
-  grpc_alarm_init(&call->alarm, deadline, call_alarm, call, gpr_now());
+  grpc_alarm_init(&call->alarm, deadline, call_alarm, call,
+                  gpr_now(GPR_CLOCK_REALTIME));
 }
 
 /* we offset status by a small amount when storing it into transport metadata
@@ -1316,11 +1359,13 @@
 }
 
 static void finish_batch(grpc_call *call, int success, void *tag) {
-  grpc_cq_end_op(call->cq, tag, call, success);
+  grpc_cq_end_op(call->cq, tag, success, done_completion, call,
+                 allocate_completion(call));
 }
 
 static void finish_batch_with_close(grpc_call *call, int success, void *tag) {
-  grpc_cq_end_op(call->cq, tag, call, 1);
+  grpc_cq_end_op(call->cq, tag, 1, done_completion, call,
+                 allocate_completion(call));
 }
 
 static int are_write_flags_valid(gpr_uint32 flags) {
@@ -1343,8 +1388,10 @@
   GRPC_CALL_LOG_BATCH(GPR_INFO, call, ops, nops, tag);
 
   if (nops == 0) {
-    grpc_cq_begin_op(call->cq, call);
-    grpc_cq_end_op(call->cq, tag, call, 1);
+    grpc_cq_begin_op(call->cq);
+    GRPC_CALL_INTERNAL_REF(call, "completion");
+    grpc_cq_end_op(call->cq, tag, 1, done_completion, call,
+                   allocate_completion(call));
     return GRPC_CALL_OK;
   }
 
@@ -1466,7 +1513,8 @@
     }
   }
 
-  grpc_cq_begin_op(call->cq, call);
+  GRPC_CALL_INTERNAL_REF(call, "completion");
+  grpc_cq_begin_op(call->cq);
 
   return grpc_call_start_ioreq_and_call_back(call, reqs, out, finish_func, tag);
 }
diff --git a/src/core/surface/channel.c b/src/core/surface/channel.c
index eeae3b5..b7826d4 100644
--- a/src/core/surface/channel.c
+++ b/src/core/surface/channel.c
@@ -91,6 +91,7 @@
   size_t size =
       sizeof(grpc_channel) + grpc_channel_stack_size(filters, num_filters);
   grpc_channel *channel = gpr_malloc(size);
+  memset(channel, 0, sizeof(*channel));
   GPR_ASSERT(grpc_is_initialized() && "call grpc_init()");
   channel->is_client = is_client;
   /* decremented by grpc_channel_destroy */
diff --git a/src/core/surface/completion_queue.c b/src/core/surface/completion_queue.c
index 030a8b4..c67f75f 100644
--- a/src/core/surface/completion_queue.c
+++ b/src/core/surface/completion_queue.c
@@ -45,34 +45,20 @@
 #include <grpc/support/atm.h>
 #include <grpc/support/log.h>
 
-#define NUM_TAG_BUCKETS 31
-
-/* A single event: extends grpc_event to form a linked list with a destruction
-   function (on_finish) that is hidden from outside this module */
-typedef struct event {
-  grpc_event base;
-  struct event *queue_next;
-  struct event *queue_prev;
-  struct event *bucket_next;
-  struct event *bucket_prev;
-} event;
-
 /* Completion queue structure */
 struct grpc_completion_queue {
-  /* When refs drops to zero, we are in shutdown mode, and will be destroyable
-     once all queued events are drained */
-  gpr_refcount refs;
-  /* Once owning_refs drops to zero, we will destroy the cq */
+  /** completed events */
+  grpc_cq_completion completed_head;
+  grpc_cq_completion *completed_tail;
+  /** Number of pending events (+1 if we're not shutdown) */
+  gpr_refcount pending_events;
+  /** Once owning_refs drops to zero, we will destroy the cq */
   gpr_refcount owning_refs;
-  /* the set of low level i/o things that concern this cq */
+  /** the set of low level i/o things that concern this cq */
   grpc_pollset pollset;
-  /* 0 initially, 1 once we've begun shutting down */
+  /** 0 initially, 1 once we've begun shutting down */
   int shutdown;
   int shutdown_called;
-  /* Head of a linked list of queued events (prev points to the last element) */
-  event *queue;
-  /* Fixed size chained hash table of events for pluck() */
-  event *buckets[NUM_TAG_BUCKETS];
   int is_server_cq;
 };
 
@@ -80,19 +66,20 @@
   grpc_completion_queue *cc = gpr_malloc(sizeof(grpc_completion_queue));
   memset(cc, 0, sizeof(*cc));
   /* Initial ref is dropped by grpc_completion_queue_shutdown */
-  gpr_ref_init(&cc->refs, 1);
+  gpr_ref_init(&cc->pending_events, 1);
   /* One for destroy(), one for pollset_shutdown */
   gpr_ref_init(&cc->owning_refs, 2);
   grpc_pollset_init(&cc->pollset);
+  cc->completed_tail = &cc->completed_head;
+  cc->completed_head.next = (gpr_uintptr)cc->completed_tail;
   return cc;
 }
 
 #ifdef GRPC_CQ_REF_COUNT_DEBUG
 void grpc_cq_internal_ref(grpc_completion_queue *cc, const char *reason,
                           const char *file, int line) {
-  gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG, "CQ:%p   ref %d -> %d %s",
-          cc, (int)cc->owning_refs.count, (int)cc->owning_refs.count + 1,
-          reason);
+  gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG, "CQ:%p   ref %d -> %d %s", cc,
+          (int)cc->owning_refs.count, (int)cc->owning_refs.count + 1, reason);
 #else
 void grpc_cq_internal_ref(grpc_completion_queue *cc) {
 #endif
@@ -107,186 +94,135 @@
 #ifdef GRPC_CQ_REF_COUNT_DEBUG
 void grpc_cq_internal_unref(grpc_completion_queue *cc, const char *reason,
                             const char *file, int line) {
-  gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG, "CQ:%p unref %d -> %d %s",
-          cc, (int)cc->owning_refs.count, (int)cc->owning_refs.count - 1,
-          reason);
+  gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG, "CQ:%p unref %d -> %d %s", cc,
+          (int)cc->owning_refs.count, (int)cc->owning_refs.count - 1, reason);
 #else
 void grpc_cq_internal_unref(grpc_completion_queue *cc) {
 #endif
   if (gpr_unref(&cc->owning_refs)) {
-    GPR_ASSERT(cc->queue == NULL);
+    GPR_ASSERT(cc->completed_head.next == (gpr_uintptr)&cc->completed_head);
     grpc_pollset_destroy(&cc->pollset);
     gpr_free(cc);
   }
 }
 
-/* Create and append an event to the queue. Returns the event so that its data
-   members can be filled in.
-   Requires GRPC_POLLSET_MU(&cc->pollset) locked. */
-static event *add_locked(grpc_completion_queue *cc, grpc_completion_type type,
-                         void *tag, grpc_call *call) {
-  event *ev = gpr_malloc(sizeof(event));
-  gpr_uintptr bucket = ((gpr_uintptr)tag) % NUM_TAG_BUCKETS;
-  ev->base.type = type;
-  ev->base.tag = tag;
-  if (cc->queue == NULL) {
-    cc->queue = ev->queue_next = ev->queue_prev = ev;
-  } else {
-    ev->queue_next = cc->queue;
-    ev->queue_prev = cc->queue->queue_prev;
-    ev->queue_next->queue_prev = ev->queue_prev->queue_next = ev;
-  }
-  if (cc->buckets[bucket] == NULL) {
-    cc->buckets[bucket] = ev->bucket_next = ev->bucket_prev = ev;
-  } else {
-    ev->bucket_next = cc->buckets[bucket];
-    ev->bucket_prev = cc->buckets[bucket]->bucket_prev;
-    ev->bucket_next->bucket_prev = ev->bucket_prev->bucket_next = ev;
-  }
-  grpc_pollset_kick(&cc->pollset);
-  return ev;
-}
-
-void grpc_cq_begin_op(grpc_completion_queue *cc, grpc_call *call) {
-  gpr_ref(&cc->refs);
-  if (call) GRPC_CALL_INTERNAL_REF(call, "cq");
+void grpc_cq_begin_op(grpc_completion_queue *cc) {
+  gpr_ref(&cc->pending_events);
 }
 
 /* Signal the end of an operation - if this is the last waiting-to-be-queued
    event, then enter shutdown mode */
-void grpc_cq_end_op(grpc_completion_queue *cc, void *tag, grpc_call *call,
-                    int success) {
-  event *ev;
-  int shutdown = 0;
-  gpr_mu_lock(GRPC_POLLSET_MU(&cc->pollset));
-  ev = add_locked(cc, GRPC_OP_COMPLETE, tag, call);
-  ev->base.success = success;
-  if (gpr_unref(&cc->refs)) {
+/* Queue a GRPC_OP_COMPLETED operation */
+void grpc_cq_end_op(grpc_completion_queue *cc, void *tag, int success,
+                    void (*done)(void *done_arg, grpc_cq_completion *storage),
+                    void *done_arg, grpc_cq_completion *storage) {
+  int shutdown = gpr_unref(&cc->pending_events);
+
+  storage->tag = tag;
+  storage->done = done;
+  storage->done_arg = done_arg;
+  storage->next =
+      ((gpr_uintptr)&cc->completed_head) | ((gpr_uintptr)(success != 0));
+
+  if (!shutdown) {
+    gpr_mu_lock(GRPC_POLLSET_MU(&cc->pollset));
+    cc->completed_tail->next =
+        ((gpr_uintptr)storage) | (1u & (gpr_uintptr)cc->completed_tail->next);
+    cc->completed_tail = storage;
+    grpc_pollset_kick(&cc->pollset);
+    gpr_mu_unlock(GRPC_POLLSET_MU(&cc->pollset));
+  } else {
+    gpr_mu_lock(GRPC_POLLSET_MU(&cc->pollset));
+    cc->completed_tail->next =
+        ((gpr_uintptr)storage) | (1u & (gpr_uintptr)cc->completed_tail->next);
+    cc->completed_tail = storage;
     GPR_ASSERT(!cc->shutdown);
     GPR_ASSERT(cc->shutdown_called);
     cc->shutdown = 1;
-    shutdown = 1;
-  }
-  gpr_mu_unlock(GRPC_POLLSET_MU(&cc->pollset));
-  if (call) GRPC_CALL_INTERNAL_UNREF(call, "cq", 0);
-  if (shutdown) {
+    gpr_mu_unlock(GRPC_POLLSET_MU(&cc->pollset));
     grpc_pollset_shutdown(&cc->pollset, on_pollset_destroy_done, cc);
   }
 }
 
-/* Create a GRPC_QUEUE_SHUTDOWN event without queuing it anywhere */
-static event *create_shutdown_event(void) {
-  event *ev = gpr_malloc(sizeof(event));
-  ev->base.type = GRPC_QUEUE_SHUTDOWN;
-  ev->base.tag = NULL;
-  return ev;
-}
-
 grpc_event grpc_completion_queue_next(grpc_completion_queue *cc,
                                       gpr_timespec deadline) {
-  event *ev = NULL;
   grpc_event ret;
 
   GRPC_CQ_INTERNAL_REF(cc, "next");
   gpr_mu_lock(GRPC_POLLSET_MU(&cc->pollset));
   for (;;) {
-    if (cc->queue != NULL) {
-      gpr_uintptr bucket;
-      ev = cc->queue;
-      bucket = ((gpr_uintptr)ev->base.tag) % NUM_TAG_BUCKETS;
-      cc->queue = ev->queue_next;
-      ev->queue_next->queue_prev = ev->queue_prev;
-      ev->queue_prev->queue_next = ev->queue_next;
-      ev->bucket_next->bucket_prev = ev->bucket_prev;
-      ev->bucket_prev->bucket_next = ev->bucket_next;
-      if (ev == cc->buckets[bucket]) {
-        cc->buckets[bucket] = ev->bucket_next;
-        if (ev == cc->buckets[bucket]) {
-          cc->buckets[bucket] = NULL;
-        }
+    if (cc->completed_tail != &cc->completed_head) {
+      grpc_cq_completion *c = (grpc_cq_completion *)cc->completed_head.next;
+      cc->completed_head.next = c->next & ~(gpr_uintptr)1;
+      if (c == cc->completed_tail) {
+        cc->completed_tail = &cc->completed_head;
       }
-      if (cc->queue == ev) {
-        cc->queue = NULL;
-      }
+      gpr_mu_unlock(GRPC_POLLSET_MU(&cc->pollset));
+      ret.type = GRPC_OP_COMPLETE;
+      ret.success = c->next & 1u;
+      ret.tag = c->tag;
+      c->done(c->done_arg, c);
       break;
     }
     if (cc->shutdown) {
-      ev = create_shutdown_event();
+      gpr_mu_unlock(GRPC_POLLSET_MU(&cc->pollset));
+      memset(&ret, 0, sizeof(ret));
+      ret.type = GRPC_QUEUE_SHUTDOWN;
       break;
     }
     if (!grpc_pollset_work(&cc->pollset, deadline)) {
       gpr_mu_unlock(GRPC_POLLSET_MU(&cc->pollset));
       memset(&ret, 0, sizeof(ret));
       ret.type = GRPC_QUEUE_TIMEOUT;
-      GRPC_SURFACE_TRACE_RETURNED_EVENT(cc, &ret);
-      GRPC_CQ_INTERNAL_UNREF(cc, "next");
-      return ret;
+      break;
     }
   }
-  gpr_mu_unlock(GRPC_POLLSET_MU(&cc->pollset));
-  ret = ev->base;
-  gpr_free(ev);
   GRPC_SURFACE_TRACE_RETURNED_EVENT(cc, &ret);
   GRPC_CQ_INTERNAL_UNREF(cc, "next");
   return ret;
 }
 
-static event *pluck_event(grpc_completion_queue *cc, void *tag) {
-  gpr_uintptr bucket = ((gpr_uintptr)tag) % NUM_TAG_BUCKETS;
-  event *ev = cc->buckets[bucket];
-  if (ev == NULL) return NULL;
-  do {
-    if (ev->base.tag == tag) {
-      ev->queue_next->queue_prev = ev->queue_prev;
-      ev->queue_prev->queue_next = ev->queue_next;
-      ev->bucket_next->bucket_prev = ev->bucket_prev;
-      ev->bucket_prev->bucket_next = ev->bucket_next;
-      if (ev == cc->buckets[bucket]) {
-        cc->buckets[bucket] = ev->bucket_next;
-        if (ev == cc->buckets[bucket]) {
-          cc->buckets[bucket] = NULL;
-        }
-      }
-      if (cc->queue == ev) {
-        cc->queue = ev->queue_next;
-        if (cc->queue == ev) {
-          cc->queue = NULL;
-        }
-      }
-      return ev;
-    }
-    ev = ev->bucket_next;
-  } while (ev != cc->buckets[bucket]);
-  return NULL;
-}
-
 grpc_event grpc_completion_queue_pluck(grpc_completion_queue *cc, void *tag,
                                        gpr_timespec deadline) {
-  event *ev = NULL;
   grpc_event ret;
+  grpc_cq_completion *c;
+  grpc_cq_completion *prev;
 
   GRPC_CQ_INTERNAL_REF(cc, "pluck");
   gpr_mu_lock(GRPC_POLLSET_MU(&cc->pollset));
   for (;;) {
-    if ((ev = pluck_event(cc, tag))) {
-      break;
+    prev = &cc->completed_head;
+    while ((c = (grpc_cq_completion *)(prev->next & ~(gpr_uintptr)1)) !=
+           &cc->completed_head) {
+      if (c->tag == tag) {
+        prev->next =
+            (prev->next & (gpr_uintptr)1) | (c->next & ~(gpr_uintptr)1);
+        if (c == cc->completed_tail) {
+          cc->completed_tail = prev;
+        }
+        gpr_mu_unlock(GRPC_POLLSET_MU(&cc->pollset));
+        ret.type = GRPC_OP_COMPLETE;
+        ret.success = c->next & 1u;
+        ret.tag = c->tag;
+        c->done(c->done_arg, c);
+        goto done;
+      }
+      prev = c;
     }
     if (cc->shutdown) {
-      ev = create_shutdown_event();
+      gpr_mu_unlock(GRPC_POLLSET_MU(&cc->pollset));
+      memset(&ret, 0, sizeof(ret));
+      ret.type = GRPC_QUEUE_SHUTDOWN;
       break;
     }
     if (!grpc_pollset_work(&cc->pollset, deadline)) {
       gpr_mu_unlock(GRPC_POLLSET_MU(&cc->pollset));
       memset(&ret, 0, sizeof(ret));
       ret.type = GRPC_QUEUE_TIMEOUT;
-      GRPC_SURFACE_TRACE_RETURNED_EVENT(cc, &ret);
-      GRPC_CQ_INTERNAL_UNREF(cc, "pluck");
-      return ret;
+      break;
     }
   }
-  gpr_mu_unlock(GRPC_POLLSET_MU(&cc->pollset));
-  ret = ev->base;
-  gpr_free(ev);
+done:
   GRPC_SURFACE_TRACE_RETURNED_EVENT(cc, &ret);
   GRPC_CQ_INTERNAL_UNREF(cc, "pluck");
   return ret;
@@ -303,7 +239,7 @@
   cc->shutdown_called = 1;
   gpr_mu_unlock(GRPC_POLLSET_MU(&cc->pollset));
 
-  if (gpr_unref(&cc->refs)) {
+  if (gpr_unref(&cc->pending_events)) {
     gpr_mu_lock(GRPC_POLLSET_MU(&cc->pollset));
     GPR_ASSERT(!cc->shutdown);
     cc->shutdown = 1;
@@ -324,8 +260,8 @@
 void grpc_cq_hack_spin_pollset(grpc_completion_queue *cc) {
   gpr_mu_lock(GRPC_POLLSET_MU(&cc->pollset));
   grpc_pollset_kick(&cc->pollset);
-  grpc_pollset_work(&cc->pollset,
-                    gpr_time_add(gpr_now(), gpr_time_from_millis(100)));
+  grpc_pollset_work(&cc->pollset, gpr_time_add(gpr_now(GPR_CLOCK_REALTIME),
+                                               gpr_time_from_millis(100)));
   gpr_mu_unlock(GRPC_POLLSET_MU(&cc->pollset));
 }
 
diff --git a/src/core/surface/completion_queue.h b/src/core/surface/completion_queue.h
index 1b9010f..f944f48 100644
--- a/src/core/surface/completion_queue.h
+++ b/src/core/surface/completion_queue.h
@@ -39,6 +39,17 @@
 #include "src/core/iomgr/pollset.h"
 #include <grpc/grpc.h>
 
+typedef struct grpc_cq_completion {
+  /** user supplied tag */
+  void *tag;
+  /** done callback - called when this queue element is no longer
+      needed by the completion queue */
+  void (*done)(void *done_arg, struct grpc_cq_completion *c);
+  void *done_arg;
+  /** next pointer; low bit is used to indicate success or not */
+  gpr_uintptr next;
+} grpc_cq_completion;
+
 #ifdef GRPC_CQ_REF_COUNT_DEBUG
 void grpc_cq_internal_ref(grpc_completion_queue *cc, const char *reason,
                           const char *file, int line);
@@ -57,11 +68,12 @@
 
 /* Flag that an operation is beginning: the completion channel will not finish
    shutdown until a corrensponding grpc_cq_end_* call is made */
-void grpc_cq_begin_op(grpc_completion_queue *cc, grpc_call *call);
+void grpc_cq_begin_op(grpc_completion_queue *cc);
 
 /* Queue a GRPC_OP_COMPLETED operation */
-void grpc_cq_end_op(grpc_completion_queue *cc, void *tag, grpc_call *call,
-                    int success);
+void grpc_cq_end_op(grpc_completion_queue *cc, void *tag, int success,
+                    void (*done)(void *done_arg, grpc_cq_completion *storage),
+                    void *done_arg, grpc_cq_completion *storage);
 
 grpc_pollset *grpc_cq_pollset(grpc_completion_queue *cc);
 
diff --git a/src/core/surface/init.c b/src/core/surface/init.c
index 3847ded..04e27d3 100644
--- a/src/core/surface/init.c
+++ b/src/core/surface/init.c
@@ -35,6 +35,7 @@
 
 #include <grpc/census.h>
 #include <grpc/grpc.h>
+#include <grpc/support/time.h>
 #include "src/core/channel/channel_stack.h"
 #include "src/core/client_config/resolver_registry.h"
 #include "src/core/client_config/resolvers/dns_resolver.h"
@@ -64,6 +65,7 @@
 
   gpr_mu_lock(&g_init_mu);
   if (++g_initializations == 1) {
+    gpr_time_init();
     grpc_resolver_registry_init("dns:///");
     grpc_register_resolver_type("dns", grpc_dns_resolver_factory_create());
 #ifdef GPR_POSIX_SOCKET
diff --git a/src/core/surface/server.c b/src/core/surface/server.c
index adc7ef8..4dc51bf 100644
--- a/src/core/surface/server.c
+++ b/src/core/surface/server.c
@@ -72,12 +72,14 @@
 
 typedef enum { BATCH_CALL, REGISTERED_CALL } requested_call_type;
 
-typedef struct {
+typedef struct requested_call {
   requested_call_type type;
+  struct requested_call *next;
   void *tag;
   grpc_completion_queue *cq_bound_to_call;
   grpc_completion_queue *cq_for_notification;
   grpc_call **call;
+  grpc_cq_completion completion;
   union {
     struct {
       grpc_call_details *details;
@@ -92,17 +94,11 @@
   } data;
 } requested_call;
 
-typedef struct {
-  requested_call *calls;
-  size_t count;
-  size_t capacity;
-} requested_call_array;
-
 struct registered_method {
   char *method;
   char *host;
   call_data *pending;
-  requested_call_array requested;
+  requested_call *requests;
   registered_method *next;
 };
 
@@ -131,6 +127,7 @@
 typedef struct shutdown_tag {
   void *tag;
   grpc_completion_queue *cq;
+  grpc_cq_completion completion;
 } shutdown_tag;
 
 struct grpc_server {
@@ -153,7 +150,7 @@
   gpr_mu mu_call;   /* mutex for call-specific state */
 
   registered_method *registered_methods;
-  requested_call_array requested_calls;
+  requested_call *requests;
 
   gpr_uint8 shutdown;
   gpr_uint8 shutdown_published;
@@ -273,7 +270,8 @@
 }
 
 static void channel_broadcaster_shutdown(channel_broadcaster *cb,
-                                         int send_goaway, int force_disconnect) {
+                                         int send_goaway,
+                                         int force_disconnect) {
   size_t i;
 
   for (i = 0; i < cb->num_channels; i++) {
@@ -332,22 +330,6 @@
   return 1;
 }
 
-static void requested_call_array_destroy(requested_call_array *array) {
-  gpr_free(array->calls);
-}
-
-static requested_call *requested_call_array_add(requested_call_array *array) {
-  requested_call *rc;
-  if (array->count == array->capacity) {
-    array->capacity = GPR_MAX(array->capacity + 8, array->capacity * 2);
-    array->calls =
-        gpr_realloc(array->calls, sizeof(requested_call) * array->capacity);
-  }
-  rc = &array->calls[array->count++];
-  memset(rc, 0, sizeof(*rc));
-  return rc;
-}
-
 static void server_ref(grpc_server *server) {
   gpr_ref(&server->internal_refcount);
 }
@@ -359,12 +341,10 @@
   gpr_mu_destroy(&server->mu_global);
   gpr_mu_destroy(&server->mu_call);
   gpr_free(server->channel_filters);
-  requested_call_array_destroy(&server->requested_calls);
   while ((rm = server->registered_methods) != NULL) {
     server->registered_methods = rm->next;
     gpr_free(rm->method);
     gpr_free(rm->host);
-    requested_call_array_destroy(&rm->requested);
     gpr_free(rm);
   }
   for (i = 0; i < server->cq_count; i++) {
@@ -412,23 +392,24 @@
 
 static void finish_start_new_rpc(grpc_server *server, grpc_call_element *elem,
                                  call_data **pending_root,
-                                 requested_call_array *array) {
-  requested_call rc;
+                                 requested_call **requests) {
+  requested_call *rc;
   call_data *calld = elem->call_data;
   gpr_mu_lock(&server->mu_call);
-  if (array->count == 0) {
+  rc = *requests;
+  if (rc == NULL) {
     gpr_mu_lock(&calld->mu_state);
     calld->state = PENDING;
     gpr_mu_unlock(&calld->mu_state);
     call_list_join(pending_root, calld, PENDING_START);
     gpr_mu_unlock(&server->mu_call);
   } else {
-    rc = array->calls[--array->count];
+    *requests = rc->next;
     gpr_mu_lock(&calld->mu_state);
     calld->state = ACTIVATED;
     gpr_mu_unlock(&calld->mu_state);
     gpr_mu_unlock(&server->mu_call);
-    begin_call(server, calld, &rc);
+    begin_call(server, calld, rc);
   }
 }
 
@@ -451,7 +432,7 @@
       if (rm->host != calld->host) continue;
       if (rm->method != calld->path) continue;
       finish_start_new_rpc(server, elem, &rm->server_registered_method->pending,
-                           &rm->server_registered_method->requested);
+                           &rm->server_registered_method->requests);
       return;
     }
     /* check for a wildcard method definition (no host set) */
@@ -463,12 +444,12 @@
       if (rm->host != NULL) continue;
       if (rm->method != calld->path) continue;
       finish_start_new_rpc(server, elem, &rm->server_registered_method->pending,
-                           &rm->server_registered_method->requested);
+                           &rm->server_registered_method->requests);
       return;
     }
   }
   finish_start_new_rpc(server, elem, &server->lists[PENDING_START],
-                       &server->requested_calls);
+                       &server->requests);
 }
 
 static void kill_zombie(void *elem, int success) {
@@ -484,6 +465,10 @@
   return n;
 }
 
+static void done_shutdown_event(void *server, grpc_cq_completion *completion) {
+  server_unref(server);
+}
+
 static int num_channels(grpc_server *server) {
   channel_data *chand;
   int n = 0;
@@ -503,9 +488,9 @@
   if (server->root_channel_data.next != &server->root_channel_data ||
       server->listeners_destroyed < num_listeners(server)) {
     if (gpr_time_cmp(
-            gpr_time_sub(gpr_now(), server->last_shutdown_message_time),
+            gpr_time_sub(gpr_now(GPR_CLOCK_REALTIME), server->last_shutdown_message_time),
             gpr_time_from_seconds(1)) >= 0) {
-      server->last_shutdown_message_time = gpr_now();
+      server->last_shutdown_message_time = gpr_now(GPR_CLOCK_REALTIME);
       gpr_log(GPR_DEBUG,
               "Waiting for %d channels and %d/%d listeners to be destroyed"
               " before shutting down server",
@@ -517,8 +502,10 @@
   }
   server->shutdown_published = 1;
   for (i = 0; i < server->num_shutdown_tags; i++) {
-    grpc_cq_end_op(server->shutdown_tags[i].cq, server->shutdown_tags[i].tag,
-                   NULL, 1);
+    server_ref(server);
+    grpc_cq_end_op(server->shutdown_tags[i].cq, server->shutdown_tags[i].tag, 1,
+                   done_shutdown_event, server,
+                   &server->shutdown_tags[i].completion);
   }
 }
 
@@ -942,15 +929,14 @@
 void grpc_server_shutdown_and_notify(grpc_server *server,
                                      grpc_completion_queue *cq, void *tag) {
   listener *l;
-  requested_call_array requested_calls;
-  size_t i;
+  requested_call *requests = NULL;
   registered_method *rm;
   shutdown_tag *sdt;
   channel_broadcaster broadcaster;
 
   /* lock, and gather up some stuff to do */
   gpr_mu_lock(&server->mu_global);
-  grpc_cq_begin_op(cq, NULL);
+  grpc_cq_begin_op(cq);
   server->shutdown_tags =
       gpr_realloc(server->shutdown_tags,
                   sizeof(shutdown_tag) * (server->num_shutdown_tags + 1));
@@ -962,29 +948,21 @@
     return;
   }
 
-  server->last_shutdown_message_time = gpr_now();
+  server->last_shutdown_message_time = gpr_now(GPR_CLOCK_REALTIME);
 
   channel_broadcaster_init(server, &broadcaster);
 
   /* collect all unregistered then registered calls */
   gpr_mu_lock(&server->mu_call);
-  requested_calls = server->requested_calls;
-  memset(&server->requested_calls, 0, sizeof(server->requested_calls));
+  requests = server->requests;
+  server->requests = NULL;
   for (rm = server->registered_methods; rm; rm = rm->next) {
-    if (requested_calls.count + rm->requested.count >
-        requested_calls.capacity) {
-      requested_calls.capacity =
-          GPR_MAX(requested_calls.count + rm->requested.count,
-                  2 * requested_calls.capacity);
-      requested_calls.calls =
-          gpr_realloc(requested_calls.calls, sizeof(*requested_calls.calls) *
-                                                 requested_calls.capacity);
+    while (rm->requests != NULL) {
+      requested_call *c = rm->requests;
+      rm->requests = c->next;
+      c->next = requests;
+      requests = c;
     }
-    memcpy(requested_calls.calls + requested_calls.count, rm->requested.calls,
-           sizeof(*requested_calls.calls) * rm->requested.count);
-    requested_calls.count += rm->requested.count;
-    gpr_free(rm->requested.calls);
-    memset(&rm->requested, 0, sizeof(rm->requested));
   }
   gpr_mu_unlock(&server->mu_call);
 
@@ -993,10 +971,11 @@
   gpr_mu_unlock(&server->mu_global);
 
   /* terminate all the requested calls */
-  for (i = 0; i < requested_calls.count; i++) {
-    fail_call(server, &requested_calls.calls[i]);
+  while (requests != NULL) {
+    requested_call *next = requests->next;
+    fail_call(server, requests);
+    requests = next;
   }
-  gpr_free(requested_calls.calls);
 
   /* Shutdown listeners */
   for (l = server->listeners; l; l = l->next) {
@@ -1058,7 +1037,7 @@
 static grpc_call_error queue_call_request(grpc_server *server,
                                           requested_call *rc) {
   call_data *calld = NULL;
-  requested_call_array *requested_calls = NULL;
+  requested_call **requests = NULL;
   gpr_mu_lock(&server->mu_call);
   if (server->shutdown) {
     gpr_mu_unlock(&server->mu_call);
@@ -1069,12 +1048,12 @@
     case BATCH_CALL:
       calld =
           call_list_remove_head(&server->lists[PENDING_START], PENDING_START);
-      requested_calls = &server->requested_calls;
+      requests = &server->requests;
       break;
     case REGISTERED_CALL:
       calld = call_list_remove_head(
           &rc->data.registered.registered_method->pending, PENDING_START);
-      requested_calls = &rc->data.registered.registered_method->requested;
+      requests = &rc->data.registered.registered_method->requests;
       break;
   }
   if (calld != NULL) {
@@ -1086,7 +1065,8 @@
     begin_call(server, calld, rc);
     return GRPC_CALL_OK;
   } else {
-    *requested_call_array_add(requested_calls) = *rc;
+    rc->next = *requests;
+    *requests = rc;
     gpr_mu_unlock(&server->mu_call);
     return GRPC_CALL_OK;
   }
@@ -1097,22 +1077,23 @@
     grpc_metadata_array *initial_metadata,
     grpc_completion_queue *cq_bound_to_call,
     grpc_completion_queue *cq_for_notification, void *tag) {
-  requested_call rc;
+  requested_call *rc = gpr_malloc(sizeof(*rc));
   GRPC_SERVER_LOG_REQUEST_CALL(GPR_INFO, server, call, details,
                                initial_metadata, cq_bound_to_call,
                                cq_for_notification, tag);
   if (!grpc_cq_is_server_cq(cq_for_notification)) {
+    gpr_free(rc);
     return GRPC_CALL_ERROR_NOT_SERVER_COMPLETION_QUEUE;
   }
-  grpc_cq_begin_op(cq_for_notification, NULL);
-  rc.type = BATCH_CALL;
-  rc.tag = tag;
-  rc.cq_bound_to_call = cq_bound_to_call;
-  rc.cq_for_notification = cq_for_notification;
-  rc.call = call;
-  rc.data.batch.details = details;
-  rc.data.batch.initial_metadata = initial_metadata;
-  return queue_call_request(server, &rc);
+  grpc_cq_begin_op(cq_for_notification);
+  rc->type = BATCH_CALL;
+  rc->tag = tag;
+  rc->cq_bound_to_call = cq_bound_to_call;
+  rc->cq_for_notification = cq_for_notification;
+  rc->call = call;
+  rc->data.batch.details = details;
+  rc->data.batch.initial_metadata = initial_metadata;
+  return queue_call_request(server, rc);
 }
 
 grpc_call_error grpc_server_request_registered_call(
@@ -1120,22 +1101,23 @@
     grpc_metadata_array *initial_metadata, grpc_byte_buffer **optional_payload,
     grpc_completion_queue *cq_bound_to_call,
     grpc_completion_queue *cq_for_notification, void *tag) {
-  requested_call rc;
+  requested_call *rc = gpr_malloc(sizeof(*rc));
   registered_method *registered_method = rm;
   if (!grpc_cq_is_server_cq(cq_for_notification)) {
+    gpr_free(rc);
     return GRPC_CALL_ERROR_NOT_SERVER_COMPLETION_QUEUE;
   }
-  grpc_cq_begin_op(cq_for_notification, NULL);
-  rc.type = REGISTERED_CALL;
-  rc.tag = tag;
-  rc.cq_bound_to_call = cq_bound_to_call;
-  rc.cq_for_notification = cq_for_notification;
-  rc.call = call;
-  rc.data.registered.registered_method = registered_method;
-  rc.data.registered.deadline = deadline;
-  rc.data.registered.initial_metadata = initial_metadata;
-  rc.data.registered.optional_payload = optional_payload;
-  return queue_call_request(server, &rc);
+  grpc_cq_begin_op(cq_for_notification);
+  rc->type = REGISTERED_CALL;
+  rc->tag = tag;
+  rc->cq_bound_to_call = cq_bound_to_call;
+  rc->cq_for_notification = cq_for_notification;
+  rc->call = call;
+  rc->data.registered.registered_method = registered_method;
+  rc->data.registered.deadline = deadline;
+  rc->data.registered.initial_metadata = initial_metadata;
+  rc->data.registered.optional_payload = optional_payload;
+  return queue_call_request(server, rc);
 }
 
 static void publish_registered_or_batch(grpc_call *call, int success,
@@ -1202,8 +1184,11 @@
   }
 
   GRPC_CALL_INTERNAL_REF(calld->call, "server");
-  grpc_call_start_ioreq_and_call_back(calld->call, req, r - req, publish,
-                                      rc->tag);
+  grpc_call_start_ioreq_and_call_back(calld->call, req, r - req, publish, rc);
+}
+
+static void done_request_event(void *req, grpc_cq_completion *c) {
+  gpr_free(req);
 }
 
 static void fail_call(grpc_server *server, requested_call *rc) {
@@ -1216,15 +1201,19 @@
       rc->data.registered.initial_metadata->count = 0;
       break;
   }
-  grpc_cq_end_op(rc->cq_for_notification, rc->tag, NULL, 0);
+  grpc_cq_end_op(rc->cq_for_notification, rc->tag, 0, done_request_event, rc,
+                 &rc->completion);
 }
 
 static void publish_registered_or_batch(grpc_call *call, int success,
-                                        void *tag) {
+                                        void *prc) {
   grpc_call_element *elem =
       grpc_call_stack_element(grpc_call_get_call_stack(call), 0);
+  requested_call *rc = prc;
   call_data *calld = elem->call_data;
-  grpc_cq_end_op(calld->cq_new, tag, call, success);
+  grpc_cq_end_op(calld->cq_new, rc->tag, success, done_request_event, rc,
+                 &rc->completion);
+  GRPC_CALL_INTERNAL_UNREF(call, "server", 0);
 }
 
 const grpc_channel_args *grpc_server_get_channel_args(grpc_server *server) {
diff --git a/src/core/surface/version.c b/src/core/surface/version.c
new file mode 100644
index 0000000..4f5d648
--- /dev/null
+++ b/src/core/surface/version.c
@@ -0,0 +1,41 @@
+/*
+ *
+ * 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.
+ *
+ */
+
+/* This file is autogenerated from:
+   templates/src/core/surface/version.c.template */
+
+#include <grpc/grpc.h>
+
+const char *grpc_version_string(void) {
+	return "0.10.0.0";
+}
diff --git a/src/core/transport/chttp2/frame_data.c b/src/core/transport/chttp2/frame_data.c
index 0ad62a9..7e39801 100644
--- a/src/core/transport/chttp2/frame_data.c
+++ b/src/core/transport/chttp2/frame_data.c
@@ -89,12 +89,9 @@
   fh_0:
     case GRPC_CHTTP2_DATA_FH_0:
       p->frame_type = *cur;
-      if (++cur == end) {
-        p->state = GRPC_CHTTP2_DATA_FH_1;
-        return GRPC_CHTTP2_PARSE_OK;
-      }
       switch (p->frame_type) {
         case 0:
+          /* noop */
           break;
         case 1:
           gpr_log(GPR_ERROR, "Compressed GRPC frames not yet supported");
@@ -103,6 +100,10 @@
           gpr_log(GPR_ERROR, "Bad GRPC frame type 0x%02x", p->frame_type);
           return GRPC_CHTTP2_STREAM_ERROR;
       }
+      if (++cur == end) {
+        p->state = GRPC_CHTTP2_DATA_FH_1;
+        return GRPC_CHTTP2_PARSE_OK;
+      }
     /* fallthrough */
     case GRPC_CHTTP2_DATA_FH_1:
       p->frame_size = ((gpr_uint32)*cur) << 24;
diff --git a/src/core/transport/chttp2/parsing.c b/src/core/transport/chttp2/parsing.c
index 130167f..9597395 100644
--- a/src/core/transport/chttp2/parsing.c
+++ b/src/core/transport/chttp2/parsing.c
@@ -205,7 +205,8 @@
     }
     if (stream_parsing->saw_rst_stream) {
       stream_global->cancelled = 1;
-      stream_global->cancelled_status = grpc_chttp2_http2_error_to_grpc_status(stream_parsing->rst_stream_reason);
+      stream_global->cancelled_status = grpc_chttp2_http2_error_to_grpc_status(
+          stream_parsing->rst_stream_reason);
       if (stream_parsing->rst_stream_reason == GRPC_CHTTP2_NO_ERROR) {
         stream_global->published_cancelled = 1;
       }
@@ -599,7 +600,7 @@
     }
     grpc_chttp2_incoming_metadata_buffer_set_deadline(
         &stream_parsing->incoming_metadata,
-        gpr_time_add(gpr_now(), *cached_timeout));
+        gpr_time_add(gpr_now(GPR_CLOCK_REALTIME), *cached_timeout));
     GRPC_MDELEM_UNREF(md);
   } else {
     grpc_chttp2_incoming_metadata_buffer_add(&stream_parsing->incoming_metadata,
diff --git a/src/core/transport/chttp2/stream_encoder.c b/src/core/transport/chttp2/stream_encoder.c
index 56ab820..d553d80 100644
--- a/src/core/transport/chttp2/stream_encoder.c
+++ b/src/core/transport/chttp2/stream_encoder.c
@@ -437,7 +437,8 @@
                          framer_state *st) {
   char timeout_str[GRPC_CHTTP2_TIMEOUT_ENCODE_MIN_BUFSIZE];
   grpc_mdelem *mdelem;
-  grpc_chttp2_encode_timeout(gpr_time_sub(deadline, gpr_now()), timeout_str);
+  grpc_chttp2_encode_timeout(
+      gpr_time_sub(deadline, gpr_now(GPR_CLOCK_REALTIME)), timeout_str);
   mdelem = grpc_mdelem_from_metadata_strings(
       c->mdctx, GRPC_MDSTR_REF(c->timeout_key_str),
       grpc_mdstr_from_string(c->mdctx, timeout_str));
diff --git a/src/core/transport/metadata.c b/src/core/transport/metadata.c
index 9cbb095..e95b7a2 100644
--- a/src/core/transport/metadata.c
+++ b/src/core/transport/metadata.c
@@ -87,6 +87,7 @@
   gpr_atm refcnt;
 
   /* private only data */
+  gpr_mu mu_user_data;
   void *user_data;
   void (*destroy_user_data)(void *user_data);
 
@@ -183,7 +184,7 @@
   /* This seed is used to prevent remote connections from controlling hash table
    * collisions. It needs to be somewhat unpredictable to a remote connection.
    */
-  return grpc_mdctx_create_with_seed(gpr_now().tv_nsec);
+  return grpc_mdctx_create_with_seed(gpr_now(GPR_CLOCK_REALTIME).tv_nsec);
 }
 
 static void discard_metadata(grpc_mdctx *ctx) {
@@ -200,6 +201,7 @@
       if (cur->user_data) {
         cur->destroy_user_data(cur->user_data);
       }
+      gpr_mu_destroy(&cur->mu_user_data);
       gpr_free(cur);
       cur = next;
       ctx->mdtab_free--;
@@ -467,6 +469,7 @@
   md->user_data = NULL;
   md->destroy_user_data = NULL;
   md->bucket_next = ctx->mdtab[hash % ctx->mdtab_capacity];
+  gpr_mu_init(&md->mu_user_data);
 #ifdef GRPC_METADATA_REFCOUNT_DEBUG
   gpr_log(GPR_DEBUG, "ELM   NEW:%p:%d: '%s' = '%s'", md,
           gpr_atm_no_barrier_load(&md->refcnt),
@@ -581,18 +584,29 @@
 void *grpc_mdelem_get_user_data(grpc_mdelem *md,
                                 void (*if_destroy_func)(void *)) {
   internal_metadata *im = (internal_metadata *)md;
-  return im->destroy_user_data == if_destroy_func ? im->user_data : NULL;
+  void *result;
+  gpr_mu_lock(&im->mu_user_data);
+  result = im->destroy_user_data == if_destroy_func ? im->user_data : NULL;
+  gpr_mu_unlock(&im->mu_user_data);
+  return result;
 }
 
 void grpc_mdelem_set_user_data(grpc_mdelem *md, void (*destroy_func)(void *),
                                void *user_data) {
   internal_metadata *im = (internal_metadata *)md;
   GPR_ASSERT((user_data == NULL) == (destroy_func == NULL));
+  gpr_mu_lock(&im->mu_user_data);
   if (im->destroy_user_data) {
-    im->destroy_user_data(im->user_data);
+    /* user data can only be set once */
+    gpr_mu_unlock(&im->mu_user_data);
+    if (destroy_func != NULL) {
+      destroy_func(user_data);
+    }
+    return;
   }
   im->destroy_user_data = destroy_func;
   im->user_data = user_data;
+  gpr_mu_unlock(&im->mu_user_data);
 }
 
 gpr_slice grpc_mdstr_as_base64_encoded_and_huffman_compressed(grpc_mdstr *gs) {
diff --git a/src/cpp/server/server_context.cc b/src/cpp/server/server_context.cc
index 1bb3a8b..0be7713 100644
--- a/src/cpp/server/server_context.cc
+++ b/src/cpp/server/server_context.cc
@@ -153,4 +153,11 @@
   auth_context_ = CreateAuthContext(call);
 }
 
+std::shared_ptr<const AuthContext> ServerContext::auth_context() const {
+  if (auth_context_.get() == nullptr) {
+    auth_context_ = CreateAuthContext(call_);
+  }
+  return auth_context_;
+}
+
 }  // namespace grpc
diff --git a/src/csharp/Grpc.Auth/Grpc.Auth.csproj b/src/csharp/Grpc.Auth/Grpc.Auth.csproj
index e6abbbf..fdec2e7 100644
--- a/src/csharp/Grpc.Auth/Grpc.Auth.csproj
+++ b/src/csharp/Grpc.Auth/Grpc.Auth.csproj
@@ -68,6 +68,9 @@
     <Reference Include="System.Net.Http.WebRequest" />
   </ItemGroup>
   <ItemGroup>
+    <Compile Include="..\Grpc.Core\Version.cs">
+      <Link>Version.cs</Link>
+    </Compile>
     <Compile Include="Properties\AssemblyInfo.cs" />
     <Compile Include="GoogleCredential.cs" />
     <Compile Include="OAuth2InterceptorFactory.cs" />
@@ -81,6 +84,7 @@
   </ItemGroup>
   <ItemGroup>
     <None Include="app.config" />
+    <None Include="Grpc.Auth.nuspec" />
     <None Include="packages.config" />
   </ItemGroup>
   <Import Project="..\packages\Microsoft.Bcl.Build.1.0.14\tools\Microsoft.Bcl.Build.targets" Condition="Exists('..\packages\Microsoft.Bcl.Build.1.0.14\tools\Microsoft.Bcl.Build.targets')" />
diff --git a/src/csharp/Grpc.Auth/Grpc.Auth.nuspec b/src/csharp/Grpc.Auth/Grpc.Auth.nuspec
index e7a538b..1262bdb 100644
--- a/src/csharp/Grpc.Auth/Grpc.Auth.nuspec
+++ b/src/csharp/Grpc.Auth/Grpc.Auth.nuspec
@@ -5,19 +5,19 @@
     <title>gRPC C# Auth</title>
     <summary>Auth library for C# implementation of gRPC - an RPC library and framework</summary>
     <description>Auth library for C# implementation of gRPC - an RPC library and framework. See project site for more info.</description>
-    <version>0.5.1</version>
+    <version>$version$</version>
     <authors>Google Inc.</authors>
     <owners>grpc-packages</owners>
     <licenseUrl>https://github.com/grpc/grpc/blob/master/LICENSE</licenseUrl>
     <projectUrl>https://github.com/grpc/grpc</projectUrl>
     <requireLicenseAcceptance>false</requireLicenseAcceptance>
-    <releaseNotes>Release 0.5.1 of gRPC C#</releaseNotes>
+    <releaseNotes>Release $version$ of gRPC C#</releaseNotes>
     <copyright>Copyright 2015, Google Inc.</copyright>
     <tags>gRPC RPC Protocol HTTP/2 Auth OAuth2</tags>
 	<dependencies>
 	  <dependency id="BouncyCastle" version="1.7.0" />
 	  <dependency id="Google.Apis.Auth" version="1.9.1" />
-	  <dependency id="Grpc.Core" version="0.5.1" />
+	  <dependency id="Grpc.Core" version="$version$" />
     </dependencies>
   </metadata>
   <files>
diff --git a/src/csharp/Grpc.Auth/Properties/AssemblyInfo.cs b/src/csharp/Grpc.Auth/Properties/AssemblyInfo.cs
index c442ccc..70cb32d 100644
--- a/src/csharp/Grpc.Auth/Properties/AssemblyInfo.cs
+++ b/src/csharp/Grpc.Auth/Properties/AssemblyInfo.cs
@@ -9,6 +9,5 @@
 [assembly: AssemblyCopyright("Google Inc.  All rights reserved.")]
 [assembly: AssemblyTrademark("")]
 [assembly: AssemblyCulture("")]
-[assembly: AssemblyVersion("0.5.*")]
 
 [assembly: InternalsVisibleTo("Grpc.Auth.Tests")]
diff --git a/src/csharp/Grpc.Core.Tests/ClientServerTest.cs b/src/csharp/Grpc.Core.Tests/ClientServerTest.cs
index 21f94d3..e797dd8 100644
--- a/src/csharp/Grpc.Core.Tests/ClientServerTest.cs
+++ b/src/csharp/Grpc.Core.Tests/ClientServerTest.cs
@@ -73,12 +73,6 @@
         Server server;
         Channel channel;
 
-        [TestFixtureSetUp]
-        public void InitClass()
-        {
-            GrpcEnvironment.Initialize();
-        }
-
         [SetUp]
         public void Init()
         {
diff --git a/src/csharp/Grpc.Core.Tests/Grpc.Core.Tests.csproj b/src/csharp/Grpc.Core.Tests/Grpc.Core.Tests.csproj
index 92e28b7..927954c 100644
--- a/src/csharp/Grpc.Core.Tests/Grpc.Core.Tests.csproj
+++ b/src/csharp/Grpc.Core.Tests/Grpc.Core.Tests.csproj
@@ -37,6 +37,9 @@
     </Reference>
   </ItemGroup>
   <ItemGroup>
+    <Compile Include="..\Grpc.Core\Version.cs">
+      <Link>Version.cs</Link>
+    </Compile>
     <Compile Include="Properties\AssemblyInfo.cs" />
     <Compile Include="ClientServerTest.cs" />
     <Compile Include="ServerTest.cs" />
@@ -63,4 +66,4 @@
     <Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" />
   </ItemGroup>
   <ItemGroup />
-</Project>
+</Project>
\ No newline at end of file
diff --git a/src/csharp/Grpc.Core.Tests/GrpcEnvironmentTest.cs b/src/csharp/Grpc.Core.Tests/GrpcEnvironmentTest.cs
index 6a132a5..9ae1277 100644
--- a/src/csharp/Grpc.Core.Tests/GrpcEnvironmentTest.cs
+++ b/src/csharp/Grpc.Core.Tests/GrpcEnvironmentTest.cs
@@ -43,16 +43,17 @@
         [Test]
         public void InitializeAndShutdownGrpcEnvironment()
         {
-            GrpcEnvironment.Initialize();
-            Assert.IsNotNull(GrpcEnvironment.ThreadPool.CompletionQueue);
+            var env = GrpcEnvironment.GetInstance();
+            Assert.IsNotNull(env.CompletionQueue);
             GrpcEnvironment.Shutdown();
         }
 
         [Test]
         public void SubsequentInvocations()
         {
-            GrpcEnvironment.Initialize();
-            GrpcEnvironment.Initialize();
+            var env1 = GrpcEnvironment.GetInstance();
+            var env2 = GrpcEnvironment.GetInstance();
+            Assert.IsTrue(object.ReferenceEquals(env1, env2));
             GrpcEnvironment.Shutdown();
             GrpcEnvironment.Shutdown();
         }
@@ -60,15 +61,13 @@
         [Test]
         public void InitializeAfterShutdown()
         {
-            GrpcEnvironment.Initialize();
-            var tp1 = GrpcEnvironment.ThreadPool;
+            var env1 = GrpcEnvironment.GetInstance();
             GrpcEnvironment.Shutdown();
 
-            GrpcEnvironment.Initialize();
-            var tp2 = GrpcEnvironment.ThreadPool;
+            var env2 = GrpcEnvironment.GetInstance();
             GrpcEnvironment.Shutdown();
 
-            Assert.IsFalse(object.ReferenceEquals(tp1, tp2));
+            Assert.IsFalse(object.ReferenceEquals(env1, env2));
         }
     }
 }
diff --git a/src/csharp/Grpc.Core.Tests/PInvokeTest.cs b/src/csharp/Grpc.Core.Tests/PInvokeTest.cs
index 8b3c910..714c2f7 100644
--- a/src/csharp/Grpc.Core.Tests/PInvokeTest.cs
+++ b/src/csharp/Grpc.Core.Tests/PInvokeTest.cs
@@ -53,18 +53,6 @@
         [DllImport("grpc_csharp_ext.dll")]
         static extern IntPtr grpcsharp_test_nop(IntPtr ptr);
 
-        [TestFixtureSetUp]
-        public void Init()
-        {
-            GrpcEnvironment.Initialize();
-        }
-
-        [TestFixtureTearDown]
-        public void Cleanup()
-        {
-            GrpcEnvironment.Shutdown();
-        }
-
         /// <summary>
         /// (~1.26us .NET Windows)
         /// </summary>
diff --git a/src/csharp/Grpc.Core.Tests/Properties/AssemblyInfo.cs b/src/csharp/Grpc.Core.Tests/Properties/AssemblyInfo.cs
index 7f6133a..c2e5e81 100644
--- a/src/csharp/Grpc.Core.Tests/Properties/AssemblyInfo.cs
+++ b/src/csharp/Grpc.Core.Tests/Properties/AssemblyInfo.cs
@@ -9,4 +9,3 @@
 [assembly: AssemblyCopyright("Google Inc.  All rights reserved.")]
 [assembly: AssemblyTrademark("")]
 [assembly: AssemblyCulture("")]
-[assembly: AssemblyVersion("0.5.*")]
diff --git a/src/csharp/Grpc.Core.Tests/ServerTest.cs b/src/csharp/Grpc.Core.Tests/ServerTest.cs
index 02c773c..1119aa3 100644
--- a/src/csharp/Grpc.Core.Tests/ServerTest.cs
+++ b/src/csharp/Grpc.Core.Tests/ServerTest.cs
@@ -44,13 +44,10 @@
         [Test]
         public void StartAndShutdownServer()
         {
-            GrpcEnvironment.Initialize();
-
             Server server = new Server();
             server.AddListeningPort("localhost", Server.PickUnusedPort);
             server.Start();
             server.ShutdownAsync().Wait();
-
             GrpcEnvironment.Shutdown();
         }
     }
diff --git a/src/csharp/Grpc.Core/Calls.cs b/src/csharp/Grpc.Core/Calls.cs
index 9f8baac..7502822 100644
--- a/src/csharp/Grpc.Core/Calls.cs
+++ b/src/csharp/Grpc.Core/Calls.cs
@@ -58,7 +58,7 @@
             where TResponse : class
         {
             var asyncCall = new AsyncCall<TRequest, TResponse>(call.RequestMarshaller.Serializer, call.ResponseMarshaller.Deserializer);
-            asyncCall.Initialize(call.Channel, GetCompletionQueue(), call.Name);
+            asyncCall.Initialize(call.Channel, call.Channel.CompletionQueue, call.Name);
             var asyncResult = asyncCall.UnaryCallAsync(req, call.Headers);
             RegisterCancellationCallback(asyncCall, token);
             return await asyncResult;
@@ -69,7 +69,7 @@
             where TResponse : class
         {
             var asyncCall = new AsyncCall<TRequest, TResponse>(call.RequestMarshaller.Serializer, call.ResponseMarshaller.Deserializer);
-            asyncCall.Initialize(call.Channel, GetCompletionQueue(), call.Name);
+            asyncCall.Initialize(call.Channel, call.Channel.CompletionQueue, call.Name);
             asyncCall.StartServerStreamingCall(req, call.Headers);
             RegisterCancellationCallback(asyncCall, token);
             var responseStream = new ClientResponseStream<TRequest, TResponse>(asyncCall);
@@ -81,7 +81,7 @@
             where TResponse : class
         {
             var asyncCall = new AsyncCall<TRequest, TResponse>(call.RequestMarshaller.Serializer, call.ResponseMarshaller.Deserializer);
-            asyncCall.Initialize(call.Channel, GetCompletionQueue(), call.Name);
+            asyncCall.Initialize(call.Channel, call.Channel.CompletionQueue, call.Name);
             var resultTask = asyncCall.ClientStreamingCallAsync(call.Headers);
             RegisterCancellationCallback(asyncCall, token);
             var requestStream = new ClientRequestStream<TRequest, TResponse>(asyncCall);
@@ -93,7 +93,7 @@
             where TResponse : class
         {
             var asyncCall = new AsyncCall<TRequest, TResponse>(call.RequestMarshaller.Serializer, call.ResponseMarshaller.Deserializer);
-            asyncCall.Initialize(call.Channel, GetCompletionQueue(), call.Name);
+            asyncCall.Initialize(call.Channel, call.Channel.CompletionQueue, call.Name);
             asyncCall.StartDuplexStreamingCall(call.Headers);
             RegisterCancellationCallback(asyncCall, token);
             var requestStream = new ClientRequestStream<TRequest, TResponse>(asyncCall);
@@ -108,13 +108,5 @@
                 token.Register(() => asyncCall.Cancel());
             }
         }
-
-        /// <summary>
-        /// Gets shared completion queue used for async calls.
-        /// </summary>
-        private static CompletionQueueSafeHandle GetCompletionQueue()
-        {
-            return GrpcEnvironment.ThreadPool.CompletionQueue;
-        }
     }
 }
diff --git a/src/csharp/Grpc.Core/Channel.cs b/src/csharp/Grpc.Core/Channel.cs
index d6bfbb7..5baf260 100644
--- a/src/csharp/Grpc.Core/Channel.cs
+++ b/src/csharp/Grpc.Core/Channel.cs
@@ -42,8 +42,10 @@
     /// </summary>
     public class Channel : IDisposable
     {
+        readonly GrpcEnvironment environment;
         readonly ChannelSafeHandle handle;
         readonly string target;
+        bool disposed;
 
         /// <summary>
         /// Creates a channel that connects to a specific host.
@@ -54,6 +56,7 @@
         /// <param name="options">Channel options.</param>
         public Channel(string host, Credentials credentials = null, IEnumerable<ChannelOption> options = null)
         {
+            this.environment = GrpcEnvironment.GetInstance();
             using (ChannelArgsSafeHandle nativeChannelArgs = ChannelOptions.CreateChannelArgs(options))
             {
                 if (credentials != null)
@@ -105,10 +108,35 @@
             }
         }
 
+        internal CompletionQueueSafeHandle CompletionQueue
+        {
+            get
+            {
+                return this.environment.CompletionQueue;
+            }
+        }
+
+        internal CompletionRegistry CompletionRegistry
+        {
+            get
+            {
+                return this.environment.CompletionRegistry;
+            }
+        }
+
+        internal GrpcEnvironment Environment
+        {
+            get
+            {
+                return this.environment;
+            }
+        }
+
         protected virtual void Dispose(bool disposing)
         {
-            if (handle != null && !handle.IsInvalid)
+            if (disposing && handle != null && !disposed)
             {
+                disposed = true;
                 handle.Dispose();
             }
         }
diff --git a/src/csharp/Grpc.Core/Grpc.Core.csproj b/src/csharp/Grpc.Core/Grpc.Core.csproj
index a36a6a5..cde42c3 100644
--- a/src/csharp/Grpc.Core/Grpc.Core.csproj
+++ b/src/csharp/Grpc.Core/Grpc.Core.csproj
@@ -33,8 +33,9 @@
   </PropertyGroup>
   <ItemGroup>
     <Reference Include="System" />
-    <Reference Include="System.Collections.Immutable">
-      <HintPath>..\packages\Microsoft.Bcl.Immutable.1.0.34\lib\portable-net45+win8+wp8+wpa81\System.Collections.Immutable.dll</HintPath>
+    <Reference Include="System.Collections.Immutable, Version=1.1.36.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
+      <SpecificVersion>False</SpecificVersion>
+      <HintPath>..\packages\System.Collections.Immutable.1.1.36\lib\portable-net45+win8+wp8+wpa81\System.Collections.Immutable.dll</HintPath>
     </Reference>
     <Reference Include="System.Interactive.Async">
       <HintPath>..\packages\Ix-Async.1.2.3\lib\net45\System.Interactive.Async.dll</HintPath>
@@ -48,6 +49,7 @@
     <Compile Include="IAsyncStreamWriter.cs" />
     <Compile Include="IAsyncStreamReader.cs" />
     <Compile Include="Internal\GrpcLog.cs" />
+    <Compile Include="Version.cs" />
     <Compile Include="Properties\AssemblyInfo.cs" />
     <Compile Include="RpcException.cs" />
     <Compile Include="Calls.cs" />
@@ -103,6 +105,7 @@
     <Compile Include="ChannelOptions.cs" />
   </ItemGroup>
   <ItemGroup>
+    <None Include="Grpc.Core.nuspec" />
     <None Include="packages.config" />
   </ItemGroup>
   <Choose>
@@ -130,4 +133,4 @@
   </Target>
   <Import Project="..\packages\grpc.dependencies.openssl.redist.1.0.2.2\build\portable-net45\grpc.dependencies.openssl.redist.targets" Condition="Exists('..\packages\grpc.dependencies.openssl.redist.1.0.2.2\build\portable-net45\grpc.dependencies.openssl.redist.targets')" />
   <Import Project="..\packages\grpc.dependencies.zlib.redist.1.2.8.9\build\portable-net45\grpc.dependencies.zlib.redist.targets" Condition="Exists('..\packages\grpc.dependencies.zlib.redist.1.2.8.9\build\portable-net45\grpc.dependencies.zlib.redist.targets')" />
-</Project>
+</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 629b978..5ace6dc 100644
--- a/src/csharp/Grpc.Core/Grpc.Core.nuspec
+++ b/src/csharp/Grpc.Core/Grpc.Core.nuspec
@@ -5,19 +5,19 @@
     <title>gRPC C# Core</title>
     <summary>Core C# implementation of gRPC - an RPC library and framework</summary>
     <description>Core C# implementation of gRPC - an RPC library and framework. See project site for more info.</description>
-    <version>0.5.1</version>
+    <version>$version$</version>
     <authors>Google Inc.</authors>
     <owners>grpc-packages</owners>
     <licenseUrl>https://github.com/grpc/grpc/blob/master/LICENSE</licenseUrl>
     <projectUrl>https://github.com/grpc/grpc</projectUrl>
     <requireLicenseAcceptance>false</requireLicenseAcceptance>
-    <releaseNotes>Release 0.5.1 of gRPC C#</releaseNotes>
+    <releaseNotes>Release $version$ of gRPC C#</releaseNotes>
     <copyright>Copyright 2015, Google Inc.</copyright>
     <tags>gRPC RPC Protocol HTTP/2</tags>
 	<dependencies>
-	  <dependency id="Microsoft.Bcl.Immutable" version="1.0.34" />
+	  <dependency id="System.Collections.Immutable" version="1.1.36" />
 	  <dependency id="Ix-Async" version="1.2.3" />
-	  <dependency id="grpc.native.csharp_ext" version="0.9.1" />
+	  <dependency id="grpc.native.csharp_ext" version="$GrpcNativeCsharpExtVersion$" />
     </dependencies>
   </metadata>
   <files>
diff --git a/src/csharp/Grpc.Core/GrpcEnvironment.cs b/src/csharp/Grpc.Core/GrpcEnvironment.cs
index 30ff289..47d1651 100644
--- a/src/csharp/Grpc.Core/GrpcEnvironment.cs
+++ b/src/csharp/Grpc.Core/GrpcEnvironment.cs
@@ -33,7 +33,9 @@
 
 using System;
 using System.Runtime.InteropServices;
+using System.Threading.Tasks;
 using Grpc.Core.Internal;
+using Grpc.Core.Utils;
 
 namespace Grpc.Core
 {
@@ -51,20 +53,18 @@
         static extern void grpcsharp_shutdown();
 
         static object staticLock = new object();
-        static volatile GrpcEnvironment instance;
+        static GrpcEnvironment instance;
 
         readonly GrpcThreadPool threadPool;
         readonly CompletionRegistry completionRegistry;
+        readonly DebugStats debugStats = new DebugStats();
         bool isClosed;
 
         /// <summary>
-        /// Makes sure GRPC environment is initialized. Subsequent invocations don't have any
-        /// effect unless you call Shutdown first.
-        /// Although normal use cases assume you will call this just once in your application's
-        /// lifetime (and call Shutdown once you're done), for the sake of easier testing it's
-        /// allowed to initialize the environment again after it has been successfully shutdown.
+        /// Returns an instance of initialized gRPC environment.
+        /// Subsequent invocations return the same instance unless Shutdown has been called first.
         /// </summary>
-        public static void Initialize()
+        internal static GrpcEnvironment GetInstance()
         {
             lock (staticLock)
             {
@@ -72,12 +72,13 @@
                 {
                     instance = new GrpcEnvironment();
                 }
+                return instance;
             }
         }
 
         /// <summary>
-        /// Shuts down the GRPC environment if it was initialized before.
-        /// Repeated invocations have no effect.
+        /// Shuts down the gRPC environment if it was initialized before.
+        /// Blocks until the environment has been fully shutdown.
         /// </summary>
         public static void Shutdown()
         {
@@ -87,38 +88,10 @@
                 {
                     instance.Close();
                     instance = null;
-
-                    CheckDebugStats();
                 }
             }
         }
 
-        internal static GrpcThreadPool ThreadPool
-        {
-            get
-            {
-                var inst = instance;
-                if (inst == null)
-                {
-                    throw new InvalidOperationException("GRPC environment not initialized");
-                }
-                return inst.threadPool;
-            }
-        }
-
-        internal static CompletionRegistry CompletionRegistry
-        {
-            get
-            {
-                var inst = instance;
-                if (inst == null)
-                {
-                    throw new InvalidOperationException("GRPC environment not initialized");
-                }
-                return inst.completionRegistry;
-            }
-        }
-
         /// <summary>
         /// Creates gRPC environment.
         /// </summary>
@@ -126,14 +99,47 @@
         {
             GrpcLog.RedirectNativeLogs(Console.Error);
             grpcsharp_init();
-            completionRegistry = new CompletionRegistry();
-            threadPool = new GrpcThreadPool(THREAD_POOL_SIZE);
+            completionRegistry = new CompletionRegistry(this);
+            threadPool = new GrpcThreadPool(this, THREAD_POOL_SIZE);
             threadPool.Start();
             // TODO: use proper logging here
             Console.WriteLine("GRPC initialized.");
         }
 
         /// <summary>
+        /// Gets the completion registry used by this gRPC environment.
+        /// </summary>
+        internal CompletionRegistry CompletionRegistry
+        {
+            get
+            {
+                return this.completionRegistry;
+            }
+        }
+
+        /// <summary>
+        /// Gets the completion queue used by this gRPC environment.
+        /// </summary>
+        internal CompletionQueueSafeHandle CompletionQueue
+        {
+            get
+            {
+                return this.threadPool.CompletionQueue;
+            }
+        }
+
+        /// <summary>
+        /// Gets the completion queue used by this gRPC environment.
+        /// </summary>
+        internal DebugStats DebugStats
+        {
+            get
+            {
+                return this.debugStats;
+            }
+        }
+
+        /// <summary>
         /// Shuts down this environment.
         /// </summary>
         private void Close()
@@ -146,32 +152,28 @@
             grpcsharp_shutdown();
             isClosed = true;
 
+            debugStats.CheckOK();
+
             // TODO: use proper logging here
             Console.WriteLine("GRPC shutdown.");
         }
 
-        private static void CheckDebugStats()
+        /// <summary>
+        /// Shuts down this environment asynchronously.
+        /// </summary>
+        private Task CloseAsync()
         {
-            var remainingClientCalls = DebugStats.ActiveClientCalls.Count;
-            if (remainingClientCalls != 0)
-            {                
-                DebugWarning(string.Format("Detected {0} client calls that weren't disposed properly.", remainingClientCalls));
-            }
-            var remainingServerCalls = DebugStats.ActiveServerCalls.Count;
-            if (remainingServerCalls != 0)
+            return Task.Run(() =>
             {
-                DebugWarning(string.Format("Detected {0} server calls that weren't disposed properly.", remainingServerCalls));
-            }
-            var pendingBatchCompletions = DebugStats.PendingBatchCompletions.Count;
-            if (pendingBatchCompletions != 0)
-            {
-                DebugWarning(string.Format("Detected {0} pending batch completions.", pendingBatchCompletions));
-            }
-        }
-
-        private static void DebugWarning(string message)
-        {
-            throw new Exception("Shutdown check: " + message);
+                try
+                {
+                    Close();
+                }
+                catch (Exception e)
+                {
+                    Console.WriteLine("Error occured while shutting down GrpcEnvironment: " + e);
+                }
+            });
         }
     }
 }
diff --git a/src/csharp/Grpc.Core/Internal/AsyncCall.cs b/src/csharp/Grpc.Core/Internal/AsyncCall.cs
index d350f45..24b75d1 100644
--- a/src/csharp/Grpc.Core/Internal/AsyncCall.cs
+++ b/src/csharp/Grpc.Core/Internal/AsyncCall.cs
@@ -47,6 +47,8 @@
     /// </summary>
     internal class AsyncCall<TRequest, TResponse> : AsyncCallBase<TRequest, TResponse>
     {
+        Channel channel;
+
         // Completion of a pending unary response if not null.
         TaskCompletionSource<TResponse> unaryResponseTcs;
 
@@ -61,8 +63,9 @@
 
         public void Initialize(Channel channel, CompletionQueueSafeHandle cq, string methodName)
         {
-            var call = CallSafeHandle.Create(channel.Handle, cq, methodName, channel.Target, Timespec.InfFuture);
-            DebugStats.ActiveClientCalls.Increment();
+            this.channel = channel;
+            var call = CallSafeHandle.Create(channel.Handle, channel.CompletionRegistry, cq, methodName, channel.Target, Timespec.InfFuture);
+            channel.Environment.DebugStats.ActiveClientCalls.Increment();
             InitializeInternal(call);
         }
 
@@ -277,7 +280,7 @@
 
         protected override void OnReleaseResources()
         {
-            DebugStats.ActiveClientCalls.Decrement();
+            channel.Environment.DebugStats.ActiveClientCalls.Decrement();
         }
 
         /// <summary>
diff --git a/src/csharp/Grpc.Core/Internal/AsyncCallServer.cs b/src/csharp/Grpc.Core/Internal/AsyncCallServer.cs
index 4f510ba..309067e 100644
--- a/src/csharp/Grpc.Core/Internal/AsyncCallServer.cs
+++ b/src/csharp/Grpc.Core/Internal/AsyncCallServer.cs
@@ -48,14 +48,17 @@
     internal class AsyncCallServer<TRequest, TResponse> : AsyncCallBase<TResponse, TRequest>
     {
         readonly TaskCompletionSource<object> finishedServersideTcs = new TaskCompletionSource<object>();
+        readonly GrpcEnvironment environment;
 
-        public AsyncCallServer(Func<TResponse, byte[]> serializer, Func<byte[], TRequest> deserializer) : base(serializer, deserializer)
+        public AsyncCallServer(Func<TResponse, byte[]> serializer, Func<byte[], TRequest> deserializer, GrpcEnvironment environment) : base(serializer, deserializer)
         {
+            this.environment = Preconditions.CheckNotNull(environment);
         }
 
         public void Initialize(CallSafeHandle call)
         {
-            DebugStats.ActiveServerCalls.Increment();
+            call.SetCompletionRegistry(environment.CompletionRegistry);
+            environment.DebugStats.ActiveServerCalls.Increment();
             InitializeInternal(call);
         }
 
@@ -114,7 +117,7 @@
 
         protected override void OnReleaseResources()
         {
-            DebugStats.ActiveServerCalls.Decrement();
+            environment.DebugStats.ActiveServerCalls.Decrement();
         }
 
         /// <summary>
diff --git a/src/csharp/Grpc.Core/Internal/CallSafeHandle.cs b/src/csharp/Grpc.Core/Internal/CallSafeHandle.cs
index ef92b44..3b246ac 100644
--- a/src/csharp/Grpc.Core/Internal/CallSafeHandle.cs
+++ b/src/csharp/Grpc.Core/Internal/CallSafeHandle.cs
@@ -43,6 +43,7 @@
     internal class CallSafeHandle : SafeHandleZeroIsInvalid
     {
         const uint GRPC_WRITE_BUFFER_HINT = 1;
+        CompletionRegistry completionRegistry;
 
         [DllImport("grpc_csharp_ext.dll")]
         static extern CallSafeHandle grpcsharp_channel_create_call(ChannelSafeHandle channel, CompletionQueueSafeHandle cq, string method, string host, Timespec deadline);
@@ -97,15 +98,22 @@
         {
         }
 
-        public static CallSafeHandle Create(ChannelSafeHandle channel, CompletionQueueSafeHandle cq, string method, string host, Timespec deadline)
+        public static CallSafeHandle Create(ChannelSafeHandle channel, CompletionRegistry registry, CompletionQueueSafeHandle cq, string method, string host, Timespec deadline)
         {
-            return grpcsharp_channel_create_call(channel, cq, method, host, deadline);
+            var result = grpcsharp_channel_create_call(channel, cq, method, host, deadline);
+            result.SetCompletionRegistry(registry);
+            return result;
+        }
+
+        public void SetCompletionRegistry(CompletionRegistry completionRegistry)
+        {
+            this.completionRegistry = completionRegistry;
         }
 
         public void StartUnary(byte[] payload, BatchCompletionDelegate callback, MetadataArraySafeHandle metadataArray)
         {
             var ctx = BatchContextSafeHandle.Create();
-            GrpcEnvironment.CompletionRegistry.RegisterBatchCompletion(ctx, callback);
+            completionRegistry.RegisterBatchCompletion(ctx, callback);
             grpcsharp_call_start_unary(this, ctx, payload, new UIntPtr((ulong)payload.Length), metadataArray)
                 .CheckOk();
         }
@@ -119,56 +127,56 @@
         public void StartClientStreaming(BatchCompletionDelegate callback, MetadataArraySafeHandle metadataArray)
         {
             var ctx = BatchContextSafeHandle.Create();
-            GrpcEnvironment.CompletionRegistry.RegisterBatchCompletion(ctx, callback);
+            completionRegistry.RegisterBatchCompletion(ctx, callback);
             grpcsharp_call_start_client_streaming(this, ctx, metadataArray).CheckOk();
         }
 
         public void StartServerStreaming(byte[] payload, BatchCompletionDelegate callback, MetadataArraySafeHandle metadataArray)
         {
             var ctx = BatchContextSafeHandle.Create();
-            GrpcEnvironment.CompletionRegistry.RegisterBatchCompletion(ctx, callback);
+            completionRegistry.RegisterBatchCompletion(ctx, callback);
             grpcsharp_call_start_server_streaming(this, ctx, payload, new UIntPtr((ulong)payload.Length), metadataArray).CheckOk();
         }
 
         public void StartDuplexStreaming(BatchCompletionDelegate callback, MetadataArraySafeHandle metadataArray)
         {
             var ctx = BatchContextSafeHandle.Create();
-            GrpcEnvironment.CompletionRegistry.RegisterBatchCompletion(ctx, callback);
+            completionRegistry.RegisterBatchCompletion(ctx, callback);
             grpcsharp_call_start_duplex_streaming(this, ctx, metadataArray).CheckOk();
         }
 
         public void StartSendMessage(byte[] payload, BatchCompletionDelegate callback)
         {
             var ctx = BatchContextSafeHandle.Create();
-            GrpcEnvironment.CompletionRegistry.RegisterBatchCompletion(ctx, callback);
+            completionRegistry.RegisterBatchCompletion(ctx, callback);
             grpcsharp_call_send_message(this, ctx, payload, new UIntPtr((ulong)payload.Length)).CheckOk();
         }
 
         public void StartSendCloseFromClient(BatchCompletionDelegate callback)
         {
             var ctx = BatchContextSafeHandle.Create();
-            GrpcEnvironment.CompletionRegistry.RegisterBatchCompletion(ctx, callback);
+            completionRegistry.RegisterBatchCompletion(ctx, callback);
             grpcsharp_call_send_close_from_client(this, ctx).CheckOk();
         }
 
         public void StartSendStatusFromServer(Status status, BatchCompletionDelegate callback)
         {
             var ctx = BatchContextSafeHandle.Create();
-            GrpcEnvironment.CompletionRegistry.RegisterBatchCompletion(ctx, callback);
+            completionRegistry.RegisterBatchCompletion(ctx, callback);
             grpcsharp_call_send_status_from_server(this, ctx, status.StatusCode, status.Detail).CheckOk();
         }
 
         public void StartReceiveMessage(BatchCompletionDelegate callback)
         {
             var ctx = BatchContextSafeHandle.Create();
-            GrpcEnvironment.CompletionRegistry.RegisterBatchCompletion(ctx, callback);
+            completionRegistry.RegisterBatchCompletion(ctx, callback);
             grpcsharp_call_recv_message(this, ctx).CheckOk();
         }
 
         public void StartServerSide(BatchCompletionDelegate callback)
         {
             var ctx = BatchContextSafeHandle.Create();
-            GrpcEnvironment.CompletionRegistry.RegisterBatchCompletion(ctx, callback);
+            completionRegistry.RegisterBatchCompletion(ctx, callback);
             grpcsharp_call_start_serverside(this, ctx).CheckOk();
         }
 
diff --git a/src/csharp/Grpc.Core/Internal/CompletionRegistry.cs b/src/csharp/Grpc.Core/Internal/CompletionRegistry.cs
index 80f006a..f6d8aa0 100644
--- a/src/csharp/Grpc.Core/Internal/CompletionRegistry.cs
+++ b/src/csharp/Grpc.Core/Internal/CompletionRegistry.cs
@@ -45,11 +45,17 @@
 
     internal class CompletionRegistry
     {
-        readonly ConcurrentDictionary<IntPtr, OpCompletionDelegate> dict = new ConcurrentDictionary<IntPtr, OpCompletionDelegate>();  
+        readonly GrpcEnvironment environment;
+        readonly ConcurrentDictionary<IntPtr, OpCompletionDelegate> dict = new ConcurrentDictionary<IntPtr, OpCompletionDelegate>();
+
+        public CompletionRegistry(GrpcEnvironment environment)
+        {
+            this.environment = environment;
+        }
 
         public void Register(IntPtr key, OpCompletionDelegate callback)
         {
-            DebugStats.PendingBatchCompletions.Increment();
+            environment.DebugStats.PendingBatchCompletions.Increment();
             Preconditions.CheckState(dict.TryAdd(key, callback));
         }
 
@@ -63,7 +69,7 @@
         {
             OpCompletionDelegate value;
             Preconditions.CheckState(dict.TryRemove(key, out value));
-            DebugStats.PendingBatchCompletions.Decrement();
+            environment.DebugStats.PendingBatchCompletions.Decrement();
             return value;
         }
 
diff --git a/src/csharp/Grpc.Core/Internal/DebugStats.cs b/src/csharp/Grpc.Core/Internal/DebugStats.cs
index ef9d9af..8793450 100644
--- a/src/csharp/Grpc.Core/Internal/DebugStats.cs
+++ b/src/csharp/Grpc.Core/Internal/DebugStats.cs
@@ -36,12 +36,39 @@
 
 namespace Grpc.Core.Internal
 {
-    internal static class DebugStats
+    internal class DebugStats
     {
-        public static readonly AtomicCounter ActiveClientCalls = new AtomicCounter();
+        public readonly AtomicCounter ActiveClientCalls = new AtomicCounter();
 
-        public static readonly AtomicCounter ActiveServerCalls = new AtomicCounter();
+        public readonly AtomicCounter ActiveServerCalls = new AtomicCounter();
 
-        public static readonly AtomicCounter PendingBatchCompletions = new AtomicCounter();
+        public readonly AtomicCounter PendingBatchCompletions = new AtomicCounter();
+
+        /// <summary>
+        /// Checks the debug stats and take action for any inconsistency found.
+        /// </summary>
+        public void CheckOK()
+        {
+            var remainingClientCalls = ActiveClientCalls.Count;
+            if (remainingClientCalls != 0)
+            {                
+                DebugWarning(string.Format("Detected {0} client calls that weren't disposed properly.", remainingClientCalls));
+            }
+            var remainingServerCalls = ActiveServerCalls.Count;
+            if (remainingServerCalls != 0)
+            {
+                DebugWarning(string.Format("Detected {0} server calls that weren't disposed properly.", remainingServerCalls));
+            }
+            var pendingBatchCompletions = PendingBatchCompletions.Count;
+            if (pendingBatchCompletions != 0)
+            {
+                DebugWarning(string.Format("Detected {0} pending batch completions.", pendingBatchCompletions));
+            }
+        }
+
+        private void DebugWarning(string message)
+        {
+            throw new Exception("Shutdown check: " + message);
+        }
     }
 }
diff --git a/src/csharp/Grpc.Core/Internal/GrpcThreadPool.cs b/src/csharp/Grpc.Core/Internal/GrpcThreadPool.cs
index 89b44a4..b77e893 100644
--- a/src/csharp/Grpc.Core/Internal/GrpcThreadPool.cs
+++ b/src/csharp/Grpc.Core/Internal/GrpcThreadPool.cs
@@ -45,14 +45,16 @@
     /// </summary>
     internal class GrpcThreadPool
     {
+        readonly GrpcEnvironment environment;
         readonly object myLock = new object();
         readonly List<Thread> threads = new List<Thread>();
         readonly int poolSize;
 
         CompletionQueueSafeHandle cq;
 
-        public GrpcThreadPool(int poolSize)
+        public GrpcThreadPool(GrpcEnvironment environment, int poolSize)
         {
+            this.environment = environment;
             this.poolSize = poolSize;
         }
 
@@ -80,7 +82,7 @@
             {
                 cq.Shutdown();
 
-                Console.WriteLine("Waiting for GPRC threads to finish.");
+                Console.WriteLine("Waiting for GRPC threads to finish.");
                 foreach (var thread in threads)
                 {
                     thread.Join();
@@ -122,7 +124,7 @@
                     IntPtr tag = ev.tag;
                     try
                     {
-                        var callback = GrpcEnvironment.CompletionRegistry.Extract(tag);
+                        var callback = environment.CompletionRegistry.Extract(tag);
                         callback(success);
                     }
                     catch (Exception e)
diff --git a/src/csharp/Grpc.Core/Internal/ServerCallHandler.cs b/src/csharp/Grpc.Core/Internal/ServerCallHandler.cs
index c0e5bae..594e46b 100644
--- a/src/csharp/Grpc.Core/Internal/ServerCallHandler.cs
+++ b/src/csharp/Grpc.Core/Internal/ServerCallHandler.cs
@@ -42,7 +42,7 @@
 {
     internal interface IServerCallHandler
     {
-        Task HandleCall(string methodName, CallSafeHandle call, CompletionQueueSafeHandle cq);
+        Task HandleCall(string methodName, CallSafeHandle call, GrpcEnvironment environment);
     }
 
     internal class UnaryServerCallHandler<TRequest, TResponse> : IServerCallHandler
@@ -58,11 +58,12 @@
             this.handler = handler;
         }
 
-        public async Task HandleCall(string methodName, CallSafeHandle call, CompletionQueueSafeHandle cq)
+        public async Task HandleCall(string methodName, CallSafeHandle call, GrpcEnvironment environment)
         {
             var asyncCall = new AsyncCallServer<TRequest, TResponse>(
                 method.ResponseMarshaller.Serializer,
-                method.RequestMarshaller.Deserializer);
+                method.RequestMarshaller.Deserializer,
+                environment);
 
             asyncCall.Initialize(call);
             var finishedTask = asyncCall.ServerSideCallAsync();
@@ -110,11 +111,12 @@
             this.handler = handler;
         }
 
-        public async Task HandleCall(string methodName, CallSafeHandle call, CompletionQueueSafeHandle cq)
+        public async Task HandleCall(string methodName, CallSafeHandle call, GrpcEnvironment environment)
         {
             var asyncCall = new AsyncCallServer<TRequest, TResponse>(
                 method.ResponseMarshaller.Serializer,
-                method.RequestMarshaller.Deserializer);
+                method.RequestMarshaller.Deserializer,
+                environment);
 
             asyncCall.Initialize(call);
             var finishedTask = asyncCall.ServerSideCallAsync();
@@ -163,11 +165,12 @@
             this.handler = handler;
         }
 
-        public async Task HandleCall(string methodName, CallSafeHandle call, CompletionQueueSafeHandle cq)
+        public async Task HandleCall(string methodName, CallSafeHandle call, GrpcEnvironment environment)
         {
             var asyncCall = new AsyncCallServer<TRequest, TResponse>(
                 method.ResponseMarshaller.Serializer,
-                method.RequestMarshaller.Deserializer);
+                method.RequestMarshaller.Deserializer,
+                environment);
 
             asyncCall.Initialize(call);
             var finishedTask = asyncCall.ServerSideCallAsync();
@@ -219,11 +222,12 @@
             this.handler = handler;
         }
 
-        public async Task HandleCall(string methodName, CallSafeHandle call, CompletionQueueSafeHandle cq)
+        public async Task HandleCall(string methodName, CallSafeHandle call, GrpcEnvironment environment)
         {
             var asyncCall = new AsyncCallServer<TRequest, TResponse>(
                 method.ResponseMarshaller.Serializer,
-                method.RequestMarshaller.Deserializer);
+                method.RequestMarshaller.Deserializer,
+                environment);
 
             asyncCall.Initialize(call);
             var finishedTask = asyncCall.ServerSideCallAsync();
@@ -255,11 +259,11 @@
 
     internal class NoSuchMethodCallHandler : IServerCallHandler
     {
-        public async Task HandleCall(string methodName, CallSafeHandle call, CompletionQueueSafeHandle cq)
+        public async Task HandleCall(string methodName, CallSafeHandle call, GrpcEnvironment environment)
         {
             // We don't care about the payload type here.
             var asyncCall = new AsyncCallServer<byte[], byte[]>(
-                (payload) => payload, (payload) => payload);
+                (payload) => payload, (payload) => payload, environment);
             
             asyncCall.Initialize(call);
             var finishedTask = asyncCall.ServerSideCallAsync();
diff --git a/src/csharp/Grpc.Core/Internal/ServerSafeHandle.cs b/src/csharp/Grpc.Core/Internal/ServerSafeHandle.cs
index 83dbb91..9e1170e 100644
--- a/src/csharp/Grpc.Core/Internal/ServerSafeHandle.cs
+++ b/src/csharp/Grpc.Core/Internal/ServerSafeHandle.cs
@@ -91,19 +91,19 @@
         {
             grpcsharp_server_start(this);
         }
-            
-        public void ShutdownAndNotify(CompletionQueueSafeHandle cq, BatchCompletionDelegate callback)
+    
+        public void ShutdownAndNotify(BatchCompletionDelegate callback, GrpcEnvironment environment)
         {
             var ctx = BatchContextSafeHandle.Create();
-            GrpcEnvironment.CompletionRegistry.RegisterBatchCompletion(ctx, callback);
-            grpcsharp_server_shutdown_and_notify_callback(this, cq, ctx);
+            environment.CompletionRegistry.RegisterBatchCompletion(ctx, callback);
+            grpcsharp_server_shutdown_and_notify_callback(this, environment.CompletionQueue, ctx);
         }
 
-        public void RequestCall(CompletionQueueSafeHandle cq, BatchCompletionDelegate callback)
+        public void RequestCall(BatchCompletionDelegate callback, GrpcEnvironment environment)
         {
             var ctx = BatchContextSafeHandle.Create();
-            GrpcEnvironment.CompletionRegistry.RegisterBatchCompletion(ctx, callback);
-            grpcsharp_server_request_call(this, cq, ctx).CheckOk();
+            environment.CompletionRegistry.RegisterBatchCompletion(ctx, callback);
+            grpcsharp_server_request_call(this, environment.CompletionQueue, ctx).CheckOk();
         }
 
         protected override bool ReleaseHandle()
diff --git a/src/csharp/Grpc.Core/Properties/AssemblyInfo.cs b/src/csharp/Grpc.Core/Properties/AssemblyInfo.cs
index 03b6821..2b3d753 100644
--- a/src/csharp/Grpc.Core/Properties/AssemblyInfo.cs
+++ b/src/csharp/Grpc.Core/Properties/AssemblyInfo.cs
@@ -9,6 +9,5 @@
 [assembly: AssemblyCopyright("Google Inc.  All rights reserved.")]
 [assembly: AssemblyTrademark("")]
 [assembly: AssemblyCulture("")]
-[assembly: AssemblyVersion("0.5.*")]
 
 [assembly: InternalsVisibleTo("Grpc.Core.Tests")]
diff --git a/src/csharp/Grpc.Core/Server.cs b/src/csharp/Grpc.Core/Server.cs
index 8e81888..cbf7719 100644
--- a/src/csharp/Grpc.Core/Server.cs
+++ b/src/csharp/Grpc.Core/Server.cs
@@ -52,6 +52,7 @@
         /// </summary>
         public const int PickUnusedPort = 0;
 
+        readonly GrpcEnvironment environment;
         readonly ServerSafeHandle handle;
         readonly object myLock = new object();
 
@@ -67,9 +68,10 @@
         /// <param name="options">Channel options.</param>
         public Server(IEnumerable<ChannelOption> options = null)
         {
+            this.environment = GrpcEnvironment.GetInstance();
             using (var channelArgs = ChannelOptions.CreateChannelArgs(options))
             {
-                this.handle = ServerSafeHandle.NewServer(GetCompletionQueue(), channelArgs);
+                this.handle = ServerSafeHandle.NewServer(environment.CompletionQueue, channelArgs);
             }
         }
 
@@ -144,7 +146,7 @@
                 shutdownRequested = true;
             }
 
-            handle.ShutdownAndNotify(GetCompletionQueue(), HandleServerShutdown);
+            handle.ShutdownAndNotify(HandleServerShutdown, environment);
             await shutdownTcs.Task;
             handle.Dispose();
         }
@@ -173,7 +175,7 @@
                 shutdownRequested = true;
             }
 
-            handle.ShutdownAndNotify(GetCompletionQueue(), HandleServerShutdown);
+            handle.ShutdownAndNotify(HandleServerShutdown, environment);
             handle.CancelAllCalls();
             await shutdownTcs.Task;
             handle.Dispose();
@@ -208,7 +210,7 @@
             {
                 if (!shutdownRequested)
                 {
-                    handle.RequestCall(GetCompletionQueue(), HandleNewServerRpc);
+                    handle.RequestCall(HandleNewServerRpc, environment);
                 }
             }
         }
@@ -225,7 +227,7 @@
                 {
                     callHandler = new NoSuchMethodCallHandler();
                 }
-                await callHandler.HandleCall(method, call, GetCompletionQueue());
+                await callHandler.HandleCall(method, call, environment);
             }
             catch (Exception e)
             {
@@ -259,10 +261,5 @@
         {
             shutdownTcs.SetResult(null);
         }
-
-        private static CompletionQueueSafeHandle GetCompletionQueue()
-        {
-            return GrpcEnvironment.ThreadPool.CompletionQueue;
-        }
     }
 }
diff --git a/src/csharp/Grpc.Core/Version.cs b/src/csharp/Grpc.Core/Version.cs
new file mode 100644
index 0000000..972f495
--- /dev/null
+++ b/src/csharp/Grpc.Core/Version.cs
@@ -0,0 +1,6 @@
+using System.Reflection;
+using System.Runtime.CompilerServices;
+
+// The current version of gRPC C#.
+[assembly: AssemblyVersion("0.6.0.*")]
+
diff --git a/src/csharp/Grpc.Core/packages.config b/src/csharp/Grpc.Core/packages.config
index fb7eaae..6cdcdf2 100644
--- a/src/csharp/Grpc.Core/packages.config
+++ b/src/csharp/Grpc.Core/packages.config
@@ -3,5 +3,5 @@
   <package id="grpc.dependencies.openssl.redist" version="1.0.2.2" targetFramework="net45" />
   <package id="grpc.dependencies.zlib.redist" version="1.2.8.9" targetFramework="net45" />
   <package id="Ix-Async" version="1.2.3" targetFramework="net45" />
-  <package id="Microsoft.Bcl.Immutable" version="1.0.34" targetFramework="net45" />
+  <package id="System.Collections.Immutable" version="1.1.36" targetFramework="net45" />
 </packages>
\ No newline at end of file
diff --git a/src/csharp/Grpc.Examples.MathClient/Grpc.Examples.MathClient.csproj b/src/csharp/Grpc.Examples.MathClient/Grpc.Examples.MathClient.csproj
index 19bb434..5d54015 100644
--- a/src/csharp/Grpc.Examples.MathClient/Grpc.Examples.MathClient.csproj
+++ b/src/csharp/Grpc.Examples.MathClient/Grpc.Examples.MathClient.csproj
@@ -1,4 +1,4 @@
-<?xml version="1.0" encoding="utf-8"?>
+<?xml version="1.0" encoding="utf-8"?>
 <Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
   <PropertyGroup>
     <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
@@ -35,6 +35,9 @@
     <Reference Include="System" />
   </ItemGroup>
   <ItemGroup>
+    <Compile Include="..\Grpc.Core\Version.cs">
+      <Link>Version.cs</Link>
+    </Compile>
     <Compile Include="Properties\AssemblyInfo.cs" />
     <Compile Include="MathClient.cs" />
   </ItemGroup>
@@ -49,4 +52,4 @@
       <Name>Grpc.Examples</Name>
     </ProjectReference>
   </ItemGroup>
-</Project>
+</Project>
\ No newline at end of file
diff --git a/src/csharp/Grpc.Examples.MathClient/MathClient.cs b/src/csharp/Grpc.Examples.MathClient/MathClient.cs
index 360fe92..b763721 100644
--- a/src/csharp/Grpc.Examples.MathClient/MathClient.cs
+++ b/src/csharp/Grpc.Examples.MathClient/MathClient.cs
@@ -39,8 +39,6 @@
     {
         public static void Main(string[] args)
         {
-            GrpcEnvironment.Initialize();
-
             using (Channel channel = new Channel("127.0.0.1", 23456))
             {
                 Math.IMathClient stub = new Math.MathClient(channel);
diff --git a/src/csharp/Grpc.Examples.MathClient/Properties/AssemblyInfo.cs b/src/csharp/Grpc.Examples.MathClient/Properties/AssemblyInfo.cs
index 4b77472..0fb0dbd 100644
--- a/src/csharp/Grpc.Examples.MathClient/Properties/AssemblyInfo.cs
+++ b/src/csharp/Grpc.Examples.MathClient/Properties/AssemblyInfo.cs
@@ -9,4 +9,3 @@
 [assembly: AssemblyCopyright("Google Inc.  All rights reserved.")]
 [assembly: AssemblyTrademark("")]
 [assembly: AssemblyCulture("")]
-[assembly: AssemblyVersion("0.5.*")]
diff --git a/src/csharp/Grpc.Examples.MathServer/Grpc.Examples.MathServer.csproj b/src/csharp/Grpc.Examples.MathServer/Grpc.Examples.MathServer.csproj
index ba6586e..677d87d 100644
--- a/src/csharp/Grpc.Examples.MathServer/Grpc.Examples.MathServer.csproj
+++ b/src/csharp/Grpc.Examples.MathServer/Grpc.Examples.MathServer.csproj
@@ -35,6 +35,9 @@
     <Reference Include="System" />
   </ItemGroup>
   <ItemGroup>
+    <Compile Include="..\Grpc.Core\Version.cs">
+      <Link>Version.cs</Link>
+    </Compile>
     <Compile Include="Properties\AssemblyInfo.cs" />
     <Compile Include="MathServer.cs" />
   </ItemGroup>
diff --git a/src/csharp/Grpc.Examples.MathServer/MathServer.cs b/src/csharp/Grpc.Examples.MathServer/MathServer.cs
index d05e3f2..f440985 100644
--- a/src/csharp/Grpc.Examples.MathServer/MathServer.cs
+++ b/src/csharp/Grpc.Examples.MathServer/MathServer.cs
@@ -42,8 +42,6 @@
         {
             string host = "0.0.0.0";
 
-            GrpcEnvironment.Initialize();
-
             Server server = new Server();
             server.AddServiceDefinition(Math.BindService(new MathServiceImpl()));
             int port = server.AddListeningPort(host, 23456);
diff --git a/src/csharp/Grpc.Examples.MathServer/Properties/AssemblyInfo.cs b/src/csharp/Grpc.Examples.MathServer/Properties/AssemblyInfo.cs
index c18fc25..63035b6 100644
--- a/src/csharp/Grpc.Examples.MathServer/Properties/AssemblyInfo.cs
+++ b/src/csharp/Grpc.Examples.MathServer/Properties/AssemblyInfo.cs
@@ -9,4 +9,3 @@
 [assembly: AssemblyCopyright("Google Inc.  All rights reserved.")]
 [assembly: AssemblyTrademark("")]
 [assembly: AssemblyCulture("")]
-[assembly: AssemblyVersion("0.5.*")]
diff --git a/src/csharp/Grpc.Examples.Tests/Grpc.Examples.Tests.csproj b/src/csharp/Grpc.Examples.Tests/Grpc.Examples.Tests.csproj
index 6e84add..d59d751 100644
--- a/src/csharp/Grpc.Examples.Tests/Grpc.Examples.Tests.csproj
+++ b/src/csharp/Grpc.Examples.Tests/Grpc.Examples.Tests.csproj
@@ -43,6 +43,9 @@
     </Reference>
   </ItemGroup>
   <ItemGroup>
+    <Compile Include="..\Grpc.Core\Version.cs">
+      <Link>Version.cs</Link>
+    </Compile>
     <Compile Include="Properties\AssemblyInfo.cs" />
     <Compile Include="MathClientServerTests.cs" />
   </ItemGroup>
diff --git a/src/csharp/Grpc.Examples.Tests/MathClientServerTests.cs b/src/csharp/Grpc.Examples.Tests/MathClientServerTests.cs
index aadd49f..10dceb6 100644
--- a/src/csharp/Grpc.Examples.Tests/MathClientServerTests.cs
+++ b/src/csharp/Grpc.Examples.Tests/MathClientServerTests.cs
@@ -54,8 +54,6 @@
         [TestFixtureSetUp]
         public void Init()
         {
-            GrpcEnvironment.Initialize();
-
             server = new Server();
             server.AddServiceDefinition(Math.BindService(new MathServiceImpl()));
             int port = server.AddListeningPort(host, Server.PickUnusedPort);
@@ -75,7 +73,6 @@
         public void Cleanup()
         {
             channel.Dispose();
-
             server.ShutdownAsync().Wait();
             GrpcEnvironment.Shutdown();
         }
diff --git a/src/csharp/Grpc.Examples.Tests/Properties/AssemblyInfo.cs b/src/csharp/Grpc.Examples.Tests/Properties/AssemblyInfo.cs
index c1ba396..846afb4 100644
--- a/src/csharp/Grpc.Examples.Tests/Properties/AssemblyInfo.cs
+++ b/src/csharp/Grpc.Examples.Tests/Properties/AssemblyInfo.cs
@@ -9,4 +9,3 @@
 [assembly: AssemblyCopyright("Google Inc.  All rights reserved.")]
 [assembly: AssemblyTrademark("")]
 [assembly: AssemblyCulture("")]
-[assembly: AssemblyVersion("0.5.*")]
diff --git a/src/csharp/Grpc.Examples/Grpc.Examples.csproj b/src/csharp/Grpc.Examples/Grpc.Examples.csproj
index 5ce490f..eaf24a2 100644
--- a/src/csharp/Grpc.Examples/Grpc.Examples.csproj
+++ b/src/csharp/Grpc.Examples/Grpc.Examples.csproj
@@ -40,6 +40,9 @@
     </Reference>
   </ItemGroup>
   <ItemGroup>
+    <Compile Include="..\Grpc.Core\Version.cs">
+      <Link>Version.cs</Link>
+    </Compile>
     <Compile Include="Properties\AssemblyInfo.cs" />
     <Compile Include="Math.cs" />
     <Compile Include="MathGrpc.cs" />
diff --git a/src/csharp/Grpc.Examples/Properties/AssemblyInfo.cs b/src/csharp/Grpc.Examples/Properties/AssemblyInfo.cs
index a63e05d..9211138 100644
--- a/src/csharp/Grpc.Examples/Properties/AssemblyInfo.cs
+++ b/src/csharp/Grpc.Examples/Properties/AssemblyInfo.cs
@@ -9,4 +9,3 @@
 [assembly: AssemblyCopyright("Google Inc.  All rights reserved.")]
 [assembly: AssemblyTrademark("")]
 [assembly: AssemblyCulture("")]
-[assembly: AssemblyVersion("0.5.*")]
diff --git a/src/csharp/Grpc.HealthCheck.Tests/.gitignore b/src/csharp/Grpc.HealthCheck.Tests/.gitignore
new file mode 100644
index 0000000..1746e32
--- /dev/null
+++ b/src/csharp/Grpc.HealthCheck.Tests/.gitignore
@@ -0,0 +1,2 @@
+bin
+obj
diff --git a/src/csharp/Grpc.HealthCheck.Tests/Grpc.HealthCheck.Tests.csproj b/src/csharp/Grpc.HealthCheck.Tests/Grpc.HealthCheck.Tests.csproj
new file mode 100644
index 0000000..72e1103
--- /dev/null
+++ b/src/csharp/Grpc.HealthCheck.Tests/Grpc.HealthCheck.Tests.csproj
@@ -0,0 +1,82 @@
+<?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>{F8C6D937-C44B-4EE3-A431-B0FBAEACE47D}</ProjectGuid>
+    <OutputType>Library</OutputType>
+    <AppDesignerFolder>Properties</AppDesignerFolder>
+    <RootNamespace>Grpc.HealthCheck.Tests</RootNamespace>
+    <AssemblyName>Grpc.HealthCheck.Tests</AssemblyName>
+    <TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
+    <FileAlignment>512</FileAlignment>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+    <DebugSymbols>true</DebugSymbols>
+    <DebugType>full</DebugType>
+    <Optimize>false</Optimize>
+    <OutputPath>bin\Debug\</OutputPath>
+    <DefineConstants>DEBUG;TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+    <DebugType>pdbonly</DebugType>
+    <Optimize>true</Optimize>
+    <OutputPath>bin\Release\</OutputPath>
+    <DefineConstants>TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+  </PropertyGroup>
+  <ItemGroup>
+    <Reference Include="Google.ProtocolBuffers">
+      <HintPath>..\packages\Google.ProtocolBuffers.2.4.1.555\lib\net40\Google.ProtocolBuffers.dll</HintPath>
+    </Reference>
+    <Reference Include="Google.ProtocolBuffers.Serialization">
+      <HintPath>..\packages\Google.ProtocolBuffers.2.4.1.555\lib\net40\Google.ProtocolBuffers.Serialization.dll</HintPath>
+    </Reference>
+    <Reference Include="nunit.framework">
+      <HintPath>..\packages\NUnit.2.6.4\lib\nunit.framework.dll</HintPath>
+    </Reference>
+    <Reference Include="System" />
+    <Reference Include="System.Core" />
+    <Reference Include="System.Xml.Linq" />
+    <Reference Include="System.Data.DataSetExtensions" />
+    <Reference Include="Microsoft.CSharp" />
+    <Reference Include="System.Data" />
+    <Reference Include="System.Xml" />
+  </ItemGroup>
+  <ItemGroup>
+    <Compile Include="..\Grpc.Core\Version.cs">
+      <Link>Version.cs</Link>
+    </Compile>
+    <Compile Include="HealthServiceImplTest.cs" />
+    <Compile Include="HealthClientServerTest.cs" />
+    <Compile Include="Properties\AssemblyInfo.cs" />
+  </ItemGroup>
+  <ItemGroup>
+    <ProjectReference Include="..\Grpc.Core\Grpc.Core.csproj">
+      <Project>{ccc4440e-49f7-4790-b0af-feabb0837ae7}</Project>
+      <Name>Grpc.Core</Name>
+    </ProjectReference>
+    <ProjectReference Include="..\Grpc.HealthCheck\Grpc.HealthCheck.csproj">
+      <Project>{aa5e328a-8835-49d7-98ed-c29f2b3049f0}</Project>
+      <Name>Grpc.HealthCheck</Name>
+    </ProjectReference>
+  </ItemGroup>
+  <ItemGroup>
+    <None Include="packages.config" />
+  </ItemGroup>
+  <ItemGroup>
+    <Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" />
+  </ItemGroup>
+  <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
+  <!-- To modify your build process, add your task inside one of the targets below and uncomment it. 
+       Other similar extension points exist, see Microsoft.Common.targets.
+  <Target Name="BeforeBuild">
+  </Target>
+  <Target Name="AfterBuild">
+  </Target>
+  -->
+</Project>
\ No newline at end of file
diff --git a/src/csharp/Grpc.HealthCheck.Tests/HealthClientServerTest.cs b/src/csharp/Grpc.HealthCheck.Tests/HealthClientServerTest.cs
new file mode 100644
index 0000000..0ac1add
--- /dev/null
+++ b/src/csharp/Grpc.HealthCheck.Tests/HealthClientServerTest.cs
@@ -0,0 +1,97 @@
+#region Copyright notice and license
+// 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.
+#endregion
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+using Grpc.Core;
+using Grpc.Health.V1Alpha;
+using NUnit.Framework;
+
+namespace Grpc.HealthCheck.Tests
+{
+    /// <summary>
+    /// Health client talks to health server.
+    /// </summary>
+    public class HealthClientServerTest
+    {
+        const string Host = "localhost";
+        Server server;
+        Channel channel;
+        Grpc.Health.V1Alpha.Health.IHealthClient client;
+        Grpc.HealthCheck.HealthServiceImpl serviceImpl;
+
+        [TestFixtureSetUp]
+        public void Init()
+        {
+            serviceImpl = new HealthServiceImpl();
+
+            server = new Server();
+            server.AddServiceDefinition(Grpc.Health.V1Alpha.Health.BindService(serviceImpl));
+            int port = server.AddListeningPort(Host, Server.PickUnusedPort);
+            server.Start();
+            channel = new Channel(Host, port);
+
+            client = Grpc.Health.V1Alpha.Health.NewStub(channel);
+        }
+
+        [TestFixtureTearDown]
+        public void Cleanup()
+        {
+            channel.Dispose();
+
+            server.ShutdownAsync().Wait();
+            GrpcEnvironment.Shutdown();
+        }
+
+        [Test]
+        public void ServiceIsRunning()
+        {
+            serviceImpl.SetStatus("", "", HealthCheckResponse.Types.ServingStatus.SERVING);
+
+            var response = client.Check(HealthCheckRequest.CreateBuilder().SetHost("").SetService("").Build());
+            Assert.AreEqual(HealthCheckResponse.Types.ServingStatus.SERVING, response.Status);
+        }
+
+        [Test]
+        public void ServiceDoesntExist()
+        {
+            // TODO(jtattermusch): currently, this returns wrong status code, because we don't enable sending arbitrary status code from
+            // server handlers yet.
+            Assert.Throws(typeof(RpcException), () => client.Check(HealthCheckRequest.CreateBuilder().SetHost("").SetService("nonexistent.service").Build()));
+        }
+
+        // TODO(jtattermusch): add test with timeout once timeouts are supported
+    }
+}
\ No newline at end of file
diff --git a/src/csharp/Grpc.HealthCheck.Tests/HealthServiceImplTest.cs b/src/csharp/Grpc.HealthCheck.Tests/HealthServiceImplTest.cs
new file mode 100644
index 0000000..9b7c4f2
--- /dev/null
+++ b/src/csharp/Grpc.HealthCheck.Tests/HealthServiceImplTest.cs
@@ -0,0 +1,107 @@
+#region Copyright notice and license
+// 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.
+#endregion
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+using Grpc.Core;
+using Grpc.Health.V1Alpha;
+using NUnit.Framework;
+
+namespace Grpc.HealthCheck.Tests
+{
+    /// <summary>
+    /// Tests for HealthCheckServiceImpl
+    /// </summary>
+    public class HealthServiceImplTest
+    {
+        [Test]
+        public void SetStatus()
+        {
+            var impl = new HealthServiceImpl();
+            impl.SetStatus("", "", HealthCheckResponse.Types.ServingStatus.SERVING);
+            Assert.AreEqual(HealthCheckResponse.Types.ServingStatus.SERVING, GetStatusHelper(impl, "", ""));
+
+            impl.SetStatus("", "", HealthCheckResponse.Types.ServingStatus.NOT_SERVING);
+            Assert.AreEqual(HealthCheckResponse.Types.ServingStatus.NOT_SERVING, GetStatusHelper(impl, "", ""));
+
+            impl.SetStatus("virtual-host", "", HealthCheckResponse.Types.ServingStatus.UNKNOWN);
+            Assert.AreEqual(HealthCheckResponse.Types.ServingStatus.UNKNOWN, GetStatusHelper(impl, "virtual-host", ""));
+
+            impl.SetStatus("virtual-host", "grpc.test.TestService", HealthCheckResponse.Types.ServingStatus.SERVING);
+            Assert.AreEqual(HealthCheckResponse.Types.ServingStatus.SERVING, GetStatusHelper(impl, "virtual-host", "grpc.test.TestService"));
+        }
+
+        [Test]
+        public void ClearStatus()
+        {
+            var impl = new HealthServiceImpl();
+            impl.SetStatus("", "", HealthCheckResponse.Types.ServingStatus.SERVING);
+            impl.SetStatus("virtual-host", "", HealthCheckResponse.Types.ServingStatus.UNKNOWN);
+
+            impl.ClearStatus("", "");
+
+            Assert.Throws(Is.TypeOf(typeof(RpcException)).And.Property("Status").Property("StatusCode").EqualTo(StatusCode.NotFound), () => GetStatusHelper(impl, "", ""));
+            Assert.AreEqual(HealthCheckResponse.Types.ServingStatus.UNKNOWN, GetStatusHelper(impl, "virtual-host", ""));
+        }
+
+        [Test]
+        public void ClearAll()
+        {
+            var impl = new HealthServiceImpl();
+            impl.SetStatus("", "", HealthCheckResponse.Types.ServingStatus.SERVING);
+            impl.SetStatus("virtual-host", "", HealthCheckResponse.Types.ServingStatus.UNKNOWN);
+
+            impl.ClearAll();
+            Assert.Throws(typeof(RpcException), () => GetStatusHelper(impl, "", ""));
+            Assert.Throws(typeof(RpcException), () => GetStatusHelper(impl, "virtual-host", ""));
+        }
+
+        [Test]
+        public void NullsRejected()
+        {
+            var impl = new HealthServiceImpl();
+            Assert.Throws(typeof(NullReferenceException), () => impl.SetStatus(null, "", HealthCheckResponse.Types.ServingStatus.SERVING));
+            Assert.Throws(typeof(NullReferenceException), () => impl.SetStatus("", null, HealthCheckResponse.Types.ServingStatus.SERVING));
+
+            Assert.Throws(typeof(NullReferenceException), () => impl.ClearStatus(null, ""));
+            Assert.Throws(typeof(NullReferenceException), () => impl.ClearStatus("", null));
+        }
+
+        private static HealthCheckResponse.Types.ServingStatus GetStatusHelper(HealthServiceImpl impl, string host, string service)
+        {
+            return impl.Check(null, HealthCheckRequest.CreateBuilder().SetHost(host).SetService(service).Build()).Result.Status;
+        }
+    }
+}
diff --git a/src/csharp/Grpc.HealthCheck.Tests/Properties/AssemblyInfo.cs b/src/csharp/Grpc.HealthCheck.Tests/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000..d566030
--- /dev/null
+++ b/src/csharp/Grpc.HealthCheck.Tests/Properties/AssemblyInfo.cs
@@ -0,0 +1,11 @@
+using System.Reflection;
+using System.Runtime.CompilerServices;
+
+[assembly: AssemblyTitle("Grpc.HealthCheck.Tests")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("")]
+[assembly: AssemblyCopyright("Google Inc.  All rights reserved.")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
diff --git a/src/csharp/Grpc.HealthCheck.Tests/packages.config b/src/csharp/Grpc.HealthCheck.Tests/packages.config
new file mode 100644
index 0000000..050c4ea
--- /dev/null
+++ b/src/csharp/Grpc.HealthCheck.Tests/packages.config
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<packages>
+  <package id="Google.ProtocolBuffers" version="2.4.1.555" targetFramework="net45" />
+  <package id="NUnit" version="2.6.4" targetFramework="net45" />
+</packages>
\ No newline at end of file
diff --git a/src/csharp/Grpc.HealthCheck/.gitignore b/src/csharp/Grpc.HealthCheck/.gitignore
new file mode 100644
index 0000000..1746e32
--- /dev/null
+++ b/src/csharp/Grpc.HealthCheck/.gitignore
@@ -0,0 +1,2 @@
+bin
+obj
diff --git a/src/csharp/Grpc.HealthCheck/Grpc.HealthCheck.csproj b/src/csharp/Grpc.HealthCheck/Grpc.HealthCheck.csproj
new file mode 100644
index 0000000..4ebb644
--- /dev/null
+++ b/src/csharp/Grpc.HealthCheck/Grpc.HealthCheck.csproj
@@ -0,0 +1,79 @@
+<?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>{AA5E328A-8835-49D7-98ED-C29F2B3049F0}</ProjectGuid>
+    <OutputType>Library</OutputType>
+    <AppDesignerFolder>Properties</AppDesignerFolder>
+    <RootNamespace>Grpc.HealthCheck</RootNamespace>
+    <AssemblyName>Grpc.HealthCheck</AssemblyName>
+    <TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
+    <FileAlignment>512</FileAlignment>
+    <DocumentationFile>bin\$(Configuration)\Grpc.HealthCheck.Xml</DocumentationFile>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+    <DebugSymbols>true</DebugSymbols>
+    <DebugType>full</DebugType>
+    <Optimize>false</Optimize>
+    <OutputPath>bin\Debug\</OutputPath>
+    <DefineConstants>DEBUG;TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+    <DebugType>pdbonly</DebugType>
+    <Optimize>true</Optimize>
+    <OutputPath>bin\Release\</OutputPath>
+    <DefineConstants>TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+  </PropertyGroup>
+  <ItemGroup>
+    <Reference Include="Google.ProtocolBuffers">
+      <HintPath>..\packages\Google.ProtocolBuffers.2.4.1.555\lib\net40\Google.ProtocolBuffers.dll</HintPath>
+    </Reference>
+    <Reference Include="Google.ProtocolBuffers.Serialization">
+      <HintPath>..\packages\Google.ProtocolBuffers.2.4.1.555\lib\net40\Google.ProtocolBuffers.Serialization.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.Xml.Linq" />
+    <Reference Include="System.Data.DataSetExtensions" />
+    <Reference Include="Microsoft.CSharp" />
+    <Reference Include="System.Data" />
+    <Reference Include="System.Xml" />
+  </ItemGroup>
+  <ItemGroup>
+    <Compile Include="..\Grpc.Core\Version.cs">
+      <Link>Version.cs</Link>
+    </Compile>
+    <Compile Include="HealthServiceImpl.cs" />
+    <Compile Include="Health.cs" />
+    <Compile Include="HealthGrpc.cs" />
+    <Compile Include="Properties\AssemblyInfo.cs" />
+  </ItemGroup>
+  <ItemGroup>
+    <None Include="Grpc.HealthCheck.nuspec" />
+    <None Include="packages.config" />
+    <None Include="proto\health.proto" />
+  </ItemGroup>
+  <ItemGroup>
+    <ProjectReference Include="..\Grpc.Core\Grpc.Core.csproj">
+      <Project>{ccc4440e-49f7-4790-b0af-feabb0837ae7}</Project>
+      <Name>Grpc.Core</Name>
+    </ProjectReference>
+  </ItemGroup>
+  <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
+  <!-- To modify your build process, add your task inside one of the targets below and uncomment it. 
+       Other similar extension points exist, see Microsoft.Common.targets.
+  <Target Name="BeforeBuild">
+  </Target>
+  <Target Name="AfterBuild">
+  </Target>
+  -->
+</Project>
\ No newline at end of file
diff --git a/src/csharp/Grpc.HealthCheck/Grpc.HealthCheck.nuspec b/src/csharp/Grpc.HealthCheck/Grpc.HealthCheck.nuspec
new file mode 100644
index 0000000..ca35b36
--- /dev/null
+++ b/src/csharp/Grpc.HealthCheck/Grpc.HealthCheck.nuspec
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<package>
+  <metadata>
+    <id>Grpc.HealthCheck</id>
+    <title>gRPC C# Healthchecking</title>
+    <summary>Implementation of gRPC health service</summary>
+    <description>Example implementation of grpc.health.v1alpha service that can be used for health-checking.</description>
+    <version>$version$</version>
+    <authors>Google Inc.</authors>
+    <owners>grpc-packages</owners>
+    <licenseUrl>https://github.com/grpc/grpc/blob/master/LICENSE</licenseUrl>
+    <projectUrl>https://github.com/grpc/grpc</projectUrl>
+    <requireLicenseAcceptance>false</requireLicenseAcceptance>
+    <copyright>Copyright 2015, Google Inc.</copyright>
+    <tags>gRPC health check</tags>
+	<dependencies>
+	  <dependency id="Google.ProtocolBuffers" version="2.4.1.555" />
+	  <dependency id="Grpc.Core" version="$version$" />
+	  <dependency id="Ix-Async" version="1.2.3" />
+    </dependencies>
+  </metadata>
+  <files>
+    <file src="bin/Release/Grpc.HealthCheck.dll" target="lib/net45" />
+	<file src="bin/Release/Grpc.HealthCheck.pdb" target="lib/net45" />
+	<file src="bin/Release/Grpc.HealthCheck.xml" target="lib/net45" />
+	<file src="**\*.cs" target="src" />
+  </files>
+</package>
diff --git a/src/csharp/Grpc.HealthCheck/Health.cs b/src/csharp/Grpc.HealthCheck/Health.cs
new file mode 100644
index 0000000..361382d
--- /dev/null
+++ b/src/csharp/Grpc.HealthCheck/Health.cs
@@ -0,0 +1,687 @@
+// Generated by the protocol buffer compiler.  DO NOT EDIT!
+// source: health.proto
+#pragma warning disable 1591, 0612, 3021
+#region Designer generated code
+
+using pb = global::Google.ProtocolBuffers;
+using pbc = global::Google.ProtocolBuffers.Collections;
+using pbd = global::Google.ProtocolBuffers.Descriptors;
+using scg = global::System.Collections.Generic;
+namespace Grpc.Health.V1Alpha {
+
+  namespace Proto {
+
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+    public static partial class Health {
+
+      #region Extension registration
+      public static void RegisterAllExtensions(pb::ExtensionRegistry registry) {
+      }
+      #endregion
+      #region Static variables
+      internal static pbd::MessageDescriptor internal__static_grpc_health_v1alpha_HealthCheckRequest__Descriptor;
+      internal static pb::FieldAccess.FieldAccessorTable<global::Grpc.Health.V1Alpha.HealthCheckRequest, global::Grpc.Health.V1Alpha.HealthCheckRequest.Builder> internal__static_grpc_health_v1alpha_HealthCheckRequest__FieldAccessorTable;
+      internal static pbd::MessageDescriptor internal__static_grpc_health_v1alpha_HealthCheckResponse__Descriptor;
+      internal static pb::FieldAccess.FieldAccessorTable<global::Grpc.Health.V1Alpha.HealthCheckResponse, global::Grpc.Health.V1Alpha.HealthCheckResponse.Builder> internal__static_grpc_health_v1alpha_HealthCheckResponse__FieldAccessorTable;
+      #endregion
+      #region Descriptor
+      public static pbd::FileDescriptor Descriptor {
+        get { return descriptor; }
+      }
+      private static pbd::FileDescriptor descriptor;
+
+      static Health() {
+        byte[] descriptorData = global::System.Convert.FromBase64String(
+            string.Concat(
+              "CgxoZWFsdGgucHJvdG8SE2dycGMuaGVhbHRoLnYxYWxwaGEiMwoSSGVhbHRo", 
+              "Q2hlY2tSZXF1ZXN0EgwKBGhvc3QYASABKAkSDwoHc2VydmljZRgCIAEoCSKZ", 
+              "AQoTSGVhbHRoQ2hlY2tSZXNwb25zZRJGCgZzdGF0dXMYASABKA4yNi5ncnBj", 
+              "LmhlYWx0aC52MWFscGhhLkhlYWx0aENoZWNrUmVzcG9uc2UuU2VydmluZ1N0", 
+              "YXR1cyI6Cg1TZXJ2aW5nU3RhdHVzEgsKB1VOS05PV04QABILCgdTRVJWSU5H", 
+              "EAESDwoLTk9UX1NFUlZJTkcQAjJkCgZIZWFsdGgSWgoFQ2hlY2sSJy5ncnBj", 
+              "LmhlYWx0aC52MWFscGhhLkhlYWx0aENoZWNrUmVxdWVzdBooLmdycGMuaGVh", 
+              "bHRoLnYxYWxwaGEuSGVhbHRoQ2hlY2tSZXNwb25zZUIWqgITR3JwYy5IZWFs", 
+            "dGguVjFBbHBoYQ=="));
+        pbd::FileDescriptor.InternalDescriptorAssigner assigner = delegate(pbd::FileDescriptor root) {
+          descriptor = root;
+          internal__static_grpc_health_v1alpha_HealthCheckRequest__Descriptor = Descriptor.MessageTypes[0];
+          internal__static_grpc_health_v1alpha_HealthCheckRequest__FieldAccessorTable = 
+              new pb::FieldAccess.FieldAccessorTable<global::Grpc.Health.V1Alpha.HealthCheckRequest, global::Grpc.Health.V1Alpha.HealthCheckRequest.Builder>(internal__static_grpc_health_v1alpha_HealthCheckRequest__Descriptor,
+                  new string[] { "Host", "Service", });
+          internal__static_grpc_health_v1alpha_HealthCheckResponse__Descriptor = Descriptor.MessageTypes[1];
+          internal__static_grpc_health_v1alpha_HealthCheckResponse__FieldAccessorTable = 
+              new pb::FieldAccess.FieldAccessorTable<global::Grpc.Health.V1Alpha.HealthCheckResponse, global::Grpc.Health.V1Alpha.HealthCheckResponse.Builder>(internal__static_grpc_health_v1alpha_HealthCheckResponse__Descriptor,
+                  new string[] { "Status", });
+          pb::ExtensionRegistry registry = pb::ExtensionRegistry.CreateInstance();
+          RegisterAllExtensions(registry);
+          return registry;
+        };
+        pbd::FileDescriptor.InternalBuildGeneratedFileFrom(descriptorData,
+            new pbd::FileDescriptor[] {
+            }, assigner);
+      }
+      #endregion
+
+    }
+  }
+  #region Messages
+  [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+  public sealed partial class HealthCheckRequest : pb::GeneratedMessage<HealthCheckRequest, HealthCheckRequest.Builder> {
+    private HealthCheckRequest() { }
+    private static readonly HealthCheckRequest defaultInstance = new HealthCheckRequest().MakeReadOnly();
+    private static readonly string[] _healthCheckRequestFieldNames = new string[] { "host", "service" };
+    private static readonly uint[] _healthCheckRequestFieldTags = new uint[] { 10, 18 };
+    public static HealthCheckRequest DefaultInstance {
+      get { return defaultInstance; }
+    }
+
+    public override HealthCheckRequest DefaultInstanceForType {
+      get { return DefaultInstance; }
+    }
+
+    protected override HealthCheckRequest ThisMessage {
+      get { return this; }
+    }
+
+    public static pbd::MessageDescriptor Descriptor {
+      get { return global::Grpc.Health.V1Alpha.Proto.Health.internal__static_grpc_health_v1alpha_HealthCheckRequest__Descriptor; }
+    }
+
+    protected override pb::FieldAccess.FieldAccessorTable<HealthCheckRequest, HealthCheckRequest.Builder> InternalFieldAccessors {
+      get { return global::Grpc.Health.V1Alpha.Proto.Health.internal__static_grpc_health_v1alpha_HealthCheckRequest__FieldAccessorTable; }
+    }
+
+    public const int HostFieldNumber = 1;
+    private bool hasHost;
+    private string host_ = "";
+    public bool HasHost {
+      get { return hasHost; }
+    }
+    public string Host {
+      get { return host_; }
+    }
+
+    public const int ServiceFieldNumber = 2;
+    private bool hasService;
+    private string service_ = "";
+    public bool HasService {
+      get { return hasService; }
+    }
+    public string Service {
+      get { return service_; }
+    }
+
+    public override bool IsInitialized {
+      get {
+        return true;
+      }
+    }
+
+    public override void WriteTo(pb::ICodedOutputStream output) {
+      CalcSerializedSize();
+      string[] field_names = _healthCheckRequestFieldNames;
+      if (hasHost) {
+        output.WriteString(1, field_names[0], Host);
+      }
+      if (hasService) {
+        output.WriteString(2, field_names[1], Service);
+      }
+      UnknownFields.WriteTo(output);
+    }
+
+    private int memoizedSerializedSize = -1;
+    public override int SerializedSize {
+      get {
+        int size = memoizedSerializedSize;
+        if (size != -1) return size;
+        return CalcSerializedSize();
+      }
+    }
+
+    private int CalcSerializedSize() {
+      int size = memoizedSerializedSize;
+      if (size != -1) return size;
+
+      size = 0;
+      if (hasHost) {
+        size += pb::CodedOutputStream.ComputeStringSize(1, Host);
+      }
+      if (hasService) {
+        size += pb::CodedOutputStream.ComputeStringSize(2, Service);
+      }
+      size += UnknownFields.SerializedSize;
+      memoizedSerializedSize = size;
+      return size;
+    }
+    public static HealthCheckRequest ParseFrom(pb::ByteString data) {
+      return ((Builder) CreateBuilder().MergeFrom(data)).BuildParsed();
+    }
+    public static HealthCheckRequest ParseFrom(pb::ByteString data, pb::ExtensionRegistry extensionRegistry) {
+      return ((Builder) CreateBuilder().MergeFrom(data, extensionRegistry)).BuildParsed();
+    }
+    public static HealthCheckRequest ParseFrom(byte[] data) {
+      return ((Builder) CreateBuilder().MergeFrom(data)).BuildParsed();
+    }
+    public static HealthCheckRequest ParseFrom(byte[] data, pb::ExtensionRegistry extensionRegistry) {
+      return ((Builder) CreateBuilder().MergeFrom(data, extensionRegistry)).BuildParsed();
+    }
+    public static HealthCheckRequest ParseFrom(global::System.IO.Stream input) {
+      return ((Builder) CreateBuilder().MergeFrom(input)).BuildParsed();
+    }
+    public static HealthCheckRequest ParseFrom(global::System.IO.Stream input, pb::ExtensionRegistry extensionRegistry) {
+      return ((Builder) CreateBuilder().MergeFrom(input, extensionRegistry)).BuildParsed();
+    }
+    public static HealthCheckRequest ParseDelimitedFrom(global::System.IO.Stream input) {
+      return CreateBuilder().MergeDelimitedFrom(input).BuildParsed();
+    }
+    public static HealthCheckRequest ParseDelimitedFrom(global::System.IO.Stream input, pb::ExtensionRegistry extensionRegistry) {
+      return CreateBuilder().MergeDelimitedFrom(input, extensionRegistry).BuildParsed();
+    }
+    public static HealthCheckRequest ParseFrom(pb::ICodedInputStream input) {
+      return ((Builder) CreateBuilder().MergeFrom(input)).BuildParsed();
+    }
+    public static HealthCheckRequest ParseFrom(pb::ICodedInputStream input, pb::ExtensionRegistry extensionRegistry) {
+      return ((Builder) CreateBuilder().MergeFrom(input, extensionRegistry)).BuildParsed();
+    }
+    private HealthCheckRequest MakeReadOnly() {
+      return this;
+    }
+
+    public static Builder CreateBuilder() { return new Builder(); }
+    public override Builder ToBuilder() { return CreateBuilder(this); }
+    public override Builder CreateBuilderForType() { return new Builder(); }
+    public static Builder CreateBuilder(HealthCheckRequest prototype) {
+      return new Builder(prototype);
+    }
+
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+    public sealed partial class Builder : pb::GeneratedBuilder<HealthCheckRequest, Builder> {
+      protected override Builder ThisBuilder {
+        get { return this; }
+      }
+      public Builder() {
+        result = DefaultInstance;
+        resultIsReadOnly = true;
+      }
+      internal Builder(HealthCheckRequest cloneFrom) {
+        result = cloneFrom;
+        resultIsReadOnly = true;
+      }
+
+      private bool resultIsReadOnly;
+      private HealthCheckRequest result;
+
+      private HealthCheckRequest PrepareBuilder() {
+        if (resultIsReadOnly) {
+          HealthCheckRequest original = result;
+          result = new HealthCheckRequest();
+          resultIsReadOnly = false;
+          MergeFrom(original);
+        }
+        return result;
+      }
+
+      public override bool IsInitialized {
+        get { return result.IsInitialized; }
+      }
+
+      protected override HealthCheckRequest MessageBeingBuilt {
+        get { return PrepareBuilder(); }
+      }
+
+      public override Builder Clear() {
+        result = DefaultInstance;
+        resultIsReadOnly = true;
+        return this;
+      }
+
+      public override Builder Clone() {
+        if (resultIsReadOnly) {
+          return new Builder(result);
+        } else {
+          return new Builder().MergeFrom(result);
+        }
+      }
+
+      public override pbd::MessageDescriptor DescriptorForType {
+        get { return global::Grpc.Health.V1Alpha.HealthCheckRequest.Descriptor; }
+      }
+
+      public override HealthCheckRequest DefaultInstanceForType {
+        get { return global::Grpc.Health.V1Alpha.HealthCheckRequest.DefaultInstance; }
+      }
+
+      public override HealthCheckRequest BuildPartial() {
+        if (resultIsReadOnly) {
+          return result;
+        }
+        resultIsReadOnly = true;
+        return result.MakeReadOnly();
+      }
+
+      public override Builder MergeFrom(pb::IMessage other) {
+        if (other is HealthCheckRequest) {
+          return MergeFrom((HealthCheckRequest) other);
+        } else {
+          base.MergeFrom(other);
+          return this;
+        }
+      }
+
+      public override Builder MergeFrom(HealthCheckRequest other) {
+        if (other == global::Grpc.Health.V1Alpha.HealthCheckRequest.DefaultInstance) return this;
+        PrepareBuilder();
+        if (other.HasHost) {
+          Host = other.Host;
+        }
+        if (other.HasService) {
+          Service = other.Service;
+        }
+        this.MergeUnknownFields(other.UnknownFields);
+        return this;
+      }
+
+      public override Builder MergeFrom(pb::ICodedInputStream input) {
+        return MergeFrom(input, pb::ExtensionRegistry.Empty);
+      }
+
+      public override Builder MergeFrom(pb::ICodedInputStream input, pb::ExtensionRegistry extensionRegistry) {
+        PrepareBuilder();
+        pb::UnknownFieldSet.Builder unknownFields = null;
+        uint tag;
+        string field_name;
+        while (input.ReadTag(out tag, out field_name)) {
+          if(tag == 0 && field_name != null) {
+            int field_ordinal = global::System.Array.BinarySearch(_healthCheckRequestFieldNames, field_name, global::System.StringComparer.Ordinal);
+            if(field_ordinal >= 0)
+              tag = _healthCheckRequestFieldTags[field_ordinal];
+            else {
+              if (unknownFields == null) {
+                unknownFields = pb::UnknownFieldSet.CreateBuilder(this.UnknownFields);
+              }
+              ParseUnknownField(input, unknownFields, extensionRegistry, tag, field_name);
+              continue;
+            }
+          }
+          switch (tag) {
+            case 0: {
+              throw pb::InvalidProtocolBufferException.InvalidTag();
+            }
+            default: {
+              if (pb::WireFormat.IsEndGroupTag(tag)) {
+                if (unknownFields != null) {
+                  this.UnknownFields = unknownFields.Build();
+                }
+                return this;
+              }
+              if (unknownFields == null) {
+                unknownFields = pb::UnknownFieldSet.CreateBuilder(this.UnknownFields);
+              }
+              ParseUnknownField(input, unknownFields, extensionRegistry, tag, field_name);
+              break;
+            }
+            case 10: {
+              result.hasHost = input.ReadString(ref result.host_);
+              break;
+            }
+            case 18: {
+              result.hasService = input.ReadString(ref result.service_);
+              break;
+            }
+          }
+        }
+
+        if (unknownFields != null) {
+          this.UnknownFields = unknownFields.Build();
+        }
+        return this;
+      }
+
+
+      public bool HasHost {
+        get { return result.hasHost; }
+      }
+      public string Host {
+        get { return result.Host; }
+        set { SetHost(value); }
+      }
+      public Builder SetHost(string value) {
+        pb::ThrowHelper.ThrowIfNull(value, "value");
+        PrepareBuilder();
+        result.hasHost = true;
+        result.host_ = value;
+        return this;
+      }
+      public Builder ClearHost() {
+        PrepareBuilder();
+        result.hasHost = false;
+        result.host_ = "";
+        return this;
+      }
+
+      public bool HasService {
+        get { return result.hasService; }
+      }
+      public string Service {
+        get { return result.Service; }
+        set { SetService(value); }
+      }
+      public Builder SetService(string value) {
+        pb::ThrowHelper.ThrowIfNull(value, "value");
+        PrepareBuilder();
+        result.hasService = true;
+        result.service_ = value;
+        return this;
+      }
+      public Builder ClearService() {
+        PrepareBuilder();
+        result.hasService = false;
+        result.service_ = "";
+        return this;
+      }
+    }
+    static HealthCheckRequest() {
+      object.ReferenceEquals(global::Grpc.Health.V1Alpha.Proto.Health.Descriptor, null);
+    }
+  }
+
+  [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+  public sealed partial class HealthCheckResponse : pb::GeneratedMessage<HealthCheckResponse, HealthCheckResponse.Builder> {
+    private HealthCheckResponse() { }
+    private static readonly HealthCheckResponse defaultInstance = new HealthCheckResponse().MakeReadOnly();
+    private static readonly string[] _healthCheckResponseFieldNames = new string[] { "status" };
+    private static readonly uint[] _healthCheckResponseFieldTags = new uint[] { 8 };
+    public static HealthCheckResponse DefaultInstance {
+      get { return defaultInstance; }
+    }
+
+    public override HealthCheckResponse DefaultInstanceForType {
+      get { return DefaultInstance; }
+    }
+
+    protected override HealthCheckResponse ThisMessage {
+      get { return this; }
+    }
+
+    public static pbd::MessageDescriptor Descriptor {
+      get { return global::Grpc.Health.V1Alpha.Proto.Health.internal__static_grpc_health_v1alpha_HealthCheckResponse__Descriptor; }
+    }
+
+    protected override pb::FieldAccess.FieldAccessorTable<HealthCheckResponse, HealthCheckResponse.Builder> InternalFieldAccessors {
+      get { return global::Grpc.Health.V1Alpha.Proto.Health.internal__static_grpc_health_v1alpha_HealthCheckResponse__FieldAccessorTable; }
+    }
+
+    #region Nested types
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+    public static partial class Types {
+      public enum ServingStatus {
+        UNKNOWN = 0,
+        SERVING = 1,
+        NOT_SERVING = 2,
+      }
+
+    }
+    #endregion
+
+    public const int StatusFieldNumber = 1;
+    private bool hasStatus;
+    private global::Grpc.Health.V1Alpha.HealthCheckResponse.Types.ServingStatus status_ = global::Grpc.Health.V1Alpha.HealthCheckResponse.Types.ServingStatus.UNKNOWN;
+    public bool HasStatus {
+      get { return hasStatus; }
+    }
+    public global::Grpc.Health.V1Alpha.HealthCheckResponse.Types.ServingStatus Status {
+      get { return status_; }
+    }
+
+    public override bool IsInitialized {
+      get {
+        return true;
+      }
+    }
+
+    public override void WriteTo(pb::ICodedOutputStream output) {
+      CalcSerializedSize();
+      string[] field_names = _healthCheckResponseFieldNames;
+      if (hasStatus) {
+        output.WriteEnum(1, field_names[0], (int) Status, Status);
+      }
+      UnknownFields.WriteTo(output);
+    }
+
+    private int memoizedSerializedSize = -1;
+    public override int SerializedSize {
+      get {
+        int size = memoizedSerializedSize;
+        if (size != -1) return size;
+        return CalcSerializedSize();
+      }
+    }
+
+    private int CalcSerializedSize() {
+      int size = memoizedSerializedSize;
+      if (size != -1) return size;
+
+      size = 0;
+      if (hasStatus) {
+        size += pb::CodedOutputStream.ComputeEnumSize(1, (int) Status);
+      }
+      size += UnknownFields.SerializedSize;
+      memoizedSerializedSize = size;
+      return size;
+    }
+    public static HealthCheckResponse ParseFrom(pb::ByteString data) {
+      return ((Builder) CreateBuilder().MergeFrom(data)).BuildParsed();
+    }
+    public static HealthCheckResponse ParseFrom(pb::ByteString data, pb::ExtensionRegistry extensionRegistry) {
+      return ((Builder) CreateBuilder().MergeFrom(data, extensionRegistry)).BuildParsed();
+    }
+    public static HealthCheckResponse ParseFrom(byte[] data) {
+      return ((Builder) CreateBuilder().MergeFrom(data)).BuildParsed();
+    }
+    public static HealthCheckResponse ParseFrom(byte[] data, pb::ExtensionRegistry extensionRegistry) {
+      return ((Builder) CreateBuilder().MergeFrom(data, extensionRegistry)).BuildParsed();
+    }
+    public static HealthCheckResponse ParseFrom(global::System.IO.Stream input) {
+      return ((Builder) CreateBuilder().MergeFrom(input)).BuildParsed();
+    }
+    public static HealthCheckResponse ParseFrom(global::System.IO.Stream input, pb::ExtensionRegistry extensionRegistry) {
+      return ((Builder) CreateBuilder().MergeFrom(input, extensionRegistry)).BuildParsed();
+    }
+    public static HealthCheckResponse ParseDelimitedFrom(global::System.IO.Stream input) {
+      return CreateBuilder().MergeDelimitedFrom(input).BuildParsed();
+    }
+    public static HealthCheckResponse ParseDelimitedFrom(global::System.IO.Stream input, pb::ExtensionRegistry extensionRegistry) {
+      return CreateBuilder().MergeDelimitedFrom(input, extensionRegistry).BuildParsed();
+    }
+    public static HealthCheckResponse ParseFrom(pb::ICodedInputStream input) {
+      return ((Builder) CreateBuilder().MergeFrom(input)).BuildParsed();
+    }
+    public static HealthCheckResponse ParseFrom(pb::ICodedInputStream input, pb::ExtensionRegistry extensionRegistry) {
+      return ((Builder) CreateBuilder().MergeFrom(input, extensionRegistry)).BuildParsed();
+    }
+    private HealthCheckResponse MakeReadOnly() {
+      return this;
+    }
+
+    public static Builder CreateBuilder() { return new Builder(); }
+    public override Builder ToBuilder() { return CreateBuilder(this); }
+    public override Builder CreateBuilderForType() { return new Builder(); }
+    public static Builder CreateBuilder(HealthCheckResponse prototype) {
+      return new Builder(prototype);
+    }
+
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+    public sealed partial class Builder : pb::GeneratedBuilder<HealthCheckResponse, Builder> {
+      protected override Builder ThisBuilder {
+        get { return this; }
+      }
+      public Builder() {
+        result = DefaultInstance;
+        resultIsReadOnly = true;
+      }
+      internal Builder(HealthCheckResponse cloneFrom) {
+        result = cloneFrom;
+        resultIsReadOnly = true;
+      }
+
+      private bool resultIsReadOnly;
+      private HealthCheckResponse result;
+
+      private HealthCheckResponse PrepareBuilder() {
+        if (resultIsReadOnly) {
+          HealthCheckResponse original = result;
+          result = new HealthCheckResponse();
+          resultIsReadOnly = false;
+          MergeFrom(original);
+        }
+        return result;
+      }
+
+      public override bool IsInitialized {
+        get { return result.IsInitialized; }
+      }
+
+      protected override HealthCheckResponse MessageBeingBuilt {
+        get { return PrepareBuilder(); }
+      }
+
+      public override Builder Clear() {
+        result = DefaultInstance;
+        resultIsReadOnly = true;
+        return this;
+      }
+
+      public override Builder Clone() {
+        if (resultIsReadOnly) {
+          return new Builder(result);
+        } else {
+          return new Builder().MergeFrom(result);
+        }
+      }
+
+      public override pbd::MessageDescriptor DescriptorForType {
+        get { return global::Grpc.Health.V1Alpha.HealthCheckResponse.Descriptor; }
+      }
+
+      public override HealthCheckResponse DefaultInstanceForType {
+        get { return global::Grpc.Health.V1Alpha.HealthCheckResponse.DefaultInstance; }
+      }
+
+      public override HealthCheckResponse BuildPartial() {
+        if (resultIsReadOnly) {
+          return result;
+        }
+        resultIsReadOnly = true;
+        return result.MakeReadOnly();
+      }
+
+      public override Builder MergeFrom(pb::IMessage other) {
+        if (other is HealthCheckResponse) {
+          return MergeFrom((HealthCheckResponse) other);
+        } else {
+          base.MergeFrom(other);
+          return this;
+        }
+      }
+
+      public override Builder MergeFrom(HealthCheckResponse other) {
+        if (other == global::Grpc.Health.V1Alpha.HealthCheckResponse.DefaultInstance) return this;
+        PrepareBuilder();
+        if (other.HasStatus) {
+          Status = other.Status;
+        }
+        this.MergeUnknownFields(other.UnknownFields);
+        return this;
+      }
+
+      public override Builder MergeFrom(pb::ICodedInputStream input) {
+        return MergeFrom(input, pb::ExtensionRegistry.Empty);
+      }
+
+      public override Builder MergeFrom(pb::ICodedInputStream input, pb::ExtensionRegistry extensionRegistry) {
+        PrepareBuilder();
+        pb::UnknownFieldSet.Builder unknownFields = null;
+        uint tag;
+        string field_name;
+        while (input.ReadTag(out tag, out field_name)) {
+          if(tag == 0 && field_name != null) {
+            int field_ordinal = global::System.Array.BinarySearch(_healthCheckResponseFieldNames, field_name, global::System.StringComparer.Ordinal);
+            if(field_ordinal >= 0)
+              tag = _healthCheckResponseFieldTags[field_ordinal];
+            else {
+              if (unknownFields == null) {
+                unknownFields = pb::UnknownFieldSet.CreateBuilder(this.UnknownFields);
+              }
+              ParseUnknownField(input, unknownFields, extensionRegistry, tag, field_name);
+              continue;
+            }
+          }
+          switch (tag) {
+            case 0: {
+              throw pb::InvalidProtocolBufferException.InvalidTag();
+            }
+            default: {
+              if (pb::WireFormat.IsEndGroupTag(tag)) {
+                if (unknownFields != null) {
+                  this.UnknownFields = unknownFields.Build();
+                }
+                return this;
+              }
+              if (unknownFields == null) {
+                unknownFields = pb::UnknownFieldSet.CreateBuilder(this.UnknownFields);
+              }
+              ParseUnknownField(input, unknownFields, extensionRegistry, tag, field_name);
+              break;
+            }
+            case 8: {
+              object unknown;
+              if(input.ReadEnum(ref result.status_, out unknown)) {
+                result.hasStatus = true;
+              } else if(unknown is int) {
+                if (unknownFields == null) {
+                  unknownFields = pb::UnknownFieldSet.CreateBuilder(this.UnknownFields);
+                }
+                unknownFields.MergeVarintField(1, (ulong)(int)unknown);
+              }
+              break;
+            }
+          }
+        }
+
+        if (unknownFields != null) {
+          this.UnknownFields = unknownFields.Build();
+        }
+        return this;
+      }
+
+
+      public bool HasStatus {
+       get { return result.hasStatus; }
+      }
+      public global::Grpc.Health.V1Alpha.HealthCheckResponse.Types.ServingStatus Status {
+        get { return result.Status; }
+        set { SetStatus(value); }
+      }
+      public Builder SetStatus(global::Grpc.Health.V1Alpha.HealthCheckResponse.Types.ServingStatus value) {
+        PrepareBuilder();
+        result.hasStatus = true;
+        result.status_ = value;
+        return this;
+      }
+      public Builder ClearStatus() {
+        PrepareBuilder();
+        result.hasStatus = false;
+        result.status_ = global::Grpc.Health.V1Alpha.HealthCheckResponse.Types.ServingStatus.UNKNOWN;
+        return this;
+      }
+    }
+    static HealthCheckResponse() {
+      object.ReferenceEquals(global::Grpc.Health.V1Alpha.Proto.Health.Descriptor, null);
+    }
+  }
+
+  #endregion
+
+}
+
+#endregion Designer generated code
diff --git a/src/csharp/Grpc.HealthCheck/HealthGrpc.cs b/src/csharp/Grpc.HealthCheck/HealthGrpc.cs
new file mode 100644
index 0000000..ed9fc4e
--- /dev/null
+++ b/src/csharp/Grpc.HealthCheck/HealthGrpc.cs
@@ -0,0 +1,78 @@
+// Generated by the protocol buffer compiler.  DO NOT EDIT!
+// source: health.proto
+#region Designer generated code
+
+using System;
+using System.Threading;
+using System.Threading.Tasks;
+using Grpc.Core;
+
+namespace Grpc.Health.V1Alpha {
+  public static class Health
+  {
+    static readonly string __ServiceName = "grpc.health.v1alpha.Health";
+
+    static readonly Marshaller<global::Grpc.Health.V1Alpha.HealthCheckRequest> __Marshaller_HealthCheckRequest = Marshallers.Create((arg) => arg.ToByteArray(), global::Grpc.Health.V1Alpha.HealthCheckRequest.ParseFrom);
+    static readonly Marshaller<global::Grpc.Health.V1Alpha.HealthCheckResponse> __Marshaller_HealthCheckResponse = Marshallers.Create((arg) => arg.ToByteArray(), global::Grpc.Health.V1Alpha.HealthCheckResponse.ParseFrom);
+
+    static readonly Method<global::Grpc.Health.V1Alpha.HealthCheckRequest, global::Grpc.Health.V1Alpha.HealthCheckResponse> __Method_Check = new Method<global::Grpc.Health.V1Alpha.HealthCheckRequest, global::Grpc.Health.V1Alpha.HealthCheckResponse>(
+        MethodType.Unary,
+        "Check",
+        __Marshaller_HealthCheckRequest,
+        __Marshaller_HealthCheckResponse);
+
+    // client-side stub interface
+    public interface IHealthClient
+    {
+      global::Grpc.Health.V1Alpha.HealthCheckResponse Check(global::Grpc.Health.V1Alpha.HealthCheckRequest request, CancellationToken token = default(CancellationToken));
+      Task<global::Grpc.Health.V1Alpha.HealthCheckResponse> CheckAsync(global::Grpc.Health.V1Alpha.HealthCheckRequest request, CancellationToken token = default(CancellationToken));
+    }
+
+    // server-side interface
+    public interface IHealth
+    {
+      Task<global::Grpc.Health.V1Alpha.HealthCheckResponse> Check(ServerCallContext context, global::Grpc.Health.V1Alpha.HealthCheckRequest request);
+    }
+
+    // client stub
+    public class HealthClient : AbstractStub<HealthClient, StubConfiguration>, IHealthClient
+    {
+      public HealthClient(Channel channel) : this(channel, StubConfiguration.Default)
+      {
+      }
+      public HealthClient(Channel channel, StubConfiguration config) : base(channel, config)
+      {
+      }
+      public global::Grpc.Health.V1Alpha.HealthCheckResponse Check(global::Grpc.Health.V1Alpha.HealthCheckRequest request, CancellationToken token = default(CancellationToken))
+      {
+        var call = CreateCall(__ServiceName, __Method_Check);
+        return Calls.BlockingUnaryCall(call, request, token);
+      }
+      public Task<global::Grpc.Health.V1Alpha.HealthCheckResponse> CheckAsync(global::Grpc.Health.V1Alpha.HealthCheckRequest request, CancellationToken token = default(CancellationToken))
+      {
+        var call = CreateCall(__ServiceName, __Method_Check);
+        return Calls.AsyncUnaryCall(call, request, token);
+      }
+    }
+
+    // creates service definition that can be registered with a server
+    public static ServerServiceDefinition BindService(IHealth serviceImpl)
+    {
+      return ServerServiceDefinition.CreateBuilder(__ServiceName)
+          .AddMethod(__Method_Check, serviceImpl.Check).Build();
+    }
+
+    // creates a new client stub
+    public static IHealthClient NewStub(Channel channel)
+    {
+      return new HealthClient(channel);
+    }
+
+    // creates a new client stub
+    public static IHealthClient NewStub(Channel channel, StubConfiguration config)
+    {
+      return new HealthClient(channel, config);
+    }
+  }
+}
+#endregion
diff --git a/src/csharp/Grpc.HealthCheck/HealthServiceImpl.cs b/src/csharp/Grpc.HealthCheck/HealthServiceImpl.cs
new file mode 100644
index 0000000..db3a2a0
--- /dev/null
+++ b/src/csharp/Grpc.HealthCheck/HealthServiceImpl.cs
@@ -0,0 +1,132 @@
+#region Copyright notice and license
+// 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.
+#endregion
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+using Grpc.Core;
+using Grpc.Core.Utils;
+using Grpc.Health.V1Alpha;
+
+namespace Grpc.HealthCheck
+{
+    /// <summary>
+    /// Implementation of a simple Health service. Useful for health checking.
+    /// 
+    /// Registering service with a server:
+    /// <code>
+    /// var serviceImpl = new HealthServiceImpl();
+    /// server = new Server();
+    /// server.AddServiceDefinition(Grpc.Health.V1Alpha.Health.BindService(serviceImpl));
+    /// </code>
+    /// </summary>
+    public class HealthServiceImpl : Grpc.Health.V1Alpha.Health.IHealth
+    {
+        private readonly object myLock = new object();
+        private readonly Dictionary<Key, HealthCheckResponse.Types.ServingStatus> statusMap = 
+            new Dictionary<Key, HealthCheckResponse.Types.ServingStatus>();
+
+        /// <summary>
+        /// Sets the health status for given host and service.
+        /// </summary>
+        /// <param name="host">The host. Cannot be null.</param>
+        /// <param name="service">The service. Cannot be null.</param>
+        /// <param name="status">the health status</param>
+        public void SetStatus(string host, string service, HealthCheckResponse.Types.ServingStatus status)
+        {
+            lock (myLock)
+            {
+                statusMap[CreateKey(host, service)] = status;
+            }
+        }
+
+        /// <summary>
+        /// Clears health status for given host and service.
+        /// </summary>
+        /// <param name="host">The host. Cannot be null.</param>
+        /// <param name="service">The service. Cannot be null.</param>
+        public void ClearStatus(string host, string service)
+        {
+            lock (myLock)
+            {
+                statusMap.Remove(CreateKey(host, service));
+            }
+        }
+        
+        /// <summary>
+        /// Clears statuses for all hosts and services.
+        /// </summary>
+        public void ClearAll()
+        {
+            lock (myLock)
+            {
+                statusMap.Clear();
+            }
+        }
+
+        public Task<HealthCheckResponse> Check(ServerCallContext context, HealthCheckRequest request)
+        {
+            lock (myLock)
+            {
+                var host = request.HasHost ? request.Host : "";
+                var service = request.HasService ? request.Service : "";
+
+                HealthCheckResponse.Types.ServingStatus status;
+                if (!statusMap.TryGetValue(CreateKey(host, service), out status))
+                {
+                    // TODO(jtattermusch): returning specific status from server handler is not supported yet.
+                    throw new RpcException(new Status(StatusCode.NotFound, ""));
+                }
+                return Task.FromResult(HealthCheckResponse.CreateBuilder().SetStatus(status).Build());
+            }
+        }
+
+        private static Key CreateKey(string host, string service)
+        {
+            return new Key(host, service);
+        }
+
+        private struct Key
+        {
+            public Key(string host, string service)
+            {
+                this.Host = Preconditions.CheckNotNull(host);
+                this.Service = Preconditions.CheckNotNull(service);
+            }
+
+            readonly string Host;
+            readonly string Service;
+        }
+    }
+}
diff --git a/src/csharp/Grpc.HealthCheck/Properties/AssemblyInfo.cs b/src/csharp/Grpc.HealthCheck/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000..41a54a9
--- /dev/null
+++ b/src/csharp/Grpc.HealthCheck/Properties/AssemblyInfo.cs
@@ -0,0 +1,11 @@
+using System.Reflection;
+using System.Runtime.CompilerServices;
+
+[assembly: AssemblyTitle("Grpc.HealthCheck")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("")]
+[assembly: AssemblyCopyright("Google Inc.  All rights reserved.")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
\ No newline at end of file
diff --git a/src/csharp/Grpc.HealthCheck/packages.config b/src/csharp/Grpc.HealthCheck/packages.config
new file mode 100644
index 0000000..094a309
--- /dev/null
+++ b/src/csharp/Grpc.HealthCheck/packages.config
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<packages>
+  <package id="Google.ProtocolBuffers" version="2.4.1.555" targetFramework="net45" />
+  <package id="Ix-Async" version="1.2.3" targetFramework="net45" />
+</packages>
\ No newline at end of file
diff --git a/src/csharp/Grpc.HealthCheck/proto/health.proto b/src/csharp/Grpc.HealthCheck/proto/health.proto
new file mode 100644
index 0000000..08df7e1
--- /dev/null
+++ b/src/csharp/Grpc.HealthCheck/proto/health.proto
@@ -0,0 +1,52 @@
+// 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.
+
+// TODO(jtattermusch): switch to proto3 once C# supports that.
+syntax = "proto2";
+
+package grpc.health.v1alpha;
+option csharp_namespace = "Grpc.Health.V1Alpha";
+
+message HealthCheckRequest {
+  optional string host = 1;
+  optional string service = 2;
+}
+
+message HealthCheckResponse {
+  enum ServingStatus {
+    UNKNOWN = 0;
+    SERVING = 1;
+    NOT_SERVING = 2;
+  }
+  optional ServingStatus status = 1;
+}
+
+service Health {
+  rpc Check(HealthCheckRequest) returns (HealthCheckResponse);
+}
\ No newline at end of file
diff --git a/src/csharp/Grpc.IntegrationTesting.Client/Grpc.IntegrationTesting.Client.csproj b/src/csharp/Grpc.IntegrationTesting.Client/Grpc.IntegrationTesting.Client.csproj
index df05c53..328acb5 100644
--- a/src/csharp/Grpc.IntegrationTesting.Client/Grpc.IntegrationTesting.Client.csproj
+++ b/src/csharp/Grpc.IntegrationTesting.Client/Grpc.IntegrationTesting.Client.csproj
@@ -36,6 +36,9 @@
     <Reference Include="System" />
   </ItemGroup>
   <ItemGroup>
+    <Compile Include="..\Grpc.Core\Version.cs">
+      <Link>Version.cs</Link>
+    </Compile>
     <Compile Include="Program.cs" />
     <Compile Include="Properties\AssemblyInfo.cs" />
   </ItemGroup>
diff --git a/src/csharp/Grpc.IntegrationTesting.Client/Properties/AssemblyInfo.cs b/src/csharp/Grpc.IntegrationTesting.Client/Properties/AssemblyInfo.cs
index 26c0dcc..f51f279 100644
--- a/src/csharp/Grpc.IntegrationTesting.Client/Properties/AssemblyInfo.cs
+++ b/src/csharp/Grpc.IntegrationTesting.Client/Properties/AssemblyInfo.cs
@@ -9,4 +9,3 @@
 [assembly: AssemblyCopyright("Google Inc.  All rights reserved.")]
 [assembly: AssemblyTrademark("")]
 [assembly: AssemblyCulture("")]
-[assembly: AssemblyVersion("0.5.*")]
diff --git a/src/csharp/Grpc.IntegrationTesting.Server/Grpc.IntegrationTesting.Server.csproj b/src/csharp/Grpc.IntegrationTesting.Server/Grpc.IntegrationTesting.Server.csproj
index 235897c..ae184c1 100644
--- a/src/csharp/Grpc.IntegrationTesting.Server/Grpc.IntegrationTesting.Server.csproj
+++ b/src/csharp/Grpc.IntegrationTesting.Server/Grpc.IntegrationTesting.Server.csproj
@@ -36,6 +36,9 @@
     <Reference Include="System" />
   </ItemGroup>
   <ItemGroup>
+    <Compile Include="..\Grpc.Core\Version.cs">
+      <Link>Version.cs</Link>
+    </Compile>
     <Compile Include="Program.cs" />
     <Compile Include="Properties\AssemblyInfo.cs" />
   </ItemGroup>
diff --git a/src/csharp/Grpc.IntegrationTesting.Server/Properties/AssemblyInfo.cs b/src/csharp/Grpc.IntegrationTesting.Server/Properties/AssemblyInfo.cs
index 2d518d7..f68d9a3 100644
--- a/src/csharp/Grpc.IntegrationTesting.Server/Properties/AssemblyInfo.cs
+++ b/src/csharp/Grpc.IntegrationTesting.Server/Properties/AssemblyInfo.cs
@@ -9,4 +9,3 @@
 [assembly: AssemblyCopyright("Google Inc.  All rights reserved.")]
 [assembly: AssemblyTrademark("")]
 [assembly: AssemblyCulture("")]
-[assembly: AssemblyVersion("0.5.*")]
diff --git a/src/csharp/Grpc.IntegrationTesting/Grpc.IntegrationTesting.csproj b/src/csharp/Grpc.IntegrationTesting/Grpc.IntegrationTesting.csproj
index b3a0a29..af4a75a 100644
--- a/src/csharp/Grpc.IntegrationTesting/Grpc.IntegrationTesting.csproj
+++ b/src/csharp/Grpc.IntegrationTesting/Grpc.IntegrationTesting.csproj
@@ -54,6 +54,10 @@
     <Reference Include="Google.ProtocolBuffers">
       <HintPath>..\packages\Google.ProtocolBuffers.2.4.1.521\lib\net40\Google.ProtocolBuffers.dll</HintPath>
     </Reference>
+    <Reference Include="System.Collections.Immutable, Version=1.1.36.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
+      <SpecificVersion>False</SpecificVersion>
+      <HintPath>..\packages\System.Collections.Immutable.1.1.36\lib\portable-net45+win8+wp8+wpa81\System.Collections.Immutable.dll</HintPath>
+    </Reference>
     <Reference Include="System.Interactive.Async">
       <HintPath>..\packages\Ix-Async.1.2.3\lib\net45\System.Interactive.Async.dll</HintPath>
     </Reference>
@@ -69,11 +73,11 @@
     <Reference Include="Newtonsoft.Json">
       <HintPath>..\packages\Newtonsoft.Json.6.0.6\lib\net45\Newtonsoft.Json.dll</HintPath>
     </Reference>
-    <Reference Include="System.Collections.Immutable">
-      <HintPath>..\packages\Microsoft.Bcl.Immutable.1.0.34\lib\portable-net45+win8+wp8+wpa81\System.Collections.Immutable.dll</HintPath>
-    </Reference>
   </ItemGroup>
   <ItemGroup>
+    <Compile Include="..\Grpc.Core\Version.cs">
+      <Link>Version.cs</Link>
+    </Compile>
     <Compile Include="Properties\AssemblyInfo.cs" />
     <Compile Include="Empty.cs" />
     <Compile Include="Messages.cs" />
diff --git a/src/csharp/Grpc.IntegrationTesting/InteropClient.cs b/src/csharp/Grpc.IntegrationTesting/InteropClient.cs
index f0be522..bdcb2c5 100644
--- a/src/csharp/Grpc.IntegrationTesting/InteropClient.cs
+++ b/src/csharp/Grpc.IntegrationTesting/InteropClient.cs
@@ -102,8 +102,6 @@
 
         private void Run()
         {
-            GrpcEnvironment.Initialize();
-
             Credentials credentials = null;
             if (options.useTls)
             {
@@ -135,7 +133,6 @@
                 TestService.ITestServiceClient client = new TestService.TestServiceClient(channel, stubConfig);
                 RunTestCase(options.testCase, client);
             }
-
             GrpcEnvironment.Shutdown();
         }
 
diff --git a/src/csharp/Grpc.IntegrationTesting/InteropClientServerTest.cs b/src/csharp/Grpc.IntegrationTesting/InteropClientServerTest.cs
index 1a73345..6c2da9d 100644
--- a/src/csharp/Grpc.IntegrationTesting/InteropClientServerTest.cs
+++ b/src/csharp/Grpc.IntegrationTesting/InteropClientServerTest.cs
@@ -55,8 +55,6 @@
         [TestFixtureSetUp]
         public void Init()
         {
-            GrpcEnvironment.Initialize();
-
             server = new Server();
             server.AddServiceDefinition(TestService.BindService(new TestServiceImpl()));
             int port = server.AddListeningPort(host, Server.PickUnusedPort, TestCredentials.CreateTestServerCredentials());
@@ -74,7 +72,6 @@
         public void Cleanup()
         {
             channel.Dispose();
-
             server.ShutdownAsync().Wait();
             GrpcEnvironment.Shutdown();
         }
diff --git a/src/csharp/Grpc.IntegrationTesting/InteropServer.cs b/src/csharp/Grpc.IntegrationTesting/InteropServer.cs
index 87c3cbe..9475e66 100644
--- a/src/csharp/Grpc.IntegrationTesting/InteropServer.cs
+++ b/src/csharp/Grpc.IntegrationTesting/InteropServer.cs
@@ -88,8 +88,6 @@
 
         private void Run()
         {
-            GrpcEnvironment.Initialize();
-
             var server = new Server();
             server.AddServiceDefinition(TestService.BindService(new TestServiceImpl()));
 
diff --git a/src/csharp/Grpc.IntegrationTesting/Properties/AssemblyInfo.cs b/src/csharp/Grpc.IntegrationTesting/Properties/AssemblyInfo.cs
index f73575e..1beb0bb 100644
--- a/src/csharp/Grpc.IntegrationTesting/Properties/AssemblyInfo.cs
+++ b/src/csharp/Grpc.IntegrationTesting/Properties/AssemblyInfo.cs
@@ -9,4 +9,3 @@
 [assembly: AssemblyCopyright("Google Inc.  All rights reserved.")]
 [assembly: AssemblyTrademark("")]
 [assembly: AssemblyCulture("")]
-[assembly: AssemblyVersion("0.5.*")]
diff --git a/src/csharp/Grpc.IntegrationTesting/packages.config b/src/csharp/Grpc.IntegrationTesting/packages.config
index 291b7b8..c74ac75 100644
--- a/src/csharp/Grpc.IntegrationTesting/packages.config
+++ b/src/csharp/Grpc.IntegrationTesting/packages.config
@@ -7,8 +7,8 @@
   <package id="Microsoft.Bcl" version="1.1.9" targetFramework="net45" />
   <package id="Microsoft.Bcl.Async" version="1.0.168" targetFramework="net45" />
   <package id="Microsoft.Bcl.Build" version="1.0.14" targetFramework="net45" />
-  <package id="Microsoft.Bcl.Immutable" version="1.0.34" targetFramework="net45" />
   <package id="Microsoft.Net.Http" version="2.2.28" targetFramework="net45" />
   <package id="Newtonsoft.Json" version="6.0.6" targetFramework="net45" />
   <package id="NUnit" version="2.6.4" targetFramework="net45" />
+  <package id="System.Collections.Immutable" version="1.1.36" targetFramework="net45" />
 </packages>
\ No newline at end of file
diff --git a/src/csharp/Grpc.Tools.nuspec b/src/csharp/Grpc.Tools.nuspec
index 913d4c8..eabf5dc 100644
--- a/src/csharp/Grpc.Tools.nuspec
+++ b/src/csharp/Grpc.Tools.nuspec
@@ -5,13 +5,13 @@
     <title>gRPC C# Tools</title>
     <summary>Tools for C# implementation of gRPC - an RPC library and framework</summary>
     <description>Precompiled Windows binaries for generating protocol buffer messages and gRPC client/server code</description>
-    <version>0.5.1</version>
+    <version>$version$</version>
     <authors>Google Inc.</authors>
     <owners>grpc-packages</owners>
     <licenseUrl>https://github.com/grpc/grpc/blob/master/LICENSE</licenseUrl>
     <projectUrl>https://github.com/grpc/grpc</projectUrl>
     <requireLicenseAcceptance>false</requireLicenseAcceptance>
-    <releaseNotes>protoc.exe - protocol buffer compiler v3.0.0-alpha-3; grpc_csharp_plugin.exe - gRPC C# protoc plugin version 0.5.1</releaseNotes>
+    <releaseNotes>protoc.exe - protocol buffer compiler v3.0.0-alpha-3; grpc_csharp_plugin.exe - gRPC C# protoc plugin version $version$</releaseNotes>
     <copyright>Copyright 2015, Google Inc.</copyright>
     <tags>gRPC RPC Protocol HTTP/2</tags>
   </metadata>
diff --git a/src/csharp/Grpc.nuspec b/src/csharp/Grpc.nuspec
index cf4c74f..7fbd861 100644
--- a/src/csharp/Grpc.nuspec
+++ b/src/csharp/Grpc.nuspec
@@ -5,17 +5,17 @@
     <title>gRPC C#</title>
     <summary>C# implementation of gRPC - an RPC library and framework</summary>
     <description>C# implementation of gRPC - an RPC library and framework. See project site for more info.</description>
-    <version>0.5.1</version>
+    <version>$version$</version>
     <authors>Google Inc.</authors>
     <owners>grpc-packages</owners>
     <licenseUrl>https://github.com/grpc/grpc/blob/master/LICENSE</licenseUrl>
     <projectUrl>https://github.com/grpc/grpc</projectUrl>
     <requireLicenseAcceptance>false</requireLicenseAcceptance>
-    <releaseNotes>Release 0.5.1 of gRPC C#</releaseNotes>
+    <releaseNotes>Release $version$ of gRPC C#</releaseNotes>
     <copyright>Copyright 2015, Google Inc.</copyright>
     <tags>gRPC RPC Protocol HTTP/2</tags>
     <dependencies>
-      <dependency id="Grpc.Core" version="0.5.1" />
+      <dependency id="Grpc.Core" version="$version$" />
     </dependencies>
   </metadata>
   <files/>
diff --git a/src/csharp/Grpc.sln b/src/csharp/Grpc.sln
index 978739f..705e4fb 100644
--- a/src/csharp/Grpc.sln
+++ b/src/csharp/Grpc.sln
@@ -28,57 +28,68 @@
 		.nuget\packages.config = .nuget\packages.config

 	EndProjectSection

 EndProject

+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Grpc.HealthCheck", "Grpc.HealthCheck\Grpc.HealthCheck.csproj", "{AA5E328A-8835-49D7-98ED-C29F2B3049F0}"

+EndProject

+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Grpc.HealthCheck.Tests", "Grpc.HealthCheck.Tests\Grpc.HealthCheck.Tests.csproj", "{F8C6D937-C44B-4EE3-A431-B0FBAEACE47D}"

+EndProject

 Global

 	GlobalSection(SolutionConfigurationPlatforms) = preSolution

 		Debug|x86 = Debug|x86

 		Release|x86 = Release|x86

 	EndGlobalSection

 	GlobalSection(ProjectConfigurationPlatforms) = postSolution

-		{7DC1433E-3225-42C7-B7EA-546D56E27A4B}.Debug|x86.ActiveCfg = Debug|Any CPU

-		{7DC1433E-3225-42C7-B7EA-546D56E27A4B}.Debug|x86.Build.0 = Debug|Any CPU

-		{7DC1433E-3225-42C7-B7EA-546D56E27A4B}.Release|x86.ActiveCfg = Release|Any CPU

-		{7DC1433E-3225-42C7-B7EA-546D56E27A4B}.Release|x86.Build.0 = Release|Any CPU

-		{CCC4440E-49F7-4790-B0AF-FEABB0837AE7}.Debug|x86.ActiveCfg = Debug|Any CPU

-		{CCC4440E-49F7-4790-B0AF-FEABB0837AE7}.Debug|x86.Build.0 = Debug|Any CPU

-		{CCC4440E-49F7-4790-B0AF-FEABB0837AE7}.Release|x86.ActiveCfg = Release|Any CPU

-		{CCC4440E-49F7-4790-B0AF-FEABB0837AE7}.Release|x86.Build.0 = Release|Any CPU

-		{86EC5CB4-4EA2-40A2-8057-86542A0353BB}.Debug|x86.ActiveCfg = Debug|Any CPU

-		{86EC5CB4-4EA2-40A2-8057-86542A0353BB}.Debug|x86.Build.0 = Debug|Any CPU

-		{86EC5CB4-4EA2-40A2-8057-86542A0353BB}.Release|x86.ActiveCfg = Release|Any CPU

-		{86EC5CB4-4EA2-40A2-8057-86542A0353BB}.Release|x86.Build.0 = Release|Any CPU

 		{143B1C29-C442-4BE0-BF3F-A8F92288AC9F}.Debug|x86.ActiveCfg = Debug|Any CPU

 		{143B1C29-C442-4BE0-BF3F-A8F92288AC9F}.Debug|x86.Build.0 = Debug|Any CPU

 		{143B1C29-C442-4BE0-BF3F-A8F92288AC9F}.Release|x86.ActiveCfg = Release|Any CPU

 		{143B1C29-C442-4BE0-BF3F-A8F92288AC9F}.Release|x86.Build.0 = Release|Any CPU

-		{61ECB8EE-0C96-4F8E-B187-8E4D227417C0}.Debug|x86.ActiveCfg = Debug|x86

-		{61ECB8EE-0C96-4F8E-B187-8E4D227417C0}.Debug|x86.Build.0 = Debug|x86

-		{61ECB8EE-0C96-4F8E-B187-8E4D227417C0}.Release|x86.ActiveCfg = Release|x86

-		{61ECB8EE-0C96-4F8E-B187-8E4D227417C0}.Release|x86.Build.0 = Release|x86

-		{C61154BA-DD4A-4838-8420-0162A28925E0}.Debug|x86.ActiveCfg = Debug|x86

-		{C61154BA-DD4A-4838-8420-0162A28925E0}.Debug|x86.Build.0 = Debug|x86

-		{C61154BA-DD4A-4838-8420-0162A28925E0}.Release|x86.ActiveCfg = Release|x86

-		{C61154BA-DD4A-4838-8420-0162A28925E0}.Release|x86.Build.0 = Release|x86

 		{3D166931-BA2D-416E-95A3-D36E8F6E90B9}.Debug|x86.ActiveCfg = Debug|x86

 		{3D166931-BA2D-416E-95A3-D36E8F6E90B9}.Debug|x86.Build.0 = Debug|x86

 		{3D166931-BA2D-416E-95A3-D36E8F6E90B9}.Release|x86.ActiveCfg = Release|x86

 		{3D166931-BA2D-416E-95A3-D36E8F6E90B9}.Release|x86.Build.0 = Release|x86

+		{61ECB8EE-0C96-4F8E-B187-8E4D227417C0}.Debug|x86.ActiveCfg = Debug|x86

+		{61ECB8EE-0C96-4F8E-B187-8E4D227417C0}.Debug|x86.Build.0 = Debug|x86

+		{61ECB8EE-0C96-4F8E-B187-8E4D227417C0}.Release|x86.ActiveCfg = Release|x86

+		{61ECB8EE-0C96-4F8E-B187-8E4D227417C0}.Release|x86.Build.0 = Release|x86

+		{7DC1433E-3225-42C7-B7EA-546D56E27A4B}.Debug|x86.ActiveCfg = Debug|Any CPU

+		{7DC1433E-3225-42C7-B7EA-546D56E27A4B}.Debug|x86.Build.0 = Debug|Any CPU

+		{7DC1433E-3225-42C7-B7EA-546D56E27A4B}.Release|x86.ActiveCfg = Release|Any CPU

+		{7DC1433E-3225-42C7-B7EA-546D56E27A4B}.Release|x86.Build.0 = Release|Any CPU

+		{86EC5CB4-4EA2-40A2-8057-86542A0353BB}.Debug|x86.ActiveCfg = Debug|Any CPU

+		{86EC5CB4-4EA2-40A2-8057-86542A0353BB}.Debug|x86.Build.0 = Debug|Any CPU

+		{86EC5CB4-4EA2-40A2-8057-86542A0353BB}.Release|x86.ActiveCfg = Release|Any CPU

+		{86EC5CB4-4EA2-40A2-8057-86542A0353BB}.Release|x86.Build.0 = Release|Any CPU

 		{A654F3B8-E859-4E6A-B30D-227527DBEF0D}.Debug|x86.ActiveCfg = Debug|x86

 		{A654F3B8-E859-4E6A-B30D-227527DBEF0D}.Debug|x86.Build.0 = Debug|x86

 		{A654F3B8-E859-4E6A-B30D-227527DBEF0D}.Release|x86.ActiveCfg = Release|x86

 		{A654F3B8-E859-4E6A-B30D-227527DBEF0D}.Release|x86.Build.0 = Release|x86

-		{BF62FE08-373A-43D6-9D73-41CAA38B7011}.Debug|x86.ActiveCfg = Debug|x86

-		{BF62FE08-373A-43D6-9D73-41CAA38B7011}.Debug|x86.Build.0 = Debug|x86

-		{BF62FE08-373A-43D6-9D73-41CAA38B7011}.Release|x86.ActiveCfg = Release|x86

-		{BF62FE08-373A-43D6-9D73-41CAA38B7011}.Release|x86.Build.0 = Release|x86

+		{AA5E328A-8835-49D7-98ED-C29F2B3049F0}.Debug|x86.ActiveCfg = Debug|Any CPU

+		{AA5E328A-8835-49D7-98ED-C29F2B3049F0}.Debug|x86.Build.0 = Debug|Any CPU

+		{AA5E328A-8835-49D7-98ED-C29F2B3049F0}.Release|x86.ActiveCfg = Release|Any CPU

+		{AA5E328A-8835-49D7-98ED-C29F2B3049F0}.Release|x86.Build.0 = Release|Any CPU

 		{AE21D0EE-9A2C-4C15-AB7F-5224EED5B0EA}.Debug|x86.ActiveCfg = Debug|Any CPU

 		{AE21D0EE-9A2C-4C15-AB7F-5224EED5B0EA}.Debug|x86.Build.0 = Debug|Any CPU

 		{AE21D0EE-9A2C-4C15-AB7F-5224EED5B0EA}.Release|x86.ActiveCfg = Release|Any CPU

 		{AE21D0EE-9A2C-4C15-AB7F-5224EED5B0EA}.Release|x86.Build.0 = Release|Any CPU

+		{BF62FE08-373A-43D6-9D73-41CAA38B7011}.Debug|x86.ActiveCfg = Debug|x86

+		{BF62FE08-373A-43D6-9D73-41CAA38B7011}.Debug|x86.Build.0 = Debug|x86

+		{BF62FE08-373A-43D6-9D73-41CAA38B7011}.Release|x86.ActiveCfg = Release|x86

+		{BF62FE08-373A-43D6-9D73-41CAA38B7011}.Release|x86.Build.0 = Release|x86

+		{C61154BA-DD4A-4838-8420-0162A28925E0}.Debug|x86.ActiveCfg = Debug|x86

+		{C61154BA-DD4A-4838-8420-0162A28925E0}.Debug|x86.Build.0 = Debug|x86

+		{C61154BA-DD4A-4838-8420-0162A28925E0}.Release|x86.ActiveCfg = Release|x86

+		{C61154BA-DD4A-4838-8420-0162A28925E0}.Release|x86.Build.0 = Release|x86

+		{CCC4440E-49F7-4790-B0AF-FEABB0837AE7}.Debug|x86.ActiveCfg = Debug|Any CPU

+		{CCC4440E-49F7-4790-B0AF-FEABB0837AE7}.Debug|x86.Build.0 = Debug|Any CPU

+		{CCC4440E-49F7-4790-B0AF-FEABB0837AE7}.Release|x86.ActiveCfg = Release|Any CPU

+		{CCC4440E-49F7-4790-B0AF-FEABB0837AE7}.Release|x86.Build.0 = Release|Any CPU

+		{F8C6D937-C44B-4EE3-A431-B0FBAEACE47D}.Debug|x86.ActiveCfg = Debug|Any CPU

+		{F8C6D937-C44B-4EE3-A431-B0FBAEACE47D}.Debug|x86.Build.0 = Debug|Any CPU

+		{F8C6D937-C44B-4EE3-A431-B0FBAEACE47D}.Release|x86.ActiveCfg = Release|Any CPU

+		{F8C6D937-C44B-4EE3-A431-B0FBAEACE47D}.Release|x86.Build.0 = Release|Any CPU

+	EndGlobalSection

+	GlobalSection(NestedProjects) = preSolution

 	EndGlobalSection

 	GlobalSection(SolutionProperties) = preSolution

 		HideSolutionNode = FALSE

 	EndGlobalSection

-	GlobalSection(MonoDevelopProperties) = preSolution

-		StartupItem = Grpc.Examples\Grpc.Examples.csproj

-	EndGlobalSection

 EndGlobal

diff --git a/src/csharp/build_packages.bat b/src/csharp/build_packages.bat
index 3412129..c3e5fe8 100644
--- a/src/csharp/build_packages.bat
+++ b/src/csharp/build_packages.bat
@@ -1,5 +1,9 @@
 @rem Builds gRPC NuGet packages
 
+@rem Current package versions
+set VERSION=0.6.0
+set CORE_VERSION=0.10.0
+
 @rem Adjust the location of nuget.exe
 set NUGET=C:\nuget\nuget.exe
 
@@ -10,11 +14,12 @@
 
 @call buildall.bat || goto :error
 
-%NUGET% pack ..\..\vsprojects\nuget_package\grpc.native.csharp_ext.nuspec || goto :error
-%NUGET% pack Grpc.Core\Grpc.Core.nuspec -Symbols || goto :error
-%NUGET% pack Grpc.Auth\Grpc.Auth.nuspec -Symbols || goto :error
-%NUGET% pack Grpc.Tools.nuspec || goto :error
-%NUGET% pack Grpc.nuspec || goto :error
+%NUGET% pack ..\..\vsprojects\nuget_package\grpc.native.csharp_ext.nuspec -Version %CORE_VERSION% || goto :error
+%NUGET% pack Grpc.Auth\Grpc.Auth.nuspec -Symbols -Version %VERSION% || goto :error
+%NUGET% pack Grpc.Core\Grpc.Core.nuspec -Symbols -Version %VERSION% -Properties GrpcNativeCsharpExtVersion=%CORE_VERSION% || goto :error
+%NUGET% pack Grpc.HealthCheck\Grpc.HealthCheck.nuspec -Symbols -Version %VERSION% || goto :error
+%NUGET% pack Grpc.Tools.nuspec -Version %VERSION% || goto :error
+%NUGET% pack Grpc.nuspec -Version %VERSION% || goto :error
 
 goto :EOF
 
diff --git a/src/csharp/ext/grpc_csharp_ext.c b/src/csharp/ext/grpc_csharp_ext.c
index ec125db..a55cc9e 100644
--- a/src/csharp/ext/grpc_csharp_ext.c
+++ b/src/csharp/ext/grpc_csharp_ext.c
@@ -379,7 +379,7 @@
 
 /* Timespec */
 
-GPR_EXPORT gpr_timespec GPR_CALLTYPE gprsharp_now(void) { return gpr_now(); }
+GPR_EXPORT gpr_timespec GPR_CALLTYPE gprsharp_now(void) { return gpr_now(GPR_CLOCK_REALTIME); }
 
 GPR_EXPORT gpr_timespec GPR_CALLTYPE gprsharp_inf_future(void) {
   return gpr_inf_future;
diff --git a/src/csharp/generate_proto_csharp.sh b/src/csharp/generate_proto_csharp.sh
index f980787..6eb3887 100755
--- a/src/csharp/generate_proto_csharp.sh
+++ b/src/csharp/generate_proto_csharp.sh
@@ -35,9 +35,13 @@
 PLUGIN=protoc-gen-grpc=../../bins/opt/grpc_csharp_plugin
 EXAMPLES_DIR=Grpc.Examples
 INTEROP_DIR=Grpc.IntegrationTesting
+HEALTHCHECK_DIR=Grpc.HealthCheck
 
 protoc --plugin=$PLUGIN --grpc_out=$EXAMPLES_DIR \
     -I $EXAMPLES_DIR/proto $EXAMPLES_DIR/proto/math.proto
 
 protoc --plugin=$PLUGIN --grpc_out=$INTEROP_DIR \
     -I $INTEROP_DIR/proto $INTEROP_DIR/proto/test.proto
+	
+protoc --plugin=$PLUGIN --grpc_out=$HEALTHCHECK_DIR \
+    -I $HEALTHCHECK_DIR/proto $HEALTHCHECK_DIR/proto/health.proto
diff --git a/src/node/package.json b/src/node/package.json
index 6b54570..1caf158 100644
--- a/src/node/package.json
+++ b/src/node/package.json
@@ -1,6 +1,6 @@
 {
   "name": "grpc",
-  "version": "0.9.1",
+  "version": "0.10.0",
   "author": "Google Inc.",
   "description": "gRPC Library for Node",
   "homepage": "http://www.grpc.io/",
diff --git a/src/node/src/server.js b/src/node/src/server.js
index 9ac428f..00be400 100644
--- a/src/node/src/server.js
+++ b/src/node/src/server.js
@@ -55,7 +55,7 @@
  */
 function handleError(call, error) {
   var status = {
-    code: grpc.status.INTERNAL,
+    code: grpc.status.UNKNOWN,
     details: 'Unknown Error',
     metadata: {}
   };
@@ -142,12 +142,12 @@
   stream.on('finish', sendStatus);
   /**
    * Set the pending status to a given error status. If the error does not have
-   * code or details properties, the code will be set to grpc.status.INTERNAL
+   * code or details properties, the code will be set to grpc.status.UNKNOWN
    * and the details will be set to 'Unknown Error'.
    * @param {Error} err The error object
    */
   function setStatus(err) {
-    var code = grpc.status.INTERNAL;
+    var code = grpc.status.UNKNOWN;
     var details = 'Unknown Error';
     var metadata = {};
     if (err.hasOwnProperty('message')) {
diff --git a/src/php/bin/determine_extension_dir.sh b/src/php/bin/determine_extension_dir.sh
index 6bbd934..3c1fc29 100755
--- a/src/php/bin/determine_extension_dir.sh
+++ b/src/php/bin/determine_extension_dir.sh
@@ -27,12 +27,12 @@
 # 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 -e
 default_extension_dir=$(php-config --extension-dir)
-if command -v brew >/dev/null && [ -d $(brew --prefix)/opt/grpc-php ]; then
-  # homebrew and the grpc-php formula are installed
-  extension_dir="-d extension_dir="$(brew --prefix)/opt/grpc-php
+if command -v brew > /dev/null && \
+   brew ls --versions | grep php5[56]-grpc > /dev/null; then
+  # the grpc php extension was installed by homebrew
+  :
 elif [ ! -e $default_extension_dir/grpc.so ]; then
   # the grpc extension is not found in the default PHP extension dir
   # try the source modules directory
@@ -45,5 +45,5 @@
   for f in $default_extension_dir/*.so; do
     ln -s $f $module_dir/$(basename $f) &> /dev/null || true
   done
-  extension_dir="-d extension_dir="$module_dir
+  extension_dir="-d extension_dir=${module_dir} -d extension=grpc.so"
 fi
diff --git a/src/php/bin/interop_client.sh b/src/php/bin/interop_client.sh
index 42e075c..17b888d 100755
--- a/src/php/bin/interop_client.sh
+++ b/src/php/bin/interop_client.sh
@@ -31,5 +31,5 @@
 set -e
 cd $(dirname $0)
 source ./determine_extension_dir.sh
-php $extension_dir -d extension=grpc.so \
+php $extension_dir \
   ../tests/interop/interop_client.php $@ 1>&2
diff --git a/src/php/bin/run_gen_code_test.sh b/src/php/bin/run_gen_code_test.sh
index 03a9101..6e56c72 100755
--- a/src/php/bin/run_gen_code_test.sh
+++ b/src/php/bin/run_gen_code_test.sh
@@ -31,8 +31,8 @@
 set -e
 cd $(dirname $0)
 source ./determine_extension_dir.sh
-export GRPC_TEST_HOST=localhost:7071
-php $extension_dir -d extension=grpc.so $(which phpunit) -v --debug --strict \
+export GRPC_TEST_HOST=localhost:50051
+php $extension_dir $(which phpunit) -v --debug --strict \
   ../tests/generated_code/GeneratedCodeTest.php
-php $extension_dir -d extension=grpc.so $(which phpunit) -v --debug --strict \
+php $extension_dir $(which phpunit) -v --debug --strict \
   ../tests/generated_code/GeneratedCodeWithCallbackTest.php
diff --git a/src/php/bin/run_tests.sh b/src/php/bin/run_tests.sh
index 4c37285..953f408 100755
--- a/src/php/bin/run_tests.sh
+++ b/src/php/bin/run_tests.sh
@@ -33,5 +33,5 @@
 set -e
 cd $(dirname $0)
 source ./determine_extension_dir.sh
-php $extension_dir -d extension=grpc.so $(which phpunit) -v --debug --strict \
+php $extension_dir $(which phpunit) -v --debug --strict \
   ../tests/unit_tests
diff --git a/src/php/ext/grpc/README.md b/src/php/ext/grpc/README.md
index 0ac09e1..88d2c48 100644
--- a/src/php/ext/grpc/README.md
+++ b/src/php/ext/grpc/README.md
@@ -4,7 +4,7 @@
 # Requirements
 
  * PHP 5.5+
- * [gRPC core library](https://github.com/grpc/grpc) 0.9.1
+ * [gRPC core library](https://github.com/grpc/grpc) 0.10.0
 
 # Installation
 
@@ -55,7 +55,7 @@
 Note: before a stable release, you may need to do
 
 ```sh
-$ sudo pecl install grpc-0.5.0
+$ sudo pecl install grpc-0.5.1
 ```
 
 OR
diff --git a/src/php/ext/grpc/package.xml b/src/php/ext/grpc/package.xml
index 2c89829..bc2a059 100644
--- a/src/php/ext/grpc/package.xml
+++ b/src/php/ext/grpc/package.xml
@@ -10,11 +10,11 @@
   <email>grpc-packages@google.com</email>
   <active>yes</active>
  </lead>
- <date>2015-06-16</date>
- <time>20:12:55</time>
+ <date>2015-07-09</date>
+ <time>21:47:27</time>
  <version>
-  <release>0.5.0</release>
-  <api>0.5.0</api>
+  <release>0.5.1</release>
+  <api>0.5.1</api>
  </version>
  <stability>
   <release>alpha</release>
@@ -22,7 +22,7 @@
  </stability>
  <license>BSD</license>
  <notes>
-First alpha release
+Update to wrap gRPC C Core version 0.10.0
  </notes>
  <contents>
   <dir baseinstalldir="/" name="/">
@@ -34,15 +34,15 @@
    <file baseinstalldir="/" md5sum="f1b66029daeced20b47cf00cc6523fc8" name="channel.h" role="src" />
    <file baseinstalldir="/" md5sum="81a1193e93d8b6602add8ac360de565b" name="completion_queue.c" role="src" />
    <file baseinstalldir="/" md5sum="f10b5bb232d74a6878e829e2e76cdaa2" name="completion_queue.h" role="src" />
-   <file baseinstalldir="/" md5sum="a9181ed994a072ac5f41e7c9705c170f" name="config.m4" role="src" />
+   <file baseinstalldir="/" md5sum="a22f8eac0164761058cc4d9eb2ceb069" name="config.m4" role="src" />
    <file baseinstalldir="/" md5sum="8c3f1e11dac623001378bfd53b554f08" name="credentials.c" role="src" />
    <file baseinstalldir="/" md5sum="6988d6e97c19c8f8e3eb92371cf8246b" name="credentials.h" role="src" />
    <file baseinstalldir="/" md5sum="38a1bc979d810c36ebc2a52d4b7b5319" name="CREDITS" role="doc" />
    <file baseinstalldir="/" md5sum="3f35b472bbdef5a788cd90617d7d0847" name="LICENSE" role="doc" />
    <file baseinstalldir="/" md5sum="6aaa7a290122d230f2d8c4e4e05da4a9" name="php_grpc.c" role="src" />
    <file baseinstalldir="/" md5sum="673b07859d9f69232f8a754c56780686" name="php_grpc.h" role="src" />
-   <file baseinstalldir="/" md5sum="4d4d3382f8d10cae2e4378468e5516b9" name="README.md" role="doc" />
-   <file baseinstalldir="/" md5sum="53fda0ee6937f6ddc8e271886018d441" name="server.c" role="src" />
+   <file baseinstalldir="/" md5sum="c1d0b42fd77b7d6740bf7744bee90af5" name="README.md" role="doc" />
+   <file baseinstalldir="/" md5sum="30997dd423403e1f8ad09dcee598e5c4" name="server.c" role="src" />
    <file baseinstalldir="/" md5sum="4b730f06d14cbbb0642bdbd194749595" name="server.h" role="src" />
    <file baseinstalldir="/" md5sum="f6930beafb6c0e061899262f2f077e98" name="server_credentials.c" role="src" />
    <file baseinstalldir="/" md5sum="9c4b4cc06356a8a39a16a085a9b85996" name="server_credentials.h" role="src" />
@@ -78,5 +78,20 @@
 First alpha release
    </notes>
   </release>
+  <release>
+   <version>
+    <release>0.5.1</release>
+    <api>0.5.1</api>
+   </version>
+   <stability>
+    <release>alpha</release>
+    <api>alpha</api>
+   </stability>
+   <date>2015-07-09</date>
+   <license>BSD</license>
+   <notes>
+Update to wrap gRPC C Core version 0.10.0
+   </notes>
+  </release>
  </changelog>
 </package>
diff --git a/src/php/ext/grpc/timeval.c b/src/php/ext/grpc/timeval.c
index 8a278d6..ccf7f0f 100644
--- a/src/php/ext/grpc/timeval.c
+++ b/src/php/ext/grpc/timeval.c
@@ -208,7 +208,7 @@
  * @return Timeval The current time
  */
 PHP_METHOD(Timeval, now) {
-  zval *now = grpc_php_wrap_timeval(gpr_now());
+  zval *now = grpc_php_wrap_timeval(gpr_now(GPR_CLOCK_REALTIME));
   RETURN_DESTROY_ZVAL(now);
 }
 
diff --git a/src/python/interop/setup.py b/src/python/interop/setup.py
index 502fcbe..75012b0 100644
--- a/src/python/interop/setup.py
+++ b/src/python/interop/setup.py
@@ -45,7 +45,7 @@
         'credentials/server1.pem',]
 }
 
-_INSTALL_REQUIRES = ['oauth2client>=1.4.7', 'grpcio>=0.4.0a4']
+_INSTALL_REQUIRES = ['oauth2client>=1.4.7', 'grpcio>=0.10.0a0']
 
 setuptools.setup(
     name='interop',
diff --git a/src/python/requirements.txt b/src/python/requirements.txt
index 41d633a..43395df 100644
--- a/src/python/requirements.txt
+++ b/src/python/requirements.txt
@@ -1,4 +1,3 @@
 enum34==1.0.4
 futures==2.2.0
 protobuf==3.0.0a3
-cython>=0.22
diff --git a/src/python/src/grpc/_links/__init__.py b/src/python/src/grpc/_links/__init__.py
new file mode 100644
index 0000000..7086519
--- /dev/null
+++ b/src/python/src/grpc/_links/__init__.py
@@ -0,0 +1,30 @@
+# 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.
+
+
diff --git a/src/python/src/grpc/_links/_lonely_invocation_link_test.py b/src/python/src/grpc/_links/_lonely_invocation_link_test.py
new file mode 100644
index 0000000..3d629f4
--- /dev/null
+++ b/src/python/src/grpc/_links/_lonely_invocation_link_test.py
@@ -0,0 +1,88 @@
+# 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.
+
+"""A test of invocation-side code unconnected to an RPC server."""
+
+import unittest
+
+from grpc._adapter import _intermediary_low
+from grpc._links import invocation
+from grpc.framework.common import test_constants
+from grpc.framework.interfaces.links import links
+from grpc.framework.interfaces.links import test_cases
+from grpc.framework.interfaces.links import test_utilities
+
+_NULL_BEHAVIOR = lambda unused_argument: None
+
+
+class LonelyInvocationLinkTest(unittest.TestCase):
+
+  def testUpAndDown(self):
+    channel = _intermediary_low.Channel('nonexistent:54321', None)
+    invocation_link = invocation.invocation_link(channel, 'nonexistent', {}, {})
+
+    invocation_link.start()
+    invocation_link.stop()
+
+  def _test_lonely_invocation_with_termination(self, termination):
+    test_operation_id = object()
+    test_group = 'test package.Test Service'
+    test_method = 'test method'
+    invocation_link_mate = test_utilities.RecordingLink()
+
+    channel = _intermediary_low.Channel('nonexistent:54321', None)
+    invocation_link = invocation.invocation_link(
+        channel, 'nonexistent', {(test_group, test_method): _NULL_BEHAVIOR},
+        {(test_group, test_method): _NULL_BEHAVIOR})
+    invocation_link.join_link(invocation_link_mate)
+    invocation_link.start()
+
+    ticket = links.Ticket(
+        test_operation_id, 0, test_group, test_method,
+        links.Ticket.Subscription.FULL, test_constants.SHORT_TIMEOUT, 1, None,
+        None, None, None, None, termination)
+    invocation_link.accept_ticket(ticket)
+    invocation_link_mate.block_until_tickets_satisfy(test_cases.terminated)
+
+    invocation_link.stop()
+
+    self.assertIsNot(
+        invocation_link_mate.tickets()[-1].termination,
+        links.Ticket.Termination.COMPLETION)
+
+  def testLonelyInvocationLinkWithCommencementTicket(self):
+    self._test_lonely_invocation_with_termination(None)
+
+  def testLonelyInvocationLinkWithEntireTicket(self):
+    self._test_lonely_invocation_with_termination(
+        links.Ticket.Termination.COMPLETION)
+
+
+if __name__ == '__main__':
+  unittest.main()
diff --git a/src/python/src/grpc/_links/_proto_scenarios.py b/src/python/src/grpc/_links/_proto_scenarios.py
new file mode 100644
index 0000000..ccf3c29
--- /dev/null
+++ b/src/python/src/grpc/_links/_proto_scenarios.py
@@ -0,0 +1,261 @@
+# 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.
+
+"""Test scenarios using protocol buffers."""
+
+import abc
+import threading
+
+from grpc._junkdrawer import math_pb2
+
+
+class ProtoScenario(object):
+  """An RPC test scenario using protocol buffers."""
+  __metaclass__ = abc.ABCMeta
+
+  @abc.abstractmethod
+  def group_and_method(self):
+    """Access the test group and method.
+
+    Returns:
+      The test group and method as a pair.
+    """
+    raise NotImplementedError()
+
+  @abc.abstractmethod
+  def serialize_request(self, request):
+    """Serialize a request protocol buffer.
+
+    Args:
+      request: A request protocol buffer.
+
+    Returns:
+      The bytestring serialization of the given request protocol buffer.
+    """
+    raise NotImplementedError()
+
+  @abc.abstractmethod
+  def deserialize_request(self, request_bytestring):
+    """Deserialize a request protocol buffer.
+
+    Args:
+      request_bytestring: The bytestring serialization of a request protocol
+        buffer.
+
+    Returns:
+      The request protocol buffer deserialized from the given byte string.
+    """
+    raise NotImplementedError()
+
+  @abc.abstractmethod
+  def serialize_response(self, response):
+    """Serialize a response protocol buffer.
+
+    Args:
+      response: A response protocol buffer.
+
+    Returns:
+      The bytestring serialization of the given response protocol buffer.
+    """
+    raise NotImplementedError()
+
+  @abc.abstractmethod
+  def deserialize_response(self, response_bytestring):
+    """Deserialize a response protocol buffer.
+
+    Args:
+      response_bytestring: The bytestring serialization of a response protocol
+        buffer.
+
+    Returns:
+      The response protocol buffer deserialized from the given byte string.
+    """
+    raise NotImplementedError()
+
+  @abc.abstractmethod
+  def requests(self):
+    """Access the sequence of requests for this scenario.
+
+    Returns:
+      A sequence of request protocol buffers.
+    """
+    raise NotImplementedError()
+
+  @abc.abstractmethod
+  def response_for_request(self, request):
+    """Access the response for a particular request.
+
+    Args:
+      request: A request protocol buffer.
+
+    Returns:
+      The response protocol buffer appropriate for the given request.
+    """
+    raise NotImplementedError()
+
+  @abc.abstractmethod
+  def verify_requests(self, experimental_requests):
+    """Verify the requests transmitted through the system under test.
+
+    Args:
+      experimental_requests: The request protocol buffers transmitted through
+        the system under test.
+
+    Returns:
+      True if the requests satisfy this test scenario; False otherwise.
+    """
+    raise NotImplementedError()
+
+  @abc.abstractmethod
+  def verify_responses(self, experimental_responses):
+    """Verify the responses transmitted through the system under test.
+
+    Args:
+      experimental_responses: The response protocol buffers transmitted through
+        the system under test.
+
+    Returns:
+      True if the responses satisfy this test scenario; False otherwise.
+    """
+    raise NotImplementedError()
+
+
+class EmptyScenario(ProtoScenario):
+  """A scenario that transmits no protocol buffers in either direction."""
+
+  def group_and_method(self):
+    return 'math.Math', 'DivMany'
+
+  def serialize_request(self, request):
+    raise ValueError('This should not be necessary to call!')
+
+  def deserialize_request(self, request_bytestring):
+    raise ValueError('This should not be necessary to call!')
+
+  def serialize_response(self, response):
+    raise ValueError('This should not be necessary to call!')
+
+  def deserialize_response(self, response_bytestring):
+    raise ValueError('This should not be necessary to call!')
+
+  def requests(self):
+    return ()
+
+  def response_for_request(self, request):
+    raise ValueError('This should not be necessary to call!')
+
+  def verify_requests(self, experimental_requests):
+    return not experimental_requests
+
+  def verify_responses(self, experimental_responses):
+    return not experimental_responses
+
+
+class BidirectionallyUnaryScenario(ProtoScenario):
+  """A scenario that transmits no protocol buffers in either direction."""
+
+  _DIVIDEND = 59
+  _DIVISOR = 7
+  _QUOTIENT = 8
+  _REMAINDER = 3
+
+  _REQUEST = math_pb2.DivArgs(dividend=_DIVIDEND, divisor=_DIVISOR)
+  _RESPONSE = math_pb2.DivReply(quotient=_QUOTIENT, remainder=_REMAINDER)
+
+  def group_and_method(self):
+    return 'math.Math', 'Div'
+
+  def serialize_request(self, request):
+    return request.SerializeToString()
+
+  def deserialize_request(self, request_bytestring):
+    return math_pb2.DivArgs.FromString(request_bytestring)
+
+  def serialize_response(self, response):
+    return response.SerializeToString()
+
+  def deserialize_response(self, response_bytestring):
+    return math_pb2.DivReply.FromString(response_bytestring)
+
+  def requests(self):
+    return [self._REQUEST]
+
+  def response_for_request(self, request):
+    return self._RESPONSE
+
+  def verify_requests(self, experimental_requests):
+    return tuple(experimental_requests) == (self._REQUEST,)
+
+  def verify_responses(self, experimental_responses):
+    return tuple(experimental_responses) == (self._RESPONSE,)
+
+
+class BidirectionallyStreamingScenario(ProtoScenario):
+  """A scenario that transmits no protocol buffers in either direction."""
+
+  _STREAM_LENGTH = 200
+  _REQUESTS = tuple(
+      math_pb2.DivArgs(dividend=59 + index, divisor=7 + index)
+      for index in range(_STREAM_LENGTH))
+
+  def __init__(self):
+    self._lock = threading.Lock()
+    self._responses = []
+
+  def group_and_method(self):
+    return 'math.Math', 'DivMany'
+
+  def serialize_request(self, request):
+    return request.SerializeToString()
+
+  def deserialize_request(self, request_bytestring):
+    return math_pb2.DivArgs.FromString(request_bytestring)
+
+  def serialize_response(self, response):
+    return response.SerializeToString()
+
+  def deserialize_response(self, response_bytestring):
+    return math_pb2.DivReply.FromString(response_bytestring)
+
+  def requests(self):
+    return self._REQUESTS
+
+  def response_for_request(self, request):
+    quotient, remainder = divmod(request.dividend, request.divisor)
+    response = math_pb2.DivReply(quotient=quotient, remainder=remainder)
+    with self._lock:
+      self._responses.append(response)
+    return response
+
+  def verify_requests(self, experimental_requests):
+    return tuple(experimental_requests) == self._REQUESTS
+
+  def verify_responses(self, experimental_responses):
+    with self._lock:
+      return tuple(experimental_responses) == tuple(self._responses)
diff --git a/src/python/src/grpc/_links/_transmission_test.py b/src/python/src/grpc/_links/_transmission_test.py
new file mode 100644
index 0000000..c5ef1ed
--- /dev/null
+++ b/src/python/src/grpc/_links/_transmission_test.py
@@ -0,0 +1,226 @@
+# 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.
+
+"""Tests transmission of tickets across gRPC-on-the-wire."""
+
+import unittest
+
+from grpc._adapter import _intermediary_low
+from grpc._links import _proto_scenarios
+from grpc._links import invocation
+from grpc._links import service
+from grpc.framework.common import test_constants
+from grpc.framework.interfaces.links import links
+from grpc.framework.interfaces.links import test_cases
+from grpc.framework.interfaces.links import test_utilities
+
+_IDENTITY = lambda x: x
+
+
+class TransmissionTest(test_cases.TransmissionTest, unittest.TestCase):
+
+  def create_transmitting_links(self):
+    service_link = service.service_link(
+        {self.group_and_method(): self.deserialize_request},
+        {self.group_and_method(): self.serialize_response})
+    port = service_link.add_port(0, None)
+    service_link.start()
+    channel = _intermediary_low.Channel('localhost:%d' % port, None)
+    invocation_link = invocation.invocation_link(
+        channel, 'localhost',
+        {self.group_and_method(): self.serialize_request},
+        {self.group_and_method(): self.deserialize_response})
+    invocation_link.start()
+    return invocation_link, service_link
+
+  def destroy_transmitting_links(self, invocation_side_link, service_side_link):
+    invocation_side_link.stop()
+    service_side_link.stop_gracefully()
+
+  def create_invocation_initial_metadata(self):
+    return (
+        ('first invocation initial metadata key', 'just a string value'),
+        ('second invocation initial metadata key', '0123456789'),
+        ('third invocation initial metadata key-bin', '\x00\x57' * 100),
+    )
+
+  def create_invocation_terminal_metadata(self):
+    return None
+
+  def create_service_initial_metadata(self):
+    return (
+        ('first service initial metadata key', 'just another string value'),
+        ('second service initial metadata key', '9876543210'),
+        ('third service initial metadata key-bin', '\x00\x59\x02' * 100),
+    )
+
+  def create_service_terminal_metadata(self):
+    return (
+        ('first service terminal metadata key', 'yet another string value'),
+        ('second service terminal metadata key', 'abcdefghij'),
+        ('third service terminal metadata key-bin', '\x00\x37' * 100),
+    )
+
+  def create_invocation_completion(self):
+    return None, None
+
+  def create_service_completion(self):
+    return _intermediary_low.Code.OK, 'An exuberant test "details" message!'
+
+  def assertMetadataEqual(self, original_metadata, transmitted_metadata):
+    self.assertSequenceEqual(original_metadata, transmitted_metadata)
+
+
+class RoundTripTest(unittest.TestCase):
+
+  def testZeroMessageRoundTrip(self):
+    test_operation_id = object()
+    test_group = 'test package.Test Group'
+    test_method = 'test method'
+    identity_transformation = {(test_group, test_method): _IDENTITY}
+    test_code = _intermediary_low.Code.OK
+    test_message = 'a test message'
+
+    service_link = service.service_link(
+        identity_transformation, identity_transformation)
+    service_mate = test_utilities.RecordingLink()
+    service_link.join_link(service_mate)
+    port = service_link.add_port(0, None)
+    service_link.start()
+    channel = _intermediary_low.Channel('localhost:%d' % port, None)
+    invocation_link = invocation.invocation_link(
+        channel, 'localhost', identity_transformation, identity_transformation)
+    invocation_mate = test_utilities.RecordingLink()
+    invocation_link.join_link(invocation_mate)
+    invocation_link.start()
+
+    invocation_ticket = links.Ticket(
+        test_operation_id, 0, test_group, test_method,
+        links.Ticket.Subscription.FULL, test_constants.LONG_TIMEOUT, None, None,
+        None, None, None, None, links.Ticket.Termination.COMPLETION)
+    invocation_link.accept_ticket(invocation_ticket)
+    service_mate.block_until_tickets_satisfy(test_cases.terminated)
+
+    service_ticket = links.Ticket(
+        service_mate.tickets()[-1].operation_id, 0, None, None, None, None,
+        None, None, None, None, test_code, test_message,
+        links.Ticket.Termination.COMPLETION)
+    service_link.accept_ticket(service_ticket)
+    invocation_mate.block_until_tickets_satisfy(test_cases.terminated)
+
+    invocation_link.stop()
+    service_link.stop_gracefully()
+
+    self.assertIs(
+        service_mate.tickets()[-1].termination,
+        links.Ticket.Termination.COMPLETION)
+    self.assertIs(
+        invocation_mate.tickets()[-1].termination,
+        links.Ticket.Termination.COMPLETION)
+
+  def _perform_scenario_test(self, scenario):
+    test_operation_id = object()
+    test_group, test_method = scenario.group_and_method()
+    test_code = _intermediary_low.Code.OK
+    test_message = 'a scenario test message'
+
+    service_link = service.service_link(
+        {(test_group, test_method): scenario.deserialize_request},
+        {(test_group, test_method): scenario.serialize_response})
+    service_mate = test_utilities.RecordingLink()
+    service_link.join_link(service_mate)
+    port = service_link.add_port(0, None)
+    service_link.start()
+    channel = _intermediary_low.Channel('localhost:%d' % port, None)
+    invocation_link = invocation.invocation_link(
+        channel, 'localhost',
+        {(test_group, test_method): scenario.serialize_request},
+        {(test_group, test_method): scenario.deserialize_response})
+    invocation_mate = test_utilities.RecordingLink()
+    invocation_link.join_link(invocation_mate)
+    invocation_link.start()
+
+    invocation_ticket = links.Ticket(
+        test_operation_id, 0, test_group, test_method,
+        links.Ticket.Subscription.FULL, test_constants.LONG_TIMEOUT, None, None,
+        None, None, None, None, None)
+    invocation_link.accept_ticket(invocation_ticket)
+    requests = scenario.requests()
+    for request_index, request in enumerate(requests):
+      request_ticket = links.Ticket(
+          test_operation_id, 1 + request_index, None, None, None, None, 1, None,
+          request, None, None, None, None)
+      invocation_link.accept_ticket(request_ticket)
+      service_mate.block_until_tickets_satisfy(
+          test_cases.at_least_n_payloads_received_predicate(1 + request_index))
+      response_ticket = links.Ticket(
+          service_mate.tickets()[0].operation_id, request_index, None, None,
+          None, None, 1, None, scenario.response_for_request(request), None,
+          None, None, None)
+      service_link.accept_ticket(response_ticket)
+      invocation_mate.block_until_tickets_satisfy(
+          test_cases.at_least_n_payloads_received_predicate(1 + request_index))
+    request_count = len(requests)
+    invocation_completion_ticket = links.Ticket(
+        test_operation_id, request_count + 1, None, None, None, None, None,
+        None, None, None, None, None, links.Ticket.Termination.COMPLETION)
+    invocation_link.accept_ticket(invocation_completion_ticket)
+    service_mate.block_until_tickets_satisfy(test_cases.terminated)
+    service_completion_ticket = links.Ticket(
+        service_mate.tickets()[0].operation_id, request_count, None, None, None,
+        None, None, None, None, None, test_code, test_message,
+        links.Ticket.Termination.COMPLETION)
+    service_link.accept_ticket(service_completion_ticket)
+    invocation_mate.block_until_tickets_satisfy(test_cases.terminated)
+
+    invocation_link.stop()
+    service_link.stop_gracefully()
+
+    observed_requests = tuple(
+        ticket.payload for ticket in service_mate.tickets()
+        if ticket.payload is not None)
+    observed_responses = tuple(
+        ticket.payload for ticket in invocation_mate.tickets()
+        if ticket.payload is not None)
+    self.assertTrue(scenario.verify_requests(observed_requests))
+    self.assertTrue(scenario.verify_responses(observed_responses))
+
+  def testEmptyScenario(self):
+    self._perform_scenario_test(_proto_scenarios.EmptyScenario())
+
+  def testBidirectionallyUnaryScenario(self):
+    self._perform_scenario_test(_proto_scenarios.BidirectionallyUnaryScenario())
+
+  def testBidirectionallyStreamingScenario(self):
+    self._perform_scenario_test(
+        _proto_scenarios.BidirectionallyStreamingScenario())
+
+
+if __name__ == '__main__':
+  unittest.main(verbosity=2)
diff --git a/src/python/src/grpc/_links/invocation.py b/src/python/src/grpc/_links/invocation.py
new file mode 100644
index 0000000..0058ae9
--- /dev/null
+++ b/src/python/src/grpc/_links/invocation.py
@@ -0,0 +1,363 @@
+# 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.
+
+"""The RPC-invocation-side bridge between RPC Framework and GRPC-on-the-wire."""
+
+import abc
+import enum
+import logging
+import threading
+import time
+
+from grpc._adapter import _intermediary_low
+from grpc.framework.foundation import activated
+from grpc.framework.foundation import logging_pool
+from grpc.framework.foundation import relay
+from grpc.framework.interfaces.links import links
+
+
+@enum.unique
+class _Read(enum.Enum):
+  AWAITING_METADATA = 'awaiting metadata'
+  READING = 'reading'
+  AWAITING_ALLOWANCE = 'awaiting allowance'
+  CLOSED = 'closed'
+
+
+@enum.unique
+class _HighWrite(enum.Enum):
+  OPEN = 'open'
+  CLOSED = 'closed'
+
+
+@enum.unique
+class _LowWrite(enum.Enum):
+  OPEN = 'OPEN'
+  ACTIVE = 'ACTIVE'
+  CLOSED = 'CLOSED'
+
+
+class _RPCState(object):
+
+  def __init__(
+      self, call, request_serializer, response_deserializer, sequence_number,
+      read, allowance, high_write, low_write):
+    self.call = call
+    self.request_serializer = request_serializer
+    self.response_deserializer = response_deserializer
+    self.sequence_number = sequence_number
+    self.read = read
+    self.allowance = allowance
+    self.high_write = high_write
+    self.low_write = low_write
+
+
+class _Kernel(object):
+
+  def __init__(
+      self, channel, host, request_serializers, response_deserializers,
+      ticket_relay):
+    self._lock = threading.Lock()
+    self._channel = channel
+    self._host = host
+    self._request_serializers = request_serializers
+    self._response_deserializers = response_deserializers
+    self._relay = ticket_relay
+
+    self._completion_queue = None
+    self._rpc_states = None
+    self._pool = None
+
+  def _on_write_event(self, operation_id, unused_event, rpc_state):
+    if rpc_state.high_write is _HighWrite.CLOSED:
+      rpc_state.call.complete(operation_id)
+      rpc_state.low_write = _LowWrite.CLOSED
+    else:
+      ticket = links.Ticket(
+          operation_id, rpc_state.sequence_number, None, None, None, None, 1,
+          None, None, None, None, None, None)
+      rpc_state.sequence_number += 1
+      self._relay.add_value(ticket)
+      rpc_state.low_write = _LowWrite.OPEN
+
+  def _on_read_event(self, operation_id, event, rpc_state):
+    if event.bytes is None:
+      rpc_state.read = _Read.CLOSED
+    else:
+      if 0 < rpc_state.allowance:
+        rpc_state.allowance -= 1
+        rpc_state.call.read(operation_id)
+      else:
+        rpc_state.read = _Read.AWAITING_ALLOWANCE
+      ticket = links.Ticket(
+          operation_id, rpc_state.sequence_number, None, None, None, None, None,
+          None, rpc_state.response_deserializer(event.bytes), None, None, None,
+          None)
+      rpc_state.sequence_number += 1
+      self._relay.add_value(ticket)
+
+  def _on_metadata_event(self, operation_id, event, rpc_state):
+    rpc_state.allowance -= 1
+    rpc_state.call.read(operation_id)
+    rpc_state.read = _Read.READING
+    ticket = links.Ticket(
+        operation_id, rpc_state.sequence_number, None, None,
+        links.Ticket.Subscription.FULL, None, None, event.metadata, None, None,
+        None, None, None)
+    rpc_state.sequence_number += 1
+    self._relay.add_value(ticket)
+
+  def _on_finish_event(self, operation_id, event, rpc_state):
+    self._rpc_states.pop(operation_id, None)
+    if event.status.code is _intermediary_low.Code.OK:
+      termination = links.Ticket.Termination.COMPLETION
+    elif event.status.code is _intermediary_low.Code.CANCELLED:
+      termination = links.Ticket.Termination.CANCELLATION
+    elif event.status.code is _intermediary_low.Code.DEADLINE_EXCEEDED:
+      termination = links.Ticket.Termination.EXPIRATION
+    else:
+      termination = links.Ticket.Termination.TRANSMISSION_FAILURE
+    ticket = links.Ticket(
+        operation_id, rpc_state.sequence_number, None, None, None, None, None,
+        None, None, event.metadata, event.status.code, event.status.details,
+        termination)
+    rpc_state.sequence_number += 1
+    self._relay.add_value(ticket)
+
+  def _spin(self, completion_queue):
+    while True:
+      event = completion_queue.get(None)
+      if event.kind is _intermediary_low.Event.Kind.STOP:
+        return
+      operation_id = event.tag
+      with self._lock:
+        if self._completion_queue is None:
+          continue
+        rpc_state = self._rpc_states.get(operation_id)
+        if rpc_state is not None:
+          if event.kind is _intermediary_low.Event.Kind.WRITE_ACCEPTED:
+            self._on_write_event(operation_id, event, rpc_state)
+          elif event.kind is _intermediary_low.Event.Kind.METADATA_ACCEPTED:
+            self._on_metadata_event(operation_id, event, rpc_state)
+          elif event.kind is _intermediary_low.Event.Kind.READ_ACCEPTED:
+            self._on_read_event(operation_id, event, rpc_state)
+          elif event.kind is _intermediary_low.Event.Kind.FINISH:
+            self._on_finish_event(operation_id, event, rpc_state)
+          elif event.kind is _intermediary_low.Event.Kind.COMPLETE_ACCEPTED:
+            pass
+          else:
+            logging.error('Illegal RPC event! %s', (event,))
+
+  def _invoke(
+      self, operation_id, group, method, initial_metadata, payload, termination,
+      timeout, allowance):
+    """Invoke an RPC.
+
+    Args:
+      operation_id: Any object to be used as an operation ID for the RPC.
+      group: The group to which the RPC method belongs.
+      method: The RPC method name.
+      initial_metadata: The initial metadata object for the RPC.
+      payload: A payload object for the RPC or None if no payload was given at
+        invocation-time.
+      termination: A links.Ticket.Termination value or None indicated whether or
+        not more writes will follow from this side of the RPC.
+      timeout: A duration of time in seconds to allow for the RPC.
+      allowance: The number of payloads (beyond the free first one) that the
+        local ticket exchange mate has granted permission to be read.
+    """
+    if termination is links.Ticket.Termination.COMPLETION:
+      high_write = _HighWrite.CLOSED
+    elif termination is None:
+      high_write = _HighWrite.OPEN
+    else:
+      return
+
+    request_serializer = self._request_serializers.get((group, method))
+    response_deserializer = self._response_deserializers.get((group, method))
+    if request_serializer is None or response_deserializer is None:
+      cancellation_ticket = links.Ticket(
+          operation_id, 0, None, None, None, None, None, None, None, None, None,
+          None, links.Ticket.Termination.CANCELLATION)
+      self._relay.add_value(cancellation_ticket)
+      return
+
+    call = _intermediary_low.Call(
+        self._channel, self._completion_queue, '/%s/%s' % (group, method),
+        self._host, time.time() + timeout)
+    if initial_metadata is not None:
+      for metadata_key, metadata_value in initial_metadata:
+        call.add_metadata(metadata_key, metadata_value)
+    call.invoke(self._completion_queue, operation_id, operation_id)
+    if payload is None:
+      if high_write is _HighWrite.CLOSED:
+        call.complete(operation_id)
+        low_write = _LowWrite.CLOSED
+      else:
+        low_write = _LowWrite.OPEN
+    else:
+      call.write(request_serializer(payload), operation_id)
+      low_write = _LowWrite.ACTIVE
+    self._rpc_states[operation_id] = _RPCState(
+        call, request_serializer, response_deserializer, 0,
+        _Read.AWAITING_METADATA, 1 if allowance is None else (1 + allowance),
+        high_write, low_write)
+
+  def _advance(self, operation_id, rpc_state, payload, termination, allowance):
+    if payload is not None:
+      rpc_state.call.write(rpc_state.request_serializer(payload), operation_id)
+      rpc_state.low_write = _LowWrite.ACTIVE
+
+    if allowance is not None:
+      if rpc_state.read is _Read.AWAITING_ALLOWANCE:
+        rpc_state.allowance += allowance - 1
+        rpc_state.call.read(operation_id)
+        rpc_state.read = _Read.READING
+      else:
+        rpc_state.allowance += allowance
+
+    if termination is links.Ticket.Termination.COMPLETION:
+      rpc_state.high_write = _HighWrite.CLOSED
+      if rpc_state.low_write is _LowWrite.OPEN:
+        rpc_state.call.complete(operation_id)
+        rpc_state.low_write = _LowWrite.CLOSED
+    elif termination is not None:
+      rpc_state.call.cancel()
+
+  def add_ticket(self, ticket):
+    with self._lock:
+      if self._completion_queue is None:
+        return
+      if ticket.sequence_number == 0:
+        self._invoke(
+            ticket.operation_id, ticket.group, ticket.method,
+            ticket.initial_metadata, ticket.payload, ticket.termination,
+            ticket.timeout, ticket.allowance)
+      else:
+        rpc_state = self._rpc_states.get(ticket.operation_id)
+        if rpc_state is not None:
+          self._advance(
+              ticket.operation_id, rpc_state, ticket.payload,
+              ticket.termination, ticket.allowance)
+
+  def start(self):
+    """Starts this object.
+
+    This method must be called before attempting to exchange tickets with this
+    object.
+    """
+    with self._lock:
+      self._completion_queue = _intermediary_low.CompletionQueue()
+      self._rpc_states = {}
+      self._pool = logging_pool.pool(1)
+      self._pool.submit(self._spin, self._completion_queue)
+
+  def stop(self):
+    """Stops this object.
+
+    This method must be called for proper termination of this object, and no
+    attempts to exchange tickets with this object may be made after this method
+    has been called.
+    """
+    with self._lock:
+      self._completion_queue.stop()
+      self._completion_queue = None
+      pool = self._pool
+      self._pool = None
+      self._rpc_states = None
+    pool.shutdown(wait=True)
+
+
+class InvocationLink(links.Link, activated.Activated):
+  """A links.Link for use on the invocation-side of a gRPC connection.
+
+  Implementations of this interface are only valid for use when activated.
+  """
+  __metaclass__ = abc.ABCMeta
+
+
+class _InvocationLink(InvocationLink):
+
+  def __init__(
+      self, channel, host, request_serializers, response_deserializers):
+    self._relay = relay.relay(None)
+    self._kernel = _Kernel(
+        channel, host, request_serializers, response_deserializers, self._relay)
+
+  def _start(self):
+    self._relay.start()
+    self._kernel.start()
+    return self
+
+  def _stop(self):
+    self._kernel.stop()
+    self._relay.stop()
+
+  def accept_ticket(self, ticket):
+    """See links.Link.accept_ticket for specification."""
+    self._kernel.add_ticket(ticket)
+
+  def join_link(self, link):
+    """See links.Link.join_link for specification."""
+    self._relay.set_behavior(link.accept_ticket)
+
+  def __enter__(self):
+    """See activated.Activated.__enter__ for specification."""
+    return self._start()
+
+  def __exit__(self, exc_type, exc_val, exc_tb):
+    """See activated.Activated.__exit__ for specification."""
+    self._stop()
+    return False
+
+  def start(self):
+    """See activated.Activated.start for specification."""
+    return self._start()
+
+  def stop(self):
+    """See activated.Activated.stop for specification."""
+    self._stop()
+
+
+def invocation_link(channel, host, request_serializers, response_deserializers):
+  """Creates an InvocationLink.
+
+  Args:
+    channel: A channel for use by the link.
+    host: The host to specify when invoking RPCs.
+    request_serializers: A dict from group-method pair to request object
+      serialization behavior.
+    response_deserializers: A dict from group-method pair to response object
+      deserialization behavior.
+
+  Returns:
+    An InvocationLink.
+  """
+  return _InvocationLink(
+      channel, host, request_serializers, response_deserializers)
diff --git a/src/python/src/grpc/_links/service.py b/src/python/src/grpc/_links/service.py
new file mode 100644
index 0000000..7783e91
--- /dev/null
+++ b/src/python/src/grpc/_links/service.py
@@ -0,0 +1,402 @@
+# 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.
+
+"""The RPC-service-side bridge between RPC Framework and GRPC-on-the-wire."""
+
+import abc
+import enum
+import logging
+import threading
+import time
+
+from grpc._adapter import _intermediary_low
+from grpc.framework.foundation import logging_pool
+from grpc.framework.foundation import relay
+from grpc.framework.interfaces.links import links
+
+
+@enum.unique
+class _Read(enum.Enum):
+  READING = 'reading'
+  AWAITING_ALLOWANCE = 'awaiting allowance'
+  CLOSED = 'closed'
+
+
+@enum.unique
+class _HighWrite(enum.Enum):
+  OPEN = 'open'
+  CLOSED = 'closed'
+
+
+@enum.unique
+class _LowWrite(enum.Enum):
+  """The possible categories of low-level write state."""
+
+  OPEN = 'OPEN'
+  ACTIVE = 'ACTIVE'
+  CLOSED = 'CLOSED'
+
+
+class _RPCState(object):
+
+  def __init__(
+      self, request_deserializer, response_serializer, sequence_number, read,
+      allowance, high_write, low_write, premetadataed, terminal_metadata, code,
+      message):
+    self.request_deserializer = request_deserializer
+    self.response_serializer = response_serializer
+    self.sequence_number = sequence_number
+    self.read = read
+    self.allowance = allowance
+    self.high_write = high_write
+    self.low_write = low_write
+    self.premetadataed = premetadataed
+    self.terminal_metadata = terminal_metadata
+    self.code = code
+    self.message = message
+
+
+def _metadatafy(call, metadata):
+  for metadata_key, metadata_value in metadata:
+    call.add_metadata(metadata_key, metadata_value)
+
+
+class _Kernel(object):
+
+  def __init__(self, request_deserializers, response_serializers, ticket_relay):
+    self._lock = threading.Lock()
+    self._request_deserializers = request_deserializers
+    self._response_serializers = response_serializers
+    self._relay = ticket_relay
+
+    self._completion_queue = None
+    self._server = None
+    self._rpc_states = {}
+    self._pool = None
+
+  def _on_service_acceptance_event(self, event, server):
+    server.service(None)
+
+    service_acceptance = event.service_acceptance
+    call = service_acceptance.call
+    call.accept(self._completion_queue, call)
+    try:
+      group, method = service_acceptance.method.split('/')[1:3]
+    except ValueError:
+      logging.info('Illegal path "%s"!', service_acceptance.method)
+      return
+    request_deserializer = self._request_deserializers.get((group, method))
+    response_serializer = self._response_serializers.get((group, method))
+    if request_deserializer is None or response_serializer is None:
+      # TODO(nathaniel): Terminate the RPC with code NOT_FOUND.
+      call.cancel()
+      return
+
+    call.read(call)
+    self._rpc_states[call] = _RPCState(
+        request_deserializer, response_serializer, 1, _Read.READING, 0,
+        _HighWrite.OPEN, _LowWrite.OPEN, False, None, None, None)
+    ticket = links.Ticket(
+        call, 0, group, method, links.Ticket.Subscription.FULL,
+        service_acceptance.deadline - time.time(), None, event.metadata, None,
+        None, None, None, None)
+    self._relay.add_value(ticket)
+
+  def _on_read_event(self, event):
+    call = event.tag
+    rpc_state = self._rpc_states.get(call, None)
+    if rpc_state is None:
+      return
+
+    if event.bytes is None:
+      rpc_state.read = _Read.CLOSED
+      payload = None
+      termination = links.Ticket.Termination.COMPLETION
+    else:
+      if 0 < rpc_state.allowance:
+        rpc_state.allowance -= 1
+        call.read(call)
+      else:
+        rpc_state.read = _Read.AWAITING_ALLOWANCE
+      payload = rpc_state.request_deserializer(event.bytes)
+      termination = None
+    ticket = links.Ticket(
+        call, rpc_state.sequence_number, None, None, None, None, None, None,
+        payload, None, None, None, termination)
+    rpc_state.sequence_number += 1
+    self._relay.add_value(ticket)
+
+  def _on_write_event(self, event):
+    call = event.tag
+    rpc_state = self._rpc_states.get(call, None)
+    if rpc_state is None:
+      return
+
+    if rpc_state.high_write is _HighWrite.CLOSED:
+      if rpc_state.terminal_metadata is not None:
+        _metadatafy(call, rpc_state.terminal_metadata)
+      call.status(
+          _intermediary_low.Status(rpc_state.code, rpc_state.message), call)
+      rpc_state.low_write = _LowWrite.CLOSED
+    else:
+      ticket = links.Ticket(
+          call, rpc_state.sequence_number, None, None, None, None, 1, None,
+          None, None, None, None, None)
+      rpc_state.sequence_number += 1
+      self._relay.add_value(ticket)
+      rpc_state.low_write = _LowWrite.OPEN
+
+  def _on_finish_event(self, event):
+    call = event.tag
+    rpc_state = self._rpc_states.pop(call, None)
+    if rpc_state is None:
+      return
+    code = event.status.code
+    if code is _intermediary_low.Code.OK:
+      return
+
+    if code is _intermediary_low.Code.CANCELLED:
+      termination = links.Ticket.Termination.CANCELLATION
+    elif code is _intermediary_low.Code.DEADLINE_EXCEEDED:
+      termination = links.Ticket.Termination.EXPIRATION
+    else:
+      termination = links.Ticket.Termination.TRANSMISSION_FAILURE
+    ticket = links.Ticket(
+        call, rpc_state.sequence_number, None, None, None, None, None, None,
+        None, None, None, None, termination)
+    rpc_state.sequence_number += 1
+    self._relay.add_value(ticket)
+
+  def _spin(self, completion_queue, server):
+    while True:
+      event = completion_queue.get(None)
+      if event.kind is _intermediary_low.Event.Kind.STOP:
+        return
+      with self._lock:
+        if self._server is None:
+          continue
+        elif event.kind is _intermediary_low.Event.Kind.SERVICE_ACCEPTED:
+          self._on_service_acceptance_event(event, server)
+        elif event.kind is _intermediary_low.Event.Kind.READ_ACCEPTED:
+          self._on_read_event(event)
+        elif event.kind is _intermediary_low.Event.Kind.WRITE_ACCEPTED:
+          self._on_write_event(event)
+        elif event.kind is _intermediary_low.Event.Kind.COMPLETE_ACCEPTED:
+          pass
+        elif event.kind is _intermediary_low.Event.Kind.FINISH:
+          self._on_finish_event(event)
+        else:
+          logging.error('Illegal event! %s', (event,))
+
+  def add_ticket(self, ticket):
+    with self._lock:
+      if self._server is None:
+        return
+      call = ticket.operation_id
+      rpc_state = self._rpc_states.get(call)
+      if rpc_state is None:
+        return
+
+      if ticket.initial_metadata is not None:
+        _metadatafy(call, ticket.initial_metadata)
+        call.premetadata()
+        rpc_state.premetadataed = True
+      elif not rpc_state.premetadataed:
+        if (ticket.terminal_metadata is not None or
+            ticket.payload is not None or
+            ticket.termination is links.Ticket.Termination.COMPLETION or
+            ticket.code is not None or
+            ticket.message is not None):
+          call.premetadata()
+          rpc_state.premetadataed = True
+
+      if ticket.allowance is not None:
+        if rpc_state.read is _Read.AWAITING_ALLOWANCE:
+          rpc_state.allowance += ticket.allowance - 1
+          call.read(call)
+          rpc_state.read = _Read.READING
+        else:
+          rpc_state.allowance += ticket.allowance
+
+      if ticket.payload is not None:
+        call.write(rpc_state.response_serializer(ticket.payload), call)
+        rpc_state.low_write = _LowWrite.ACTIVE
+
+      if ticket.terminal_metadata is not None:
+        rpc_state.terminal_metadata = ticket.terminal_metadata
+      if ticket.code is not None:
+        rpc_state.code = ticket.code
+      if ticket.message is not None:
+        rpc_state.message = ticket.message
+
+      if ticket.termination is links.Ticket.Termination.COMPLETION:
+        rpc_state.high_write = _HighWrite.CLOSED
+        if rpc_state.low_write is _LowWrite.OPEN:
+          if rpc_state.terminal_metadata is not None:
+            _metadatafy(call, rpc_state.terminal_metadata)
+          status = _intermediary_low.Status(
+              _intermediary_low.Code.OK
+              if rpc_state.code is None else rpc_state.code,
+              '' if rpc_state.message is None else rpc_state.message)
+          call.status(status, call)
+          rpc_state.low_write = _LowWrite.CLOSED
+      elif ticket.termination is not None:
+        call.cancel()
+        self._rpc_states.pop(call, None)
+
+  def add_port(self, port, server_credentials):
+    with self._lock:
+      address = '[::]:%d' % port
+      if self._server is None:
+        self._completion_queue = _intermediary_low.CompletionQueue()
+        self._server = _intermediary_low.Server(self._completion_queue)
+      if server_credentials is None:
+        return self._server.add_http2_addr(address)
+      else:
+        return self._server.add_secure_http2_addr(address, server_credentials)
+
+  def start(self):
+    with self._lock:
+      if self._server is None:
+        self._completion_queue = _intermediary_low.CompletionQueue()
+        self._server = _intermediary_low.Server(self._completion_queue)
+      self._pool = logging_pool.pool(1)
+      self._pool.submit(self._spin, self._completion_queue, self._server)
+      self._server.start()
+      self._server.service(None)
+
+  def graceful_stop(self):
+    with self._lock:
+      self._server.stop()
+      self._server = None
+      self._completion_queue.stop()
+      self._completion_queue = None
+      pool = self._pool
+      self._pool = None
+      self._rpc_states = None
+    pool.shutdown(wait=True)
+
+  def immediate_stop(self):
+    # TODO(nathaniel): Implementation.
+    raise NotImplementedError(
+        'TODO(nathaniel): after merge of rewritten lower layers')
+
+
+class ServiceLink(links.Link):
+  """A links.Link for use on the service-side of a gRPC connection.
+
+  Implementations of this interface are only valid for use between calls to
+  their start method and one of their stop methods.
+  """
+
+  @abc.abstractmethod
+  def add_port(self, port, server_credentials):
+    """Adds a port on which to service RPCs after this link has been started.
+
+    Args:
+      port: The port on which to service RPCs, or zero to request that a port be
+        automatically selected and used.
+      server_credentials: A ServerCredentials object, or None for insecure
+        service.
+
+    Returns:
+      A port on which RPCs will be serviced after this link has been started.
+    """
+    raise NotImplementedError()
+
+  @abc.abstractmethod
+  def start(self):
+    """Starts this object.
+
+    This method must be called before attempting to use this Link in ticket
+    exchange.
+    """
+    raise NotImplementedError()
+
+  @abc.abstractmethod
+  def stop_gracefully(self):
+    """Stops this link.
+
+    New RPCs will be rejected as soon as this method is called, but ongoing RPCs
+    will be allowed to continue until they terminate. This method blocks until
+    all RPCs have terminated.
+    """
+    raise NotImplementedError()
+
+  @abc.abstractmethod
+  def stop_immediately(self):
+    """Stops this link.
+
+    All in-progress RPCs will be terminated immediately.
+    """
+    raise NotImplementedError()
+
+
+class _ServiceLink(ServiceLink):
+
+  def __init__(self, request_deserializers, response_serializers):
+    self._relay = relay.relay(None)
+    self._kernel = _Kernel(
+        request_deserializers, response_serializers, self._relay)
+
+  def accept_ticket(self, ticket):
+    self._kernel.add_ticket(ticket)
+
+  def join_link(self, link):
+    self._relay.set_behavior(link.accept_ticket)
+
+  def add_port(self, port, server_credentials):
+    return self._kernel.add_port(port, server_credentials)
+
+  def start(self):
+    self._relay.start()
+    return self._kernel.start()
+
+  def stop_gracefully(self):
+    self._kernel.graceful_stop()
+    self._relay.stop()
+
+  def stop_immediately(self):
+    self._kernel.immediate_stop()
+    self._relay.stop()
+
+
+def service_link(request_deserializers, response_serializers):
+  """Creates a ServiceLink.
+
+  Args:
+    request_deserializers: A dict from group-method pair to request object
+      deserialization behavior.
+    response_serializers: A dict from group-method pair to response ojbect
+      serialization behavior.
+
+  Returns:
+    A ServiceLink.
+  """
+  return _ServiceLink(request_deserializers, response_serializers)
diff --git a/src/python/src/grpc/framework/common/test_constants.py b/src/python/src/grpc/framework/common/test_constants.py
new file mode 100644
index 0000000..237b875
--- /dev/null
+++ b/src/python/src/grpc/framework/common/test_constants.py
@@ -0,0 +1,37 @@
+# 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.
+
+"""Constants shared among tests throughout RPC Framework."""
+
+# Value for maximum duration in seconds of RPCs that may time out as part of a
+# test.
+SHORT_TIMEOUT = 4
+# Absurdly large value for maximum duration in seconds for should-not-time-out
+# RPCs made during tests.
+LONG_TIMEOUT = 3000
diff --git a/src/python/src/grpc/framework/common/test_control.py b/src/python/src/grpc/framework/common/test_control.py
new file mode 100644
index 0000000..3960c4e
--- /dev/null
+++ b/src/python/src/grpc/framework/common/test_control.py
@@ -0,0 +1,87 @@
+# 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.
+
+"""Code for instructing systems under test to block or fail."""
+
+import abc
+import contextlib
+import threading
+
+
+class Control(object):
+  """An object that accepts program control from a system under test.
+
+  Systems under test passed a Control should call its control() method
+  frequently during execution. The control() method may block, raise an
+  exception, or do nothing, all according to the enclosing test's desire for
+  the system under test to simulate hanging, failing, or functioning.
+  """
+
+  __metaclass__ = abc.ABCMeta
+
+  @abc.abstractmethod
+  def control(self):
+    """Potentially does anything."""
+    raise NotImplementedError()
+
+
+class PauseFailControl(Control):
+  """A Control that can be used to pause or fail code under control."""
+
+  def __init__(self):
+    self._condition = threading.Condition()
+    self._paused = False
+    self._fail = False
+
+  def control(self):
+    with self._condition:
+      if self._fail:
+        raise ValueError()
+
+      while self._paused:
+        self._condition.wait()
+
+  @contextlib.contextmanager
+  def pause(self):
+    """Pauses code under control while controlling code is in context."""
+    with self._condition:
+      self._paused = True
+    yield
+    with self._condition:
+      self._paused = False
+      self._condition.notify_all()
+
+  @contextlib.contextmanager
+  def fail(self):
+    """Fails code under control while controlling code is in context."""
+    with self._condition:
+      self._fail = True
+    yield
+    with self._condition:
+      self._fail = False
diff --git a/src/python/src/grpc/framework/common/test_coverage.py b/src/python/src/grpc/framework/common/test_coverage.py
new file mode 100644
index 0000000..a7ed358
--- /dev/null
+++ b/src/python/src/grpc/framework/common/test_coverage.py
@@ -0,0 +1,116 @@
+# 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.
+
+"""Governs coverage for tests of RPCs throughout RPC Framework."""
+
+import abc
+
+# This code is designed for use with the unittest module.
+# pylint: disable=invalid-name
+
+
+class Coverage(object):
+  """Specification of test coverage."""
+  __metaclass__ = abc.ABCMeta
+
+  @abc.abstractmethod
+  def testSuccessfulUnaryRequestUnaryResponse(self):
+    raise NotImplementedError()
+
+  @abc.abstractmethod
+  def testSuccessfulUnaryRequestStreamResponse(self):
+    raise NotImplementedError()
+
+  @abc.abstractmethod
+  def testSuccessfulStreamRequestUnaryResponse(self):
+    raise NotImplementedError()
+
+  @abc.abstractmethod
+  def testSuccessfulStreamRequestStreamResponse(self):
+    raise NotImplementedError()
+
+  @abc.abstractmethod
+  def testSequentialInvocations(self):
+    raise NotImplementedError()
+
+  @abc.abstractmethod
+  def testParallelInvocations(self):
+    raise NotImplementedError()
+
+  @abc.abstractmethod
+  def testWaitingForSomeButNotAllParallelInvocations(self):
+    raise NotImplementedError()
+
+  @abc.abstractmethod
+  def testCancelledUnaryRequestUnaryResponse(self):
+    raise NotImplementedError()
+
+  @abc.abstractmethod
+  def testCancelledUnaryRequestStreamResponse(self):
+    raise NotImplementedError()
+
+  @abc.abstractmethod
+  def testCancelledStreamRequestUnaryResponse(self):
+    raise NotImplementedError()
+
+  @abc.abstractmethod
+  def testCancelledStreamRequestStreamResponse(self):
+    raise NotImplementedError()
+
+  @abc.abstractmethod
+  def testExpiredUnaryRequestUnaryResponse(self):
+    raise NotImplementedError()
+
+  @abc.abstractmethod
+  def testExpiredUnaryRequestStreamResponse(self):
+    raise NotImplementedError()
+
+  @abc.abstractmethod
+  def testExpiredStreamRequestUnaryResponse(self):
+    raise NotImplementedError()
+
+  @abc.abstractmethod
+  def testExpiredStreamRequestStreamResponse(self):
+    raise NotImplementedError()
+
+  @abc.abstractmethod
+  def testFailedUnaryRequestUnaryResponse(self):
+    raise NotImplementedError()
+
+  @abc.abstractmethod
+  def testFailedUnaryRequestStreamResponse(self):
+    raise NotImplementedError()
+
+  @abc.abstractmethod
+  def testFailedStreamRequestUnaryResponse(self):
+    raise NotImplementedError()
+
+  @abc.abstractmethod
+  def testFailedStreamRequestStreamResponse(self):
+    raise NotImplementedError()
diff --git a/src/python/src/grpc/framework/foundation/relay.py b/src/python/src/grpc/framework/foundation/relay.py
new file mode 100644
index 0000000..9c23946
--- /dev/null
+++ b/src/python/src/grpc/framework/foundation/relay.py
@@ -0,0 +1,175 @@
+# 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.
+
+"""Implementations of in-order work deference."""
+
+import abc
+import enum
+import threading
+
+from grpc.framework.foundation import activated
+from grpc.framework.foundation import logging_pool
+
+_NULL_BEHAVIOR = lambda unused_value: None
+
+
+class Relay(object):
+  """Performs work submitted to it in another thread.
+
+  Performs work in the order in which work was submitted to it; otherwise there
+  would be no reason to use an implementation of this interface instead of a
+  thread pool.
+  """
+  __metaclass__ = abc.ABCMeta
+
+  @abc.abstractmethod
+  def add_value(self, value):
+    """Adds a value to be passed to the behavior registered with this Relay.
+
+    Args:
+      value: A value that will be passed to a call made in another thread to the
+        behavior registered with this Relay.
+    """
+    raise NotImplementedError()
+
+  @abc.abstractmethod
+  def set_behavior(self, behavior):
+    """Sets the behavior that this Relay should call when passed values.
+
+    Args:
+      behavior: The behavior that this Relay should call in another thread when
+        passed a value, or None to have passed values ignored.
+    """
+    raise NotImplementedError()
+
+
+class _PoolRelay(activated.Activated, Relay):
+
+  @enum.unique
+  class _State(enum.Enum):
+    INACTIVE = 'inactive'
+    IDLE = 'idle'
+    SPINNING = 'spinning'
+
+  def __init__(self, pool, behavior):
+    self._condition = threading.Condition()
+    self._pool = pool
+    self._own_pool = pool is None
+    self._state = _PoolRelay._State.INACTIVE
+    self._activated = False
+    self._spinning = False
+    self._values = []
+    self._behavior = _NULL_BEHAVIOR if behavior is None else behavior
+
+  def _spin(self, behavior, value):
+    while True:
+      behavior(value)
+      with self._condition:
+        if self._values:
+          value = self._values.pop(0)
+          behavior = self._behavior
+        else:
+          self._state = _PoolRelay._State.IDLE
+          self._condition.notify_all()
+          break
+
+  def add_value(self, value):
+    with self._condition:
+      if self._state is _PoolRelay._State.INACTIVE:
+        raise ValueError('add_value not valid on inactive Relay!')
+      elif self._state is _PoolRelay._State.IDLE:
+        self._pool.submit(self._spin, self._behavior, value)
+        self._state = _PoolRelay._State.SPINNING
+      else:
+        self._values.append(value)
+
+  def set_behavior(self, behavior):
+    with self._condition:
+      self._behavior = _NULL_BEHAVIOR if behavior is None else behavior
+
+  def _start(self):
+    with self._condition:
+      self._state = _PoolRelay._State.IDLE
+      if self._own_pool:
+        self._pool = logging_pool.pool(1)
+      return self
+
+  def _stop(self):
+    with self._condition:
+      while self._state is _PoolRelay._State.SPINNING:
+        self._condition.wait()
+      if self._own_pool:
+        self._pool.shutdown(wait=True)
+      self._state = _PoolRelay._State.INACTIVE
+
+  def __enter__(self):
+    return self._start()
+
+  def __exit__(self, exc_type, exc_val, exc_tb):
+    self._stop()
+    return False
+
+  def start(self):
+    return self._start()
+
+  def stop(self):
+    self._stop()
+
+
+def relay(behavior):
+  """Creates a Relay.
+
+  Args:
+    behavior: The behavior to be called by the created Relay, or None to have
+      passed values dropped until a different behavior is given to the returned
+      Relay later.
+
+  Returns:
+    An object that is both an activated.Activated and a Relay. The object is
+      only valid for use as a Relay when activated.
+  """
+  return _PoolRelay(None, behavior)
+
+
+def pool_relay(pool, behavior):
+  """Creates a Relay that uses a given thread pool.
+
+  This object will make use of at most one thread in the given pool.
+
+  Args:
+    pool: A futures.ThreadPoolExecutor for use by the created Relay.
+    behavior: The behavior to be called by the created Relay, or None to have
+      passed values dropped until a different behavior is given to the returned
+      Relay later.
+
+  Returns:
+    An object that is both an activated.Activated and a Relay. The object is
+      only valid for use as a Relay when activated.
+  """
+  return _PoolRelay(pool, behavior)
diff --git a/src/python/src/grpc/framework/interfaces/__init__.py b/src/python/src/grpc/framework/interfaces/__init__.py
new file mode 100644
index 0000000..7086519
--- /dev/null
+++ b/src/python/src/grpc/framework/interfaces/__init__.py
@@ -0,0 +1,30 @@
+# 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.
+
+
diff --git a/src/python/src/grpc/framework/interfaces/links/__init__.py b/src/python/src/grpc/framework/interfaces/links/__init__.py
new file mode 100644
index 0000000..7086519
--- /dev/null
+++ b/src/python/src/grpc/framework/interfaces/links/__init__.py
@@ -0,0 +1,30 @@
+# 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.
+
+
diff --git a/src/python/src/grpc/framework/interfaces/links/links.py b/src/python/src/grpc/framework/interfaces/links/links.py
new file mode 100644
index 0000000..5ebbac8
--- /dev/null
+++ b/src/python/src/grpc/framework/interfaces/links/links.py
@@ -0,0 +1,124 @@
+# 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.
+
+"""The low-level ticket-exchanging-links interface of RPC Framework."""
+
+import abc
+import collections
+import enum
+
+
+class Ticket(
+    collections.namedtuple(
+        'Ticket',
+        ['operation_id', 'sequence_number', 'group', 'method', 'subscription',
+         'timeout', 'allowance', 'initial_metadata', 'payload',
+         'terminal_metadata', 'code', 'message', 'termination'])):
+  """A sum type for all values sent from a front to a back.
+
+  Attributes:
+    operation_id: A unique-with-respect-to-equality hashable object identifying
+      a particular operation.
+    sequence_number: A zero-indexed integer sequence number identifying the
+      ticket's place in the stream of tickets sent in one direction for the
+      particular operation.
+    group: The group to which the method of the operation belongs. Must be
+      present in the first ticket from invocation side to service side. Ignored
+      for all other tickets exchanged during the operation.
+    method: The name of an operation. Must be present in the first ticket from
+      invocation side to service side. Ignored for all other tickets exchanged
+      during the operation.
+    subscription: A Subscription value describing the interest one side has in
+      receiving information from the other side. Must be present in the first
+      ticket from either side. Ignored for all other tickets exchanged during
+      the operation.
+    timeout: A nonzero length of time (measured from the beginning of the
+      operation) to allow for the entire operation. Must be present in the first
+      ticket from invocation side to service side. Optional for all other
+      tickets exchanged during the operation. Receipt of a value from the other
+      side of the operation indicates the value in use by that side. Setting a
+      value on a later ticket allows either side to request time extensions (or
+      even time reductions!) on in-progress operations.
+    allowance: A positive integer granting permission for a number of payloads
+      to be transmitted to the communicating side of the operation, or None if
+      no additional allowance is being granted with this ticket.
+    initial_metadata: An optional metadata value communicated from one side to
+      the other at the beginning of the operation. May be non-None in at most
+      one ticket from each side. Any non-None value must appear no later than
+      the first payload value.
+    payload: A customer payload object. May be None.
+    terminal_metadata: A metadata value comminicated from one side to the other
+      at the end of the operation. May be non-None in the same ticket as
+      the code and message, but must be None for all earlier tickets.
+    code: A value communicated at operation completion. May be None.
+    message: A value communicated at operation completion. May be None.
+    termination: A Termination value describing the end of the operation, or
+      None if the operation has not yet terminated. If set, no further tickets
+      may be sent in the same direction.
+  """
+
+  @enum.unique
+  class Subscription(enum.Enum):
+    """Identifies the level of subscription of a side of an operation."""
+
+    NONE = 'none'
+    TERMINATION = 'termination'
+    FULL = 'full'
+
+  @enum.unique
+  class Termination(enum.Enum):
+    """Identifies the termination of an operation."""
+
+    COMPLETION = 'completion'
+    CANCELLATION = 'cancellation'
+    EXPIRATION = 'expiration'
+    LOCAL_SHUTDOWN = 'local shutdown'
+    RECEPTION_FAILURE = 'reception failure'
+    TRANSMISSION_FAILURE = 'transmission failure'
+    LOCAL_FAILURE = 'local failure'
+    REMOTE_FAILURE = 'remote failure'
+
+
+class Link(object):
+  """Accepts and emits tickets."""
+  __metaclass__ = abc.ABCMeta
+
+  @abc.abstractmethod
+  def accept_ticket(self, ticket):
+    """Accept a Ticket.
+
+    Args:
+      ticket: Any Ticket.
+    """
+    raise NotImplementedError()
+
+  @abc.abstractmethod
+  def join_link(self, link):
+    """Mates this object with a peer with which it will exchange tickets."""
+    raise NotImplementedError()
diff --git a/src/python/src/grpc/framework/interfaces/links/test_cases.py b/src/python/src/grpc/framework/interfaces/links/test_cases.py
new file mode 100644
index 0000000..3ac212e
--- /dev/null
+++ b/src/python/src/grpc/framework/interfaces/links/test_cases.py
@@ -0,0 +1,332 @@
+# 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.
+
+"""Tests of the links interface of RPC Framework."""
+
+# unittest is referenced from specification in this module.
+import abc
+import unittest  # pylint: disable=unused-import
+
+from grpc.framework.common import test_constants
+from grpc.framework.interfaces.links import links
+from grpc.framework.interfaces.links import test_utilities
+
+
+def at_least_n_payloads_received_predicate(n):
+  def predicate(ticket_sequence):
+    payload_count = 0
+    for ticket in ticket_sequence:
+      if ticket.payload is not None:
+        payload_count += 1
+        if n <= payload_count:
+          return True
+    else:
+      return False
+  return predicate
+
+
+def terminated(ticket_sequence):
+  return ticket_sequence and ticket_sequence[-1].termination is not None
+
+_TRANSMISSION_GROUP = 'test.Group'
+_TRANSMISSION_METHOD = 'TestMethod'
+
+
+class TransmissionTest(object):
+  """Tests ticket transmission between two connected links.
+
+  This class must be mixed into a unittest.TestCase that implements the abstract
+  methods it provides.
+  """
+  __metaclass__ = abc.ABCMeta
+
+  # This is a unittest.TestCase mix-in.
+  # pylint: disable=invalid-name
+
+  @abc.abstractmethod
+  def create_transmitting_links(self):
+    """Creates two connected links for use in this test.
+
+    Returns:
+      Two links.Links, the first of which will be used on the invocation side
+        of RPCs and the second of which will be used on the service side of
+        RPCs.
+    """
+    raise NotImplementedError()
+
+  @abc.abstractmethod
+  def destroy_transmitting_links(self, invocation_side_link, service_side_link):
+    """Destroys the two connected links created for this test.
+
+
+    Args:
+      invocation_side_link: The link used on the invocation side of RPCs in
+        this test.
+      service_side_link: The link used on the service side of RPCs in this
+        test.
+    """
+    raise NotImplementedError()
+
+  @abc.abstractmethod
+  def create_invocation_initial_metadata(self):
+    """Creates a value for use as invocation-side initial metadata.
+
+    Returns:
+      A metadata value appropriate for use as invocation-side initial metadata
+        or None if invocation-side initial metadata transmission is not
+        supported by the links under test.
+    """
+    raise NotImplementedError()
+
+  @abc.abstractmethod
+  def create_invocation_terminal_metadata(self):
+    """Creates a value for use as invocation-side terminal metadata.
+
+    Returns:
+      A metadata value appropriate for use as invocation-side terminal
+        metadata or None if invocation-side terminal metadata transmission is
+        not supported by the links under test.
+    """
+    raise NotImplementedError()
+
+  @abc.abstractmethod
+  def create_service_initial_metadata(self):
+    """Creates a value for use as service-side initial metadata.
+
+    Returns:
+      A metadata value appropriate for use as service-side initial metadata or
+        None if service-side initial metadata transmission is not supported by
+        the links under test.
+    """
+    raise NotImplementedError()
+
+  @abc.abstractmethod
+  def create_service_terminal_metadata(self):
+    """Creates a value for use as service-side terminal metadata.
+
+    Returns:
+      A metadata value appropriate for use as service-side terminal metadata or
+        None if service-side terminal metadata transmission is not supported by
+        the links under test.
+    """
+    raise NotImplementedError()
+
+  @abc.abstractmethod
+  def create_invocation_completion(self):
+    """Creates values for use as invocation-side code and message.
+
+    Returns:
+      An invocation-side code value and an invocation-side message value.
+        Either or both may be None if invocation-side code and/or
+        invocation-side message transmission is not supported by the links
+        under test.
+    """
+    raise NotImplementedError()
+
+  @abc.abstractmethod
+  def create_service_completion(self):
+    """Creates values for use as service-side code and message.
+
+    Returns:
+      A service-side code value and a service-side message value. Either or
+        both may be None if service-side code and/or service-side message
+        transmission is not supported by the links under test.
+    """
+    raise NotImplementedError()
+
+  @abc.abstractmethod
+  def assertMetadataEqual(self, original_metadata, transmitted_metadata):
+    """Asserts that two metadata objects are equal.
+
+    Args:
+      original_metadata: A metadata object used in this test.
+      transmitted_metadata: A metadata object obtained after transmission
+        through the system under test.
+
+    Raises:
+      AssertionError: if the two metadata objects are not equal.
+    """
+    raise NotImplementedError()
+
+  def group_and_method(self):
+    """Returns the group and method used in this test case.
+
+    Returns:
+      A pair of the group and method used in this test case.
+    """
+    return _TRANSMISSION_GROUP, _TRANSMISSION_METHOD
+
+  def serialize_request(self, request):
+    """Serializes a request value used in this test case.
+
+    Args:
+      request: A request value created by this test case.
+
+    Returns:
+      A bytestring that is the serialization of the given request.
+    """
+    return request
+
+  def deserialize_request(self, serialized_request):
+    """Deserializes a request value used in this test case.
+
+    Args:
+      serialized_request: A bytestring that is the serialization of some request
+        used in this test case.
+
+    Returns:
+      The request value encoded by the given bytestring.
+    """
+    return serialized_request
+
+  def serialize_response(self, response):
+    """Serializes a response value used in this test case.
+
+    Args:
+      response: A response value created by this test case.
+
+    Returns:
+      A bytestring that is the serialization of the given response.
+    """
+    return response
+
+  def deserialize_response(self, serialized_response):
+    """Deserializes a response value used in this test case.
+
+    Args:
+      serialized_response: A bytestring that is the serialization of some
+        response used in this test case.
+
+    Returns:
+      The response value encoded by the given bytestring.
+    """
+    return serialized_response
+
+  def _assert_is_valid_metadata_payload_sequence(
+      self, ticket_sequence, payloads, initial_metadata, terminal_metadata):
+    initial_metadata_seen = False
+    seen_payloads = []
+    terminal_metadata_seen = False
+
+    for ticket in ticket_sequence:
+      if ticket.initial_metadata is not None:
+        self.assertFalse(initial_metadata_seen)
+        self.assertFalse(seen_payloads)
+        self.assertFalse(terminal_metadata_seen)
+        self.assertMetadataEqual(initial_metadata, ticket.initial_metadata)
+        initial_metadata_seen = True
+
+      if ticket.payload is not None:
+        self.assertFalse(terminal_metadata_seen)
+        seen_payloads.append(ticket.payload)
+
+      if ticket.terminal_metadata is not None:
+        self.assertFalse(terminal_metadata_seen)
+        self.assertMetadataEqual(terminal_metadata, ticket.terminal_metadata)
+        terminal_metadata_seen = True
+    self.assertSequenceEqual(payloads, seen_payloads)
+
+  def _assert_is_valid_invocation_sequence(
+      self, ticket_sequence, group, method, payloads, initial_metadata,
+      terminal_metadata, termination):
+    self.assertLess(0, len(ticket_sequence))
+    self.assertEqual(group, ticket_sequence[0].group)
+    self.assertEqual(method, ticket_sequence[0].method)
+    self._assert_is_valid_metadata_payload_sequence(
+        ticket_sequence, payloads, initial_metadata, terminal_metadata)
+    self.assertIs(termination, ticket_sequence[-1].termination)
+
+  def _assert_is_valid_service_sequence(
+      self, ticket_sequence, payloads, initial_metadata, terminal_metadata,
+      code, message, termination):
+    self.assertLess(0, len(ticket_sequence))
+    self._assert_is_valid_metadata_payload_sequence(
+        ticket_sequence, payloads, initial_metadata, terminal_metadata)
+    self.assertEqual(code, ticket_sequence[-1].code)
+    self.assertEqual(message, ticket_sequence[-1].message)
+    self.assertIs(termination, ticket_sequence[-1].termination)
+
+  def setUp(self):
+    self._invocation_link, self._service_link = self.create_transmitting_links()
+    self._invocation_mate = test_utilities.RecordingLink()
+    self._service_mate = test_utilities.RecordingLink()
+    self._invocation_link.join_link(self._invocation_mate)
+    self._service_link.join_link(self._service_mate)
+
+  def tearDown(self):
+    self.destroy_transmitting_links(self._invocation_link, self._service_link)
+
+  def testSimplestRoundTrip(self):
+    """Tests transmission of one ticket in each direction."""
+    invocation_operation_id = object()
+    invocation_payload = b'\x07' * 1023
+    timeout = test_constants.LONG_TIMEOUT
+    invocation_initial_metadata = self.create_invocation_initial_metadata()
+    invocation_terminal_metadata = self.create_invocation_terminal_metadata()
+    invocation_code, invocation_message = self.create_invocation_completion()
+    service_payload = b'\x08' * 1025
+    service_initial_metadata = self.create_service_initial_metadata()
+    service_terminal_metadata = self.create_service_terminal_metadata()
+    service_code, service_message = self.create_service_completion()
+
+    original_invocation_ticket = links.Ticket(
+        invocation_operation_id, 0, _TRANSMISSION_GROUP, _TRANSMISSION_METHOD,
+        links.Ticket.Subscription.FULL, timeout, 0, invocation_initial_metadata,
+        invocation_payload, invocation_terminal_metadata, invocation_code,
+        invocation_message, links.Ticket.Termination.COMPLETION)
+    self._invocation_link.accept_ticket(original_invocation_ticket)
+
+    # TODO(nathaniel): This shouldn't be necessary. Detecting the end of the
+    # invocation-side ticket sequence shouldn't require granting allowance for
+    # another payload.
+    self._service_mate.block_until_tickets_satisfy(
+        at_least_n_payloads_received_predicate(1))
+    service_operation_id = self._service_mate.tickets()[0].operation_id
+    self._service_link.accept_ticket(
+        links.Ticket(
+            service_operation_id, 0, None, None, links.Ticket.Subscription.FULL,
+            None, 1, None, None, None, None, None, None))
+
+    self._service_mate.block_until_tickets_satisfy(terminated)
+    self._assert_is_valid_invocation_sequence(
+        self._service_mate.tickets(), _TRANSMISSION_GROUP, _TRANSMISSION_METHOD,
+        (invocation_payload,), invocation_initial_metadata,
+        invocation_terminal_metadata, links.Ticket.Termination.COMPLETION)
+
+    original_service_ticket = links.Ticket(
+        service_operation_id, 1, None, None, links.Ticket.Subscription.FULL,
+        timeout, 0, service_initial_metadata, service_payload,
+        service_terminal_metadata, service_code, service_message,
+        links.Ticket.Termination.COMPLETION)
+    self._service_link.accept_ticket(original_service_ticket)
+    self._invocation_mate.block_until_tickets_satisfy(terminated)
+    self._assert_is_valid_service_sequence(
+        self._invocation_mate.tickets(), (service_payload,),
+        service_initial_metadata, service_terminal_metadata, service_code,
+        service_message, links.Ticket.Termination.COMPLETION)
diff --git a/src/python/src/grpc/framework/interfaces/links/test_utilities.py b/src/python/src/grpc/framework/interfaces/links/test_utilities.py
new file mode 100644
index 0000000..6c2e334
--- /dev/null
+++ b/src/python/src/grpc/framework/interfaces/links/test_utilities.py
@@ -0,0 +1,66 @@
+# 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.
+
+"""State and behavior appropriate for use in tests."""
+
+import threading
+
+from grpc.framework.interfaces.links import links
+
+
+class RecordingLink(links.Link):
+  """A Link that records every ticket passed to it."""
+
+  def __init__(self):
+    self._condition = threading.Condition()
+    self._tickets = []
+
+  def accept_ticket(self, ticket):
+    with self._condition:
+      self._tickets.append(ticket)
+      self._condition.notify_all()
+
+  def join_link(self, link):
+    pass
+
+  def block_until_tickets_satisfy(self, predicate):
+    """Blocks until the received tickets satisfy the given predicate.
+
+    Args:
+      predicate: A callable that takes a sequence of tickets and returns a
+        boolean value.
+    """
+    with self._condition:
+      while not predicate(self._tickets):
+        self._condition.wait()
+
+  def tickets(self):
+    """Returns a copy of the list of all tickets received by this Link."""
+    with self._condition:
+      return tuple(self._tickets)
diff --git a/src/python/src/grpc/framework/interfaces/links/utilities.py b/src/python/src/grpc/framework/interfaces/links/utilities.py
new file mode 100644
index 0000000..6e4fd76
--- /dev/null
+++ b/src/python/src/grpc/framework/interfaces/links/utilities.py
@@ -0,0 +1,44 @@
+# 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.
+
+"""Utilities provided as part of the links interface."""
+
+from grpc.framework.interfaces.links import links
+
+
+class _NullLink(links.Link):
+  """A do-nothing links.Link."""
+
+  def accept_ticket(self, ticket):
+    pass
+
+  def join_link(self, link):
+    pass
+
+NULL_LINK = _NullLink()
diff --git a/src/python/src/setup.py b/src/python/src/setup.py
index 193285a..a857ae9 100644
--- a/src/python/src/setup.py
+++ b/src/python/src/setup.py
@@ -33,7 +33,6 @@
 import sys
 
 from distutils import core as _core
-from distutils import extension as _extension
 import setuptools
 
 
@@ -54,19 +53,6 @@
     'grpc/_adapter/_c/types/server.c',
 )
 
-_CYTHON_EXTENSION_PACKAGE_NAMES = (
-)
-
-_CYTHON_EXTENSION_MODULE_NAMES = (
-    'grpc._cython.cygrpc',
-    'grpc._cython._cygrpc.call',
-    'grpc._cython._cygrpc.channel',
-    'grpc._cython._cygrpc.completion_queue',
-    'grpc._cython._cygrpc.credentials',
-    'grpc._cython._cygrpc.records',
-    'grpc._cython._cygrpc.server',
-)
-
 _EXTENSION_INCLUDE_DIRECTORIES = (
     '.',
 )
@@ -84,45 +70,13 @@
     include_dirs=list(_EXTENSION_INCLUDE_DIRECTORIES),
     libraries=list(_EXTENSION_LIBRARIES),
 )
-_C_EXTENSION_MODULES = [_C_EXTENSION_MODULE]
-
-
-def cython_extensions(package_names, module_names, include_dirs, libraries,
-                      build_with_cython=False):
-  file_extension = 'pyx' if build_with_cython else 'c'
-  module_files = [name.replace('.', '/') + '.' + file_extension
-                  for name in module_names]
-  extensions = [
-      _extension.Extension(
-          name=module_name, sources=[module_file],
-          include_dirs=include_dirs, libraries=libraries
-      ) for (module_name, module_file) in zip(module_names, module_files)
-  ]
-  if build_with_cython:
-    import Cython.Build
-    return Cython.Build.cythonize(extensions)
-  else:
-    return extensions
-
-_CYTHON_EXTENSION_MODULES = cython_extensions(
-    list(_CYTHON_EXTENSION_PACKAGE_NAMES), list(_CYTHON_EXTENSION_MODULE_NAMES),
-    list(_EXTENSION_INCLUDE_DIRECTORIES), list(_EXTENSION_LIBRARIES),
-    bool(_BUILD_WITH_CYTHON))
-
-# TODO(atash): We shouldn't need to gate any C code based on the python version
-# from the distutils build system. Remove this hackery once we're on Cython and
-# 3.x C API compliant.
-_EXTENSION_MODULES = list(_CYTHON_EXTENSION_MODULES)
-if sys.version_info[0:2] <= (2, 7):
-  _EXTENSION_MODULES += _C_EXTENSION_MODULES
-
+_EXTENSION_MODULES = [_C_EXTENSION_MODULE]
 
 _PACKAGES = (
     'grpc',
     'grpc._adapter',
-    'grpc._cython',
-    'grpc._cython._cygrpc',
     'grpc._junkdrawer',
+    'grpc._links',
     'grpc.early_adopter',
     'grpc.framework',
     'grpc.framework.alpha',
@@ -131,20 +85,22 @@
     'grpc.framework.face',
     'grpc.framework.face.testing',
     'grpc.framework.foundation',
+    'grpc.framework.interfaces',
+    'grpc.framework.interfaces.links',
 )
 
 _PACKAGE_DIRECTORIES = {
     'grpc': 'grpc',
     'grpc._adapter': 'grpc/_adapter',
-    'grpc._cython': 'grpc/_cython',
     'grpc._junkdrawer': 'grpc/_junkdrawer',
+    'grpc._links': 'grpc/_links',
     'grpc.early_adopter': 'grpc/early_adopter',
     'grpc.framework': 'grpc/framework',
 }
 
 setuptools.setup(
     name='grpcio',
-    version='0.9.0a1',
+    version='0.10.0a0',
     ext_modules=_EXTENSION_MODULES,
     packages=list(_PACKAGES),
     package_dir=_PACKAGE_DIRECTORIES,
diff --git a/src/ruby/ext/grpc/rb_completion_queue.c b/src/ruby/ext/grpc/rb_completion_queue.c
index 8fb3949..2d52d96 100644
--- a/src/ruby/ext/grpc/rb_completion_queue.c
+++ b/src/ruby/ext/grpc/rb_completion_queue.c
@@ -91,7 +91,7 @@
    * - investigate further, this is probably another example of C-level cleanup
    * not working consistently in all cases.
    */
-  next_call.timeout = gpr_time_add(gpr_now(), gpr_time_from_micros(5e3));
+  next_call.timeout = gpr_time_add(gpr_now(GPR_CLOCK_REALTIME), gpr_time_from_micros(5e3));
   do {
     rb_thread_call_without_gvl(grpc_rb_completion_queue_next_no_gil,
                                (void *)&next_call, NULL, NULL);
diff --git a/src/ruby/grpc.gemspec b/src/ruby/grpc.gemspec
index 319da94..dd4e27d 100755
--- a/src/ruby/grpc.gemspec
+++ b/src/ruby/grpc.gemspec
@@ -14,7 +14,7 @@
   s.license       = 'BSD-3-Clause'
 
   s.required_ruby_version = '>= 2.0.0'
-  s.requirements << 'libgrpc ~> 0.9.1 needs to be installed'
+  s.requirements << 'libgrpc ~> 0.10.0 needs to be installed'
 
   s.files         = `git ls-files`.split("\n")
   s.test_files    = `git ls-files -- spec/*`.split("\n")
diff --git a/src/ruby/lib/grpc/generic/rpc_server.rb b/src/ruby/lib/grpc/generic/rpc_server.rb
index a7e20d6..67bf35c 100644
--- a/src/ruby/lib/grpc/generic/rpc_server.rb
+++ b/src/ruby/lib/grpc/generic/rpc_server.rb
@@ -398,14 +398,14 @@
       nil
     end
 
-    # Sends NOT_FOUND if the method can't be found
-    def found?(an_rpc)
+    # Sends UNIMPLEMENTED if the method is not implemented by this server
+    def implemented?(an_rpc)
       mth = an_rpc.method.to_sym
       return an_rpc if rpc_descs.key?(mth)
-      GRPC.logger.warn("NOT_FOUND: #{an_rpc}")
+      GRPC.logger.warn("UNIMPLEMENTED: #{an_rpc}")
       noop = proc { |x| x }
       c = ActiveCall.new(an_rpc.call, @cq, noop, noop, an_rpc.deadline)
-      c.send_status(StatusCodes::NOT_FOUND, '')
+      c.send_status(StatusCodes::UNIMPLEMENTED, '')
       nil
     end
 
@@ -446,7 +446,7 @@
       an_rpc.call.run_batch(@cq, handle_call_tag, INFINITE_FUTURE,
                             SEND_INITIAL_METADATA => connect_md)
       return nil unless available?(an_rpc)
-      return nil unless found?(an_rpc)
+      return nil unless implemented?(an_rpc)
 
       # Create the ActiveCall
       GRPC.logger.info("deadline is #{an_rpc.deadline}; (now=#{Time.now})")
diff --git a/templates/Makefile.template b/templates/Makefile.template
index 84822ab..490c002 100644
--- a/templates/Makefile.template
+++ b/templates/Makefile.template
@@ -346,7 +346,15 @@
 # These are automatically computed variables.
 # There shouldn't be any need to change anything from now on.
 
-HAS_PKG_CONFIG = $(shell command -v $(PKG_CONFIG) >/dev/null 2>&1 && echo true || echo false)
+-include cache.mk
+
+CACHE_MK =
+
+HAS_PKG_CONFIG ?= $(shell command -v $(PKG_CONFIG) >/dev/null 2>&1 && echo true || echo false)
+
+ifeq ($(HAS_PKG_CONFIG), true)
+CACHE_MK += HAS_PKG_CONFIG = true\n
+endif
 
 PC_TEMPLATE = prefix=$(prefix)\n\
 exec_prefix=${'\$${prefix}'}\n\
@@ -430,23 +438,34 @@
 SYSTEMTAP_HEADERS_CHECK_CMD = $(CC) $(CFLAGS) $(CPPFLAGS) -o $(TMPOUT) test/build/systemtap.c $(LDFLAGS)
 
 ifndef REQUIRE_CUSTOM_LIBRARIES_$(CONFIG)
-HAS_SYSTEM_PERFTOOLS = $(shell $(PERFTOOLS_CHECK_CMD) 2> /dev/null && echo true || echo false)
+HAS_SYSTEM_PERFTOOLS ?= $(shell $(PERFTOOLS_CHECK_CMD) 2> /dev/null && echo true || echo false)
 ifeq ($(HAS_SYSTEM_PERFTOOLS),true)
 DEFINES += GRPC_HAVE_PERFTOOLS
 LIBS += profiler
+CACHE_MK += HAS_SYSTEM_PERFTOOLS = true\n
 endif
 endif
 
 HAS_SYSTEM_PROTOBUF_VERIFY = $(shell $(PROTOBUF_CHECK_CMD) 2> /dev/null && echo true || echo false)
 ifndef REQUIRE_CUSTOM_LIBRARIES_$(CONFIG)
-HAS_SYSTEM_OPENSSL_ALPN = $(shell $(OPENSSL_ALPN_CHECK_CMD) 2> /dev/null && echo true || echo false)
+HAS_SYSTEM_OPENSSL_ALPN ?= $(shell $(OPENSSL_ALPN_CHECK_CMD) 2> /dev/null && echo true || echo false)
 ifeq ($(HAS_SYSTEM_OPENSSL_ALPN),true)
 HAS_SYSTEM_OPENSSL_NPN = true
+CACHE_MK += HAS_SYSTEM_OPENSSL_ALPN = true\n
 else
-HAS_SYSTEM_OPENSSL_NPN = $(shell $(OPENSSL_NPN_CHECK_CMD) 2> /dev/null && echo true || echo false)
+HAS_SYSTEM_OPENSSL_NPN ?= $(shell $(OPENSSL_NPN_CHECK_CMD) 2> /dev/null && echo true || echo false)
 endif
-HAS_SYSTEM_ZLIB = $(shell $(ZLIB_CHECK_CMD) 2> /dev/null && echo true || echo false)
-HAS_SYSTEM_PROTOBUF = $(HAS_SYSTEM_PROTOBUF_VERIFY)
+ifeq ($(HAS_SYSTEM_OPENSSL_NPN),true)
+CACHE_MK += HAS_SYSTEM_OPENSSL_NPN = true\n
+endif
+HAS_SYSTEM_ZLIB ?= $(shell $(ZLIB_CHECK_CMD) 2> /dev/null && echo true || echo false)
+ifeq ($(HAS_SYSTEM_ZLIB),true)
+CACHE_MK += HAS_SYSTEM_ZLIB = true\n
+endif
+HAS_SYSTEM_PROTOBUF ?= $(HAS_SYSTEM_PROTOBUF_VERIFY)
+ifeq ($(HAS_SYSTEM_PROTOBUF),true)
+CACHE_MK += HAS_SYSTEM_PROTOBUF = true\n
+endif
 else
 # override system libraries if the config requires a custom compiled library
 HAS_SYSTEM_OPENSSL_ALPN = false
@@ -455,9 +474,13 @@
 HAS_SYSTEM_PROTOBUF = false
 endif
 
-HAS_PROTOC = $(shell $(PROTOC_CHECK_CMD) 2> /dev/null && echo true || echo false)
+HAS_PROTOC ?= $(shell $(PROTOC_CHECK_CMD) 2> /dev/null && echo true || echo false)
 ifeq ($(HAS_PROTOC),true)
-HAS_VALID_PROTOC = $(shell $(PROTOC_CHECK_VERSION_CMD) 2> /dev/null && echo true || echo false)
+CACHE_MK += HAS_PROTOC = true\n
+HAS_VALID_PROTOC ?= $(shell $(PROTOC_CHECK_VERSION_CMD) 2> /dev/null && echo true || echo false)
+ifeq ($(HAS_VALID_PROTOC),true)
+CACHE_MK += HAS_VALID_PROTOC = true\n
+endif
 else
 HAS_VALID_PROTOC = false
 endif
@@ -465,6 +488,7 @@
 # Check for Systemtap (https://sourceware.org/systemtap/), first by making sure <sys/sdt.h> is present
 # in the system and secondly by checking for the "dtrace" binary (on Linux, this is part of the Systemtap
 # distribution. It's part of the base system on BSD/Solaris machines).
+ifndef HAS_SYSTEMTAP
 HAS_SYSTEMTAP_HEADERS = $(shell $(SYSTEMTAP_HEADERS_CHECK_CMD) 2> /dev/null && echo true || echo false)
 HAS_DTRACE = $(shell $(DTRACE_CHECK_CMD) 2> /dev/null && echo true || echo false)
 HAS_SYSTEMTAP = false
@@ -473,6 +497,11 @@
 HAS_SYSTEMTAP = true
 endif
 endif
+endif
+
+ifeq ($(HAS_SYSTEMTAP),true)
+CACHE_MK += HAS_SYSTEMTAP = true\n
+endif
 
 # Note that for testing purposes, one can do:
 #   make HAS_EMBEDDED_OPENSSL_ALPN=false
@@ -842,7 +871,7 @@
 
 static: static_c static_cxx
 
-static_c: pc_c pc_c_unsecure \
+static_c: pc_c pc_c_unsecure cache.mk \
 % for lib in libs:
 % if lib.build == 'all' and lib.language == 'c':
  $(LIBDIR)/$(CONFIG)/lib${lib.name}.a\
@@ -850,7 +879,7 @@
 % endfor
 
 
-static_cxx: pc_cxx pc_cxx_unsecure pc_gpr\
+static_cxx: pc_cxx pc_cxx_unsecure pc_gpr cache.mk \
 % for lib in libs:
 % if lib.build == 'all' and lib.language == 'c++':
  $(LIBDIR)/$(CONFIG)/lib${lib.name}.a\
@@ -860,7 +889,7 @@
 
 shared: shared_c shared_cxx
 
-shared_c: pc_c pc_c_unsecure pc_gpr\
+shared_c: pc_c pc_c_unsecure pc_gpr  cache.mk\
 % for lib in libs:
 % if lib.build == 'all' and lib.language == 'c':
  $(LIBDIR)/$(CONFIG)/lib${lib.name}.$(SHARED_EXT)\
@@ -868,7 +897,7 @@
 % endfor
 
 
-shared_cxx: pc_cxx pc_cxx_unsecure \
+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)\
@@ -1077,6 +1106,10 @@
 % endfor
 endif
 
+cache.mk::
+	$(E) "[MAKE]    Generating $@"
+	$(Q) echo -e "$(CACHE_MK)" >$@
+
 $(LIBDIR)/$(CONFIG)/pkgconfig/gpr.pc:
 	$(E) "[MAKE]    Generating $@"
 	$(Q) mkdir -p $(@D)
@@ -1288,7 +1321,7 @@
 
 clean:
 	$(E) "[CLEAN]   Cleaning build directories."
-	$(Q) $(RM) -rf $(OBJDIR) $(LIBDIR) $(BINDIR) $(GENDIR)
+	$(Q) $(RM) -rf $(OBJDIR) $(LIBDIR) $(BINDIR) $(GENDIR) cache.mk
 
 
 # The various libraries
diff --git a/templates/src/core/surface/version.c.template b/templates/src/core/surface/version.c.template
new file mode 100644
index 0000000..936341c
--- /dev/null
+++ b/templates/src/core/surface/version.c.template
@@ -0,0 +1,41 @@
+/*
+ *
+ * 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.
+ *
+ */
+
+/* This file is autogenerated from:
+   templates/src/core/surface/version.c.template */
+
+#include <grpc/grpc.h>
+
+const char *grpc_version_string(void) {
+	return "${settings.version.major}.${settings.version.minor}.${settings.version.micro}.${settings.version.build}";
+}
diff --git a/templates/vsprojects/Grpc.mak.template b/templates/vsprojects/Grpc.mak.template
index b75537d..9d85376 100644
--- a/templates/vsprojects/Grpc.mak.template
+++ b/templates/vsprojects/Grpc.mak.template
@@ -72,6 +72,12 @@
 
 all: buildtests
 
+tools:
+
+tools_c:
+
+tools_cxx:
+
 $(OUT_DIR):
 	mkdir $(OUT_DIR)
 
diff --git a/test/core/end2end/cq_verifier.c b/test/core/end2end/cq_verifier.c
index 33f7c02..407c72b 100644
--- a/test/core/end2end/cq_verifier.c
+++ b/test/core/end2end/cq_verifier.c
@@ -248,7 +248,8 @@
 }
 
 void cq_verify_empty(cq_verifier *v) {
-  gpr_timespec deadline = gpr_time_add(gpr_now(), gpr_time_from_seconds(1));
+  gpr_timespec deadline =
+      gpr_time_add(gpr_now(GPR_CLOCK_REALTIME), gpr_time_from_seconds(1));
   grpc_event ev;
 
   GPR_ASSERT(v->expect.next == &v->expect && "expectation queue must be empty");
diff --git a/test/core/fling/client.c b/test/core/fling/client.c
index ee5e390..6741a9d 100644
--- a/test/core/fling/client.c
+++ b/test/core/fling/client.c
@@ -124,7 +124,7 @@
 }
 
 static double now(void) {
-  gpr_timespec tv = gpr_now();
+  gpr_timespec tv = gpr_now(GPR_CLOCK_REALTIME);
   return 1e9 * tv.tv_sec + tv.tv_nsec;
 }
 
diff --git a/test/core/fling/server.c b/test/core/fling/server.c
index 9542e15..468013c 100644
--- a/test/core/fling/server.c
+++ b/test/core/fling/server.c
@@ -241,7 +241,8 @@
       shutdown_started = 1;
     }
     ev = grpc_completion_queue_next(
-        cq, gpr_time_add(gpr_now(), gpr_time_from_micros(1000000)));
+        cq, gpr_time_add(gpr_now(GPR_CLOCK_REALTIME),
+                         gpr_time_from_micros(1000000)));
     s = ev.tag;
     switch (ev.type) {
       case GRPC_OP_COMPLETE:
diff --git a/test/core/httpcli/httpcli_test.c b/test/core/httpcli/httpcli_test.c
index 6e579bc..ca0b2d1 100644
--- a/test/core/httpcli/httpcli_test.c
+++ b/test/core/httpcli/httpcli_test.c
@@ -145,7 +145,8 @@
   gpr_free(args[0]);
   gpr_free(args[2]);
 
-  gpr_sleep_until(gpr_time_add(gpr_now(), gpr_time_from_seconds(5)));
+  gpr_sleep_until(
+      gpr_time_add(gpr_now(GPR_CLOCK_REALTIME), gpr_time_from_seconds(5)));
 
   grpc_test_init(argc, argv);
   grpc_init();
diff --git a/test/core/iomgr/alarm_list_test.c b/test/core/iomgr/alarm_list_test.c
index 684e3f5..225c449 100644
--- a/test/core/iomgr/alarm_list_test.c
+++ b/test/core/iomgr/alarm_list_test.c
@@ -51,7 +51,7 @@
 }
 
 static void add_test(void) {
-  gpr_timespec start = gpr_now();
+  gpr_timespec start = gpr_now(GPR_CLOCK_REALTIME);
   int i;
   grpc_alarm alarms[20];
 
@@ -61,13 +61,13 @@
   /* 10 ms alarms.  will expire in the current epoch */
   for (i = 0; i < 10; i++) {
     grpc_alarm_init(&alarms[i], gpr_time_add(start, gpr_time_from_millis(10)),
-                    cb, (void *)(gpr_intptr) i, start);
+                    cb, (void *)(gpr_intptr)i, start);
   }
 
   /* 1010 ms alarms.  will expire in the next epoch */
   for (i = 10; i < 20; i++) {
     grpc_alarm_init(&alarms[i], gpr_time_add(start, gpr_time_from_millis(1010)),
-                    cb, (void *)(gpr_intptr) i, start);
+                    cb, (void *)(gpr_intptr)i, start);
   }
 
   /* collect alarms.  Only the first batch should be ready. */
@@ -115,15 +115,15 @@
   memset(cb_called, 0, sizeof(cb_called));
 
   grpc_alarm_init(&alarms[0], gpr_time_from_millis(100), cb,
-                  (void *)(gpr_intptr) 0, gpr_time_0);
+                  (void *)(gpr_intptr)0, gpr_time_0);
   grpc_alarm_init(&alarms[1], gpr_time_from_millis(3), cb,
-                  (void *)(gpr_intptr) 1, gpr_time_0);
+                  (void *)(gpr_intptr)1, gpr_time_0);
   grpc_alarm_init(&alarms[2], gpr_time_from_millis(100), cb,
-                  (void *)(gpr_intptr) 2, gpr_time_0);
+                  (void *)(gpr_intptr)2, gpr_time_0);
   grpc_alarm_init(&alarms[3], gpr_time_from_millis(3), cb,
-                  (void *)(gpr_intptr) 3, gpr_time_0);
+                  (void *)(gpr_intptr)3, gpr_time_0);
   grpc_alarm_init(&alarms[4], gpr_time_from_millis(1), cb,
-                  (void *)(gpr_intptr) 4, gpr_time_0);
+                  (void *)(gpr_intptr)4, gpr_time_0);
   GPR_ASSERT(1 == grpc_alarm_check(NULL, gpr_time_from_millis(2), NULL));
   GPR_ASSERT(1 == cb_called[4][1]);
   grpc_alarm_cancel(&alarms[0]);
diff --git a/test/core/iomgr/alarm_test.c b/test/core/iomgr/alarm_test.c
index 0ccec43..362eb5f 100644
--- a/test/core/iomgr/alarm_test.c
+++ b/test/core/iomgr/alarm_test.c
@@ -113,7 +113,7 @@
   gpr_event_init(&arg.fcb_arg);
 
   grpc_alarm_init(&alarm, GRPC_TIMEOUT_MILLIS_TO_DEADLINE(100), alarm_cb, &arg,
-                  gpr_now());
+                  gpr_now(GPR_CLOCK_REALTIME));
 
   alarm_deadline = GRPC_TIMEOUT_SECONDS_TO_DEADLINE(1);
   gpr_mu_lock(&arg.mu);
@@ -165,7 +165,7 @@
   gpr_event_init(&arg2.fcb_arg);
 
   grpc_alarm_init(&alarm_to_cancel, GRPC_TIMEOUT_MILLIS_TO_DEADLINE(100),
-                  alarm_cb, &arg2, gpr_now());
+                  alarm_cb, &arg2, gpr_now(GPR_CLOCK_REALTIME));
   grpc_alarm_cancel(&alarm_to_cancel);
 
   alarm_deadline = GRPC_TIMEOUT_SECONDS_TO_DEADLINE(1);
diff --git a/test/core/iomgr/endpoint_tests.c b/test/core/iomgr/endpoint_tests.c
index 8198c24..0cfba5f 100644
--- a/test/core/iomgr/endpoint_tests.c
+++ b/test/core/iomgr/endpoint_tests.c
@@ -254,7 +254,7 @@
 
   gpr_mu_lock(GRPC_POLLSET_MU(g_pollset));
   while (!state.read_done || !state.write_done) {
-    GPR_ASSERT(gpr_time_cmp(gpr_now(), deadline) < 0);
+    GPR_ASSERT(gpr_time_cmp(gpr_now(GPR_CLOCK_REALTIME), deadline) < 0);
     grpc_pollset_work(g_pollset, deadline);
   }
   gpr_mu_unlock(GRPC_POLLSET_MU(g_pollset));
@@ -350,14 +350,14 @@
         deadline = GRPC_TIMEOUT_SECONDS_TO_DEADLINE(10);
         gpr_mu_lock(GRPC_POLLSET_MU(g_pollset));
         while (!write_st.done) {
-          GPR_ASSERT(gpr_time_cmp(gpr_now(), deadline) < 0);
+          GPR_ASSERT(gpr_time_cmp(gpr_now(GPR_CLOCK_REALTIME), deadline) < 0);
           grpc_pollset_work(g_pollset, deadline);
         }
         gpr_mu_unlock(GRPC_POLLSET_MU(g_pollset));
         grpc_endpoint_destroy(write_st.ep);
         gpr_mu_lock(GRPC_POLLSET_MU(g_pollset));
         while (!read_st.done) {
-          GPR_ASSERT(gpr_time_cmp(gpr_now(), deadline) < 0);
+          GPR_ASSERT(gpr_time_cmp(gpr_now(GPR_CLOCK_REALTIME), deadline) < 0);
           grpc_pollset_work(g_pollset, deadline);
         }
         gpr_mu_unlock(GRPC_POLLSET_MU(g_pollset));
diff --git a/test/core/iomgr/tcp_client_posix_test.c b/test/core/iomgr/tcp_client_posix_test.c
index b673c03..710cd72 100644
--- a/test/core/iomgr/tcp_client_posix_test.c
+++ b/test/core/iomgr/tcp_client_posix_test.c
@@ -187,11 +187,12 @@
   /* Make sure the event doesn't trigger early */
   gpr_mu_lock(GRPC_POLLSET_MU(&g_pollset));
   while (gpr_time_cmp(gpr_time_add(connect_deadline, gpr_time_from_seconds(2)),
-                      gpr_now()) > 0) {
-    int is_after_deadline = gpr_time_cmp(connect_deadline, gpr_now()) <= 0;
+                      gpr_now(GPR_CLOCK_REALTIME)) > 0) {
+    int is_after_deadline =
+        gpr_time_cmp(connect_deadline, gpr_now(GPR_CLOCK_REALTIME)) <= 0;
     if (is_after_deadline &&
         gpr_time_cmp(gpr_time_add(connect_deadline, gpr_time_from_seconds(1)),
-                     gpr_now()) > 0) {
+                     gpr_now(GPR_CLOCK_REALTIME)) > 0) {
       /* allow some slack before insisting that things be done */
     } else {
       GPR_ASSERT(g_connections_complete ==
diff --git a/test/core/iomgr/tcp_server_posix_test.c b/test/core/iomgr/tcp_server_posix_test.c
index fb26271..110a2eb 100644
--- a/test/core/iomgr/tcp_server_posix_test.c
+++ b/test/core/iomgr/tcp_server_posix_test.c
@@ -135,7 +135,7 @@
 
     gpr_log(GPR_DEBUG, "wait");
     while (g_nconnects == nconnects_before &&
-           gpr_time_cmp(deadline, gpr_now()) > 0) {
+           gpr_time_cmp(deadline, gpr_now(GPR_CLOCK_REALTIME)) > 0) {
       grpc_pollset_work(&g_pollset, deadline);
     }
     gpr_log(GPR_DEBUG, "wait done");
diff --git a/test/core/network_benchmarks/low_level_ping_pong.c b/test/core/network_benchmarks/low_level_ping_pong.c
index 78a0eef..0ce4bd4 100644
--- a/test/core/network_benchmarks/low_level_ping_pong.c
+++ b/test/core/network_benchmarks/low_level_ping_pong.c
@@ -296,7 +296,7 @@
 }
 
 static double now(void) {
-  gpr_timespec tv = gpr_now();
+  gpr_timespec tv = gpr_now(GPR_CLOCK_REALTIME);
   return 1e9 * tv.tv_sec + tv.tv_nsec;
 }
 
diff --git a/test/core/statistics/census_log_tests.c b/test/core/statistics/census_log_tests.c
index 241ec1c..a34dcf0 100644
--- a/test/core/statistics/census_log_tests.c
+++ b/test/core/statistics/census_log_tests.c
@@ -568,7 +568,7 @@
     double write_time_micro = 0.0;
     int nrecords = 0;
     setup_test(0);
-    start_time = gpr_now();
+    start_time = gpr_now(GPR_CLOCK_REALTIME);
     while (1) {
       void* record = census_log_start_write(write_size);
       if (record == NULL) {
@@ -577,7 +577,7 @@
       census_log_end_write(record, write_size);
       nrecords++;
     }
-    write_time = gpr_time_sub(gpr_now(), start_time);
+    write_time = gpr_time_sub(gpr_now(GPR_CLOCK_REALTIME), start_time);
     write_time_micro = write_time.tv_sec * 1000000 + write_time.tv_nsec / 1000;
     census_log_shutdown();
     printf(
diff --git a/test/core/statistics/multiple_writers_circular_buffer_test.c b/test/core/statistics/multiple_writers_circular_buffer_test.c
index a645e15..56ada89 100644
--- a/test/core/statistics/multiple_writers_circular_buffer_test.c
+++ b/test/core/statistics/multiple_writers_circular_buffer_test.c
@@ -40,7 +40,7 @@
 
 int main(int argc, char **argv) {
   grpc_test_init(argc, argv);
-  srand(gpr_now().tv_nsec);
+  srand(gpr_now(GPR_CLOCK_REALTIME).tv_nsec);
   test_multiple_writers_circular_log();
   return 0;
 }
diff --git a/test/core/statistics/multiple_writers_test.c b/test/core/statistics/multiple_writers_test.c
index 84aef15..e524927 100644
--- a/test/core/statistics/multiple_writers_test.c
+++ b/test/core/statistics/multiple_writers_test.c
@@ -40,7 +40,7 @@
 
 int main(int argc, char **argv) {
   grpc_test_init(argc, argv);
-  srand(gpr_now().tv_nsec);
+  srand(gpr_now(GPR_CLOCK_REALTIME).tv_nsec);
   test_multiple_writers();
   return 0;
 }
diff --git a/test/core/statistics/performance_test.c b/test/core/statistics/performance_test.c
index 3c1e282..3f0e080 100644
--- a/test/core/statistics/performance_test.c
+++ b/test/core/statistics/performance_test.c
@@ -40,7 +40,7 @@
 
 int main(int argc, char **argv) {
   grpc_test_init(argc, argv);
-  srand(gpr_now().tv_nsec);
+  srand(gpr_now(GPR_CLOCK_REALTIME).tv_nsec);
   test_performance();
   return 0;
 }
diff --git a/test/core/statistics/quick_test.c b/test/core/statistics/quick_test.c
index 0e43231..c72ae77 100644
--- a/test/core/statistics/quick_test.c
+++ b/test/core/statistics/quick_test.c
@@ -40,7 +40,7 @@
 
 int main(int argc, char **argv) {
   grpc_test_init(argc, argv);
-  srand(gpr_now().tv_nsec);
+  srand(gpr_now(GPR_CLOCK_REALTIME).tv_nsec);
   test_invalid_record_size();
   test_end_write_with_different_size();
   test_read_pending_record();
diff --git a/test/core/statistics/small_log_test.c b/test/core/statistics/small_log_test.c
index c151b77..b26b95f 100644
--- a/test/core/statistics/small_log_test.c
+++ b/test/core/statistics/small_log_test.c
@@ -40,7 +40,7 @@
 
 int main(int argc, char **argv) {
   grpc_test_init(argc, argv);
-  srand(gpr_now().tv_nsec);
+  srand(gpr_now(GPR_CLOCK_REALTIME).tv_nsec);
   test_small_log();
   return 0;
 }
diff --git a/test/core/statistics/window_stats_test.c b/test/core/statistics/window_stats_test.c
index d893f7f..1c66a87 100644
--- a/test/core/statistics/window_stats_test.c
+++ b/test/core/statistics/window_stats_test.c
@@ -83,7 +83,7 @@
   result.statistic = &sum;
   census_window_stats_get_sums(stats, zero, &result);
   GPR_ASSERT(result.count == 0 && sum.value1 == 0 && sum.value2 == 0);
-  census_window_stats_get_sums(stats, gpr_now(), &result);
+  census_window_stats_get_sums(stats, gpr_now(GPR_CLOCK_REALTIME), &result);
   GPR_ASSERT(result.count == 0 && sum.value1 == 0 && sum.value2 == 0);
   census_window_stats_destroy(stats);
 }
@@ -268,7 +268,7 @@
   struct census_window_stats* stats =
       census_window_stats_create(1, &kMinInterval, 7, &kMyStatInfo);
   GPR_ASSERT(stats != NULL);
-  srand(gpr_now().tv_nsec);
+  srand(gpr_now(GPR_CLOCK_REALTIME).tv_nsec);
   for (i = 0; i < 100000; i++) {
     increment.tv_nsec = rand() % 100000000; /* up to 1/10th second */
     when = gpr_time_add(when, increment);
@@ -292,7 +292,7 @@
   gpr_timespec increment = {0, 0};
   struct census_window_stats* stats =
       census_window_stats_create(1, &gpr_inf_future, 10, &kMyStatInfo);
-  srand(gpr_now().tv_nsec);
+  srand(gpr_now(GPR_CLOCK_REALTIME).tv_nsec);
   for (i = 0; i < count; i++) {
     increment.tv_sec = rand() % 21600; /* 6 hours */
     when = gpr_time_add(when, increment);
diff --git a/test/core/support/cancellable_test.c b/test/core/support/cancellable_test.c
index b2db1af..2f4b67a 100644
--- a/test/core/support/cancellable_test.c
+++ b/test/core/support/cancellable_test.c
@@ -81,22 +81,23 @@
   GPR_ASSERT(!gpr_cancellable_is_cancelled(&t.cancel));
 
   /* Test timeout on event wait for uncancelled gpr_cancellable */
-  interval = gpr_now();
-  gpr_event_cancellable_wait(
-      &t.ev, gpr_time_add(gpr_now(), gpr_time_from_micros(1000000)), &t.cancel);
-  interval = gpr_time_sub(gpr_now(), interval);
+  interval = gpr_now(GPR_CLOCK_REALTIME);
+  gpr_event_cancellable_wait(&t.ev, gpr_time_add(gpr_now(GPR_CLOCK_REALTIME),
+                                                 gpr_time_from_micros(1000000)),
+                             &t.cancel);
+  interval = gpr_time_sub(gpr_now(GPR_CLOCK_REALTIME), interval);
   GPR_ASSERT(gpr_time_cmp(interval, gpr_time_from_micros(500000)) >= 0);
   GPR_ASSERT(gpr_time_cmp(gpr_time_from_micros(2000000), interval) >= 0);
 
   /* Test timeout on cv wait for uncancelled gpr_cancellable */
   gpr_mu_lock(&t.mu);
-  interval = gpr_now();
+  interval = gpr_now(GPR_CLOCK_REALTIME);
   while (!gpr_cv_cancellable_wait(
-             &t.cv, &t.mu,
-             gpr_time_add(gpr_now(), gpr_time_from_micros(1000000)),
-             &t.cancel)) {
+      &t.cv, &t.mu,
+      gpr_time_add(gpr_now(GPR_CLOCK_REALTIME), gpr_time_from_micros(1000000)),
+      &t.cancel)) {
   }
-  interval = gpr_time_sub(gpr_now(), interval);
+  interval = gpr_time_sub(gpr_now(GPR_CLOCK_REALTIME), interval);
   GPR_ASSERT(gpr_time_cmp(interval, gpr_time_from_micros(500000)) >= 0);
   GPR_ASSERT(gpr_time_cmp(gpr_time_from_micros(2000000), interval) >= 0);
   gpr_mu_unlock(&t.mu);
@@ -112,8 +113,8 @@
 
   /* Wait a second, and check that no threads have finished waiting. */
   gpr_mu_lock(&t.mu);
-  gpr_cv_wait(&t.cv, &t.mu,
-              gpr_time_add(gpr_now(), gpr_time_from_micros(1000000)));
+  gpr_cv_wait(&t.cv, &t.mu, gpr_time_add(gpr_now(GPR_CLOCK_REALTIME),
+                                         gpr_time_from_micros(1000000)));
   GPR_ASSERT(t.n == n);
   gpr_mu_unlock(&t.mu);
 
@@ -129,21 +130,22 @@
 
   /* Test timeout on cv wait for cancelled gpr_cancellable */
   gpr_mu_lock(&t.mu);
-  interval = gpr_now();
+  interval = gpr_now(GPR_CLOCK_REALTIME);
   while (!gpr_cv_cancellable_wait(
-             &t.cv, &t.mu,
-             gpr_time_add(gpr_now(), gpr_time_from_micros(1000000)),
-             &t.cancel)) {
+      &t.cv, &t.mu,
+      gpr_time_add(gpr_now(GPR_CLOCK_REALTIME), gpr_time_from_micros(1000000)),
+      &t.cancel)) {
   }
-  interval = gpr_time_sub(gpr_now(), interval);
+  interval = gpr_time_sub(gpr_now(GPR_CLOCK_REALTIME), interval);
   GPR_ASSERT(gpr_time_cmp(gpr_time_from_micros(100000), interval) >= 0);
   gpr_mu_unlock(&t.mu);
 
   /* Test timeout on event wait for cancelled gpr_cancellable */
-  interval = gpr_now();
-  gpr_event_cancellable_wait(
-      &t.ev, gpr_time_add(gpr_now(), gpr_time_from_micros(1000000)), &t.cancel);
-  interval = gpr_time_sub(gpr_now(), interval);
+  interval = gpr_now(GPR_CLOCK_REALTIME);
+  gpr_event_cancellable_wait(&t.ev, gpr_time_add(gpr_now(GPR_CLOCK_REALTIME),
+                                                 gpr_time_from_micros(1000000)),
+                             &t.cancel);
+  interval = gpr_time_sub(gpr_now(GPR_CLOCK_REALTIME), interval);
   GPR_ASSERT(gpr_time_cmp(gpr_time_from_micros(100000), interval) >= 0);
 
   gpr_mu_destroy(&t.mu);
diff --git a/test/core/support/stack_lockfree_test.c b/test/core/support/stack_lockfree_test.c
new file mode 100644
index 0000000..42082de
--- /dev/null
+++ b/test/core/support/stack_lockfree_test.c
@@ -0,0 +1,154 @@
+/*
+ *
+ * Copyright 2015, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "src/core/support/stack_lockfree.h"
+
+#include <stdlib.h>
+
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+#include <grpc/support/sync.h>
+#include <grpc/support/thd.h>
+#include "test/core/util/test_config.h"
+
+/* max stack size supported */
+#define MAX_STACK_SIZE 65534
+
+#define MAX_THREADS 32
+
+static void test_serial_sized(int size) {
+  gpr_stack_lockfree *stack = gpr_stack_lockfree_create(size);
+  int i;
+
+  /* First try popping empty */
+  GPR_ASSERT(gpr_stack_lockfree_pop(stack) == -1);
+
+  /* Now add one item and check it */
+  gpr_stack_lockfree_push(stack, 3);
+  GPR_ASSERT(gpr_stack_lockfree_pop(stack) == 3);
+  GPR_ASSERT(gpr_stack_lockfree_pop(stack) == -1);
+
+  /* Now add repeatedly more items and check them */
+  for (i = 1; i < size; i *= 2) {
+    int j;
+    for (j = 0; j <= i; j++) {
+      gpr_stack_lockfree_push(stack, j);
+    }
+    for (j = 0; j <= i; j++) {
+      GPR_ASSERT(gpr_stack_lockfree_pop(stack) == i - j);
+    }
+    GPR_ASSERT(gpr_stack_lockfree_pop(stack) == -1);
+  }
+
+  gpr_stack_lockfree_destroy(stack);
+}
+
+static void test_serial() {
+  int i;
+  for (i = 128; i < MAX_STACK_SIZE; i *= 2) {
+    test_serial_sized(i);
+  }
+  test_serial_sized(MAX_STACK_SIZE);
+}
+
+struct test_arg {
+  gpr_stack_lockfree *stack;
+  int stack_size;
+  int nthreads;
+  int rank;
+  int sum;
+};
+
+static void test_mt_body(void *v) {
+  struct test_arg *arg = (struct test_arg *)v;
+  int lo, hi;
+  int i;
+  int res;
+  lo = arg->rank * arg->stack_size / arg->nthreads;
+  hi = (arg->rank + 1) * arg->stack_size / arg->nthreads;
+  for (i = lo; i < hi; i++) {
+    gpr_stack_lockfree_push(arg->stack, i);
+    if ((res = gpr_stack_lockfree_pop(arg->stack)) != -1) {
+      arg->sum += res;
+    }
+  }
+  while ((res = gpr_stack_lockfree_pop(arg->stack)) != -1) {
+    arg->sum += res;
+  }
+}
+
+static void test_mt_sized(int size, int nth) {
+  gpr_stack_lockfree *stack;
+  struct test_arg args[MAX_THREADS];
+  gpr_thd_id thds[MAX_THREADS];
+  int sum;
+  int i;
+  gpr_thd_options options = gpr_thd_options_default();
+
+  stack = gpr_stack_lockfree_create(size);
+  for (i = 0; i < nth; i++) {
+    args[i].stack = stack;
+    args[i].stack_size = size;
+    args[i].nthreads = nth;
+    args[i].rank = i;
+    args[i].sum = 0;
+  }
+  gpr_thd_options_set_joinable(&options);
+  for (i = 0; i < nth; i++) {
+    GPR_ASSERT(gpr_thd_new(&thds[i], test_mt_body, &args[i], &options));
+  }
+  sum = 0;
+  for (i = 0; i < nth; i++) {
+    gpr_thd_join(thds[i]);
+    sum = sum + args[i].sum;
+  }
+  GPR_ASSERT((unsigned)sum == ((unsigned)size * (size - 1)) / 2);
+  gpr_stack_lockfree_destroy(stack);
+}
+
+static void test_mt() {
+  int size, nth;
+  for (nth = 1; nth < MAX_THREADS; nth++) {
+    for (size = 128; size < MAX_STACK_SIZE; size *= 2) {
+      test_mt_sized(size, nth);
+    }
+    test_mt_sized(MAX_STACK_SIZE, nth);
+  }
+}
+
+int main(int argc, char **argv) {
+  grpc_test_init(argc, argv);
+  test_serial();
+  test_mt();
+  return 0;
+}
diff --git a/test/core/support/sync_test.c b/test/core/support/sync_test.c
index 44bc6ba..99be5cd 100644
--- a/test/core/support/sync_test.c
+++ b/test/core/support/sync_test.c
@@ -242,12 +242,12 @@
                  void (*extra)(void *m), int timeout_s) {
   gpr_int64 iterations = 1024;
   struct test *m;
-  gpr_timespec start = gpr_now();
+  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));
   fprintf(stderr, "%s:", name);
-  while (gpr_time_cmp(gpr_now(), deadline) < 0) {
+  while (gpr_time_cmp(gpr_now(GPR_CLOCK_REALTIME), deadline) < 0) {
     iterations <<= 1;
     fprintf(stderr, " %ld", (long)iterations);
     m = test_new(10, iterations);
@@ -265,7 +265,7 @@
     }
     test_destroy(m);
   }
-  time_taken = gpr_time_sub(gpr_now(), start);
+  time_taken = gpr_time_sub(gpr_now(GPR_CLOCK_REALTIME), start);
   fprintf(stderr, " done %ld.%09d s\n", (long)time_taken.tv_sec,
           (int)time_taken.tv_nsec);
 }
@@ -323,7 +323,8 @@
   for (i = 0; i != m->iterations; i++) {
     gpr_timespec deadline;
     gpr_mu_lock(&m->mu);
-    deadline = gpr_time_add(gpr_now(), gpr_time_from_micros(1000));
+    deadline =
+        gpr_time_add(gpr_now(GPR_CLOCK_REALTIME), gpr_time_from_micros(1000));
     while (!gpr_cv_wait(&m->cv, &m->mu, deadline)) {
     }
     m->counter++;
@@ -339,7 +340,8 @@
   gpr_int64 i;
   for (i = 0; i != m->iterations; i++) {
     gpr_timespec deadline;
-    deadline = gpr_time_add(gpr_now(), gpr_time_from_micros(1000));
+    deadline =
+        gpr_time_add(gpr_now(GPR_CLOCK_REALTIME), gpr_time_from_micros(1000));
     GPR_ASSERT(gpr_event_wait(&m->event, deadline) == NULL);
     gpr_mu_lock(&m->mu);
     m->counter++;
@@ -382,9 +384,9 @@
   gpr_mu_lock(&m->mu);
   m->counter = n;
   gpr_mu_unlock(&m->mu);
-  GPR_ASSERT(
-      !queue_remove(&m->q, &value,
-                    gpr_time_add(gpr_now(), gpr_time_from_micros(1000000))));
+  GPR_ASSERT(!queue_remove(&m->q, &value,
+                           gpr_time_add(gpr_now(GPR_CLOCK_REALTIME),
+                                        gpr_time_from_micros(1000000))));
   mark_thread_done(m);
 }
 
diff --git a/test/core/surface/completion_queue_test.c b/test/core/surface/completion_queue_test.c
index eba24f5..177adbe 100644
--- a/test/core/surface/completion_queue_test.c
+++ b/test/core/surface/completion_queue_test.c
@@ -69,22 +69,25 @@
   LOG_TEST("test_wait_empty");
 
   cc = grpc_completion_queue_create();
-  GPR_ASSERT(grpc_completion_queue_next(cc, gpr_now()).type ==
+  GPR_ASSERT(grpc_completion_queue_next(cc, gpr_now(GPR_CLOCK_REALTIME)).type ==
              GRPC_QUEUE_TIMEOUT);
   shutdown_and_destroy(cc);
 }
 
+static void do_nothing_end_completion(void *arg, grpc_cq_completion *c) {}
+
 static void test_cq_end_op(void) {
   grpc_event ev;
   grpc_completion_queue *cc;
+  grpc_cq_completion completion;
   void *tag = create_test_tag();
 
   LOG_TEST("test_cq_end_op");
 
   cc = grpc_completion_queue_create();
 
-  grpc_cq_begin_op(cc, NULL);
-  grpc_cq_end_op(cc, tag, NULL, 1);
+  grpc_cq_begin_op(cc);
+  grpc_cq_end_op(cc, tag, 1, do_nothing_end_completion, NULL, &completion);
 
   ev = grpc_completion_queue_next(cc, gpr_inf_past);
   GPR_ASSERT(ev.type == GRPC_OP_COMPLETE);
@@ -120,6 +123,7 @@
   grpc_event ev;
   grpc_completion_queue *cc;
   void *tags[128];
+  grpc_cq_completion completions[GPR_ARRAY_SIZE(tags)];
   unsigned i, j;
 
   LOG_TEST("test_pluck");
@@ -134,8 +138,9 @@
   cc = grpc_completion_queue_create();
 
   for (i = 0; i < GPR_ARRAY_SIZE(tags); i++) {
-    grpc_cq_begin_op(cc, NULL);
-    grpc_cq_end_op(cc, tags[i], NULL, 1);
+    grpc_cq_begin_op(cc);
+    grpc_cq_end_op(cc, tags[i], 1, do_nothing_end_completion, NULL,
+                   &completions[i]);
   }
 
   for (i = 0; i < GPR_ARRAY_SIZE(tags); i++) {
@@ -144,8 +149,9 @@
   }
 
   for (i = 0; i < GPR_ARRAY_SIZE(tags); i++) {
-    grpc_cq_begin_op(cc, NULL);
-    grpc_cq_end_op(cc, tags[i], NULL, 1);
+    grpc_cq_begin_op(cc);
+    grpc_cq_end_op(cc, tags[i], 1, do_nothing_end_completion, NULL,
+                   &completions[i]);
   }
 
   for (i = 0; i < GPR_ARRAY_SIZE(tags); i++) {
@@ -171,7 +177,11 @@
 } test_thread_options;
 
 gpr_timespec ten_seconds_time(void) {
-  return GRPC_TIMEOUT_SECONDS_TO_DEADLINE(1);
+  return GRPC_TIMEOUT_SECONDS_TO_DEADLINE(10);
+}
+
+static void free_completion(void *arg, grpc_cq_completion *completion) {
+  gpr_free(completion);
 }
 
 static void producer_thread(void *arg) {
@@ -184,7 +194,7 @@
 
   gpr_log(GPR_INFO, "producer %d phase 1", opt->id);
   for (i = 0; i < TEST_THREAD_EVENTS; i++) {
-    grpc_cq_begin_op(opt->cc, NULL);
+    grpc_cq_begin_op(opt->cc);
   }
 
   gpr_log(GPR_INFO, "producer %d phase 1 done", opt->id);
@@ -193,7 +203,8 @@
 
   gpr_log(GPR_INFO, "producer %d phase 2", opt->id);
   for (i = 0; i < TEST_THREAD_EVENTS; i++) {
-    grpc_cq_end_op(opt->cc, (void *)(gpr_intptr)1, NULL, 1);
+    grpc_cq_end_op(opt->cc, (void *)(gpr_intptr)1, 1, free_completion, NULL,
+                   gpr_malloc(sizeof(grpc_cq_completion)));
     opt->events_triggered++;
   }
 
diff --git a/test/core/util/test_config.c b/test/core/util/test_config.c
index 20ab67e..225658f 100644
--- a/test/core/util/test_config.c
+++ b/test/core/util/test_config.c
@@ -48,7 +48,45 @@
 static int seed(void) { return _getpid(); }
 #endif
 
+#if GPR_WINDOWS_CRASH_HANDLER
+LONG crash_handler(struct _EXCEPTION_POINTERS* ex_info) {
+  gpr_log(GPR_DEBUG, "Exception handler called, dumping information");
+  while (ex_info->ExceptionRecord) {
+    DWORD code = ex_info->ExceptionRecord->ExceptionCode;
+    DWORD flgs = ex_info->ExceptionRecord->ExceptionFlags;
+    PVOID addr = ex_info->ExceptionRecord->ExceptionAddress;
+    gpr_log("code: %x - flags: %d - address: %p", code, flgs, addr);
+    ex_info->ExceptionRecord = ex_info->ExceptionRecord->ExceptionRecord;
+  }
+  if (IsDebuggerPresent()) {
+    __debugbreak();
+  } else {
+    _exit(1);
+  }
+  return EXCEPTION_EXECUTE_HANDLER;
+}
+
+void abort_handler(int sig) {
+  gpr_log(GPR_DEBUG, "Abort handler called.");
+  if (IsDebuggerPresent()) {
+    __debugbreak();
+  } else {
+    _exit(1);
+  }
+}
+
+static void install_crash_handler() {
+  SetUnhandledExceptionFilter((LPTOP_LEVEL_EXCEPTION_FILTER) crash_handler);
+  _set_abort_behavior(0, _WRITE_ABORT_MSG);
+  _set_abort_behavior(0, _CALL_REPORTFAULT);
+  signal(SIGABRT, abort_handler);
+}
+#else
+static void install_crash_handler() { }
+#endif
+
 void grpc_test_init(int argc, char **argv) {
+  install_crash_handler();
   gpr_log(GPR_DEBUG, "test slowdown: machine=%f build=%f total=%f",
           (double)GRPC_TEST_SLOWDOWN_MACHINE_FACTOR,
           (double)GRPC_TEST_SLOWDOWN_BUILD_FACTOR,
diff --git a/test/core/util/test_config.h b/test/core/util/test_config.h
index 0b3c543..3218953 100644
--- a/test/core/util/test_config.h
+++ b/test/core/util/test_config.h
@@ -52,11 +52,11 @@
   (GRPC_TEST_SLOWDOWN_BUILD_FACTOR * GRPC_TEST_SLOWDOWN_MACHINE_FACTOR)
 
 #define GRPC_TIMEOUT_SECONDS_TO_DEADLINE(x) \
-  gpr_time_add(gpr_now(),                   \
+  gpr_time_add(gpr_now(GPR_CLOCK_REALTIME), \
                gpr_time_from_micros(GRPC_TEST_SLOWDOWN_FACTOR * 1e6 * (x)))
 
-#define GRPC_TIMEOUT_MILLIS_TO_DEADLINE(x) \
-  gpr_time_add(gpr_now(),                  \
+#define GRPC_TIMEOUT_MILLIS_TO_DEADLINE(x)  \
+  gpr_time_add(gpr_now(GPR_CLOCK_REALTIME), \
                gpr_time_from_micros(GRPC_TEST_SLOWDOWN_FACTOR * 1e3 * (x)))
 
 #ifndef GRPC_TEST_CUSTOM_PICK_PORT
@@ -69,4 +69,4 @@
 }
 #endif /*  __cplusplus */
 
-#endif  /* GRPC_TEST_CORE_UTIL_TEST_CONFIG_H */
+#endif /* GRPC_TEST_CORE_UTIL_TEST_CONFIG_H */
diff --git a/test/cpp/common/secure_auth_context_test.cc b/test/cpp/common/secure_auth_context_test.cc
index 6f8fb8f..a1819dc 100644
--- a/test/cpp/common/secure_auth_context_test.cc
+++ b/test/cpp/common/secure_auth_context_test.cc
@@ -59,12 +59,12 @@
 
   SecureAuthContext context(ctx);
   std::vector<grpc::string> peer_identity = context.GetPeerIdentity();
-  EXPECT_EQ(2, peer_identity.size());
+  EXPECT_EQ(2u, peer_identity.size());
   EXPECT_EQ("chapi", peer_identity[0]);
   EXPECT_EQ("chapo", peer_identity[1]);
   EXPECT_EQ("name", context.GetPeerIdentityPropertyName());
   std::vector<grpc::string> bar = context.FindPropertyValues("foo");
-  EXPECT_EQ(1, bar.size());
+  EXPECT_EQ(1u, bar.size());
   EXPECT_EQ("bar", bar[0]);
 }
 
diff --git a/test/cpp/end2end/end2end_test.cc b/test/cpp/end2end/end2end_test.cc
index 0912b19..207dad5 100644
--- a/test/cpp/end2end/end2end_test.cc
+++ b/test/cpp/end2end/end2end_test.cc
@@ -88,7 +88,7 @@
   std::shared_ptr<const AuthContext> auth_ctx = context->auth_context();
   std::vector<grpc::string> fake =
       auth_ctx->FindPropertyValues("transport_security_type");
-  EXPECT_EQ(1, fake.size());
+  EXPECT_EQ(1u, fake.size());
   EXPECT_EQ("fake", fake[0]);
   EXPECT_TRUE(auth_ctx->GetPeerIdentityPropertyName().empty());
   EXPECT_TRUE(auth_ctx->GetPeerIdentity().empty());
@@ -98,8 +98,9 @@
 
 class TestServiceImpl : public ::grpc::cpp::test::util::TestService::Service {
  public:
-  TestServiceImpl() : signal_client_(false), host_(nullptr) {}
-  explicit TestServiceImpl(const grpc::string& host) : signal_client_(false), host_(new grpc::string(host)) {}
+  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 {
@@ -115,15 +116,15 @@
       }
       while (!context->IsCancelled()) {
         gpr_sleep_until(gpr_time_add(
-            gpr_now(),
+            gpr_now(GPR_CLOCK_REALTIME),
             gpr_time_from_micros(request->param().client_cancel_after_us())));
       }
       return Status::CANCELLED;
     } else if (request->has_param() &&
                request->param().server_cancel_after_us()) {
       gpr_sleep_until(gpr_time_add(
-            gpr_now(),
-            gpr_time_from_micros(request->param().server_cancel_after_us())));
+          gpr_now(GPR_CLOCK_REALTIME),
+          gpr_time_from_micros(request->param().server_cancel_after_us())));
       return Status::CANCELLED;
     } else {
       EXPECT_FALSE(context->IsCancelled());
@@ -224,7 +225,8 @@
 
 class End2endTest : public ::testing::Test {
  protected:
-  End2endTest() : kMaxMessageSize_(8192), special_service_("special"), thread_pool_(2) {}
+  End2endTest()
+      : kMaxMessageSize_(8192), special_service_("special"), thread_pool_(2) {}
 
   void SetUp() GRPC_OVERRIDE {
     int port = grpc_pick_unused_port_or_die();
@@ -527,7 +529,8 @@
 }
 
 void CancelRpc(ClientContext* context, int delay_us, TestServiceImpl* service) {
-  gpr_sleep_until(gpr_time_add(gpr_now(), gpr_time_from_micros(delay_us)));
+  gpr_sleep_until(gpr_time_add(gpr_now(GPR_CLOCK_REALTIME),
+                               gpr_time_from_micros(delay_us)));
   while (!service->signal_client()) {
   }
   context->TryCancel();
diff --git a/test/cpp/end2end/mock_test.cc b/test/cpp/end2end/mock_test.cc
index 2809ab8..59a8edf 100644
--- a/test/cpp/end2end/mock_test.cc
+++ b/test/cpp/end2end/mock_test.cc
@@ -86,7 +86,9 @@
     msg->set_message(last_message_);
     return true;
   }
-  bool Write(const EchoRequest& msg) GRPC_OVERRIDE {
+
+  bool Write(const EchoRequest& msg,
+             const WriteOptions& options) GRPC_OVERRIDE {
     gpr_log(GPR_INFO, "mock recv msg %s", msg.message().c_str());
     last_message_ = msg.message();
     return true;
diff --git a/test/cpp/end2end/server_crash_test.cc b/test/cpp/end2end/server_crash_test.cc
index 3fdae9b..4d4d590 100644
--- a/test/cpp/end2end/server_crash_test.cc
+++ b/test/cpp/end2end/server_crash_test.cc
@@ -84,7 +84,8 @@
       gpr_log(GPR_INFO, "recv msg %s", request.message().c_str());
       response.set_message(request.message());
       stream->Write(response);
-      gpr_sleep_until(gpr_time_add(gpr_now(), gpr_time_from_seconds(1)));
+      gpr_sleep_until(
+          gpr_time_add(gpr_now(GPR_CLOCK_REALTIME), gpr_time_from_seconds(1)));
     }
     return Status::OK;
   }
@@ -98,7 +99,8 @@
       msg << "Hello " << i;
       response.set_message(msg.str());
       if (!writer->Write(response)) break;
-      gpr_sleep_until(gpr_time_add(gpr_now(), gpr_time_from_seconds(1)));
+      gpr_sleep_until(
+          gpr_time_add(gpr_now(GPR_CLOCK_REALTIME), gpr_time_from_seconds(1)));
     }
     return Status::OK;
   }
@@ -145,7 +147,8 @@
 TEST_F(CrashTest, ResponseStream) {
   auto server = CreateServerAndClient("response");
 
-  gpr_sleep_until(gpr_time_add(gpr_now(), gpr_time_from_seconds(5)));
+  gpr_sleep_until(
+      gpr_time_add(gpr_now(GPR_CLOCK_REALTIME), gpr_time_from_seconds(5)));
   KillClient();
   server->Shutdown();
   GPR_ASSERT(HadOneResponseStream());
@@ -154,7 +157,8 @@
 TEST_F(CrashTest, BidiStream) {
   auto server = CreateServerAndClient("bidi");
 
-  gpr_sleep_until(gpr_time_add(gpr_now(), gpr_time_from_seconds(5)));
+  gpr_sleep_until(
+      gpr_time_add(gpr_now(GPR_CLOCK_REALTIME), gpr_time_from_seconds(5)));
   KillClient();
   server->Shutdown();
   GPR_ASSERT(HadOneBidiStream());
diff --git a/test/cpp/end2end/thread_stress_test.cc b/test/cpp/end2end/thread_stress_test.cc
index 0b43dfd..0b4d942 100644
--- a/test/cpp/end2end/thread_stress_test.cc
+++ b/test/cpp/end2end/thread_stress_test.cc
@@ -96,14 +96,14 @@
       }
       while (!context->IsCancelled()) {
         gpr_sleep_until(gpr_time_add(
-            gpr_now(),
+            gpr_now(GPR_CLOCK_REALTIME),
             gpr_time_from_micros(request->param().client_cancel_after_us())));
       }
       return Status::CANCELLED;
     } else if (request->has_param() &&
                request->param().server_cancel_after_us()) {
       gpr_sleep_until(gpr_time_add(
-          gpr_now(),
+          gpr_now(GPR_CLOCK_REALTIME),
           gpr_time_from_micros(request->param().server_cancel_after_us())));
       return Status::CANCELLED;
     } else {
diff --git a/test/cpp/qps/driver.cc b/test/cpp/qps/driver.cc
index c8cc11e..5597bcd 100644
--- a/test/cpp/qps/driver.cc
+++ b/test/cpp/qps/driver.cc
@@ -185,7 +185,7 @@
 
   // Let everything warmup
   gpr_log(GPR_INFO, "Warming up");
-  gpr_timespec start = gpr_now();
+  gpr_timespec start = gpr_now(GPR_CLOCK_REALTIME);
   gpr_sleep_until(gpr_time_add(start, gpr_time_from_seconds(warmup_seconds)));
 
   // Start a run
diff --git a/test/cpp/qps/qps_test_openloop.cc b/test/cpp/qps/qps_openloop_test.cc
similarity index 100%
rename from test/cpp/qps/qps_test_openloop.cc
rename to test/cpp/qps/qps_openloop_test.cc
diff --git a/test/cpp/qps/timer.cc b/test/cpp/qps/timer.cc
index d1b6bc1..07289f6 100644
--- a/test/cpp/qps/timer.cc
+++ b/test/cpp/qps/timer.cc
@@ -41,7 +41,7 @@
 Timer::Timer() : start_(Sample()) {}
 
 double Timer::Now() {
-  auto ts = gpr_now();
+  auto ts = gpr_now(GPR_CLOCK_REALTIME);
   return ts.tv_sec + 1e-9 * ts.tv_nsec;
 }
 
diff --git a/test/cpp/qps/worker.cc b/test/cpp/qps/worker.cc
index 14a8b0b..2bc0a56 100644
--- a/test/cpp/qps/worker.cc
+++ b/test/cpp/qps/worker.cc
@@ -57,7 +57,8 @@
   QpsWorker worker(FLAGS_driver_port, FLAGS_server_port);
 
   while (!got_sigint) {
-    gpr_sleep_until(gpr_time_add(gpr_now(), gpr_time_from_seconds(5)));
+    gpr_sleep_until(
+        gpr_time_add(gpr_now(GPR_CLOCK_REALTIME), gpr_time_from_seconds(5)));
   }
 }
 
diff --git a/tools/buildgen/generate_projects.py b/tools/buildgen/generate_projects.py
index 1964ceb..5de0635 100755
--- a/tools/buildgen/generate_projects.py
+++ b/tools/buildgen/generate_projects.py
@@ -48,30 +48,33 @@
 
 jobs = []
 for root, dirs, files in os.walk('templates'):
-	for f in files:
-		if os.path.splitext(f)[1] == '.template':
-			out = '.' + root[len('templates'):] + '/' + os.path.splitext(f)[0]
-			cmd = ['tools/buildgen/mako_renderer.py']
-			for plugin in plugins:
-				cmd.append('-p')
-				cmd.append(plugin)
-			for js in json:
-				cmd.append('-d')
-				cmd.append(js)
-			cmd.append('-o')
-			if test is None:
-				cmd.append(out)
-			else:
-				tf = tempfile.mkstemp()
-				test[out] = tf[1]
-				os.close(tf[0])
-				cmd.append(test[out])
-			cmd.append(root + '/' + f)
-			jobs.append(jobset.JobSpec(cmd, shortname=out))
+  for f in files:
+    if os.path.splitext(f)[1] == '.template':
+      out_dir = '.' + root[len('templates'):]
+      out = out_dir + '/' + os.path.splitext(f)[0]
+      if not os.path.exists(out_dir):
+        os.makedirs(out_dir)
+      cmd = ['tools/buildgen/mako_renderer.py']
+      for plugin in plugins:
+        cmd.append('-p')
+        cmd.append(plugin)
+      for js in json:
+        cmd.append('-d')
+        cmd.append(js)
+      cmd.append('-o')
+      if test is None:
+        cmd.append(out)
+      else:
+        tf = tempfile.mkstemp()
+        test[out] = tf[1]
+        os.close(tf[0])
+        cmd.append(test[out])
+      cmd.append(root + '/' + f)
+      jobs.append(jobset.JobSpec(cmd, shortname=out))
 
 jobset.run(jobs)
 
 if test is not None:
-	for s, g in test.iteritems():
-		assert(0 == os.system('diff %s %s' % (s, g)))
-		os.unlink(g)
+  for s, g in test.iteritems():
+    assert(0 == os.system('diff %s %s' % (s, g)))
+    os.unlink(g)
diff --git a/tools/doxygen/Doxyfile.core.internal b/tools/doxygen/Doxyfile.core.internal
index ac411e3..a658f1a 100644
--- a/tools/doxygen/Doxyfile.core.internal
+++ b/tools/doxygen/Doxyfile.core.internal
@@ -985,6 +985,7 @@
 src/core/surface/server_chttp2.c \
 src/core/surface/server_create.c \
 src/core/surface/surface_trace.c \
+src/core/surface/version.c \
 src/core/transport/chttp2/alpn.c \
 src/core/transport/chttp2/bin_encoder.c \
 src/core/transport/chttp2/frame_data.c \
@@ -1044,6 +1045,7 @@
 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 \
@@ -1070,6 +1072,7 @@
 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 \
diff --git a/tools/jenkins/grpc_linuxbrew/Dockerfile b/tools/jenkins/grpc_linuxbrew/Dockerfile
new file mode 100644
index 0000000..9b76e3c
--- /dev/null
+++ b/tools/jenkins/grpc_linuxbrew/Dockerfile
@@ -0,0 +1,62 @@
+# 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.
+
+# A work-in-progress Dockerfile that allows running gRPC homebrew
+# installations inside docker containers
+FROM debian:jessie
+
+# Core dependencies
+RUN apt-get update && apt-get install -y \
+  bzip2 curl git ruby wget
+
+# Install linuxbrew
+ENV PATH /home/linuxbrew/.linuxbrew/bin:/home/linuxbrew/.linuxbrew/sbin:$PATH
+RUN git clone https://github.com/Homebrew/linuxbrew.git /home/linuxbrew/.linuxbrew
+RUN brew doctor || true
+
+# Python dependency
+RUN apt-get update && apt-get install -y python-dev
+RUN curl https://bootstrap.pypa.io/get-pip.py | python
+
+# NodeJS dependency
+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"
+
+# Ruby dependency
+RUN gpg --keyserver hkp://keys.gnupg.net --recv-keys 409B6B1796C275462A1703113804BB82D39DC0E3
+RUN /bin/bash -l -c "\curl -sSL https://get.rvm.io | bash -s stable"
+RUN /bin/bash -l -c "rvm install ruby-2.1"
+
+# PHP dependency
+RUN apt-get update && apt-get install -y php5 php5-dev phpunit unzip
+
+RUN /bin/bash -l -c "echo 'export PATH=/home/linuxbrew/.linuxbrew/bin:\$PATH' >> ~/.bashrc"
+
+CMD ["bash"]
diff --git a/tools/jenkins/run_jenkins.sh b/tools/jenkins/run_jenkins.sh
index 88476b5..af49ea0 100755
--- a/tools/jenkins/run_jenkins.sh
+++ b/tools/jenkins/run_jenkins.sh
@@ -70,7 +70,8 @@
   DOCKER_CID=`cat docker.cid`
   docker kill $DOCKER_CID
   docker cp $DOCKER_CID:/var/local/git/grpc/report.xml $git_root
-  docker rm $DOCKER_CID
+  sleep 4
+  docker rm $DOCKER_CID || true
 
 elif [ "$platform" == "windows" ]
 then
@@ -83,12 +84,12 @@
   /cygdrive/c/nuget/nuget.exe restore vsprojects/grpc.sln
   /cygdrive/c/nuget/nuget.exe restore src/csharp/Grpc.sln
 
-  python tools/run_tests/run_tests.py -t -l $language -x report.xml
+  python tools/run_tests/run_tests.py -t -l $language -x report.xml || true
 elif [ "$platform" == "macos" ]
 then
   echo "building $language on MacOS"
 
-  ./tools/run_tests/run_tests.py -t -l $language -c $config -x report.xml
+  ./tools/run_tests/run_tests.py -t -l $language -c $config -x report.xml || true
 else
   echo "Unknown platform $platform"
   exit 1
diff --git a/tools/jenkins/run_linuxbrew.sh b/tools/jenkins/run_linuxbrew.sh
new file mode 100755
index 0000000..10c41b4
--- /dev/null
+++ b/tools/jenkins/run_linuxbrew.sh
@@ -0,0 +1,55 @@
+#!/bin/bash
+# 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.
+#
+# This script is invoked by Jenkins and triggers a test run of
+# linuxbrew installation of a selected language
+set -ex
+
+sha1=$(sha1sum tools/jenkins/grpc_linuxbrew/Dockerfile | cut -f1 -d\ )
+DOCKER_IMAGE_NAME=grpc_linuxbrew_$sha1
+
+docker build -t $DOCKER_IMAGE_NAME tools/jenkins/grpc_linuxbrew
+
+supported="python nodejs ruby php"
+
+if [ "$language" == "core" ]; then
+  command="curl -fsSL https://goo.gl/getgrpc | bash -"
+elif [[ "$supported" =~ "$language" ]]; then
+  command="curl -fsSL https://goo.gl/getgrpc | bash -s $language"
+else
+  echo "unsupported language $language"
+  exit 1
+fi
+
+docker run $DOCKER_IMAGE_NAME bash -l \
+  -c "nvm use 0.12; \
+      npm set unsafe-perm true; \
+      rvm use ruby-2.1; \
+      $command"
diff --git a/tools/run_tests/jobset.py b/tools/run_tests/jobset.py
index e513814..46137f0 100755
--- a/tools/run_tests/jobset.py
+++ b/tools/run_tests/jobset.py
@@ -206,13 +206,14 @@
                 do_newline=self._newline_on_success or self._travis)
         if self._bin_hash:
           update_cache.finished(self._spec.identity(), self._bin_hash)
-    elif self._state == _RUNNING and time.time() - self._start > 300:
+    elif self._state == _RUNNING and time.time() - self._start > 600:
       self._tempfile.seek(0)
       stdout = self._tempfile.read()
+      filtered_stdout = filter(lambda x: x in string.printable, stdout.decode(errors='ignore'))
       message('TIMEOUT', self._spec.shortname, stdout, do_newline=True)
       self.kill()
       if self._xml_test is not None:
-        ET.SubElement(self._xml_test, 'system-out').text = stdout
+        ET.SubElement(self._xml_test, 'system-out').text = filtered_stdout
         ET.SubElement(self._xml_test, 'error', message='Timeout')
     return self._state
 
diff --git a/tools/run_tests/python_tests.json b/tools/run_tests/python_tests.json
index 4da4c1b..3d75d8d 100755
--- a/tools/run_tests/python_tests.json
+++ b/tools/run_tests/python_tests.json
@@ -1,18 +1,5 @@
 [
   {
-    "module": "grpc._cython.cygrpc_test",
-    "pythonVersions": [
-      "2.7",
-      "3.4"
-    ]
-  },
-  {
-    "module": "grpc._cython.adapter_low_test",
-    "pythonVersions": [
-      "2.7"
-    ]
-  },
-  {
     "module": "grpc._adapter._c_test",
     "pythonVersions": [
       "2.7"
@@ -61,6 +48,18 @@
     ]
   },
   {
+    "module": "grpc._links._lonely_invocation_link_test",
+    "pythonVersions": [
+      "2.7"
+    ]
+  },
+  {
+    "module": "grpc._links._transmission_test",
+    "pythonVersions": [
+      "2.7"
+    ]
+  },
+  {
     "module": "grpc.early_adopter.implementations_test",
     "pythonVersions": [
       "2.7"
diff --git a/tools/run_tests/sources_and_headers.json b/tools/run_tests/sources_and_headers.json
index 1fc5c20..8daee3c 100644
--- a/tools/run_tests/sources_and_headers.json
+++ b/tools/run_tests/sources_and_headers.json
@@ -338,6 +338,18 @@
     ], 
     "headers": [], 
     "language": "c", 
+    "name": "gpr_stack_lockfree_test", 
+    "src": [
+      "test/core/support/stack_lockfree_test.c"
+    ]
+  }, 
+  {
+    "deps": [
+      "gpr", 
+      "gpr_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
     "name": "gpr_string_test", 
     "src": [
       "test/core/support/string_test.c"
@@ -1437,9 +1449,9 @@
     ], 
     "headers": [], 
     "language": "c++", 
-    "name": "qps_test", 
+    "name": "qps_openloop_test", 
     "src": [
-      "test/cpp/qps/qps_test.cc"
+      "test/cpp/qps/qps_openloop_test.cc"
     ]
   }, 
   {
@@ -1455,9 +1467,9 @@
     ], 
     "headers": [], 
     "language": "c++", 
-    "name": "qps_test_openloop", 
+    "name": "qps_test", 
     "src": [
-      "test/cpp/qps/qps_test_openloop.cc"
+      "test/cpp/qps/qps_test.cc"
     ]
   }, 
   {
@@ -8608,6 +8620,7 @@
       "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"
@@ -8669,6 +8682,8 @@
       "src/core/support/murmur_hash.h", 
       "src/core/support/slice.c", 
       "src/core/support/slice_buffer.c", 
+      "src/core/support/stack_lockfree.c", 
+      "src/core/support/stack_lockfree.h", 
       "src/core/support/string.c", 
       "src/core/support/string.h", 
       "src/core/support/string_posix.c", 
@@ -9025,6 +9040,7 @@
       "src/core/surface/server_create.c", 
       "src/core/surface/surface_trace.c", 
       "src/core/surface/surface_trace.h", 
+      "src/core/surface/version.c", 
       "src/core/transport/chttp2/alpn.c", 
       "src/core/transport/chttp2/alpn.h", 
       "src/core/transport/chttp2/bin_encoder.c", 
@@ -9426,6 +9442,7 @@
       "src/core/surface/server_create.c", 
       "src/core/surface/surface_trace.c", 
       "src/core/surface/surface_trace.h", 
+      "src/core/surface/version.c", 
       "src/core/transport/chttp2/alpn.c", 
       "src/core/transport/chttp2/alpn.h", 
       "src/core/transport/chttp2/bin_encoder.c", 
diff --git a/tools/run_tests/tests.json b/tools/run_tests/tests.json
index cc05870..3a22ba9 100644
--- a/tools/run_tests/tests.json
+++ b/tools/run_tests/tests.json
@@ -197,6 +197,15 @@
   {
     "flaky": false, 
     "language": "c", 
+    "name": "gpr_stack_lockfree_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
+  }, 
+  {
+    "flaky": false, 
+    "language": "c", 
     "name": "gpr_string_test", 
     "platforms": [
       "windows", 
@@ -705,7 +714,7 @@
   {
     "flaky": false, 
     "language": "c++", 
-    "name": "qps_test", 
+    "name": "qps_openloop_test", 
     "platforms": [
       "windows", 
       "posix"
@@ -714,7 +723,7 @@
   {
     "flaky": false, 
     "language": "c++", 
-    "name": "qps_test_openloop", 
+    "name": "qps_test", 
     "platforms": [
       "windows", 
       "posix"
diff --git a/vsprojects/Grpc.mak b/vsprojects/Grpc.mak
index d9b2255..1e35a0b 100644
--- a/vsprojects/Grpc.mak
+++ b/vsprojects/Grpc.mak
@@ -51,13 +51,19 @@
 
 all: buildtests
 
+tools:
+
+tools_c:
+
+tools_cxx:
+
 $(OUT_DIR):
 	mkdir $(OUT_DIR)
 
 build_libs: build_gpr build_gpr_test_util build_grpc build_grpc_test_util build_grpc_test_util_unsecure build_grpc_unsecure Debug\end2end_fixture_chttp2_fake_security.lib Debug\end2end_fixture_chttp2_fullstack.lib Debug\end2end_fixture_chttp2_simple_ssl_fullstack.lib Debug\end2end_fixture_chttp2_simple_ssl_with_oauth2_fullstack.lib Debug\end2end_fixture_chttp2_socket_pair.lib Debug\end2end_fixture_chttp2_socket_pair_one_byte_at_a_time.lib Debug\end2end_fixture_chttp2_socket_pair_with_grpc_trace.lib Debug\end2end_test_bad_hostname.lib Debug\end2end_test_cancel_after_accept.lib Debug\end2end_test_cancel_after_accept_and_writes_closed.lib Debug\end2end_test_cancel_after_invoke.lib Debug\end2end_test_cancel_before_invoke.lib Debug\end2end_test_cancel_in_a_vacuum.lib Debug\end2end_test_census_simple_request.lib Debug\end2end_test_disappearing_server.lib Debug\end2end_test_early_server_shutdown_finishes_inflight_calls.lib Debug\end2end_test_early_server_shutdown_finishes_tags.lib Debug\end2end_test_empty_batch.lib Debug\end2end_test_graceful_server_shutdown.lib Debug\end2end_test_invoke_large_request.lib Debug\end2end_test_max_concurrent_streams.lib Debug\end2end_test_max_message_length.lib Debug\end2end_test_no_op.lib Debug\end2end_test_ping_pong_streaming.lib Debug\end2end_test_registered_call.lib Debug\end2end_test_request_response_with_binary_metadata_and_payload.lib Debug\end2end_test_request_response_with_metadata_and_payload.lib Debug\end2end_test_request_response_with_payload.lib Debug\end2end_test_request_response_with_payload_and_call_creds.lib Debug\end2end_test_request_response_with_trailing_metadata_and_payload.lib Debug\end2end_test_request_with_flags.lib Debug\end2end_test_request_with_large_metadata.lib Debug\end2end_test_request_with_payload.lib Debug\end2end_test_server_finishes_request.lib Debug\end2end_test_simple_delayed_request.lib Debug\end2end_test_simple_request.lib Debug\end2end_test_simple_request_with_high_initial_sequence_number.lib Debug\end2end_certs.lib Debug\bad_client_test.lib 
 buildtests: buildtests_c buildtests_cxx
 
-buildtests_c: alarm_heap_test.exe alarm_list_test.exe alarm_test.exe alpn_test.exe bin_encoder_test.exe chttp2_status_conversion_test.exe chttp2_stream_encoder_test.exe chttp2_stream_map_test.exe fling_client.exe fling_server.exe gpr_cancellable_test.exe gpr_cmdline_test.exe gpr_env_test.exe gpr_file_test.exe gpr_histogram_test.exe gpr_host_port_test.exe gpr_log_test.exe gpr_slice_buffer_test.exe gpr_slice_test.exe gpr_string_test.exe gpr_sync_test.exe gpr_thd_test.exe gpr_time_test.exe gpr_tls_test.exe gpr_useful_test.exe grpc_auth_context_test.exe grpc_base64_test.exe grpc_byte_buffer_reader_test.exe grpc_channel_stack_test.exe grpc_completion_queue_test.exe grpc_credentials_test.exe grpc_json_token_test.exe grpc_jwt_verifier_test.exe grpc_security_connector_test.exe grpc_stream_op_test.exe hpack_parser_test.exe hpack_table_test.exe httpcli_format_request_test.exe httpcli_parser_test.exe json_rewrite.exe json_rewrite_test.exe json_test.exe lame_client_test.exe message_compress_test.exe multi_init_test.exe multiple_server_queues_test.exe murmur_hash_test.exe no_server_test.exe resolve_address_test.exe secure_endpoint_test.exe sockaddr_utils_test.exe time_averaged_stats_test.exe time_test.exe timeout_encoding_test.exe timers_test.exe transport_metadata_test.exe transport_security_test.exe uri_parser_test.exe chttp2_fake_security_bad_hostname_test.exe chttp2_fake_security_cancel_after_accept_test.exe chttp2_fake_security_cancel_after_accept_and_writes_closed_test.exe chttp2_fake_security_cancel_after_invoke_test.exe chttp2_fake_security_cancel_before_invoke_test.exe chttp2_fake_security_cancel_in_a_vacuum_test.exe chttp2_fake_security_census_simple_request_test.exe chttp2_fake_security_disappearing_server_test.exe chttp2_fake_security_early_server_shutdown_finishes_inflight_calls_test.exe chttp2_fake_security_early_server_shutdown_finishes_tags_test.exe chttp2_fake_security_empty_batch_test.exe chttp2_fake_security_graceful_server_shutdown_test.exe chttp2_fake_security_invoke_large_request_test.exe chttp2_fake_security_max_concurrent_streams_test.exe chttp2_fake_security_max_message_length_test.exe chttp2_fake_security_no_op_test.exe chttp2_fake_security_ping_pong_streaming_test.exe chttp2_fake_security_registered_call_test.exe chttp2_fake_security_request_response_with_binary_metadata_and_payload_test.exe chttp2_fake_security_request_response_with_metadata_and_payload_test.exe chttp2_fake_security_request_response_with_payload_test.exe chttp2_fake_security_request_response_with_payload_and_call_creds_test.exe chttp2_fake_security_request_response_with_trailing_metadata_and_payload_test.exe chttp2_fake_security_request_with_flags_test.exe chttp2_fake_security_request_with_large_metadata_test.exe chttp2_fake_security_request_with_payload_test.exe chttp2_fake_security_server_finishes_request_test.exe chttp2_fake_security_simple_delayed_request_test.exe chttp2_fake_security_simple_request_test.exe chttp2_fake_security_simple_request_with_high_initial_sequence_number_test.exe chttp2_fullstack_bad_hostname_test.exe chttp2_fullstack_cancel_after_accept_test.exe chttp2_fullstack_cancel_after_accept_and_writes_closed_test.exe chttp2_fullstack_cancel_after_invoke_test.exe chttp2_fullstack_cancel_before_invoke_test.exe chttp2_fullstack_cancel_in_a_vacuum_test.exe chttp2_fullstack_census_simple_request_test.exe chttp2_fullstack_disappearing_server_test.exe chttp2_fullstack_early_server_shutdown_finishes_inflight_calls_test.exe chttp2_fullstack_early_server_shutdown_finishes_tags_test.exe chttp2_fullstack_empty_batch_test.exe chttp2_fullstack_graceful_server_shutdown_test.exe chttp2_fullstack_invoke_large_request_test.exe chttp2_fullstack_max_concurrent_streams_test.exe chttp2_fullstack_max_message_length_test.exe chttp2_fullstack_no_op_test.exe chttp2_fullstack_ping_pong_streaming_test.exe chttp2_fullstack_registered_call_test.exe chttp2_fullstack_request_response_with_binary_metadata_and_payload_test.exe chttp2_fullstack_request_response_with_metadata_and_payload_test.exe chttp2_fullstack_request_response_with_payload_test.exe chttp2_fullstack_request_response_with_payload_and_call_creds_test.exe chttp2_fullstack_request_response_with_trailing_metadata_and_payload_test.exe chttp2_fullstack_request_with_flags_test.exe chttp2_fullstack_request_with_large_metadata_test.exe chttp2_fullstack_request_with_payload_test.exe chttp2_fullstack_server_finishes_request_test.exe chttp2_fullstack_simple_delayed_request_test.exe chttp2_fullstack_simple_request_test.exe chttp2_fullstack_simple_request_with_high_initial_sequence_number_test.exe chttp2_simple_ssl_fullstack_bad_hostname_test.exe chttp2_simple_ssl_fullstack_cancel_after_accept_test.exe chttp2_simple_ssl_fullstack_cancel_after_accept_and_writes_closed_test.exe chttp2_simple_ssl_fullstack_cancel_after_invoke_test.exe chttp2_simple_ssl_fullstack_cancel_before_invoke_test.exe chttp2_simple_ssl_fullstack_cancel_in_a_vacuum_test.exe chttp2_simple_ssl_fullstack_census_simple_request_test.exe chttp2_simple_ssl_fullstack_disappearing_server_test.exe chttp2_simple_ssl_fullstack_early_server_shutdown_finishes_inflight_calls_test.exe chttp2_simple_ssl_fullstack_early_server_shutdown_finishes_tags_test.exe chttp2_simple_ssl_fullstack_empty_batch_test.exe chttp2_simple_ssl_fullstack_graceful_server_shutdown_test.exe chttp2_simple_ssl_fullstack_invoke_large_request_test.exe chttp2_simple_ssl_fullstack_max_concurrent_streams_test.exe chttp2_simple_ssl_fullstack_max_message_length_test.exe chttp2_simple_ssl_fullstack_no_op_test.exe chttp2_simple_ssl_fullstack_ping_pong_streaming_test.exe chttp2_simple_ssl_fullstack_registered_call_test.exe chttp2_simple_ssl_fullstack_request_response_with_binary_metadata_and_payload_test.exe chttp2_simple_ssl_fullstack_request_response_with_metadata_and_payload_test.exe chttp2_simple_ssl_fullstack_request_response_with_payload_test.exe chttp2_simple_ssl_fullstack_request_response_with_payload_and_call_creds_test.exe chttp2_simple_ssl_fullstack_request_response_with_trailing_metadata_and_payload_test.exe chttp2_simple_ssl_fullstack_request_with_flags_test.exe chttp2_simple_ssl_fullstack_request_with_large_metadata_test.exe chttp2_simple_ssl_fullstack_request_with_payload_test.exe chttp2_simple_ssl_fullstack_server_finishes_request_test.exe chttp2_simple_ssl_fullstack_simple_delayed_request_test.exe chttp2_simple_ssl_fullstack_simple_request_test.exe chttp2_simple_ssl_fullstack_simple_request_with_high_initial_sequence_number_test.exe chttp2_simple_ssl_with_oauth2_fullstack_bad_hostname_test.exe chttp2_simple_ssl_with_oauth2_fullstack_cancel_after_accept_test.exe chttp2_simple_ssl_with_oauth2_fullstack_cancel_after_accept_and_writes_closed_test.exe chttp2_simple_ssl_with_oauth2_fullstack_cancel_after_invoke_test.exe chttp2_simple_ssl_with_oauth2_fullstack_cancel_before_invoke_test.exe chttp2_simple_ssl_with_oauth2_fullstack_cancel_in_a_vacuum_test.exe chttp2_simple_ssl_with_oauth2_fullstack_census_simple_request_test.exe chttp2_simple_ssl_with_oauth2_fullstack_disappearing_server_test.exe chttp2_simple_ssl_with_oauth2_fullstack_early_server_shutdown_finishes_inflight_calls_test.exe chttp2_simple_ssl_with_oauth2_fullstack_early_server_shutdown_finishes_tags_test.exe chttp2_simple_ssl_with_oauth2_fullstack_empty_batch_test.exe chttp2_simple_ssl_with_oauth2_fullstack_graceful_server_shutdown_test.exe chttp2_simple_ssl_with_oauth2_fullstack_invoke_large_request_test.exe chttp2_simple_ssl_with_oauth2_fullstack_max_concurrent_streams_test.exe chttp2_simple_ssl_with_oauth2_fullstack_max_message_length_test.exe chttp2_simple_ssl_with_oauth2_fullstack_no_op_test.exe chttp2_simple_ssl_with_oauth2_fullstack_ping_pong_streaming_test.exe chttp2_simple_ssl_with_oauth2_fullstack_registered_call_test.exe chttp2_simple_ssl_with_oauth2_fullstack_request_response_with_binary_metadata_and_payload_test.exe chttp2_simple_ssl_with_oauth2_fullstack_request_response_with_metadata_and_payload_test.exe chttp2_simple_ssl_with_oauth2_fullstack_request_response_with_payload_test.exe chttp2_simple_ssl_with_oauth2_fullstack_request_response_with_payload_and_call_creds_test.exe chttp2_simple_ssl_with_oauth2_fullstack_request_response_with_trailing_metadata_and_payload_test.exe chttp2_simple_ssl_with_oauth2_fullstack_request_with_flags_test.exe chttp2_simple_ssl_with_oauth2_fullstack_request_with_large_metadata_test.exe chttp2_simple_ssl_with_oauth2_fullstack_request_with_payload_test.exe chttp2_simple_ssl_with_oauth2_fullstack_server_finishes_request_test.exe chttp2_simple_ssl_with_oauth2_fullstack_simple_delayed_request_test.exe chttp2_simple_ssl_with_oauth2_fullstack_simple_request_test.exe chttp2_simple_ssl_with_oauth2_fullstack_simple_request_with_high_initial_sequence_number_test.exe chttp2_socket_pair_bad_hostname_test.exe chttp2_socket_pair_cancel_after_accept_test.exe chttp2_socket_pair_cancel_after_accept_and_writes_closed_test.exe chttp2_socket_pair_cancel_after_invoke_test.exe chttp2_socket_pair_cancel_before_invoke_test.exe chttp2_socket_pair_cancel_in_a_vacuum_test.exe chttp2_socket_pair_census_simple_request_test.exe chttp2_socket_pair_disappearing_server_test.exe chttp2_socket_pair_early_server_shutdown_finishes_inflight_calls_test.exe chttp2_socket_pair_early_server_shutdown_finishes_tags_test.exe chttp2_socket_pair_empty_batch_test.exe chttp2_socket_pair_graceful_server_shutdown_test.exe chttp2_socket_pair_invoke_large_request_test.exe chttp2_socket_pair_max_concurrent_streams_test.exe chttp2_socket_pair_max_message_length_test.exe chttp2_socket_pair_no_op_test.exe chttp2_socket_pair_ping_pong_streaming_test.exe chttp2_socket_pair_registered_call_test.exe chttp2_socket_pair_request_response_with_binary_metadata_and_payload_test.exe chttp2_socket_pair_request_response_with_metadata_and_payload_test.exe chttp2_socket_pair_request_response_with_payload_test.exe chttp2_socket_pair_request_response_with_payload_and_call_creds_test.exe chttp2_socket_pair_request_response_with_trailing_metadata_and_payload_test.exe chttp2_socket_pair_request_with_flags_test.exe chttp2_socket_pair_request_with_large_metadata_test.exe chttp2_socket_pair_request_with_payload_test.exe chttp2_socket_pair_server_finishes_request_test.exe chttp2_socket_pair_simple_delayed_request_test.exe chttp2_socket_pair_simple_request_test.exe chttp2_socket_pair_simple_request_with_high_initial_sequence_number_test.exe chttp2_socket_pair_one_byte_at_a_time_bad_hostname_test.exe chttp2_socket_pair_one_byte_at_a_time_cancel_after_accept_test.exe chttp2_socket_pair_one_byte_at_a_time_cancel_after_accept_and_writes_closed_test.exe chttp2_socket_pair_one_byte_at_a_time_cancel_after_invoke_test.exe chttp2_socket_pair_one_byte_at_a_time_cancel_before_invoke_test.exe chttp2_socket_pair_one_byte_at_a_time_cancel_in_a_vacuum_test.exe chttp2_socket_pair_one_byte_at_a_time_census_simple_request_test.exe chttp2_socket_pair_one_byte_at_a_time_disappearing_server_test.exe chttp2_socket_pair_one_byte_at_a_time_early_server_shutdown_finishes_inflight_calls_test.exe chttp2_socket_pair_one_byte_at_a_time_early_server_shutdown_finishes_tags_test.exe chttp2_socket_pair_one_byte_at_a_time_empty_batch_test.exe chttp2_socket_pair_one_byte_at_a_time_graceful_server_shutdown_test.exe chttp2_socket_pair_one_byte_at_a_time_invoke_large_request_test.exe chttp2_socket_pair_one_byte_at_a_time_max_concurrent_streams_test.exe chttp2_socket_pair_one_byte_at_a_time_max_message_length_test.exe chttp2_socket_pair_one_byte_at_a_time_no_op_test.exe chttp2_socket_pair_one_byte_at_a_time_ping_pong_streaming_test.exe chttp2_socket_pair_one_byte_at_a_time_registered_call_test.exe chttp2_socket_pair_one_byte_at_a_time_request_response_with_binary_metadata_and_payload_test.exe chttp2_socket_pair_one_byte_at_a_time_request_response_with_metadata_and_payload_test.exe chttp2_socket_pair_one_byte_at_a_time_request_response_with_payload_test.exe chttp2_socket_pair_one_byte_at_a_time_request_response_with_payload_and_call_creds_test.exe chttp2_socket_pair_one_byte_at_a_time_request_response_with_trailing_metadata_and_payload_test.exe chttp2_socket_pair_one_byte_at_a_time_request_with_flags_test.exe chttp2_socket_pair_one_byte_at_a_time_request_with_large_metadata_test.exe chttp2_socket_pair_one_byte_at_a_time_request_with_payload_test.exe chttp2_socket_pair_one_byte_at_a_time_server_finishes_request_test.exe chttp2_socket_pair_one_byte_at_a_time_simple_delayed_request_test.exe chttp2_socket_pair_one_byte_at_a_time_simple_request_test.exe chttp2_socket_pair_one_byte_at_a_time_simple_request_with_high_initial_sequence_number_test.exe chttp2_socket_pair_with_grpc_trace_bad_hostname_test.exe chttp2_socket_pair_with_grpc_trace_cancel_after_accept_test.exe chttp2_socket_pair_with_grpc_trace_cancel_after_accept_and_writes_closed_test.exe chttp2_socket_pair_with_grpc_trace_cancel_after_invoke_test.exe chttp2_socket_pair_with_grpc_trace_cancel_before_invoke_test.exe chttp2_socket_pair_with_grpc_trace_cancel_in_a_vacuum_test.exe chttp2_socket_pair_with_grpc_trace_census_simple_request_test.exe chttp2_socket_pair_with_grpc_trace_disappearing_server_test.exe chttp2_socket_pair_with_grpc_trace_early_server_shutdown_finishes_inflight_calls_test.exe chttp2_socket_pair_with_grpc_trace_early_server_shutdown_finishes_tags_test.exe chttp2_socket_pair_with_grpc_trace_empty_batch_test.exe chttp2_socket_pair_with_grpc_trace_graceful_server_shutdown_test.exe chttp2_socket_pair_with_grpc_trace_invoke_large_request_test.exe chttp2_socket_pair_with_grpc_trace_max_concurrent_streams_test.exe chttp2_socket_pair_with_grpc_trace_max_message_length_test.exe chttp2_socket_pair_with_grpc_trace_no_op_test.exe chttp2_socket_pair_with_grpc_trace_ping_pong_streaming_test.exe chttp2_socket_pair_with_grpc_trace_registered_call_test.exe chttp2_socket_pair_with_grpc_trace_request_response_with_binary_metadata_and_payload_test.exe chttp2_socket_pair_with_grpc_trace_request_response_with_metadata_and_payload_test.exe chttp2_socket_pair_with_grpc_trace_request_response_with_payload_test.exe chttp2_socket_pair_with_grpc_trace_request_response_with_payload_and_call_creds_test.exe chttp2_socket_pair_with_grpc_trace_request_response_with_trailing_metadata_and_payload_test.exe chttp2_socket_pair_with_grpc_trace_request_with_flags_test.exe chttp2_socket_pair_with_grpc_trace_request_with_large_metadata_test.exe chttp2_socket_pair_with_grpc_trace_request_with_payload_test.exe chttp2_socket_pair_with_grpc_trace_server_finishes_request_test.exe chttp2_socket_pair_with_grpc_trace_simple_delayed_request_test.exe chttp2_socket_pair_with_grpc_trace_simple_request_test.exe chttp2_socket_pair_with_grpc_trace_simple_request_with_high_initial_sequence_number_test.exe chttp2_fullstack_bad_hostname_unsecure_test.exe chttp2_fullstack_cancel_after_accept_unsecure_test.exe chttp2_fullstack_cancel_after_accept_and_writes_closed_unsecure_test.exe chttp2_fullstack_cancel_after_invoke_unsecure_test.exe chttp2_fullstack_cancel_before_invoke_unsecure_test.exe chttp2_fullstack_cancel_in_a_vacuum_unsecure_test.exe chttp2_fullstack_census_simple_request_unsecure_test.exe chttp2_fullstack_disappearing_server_unsecure_test.exe chttp2_fullstack_early_server_shutdown_finishes_inflight_calls_unsecure_test.exe chttp2_fullstack_early_server_shutdown_finishes_tags_unsecure_test.exe chttp2_fullstack_empty_batch_unsecure_test.exe chttp2_fullstack_graceful_server_shutdown_unsecure_test.exe chttp2_fullstack_invoke_large_request_unsecure_test.exe chttp2_fullstack_max_concurrent_streams_unsecure_test.exe chttp2_fullstack_max_message_length_unsecure_test.exe chttp2_fullstack_no_op_unsecure_test.exe chttp2_fullstack_ping_pong_streaming_unsecure_test.exe chttp2_fullstack_registered_call_unsecure_test.exe chttp2_fullstack_request_response_with_binary_metadata_and_payload_unsecure_test.exe chttp2_fullstack_request_response_with_metadata_and_payload_unsecure_test.exe chttp2_fullstack_request_response_with_payload_unsecure_test.exe chttp2_fullstack_request_response_with_trailing_metadata_and_payload_unsecure_test.exe chttp2_fullstack_request_with_flags_unsecure_test.exe chttp2_fullstack_request_with_large_metadata_unsecure_test.exe chttp2_fullstack_request_with_payload_unsecure_test.exe chttp2_fullstack_server_finishes_request_unsecure_test.exe chttp2_fullstack_simple_delayed_request_unsecure_test.exe chttp2_fullstack_simple_request_unsecure_test.exe chttp2_fullstack_simple_request_with_high_initial_sequence_number_unsecure_test.exe chttp2_socket_pair_bad_hostname_unsecure_test.exe chttp2_socket_pair_cancel_after_accept_unsecure_test.exe chttp2_socket_pair_cancel_after_accept_and_writes_closed_unsecure_test.exe chttp2_socket_pair_cancel_after_invoke_unsecure_test.exe chttp2_socket_pair_cancel_before_invoke_unsecure_test.exe chttp2_socket_pair_cancel_in_a_vacuum_unsecure_test.exe chttp2_socket_pair_census_simple_request_unsecure_test.exe chttp2_socket_pair_disappearing_server_unsecure_test.exe chttp2_socket_pair_early_server_shutdown_finishes_inflight_calls_unsecure_test.exe chttp2_socket_pair_early_server_shutdown_finishes_tags_unsecure_test.exe chttp2_socket_pair_empty_batch_unsecure_test.exe chttp2_socket_pair_graceful_server_shutdown_unsecure_test.exe chttp2_socket_pair_invoke_large_request_unsecure_test.exe chttp2_socket_pair_max_concurrent_streams_unsecure_test.exe chttp2_socket_pair_max_message_length_unsecure_test.exe chttp2_socket_pair_no_op_unsecure_test.exe chttp2_socket_pair_ping_pong_streaming_unsecure_test.exe chttp2_socket_pair_registered_call_unsecure_test.exe chttp2_socket_pair_request_response_with_binary_metadata_and_payload_unsecure_test.exe chttp2_socket_pair_request_response_with_metadata_and_payload_unsecure_test.exe chttp2_socket_pair_request_response_with_payload_unsecure_test.exe chttp2_socket_pair_request_response_with_trailing_metadata_and_payload_unsecure_test.exe chttp2_socket_pair_request_with_flags_unsecure_test.exe chttp2_socket_pair_request_with_large_metadata_unsecure_test.exe chttp2_socket_pair_request_with_payload_unsecure_test.exe chttp2_socket_pair_server_finishes_request_unsecure_test.exe chttp2_socket_pair_simple_delayed_request_unsecure_test.exe chttp2_socket_pair_simple_request_unsecure_test.exe chttp2_socket_pair_simple_request_with_high_initial_sequence_number_unsecure_test.exe chttp2_socket_pair_one_byte_at_a_time_bad_hostname_unsecure_test.exe chttp2_socket_pair_one_byte_at_a_time_cancel_after_accept_unsecure_test.exe chttp2_socket_pair_one_byte_at_a_time_cancel_after_accept_and_writes_closed_unsecure_test.exe chttp2_socket_pair_one_byte_at_a_time_cancel_after_invoke_unsecure_test.exe chttp2_socket_pair_one_byte_at_a_time_cancel_before_invoke_unsecure_test.exe chttp2_socket_pair_one_byte_at_a_time_cancel_in_a_vacuum_unsecure_test.exe chttp2_socket_pair_one_byte_at_a_time_census_simple_request_unsecure_test.exe chttp2_socket_pair_one_byte_at_a_time_disappearing_server_unsecure_test.exe chttp2_socket_pair_one_byte_at_a_time_early_server_shutdown_finishes_inflight_calls_unsecure_test.exe chttp2_socket_pair_one_byte_at_a_time_early_server_shutdown_finishes_tags_unsecure_test.exe chttp2_socket_pair_one_byte_at_a_time_empty_batch_unsecure_test.exe chttp2_socket_pair_one_byte_at_a_time_graceful_server_shutdown_unsecure_test.exe chttp2_socket_pair_one_byte_at_a_time_invoke_large_request_unsecure_test.exe chttp2_socket_pair_one_byte_at_a_time_max_concurrent_streams_unsecure_test.exe chttp2_socket_pair_one_byte_at_a_time_max_message_length_unsecure_test.exe chttp2_socket_pair_one_byte_at_a_time_no_op_unsecure_test.exe chttp2_socket_pair_one_byte_at_a_time_ping_pong_streaming_unsecure_test.exe chttp2_socket_pair_one_byte_at_a_time_registered_call_unsecure_test.exe chttp2_socket_pair_one_byte_at_a_time_request_response_with_binary_metadata_and_payload_unsecure_test.exe chttp2_socket_pair_one_byte_at_a_time_request_response_with_metadata_and_payload_unsecure_test.exe chttp2_socket_pair_one_byte_at_a_time_request_response_with_payload_unsecure_test.exe chttp2_socket_pair_one_byte_at_a_time_request_response_with_trailing_metadata_and_payload_unsecure_test.exe chttp2_socket_pair_one_byte_at_a_time_request_with_flags_unsecure_test.exe chttp2_socket_pair_one_byte_at_a_time_request_with_large_metadata_unsecure_test.exe chttp2_socket_pair_one_byte_at_a_time_request_with_payload_unsecure_test.exe chttp2_socket_pair_one_byte_at_a_time_server_finishes_request_unsecure_test.exe chttp2_socket_pair_one_byte_at_a_time_simple_delayed_request_unsecure_test.exe chttp2_socket_pair_one_byte_at_a_time_simple_request_unsecure_test.exe chttp2_socket_pair_one_byte_at_a_time_simple_request_with_high_initial_sequence_number_unsecure_test.exe chttp2_socket_pair_with_grpc_trace_bad_hostname_unsecure_test.exe chttp2_socket_pair_with_grpc_trace_cancel_after_accept_unsecure_test.exe chttp2_socket_pair_with_grpc_trace_cancel_after_accept_and_writes_closed_unsecure_test.exe chttp2_socket_pair_with_grpc_trace_cancel_after_invoke_unsecure_test.exe chttp2_socket_pair_with_grpc_trace_cancel_before_invoke_unsecure_test.exe chttp2_socket_pair_with_grpc_trace_cancel_in_a_vacuum_unsecure_test.exe chttp2_socket_pair_with_grpc_trace_census_simple_request_unsecure_test.exe chttp2_socket_pair_with_grpc_trace_disappearing_server_unsecure_test.exe chttp2_socket_pair_with_grpc_trace_early_server_shutdown_finishes_inflight_calls_unsecure_test.exe chttp2_socket_pair_with_grpc_trace_early_server_shutdown_finishes_tags_unsecure_test.exe chttp2_socket_pair_with_grpc_trace_empty_batch_unsecure_test.exe chttp2_socket_pair_with_grpc_trace_graceful_server_shutdown_unsecure_test.exe chttp2_socket_pair_with_grpc_trace_invoke_large_request_unsecure_test.exe chttp2_socket_pair_with_grpc_trace_max_concurrent_streams_unsecure_test.exe chttp2_socket_pair_with_grpc_trace_max_message_length_unsecure_test.exe chttp2_socket_pair_with_grpc_trace_no_op_unsecure_test.exe chttp2_socket_pair_with_grpc_trace_ping_pong_streaming_unsecure_test.exe chttp2_socket_pair_with_grpc_trace_registered_call_unsecure_test.exe chttp2_socket_pair_with_grpc_trace_request_response_with_binary_metadata_and_payload_unsecure_test.exe chttp2_socket_pair_with_grpc_trace_request_response_with_metadata_and_payload_unsecure_test.exe chttp2_socket_pair_with_grpc_trace_request_response_with_payload_unsecure_test.exe chttp2_socket_pair_with_grpc_trace_request_response_with_trailing_metadata_and_payload_unsecure_test.exe chttp2_socket_pair_with_grpc_trace_request_with_flags_unsecure_test.exe chttp2_socket_pair_with_grpc_trace_request_with_large_metadata_unsecure_test.exe chttp2_socket_pair_with_grpc_trace_request_with_payload_unsecure_test.exe chttp2_socket_pair_with_grpc_trace_server_finishes_request_unsecure_test.exe chttp2_socket_pair_with_grpc_trace_simple_delayed_request_unsecure_test.exe chttp2_socket_pair_with_grpc_trace_simple_request_unsecure_test.exe chttp2_socket_pair_with_grpc_trace_simple_request_with_high_initial_sequence_number_unsecure_test.exe connection_prefix_bad_client_test.exe initial_settings_frame_bad_client_test.exe 
+buildtests_c: alarm_heap_test.exe alarm_list_test.exe alarm_test.exe alpn_test.exe bin_encoder_test.exe chttp2_status_conversion_test.exe chttp2_stream_encoder_test.exe chttp2_stream_map_test.exe fling_client.exe fling_server.exe gpr_cancellable_test.exe gpr_cmdline_test.exe gpr_env_test.exe gpr_file_test.exe gpr_histogram_test.exe gpr_host_port_test.exe gpr_log_test.exe gpr_slice_buffer_test.exe gpr_slice_test.exe gpr_stack_lockfree_test.exe gpr_string_test.exe gpr_sync_test.exe gpr_thd_test.exe gpr_time_test.exe gpr_tls_test.exe gpr_useful_test.exe grpc_auth_context_test.exe grpc_base64_test.exe grpc_byte_buffer_reader_test.exe grpc_channel_stack_test.exe grpc_completion_queue_test.exe grpc_credentials_test.exe grpc_json_token_test.exe grpc_jwt_verifier_test.exe grpc_security_connector_test.exe grpc_stream_op_test.exe hpack_parser_test.exe hpack_table_test.exe httpcli_format_request_test.exe httpcli_parser_test.exe json_rewrite.exe json_rewrite_test.exe json_test.exe lame_client_test.exe message_compress_test.exe multi_init_test.exe multiple_server_queues_test.exe murmur_hash_test.exe no_server_test.exe resolve_address_test.exe secure_endpoint_test.exe sockaddr_utils_test.exe time_averaged_stats_test.exe time_test.exe timeout_encoding_test.exe timers_test.exe transport_metadata_test.exe transport_security_test.exe uri_parser_test.exe chttp2_fake_security_bad_hostname_test.exe chttp2_fake_security_cancel_after_accept_test.exe chttp2_fake_security_cancel_after_accept_and_writes_closed_test.exe chttp2_fake_security_cancel_after_invoke_test.exe chttp2_fake_security_cancel_before_invoke_test.exe chttp2_fake_security_cancel_in_a_vacuum_test.exe chttp2_fake_security_census_simple_request_test.exe chttp2_fake_security_disappearing_server_test.exe chttp2_fake_security_early_server_shutdown_finishes_inflight_calls_test.exe chttp2_fake_security_early_server_shutdown_finishes_tags_test.exe chttp2_fake_security_empty_batch_test.exe chttp2_fake_security_graceful_server_shutdown_test.exe chttp2_fake_security_invoke_large_request_test.exe chttp2_fake_security_max_concurrent_streams_test.exe chttp2_fake_security_max_message_length_test.exe chttp2_fake_security_no_op_test.exe chttp2_fake_security_ping_pong_streaming_test.exe chttp2_fake_security_registered_call_test.exe chttp2_fake_security_request_response_with_binary_metadata_and_payload_test.exe chttp2_fake_security_request_response_with_metadata_and_payload_test.exe chttp2_fake_security_request_response_with_payload_test.exe chttp2_fake_security_request_response_with_payload_and_call_creds_test.exe chttp2_fake_security_request_response_with_trailing_metadata_and_payload_test.exe chttp2_fake_security_request_with_flags_test.exe chttp2_fake_security_request_with_large_metadata_test.exe chttp2_fake_security_request_with_payload_test.exe chttp2_fake_security_server_finishes_request_test.exe chttp2_fake_security_simple_delayed_request_test.exe chttp2_fake_security_simple_request_test.exe chttp2_fake_security_simple_request_with_high_initial_sequence_number_test.exe chttp2_fullstack_bad_hostname_test.exe chttp2_fullstack_cancel_after_accept_test.exe chttp2_fullstack_cancel_after_accept_and_writes_closed_test.exe chttp2_fullstack_cancel_after_invoke_test.exe chttp2_fullstack_cancel_before_invoke_test.exe chttp2_fullstack_cancel_in_a_vacuum_test.exe chttp2_fullstack_census_simple_request_test.exe chttp2_fullstack_disappearing_server_test.exe chttp2_fullstack_early_server_shutdown_finishes_inflight_calls_test.exe chttp2_fullstack_early_server_shutdown_finishes_tags_test.exe chttp2_fullstack_empty_batch_test.exe chttp2_fullstack_graceful_server_shutdown_test.exe chttp2_fullstack_invoke_large_request_test.exe chttp2_fullstack_max_concurrent_streams_test.exe chttp2_fullstack_max_message_length_test.exe chttp2_fullstack_no_op_test.exe chttp2_fullstack_ping_pong_streaming_test.exe chttp2_fullstack_registered_call_test.exe chttp2_fullstack_request_response_with_binary_metadata_and_payload_test.exe chttp2_fullstack_request_response_with_metadata_and_payload_test.exe chttp2_fullstack_request_response_with_payload_test.exe chttp2_fullstack_request_response_with_payload_and_call_creds_test.exe chttp2_fullstack_request_response_with_trailing_metadata_and_payload_test.exe chttp2_fullstack_request_with_flags_test.exe chttp2_fullstack_request_with_large_metadata_test.exe chttp2_fullstack_request_with_payload_test.exe chttp2_fullstack_server_finishes_request_test.exe chttp2_fullstack_simple_delayed_request_test.exe chttp2_fullstack_simple_request_test.exe chttp2_fullstack_simple_request_with_high_initial_sequence_number_test.exe chttp2_simple_ssl_fullstack_bad_hostname_test.exe chttp2_simple_ssl_fullstack_cancel_after_accept_test.exe chttp2_simple_ssl_fullstack_cancel_after_accept_and_writes_closed_test.exe chttp2_simple_ssl_fullstack_cancel_after_invoke_test.exe chttp2_simple_ssl_fullstack_cancel_before_invoke_test.exe chttp2_simple_ssl_fullstack_cancel_in_a_vacuum_test.exe chttp2_simple_ssl_fullstack_census_simple_request_test.exe chttp2_simple_ssl_fullstack_disappearing_server_test.exe chttp2_simple_ssl_fullstack_early_server_shutdown_finishes_inflight_calls_test.exe chttp2_simple_ssl_fullstack_early_server_shutdown_finishes_tags_test.exe chttp2_simple_ssl_fullstack_empty_batch_test.exe chttp2_simple_ssl_fullstack_graceful_server_shutdown_test.exe chttp2_simple_ssl_fullstack_invoke_large_request_test.exe chttp2_simple_ssl_fullstack_max_concurrent_streams_test.exe chttp2_simple_ssl_fullstack_max_message_length_test.exe chttp2_simple_ssl_fullstack_no_op_test.exe chttp2_simple_ssl_fullstack_ping_pong_streaming_test.exe chttp2_simple_ssl_fullstack_registered_call_test.exe chttp2_simple_ssl_fullstack_request_response_with_binary_metadata_and_payload_test.exe chttp2_simple_ssl_fullstack_request_response_with_metadata_and_payload_test.exe chttp2_simple_ssl_fullstack_request_response_with_payload_test.exe chttp2_simple_ssl_fullstack_request_response_with_payload_and_call_creds_test.exe chttp2_simple_ssl_fullstack_request_response_with_trailing_metadata_and_payload_test.exe chttp2_simple_ssl_fullstack_request_with_flags_test.exe chttp2_simple_ssl_fullstack_request_with_large_metadata_test.exe chttp2_simple_ssl_fullstack_request_with_payload_test.exe chttp2_simple_ssl_fullstack_server_finishes_request_test.exe chttp2_simple_ssl_fullstack_simple_delayed_request_test.exe chttp2_simple_ssl_fullstack_simple_request_test.exe chttp2_simple_ssl_fullstack_simple_request_with_high_initial_sequence_number_test.exe chttp2_simple_ssl_with_oauth2_fullstack_bad_hostname_test.exe chttp2_simple_ssl_with_oauth2_fullstack_cancel_after_accept_test.exe chttp2_simple_ssl_with_oauth2_fullstack_cancel_after_accept_and_writes_closed_test.exe chttp2_simple_ssl_with_oauth2_fullstack_cancel_after_invoke_test.exe chttp2_simple_ssl_with_oauth2_fullstack_cancel_before_invoke_test.exe chttp2_simple_ssl_with_oauth2_fullstack_cancel_in_a_vacuum_test.exe chttp2_simple_ssl_with_oauth2_fullstack_census_simple_request_test.exe chttp2_simple_ssl_with_oauth2_fullstack_disappearing_server_test.exe chttp2_simple_ssl_with_oauth2_fullstack_early_server_shutdown_finishes_inflight_calls_test.exe chttp2_simple_ssl_with_oauth2_fullstack_early_server_shutdown_finishes_tags_test.exe chttp2_simple_ssl_with_oauth2_fullstack_empty_batch_test.exe chttp2_simple_ssl_with_oauth2_fullstack_graceful_server_shutdown_test.exe chttp2_simple_ssl_with_oauth2_fullstack_invoke_large_request_test.exe chttp2_simple_ssl_with_oauth2_fullstack_max_concurrent_streams_test.exe chttp2_simple_ssl_with_oauth2_fullstack_max_message_length_test.exe chttp2_simple_ssl_with_oauth2_fullstack_no_op_test.exe chttp2_simple_ssl_with_oauth2_fullstack_ping_pong_streaming_test.exe chttp2_simple_ssl_with_oauth2_fullstack_registered_call_test.exe chttp2_simple_ssl_with_oauth2_fullstack_request_response_with_binary_metadata_and_payload_test.exe chttp2_simple_ssl_with_oauth2_fullstack_request_response_with_metadata_and_payload_test.exe chttp2_simple_ssl_with_oauth2_fullstack_request_response_with_payload_test.exe chttp2_simple_ssl_with_oauth2_fullstack_request_response_with_payload_and_call_creds_test.exe chttp2_simple_ssl_with_oauth2_fullstack_request_response_with_trailing_metadata_and_payload_test.exe chttp2_simple_ssl_with_oauth2_fullstack_request_with_flags_test.exe chttp2_simple_ssl_with_oauth2_fullstack_request_with_large_metadata_test.exe chttp2_simple_ssl_with_oauth2_fullstack_request_with_payload_test.exe chttp2_simple_ssl_with_oauth2_fullstack_server_finishes_request_test.exe chttp2_simple_ssl_with_oauth2_fullstack_simple_delayed_request_test.exe chttp2_simple_ssl_with_oauth2_fullstack_simple_request_test.exe chttp2_simple_ssl_with_oauth2_fullstack_simple_request_with_high_initial_sequence_number_test.exe chttp2_socket_pair_bad_hostname_test.exe chttp2_socket_pair_cancel_after_accept_test.exe chttp2_socket_pair_cancel_after_accept_and_writes_closed_test.exe chttp2_socket_pair_cancel_after_invoke_test.exe chttp2_socket_pair_cancel_before_invoke_test.exe chttp2_socket_pair_cancel_in_a_vacuum_test.exe chttp2_socket_pair_census_simple_request_test.exe chttp2_socket_pair_disappearing_server_test.exe chttp2_socket_pair_early_server_shutdown_finishes_inflight_calls_test.exe chttp2_socket_pair_early_server_shutdown_finishes_tags_test.exe chttp2_socket_pair_empty_batch_test.exe chttp2_socket_pair_graceful_server_shutdown_test.exe chttp2_socket_pair_invoke_large_request_test.exe chttp2_socket_pair_max_concurrent_streams_test.exe chttp2_socket_pair_max_message_length_test.exe chttp2_socket_pair_no_op_test.exe chttp2_socket_pair_ping_pong_streaming_test.exe chttp2_socket_pair_registered_call_test.exe chttp2_socket_pair_request_response_with_binary_metadata_and_payload_test.exe chttp2_socket_pair_request_response_with_metadata_and_payload_test.exe chttp2_socket_pair_request_response_with_payload_test.exe chttp2_socket_pair_request_response_with_payload_and_call_creds_test.exe chttp2_socket_pair_request_response_with_trailing_metadata_and_payload_test.exe chttp2_socket_pair_request_with_flags_test.exe chttp2_socket_pair_request_with_large_metadata_test.exe chttp2_socket_pair_request_with_payload_test.exe chttp2_socket_pair_server_finishes_request_test.exe chttp2_socket_pair_simple_delayed_request_test.exe chttp2_socket_pair_simple_request_test.exe chttp2_socket_pair_simple_request_with_high_initial_sequence_number_test.exe chttp2_socket_pair_one_byte_at_a_time_bad_hostname_test.exe chttp2_socket_pair_one_byte_at_a_time_cancel_after_accept_test.exe chttp2_socket_pair_one_byte_at_a_time_cancel_after_accept_and_writes_closed_test.exe chttp2_socket_pair_one_byte_at_a_time_cancel_after_invoke_test.exe chttp2_socket_pair_one_byte_at_a_time_cancel_before_invoke_test.exe chttp2_socket_pair_one_byte_at_a_time_cancel_in_a_vacuum_test.exe chttp2_socket_pair_one_byte_at_a_time_census_simple_request_test.exe chttp2_socket_pair_one_byte_at_a_time_disappearing_server_test.exe chttp2_socket_pair_one_byte_at_a_time_early_server_shutdown_finishes_inflight_calls_test.exe chttp2_socket_pair_one_byte_at_a_time_early_server_shutdown_finishes_tags_test.exe chttp2_socket_pair_one_byte_at_a_time_empty_batch_test.exe chttp2_socket_pair_one_byte_at_a_time_graceful_server_shutdown_test.exe chttp2_socket_pair_one_byte_at_a_time_invoke_large_request_test.exe chttp2_socket_pair_one_byte_at_a_time_max_concurrent_streams_test.exe chttp2_socket_pair_one_byte_at_a_time_max_message_length_test.exe chttp2_socket_pair_one_byte_at_a_time_no_op_test.exe chttp2_socket_pair_one_byte_at_a_time_ping_pong_streaming_test.exe chttp2_socket_pair_one_byte_at_a_time_registered_call_test.exe chttp2_socket_pair_one_byte_at_a_time_request_response_with_binary_metadata_and_payload_test.exe chttp2_socket_pair_one_byte_at_a_time_request_response_with_metadata_and_payload_test.exe chttp2_socket_pair_one_byte_at_a_time_request_response_with_payload_test.exe chttp2_socket_pair_one_byte_at_a_time_request_response_with_payload_and_call_creds_test.exe chttp2_socket_pair_one_byte_at_a_time_request_response_with_trailing_metadata_and_payload_test.exe chttp2_socket_pair_one_byte_at_a_time_request_with_flags_test.exe chttp2_socket_pair_one_byte_at_a_time_request_with_large_metadata_test.exe chttp2_socket_pair_one_byte_at_a_time_request_with_payload_test.exe chttp2_socket_pair_one_byte_at_a_time_server_finishes_request_test.exe chttp2_socket_pair_one_byte_at_a_time_simple_delayed_request_test.exe chttp2_socket_pair_one_byte_at_a_time_simple_request_test.exe chttp2_socket_pair_one_byte_at_a_time_simple_request_with_high_initial_sequence_number_test.exe chttp2_socket_pair_with_grpc_trace_bad_hostname_test.exe chttp2_socket_pair_with_grpc_trace_cancel_after_accept_test.exe chttp2_socket_pair_with_grpc_trace_cancel_after_accept_and_writes_closed_test.exe chttp2_socket_pair_with_grpc_trace_cancel_after_invoke_test.exe chttp2_socket_pair_with_grpc_trace_cancel_before_invoke_test.exe chttp2_socket_pair_with_grpc_trace_cancel_in_a_vacuum_test.exe chttp2_socket_pair_with_grpc_trace_census_simple_request_test.exe chttp2_socket_pair_with_grpc_trace_disappearing_server_test.exe chttp2_socket_pair_with_grpc_trace_early_server_shutdown_finishes_inflight_calls_test.exe chttp2_socket_pair_with_grpc_trace_early_server_shutdown_finishes_tags_test.exe chttp2_socket_pair_with_grpc_trace_empty_batch_test.exe chttp2_socket_pair_with_grpc_trace_graceful_server_shutdown_test.exe chttp2_socket_pair_with_grpc_trace_invoke_large_request_test.exe chttp2_socket_pair_with_grpc_trace_max_concurrent_streams_test.exe chttp2_socket_pair_with_grpc_trace_max_message_length_test.exe chttp2_socket_pair_with_grpc_trace_no_op_test.exe chttp2_socket_pair_with_grpc_trace_ping_pong_streaming_test.exe chttp2_socket_pair_with_grpc_trace_registered_call_test.exe chttp2_socket_pair_with_grpc_trace_request_response_with_binary_metadata_and_payload_test.exe chttp2_socket_pair_with_grpc_trace_request_response_with_metadata_and_payload_test.exe chttp2_socket_pair_with_grpc_trace_request_response_with_payload_test.exe chttp2_socket_pair_with_grpc_trace_request_response_with_payload_and_call_creds_test.exe chttp2_socket_pair_with_grpc_trace_request_response_with_trailing_metadata_and_payload_test.exe chttp2_socket_pair_with_grpc_trace_request_with_flags_test.exe chttp2_socket_pair_with_grpc_trace_request_with_large_metadata_test.exe chttp2_socket_pair_with_grpc_trace_request_with_payload_test.exe chttp2_socket_pair_with_grpc_trace_server_finishes_request_test.exe chttp2_socket_pair_with_grpc_trace_simple_delayed_request_test.exe chttp2_socket_pair_with_grpc_trace_simple_request_test.exe chttp2_socket_pair_with_grpc_trace_simple_request_with_high_initial_sequence_number_test.exe chttp2_fullstack_bad_hostname_unsecure_test.exe chttp2_fullstack_cancel_after_accept_unsecure_test.exe chttp2_fullstack_cancel_after_accept_and_writes_closed_unsecure_test.exe chttp2_fullstack_cancel_after_invoke_unsecure_test.exe chttp2_fullstack_cancel_before_invoke_unsecure_test.exe chttp2_fullstack_cancel_in_a_vacuum_unsecure_test.exe chttp2_fullstack_census_simple_request_unsecure_test.exe chttp2_fullstack_disappearing_server_unsecure_test.exe chttp2_fullstack_early_server_shutdown_finishes_inflight_calls_unsecure_test.exe chttp2_fullstack_early_server_shutdown_finishes_tags_unsecure_test.exe chttp2_fullstack_empty_batch_unsecure_test.exe chttp2_fullstack_graceful_server_shutdown_unsecure_test.exe chttp2_fullstack_invoke_large_request_unsecure_test.exe chttp2_fullstack_max_concurrent_streams_unsecure_test.exe chttp2_fullstack_max_message_length_unsecure_test.exe chttp2_fullstack_no_op_unsecure_test.exe chttp2_fullstack_ping_pong_streaming_unsecure_test.exe chttp2_fullstack_registered_call_unsecure_test.exe chttp2_fullstack_request_response_with_binary_metadata_and_payload_unsecure_test.exe chttp2_fullstack_request_response_with_metadata_and_payload_unsecure_test.exe chttp2_fullstack_request_response_with_payload_unsecure_test.exe chttp2_fullstack_request_response_with_trailing_metadata_and_payload_unsecure_test.exe chttp2_fullstack_request_with_flags_unsecure_test.exe chttp2_fullstack_request_with_large_metadata_unsecure_test.exe chttp2_fullstack_request_with_payload_unsecure_test.exe chttp2_fullstack_server_finishes_request_unsecure_test.exe chttp2_fullstack_simple_delayed_request_unsecure_test.exe chttp2_fullstack_simple_request_unsecure_test.exe chttp2_fullstack_simple_request_with_high_initial_sequence_number_unsecure_test.exe chttp2_socket_pair_bad_hostname_unsecure_test.exe chttp2_socket_pair_cancel_after_accept_unsecure_test.exe chttp2_socket_pair_cancel_after_accept_and_writes_closed_unsecure_test.exe chttp2_socket_pair_cancel_after_invoke_unsecure_test.exe chttp2_socket_pair_cancel_before_invoke_unsecure_test.exe chttp2_socket_pair_cancel_in_a_vacuum_unsecure_test.exe chttp2_socket_pair_census_simple_request_unsecure_test.exe chttp2_socket_pair_disappearing_server_unsecure_test.exe chttp2_socket_pair_early_server_shutdown_finishes_inflight_calls_unsecure_test.exe chttp2_socket_pair_early_server_shutdown_finishes_tags_unsecure_test.exe chttp2_socket_pair_empty_batch_unsecure_test.exe chttp2_socket_pair_graceful_server_shutdown_unsecure_test.exe chttp2_socket_pair_invoke_large_request_unsecure_test.exe chttp2_socket_pair_max_concurrent_streams_unsecure_test.exe chttp2_socket_pair_max_message_length_unsecure_test.exe chttp2_socket_pair_no_op_unsecure_test.exe chttp2_socket_pair_ping_pong_streaming_unsecure_test.exe chttp2_socket_pair_registered_call_unsecure_test.exe chttp2_socket_pair_request_response_with_binary_metadata_and_payload_unsecure_test.exe chttp2_socket_pair_request_response_with_metadata_and_payload_unsecure_test.exe chttp2_socket_pair_request_response_with_payload_unsecure_test.exe chttp2_socket_pair_request_response_with_trailing_metadata_and_payload_unsecure_test.exe chttp2_socket_pair_request_with_flags_unsecure_test.exe chttp2_socket_pair_request_with_large_metadata_unsecure_test.exe chttp2_socket_pair_request_with_payload_unsecure_test.exe chttp2_socket_pair_server_finishes_request_unsecure_test.exe chttp2_socket_pair_simple_delayed_request_unsecure_test.exe chttp2_socket_pair_simple_request_unsecure_test.exe chttp2_socket_pair_simple_request_with_high_initial_sequence_number_unsecure_test.exe chttp2_socket_pair_one_byte_at_a_time_bad_hostname_unsecure_test.exe chttp2_socket_pair_one_byte_at_a_time_cancel_after_accept_unsecure_test.exe chttp2_socket_pair_one_byte_at_a_time_cancel_after_accept_and_writes_closed_unsecure_test.exe chttp2_socket_pair_one_byte_at_a_time_cancel_after_invoke_unsecure_test.exe chttp2_socket_pair_one_byte_at_a_time_cancel_before_invoke_unsecure_test.exe chttp2_socket_pair_one_byte_at_a_time_cancel_in_a_vacuum_unsecure_test.exe chttp2_socket_pair_one_byte_at_a_time_census_simple_request_unsecure_test.exe chttp2_socket_pair_one_byte_at_a_time_disappearing_server_unsecure_test.exe chttp2_socket_pair_one_byte_at_a_time_early_server_shutdown_finishes_inflight_calls_unsecure_test.exe chttp2_socket_pair_one_byte_at_a_time_early_server_shutdown_finishes_tags_unsecure_test.exe chttp2_socket_pair_one_byte_at_a_time_empty_batch_unsecure_test.exe chttp2_socket_pair_one_byte_at_a_time_graceful_server_shutdown_unsecure_test.exe chttp2_socket_pair_one_byte_at_a_time_invoke_large_request_unsecure_test.exe chttp2_socket_pair_one_byte_at_a_time_max_concurrent_streams_unsecure_test.exe chttp2_socket_pair_one_byte_at_a_time_max_message_length_unsecure_test.exe chttp2_socket_pair_one_byte_at_a_time_no_op_unsecure_test.exe chttp2_socket_pair_one_byte_at_a_time_ping_pong_streaming_unsecure_test.exe chttp2_socket_pair_one_byte_at_a_time_registered_call_unsecure_test.exe chttp2_socket_pair_one_byte_at_a_time_request_response_with_binary_metadata_and_payload_unsecure_test.exe chttp2_socket_pair_one_byte_at_a_time_request_response_with_metadata_and_payload_unsecure_test.exe chttp2_socket_pair_one_byte_at_a_time_request_response_with_payload_unsecure_test.exe chttp2_socket_pair_one_byte_at_a_time_request_response_with_trailing_metadata_and_payload_unsecure_test.exe chttp2_socket_pair_one_byte_at_a_time_request_with_flags_unsecure_test.exe chttp2_socket_pair_one_byte_at_a_time_request_with_large_metadata_unsecure_test.exe chttp2_socket_pair_one_byte_at_a_time_request_with_payload_unsecure_test.exe chttp2_socket_pair_one_byte_at_a_time_server_finishes_request_unsecure_test.exe chttp2_socket_pair_one_byte_at_a_time_simple_delayed_request_unsecure_test.exe chttp2_socket_pair_one_byte_at_a_time_simple_request_unsecure_test.exe chttp2_socket_pair_one_byte_at_a_time_simple_request_with_high_initial_sequence_number_unsecure_test.exe chttp2_socket_pair_with_grpc_trace_bad_hostname_unsecure_test.exe chttp2_socket_pair_with_grpc_trace_cancel_after_accept_unsecure_test.exe chttp2_socket_pair_with_grpc_trace_cancel_after_accept_and_writes_closed_unsecure_test.exe chttp2_socket_pair_with_grpc_trace_cancel_after_invoke_unsecure_test.exe chttp2_socket_pair_with_grpc_trace_cancel_before_invoke_unsecure_test.exe chttp2_socket_pair_with_grpc_trace_cancel_in_a_vacuum_unsecure_test.exe chttp2_socket_pair_with_grpc_trace_census_simple_request_unsecure_test.exe chttp2_socket_pair_with_grpc_trace_disappearing_server_unsecure_test.exe chttp2_socket_pair_with_grpc_trace_early_server_shutdown_finishes_inflight_calls_unsecure_test.exe chttp2_socket_pair_with_grpc_trace_early_server_shutdown_finishes_tags_unsecure_test.exe chttp2_socket_pair_with_grpc_trace_empty_batch_unsecure_test.exe chttp2_socket_pair_with_grpc_trace_graceful_server_shutdown_unsecure_test.exe chttp2_socket_pair_with_grpc_trace_invoke_large_request_unsecure_test.exe chttp2_socket_pair_with_grpc_trace_max_concurrent_streams_unsecure_test.exe chttp2_socket_pair_with_grpc_trace_max_message_length_unsecure_test.exe chttp2_socket_pair_with_grpc_trace_no_op_unsecure_test.exe chttp2_socket_pair_with_grpc_trace_ping_pong_streaming_unsecure_test.exe chttp2_socket_pair_with_grpc_trace_registered_call_unsecure_test.exe chttp2_socket_pair_with_grpc_trace_request_response_with_binary_metadata_and_payload_unsecure_test.exe chttp2_socket_pair_with_grpc_trace_request_response_with_metadata_and_payload_unsecure_test.exe chttp2_socket_pair_with_grpc_trace_request_response_with_payload_unsecure_test.exe chttp2_socket_pair_with_grpc_trace_request_response_with_trailing_metadata_and_payload_unsecure_test.exe chttp2_socket_pair_with_grpc_trace_request_with_flags_unsecure_test.exe chttp2_socket_pair_with_grpc_trace_request_with_large_metadata_unsecure_test.exe chttp2_socket_pair_with_grpc_trace_request_with_payload_unsecure_test.exe chttp2_socket_pair_with_grpc_trace_server_finishes_request_unsecure_test.exe chttp2_socket_pair_with_grpc_trace_simple_delayed_request_unsecure_test.exe chttp2_socket_pair_with_grpc_trace_simple_request_unsecure_test.exe chttp2_socket_pair_with_grpc_trace_simple_request_with_high_initial_sequence_number_unsecure_test.exe connection_prefix_bad_client_test.exe initial_settings_frame_bad_client_test.exe 
 	echo All tests built.
 
 buildtests_cxx: interop_client.exe interop_server.exe 
@@ -203,6 +209,13 @@
 gpr_slice_test: gpr_slice_test.exe
 	echo Running gpr_slice_test
 	$(OUT_DIR)\gpr_slice_test.exe
+gpr_stack_lockfree_test.exe: build_libs $(OUT_DIR)
+	echo Building gpr_stack_lockfree_test
+	$(CC) $(CFLAGS) /Fo:$(OUT_DIR)\ $(REPO_ROOT)\test\core\support\stack_lockfree_test.c 
+	$(LINK) $(LFLAGS) /OUT:"$(OUT_DIR)\gpr_stack_lockfree_test.exe" Debug\gpr_test_util.lib Debug\gpr.lib $(LIBS) $(OUT_DIR)\stack_lockfree_test.obj 
+gpr_stack_lockfree_test: gpr_stack_lockfree_test.exe
+	echo Running gpr_stack_lockfree_test
+	$(OUT_DIR)\gpr_stack_lockfree_test.exe
 gpr_string_test.exe: build_libs $(OUT_DIR)
 	echo Building gpr_string_test
 	$(CC) $(CFLAGS) /Fo:$(OUT_DIR)\ $(REPO_ROOT)\test\core\support\string_test.c 
diff --git a/vsprojects/README.md b/vsprojects/README.md
index 14178da..dade9e5 100644
--- a/vsprojects/README.md
+++ b/vsprojects/README.md
@@ -12,7 +12,7 @@
 ```
 > REM Run from this directory.
 > REM No need to do this if you have NuGet visual studio extension.
-> nuget restore
+> nuget restore grpc.sln
 ```
 
 After that, you can build the solution using one of these options:
diff --git a/vsprojects/gpr/gpr.vcxproj b/vsprojects/gpr/gpr.vcxproj
index 3e6bb20..32a08a2 100644
--- a/vsprojects/gpr/gpr.vcxproj
+++ b/vsprojects/gpr/gpr.vcxproj
@@ -179,6 +179,7 @@
     <ClInclude Include="..\..\src\core\support\env.h" />
     <ClInclude Include="..\..\src\core\support\file.h" />
     <ClInclude Include="..\..\src\core\support\murmur_hash.h" />
+    <ClInclude Include="..\..\src\core\support\stack_lockfree.h" />
     <ClInclude Include="..\..\src\core\support\string.h" />
     <ClInclude Include="..\..\src\core\support\string_win32.h" />
     <ClInclude Include="..\..\src\core\support\thd_internal.h" />
@@ -230,6 +231,8 @@
     </ClCompile>
     <ClCompile Include="..\..\src\core\support\slice_buffer.c">
     </ClCompile>
+    <ClCompile Include="..\..\src\core\support\stack_lockfree.c">
+    </ClCompile>
     <ClCompile Include="..\..\src\core\support\string.c">
     </ClCompile>
     <ClCompile Include="..\..\src\core\support\string_posix.c">
diff --git a/vsprojects/gpr/gpr.vcxproj.filters b/vsprojects/gpr/gpr.vcxproj.filters
index a270902..ace549f 100644
--- a/vsprojects/gpr/gpr.vcxproj.filters
+++ b/vsprojects/gpr/gpr.vcxproj.filters
@@ -70,6 +70,9 @@
     <ClCompile Include="..\..\src\core\support\slice_buffer.c">
       <Filter>src\core\support</Filter>
     </ClCompile>
+    <ClCompile Include="..\..\src\core\support\stack_lockfree.c">
+      <Filter>src\core\support</Filter>
+    </ClCompile>
     <ClCompile Include="..\..\src\core\support\string.c">
       <Filter>src\core\support</Filter>
     </ClCompile>
@@ -209,6 +212,9 @@
     <ClInclude Include="..\..\src\core\support\murmur_hash.h">
       <Filter>src\core\support</Filter>
     </ClInclude>
+    <ClInclude Include="..\..\src\core\support\stack_lockfree.h">
+      <Filter>src\core\support</Filter>
+    </ClInclude>
     <ClInclude Include="..\..\src\core\support\string.h">
       <Filter>src\core\support</Filter>
     </ClInclude>
diff --git a/vsprojects/grpc/grpc.vcxproj b/vsprojects/grpc/grpc.vcxproj
index 865e76e..16744b1 100644
--- a/vsprojects/grpc/grpc.vcxproj
+++ b/vsprojects/grpc/grpc.vcxproj
@@ -481,6 +481,8 @@
     </ClCompile>
     <ClCompile Include="..\..\src\core\surface\surface_trace.c">
     </ClCompile>
+    <ClCompile Include="..\..\src\core\surface\version.c">
+    </ClCompile>
     <ClCompile Include="..\..\src\core\transport\chttp2\alpn.c">
     </ClCompile>
     <ClCompile Include="..\..\src\core\transport\chttp2\bin_encoder.c">
diff --git a/vsprojects/grpc/grpc.vcxproj.filters b/vsprojects/grpc/grpc.vcxproj.filters
index f560fef..de9f205 100644
--- a/vsprojects/grpc/grpc.vcxproj.filters
+++ b/vsprojects/grpc/grpc.vcxproj.filters
@@ -316,6 +316,9 @@
     <ClCompile Include="..\..\src\core\surface\surface_trace.c">
       <Filter>src\core\surface</Filter>
     </ClCompile>
+    <ClCompile Include="..\..\src\core\surface\version.c">
+      <Filter>src\core\surface</Filter>
+    </ClCompile>
     <ClCompile Include="..\..\src\core\transport\chttp2\alpn.c">
       <Filter>src\core\transport\chttp2</Filter>
     </ClCompile>
diff --git a/vsprojects/grpc_unsecure/grpc_unsecure.vcxproj b/vsprojects/grpc_unsecure/grpc_unsecure.vcxproj
index 4ead6f8..02c791f 100644
--- a/vsprojects/grpc_unsecure/grpc_unsecure.vcxproj
+++ b/vsprojects/grpc_unsecure/grpc_unsecure.vcxproj
@@ -416,6 +416,8 @@
     </ClCompile>
     <ClCompile Include="..\..\src\core\surface\surface_trace.c">
     </ClCompile>
+    <ClCompile Include="..\..\src\core\surface\version.c">
+    </ClCompile>
     <ClCompile Include="..\..\src\core\transport\chttp2\alpn.c">
     </ClCompile>
     <ClCompile Include="..\..\src\core\transport\chttp2\bin_encoder.c">
diff --git a/vsprojects/grpc_unsecure/grpc_unsecure.vcxproj.filters b/vsprojects/grpc_unsecure/grpc_unsecure.vcxproj.filters
index 45ca1f7..333a71f 100644
--- a/vsprojects/grpc_unsecure/grpc_unsecure.vcxproj.filters
+++ b/vsprojects/grpc_unsecure/grpc_unsecure.vcxproj.filters
@@ -247,6 +247,9 @@
     <ClCompile Include="..\..\src\core\surface\surface_trace.c">
       <Filter>src\core\surface</Filter>
     </ClCompile>
+    <ClCompile Include="..\..\src\core\surface\version.c">
+      <Filter>src\core\surface</Filter>
+    </ClCompile>
     <ClCompile Include="..\..\src\core\transport\chttp2\alpn.c">
       <Filter>src\core\transport\chttp2</Filter>
     </ClCompile>
diff --git a/vsprojects/nuget_package/grpc.native.csharp_ext.nuspec b/vsprojects/nuget_package/grpc.native.csharp_ext.nuspec
index 211d747..d2ac440 100644
--- a/vsprojects/nuget_package/grpc.native.csharp_ext.nuspec
+++ b/vsprojects/nuget_package/grpc.native.csharp_ext.nuspec
@@ -2,14 +2,14 @@
 <package>
   <metadata>
     <id>grpc.native.csharp_ext</id>
-    <version>0.9.1</version>
+    <version>0.10.0</version>
     <authors>Google Inc.</authors>
     <owners>grpc-packages</owners>
     <licenseUrl>https://github.com/grpc/grpc/blob/master/LICENSE</licenseUrl>
     <projectUrl>http://github.com/grpc/grpc</projectUrl>
     <requireLicenseAcceptance>false</requireLicenseAcceptance>
     <description>Native extension needed by gRPC C# library. This is not the package you are looking for, it is only meant to be used as a dependency.</description>
-    <releaseNotes>Release of gRPC C core 0.9.1 libraries.</releaseNotes>
+    <releaseNotes>Release of gRPC C core 0.10.0 libraries.</releaseNotes>
     <copyright>Copyright 2015</copyright>
     <title>gRPC C# Native Extension</title>
     <summary>Native library required by gRPC C#</summary>