diff --git a/BUILD b/BUILD
index ccff9c05c65cc1a0b6577e5007efc070ec7b17e3..12fd6488b6bf480912dfe359f9638687a2665e02 100644
--- a/BUILD
+++ b/BUILD
@@ -32,535 +32,800 @@
 
 licenses(["notice"])  # 3-clause BSD
 
+package(default_visibility = ["//visibility:public"])
+
+
+
+
+cc_library(
+  name = "gpr",
+  srcs = [
+    "src/core/support/env.h",
+    "src/core/support/file.h",
+    "src/core/support/murmur_hash.h",
+    "src/core/support/string.h",
+    "src/core/support/string_win32.h",
+    "src/core/support/thd_internal.h",
+    "src/core/support/alloc.c",
+    "src/core/support/cancellable.c",
+    "src/core/support/cmdline.c",
+    "src/core/support/cpu_iphone.c",
+    "src/core/support/cpu_linux.c",
+    "src/core/support/cpu_posix.c",
+    "src/core/support/cpu_windows.c",
+    "src/core/support/env_linux.c",
+    "src/core/support/env_posix.c",
+    "src/core/support/env_win32.c",
+    "src/core/support/file.c",
+    "src/core/support/file_posix.c",
+    "src/core/support/file_win32.c",
+    "src/core/support/histogram.c",
+    "src/core/support/host_port.c",
+    "src/core/support/log.c",
+    "src/core/support/log_android.c",
+    "src/core/support/log_linux.c",
+    "src/core/support/log_posix.c",
+    "src/core/support/log_win32.c",
+    "src/core/support/murmur_hash.c",
+    "src/core/support/slice.c",
+    "src/core/support/slice_buffer.c",
+    "src/core/support/string.c",
+    "src/core/support/string_posix.c",
+    "src/core/support/string_win32.c",
+    "src/core/support/sync.c",
+    "src/core/support/sync_posix.c",
+    "src/core/support/sync_win32.c",
+    "src/core/support/thd.c",
+    "src/core/support/thd_posix.c",
+    "src/core/support/thd_win32.c",
+    "src/core/support/time.c",
+    "src/core/support/time_posix.c",
+    "src/core/support/time_win32.c",
+  ],
+  hdrs = [
+    "include/grpc/support/alloc.h",
+    "include/grpc/support/atm.h",
+    "include/grpc/support/atm_gcc_atomic.h",
+    "include/grpc/support/atm_gcc_sync.h",
+    "include/grpc/support/atm_win32.h",
+    "include/grpc/support/cancellable_platform.h",
+    "include/grpc/support/cmdline.h",
+    "include/grpc/support/cpu.h",
+    "include/grpc/support/histogram.h",
+    "include/grpc/support/host_port.h",
+    "include/grpc/support/log.h",
+    "include/grpc/support/log_win32.h",
+    "include/grpc/support/port_platform.h",
+    "include/grpc/support/slice.h",
+    "include/grpc/support/slice_buffer.h",
+    "include/grpc/support/sync.h",
+    "include/grpc/support/sync_generic.h",
+    "include/grpc/support/sync_posix.h",
+    "include/grpc/support/sync_win32.h",
+    "include/grpc/support/thd.h",
+    "include/grpc/support/time.h",
+    "include/grpc/support/tls.h",
+    "include/grpc/support/tls_gcc.h",
+    "include/grpc/support/tls_msvc.h",
+    "include/grpc/support/tls_pthread.h",
+    "include/grpc/support/useful.h",
+  ],
+  includes = [
+    "include",
+    ".",
+  ],
+  deps = [
+  ],
+)
+
+
+cc_library(
+  name = "grpc",
+  srcs = [
+    "src/core/httpcli/format_request.h",
+    "src/core/httpcli/httpcli.h",
+    "src/core/httpcli/httpcli_security_context.h",
+    "src/core/httpcli/parser.h",
+    "src/core/security/auth.h",
+    "src/core/security/base64.h",
+    "src/core/security/credentials.h",
+    "src/core/security/json_token.h",
+    "src/core/security/secure_endpoint.h",
+    "src/core/security/secure_transport_setup.h",
+    "src/core/security/security_context.h",
+    "src/core/tsi/fake_transport_security.h",
+    "src/core/tsi/ssl_transport_security.h",
+    "src/core/tsi/transport_security.h",
+    "src/core/tsi/transport_security_interface.h",
+    "src/core/channel/census_filter.h",
+    "src/core/channel/channel_args.h",
+    "src/core/channel/channel_stack.h",
+    "src/core/channel/child_channel.h",
+    "src/core/channel/client_channel.h",
+    "src/core/channel/client_setup.h",
+    "src/core/channel/connected_channel.h",
+    "src/core/channel/http_client_filter.h",
+    "src/core/channel/http_filter.h",
+    "src/core/channel/http_server_filter.h",
+    "src/core/channel/metadata_buffer.h",
+    "src/core/channel/noop_filter.h",
+    "src/core/compression/algorithm.h",
+    "src/core/compression/message_compress.h",
+    "src/core/debug/trace.h",
+    "src/core/iomgr/alarm.h",
+    "src/core/iomgr/alarm_heap.h",
+    "src/core/iomgr/alarm_internal.h",
+    "src/core/iomgr/endpoint.h",
+    "src/core/iomgr/endpoint_pair.h",
+    "src/core/iomgr/fd_posix.h",
+    "src/core/iomgr/iocp_windows.h",
+    "src/core/iomgr/iomgr.h",
+    "src/core/iomgr/iomgr_internal.h",
+    "src/core/iomgr/iomgr_posix.h",
+    "src/core/iomgr/pollset.h",
+    "src/core/iomgr/pollset_kick.h",
+    "src/core/iomgr/pollset_kick_posix.h",
+    "src/core/iomgr/pollset_kick_windows.h",
+    "src/core/iomgr/pollset_posix.h",
+    "src/core/iomgr/pollset_windows.h",
+    "src/core/iomgr/resolve_address.h",
+    "src/core/iomgr/sockaddr.h",
+    "src/core/iomgr/sockaddr_posix.h",
+    "src/core/iomgr/sockaddr_utils.h",
+    "src/core/iomgr/sockaddr_win32.h",
+    "src/core/iomgr/socket_utils_posix.h",
+    "src/core/iomgr/socket_windows.h",
+    "src/core/iomgr/tcp_client.h",
+    "src/core/iomgr/tcp_posix.h",
+    "src/core/iomgr/tcp_server.h",
+    "src/core/iomgr/tcp_windows.h",
+    "src/core/iomgr/time_averaged_stats.h",
+    "src/core/iomgr/wakeup_fd_pipe.h",
+    "src/core/iomgr/wakeup_fd_posix.h",
+    "src/core/json/json.h",
+    "src/core/json/json_common.h",
+    "src/core/json/json_reader.h",
+    "src/core/json/json_writer.h",
+    "src/core/statistics/census_interface.h",
+    "src/core/statistics/census_log.h",
+    "src/core/statistics/census_rpc_stats.h",
+    "src/core/statistics/census_tracing.h",
+    "src/core/statistics/hash_table.h",
+    "src/core/statistics/window_stats.h",
+    "src/core/surface/byte_buffer_queue.h",
+    "src/core/surface/call.h",
+    "src/core/surface/channel.h",
+    "src/core/surface/client.h",
+    "src/core/surface/completion_queue.h",
+    "src/core/surface/event_string.h",
+    "src/core/surface/init.h",
+    "src/core/surface/server.h",
+    "src/core/surface/surface_trace.h",
+    "src/core/transport/chttp2/alpn.h",
+    "src/core/transport/chttp2/bin_encoder.h",
+    "src/core/transport/chttp2/frame.h",
+    "src/core/transport/chttp2/frame_data.h",
+    "src/core/transport/chttp2/frame_goaway.h",
+    "src/core/transport/chttp2/frame_ping.h",
+    "src/core/transport/chttp2/frame_rst_stream.h",
+    "src/core/transport/chttp2/frame_settings.h",
+    "src/core/transport/chttp2/frame_window_update.h",
+    "src/core/transport/chttp2/hpack_parser.h",
+    "src/core/transport/chttp2/hpack_table.h",
+    "src/core/transport/chttp2/http2_errors.h",
+    "src/core/transport/chttp2/huffsyms.h",
+    "src/core/transport/chttp2/status_conversion.h",
+    "src/core/transport/chttp2/stream_encoder.h",
+    "src/core/transport/chttp2/stream_map.h",
+    "src/core/transport/chttp2/timeout_encoding.h",
+    "src/core/transport/chttp2/varint.h",
+    "src/core/transport/chttp2_transport.h",
+    "src/core/transport/metadata.h",
+    "src/core/transport/stream_op.h",
+    "src/core/transport/transport.h",
+    "src/core/transport/transport_impl.h",
+    "src/core/httpcli/format_request.c",
+    "src/core/httpcli/httpcli.c",
+    "src/core/httpcli/httpcli_security_context.c",
+    "src/core/httpcli/parser.c",
+    "src/core/security/auth.c",
+    "src/core/security/base64.c",
+    "src/core/security/credentials.c",
+    "src/core/security/credentials_posix.c",
+    "src/core/security/credentials_win32.c",
+    "src/core/security/factories.c",
+    "src/core/security/google_default_credentials.c",
+    "src/core/security/json_token.c",
+    "src/core/security/secure_endpoint.c",
+    "src/core/security/secure_transport_setup.c",
+    "src/core/security/security_context.c",
+    "src/core/security/server_secure_chttp2.c",
+    "src/core/surface/init_secure.c",
+    "src/core/surface/secure_channel_create.c",
+    "src/core/tsi/fake_transport_security.c",
+    "src/core/tsi/ssl_transport_security.c",
+    "src/core/tsi/transport_security.c",
+    "src/core/channel/call_op_string.c",
+    "src/core/channel/census_filter.c",
+    "src/core/channel/channel_args.c",
+    "src/core/channel/channel_stack.c",
+    "src/core/channel/child_channel.c",
+    "src/core/channel/client_channel.c",
+    "src/core/channel/client_setup.c",
+    "src/core/channel/connected_channel.c",
+    "src/core/channel/http_client_filter.c",
+    "src/core/channel/http_filter.c",
+    "src/core/channel/http_server_filter.c",
+    "src/core/channel/metadata_buffer.c",
+    "src/core/channel/noop_filter.c",
+    "src/core/compression/algorithm.c",
+    "src/core/compression/message_compress.c",
+    "src/core/debug/trace.c",
+    "src/core/iomgr/alarm.c",
+    "src/core/iomgr/alarm_heap.c",
+    "src/core/iomgr/endpoint.c",
+    "src/core/iomgr/endpoint_pair_posix.c",
+    "src/core/iomgr/endpoint_pair_windows.c",
+    "src/core/iomgr/fd_posix.c",
+    "src/core/iomgr/iocp_windows.c",
+    "src/core/iomgr/iomgr.c",
+    "src/core/iomgr/iomgr_posix.c",
+    "src/core/iomgr/iomgr_windows.c",
+    "src/core/iomgr/pollset_kick.c",
+    "src/core/iomgr/pollset_multipoller_with_epoll.c",
+    "src/core/iomgr/pollset_multipoller_with_poll_posix.c",
+    "src/core/iomgr/pollset_posix.c",
+    "src/core/iomgr/pollset_windows.c",
+    "src/core/iomgr/resolve_address_posix.c",
+    "src/core/iomgr/resolve_address_windows.c",
+    "src/core/iomgr/sockaddr_utils.c",
+    "src/core/iomgr/socket_utils_common_posix.c",
+    "src/core/iomgr/socket_utils_linux.c",
+    "src/core/iomgr/socket_utils_posix.c",
+    "src/core/iomgr/socket_windows.c",
+    "src/core/iomgr/tcp_client_posix.c",
+    "src/core/iomgr/tcp_client_windows.c",
+    "src/core/iomgr/tcp_posix.c",
+    "src/core/iomgr/tcp_server_posix.c",
+    "src/core/iomgr/tcp_server_windows.c",
+    "src/core/iomgr/tcp_windows.c",
+    "src/core/iomgr/time_averaged_stats.c",
+    "src/core/iomgr/wakeup_fd_eventfd.c",
+    "src/core/iomgr/wakeup_fd_nospecial.c",
+    "src/core/iomgr/wakeup_fd_pipe.c",
+    "src/core/iomgr/wakeup_fd_posix.c",
+    "src/core/json/json.c",
+    "src/core/json/json_reader.c",
+    "src/core/json/json_string.c",
+    "src/core/json/json_writer.c",
+    "src/core/statistics/census_init.c",
+    "src/core/statistics/census_log.c",
+    "src/core/statistics/census_rpc_stats.c",
+    "src/core/statistics/census_tracing.c",
+    "src/core/statistics/hash_table.c",
+    "src/core/statistics/window_stats.c",
+    "src/core/surface/byte_buffer.c",
+    "src/core/surface/byte_buffer_queue.c",
+    "src/core/surface/byte_buffer_reader.c",
+    "src/core/surface/call.c",
+    "src/core/surface/call_details.c",
+    "src/core/surface/call_log_batch.c",
+    "src/core/surface/channel.c",
+    "src/core/surface/channel_create.c",
+    "src/core/surface/client.c",
+    "src/core/surface/completion_queue.c",
+    "src/core/surface/event_string.c",
+    "src/core/surface/init.c",
+    "src/core/surface/lame_client.c",
+    "src/core/surface/metadata_array.c",
+    "src/core/surface/server.c",
+    "src/core/surface/server_chttp2.c",
+    "src/core/surface/server_create.c",
+    "src/core/surface/surface_trace.c",
+    "src/core/transport/chttp2/alpn.c",
+    "src/core/transport/chttp2/bin_encoder.c",
+    "src/core/transport/chttp2/frame_data.c",
+    "src/core/transport/chttp2/frame_goaway.c",
+    "src/core/transport/chttp2/frame_ping.c",
+    "src/core/transport/chttp2/frame_rst_stream.c",
+    "src/core/transport/chttp2/frame_settings.c",
+    "src/core/transport/chttp2/frame_window_update.c",
+    "src/core/transport/chttp2/hpack_parser.c",
+    "src/core/transport/chttp2/hpack_table.c",
+    "src/core/transport/chttp2/huffsyms.c",
+    "src/core/transport/chttp2/status_conversion.c",
+    "src/core/transport/chttp2/stream_encoder.c",
+    "src/core/transport/chttp2/stream_map.c",
+    "src/core/transport/chttp2/timeout_encoding.c",
+    "src/core/transport/chttp2/varint.c",
+    "src/core/transport/chttp2_transport.c",
+    "src/core/transport/metadata.c",
+    "src/core/transport/stream_op.c",
+    "src/core/transport/transport.c",
+  ],
+  hdrs = [
+    "include/grpc/grpc_security.h",
+    "include/grpc/byte_buffer.h",
+    "include/grpc/byte_buffer_reader.h",
+    "include/grpc/grpc.h",
+    "include/grpc/grpc_http.h",
+    "include/grpc/status.h",
+  ],
+  includes = [
+    "include",
+    ".",
+  ],
+  deps = [
+    "//external:libssl",
+    ":gpr",
+  ],
+)
 
 
 cc_library(
-    name = "gpr",
-    srcs = [
-        "src/core/support/env.h",
-        "src/core/support/file.h",
-        "src/core/support/murmur_hash.h",
-        "src/core/support/string.h",
-        "src/core/support/string_win32.h",
-        "src/core/support/thd_internal.h",
-        "src/core/support/alloc.c",
-        "src/core/support/cancellable.c",
-        "src/core/support/cmdline.c",
-        "src/core/support/cpu_iphone.c",
-        "src/core/support/cpu_linux.c",
-        "src/core/support/cpu_posix.c",
-        "src/core/support/cpu_windows.c",
-        "src/core/support/env_linux.c",
-        "src/core/support/env_posix.c",
-        "src/core/support/env_win32.c",
-        "src/core/support/file.c",
-        "src/core/support/file_posix.c",
-        "src/core/support/file_win32.c",
-        "src/core/support/histogram.c",
-        "src/core/support/host_port.c",
-        "src/core/support/log.c",
-        "src/core/support/log_android.c",
-        "src/core/support/log_linux.c",
-        "src/core/support/log_posix.c",
-        "src/core/support/log_win32.c",
-        "src/core/support/murmur_hash.c",
-        "src/core/support/slice.c",
-        "src/core/support/slice_buffer.c",
-        "src/core/support/string.c",
-        "src/core/support/string_posix.c",
-        "src/core/support/string_win32.c",
-        "src/core/support/sync.c",
-        "src/core/support/sync_posix.c",
-        "src/core/support/sync_win32.c",
-        "src/core/support/thd.c",
-        "src/core/support/thd_posix.c",
-        "src/core/support/thd_win32.c",
-        "src/core/support/time.c",
-        "src/core/support/time_posix.c",
-        "src/core/support/time_win32.c",
-    ],
-    hdrs = [
-        "include/grpc/support/alloc.h",
-        "include/grpc/support/atm.h",
-        "include/grpc/support/atm_gcc_atomic.h",
-        "include/grpc/support/atm_gcc_sync.h",
-        "include/grpc/support/atm_win32.h",
-        "include/grpc/support/cancellable_platform.h",
-        "include/grpc/support/cmdline.h",
-        "include/grpc/support/cpu.h",
-        "include/grpc/support/histogram.h",
-        "include/grpc/support/host_port.h",
-        "include/grpc/support/log.h",
-        "include/grpc/support/log_win32.h",
-        "include/grpc/support/port_platform.h",
-        "include/grpc/support/slice.h",
-        "include/grpc/support/slice_buffer.h",
-        "include/grpc/support/sync.h",
-        "include/grpc/support/sync_generic.h",
-        "include/grpc/support/sync_posix.h",
-        "include/grpc/support/sync_win32.h",
-        "include/grpc/support/thd.h",
-        "include/grpc/support/time.h",
-        "include/grpc/support/useful.h",
-    ],
-    includes = [
-        "include",
-        ".",
-    ],
-    deps = [
-    ],
+  name = "grpc_unsecure",
+  srcs = [
+    "src/core/channel/census_filter.h",
+    "src/core/channel/channel_args.h",
+    "src/core/channel/channel_stack.h",
+    "src/core/channel/child_channel.h",
+    "src/core/channel/client_channel.h",
+    "src/core/channel/client_setup.h",
+    "src/core/channel/connected_channel.h",
+    "src/core/channel/http_client_filter.h",
+    "src/core/channel/http_filter.h",
+    "src/core/channel/http_server_filter.h",
+    "src/core/channel/metadata_buffer.h",
+    "src/core/channel/noop_filter.h",
+    "src/core/compression/algorithm.h",
+    "src/core/compression/message_compress.h",
+    "src/core/debug/trace.h",
+    "src/core/iomgr/alarm.h",
+    "src/core/iomgr/alarm_heap.h",
+    "src/core/iomgr/alarm_internal.h",
+    "src/core/iomgr/endpoint.h",
+    "src/core/iomgr/endpoint_pair.h",
+    "src/core/iomgr/fd_posix.h",
+    "src/core/iomgr/iocp_windows.h",
+    "src/core/iomgr/iomgr.h",
+    "src/core/iomgr/iomgr_internal.h",
+    "src/core/iomgr/iomgr_posix.h",
+    "src/core/iomgr/pollset.h",
+    "src/core/iomgr/pollset_kick.h",
+    "src/core/iomgr/pollset_kick_posix.h",
+    "src/core/iomgr/pollset_kick_windows.h",
+    "src/core/iomgr/pollset_posix.h",
+    "src/core/iomgr/pollset_windows.h",
+    "src/core/iomgr/resolve_address.h",
+    "src/core/iomgr/sockaddr.h",
+    "src/core/iomgr/sockaddr_posix.h",
+    "src/core/iomgr/sockaddr_utils.h",
+    "src/core/iomgr/sockaddr_win32.h",
+    "src/core/iomgr/socket_utils_posix.h",
+    "src/core/iomgr/socket_windows.h",
+    "src/core/iomgr/tcp_client.h",
+    "src/core/iomgr/tcp_posix.h",
+    "src/core/iomgr/tcp_server.h",
+    "src/core/iomgr/tcp_windows.h",
+    "src/core/iomgr/time_averaged_stats.h",
+    "src/core/iomgr/wakeup_fd_pipe.h",
+    "src/core/iomgr/wakeup_fd_posix.h",
+    "src/core/json/json.h",
+    "src/core/json/json_common.h",
+    "src/core/json/json_reader.h",
+    "src/core/json/json_writer.h",
+    "src/core/statistics/census_interface.h",
+    "src/core/statistics/census_log.h",
+    "src/core/statistics/census_rpc_stats.h",
+    "src/core/statistics/census_tracing.h",
+    "src/core/statistics/hash_table.h",
+    "src/core/statistics/window_stats.h",
+    "src/core/surface/byte_buffer_queue.h",
+    "src/core/surface/call.h",
+    "src/core/surface/channel.h",
+    "src/core/surface/client.h",
+    "src/core/surface/completion_queue.h",
+    "src/core/surface/event_string.h",
+    "src/core/surface/init.h",
+    "src/core/surface/server.h",
+    "src/core/surface/surface_trace.h",
+    "src/core/transport/chttp2/alpn.h",
+    "src/core/transport/chttp2/bin_encoder.h",
+    "src/core/transport/chttp2/frame.h",
+    "src/core/transport/chttp2/frame_data.h",
+    "src/core/transport/chttp2/frame_goaway.h",
+    "src/core/transport/chttp2/frame_ping.h",
+    "src/core/transport/chttp2/frame_rst_stream.h",
+    "src/core/transport/chttp2/frame_settings.h",
+    "src/core/transport/chttp2/frame_window_update.h",
+    "src/core/transport/chttp2/hpack_parser.h",
+    "src/core/transport/chttp2/hpack_table.h",
+    "src/core/transport/chttp2/http2_errors.h",
+    "src/core/transport/chttp2/huffsyms.h",
+    "src/core/transport/chttp2/status_conversion.h",
+    "src/core/transport/chttp2/stream_encoder.h",
+    "src/core/transport/chttp2/stream_map.h",
+    "src/core/transport/chttp2/timeout_encoding.h",
+    "src/core/transport/chttp2/varint.h",
+    "src/core/transport/chttp2_transport.h",
+    "src/core/transport/metadata.h",
+    "src/core/transport/stream_op.h",
+    "src/core/transport/transport.h",
+    "src/core/transport/transport_impl.h",
+    "src/core/surface/init_unsecure.c",
+    "src/core/channel/call_op_string.c",
+    "src/core/channel/census_filter.c",
+    "src/core/channel/channel_args.c",
+    "src/core/channel/channel_stack.c",
+    "src/core/channel/child_channel.c",
+    "src/core/channel/client_channel.c",
+    "src/core/channel/client_setup.c",
+    "src/core/channel/connected_channel.c",
+    "src/core/channel/http_client_filter.c",
+    "src/core/channel/http_filter.c",
+    "src/core/channel/http_server_filter.c",
+    "src/core/channel/metadata_buffer.c",
+    "src/core/channel/noop_filter.c",
+    "src/core/compression/algorithm.c",
+    "src/core/compression/message_compress.c",
+    "src/core/debug/trace.c",
+    "src/core/iomgr/alarm.c",
+    "src/core/iomgr/alarm_heap.c",
+    "src/core/iomgr/endpoint.c",
+    "src/core/iomgr/endpoint_pair_posix.c",
+    "src/core/iomgr/endpoint_pair_windows.c",
+    "src/core/iomgr/fd_posix.c",
+    "src/core/iomgr/iocp_windows.c",
+    "src/core/iomgr/iomgr.c",
+    "src/core/iomgr/iomgr_posix.c",
+    "src/core/iomgr/iomgr_windows.c",
+    "src/core/iomgr/pollset_kick.c",
+    "src/core/iomgr/pollset_multipoller_with_epoll.c",
+    "src/core/iomgr/pollset_multipoller_with_poll_posix.c",
+    "src/core/iomgr/pollset_posix.c",
+    "src/core/iomgr/pollset_windows.c",
+    "src/core/iomgr/resolve_address_posix.c",
+    "src/core/iomgr/resolve_address_windows.c",
+    "src/core/iomgr/sockaddr_utils.c",
+    "src/core/iomgr/socket_utils_common_posix.c",
+    "src/core/iomgr/socket_utils_linux.c",
+    "src/core/iomgr/socket_utils_posix.c",
+    "src/core/iomgr/socket_windows.c",
+    "src/core/iomgr/tcp_client_posix.c",
+    "src/core/iomgr/tcp_client_windows.c",
+    "src/core/iomgr/tcp_posix.c",
+    "src/core/iomgr/tcp_server_posix.c",
+    "src/core/iomgr/tcp_server_windows.c",
+    "src/core/iomgr/tcp_windows.c",
+    "src/core/iomgr/time_averaged_stats.c",
+    "src/core/iomgr/wakeup_fd_eventfd.c",
+    "src/core/iomgr/wakeup_fd_nospecial.c",
+    "src/core/iomgr/wakeup_fd_pipe.c",
+    "src/core/iomgr/wakeup_fd_posix.c",
+    "src/core/json/json.c",
+    "src/core/json/json_reader.c",
+    "src/core/json/json_string.c",
+    "src/core/json/json_writer.c",
+    "src/core/statistics/census_init.c",
+    "src/core/statistics/census_log.c",
+    "src/core/statistics/census_rpc_stats.c",
+    "src/core/statistics/census_tracing.c",
+    "src/core/statistics/hash_table.c",
+    "src/core/statistics/window_stats.c",
+    "src/core/surface/byte_buffer.c",
+    "src/core/surface/byte_buffer_queue.c",
+    "src/core/surface/byte_buffer_reader.c",
+    "src/core/surface/call.c",
+    "src/core/surface/call_details.c",
+    "src/core/surface/call_log_batch.c",
+    "src/core/surface/channel.c",
+    "src/core/surface/channel_create.c",
+    "src/core/surface/client.c",
+    "src/core/surface/completion_queue.c",
+    "src/core/surface/event_string.c",
+    "src/core/surface/init.c",
+    "src/core/surface/lame_client.c",
+    "src/core/surface/metadata_array.c",
+    "src/core/surface/server.c",
+    "src/core/surface/server_chttp2.c",
+    "src/core/surface/server_create.c",
+    "src/core/surface/surface_trace.c",
+    "src/core/transport/chttp2/alpn.c",
+    "src/core/transport/chttp2/bin_encoder.c",
+    "src/core/transport/chttp2/frame_data.c",
+    "src/core/transport/chttp2/frame_goaway.c",
+    "src/core/transport/chttp2/frame_ping.c",
+    "src/core/transport/chttp2/frame_rst_stream.c",
+    "src/core/transport/chttp2/frame_settings.c",
+    "src/core/transport/chttp2/frame_window_update.c",
+    "src/core/transport/chttp2/hpack_parser.c",
+    "src/core/transport/chttp2/hpack_table.c",
+    "src/core/transport/chttp2/huffsyms.c",
+    "src/core/transport/chttp2/status_conversion.c",
+    "src/core/transport/chttp2/stream_encoder.c",
+    "src/core/transport/chttp2/stream_map.c",
+    "src/core/transport/chttp2/timeout_encoding.c",
+    "src/core/transport/chttp2/varint.c",
+    "src/core/transport/chttp2_transport.c",
+    "src/core/transport/metadata.c",
+    "src/core/transport/stream_op.c",
+    "src/core/transport/transport.c",
+  ],
+  hdrs = [
+    "include/grpc/byte_buffer.h",
+    "include/grpc/byte_buffer_reader.h",
+    "include/grpc/grpc.h",
+    "include/grpc/grpc_http.h",
+    "include/grpc/status.h",
+  ],
+  includes = [
+    "include",
+    ".",
+  ],
+  deps = [
+    ":gpr",
+  ],
 )
 
 
+cc_library(
+  name = "grpc++",
+  srcs = [
+    "src/cpp/client/secure_credentials.h",
+    "src/cpp/server/secure_server_credentials.h",
+    "src/cpp/client/channel.h",
+    "src/cpp/proto/proto_utils.h",
+    "src/cpp/server/thread_pool.h",
+    "src/cpp/util/time.h",
+    "src/cpp/client/secure_credentials.cc",
+    "src/cpp/server/secure_server_credentials.cc",
+    "src/cpp/client/channel.cc",
+    "src/cpp/client/channel_arguments.cc",
+    "src/cpp/client/client_context.cc",
+    "src/cpp/client/client_unary_call.cc",
+    "src/cpp/client/create_channel.cc",
+    "src/cpp/client/credentials.cc",
+    "src/cpp/client/generic_stub.cc",
+    "src/cpp/client/insecure_credentials.cc",
+    "src/cpp/client/internal_stub.cc",
+    "src/cpp/common/call.cc",
+    "src/cpp/common/completion_queue.cc",
+    "src/cpp/common/rpc_method.cc",
+    "src/cpp/proto/proto_utils.cc",
+    "src/cpp/server/async_generic_service.cc",
+    "src/cpp/server/insecure_server_credentials.cc",
+    "src/cpp/server/server.cc",
+    "src/cpp/server/server_builder.cc",
+    "src/cpp/server/server_context.cc",
+    "src/cpp/server/server_credentials.cc",
+    "src/cpp/server/thread_pool.cc",
+    "src/cpp/util/byte_buffer.cc",
+    "src/cpp/util/slice.cc",
+    "src/cpp/util/status.cc",
+    "src/cpp/util/time.cc",
+  ],
+  hdrs = [
+    "include/grpc++/async_generic_service.h",
+    "include/grpc++/async_unary_call.h",
+    "include/grpc++/byte_buffer.h",
+    "include/grpc++/channel_arguments.h",
+    "include/grpc++/channel_interface.h",
+    "include/grpc++/client_context.h",
+    "include/grpc++/completion_queue.h",
+    "include/grpc++/config.h",
+    "include/grpc++/create_channel.h",
+    "include/grpc++/credentials.h",
+    "include/grpc++/generic_stub.h",
+    "include/grpc++/impl/call.h",
+    "include/grpc++/impl/client_unary_call.h",
+    "include/grpc++/impl/internal_stub.h",
+    "include/grpc++/impl/rpc_method.h",
+    "include/grpc++/impl/rpc_service_method.h",
+    "include/grpc++/impl/service_type.h",
+    "include/grpc++/impl/sync.h",
+    "include/grpc++/impl/sync_cxx11.h",
+    "include/grpc++/impl/sync_no_cxx11.h",
+    "include/grpc++/impl/thd.h",
+    "include/grpc++/impl/thd_cxx11.h",
+    "include/grpc++/impl/thd_no_cxx11.h",
+    "include/grpc++/server.h",
+    "include/grpc++/server_builder.h",
+    "include/grpc++/server_context.h",
+    "include/grpc++/server_credentials.h",
+    "include/grpc++/slice.h",
+    "include/grpc++/status.h",
+    "include/grpc++/status_code_enum.h",
+    "include/grpc++/stream.h",
+    "include/grpc++/thread_pool_interface.h",
+  ],
+  includes = [
+    "include",
+    ".",
+  ],
+  deps = [
+    "//external:protobuf_clib",
+    ":gpr",
+    ":grpc",
+  ],
+)
 
 
 cc_library(
-    name = "grpc",
-    srcs = [
-        "src/core/httpcli/format_request.h",
-        "src/core/httpcli/httpcli.h",
-        "src/core/httpcli/httpcli_security_context.h",
-        "src/core/httpcli/parser.h",
-        "src/core/security/auth.h",
-        "src/core/security/base64.h",
-        "src/core/security/credentials.h",
-        "src/core/security/json_token.h",
-        "src/core/security/secure_endpoint.h",
-        "src/core/security/secure_transport_setup.h",
-        "src/core/security/security_context.h",
-        "src/core/tsi/fake_transport_security.h",
-        "src/core/tsi/ssl_transport_security.h",
-        "src/core/tsi/transport_security.h",
-        "src/core/tsi/transport_security_interface.h",
-        "src/core/channel/census_filter.h",
-        "src/core/channel/channel_args.h",
-        "src/core/channel/channel_stack.h",
-        "src/core/channel/child_channel.h",
-        "src/core/channel/client_channel.h",
-        "src/core/channel/client_setup.h",
-        "src/core/channel/connected_channel.h",
-        "src/core/channel/http_client_filter.h",
-        "src/core/channel/http_filter.h",
-        "src/core/channel/http_server_filter.h",
-        "src/core/channel/metadata_buffer.h",
-        "src/core/channel/noop_filter.h",
-        "src/core/compression/algorithm.h",
-        "src/core/compression/message_compress.h",
-        "src/core/debug/trace.h",
-        "src/core/iomgr/alarm.h",
-        "src/core/iomgr/alarm_heap.h",
-        "src/core/iomgr/alarm_internal.h",
-        "src/core/iomgr/endpoint.h",
-        "src/core/iomgr/endpoint_pair.h",
-        "src/core/iomgr/fd_posix.h",
-        "src/core/iomgr/iocp_windows.h",
-        "src/core/iomgr/iomgr.h",
-        "src/core/iomgr/iomgr_internal.h",
-        "src/core/iomgr/iomgr_posix.h",
-        "src/core/iomgr/pollset.h",
-        "src/core/iomgr/pollset_kick.h",
-        "src/core/iomgr/pollset_kick_posix.h",
-        "src/core/iomgr/pollset_kick_windows.h",
-        "src/core/iomgr/pollset_posix.h",
-        "src/core/iomgr/pollset_windows.h",
-        "src/core/iomgr/resolve_address.h",
-        "src/core/iomgr/sockaddr.h",
-        "src/core/iomgr/sockaddr_posix.h",
-        "src/core/iomgr/sockaddr_utils.h",
-        "src/core/iomgr/sockaddr_win32.h",
-        "src/core/iomgr/socket_utils_posix.h",
-        "src/core/iomgr/socket_windows.h",
-        "src/core/iomgr/tcp_client.h",
-        "src/core/iomgr/tcp_posix.h",
-        "src/core/iomgr/tcp_server.h",
-        "src/core/iomgr/tcp_windows.h",
-        "src/core/iomgr/time_averaged_stats.h",
-        "src/core/iomgr/wakeup_fd_pipe.h",
-        "src/core/iomgr/wakeup_fd_posix.h",
-        "src/core/json/json.h",
-        "src/core/json/json_common.h",
-        "src/core/json/json_reader.h",
-        "src/core/json/json_writer.h",
-        "src/core/statistics/census_interface.h",
-        "src/core/statistics/census_log.h",
-        "src/core/statistics/census_rpc_stats.h",
-        "src/core/statistics/census_tracing.h",
-        "src/core/statistics/hash_table.h",
-        "src/core/statistics/window_stats.h",
-        "src/core/surface/byte_buffer_queue.h",
-        "src/core/surface/call.h",
-        "src/core/surface/channel.h",
-        "src/core/surface/client.h",
-        "src/core/surface/completion_queue.h",
-        "src/core/surface/event_string.h",
-        "src/core/surface/init.h",
-        "src/core/surface/server.h",
-        "src/core/surface/surface_trace.h",
-        "src/core/transport/chttp2/alpn.h",
-        "src/core/transport/chttp2/bin_encoder.h",
-        "src/core/transport/chttp2/frame.h",
-        "src/core/transport/chttp2/frame_data.h",
-        "src/core/transport/chttp2/frame_goaway.h",
-        "src/core/transport/chttp2/frame_ping.h",
-        "src/core/transport/chttp2/frame_rst_stream.h",
-        "src/core/transport/chttp2/frame_settings.h",
-        "src/core/transport/chttp2/frame_window_update.h",
-        "src/core/transport/chttp2/hpack_parser.h",
-        "src/core/transport/chttp2/hpack_table.h",
-        "src/core/transport/chttp2/http2_errors.h",
-        "src/core/transport/chttp2/huffsyms.h",
-        "src/core/transport/chttp2/status_conversion.h",
-        "src/core/transport/chttp2/stream_encoder.h",
-        "src/core/transport/chttp2/stream_map.h",
-        "src/core/transport/chttp2/timeout_encoding.h",
-        "src/core/transport/chttp2/varint.h",
-        "src/core/transport/chttp2_transport.h",
-        "src/core/transport/metadata.h",
-        "src/core/transport/stream_op.h",
-        "src/core/transport/transport.h",
-        "src/core/transport/transport_impl.h",
-        "src/core/httpcli/format_request.c",
-        "src/core/httpcli/httpcli.c",
-        "src/core/httpcli/httpcli_security_context.c",
-        "src/core/httpcli/parser.c",
-        "src/core/security/auth.c",
-        "src/core/security/base64.c",
-        "src/core/security/credentials.c",
-        "src/core/security/credentials_posix.c",
-        "src/core/security/credentials_win32.c",
-        "src/core/security/factories.c",
-        "src/core/security/google_default_credentials.c",
-        "src/core/security/json_token.c",
-        "src/core/security/secure_endpoint.c",
-        "src/core/security/secure_transport_setup.c",
-        "src/core/security/security_context.c",
-        "src/core/security/server_secure_chttp2.c",
-        "src/core/surface/init_secure.c",
-        "src/core/surface/secure_channel_create.c",
-        "src/core/tsi/fake_transport_security.c",
-        "src/core/tsi/ssl_transport_security.c",
-        "src/core/tsi/transport_security.c",
-        "src/core/channel/call_op_string.c",
-        "src/core/channel/census_filter.c",
-        "src/core/channel/channel_args.c",
-        "src/core/channel/channel_stack.c",
-        "src/core/channel/child_channel.c",
-        "src/core/channel/client_channel.c",
-        "src/core/channel/client_setup.c",
-        "src/core/channel/connected_channel.c",
-        "src/core/channel/http_client_filter.c",
-        "src/core/channel/http_filter.c",
-        "src/core/channel/http_server_filter.c",
-        "src/core/channel/metadata_buffer.c",
-        "src/core/channel/noop_filter.c",
-        "src/core/compression/algorithm.c",
-        "src/core/compression/message_compress.c",
-        "src/core/debug/trace.c",
-        "src/core/iomgr/alarm.c",
-        "src/core/iomgr/alarm_heap.c",
-        "src/core/iomgr/endpoint.c",
-        "src/core/iomgr/endpoint_pair_posix.c",
-        "src/core/iomgr/fd_posix.c",
-        "src/core/iomgr/iocp_windows.c",
-        "src/core/iomgr/iomgr.c",
-        "src/core/iomgr/iomgr_posix.c",
-        "src/core/iomgr/iomgr_windows.c",
-        "src/core/iomgr/pollset_kick.c",
-        "src/core/iomgr/pollset_multipoller_with_epoll.c",
-        "src/core/iomgr/pollset_multipoller_with_poll_posix.c",
-        "src/core/iomgr/pollset_posix.c",
-        "src/core/iomgr/pollset_windows.c",
-        "src/core/iomgr/resolve_address_posix.c",
-        "src/core/iomgr/resolve_address_windows.c",
-        "src/core/iomgr/sockaddr_utils.c",
-        "src/core/iomgr/socket_utils_common_posix.c",
-        "src/core/iomgr/socket_utils_linux.c",
-        "src/core/iomgr/socket_utils_posix.c",
-        "src/core/iomgr/socket_windows.c",
-        "src/core/iomgr/tcp_client_posix.c",
-        "src/core/iomgr/tcp_client_windows.c",
-        "src/core/iomgr/tcp_posix.c",
-        "src/core/iomgr/tcp_server_posix.c",
-        "src/core/iomgr/tcp_server_windows.c",
-        "src/core/iomgr/tcp_windows.c",
-        "src/core/iomgr/time_averaged_stats.c",
-        "src/core/iomgr/wakeup_fd_eventfd.c",
-        "src/core/iomgr/wakeup_fd_nospecial.c",
-        "src/core/iomgr/wakeup_fd_pipe.c",
-        "src/core/iomgr/wakeup_fd_posix.c",
-        "src/core/json/json.c",
-        "src/core/json/json_reader.c",
-        "src/core/json/json_string.c",
-        "src/core/json/json_writer.c",
-        "src/core/statistics/census_init.c",
-        "src/core/statistics/census_log.c",
-        "src/core/statistics/census_rpc_stats.c",
-        "src/core/statistics/census_tracing.c",
-        "src/core/statistics/hash_table.c",
-        "src/core/statistics/window_stats.c",
-        "src/core/surface/byte_buffer.c",
-        "src/core/surface/byte_buffer_queue.c",
-        "src/core/surface/byte_buffer_reader.c",
-        "src/core/surface/call.c",
-        "src/core/surface/call_details.c",
-        "src/core/surface/call_log_batch.c",
-        "src/core/surface/channel.c",
-        "src/core/surface/channel_create.c",
-        "src/core/surface/client.c",
-        "src/core/surface/completion_queue.c",
-        "src/core/surface/event_string.c",
-        "src/core/surface/init.c",
-        "src/core/surface/lame_client.c",
-        "src/core/surface/metadata_array.c",
-        "src/core/surface/server.c",
-        "src/core/surface/server_chttp2.c",
-        "src/core/surface/server_create.c",
-        "src/core/surface/surface_trace.c",
-        "src/core/transport/chttp2/alpn.c",
-        "src/core/transport/chttp2/bin_encoder.c",
-        "src/core/transport/chttp2/frame_data.c",
-        "src/core/transport/chttp2/frame_goaway.c",
-        "src/core/transport/chttp2/frame_ping.c",
-        "src/core/transport/chttp2/frame_rst_stream.c",
-        "src/core/transport/chttp2/frame_settings.c",
-        "src/core/transport/chttp2/frame_window_update.c",
-        "src/core/transport/chttp2/hpack_parser.c",
-        "src/core/transport/chttp2/hpack_table.c",
-        "src/core/transport/chttp2/huffsyms.c",
-        "src/core/transport/chttp2/status_conversion.c",
-        "src/core/transport/chttp2/stream_encoder.c",
-        "src/core/transport/chttp2/stream_map.c",
-        "src/core/transport/chttp2/timeout_encoding.c",
-        "src/core/transport/chttp2/varint.c",
-        "src/core/transport/chttp2_transport.c",
-        "src/core/transport/metadata.c",
-        "src/core/transport/stream_op.c",
-        "src/core/transport/transport.c",
-    ],
-    hdrs = [
-        "include/grpc/grpc_security.h",
-        "include/grpc/byte_buffer.h",
-        "include/grpc/byte_buffer_reader.h",
-        "include/grpc/grpc.h",
-        "include/grpc/grpc_http.h",
-        "include/grpc/status.h",
-    ],
-    includes = [
-        "include",
-        ".",
-    ],
-    deps = [
-        ":gpr",
-    ],
+  name = "grpc++_unsecure",
+  srcs = [
+    "src/cpp/client/channel.h",
+    "src/cpp/proto/proto_utils.h",
+    "src/cpp/server/thread_pool.h",
+    "src/cpp/util/time.h",
+    "src/cpp/client/channel.cc",
+    "src/cpp/client/channel_arguments.cc",
+    "src/cpp/client/client_context.cc",
+    "src/cpp/client/client_unary_call.cc",
+    "src/cpp/client/create_channel.cc",
+    "src/cpp/client/credentials.cc",
+    "src/cpp/client/generic_stub.cc",
+    "src/cpp/client/insecure_credentials.cc",
+    "src/cpp/client/internal_stub.cc",
+    "src/cpp/common/call.cc",
+    "src/cpp/common/completion_queue.cc",
+    "src/cpp/common/rpc_method.cc",
+    "src/cpp/proto/proto_utils.cc",
+    "src/cpp/server/async_generic_service.cc",
+    "src/cpp/server/insecure_server_credentials.cc",
+    "src/cpp/server/server.cc",
+    "src/cpp/server/server_builder.cc",
+    "src/cpp/server/server_context.cc",
+    "src/cpp/server/server_credentials.cc",
+    "src/cpp/server/thread_pool.cc",
+    "src/cpp/util/byte_buffer.cc",
+    "src/cpp/util/slice.cc",
+    "src/cpp/util/status.cc",
+    "src/cpp/util/time.cc",
+  ],
+  hdrs = [
+    "include/grpc++/async_generic_service.h",
+    "include/grpc++/async_unary_call.h",
+    "include/grpc++/byte_buffer.h",
+    "include/grpc++/channel_arguments.h",
+    "include/grpc++/channel_interface.h",
+    "include/grpc++/client_context.h",
+    "include/grpc++/completion_queue.h",
+    "include/grpc++/config.h",
+    "include/grpc++/create_channel.h",
+    "include/grpc++/credentials.h",
+    "include/grpc++/generic_stub.h",
+    "include/grpc++/impl/call.h",
+    "include/grpc++/impl/client_unary_call.h",
+    "include/grpc++/impl/internal_stub.h",
+    "include/grpc++/impl/rpc_method.h",
+    "include/grpc++/impl/rpc_service_method.h",
+    "include/grpc++/impl/service_type.h",
+    "include/grpc++/impl/sync.h",
+    "include/grpc++/impl/sync_cxx11.h",
+    "include/grpc++/impl/sync_no_cxx11.h",
+    "include/grpc++/impl/thd.h",
+    "include/grpc++/impl/thd_cxx11.h",
+    "include/grpc++/impl/thd_no_cxx11.h",
+    "include/grpc++/server.h",
+    "include/grpc++/server_builder.h",
+    "include/grpc++/server_context.h",
+    "include/grpc++/server_credentials.h",
+    "include/grpc++/slice.h",
+    "include/grpc++/status.h",
+    "include/grpc++/status_code_enum.h",
+    "include/grpc++/stream.h",
+    "include/grpc++/thread_pool_interface.h",
+  ],
+  includes = [
+    "include",
+    ".",
+  ],
+  deps = [
+    "//external:protobuf_clib",
+    ":gpr",
+    ":grpc_unsecure",
+  ],
 )
 
 
+cc_library(
+  name = "grpc_plugin_support",
+  srcs = [
+    "src/compiler/config.h",
+    "src/compiler/cpp_generator.h",
+    "src/compiler/cpp_generator_helpers.h",
+    "src/compiler/generator_helpers.h",
+    "src/compiler/objective_c_generator.h",
+    "src/compiler/objective_c_generator_helpers.h",
+    "src/compiler/python_generator.h",
+    "src/compiler/ruby_generator.h",
+    "src/compiler/ruby_generator_helpers-inl.h",
+    "src/compiler/ruby_generator_map-inl.h",
+    "src/compiler/ruby_generator_string-inl.h",
+    "src/compiler/cpp_generator.cc",
+    "src/compiler/objective_c_generator.cc",
+    "src/compiler/python_generator.cc",
+    "src/compiler/ruby_generator.cc",
+  ],
+  hdrs = [
+  ],
+  includes = [
+    "include",
+    ".",
+  ],
+  deps = [
+    "//external:protobuf_compiler",
+  ],
+)
 
 
 cc_library(
-    name = "grpc_unsecure",
-    srcs = [
-        "src/core/channel/census_filter.h",
-        "src/core/channel/channel_args.h",
-        "src/core/channel/channel_stack.h",
-        "src/core/channel/child_channel.h",
-        "src/core/channel/client_channel.h",
-        "src/core/channel/client_setup.h",
-        "src/core/channel/connected_channel.h",
-        "src/core/channel/http_client_filter.h",
-        "src/core/channel/http_filter.h",
-        "src/core/channel/http_server_filter.h",
-        "src/core/channel/metadata_buffer.h",
-        "src/core/channel/noop_filter.h",
-        "src/core/compression/algorithm.h",
-        "src/core/compression/message_compress.h",
-        "src/core/debug/trace.h",
-        "src/core/iomgr/alarm.h",
-        "src/core/iomgr/alarm_heap.h",
-        "src/core/iomgr/alarm_internal.h",
-        "src/core/iomgr/endpoint.h",
-        "src/core/iomgr/endpoint_pair.h",
-        "src/core/iomgr/fd_posix.h",
-        "src/core/iomgr/iocp_windows.h",
-        "src/core/iomgr/iomgr.h",
-        "src/core/iomgr/iomgr_internal.h",
-        "src/core/iomgr/iomgr_posix.h",
-        "src/core/iomgr/pollset.h",
-        "src/core/iomgr/pollset_kick.h",
-        "src/core/iomgr/pollset_kick_posix.h",
-        "src/core/iomgr/pollset_kick_windows.h",
-        "src/core/iomgr/pollset_posix.h",
-        "src/core/iomgr/pollset_windows.h",
-        "src/core/iomgr/resolve_address.h",
-        "src/core/iomgr/sockaddr.h",
-        "src/core/iomgr/sockaddr_posix.h",
-        "src/core/iomgr/sockaddr_utils.h",
-        "src/core/iomgr/sockaddr_win32.h",
-        "src/core/iomgr/socket_utils_posix.h",
-        "src/core/iomgr/socket_windows.h",
-        "src/core/iomgr/tcp_client.h",
-        "src/core/iomgr/tcp_posix.h",
-        "src/core/iomgr/tcp_server.h",
-        "src/core/iomgr/tcp_windows.h",
-        "src/core/iomgr/time_averaged_stats.h",
-        "src/core/iomgr/wakeup_fd_pipe.h",
-        "src/core/iomgr/wakeup_fd_posix.h",
-        "src/core/json/json.h",
-        "src/core/json/json_common.h",
-        "src/core/json/json_reader.h",
-        "src/core/json/json_writer.h",
-        "src/core/statistics/census_interface.h",
-        "src/core/statistics/census_log.h",
-        "src/core/statistics/census_rpc_stats.h",
-        "src/core/statistics/census_tracing.h",
-        "src/core/statistics/hash_table.h",
-        "src/core/statistics/window_stats.h",
-        "src/core/surface/byte_buffer_queue.h",
-        "src/core/surface/call.h",
-        "src/core/surface/channel.h",
-        "src/core/surface/client.h",
-        "src/core/surface/completion_queue.h",
-        "src/core/surface/event_string.h",
-        "src/core/surface/init.h",
-        "src/core/surface/server.h",
-        "src/core/surface/surface_trace.h",
-        "src/core/transport/chttp2/alpn.h",
-        "src/core/transport/chttp2/bin_encoder.h",
-        "src/core/transport/chttp2/frame.h",
-        "src/core/transport/chttp2/frame_data.h",
-        "src/core/transport/chttp2/frame_goaway.h",
-        "src/core/transport/chttp2/frame_ping.h",
-        "src/core/transport/chttp2/frame_rst_stream.h",
-        "src/core/transport/chttp2/frame_settings.h",
-        "src/core/transport/chttp2/frame_window_update.h",
-        "src/core/transport/chttp2/hpack_parser.h",
-        "src/core/transport/chttp2/hpack_table.h",
-        "src/core/transport/chttp2/http2_errors.h",
-        "src/core/transport/chttp2/huffsyms.h",
-        "src/core/transport/chttp2/status_conversion.h",
-        "src/core/transport/chttp2/stream_encoder.h",
-        "src/core/transport/chttp2/stream_map.h",
-        "src/core/transport/chttp2/timeout_encoding.h",
-        "src/core/transport/chttp2/varint.h",
-        "src/core/transport/chttp2_transport.h",
-        "src/core/transport/metadata.h",
-        "src/core/transport/stream_op.h",
-        "src/core/transport/transport.h",
-        "src/core/transport/transport_impl.h",
-        "src/core/surface/init_unsecure.c",
-        "src/core/channel/call_op_string.c",
-        "src/core/channel/census_filter.c",
-        "src/core/channel/channel_args.c",
-        "src/core/channel/channel_stack.c",
-        "src/core/channel/child_channel.c",
-        "src/core/channel/client_channel.c",
-        "src/core/channel/client_setup.c",
-        "src/core/channel/connected_channel.c",
-        "src/core/channel/http_client_filter.c",
-        "src/core/channel/http_filter.c",
-        "src/core/channel/http_server_filter.c",
-        "src/core/channel/metadata_buffer.c",
-        "src/core/channel/noop_filter.c",
-        "src/core/compression/algorithm.c",
-        "src/core/compression/message_compress.c",
-        "src/core/debug/trace.c",
-        "src/core/iomgr/alarm.c",
-        "src/core/iomgr/alarm_heap.c",
-        "src/core/iomgr/endpoint.c",
-        "src/core/iomgr/endpoint_pair_posix.c",
-        "src/core/iomgr/fd_posix.c",
-        "src/core/iomgr/iocp_windows.c",
-        "src/core/iomgr/iomgr.c",
-        "src/core/iomgr/iomgr_posix.c",
-        "src/core/iomgr/iomgr_windows.c",
-        "src/core/iomgr/pollset_kick.c",
-        "src/core/iomgr/pollset_multipoller_with_epoll.c",
-        "src/core/iomgr/pollset_multipoller_with_poll_posix.c",
-        "src/core/iomgr/pollset_posix.c",
-        "src/core/iomgr/pollset_windows.c",
-        "src/core/iomgr/resolve_address_posix.c",
-        "src/core/iomgr/resolve_address_windows.c",
-        "src/core/iomgr/sockaddr_utils.c",
-        "src/core/iomgr/socket_utils_common_posix.c",
-        "src/core/iomgr/socket_utils_linux.c",
-        "src/core/iomgr/socket_utils_posix.c",
-        "src/core/iomgr/socket_windows.c",
-        "src/core/iomgr/tcp_client_posix.c",
-        "src/core/iomgr/tcp_client_windows.c",
-        "src/core/iomgr/tcp_posix.c",
-        "src/core/iomgr/tcp_server_posix.c",
-        "src/core/iomgr/tcp_server_windows.c",
-        "src/core/iomgr/tcp_windows.c",
-        "src/core/iomgr/time_averaged_stats.c",
-        "src/core/iomgr/wakeup_fd_eventfd.c",
-        "src/core/iomgr/wakeup_fd_nospecial.c",
-        "src/core/iomgr/wakeup_fd_pipe.c",
-        "src/core/iomgr/wakeup_fd_posix.c",
-        "src/core/json/json.c",
-        "src/core/json/json_reader.c",
-        "src/core/json/json_string.c",
-        "src/core/json/json_writer.c",
-        "src/core/statistics/census_init.c",
-        "src/core/statistics/census_log.c",
-        "src/core/statistics/census_rpc_stats.c",
-        "src/core/statistics/census_tracing.c",
-        "src/core/statistics/hash_table.c",
-        "src/core/statistics/window_stats.c",
-        "src/core/surface/byte_buffer.c",
-        "src/core/surface/byte_buffer_queue.c",
-        "src/core/surface/byte_buffer_reader.c",
-        "src/core/surface/call.c",
-        "src/core/surface/call_details.c",
-        "src/core/surface/call_log_batch.c",
-        "src/core/surface/channel.c",
-        "src/core/surface/channel_create.c",
-        "src/core/surface/client.c",
-        "src/core/surface/completion_queue.c",
-        "src/core/surface/event_string.c",
-        "src/core/surface/init.c",
-        "src/core/surface/lame_client.c",
-        "src/core/surface/metadata_array.c",
-        "src/core/surface/server.c",
-        "src/core/surface/server_chttp2.c",
-        "src/core/surface/server_create.c",
-        "src/core/surface/surface_trace.c",
-        "src/core/transport/chttp2/alpn.c",
-        "src/core/transport/chttp2/bin_encoder.c",
-        "src/core/transport/chttp2/frame_data.c",
-        "src/core/transport/chttp2/frame_goaway.c",
-        "src/core/transport/chttp2/frame_ping.c",
-        "src/core/transport/chttp2/frame_rst_stream.c",
-        "src/core/transport/chttp2/frame_settings.c",
-        "src/core/transport/chttp2/frame_window_update.c",
-        "src/core/transport/chttp2/hpack_parser.c",
-        "src/core/transport/chttp2/hpack_table.c",
-        "src/core/transport/chttp2/huffsyms.c",
-        "src/core/transport/chttp2/status_conversion.c",
-        "src/core/transport/chttp2/stream_encoder.c",
-        "src/core/transport/chttp2/stream_map.c",
-        "src/core/transport/chttp2/timeout_encoding.c",
-        "src/core/transport/chttp2/varint.c",
-        "src/core/transport/chttp2_transport.c",
-        "src/core/transport/metadata.c",
-        "src/core/transport/stream_op.c",
-        "src/core/transport/transport.c",
-    ],
-    hdrs = [
-        "include/grpc/byte_buffer.h",
-        "include/grpc/byte_buffer_reader.h",
-        "include/grpc/grpc.h",
-        "include/grpc/grpc_http.h",
-        "include/grpc/status.h",
-    ],
-    includes = [
-        "include",
-        ".",
-    ],
-    deps = [
-        ":gpr",
-    ],
+  name = "grpc_csharp_ext",
+  srcs = [
+    "src/csharp/ext/grpc_csharp_ext.c",
+  ],
+  hdrs = [
+  ],
+  includes = [
+    "include",
+    ".",
+  ],
+  deps = [
+    ":gpr",
+    ":grpc",
+  ],
 )
 
 
 
+cc_binary(
+  name = "grpc_cpp_plugin",
+  srcs = [
+    "src/compiler/cpp_plugin.cc",
+  ],
+  deps = [
+    "//external:protobuf_compiler",
+    ":grpc_plugin_support",
+  ],
+)
+
+
+cc_binary(
+  name = "grpc_objective_c_plugin",
+  srcs = [
+    "src/compiler/objective_c_plugin.cc",
+  ],
+  deps = [
+    "//external:protobuf_compiler",
+    ":grpc_plugin_support",
+  ],
+)
+
+
+cc_binary(
+  name = "grpc_python_plugin",
+  srcs = [
+    "src/compiler/python_plugin.cc",
+  ],
+  deps = [
+    "//external:protobuf_compiler",
+    ":grpc_plugin_support",
+  ],
+)
+
+
+cc_binary(
+  name = "grpc_ruby_plugin",
+  srcs = [
+    "src/compiler/ruby_plugin.cc",
+  ],
+  deps = [
+    "//external:protobuf_compiler",
+    ":grpc_plugin_support",
+  ],
+)
+
+
+
+
 
diff --git a/Makefile b/Makefile
index c50eb8c0cb8017bace83cd49b0d809a8d01ed2f0..0a3b2b98e95ee0662a0469a13b9cd72a15e79f89 100644
--- a/Makefile
+++ b/Makefile
@@ -583,6 +583,7 @@ gpr_string_test: $(BINDIR)/$(CONFIG)/gpr_string_test
 gpr_sync_test: $(BINDIR)/$(CONFIG)/gpr_sync_test
 gpr_thd_test: $(BINDIR)/$(CONFIG)/gpr_thd_test
 gpr_time_test: $(BINDIR)/$(CONFIG)/gpr_time_test
+gpr_tls_test: $(BINDIR)/$(CONFIG)/gpr_tls_test
 gpr_useful_test: $(BINDIR)/$(CONFIG)/gpr_useful_test
 grpc_base64_test: $(BINDIR)/$(CONFIG)/grpc_base64_test
 grpc_byte_buffer_reader_test: $(BINDIR)/$(CONFIG)/grpc_byte_buffer_reader_test
@@ -641,6 +642,7 @@ pubsub_client: $(BINDIR)/$(CONFIG)/pubsub_client
 pubsub_publisher_test: $(BINDIR)/$(CONFIG)/pubsub_publisher_test
 pubsub_subscriber_test: $(BINDIR)/$(CONFIG)/pubsub_subscriber_test
 qps_driver: $(BINDIR)/$(CONFIG)/qps_driver
+qps_smoke_test: $(BINDIR)/$(CONFIG)/qps_smoke_test
 qps_worker: $(BINDIR)/$(CONFIG)/qps_worker
 status_test: $(BINDIR)/$(CONFIG)/status_test
 thread_pool_test: $(BINDIR)/$(CONFIG)/thread_pool_test
@@ -1075,13 +1077,13 @@ privatelibs: privatelibs_c privatelibs_cxx
 
 privatelibs_c:  $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libend2end_fixture_chttp2_fake_security.a $(LIBDIR)/$(CONFIG)/libend2end_fixture_chttp2_fullstack.a $(LIBDIR)/$(CONFIG)/libend2end_fixture_chttp2_fullstack_uds.a $(LIBDIR)/$(CONFIG)/libend2end_fixture_chttp2_simple_ssl_fullstack.a $(LIBDIR)/$(CONFIG)/libend2end_fixture_chttp2_simple_ssl_with_oauth2_fullstack.a $(LIBDIR)/$(CONFIG)/libend2end_fixture_chttp2_socket_pair.a $(LIBDIR)/$(CONFIG)/libend2end_fixture_chttp2_socket_pair_one_byte_at_a_time.a $(LIBDIR)/$(CONFIG)/libend2end_test_bad_hostname.a $(LIBDIR)/$(CONFIG)/libend2end_test_cancel_after_accept.a $(LIBDIR)/$(CONFIG)/libend2end_test_cancel_after_accept_and_writes_closed.a $(LIBDIR)/$(CONFIG)/libend2end_test_cancel_after_invoke.a $(LIBDIR)/$(CONFIG)/libend2end_test_cancel_before_invoke.a $(LIBDIR)/$(CONFIG)/libend2end_test_cancel_in_a_vacuum.a $(LIBDIR)/$(CONFIG)/libend2end_test_census_simple_request.a $(LIBDIR)/$(CONFIG)/libend2end_test_disappearing_server.a $(LIBDIR)/$(CONFIG)/libend2end_test_early_server_shutdown_finishes_inflight_calls.a $(LIBDIR)/$(CONFIG)/libend2end_test_early_server_shutdown_finishes_tags.a $(LIBDIR)/$(CONFIG)/libend2end_test_empty_batch.a $(LIBDIR)/$(CONFIG)/libend2end_test_graceful_server_shutdown.a $(LIBDIR)/$(CONFIG)/libend2end_test_invoke_large_request.a $(LIBDIR)/$(CONFIG)/libend2end_test_max_concurrent_streams.a $(LIBDIR)/$(CONFIG)/libend2end_test_no_op.a $(LIBDIR)/$(CONFIG)/libend2end_test_ping_pong_streaming.a $(LIBDIR)/$(CONFIG)/libend2end_test_request_response_with_binary_metadata_and_payload.a $(LIBDIR)/$(CONFIG)/libend2end_test_request_response_with_metadata_and_payload.a $(LIBDIR)/$(CONFIG)/libend2end_test_request_response_with_payload.a $(LIBDIR)/$(CONFIG)/libend2end_test_request_with_large_metadata.a $(LIBDIR)/$(CONFIG)/libend2end_test_request_with_payload.a $(LIBDIR)/$(CONFIG)/libend2end_test_simple_delayed_request.a $(LIBDIR)/$(CONFIG)/libend2end_test_simple_request.a $(LIBDIR)/$(CONFIG)/libend2end_test_thread_stress.a $(LIBDIR)/$(CONFIG)/libend2end_test_writes_done_hangs_with_pending_read.a $(LIBDIR)/$(CONFIG)/libend2end_test_cancel_after_accept_legacy.a $(LIBDIR)/$(CONFIG)/libend2end_test_cancel_after_accept_and_writes_closed_legacy.a $(LIBDIR)/$(CONFIG)/libend2end_test_cancel_after_invoke_legacy.a $(LIBDIR)/$(CONFIG)/libend2end_test_cancel_before_invoke_legacy.a $(LIBDIR)/$(CONFIG)/libend2end_test_cancel_in_a_vacuum_legacy.a $(LIBDIR)/$(CONFIG)/libend2end_test_census_simple_request_legacy.a $(LIBDIR)/$(CONFIG)/libend2end_test_disappearing_server_legacy.a $(LIBDIR)/$(CONFIG)/libend2end_test_early_server_shutdown_finishes_inflight_calls_legacy.a $(LIBDIR)/$(CONFIG)/libend2end_test_early_server_shutdown_finishes_tags_legacy.a $(LIBDIR)/$(CONFIG)/libend2end_test_graceful_server_shutdown_legacy.a $(LIBDIR)/$(CONFIG)/libend2end_test_invoke_large_request_legacy.a $(LIBDIR)/$(CONFIG)/libend2end_test_max_concurrent_streams_legacy.a $(LIBDIR)/$(CONFIG)/libend2end_test_no_op_legacy.a $(LIBDIR)/$(CONFIG)/libend2end_test_ping_pong_streaming_legacy.a $(LIBDIR)/$(CONFIG)/libend2end_test_request_response_with_binary_metadata_and_payload_legacy.a $(LIBDIR)/$(CONFIG)/libend2end_test_request_response_with_metadata_and_payload_legacy.a $(LIBDIR)/$(CONFIG)/libend2end_test_request_response_with_payload_legacy.a $(LIBDIR)/$(CONFIG)/libend2end_test_request_response_with_trailing_metadata_and_payload_legacy.a $(LIBDIR)/$(CONFIG)/libend2end_test_request_with_large_metadata_legacy.a $(LIBDIR)/$(CONFIG)/libend2end_test_request_with_payload_legacy.a $(LIBDIR)/$(CONFIG)/libend2end_test_simple_delayed_request_legacy.a $(LIBDIR)/$(CONFIG)/libend2end_test_simple_request_legacy.a $(LIBDIR)/$(CONFIG)/libend2end_test_thread_stress_legacy.a $(LIBDIR)/$(CONFIG)/libend2end_test_writes_done_hangs_with_pending_read_legacy.a $(LIBDIR)/$(CONFIG)/libend2end_certs.a
 
-privatelibs_cxx:  $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libpubsub_client_lib.a $(LIBDIR)/$(CONFIG)/libqps.a
+privatelibs_cxx:  $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libinterop_client_helper.a $(LIBDIR)/$(CONFIG)/libinterop_client_main.a $(LIBDIR)/$(CONFIG)/libinterop_server_helper.a $(LIBDIR)/$(CONFIG)/libinterop_server_main.a $(LIBDIR)/$(CONFIG)/libpubsub_client_lib.a $(LIBDIR)/$(CONFIG)/libqps.a
 
 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)/census_hash_table_test $(BINDIR)/$(CONFIG)/census_statistics_multiple_writers_circular_buffer_test $(BINDIR)/$(CONFIG)/census_statistics_multiple_writers_test $(BINDIR)/$(CONFIG)/census_statistics_performance_test $(BINDIR)/$(CONFIG)/census_statistics_quick_test $(BINDIR)/$(CONFIG)/census_statistics_small_log_test $(BINDIR)/$(CONFIG)/census_stub_test $(BINDIR)/$(CONFIG)/census_window_stats_test $(BINDIR)/$(CONFIG)/chttp2_status_conversion_test $(BINDIR)/$(CONFIG)/chttp2_stream_encoder_test $(BINDIR)/$(CONFIG)/chttp2_stream_map_test $(BINDIR)/$(CONFIG)/chttp2_transport_end2end_test $(BINDIR)/$(CONFIG)/dualstack_socket_test $(BINDIR)/$(CONFIG)/echo_client $(BINDIR)/$(CONFIG)/echo_server $(BINDIR)/$(CONFIG)/echo_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_useful_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_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)/metadata_buffer_test $(BINDIR)/$(CONFIG)/multi_init_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)/transport_metadata_test $(BINDIR)/$(CONFIG)/transport_security_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_no_op_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_ping_pong_streaming_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_with_large_metadata_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_request_with_payload_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_simple_delayed_request_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_simple_request_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_thread_stress_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_writes_done_hangs_with_pending_read_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_cancel_after_accept_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_cancel_after_accept_and_writes_closed_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_cancel_after_invoke_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_cancel_before_invoke_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_cancel_in_a_vacuum_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_census_simple_request_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_disappearing_server_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_early_server_shutdown_finishes_inflight_calls_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_early_server_shutdown_finishes_tags_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_graceful_server_shutdown_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_invoke_large_request_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_max_concurrent_streams_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_no_op_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_ping_pong_streaming_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_request_response_with_binary_metadata_and_payload_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_request_response_with_metadata_and_payload_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_request_response_with_payload_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_request_response_with_trailing_metadata_and_payload_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_request_with_large_metadata_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_request_with_payload_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_simple_delayed_request_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_simple_request_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_thread_stress_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_writes_done_hangs_with_pending_read_legacy_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_no_op_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_ping_pong_streaming_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_with_large_metadata_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_request_with_payload_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_simple_delayed_request_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_simple_request_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_thread_stress_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_writes_done_hangs_with_pending_read_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_cancel_after_accept_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_cancel_after_accept_and_writes_closed_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_cancel_after_invoke_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_cancel_before_invoke_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_cancel_in_a_vacuum_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_census_simple_request_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_disappearing_server_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_early_server_shutdown_finishes_inflight_calls_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_early_server_shutdown_finishes_tags_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_graceful_server_shutdown_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_invoke_large_request_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_max_concurrent_streams_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_no_op_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_ping_pong_streaming_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_request_response_with_binary_metadata_and_payload_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_request_response_with_metadata_and_payload_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_request_response_with_payload_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_request_response_with_trailing_metadata_and_payload_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_request_with_large_metadata_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_request_with_payload_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_simple_delayed_request_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_simple_request_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_thread_stress_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_writes_done_hangs_with_pending_read_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_bad_hostname_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_cancel_after_accept_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_cancel_after_accept_and_writes_closed_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_cancel_after_invoke_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_cancel_before_invoke_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_cancel_in_a_vacuum_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_census_simple_request_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_disappearing_server_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_early_server_shutdown_finishes_inflight_calls_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_early_server_shutdown_finishes_tags_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_empty_batch_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_graceful_server_shutdown_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_invoke_large_request_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_max_concurrent_streams_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_no_op_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_ping_pong_streaming_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_request_response_with_binary_metadata_and_payload_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_request_response_with_metadata_and_payload_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_request_response_with_payload_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_request_with_large_metadata_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_request_with_payload_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_simple_delayed_request_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_simple_request_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_thread_stress_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_writes_done_hangs_with_pending_read_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_cancel_after_accept_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_cancel_after_accept_and_writes_closed_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_cancel_after_invoke_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_cancel_before_invoke_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_cancel_in_a_vacuum_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_census_simple_request_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_disappearing_server_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_early_server_shutdown_finishes_inflight_calls_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_early_server_shutdown_finishes_tags_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_graceful_server_shutdown_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_invoke_large_request_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_max_concurrent_streams_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_no_op_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_ping_pong_streaming_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_request_response_with_binary_metadata_and_payload_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_request_response_with_metadata_and_payload_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_request_response_with_payload_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_request_response_with_trailing_metadata_and_payload_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_request_with_large_metadata_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_request_with_payload_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_simple_delayed_request_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_simple_request_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_thread_stress_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_writes_done_hangs_with_pending_read_legacy_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_no_op_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_ping_pong_streaming_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_with_large_metadata_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_request_with_payload_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_thread_stress_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_writes_done_hangs_with_pending_read_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_cancel_after_accept_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_cancel_after_accept_and_writes_closed_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_cancel_after_invoke_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_cancel_before_invoke_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_cancel_in_a_vacuum_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_census_simple_request_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_disappearing_server_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_early_server_shutdown_finishes_inflight_calls_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_early_server_shutdown_finishes_tags_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_graceful_server_shutdown_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_invoke_large_request_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_max_concurrent_streams_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_no_op_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_ping_pong_streaming_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_request_response_with_binary_metadata_and_payload_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_request_response_with_metadata_and_payload_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_request_response_with_payload_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_request_response_with_trailing_metadata_and_payload_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_request_with_large_metadata_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_request_with_payload_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_simple_delayed_request_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_simple_request_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_thread_stress_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_writes_done_hangs_with_pending_read_legacy_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_no_op_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_ping_pong_streaming_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_with_large_metadata_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_request_with_payload_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_thread_stress_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_writes_done_hangs_with_pending_read_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_cancel_after_accept_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_cancel_after_accept_and_writes_closed_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_cancel_after_invoke_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_cancel_before_invoke_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_cancel_in_a_vacuum_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_census_simple_request_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_disappearing_server_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_early_server_shutdown_finishes_inflight_calls_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_early_server_shutdown_finishes_tags_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_graceful_server_shutdown_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_invoke_large_request_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_max_concurrent_streams_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_no_op_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_ping_pong_streaming_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_request_response_with_binary_metadata_and_payload_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_request_response_with_metadata_and_payload_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_request_response_with_payload_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_request_response_with_trailing_metadata_and_payload_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_request_with_large_metadata_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_request_with_payload_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_simple_delayed_request_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_simple_request_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_thread_stress_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_writes_done_hangs_with_pending_read_legacy_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_no_op_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_ping_pong_streaming_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_with_large_metadata_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_request_with_payload_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_simple_delayed_request_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_simple_request_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_thread_stress_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_writes_done_hangs_with_pending_read_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_cancel_after_accept_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_cancel_after_accept_and_writes_closed_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_cancel_after_invoke_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_cancel_before_invoke_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_cancel_in_a_vacuum_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_census_simple_request_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_disappearing_server_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_early_server_shutdown_finishes_inflight_calls_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_early_server_shutdown_finishes_tags_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_graceful_server_shutdown_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_invoke_large_request_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_max_concurrent_streams_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_no_op_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_ping_pong_streaming_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_request_response_with_binary_metadata_and_payload_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_request_response_with_metadata_and_payload_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_request_response_with_payload_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_request_response_with_trailing_metadata_and_payload_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_request_with_large_metadata_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_request_with_payload_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_simple_delayed_request_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_simple_request_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_thread_stress_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_writes_done_hangs_with_pending_read_legacy_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_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_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_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_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_thread_stress_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_writes_done_hangs_with_pending_read_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_cancel_after_accept_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_cancel_after_accept_and_writes_closed_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_cancel_after_invoke_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_cancel_before_invoke_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_cancel_in_a_vacuum_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_census_simple_request_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_disappearing_server_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_early_server_shutdown_finishes_inflight_calls_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_early_server_shutdown_finishes_tags_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_graceful_server_shutdown_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_invoke_large_request_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_max_concurrent_streams_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_no_op_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_ping_pong_streaming_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_request_response_with_binary_metadata_and_payload_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_request_response_with_metadata_and_payload_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_request_response_with_payload_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_request_response_with_trailing_metadata_and_payload_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_request_with_large_metadata_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_request_with_payload_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_simple_delayed_request_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_simple_request_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_thread_stress_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_writes_done_hangs_with_pending_read_legacy_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)/census_hash_table_test $(BINDIR)/$(CONFIG)/census_statistics_multiple_writers_circular_buffer_test $(BINDIR)/$(CONFIG)/census_statistics_multiple_writers_test $(BINDIR)/$(CONFIG)/census_statistics_performance_test $(BINDIR)/$(CONFIG)/census_statistics_quick_test $(BINDIR)/$(CONFIG)/census_statistics_small_log_test $(BINDIR)/$(CONFIG)/census_stub_test $(BINDIR)/$(CONFIG)/census_window_stats_test $(BINDIR)/$(CONFIG)/chttp2_status_conversion_test $(BINDIR)/$(CONFIG)/chttp2_stream_encoder_test $(BINDIR)/$(CONFIG)/chttp2_stream_map_test $(BINDIR)/$(CONFIG)/chttp2_transport_end2end_test $(BINDIR)/$(CONFIG)/dualstack_socket_test $(BINDIR)/$(CONFIG)/echo_client $(BINDIR)/$(CONFIG)/echo_server $(BINDIR)/$(CONFIG)/echo_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_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_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)/metadata_buffer_test $(BINDIR)/$(CONFIG)/multi_init_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)/transport_metadata_test $(BINDIR)/$(CONFIG)/transport_security_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_no_op_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_ping_pong_streaming_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_with_large_metadata_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_request_with_payload_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_simple_delayed_request_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_simple_request_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_thread_stress_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_writes_done_hangs_with_pending_read_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_cancel_after_accept_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_cancel_after_accept_and_writes_closed_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_cancel_after_invoke_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_cancel_before_invoke_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_cancel_in_a_vacuum_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_census_simple_request_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_disappearing_server_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_early_server_shutdown_finishes_inflight_calls_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_early_server_shutdown_finishes_tags_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_graceful_server_shutdown_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_invoke_large_request_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_max_concurrent_streams_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_no_op_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_ping_pong_streaming_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_request_response_with_binary_metadata_and_payload_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_request_response_with_metadata_and_payload_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_request_response_with_payload_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_request_response_with_trailing_metadata_and_payload_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_request_with_large_metadata_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_request_with_payload_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_simple_delayed_request_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_simple_request_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_thread_stress_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fake_security_writes_done_hangs_with_pending_read_legacy_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_no_op_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_ping_pong_streaming_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_with_large_metadata_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_request_with_payload_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_simple_delayed_request_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_simple_request_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_thread_stress_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_writes_done_hangs_with_pending_read_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_cancel_after_accept_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_cancel_after_accept_and_writes_closed_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_cancel_after_invoke_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_cancel_before_invoke_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_cancel_in_a_vacuum_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_census_simple_request_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_disappearing_server_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_early_server_shutdown_finishes_inflight_calls_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_early_server_shutdown_finishes_tags_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_graceful_server_shutdown_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_invoke_large_request_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_max_concurrent_streams_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_no_op_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_ping_pong_streaming_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_request_response_with_binary_metadata_and_payload_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_request_response_with_metadata_and_payload_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_request_response_with_payload_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_request_response_with_trailing_metadata_and_payload_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_request_with_large_metadata_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_request_with_payload_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_simple_delayed_request_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_simple_request_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_thread_stress_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_writes_done_hangs_with_pending_read_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_bad_hostname_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_cancel_after_accept_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_cancel_after_accept_and_writes_closed_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_cancel_after_invoke_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_cancel_before_invoke_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_cancel_in_a_vacuum_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_census_simple_request_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_disappearing_server_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_early_server_shutdown_finishes_inflight_calls_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_early_server_shutdown_finishes_tags_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_empty_batch_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_graceful_server_shutdown_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_invoke_large_request_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_max_concurrent_streams_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_no_op_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_ping_pong_streaming_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_request_response_with_binary_metadata_and_payload_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_request_response_with_metadata_and_payload_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_request_response_with_payload_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_request_with_large_metadata_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_request_with_payload_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_simple_delayed_request_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_simple_request_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_thread_stress_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_writes_done_hangs_with_pending_read_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_cancel_after_accept_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_cancel_after_accept_and_writes_closed_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_cancel_after_invoke_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_cancel_before_invoke_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_cancel_in_a_vacuum_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_census_simple_request_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_disappearing_server_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_early_server_shutdown_finishes_inflight_calls_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_early_server_shutdown_finishes_tags_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_graceful_server_shutdown_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_invoke_large_request_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_max_concurrent_streams_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_no_op_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_ping_pong_streaming_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_request_response_with_binary_metadata_and_payload_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_request_response_with_metadata_and_payload_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_request_response_with_payload_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_request_response_with_trailing_metadata_and_payload_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_request_with_large_metadata_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_request_with_payload_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_simple_delayed_request_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_simple_request_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_thread_stress_legacy_test $(BINDIR)/$(CONFIG)/chttp2_fullstack_uds_writes_done_hangs_with_pending_read_legacy_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_no_op_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_ping_pong_streaming_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_with_large_metadata_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_request_with_payload_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_thread_stress_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_writes_done_hangs_with_pending_read_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_cancel_after_accept_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_cancel_after_accept_and_writes_closed_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_cancel_after_invoke_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_cancel_before_invoke_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_cancel_in_a_vacuum_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_census_simple_request_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_disappearing_server_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_early_server_shutdown_finishes_inflight_calls_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_early_server_shutdown_finishes_tags_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_graceful_server_shutdown_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_invoke_large_request_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_max_concurrent_streams_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_no_op_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_ping_pong_streaming_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_request_response_with_binary_metadata_and_payload_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_request_response_with_metadata_and_payload_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_request_response_with_payload_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_request_response_with_trailing_metadata_and_payload_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_request_with_large_metadata_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_request_with_payload_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_simple_delayed_request_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_simple_request_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_thread_stress_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_fullstack_writes_done_hangs_with_pending_read_legacy_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_no_op_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_ping_pong_streaming_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_with_large_metadata_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_request_with_payload_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_thread_stress_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_writes_done_hangs_with_pending_read_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_cancel_after_accept_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_cancel_after_accept_and_writes_closed_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_cancel_after_invoke_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_cancel_before_invoke_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_cancel_in_a_vacuum_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_census_simple_request_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_disappearing_server_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_early_server_shutdown_finishes_inflight_calls_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_early_server_shutdown_finishes_tags_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_graceful_server_shutdown_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_invoke_large_request_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_max_concurrent_streams_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_no_op_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_ping_pong_streaming_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_request_response_with_binary_metadata_and_payload_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_request_response_with_metadata_and_payload_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_request_response_with_payload_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_request_response_with_trailing_metadata_and_payload_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_request_with_large_metadata_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_request_with_payload_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_simple_delayed_request_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_simple_request_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_thread_stress_legacy_test $(BINDIR)/$(CONFIG)/chttp2_simple_ssl_with_oauth2_fullstack_writes_done_hangs_with_pending_read_legacy_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_no_op_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_ping_pong_streaming_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_with_large_metadata_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_request_with_payload_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_simple_delayed_request_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_simple_request_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_thread_stress_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_writes_done_hangs_with_pending_read_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_cancel_after_accept_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_cancel_after_accept_and_writes_closed_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_cancel_after_invoke_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_cancel_before_invoke_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_cancel_in_a_vacuum_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_census_simple_request_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_disappearing_server_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_early_server_shutdown_finishes_inflight_calls_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_early_server_shutdown_finishes_tags_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_graceful_server_shutdown_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_invoke_large_request_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_max_concurrent_streams_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_no_op_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_ping_pong_streaming_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_request_response_with_binary_metadata_and_payload_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_request_response_with_metadata_and_payload_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_request_response_with_payload_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_request_response_with_trailing_metadata_and_payload_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_request_with_large_metadata_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_request_with_payload_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_simple_delayed_request_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_simple_request_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_thread_stress_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_writes_done_hangs_with_pending_read_legacy_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_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_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_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_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_thread_stress_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_writes_done_hangs_with_pending_read_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_cancel_after_accept_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_cancel_after_accept_and_writes_closed_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_cancel_after_invoke_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_cancel_before_invoke_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_cancel_in_a_vacuum_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_census_simple_request_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_disappearing_server_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_early_server_shutdown_finishes_inflight_calls_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_early_server_shutdown_finishes_tags_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_graceful_server_shutdown_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_invoke_large_request_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_max_concurrent_streams_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_no_op_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_ping_pong_streaming_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_request_response_with_binary_metadata_and_payload_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_request_response_with_metadata_and_payload_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_request_response_with_payload_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_request_response_with_trailing_metadata_and_payload_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_request_with_large_metadata_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_request_with_payload_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_simple_delayed_request_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_simple_request_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_thread_stress_legacy_test $(BINDIR)/$(CONFIG)/chttp2_socket_pair_one_byte_at_a_time_writes_done_hangs_with_pending_read_legacy_test
 
-buildtests_cxx: privatelibs_cxx $(BINDIR)/$(CONFIG)/async_end2end_test $(BINDIR)/$(CONFIG)/channel_arguments_test $(BINDIR)/$(CONFIG)/cli_call_test $(BINDIR)/$(CONFIG)/credentials_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)/pubsub_client $(BINDIR)/$(CONFIG)/pubsub_publisher_test $(BINDIR)/$(CONFIG)/pubsub_subscriber_test $(BINDIR)/$(CONFIG)/qps_driver $(BINDIR)/$(CONFIG)/qps_worker $(BINDIR)/$(CONFIG)/status_test $(BINDIR)/$(CONFIG)/thread_pool_test
+buildtests_cxx: privatelibs_cxx $(BINDIR)/$(CONFIG)/async_end2end_test $(BINDIR)/$(CONFIG)/channel_arguments_test $(BINDIR)/$(CONFIG)/cli_call_test $(BINDIR)/$(CONFIG)/credentials_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)/pubsub_client $(BINDIR)/$(CONFIG)/pubsub_publisher_test $(BINDIR)/$(CONFIG)/pubsub_subscriber_test $(BINDIR)/$(CONFIG)/qps_driver $(BINDIR)/$(CONFIG)/qps_smoke_test $(BINDIR)/$(CONFIG)/qps_worker $(BINDIR)/$(CONFIG)/status_test $(BINDIR)/$(CONFIG)/thread_pool_test
 
 test: test_c test_cxx
 
@@ -1156,6 +1158,8 @@ test_c: buildtests_c
 	$(Q) $(BINDIR)/$(CONFIG)/gpr_thd_test || ( echo test gpr_thd_test failed ; exit 1 )
 	$(E) "[RUN]     Testing gpr_time_test"
 	$(Q) $(BINDIR)/$(CONFIG)/gpr_time_test || ( echo test gpr_time_test failed ; exit 1 )
+	$(E) "[RUN]     Testing gpr_tls_test"
+	$(Q) $(BINDIR)/$(CONFIG)/gpr_tls_test || ( echo test gpr_tls_test failed ; exit 1 )
 	$(E) "[RUN]     Testing gpr_useful_test"
 	$(Q) $(BINDIR)/$(CONFIG)/gpr_useful_test || ( echo test gpr_useful_test failed ; exit 1 )
 	$(E) "[RUN]     Testing grpc_base64_test"
@@ -2227,6 +2231,7 @@ else
 	$(Q) $(INSTALL) -d $(prefix)/lib
 	$(Q) $(INSTALL) $(LIBDIR)/$(CONFIG)/libgpr.$(SHARED_EXT) $(prefix)/lib/libgpr.$(SHARED_EXT)
 ifneq ($(SYSTEM),Darwin)
+	$(Q) ln -sf libgpr.$(SHARED_EXT) $(prefix)/lib/libgpr.so.0
 	$(Q) ln -sf libgpr.$(SHARED_EXT) $(prefix)/lib/libgpr.so
 endif
 endif
@@ -2240,6 +2245,7 @@ else
 	$(Q) $(INSTALL) -d $(prefix)/lib
 	$(Q) $(INSTALL) $(LIBDIR)/$(CONFIG)/libgrpc.$(SHARED_EXT) $(prefix)/lib/libgrpc.$(SHARED_EXT)
 ifneq ($(SYSTEM),Darwin)
+	$(Q) ln -sf libgrpc.$(SHARED_EXT) $(prefix)/lib/libgrpc.so.0
 	$(Q) ln -sf libgrpc.$(SHARED_EXT) $(prefix)/lib/libgrpc.so
 endif
 endif
@@ -2253,6 +2259,7 @@ else
 	$(Q) $(INSTALL) -d $(prefix)/lib
 	$(Q) $(INSTALL) $(LIBDIR)/$(CONFIG)/libgrpc_unsecure.$(SHARED_EXT) $(prefix)/lib/libgrpc_unsecure.$(SHARED_EXT)
 ifneq ($(SYSTEM),Darwin)
+	$(Q) ln -sf libgrpc_unsecure.$(SHARED_EXT) $(prefix)/lib/libgrpc_unsecure.so.0
 	$(Q) ln -sf libgrpc_unsecure.$(SHARED_EXT) $(prefix)/lib/libgrpc_unsecure.so
 endif
 endif
@@ -2274,6 +2281,7 @@ else
 	$(Q) $(INSTALL) -d $(prefix)/lib
 	$(Q) $(INSTALL) $(LIBDIR)/$(CONFIG)/libgrpc++.$(SHARED_EXT) $(prefix)/lib/libgrpc++.$(SHARED_EXT)
 ifneq ($(SYSTEM),Darwin)
+	$(Q) ln -sf libgrpc++.$(SHARED_EXT) $(prefix)/lib/libgrpc++.so.0
 	$(Q) ln -sf libgrpc++.$(SHARED_EXT) $(prefix)/lib/libgrpc++.so
 endif
 endif
@@ -2287,6 +2295,7 @@ else
 	$(Q) $(INSTALL) -d $(prefix)/lib
 	$(Q) $(INSTALL) $(LIBDIR)/$(CONFIG)/libgrpc++_unsecure.$(SHARED_EXT) $(prefix)/lib/libgrpc++_unsecure.$(SHARED_EXT)
 ifneq ($(SYSTEM),Darwin)
+	$(Q) ln -sf libgrpc++_unsecure.$(SHARED_EXT) $(prefix)/lib/libgrpc++_unsecure.so.0
 	$(Q) ln -sf libgrpc++_unsecure.$(SHARED_EXT) $(prefix)/lib/libgrpc++_unsecure.so
 endif
 endif
@@ -2308,6 +2317,7 @@ else
 	$(Q) $(INSTALL) -d $(prefix)/lib
 	$(Q) $(INSTALL) $(LIBDIR)/$(CONFIG)/libgrpc_csharp_ext.$(SHARED_EXT) $(prefix)/lib/libgrpc_csharp_ext.$(SHARED_EXT)
 ifneq ($(SYSTEM),Darwin)
+	$(Q) ln -sf libgrpc_csharp_ext.$(SHARED_EXT) $(prefix)/lib/libgrpc_csharp_ext.so.0
 	$(Q) ln -sf libgrpc_csharp_ext.$(SHARED_EXT) $(prefix)/lib/libgrpc_csharp_ext.so
 endif
 endif
@@ -2425,6 +2435,10 @@ PUBLIC_HEADERS_C += \
     include/grpc/support/sync_win32.h \
     include/grpc/support/thd.h \
     include/grpc/support/time.h \
+    include/grpc/support/tls.h \
+    include/grpc/support/tls_gcc.h \
+    include/grpc/support/tls_msvc.h \
+    include/grpc/support/tls_pthread.h \
     include/grpc/support/useful.h \
 
 LIBGPR_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(LIBGPR_SRC))))
@@ -2587,6 +2601,7 @@ LIBGRPC_SRC = \
     src/core/iomgr/alarm_heap.c \
     src/core/iomgr/endpoint.c \
     src/core/iomgr/endpoint_pair_posix.c \
+    src/core/iomgr/endpoint_pair_windows.c \
     src/core/iomgr/fd_posix.c \
     src/core/iomgr/iocp_windows.c \
     src/core/iomgr/iomgr.c \
@@ -2734,6 +2749,7 @@ src/core/iomgr/alarm.c: $(OPENSSL_DEP)
 src/core/iomgr/alarm_heap.c: $(OPENSSL_DEP)
 src/core/iomgr/endpoint.c: $(OPENSSL_DEP)
 src/core/iomgr/endpoint_pair_posix.c: $(OPENSSL_DEP)
+src/core/iomgr/endpoint_pair_windows.c: $(OPENSSL_DEP)
 src/core/iomgr/fd_posix.c: $(OPENSSL_DEP)
 src/core/iomgr/iocp_windows.c: $(OPENSSL_DEP)
 src/core/iomgr/iomgr.c: $(OPENSSL_DEP)
@@ -2897,6 +2913,7 @@ $(OBJDIR)/$(CONFIG)/src/core/iomgr/alarm.o:
 $(OBJDIR)/$(CONFIG)/src/core/iomgr/alarm_heap.o: 
 $(OBJDIR)/$(CONFIG)/src/core/iomgr/endpoint.o: 
 $(OBJDIR)/$(CONFIG)/src/core/iomgr/endpoint_pair_posix.o: 
+$(OBJDIR)/$(CONFIG)/src/core/iomgr/endpoint_pair_windows.o: 
 $(OBJDIR)/$(CONFIG)/src/core/iomgr/fd_posix.o: 
 $(OBJDIR)/$(CONFIG)/src/core/iomgr/iocp_windows.o: 
 $(OBJDIR)/$(CONFIG)/src/core/iomgr/iomgr.o: 
@@ -2986,6 +3003,7 @@ LIBGRPC_TEST_UTIL_SRC = \
     test/core/util/grpc_profiler.c \
     test/core/util/parse_hexstring.c \
     test/core/util/port_posix.c \
+    test/core/util/port_windows.c \
     test/core/util/slice_splitter.c \
 
 
@@ -3015,6 +3033,7 @@ test/core/transport/transport_end2end_tests.c: $(OPENSSL_DEP)
 test/core/util/grpc_profiler.c: $(OPENSSL_DEP)
 test/core/util/parse_hexstring.c: $(OPENSSL_DEP)
 test/core/util/port_posix.c: $(OPENSSL_DEP)
+test/core/util/port_windows.c: $(OPENSSL_DEP)
 test/core/util/slice_splitter.c: $(OPENSSL_DEP)
 endif
 
@@ -3048,6 +3067,7 @@ $(OBJDIR)/$(CONFIG)/test/core/transport/transport_end2end_tests.o:
 $(OBJDIR)/$(CONFIG)/test/core/util/grpc_profiler.o: 
 $(OBJDIR)/$(CONFIG)/test/core/util/parse_hexstring.o: 
 $(OBJDIR)/$(CONFIG)/test/core/util/port_posix.o: 
+$(OBJDIR)/$(CONFIG)/test/core/util/port_windows.o: 
 $(OBJDIR)/$(CONFIG)/test/core/util/slice_splitter.o: 
 
 
@@ -3073,6 +3093,7 @@ LIBGRPC_UNSECURE_SRC = \
     src/core/iomgr/alarm_heap.c \
     src/core/iomgr/endpoint.c \
     src/core/iomgr/endpoint_pair_posix.c \
+    src/core/iomgr/endpoint_pair_windows.c \
     src/core/iomgr/fd_posix.c \
     src/core/iomgr/iocp_windows.c \
     src/core/iomgr/iomgr.c \
@@ -3213,6 +3234,7 @@ $(OBJDIR)/$(CONFIG)/src/core/iomgr/alarm.o:
 $(OBJDIR)/$(CONFIG)/src/core/iomgr/alarm_heap.o: 
 $(OBJDIR)/$(CONFIG)/src/core/iomgr/endpoint.o: 
 $(OBJDIR)/$(CONFIG)/src/core/iomgr/endpoint_pair_posix.o: 
+$(OBJDIR)/$(CONFIG)/src/core/iomgr/endpoint_pair_windows.o: 
 $(OBJDIR)/$(CONFIG)/src/core/iomgr/fd_posix.o: 
 $(OBJDIR)/$(CONFIG)/src/core/iomgr/iocp_windows.o: 
 $(OBJDIR)/$(CONFIG)/src/core/iomgr/iomgr.o: 
@@ -3337,6 +3359,12 @@ PUBLIC_HEADERS_CXX += \
     include/grpc++/impl/rpc_method.h \
     include/grpc++/impl/rpc_service_method.h \
     include/grpc++/impl/service_type.h \
+    include/grpc++/impl/sync.h \
+    include/grpc++/impl/sync_cxx11.h \
+    include/grpc++/impl/sync_no_cxx11.h \
+    include/grpc++/impl/thd.h \
+    include/grpc++/impl/thd_cxx11.h \
+    include/grpc++/impl/thd_no_cxx11.h \
     include/grpc++/server.h \
     include/grpc++/server_builder.h \
     include/grpc++/server_context.h \
@@ -3588,6 +3616,12 @@ PUBLIC_HEADERS_CXX += \
     include/grpc++/impl/rpc_method.h \
     include/grpc++/impl/rpc_service_method.h \
     include/grpc++/impl/service_type.h \
+    include/grpc++/impl/sync.h \
+    include/grpc++/impl/sync_cxx11.h \
+    include/grpc++/impl/sync_no_cxx11.h \
+    include/grpc++/impl/thd.h \
+    include/grpc++/impl/thd_cxx11.h \
+    include/grpc++/impl/thd_no_cxx11.h \
     include/grpc++/server.h \
     include/grpc++/server_builder.h \
     include/grpc++/server_context.h \
@@ -3717,6 +3751,251 @@ $(OBJDIR)/$(CONFIG)/src/compiler/python_generator.o:
 $(OBJDIR)/$(CONFIG)/src/compiler/ruby_generator.o: 
 
 
+LIBINTEROP_CLIENT_HELPER_SRC = \
+    test/cpp/interop/client_helper.cc \
+
+
+LIBINTEROP_CLIENT_HELPER_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(LIBINTEROP_CLIENT_HELPER_SRC))))
+
+ifeq ($(NO_SECURE),true)
+
+# You can't build secure libraries if you don't have OpenSSL with ALPN.
+
+$(LIBDIR)/$(CONFIG)/libinterop_client_helper.a: openssl_dep_error
+
+
+else
+
+ifeq ($(NO_PROTOBUF),true)
+
+# You can't build a C++ library if you don't have protobuf - a bit overreached, but still okay.
+
+$(LIBDIR)/$(CONFIG)/libinterop_client_helper.a: protobuf_dep_error
+
+
+else
+
+ifneq ($(OPENSSL_DEP),)
+# This is to ensure the embedded OpenSSL is built beforehand, properly
+# installing headers to their final destination on the drive. We need this
+# otherwise parallel compilation will fail if a source is compiled first.
+test/cpp/interop/client_helper.cc: $(OPENSSL_DEP)
+endif
+
+$(LIBDIR)/$(CONFIG)/libinterop_client_helper.a: $(ZLIB_DEP) $(OPENSSL_DEP) $(PROTOBUF_DEP) $(LIBINTEROP_CLIENT_HELPER_OBJS)
+	$(E) "[AR]      Creating $@"
+	$(Q) mkdir -p `dirname $@`
+	$(Q) rm -f $(LIBDIR)/$(CONFIG)/libinterop_client_helper.a
+	$(Q) $(AR) rcs $(LIBDIR)/$(CONFIG)/libinterop_client_helper.a $(LIBINTEROP_CLIENT_HELPER_OBJS)
+ifeq ($(SYSTEM),Darwin)
+	$(Q) ranlib $(LIBDIR)/$(CONFIG)/libinterop_client_helper.a
+endif
+
+
+
+
+endif
+
+endif
+
+ifneq ($(NO_SECURE),true)
+ifneq ($(NO_DEPS),true)
+-include $(LIBINTEROP_CLIENT_HELPER_OBJS:.o=.dep)
+endif
+endif
+
+$(OBJDIR)/$(CONFIG)/test/cpp/interop/client_helper.o: 
+
+
+LIBINTEROP_CLIENT_MAIN_SRC = \
+    $(GENDIR)/test/cpp/interop/empty.pb.cc $(GENDIR)/test/cpp/interop/empty.grpc.pb.cc \
+    $(GENDIR)/test/cpp/interop/messages.pb.cc $(GENDIR)/test/cpp/interop/messages.grpc.pb.cc \
+    $(GENDIR)/test/cpp/interop/test.pb.cc $(GENDIR)/test/cpp/interop/test.grpc.pb.cc \
+    test/cpp/interop/client.cc \
+    test/cpp/interop/interop_client.cc \
+
+
+LIBINTEROP_CLIENT_MAIN_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(LIBINTEROP_CLIENT_MAIN_SRC))))
+
+ifeq ($(NO_SECURE),true)
+
+# You can't build secure libraries if you don't have OpenSSL with ALPN.
+
+$(LIBDIR)/$(CONFIG)/libinterop_client_main.a: openssl_dep_error
+
+
+else
+
+ifeq ($(NO_PROTOBUF),true)
+
+# You can't build a C++ library if you don't have protobuf - a bit overreached, but still okay.
+
+$(LIBDIR)/$(CONFIG)/libinterop_client_main.a: protobuf_dep_error
+
+
+else
+
+ifneq ($(OPENSSL_DEP),)
+# This is to ensure the embedded OpenSSL is built beforehand, properly
+# installing headers to their final destination on the drive. We need this
+# otherwise parallel compilation will fail if a source is compiled first.
+test/cpp/interop/empty.proto: $(OPENSSL_DEP)
+test/cpp/interop/messages.proto: $(OPENSSL_DEP)
+test/cpp/interop/test.proto: $(OPENSSL_DEP)
+test/cpp/interop/client.cc: $(OPENSSL_DEP)
+test/cpp/interop/interop_client.cc: $(OPENSSL_DEP)
+endif
+
+$(LIBDIR)/$(CONFIG)/libinterop_client_main.a: $(ZLIB_DEP) $(OPENSSL_DEP) $(PROTOBUF_DEP) $(LIBINTEROP_CLIENT_MAIN_OBJS)
+	$(E) "[AR]      Creating $@"
+	$(Q) mkdir -p `dirname $@`
+	$(Q) rm -f $(LIBDIR)/$(CONFIG)/libinterop_client_main.a
+	$(Q) $(AR) rcs $(LIBDIR)/$(CONFIG)/libinterop_client_main.a $(LIBINTEROP_CLIENT_MAIN_OBJS)
+ifeq ($(SYSTEM),Darwin)
+	$(Q) ranlib $(LIBDIR)/$(CONFIG)/libinterop_client_main.a
+endif
+
+
+
+
+endif
+
+endif
+
+ifneq ($(NO_SECURE),true)
+ifneq ($(NO_DEPS),true)
+-include $(LIBINTEROP_CLIENT_MAIN_OBJS:.o=.dep)
+endif
+endif
+
+
+
+
+$(OBJDIR)/$(CONFIG)/test/cpp/interop/client.o:     $(GENDIR)/test/cpp/interop/empty.pb.cc $(GENDIR)/test/cpp/interop/empty.grpc.pb.cc    $(GENDIR)/test/cpp/interop/messages.pb.cc $(GENDIR)/test/cpp/interop/messages.grpc.pb.cc    $(GENDIR)/test/cpp/interop/test.pb.cc $(GENDIR)/test/cpp/interop/test.grpc.pb.cc
+$(OBJDIR)/$(CONFIG)/test/cpp/interop/interop_client.o:     $(GENDIR)/test/cpp/interop/empty.pb.cc $(GENDIR)/test/cpp/interop/empty.grpc.pb.cc    $(GENDIR)/test/cpp/interop/messages.pb.cc $(GENDIR)/test/cpp/interop/messages.grpc.pb.cc    $(GENDIR)/test/cpp/interop/test.pb.cc $(GENDIR)/test/cpp/interop/test.grpc.pb.cc
+
+
+LIBINTEROP_SERVER_HELPER_SRC = \
+    test/cpp/interop/server_helper.cc \
+
+
+LIBINTEROP_SERVER_HELPER_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(LIBINTEROP_SERVER_HELPER_SRC))))
+
+ifeq ($(NO_SECURE),true)
+
+# You can't build secure libraries if you don't have OpenSSL with ALPN.
+
+$(LIBDIR)/$(CONFIG)/libinterop_server_helper.a: openssl_dep_error
+
+
+else
+
+ifeq ($(NO_PROTOBUF),true)
+
+# You can't build a C++ library if you don't have protobuf - a bit overreached, but still okay.
+
+$(LIBDIR)/$(CONFIG)/libinterop_server_helper.a: protobuf_dep_error
+
+
+else
+
+ifneq ($(OPENSSL_DEP),)
+# This is to ensure the embedded OpenSSL is built beforehand, properly
+# installing headers to their final destination on the drive. We need this
+# otherwise parallel compilation will fail if a source is compiled first.
+test/cpp/interop/server_helper.cc: $(OPENSSL_DEP)
+endif
+
+$(LIBDIR)/$(CONFIG)/libinterop_server_helper.a: $(ZLIB_DEP) $(OPENSSL_DEP) $(PROTOBUF_DEP) $(LIBINTEROP_SERVER_HELPER_OBJS)
+	$(E) "[AR]      Creating $@"
+	$(Q) mkdir -p `dirname $@`
+	$(Q) rm -f $(LIBDIR)/$(CONFIG)/libinterop_server_helper.a
+	$(Q) $(AR) rcs $(LIBDIR)/$(CONFIG)/libinterop_server_helper.a $(LIBINTEROP_SERVER_HELPER_OBJS)
+ifeq ($(SYSTEM),Darwin)
+	$(Q) ranlib $(LIBDIR)/$(CONFIG)/libinterop_server_helper.a
+endif
+
+
+
+
+endif
+
+endif
+
+ifneq ($(NO_SECURE),true)
+ifneq ($(NO_DEPS),true)
+-include $(LIBINTEROP_SERVER_HELPER_OBJS:.o=.dep)
+endif
+endif
+
+$(OBJDIR)/$(CONFIG)/test/cpp/interop/server_helper.o: 
+
+
+LIBINTEROP_SERVER_MAIN_SRC = \
+    $(GENDIR)/test/cpp/interop/empty.pb.cc $(GENDIR)/test/cpp/interop/empty.grpc.pb.cc \
+    $(GENDIR)/test/cpp/interop/messages.pb.cc $(GENDIR)/test/cpp/interop/messages.grpc.pb.cc \
+    $(GENDIR)/test/cpp/interop/test.pb.cc $(GENDIR)/test/cpp/interop/test.grpc.pb.cc \
+    test/cpp/interop/server.cc \
+
+
+LIBINTEROP_SERVER_MAIN_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(LIBINTEROP_SERVER_MAIN_SRC))))
+
+ifeq ($(NO_SECURE),true)
+
+# You can't build secure libraries if you don't have OpenSSL with ALPN.
+
+$(LIBDIR)/$(CONFIG)/libinterop_server_main.a: openssl_dep_error
+
+
+else
+
+ifeq ($(NO_PROTOBUF),true)
+
+# You can't build a C++ library if you don't have protobuf - a bit overreached, but still okay.
+
+$(LIBDIR)/$(CONFIG)/libinterop_server_main.a: protobuf_dep_error
+
+
+else
+
+ifneq ($(OPENSSL_DEP),)
+# This is to ensure the embedded OpenSSL is built beforehand, properly
+# installing headers to their final destination on the drive. We need this
+# otherwise parallel compilation will fail if a source is compiled first.
+test/cpp/interop/empty.proto: $(OPENSSL_DEP)
+test/cpp/interop/messages.proto: $(OPENSSL_DEP)
+test/cpp/interop/test.proto: $(OPENSSL_DEP)
+test/cpp/interop/server.cc: $(OPENSSL_DEP)
+endif
+
+$(LIBDIR)/$(CONFIG)/libinterop_server_main.a: $(ZLIB_DEP) $(OPENSSL_DEP) $(PROTOBUF_DEP) $(LIBINTEROP_SERVER_MAIN_OBJS)
+	$(E) "[AR]      Creating $@"
+	$(Q) mkdir -p `dirname $@`
+	$(Q) rm -f $(LIBDIR)/$(CONFIG)/libinterop_server_main.a
+	$(Q) $(AR) rcs $(LIBDIR)/$(CONFIG)/libinterop_server_main.a $(LIBINTEROP_SERVER_MAIN_OBJS)
+ifeq ($(SYSTEM),Darwin)
+	$(Q) ranlib $(LIBDIR)/$(CONFIG)/libinterop_server_main.a
+endif
+
+
+
+
+endif
+
+endif
+
+ifneq ($(NO_SECURE),true)
+ifneq ($(NO_DEPS),true)
+-include $(LIBINTEROP_SERVER_MAIN_OBJS:.o=.dep)
+endif
+endif
+
+
+
+
+$(OBJDIR)/$(CONFIG)/test/cpp/interop/server.o:     $(GENDIR)/test/cpp/interop/empty.pb.cc $(GENDIR)/test/cpp/interop/empty.grpc.pb.cc    $(GENDIR)/test/cpp/interop/messages.pb.cc $(GENDIR)/test/cpp/interop/messages.grpc.pb.cc    $(GENDIR)/test/cpp/interop/test.pb.cc $(GENDIR)/test/cpp/interop/test.grpc.pb.cc
+
+
 LIBPUBSUB_CLIENT_LIB_SRC = \
     $(GENDIR)/examples/pubsub/label.pb.cc $(GENDIR)/examples/pubsub/label.grpc.pb.cc \
     $(GENDIR)/examples/pubsub/empty.pb.cc $(GENDIR)/examples/pubsub/empty.grpc.pb.cc \
@@ -3788,6 +4067,7 @@ $(OBJDIR)/$(CONFIG)/examples/pubsub/subscriber.o:     $(GENDIR)/examples/pubsub/
 LIBQPS_SRC = \
     $(GENDIR)/test/cpp/qps/qpstest.pb.cc $(GENDIR)/test/cpp/qps/qpstest.grpc.pb.cc \
     test/cpp/qps/driver.cc \
+    test/cpp/qps/report.cc \
     test/cpp/qps/timer.cc \
 
 
@@ -3817,6 +4097,7 @@ ifneq ($(OPENSSL_DEP),)
 # otherwise parallel compilation will fail if a source is compiled first.
 test/cpp/qps/qpstest.proto: $(OPENSSL_DEP)
 test/cpp/qps/driver.cc: $(OPENSSL_DEP)
+test/cpp/qps/report.cc: $(OPENSSL_DEP)
 test/cpp/qps/timer.cc: $(OPENSSL_DEP)
 endif
 
@@ -3844,6 +4125,7 @@ endif
 
 
 $(OBJDIR)/$(CONFIG)/test/cpp/qps/driver.o:     $(GENDIR)/test/cpp/qps/qpstest.pb.cc $(GENDIR)/test/cpp/qps/qpstest.grpc.pb.cc
+$(OBJDIR)/$(CONFIG)/test/cpp/qps/report.o:     $(GENDIR)/test/cpp/qps/qpstest.pb.cc $(GENDIR)/test/cpp/qps/qpstest.grpc.pb.cc
 $(OBJDIR)/$(CONFIG)/test/cpp/qps/timer.o:     $(GENDIR)/test/cpp/qps/qpstest.pb.cc $(GENDIR)/test/cpp/qps/qpstest.grpc.pb.cc
 
 
@@ -6820,6 +7102,37 @@ endif
 endif
 
 
+GPR_TLS_TEST_SRC = \
+    test/core/support/tls_test.c \
+
+GPR_TLS_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(GPR_TLS_TEST_SRC))))
+
+ifeq ($(NO_SECURE),true)
+
+# You can't build secure targets if you don't have OpenSSL with ALPN.
+
+$(BINDIR)/$(CONFIG)/gpr_tls_test: openssl_dep_error
+
+else
+
+$(BINDIR)/$(CONFIG)/gpr_tls_test: $(GPR_TLS_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
+	$(E) "[LD]      Linking $@"
+	$(Q) mkdir -p `dirname $@`
+	$(Q) $(LD) $(LDFLAGS) $(GPR_TLS_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBS) $(LDLIBS_SECURE) -o $(BINDIR)/$(CONFIG)/gpr_tls_test
+
+endif
+
+$(OBJDIR)/$(CONFIG)/test/core/support/tls_test.o:  $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
+
+deps_gpr_tls_test: $(GPR_TLS_TEST_OBJS:.o=.dep)
+
+ifneq ($(NO_SECURE),true)
+ifneq ($(NO_DEPS),true)
+-include $(GPR_TLS_TEST_OBJS:.o=.dep)
+endif
+endif
+
+
 GPR_USEFUL_TEST_SRC = \
     test/core/support/useful_test.c \
 
@@ -8054,7 +8367,7 @@ else
 $(BINDIR)/$(CONFIG)/async_end2end_test: $(PROTOBUF_DEP) $(ASYNC_END2END_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
 	$(E) "[LD]      Linking $@"
 	$(Q) mkdir -p `dirname $@`
-	$(Q) $(LDXX) $(LDFLAGS) $(ASYNC_END2END_TEST_OBJS) $(GTEST_LIB) $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBSXX) $(LDLIBS_PROTOBUF) $(LDLIBS) $(LDLIBS_SECURE) -o $(BINDIR)/$(CONFIG)/async_end2end_test
+	$(Q) $(LDXX) $(LDFLAGS) $(ASYNC_END2END_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBSXX) $(LDLIBS_PROTOBUF) $(LDLIBS) $(LDLIBS_SECURE) $(GTEST_LIB) -o $(BINDIR)/$(CONFIG)/async_end2end_test
 
 endif
 
@@ -8096,7 +8409,7 @@ else
 $(BINDIR)/$(CONFIG)/channel_arguments_test: $(PROTOBUF_DEP) $(CHANNEL_ARGUMENTS_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr.a
 	$(E) "[LD]      Linking $@"
 	$(Q) mkdir -p `dirname $@`
-	$(Q) $(LDXX) $(LDFLAGS) $(CHANNEL_ARGUMENTS_TEST_OBJS) $(GTEST_LIB) $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBSXX) $(LDLIBS_PROTOBUF) $(LDLIBS) $(LDLIBS_SECURE) -o $(BINDIR)/$(CONFIG)/channel_arguments_test
+	$(Q) $(LDXX) $(LDFLAGS) $(CHANNEL_ARGUMENTS_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBSXX) $(LDLIBS_PROTOBUF) $(LDLIBS) $(LDLIBS_SECURE) $(GTEST_LIB) -o $(BINDIR)/$(CONFIG)/channel_arguments_test
 
 endif
 
@@ -8138,7 +8451,7 @@ else
 $(BINDIR)/$(CONFIG)/cli_call_test: $(PROTOBUF_DEP) $(CLI_CALL_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
 	$(E) "[LD]      Linking $@"
 	$(Q) mkdir -p `dirname $@`
-	$(Q) $(LDXX) $(LDFLAGS) $(CLI_CALL_TEST_OBJS) $(GTEST_LIB) $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBSXX) $(LDLIBS_PROTOBUF) $(LDLIBS) $(LDLIBS_SECURE) -o $(BINDIR)/$(CONFIG)/cli_call_test
+	$(Q) $(LDXX) $(LDFLAGS) $(CLI_CALL_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBSXX) $(LDLIBS_PROTOBUF) $(LDLIBS) $(LDLIBS_SECURE) $(GTEST_LIB) -o $(BINDIR)/$(CONFIG)/cli_call_test
 
 endif
 
@@ -8180,7 +8493,7 @@ else
 $(BINDIR)/$(CONFIG)/credentials_test: $(PROTOBUF_DEP) $(CREDENTIALS_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr.a
 	$(E) "[LD]      Linking $@"
 	$(Q) mkdir -p `dirname $@`
-	$(Q) $(LDXX) $(LDFLAGS) $(CREDENTIALS_TEST_OBJS) $(GTEST_LIB) $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBSXX) $(LDLIBS_PROTOBUF) $(LDLIBS) $(LDLIBS_SECURE) -o $(BINDIR)/$(CONFIG)/credentials_test
+	$(Q) $(LDXX) $(LDFLAGS) $(CREDENTIALS_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBSXX) $(LDLIBS_PROTOBUF) $(LDLIBS) $(LDLIBS_SECURE) $(GTEST_LIB) -o $(BINDIR)/$(CONFIG)/credentials_test
 
 endif
 
@@ -8222,7 +8535,7 @@ else
 $(BINDIR)/$(CONFIG)/cxx_time_test: $(PROTOBUF_DEP) $(CXX_TIME_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
 	$(E) "[LD]      Linking $@"
 	$(Q) mkdir -p `dirname $@`
-	$(Q) $(LDXX) $(LDFLAGS) $(CXX_TIME_TEST_OBJS) $(GTEST_LIB) $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBSXX) $(LDLIBS_PROTOBUF) $(LDLIBS) $(LDLIBS_SECURE) -o $(BINDIR)/$(CONFIG)/cxx_time_test
+	$(Q) $(LDXX) $(LDFLAGS) $(CXX_TIME_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBSXX) $(LDLIBS_PROTOBUF) $(LDLIBS) $(LDLIBS_SECURE) $(GTEST_LIB) -o $(BINDIR)/$(CONFIG)/cxx_time_test
 
 endif
 
@@ -8264,7 +8577,7 @@ else
 $(BINDIR)/$(CONFIG)/end2end_test: $(PROTOBUF_DEP) $(END2END_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
 	$(E) "[LD]      Linking $@"
 	$(Q) mkdir -p `dirname $@`
-	$(Q) $(LDXX) $(LDFLAGS) $(END2END_TEST_OBJS) $(GTEST_LIB) $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBSXX) $(LDLIBS_PROTOBUF) $(LDLIBS) $(LDLIBS_SECURE) -o $(BINDIR)/$(CONFIG)/end2end_test
+	$(Q) $(LDXX) $(LDFLAGS) $(END2END_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBSXX) $(LDLIBS_PROTOBUF) $(LDLIBS) $(LDLIBS_SECURE) $(GTEST_LIB) -o $(BINDIR)/$(CONFIG)/end2end_test
 
 endif
 
@@ -8306,7 +8619,7 @@ else
 $(BINDIR)/$(CONFIG)/generic_end2end_test: $(PROTOBUF_DEP) $(GENERIC_END2END_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
 	$(E) "[LD]      Linking $@"
 	$(Q) mkdir -p `dirname $@`
-	$(Q) $(LDXX) $(LDFLAGS) $(GENERIC_END2END_TEST_OBJS) $(GTEST_LIB) $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBSXX) $(LDLIBS_PROTOBUF) $(LDLIBS) $(LDLIBS_SECURE) -o $(BINDIR)/$(CONFIG)/generic_end2end_test
+	$(Q) $(LDXX) $(LDFLAGS) $(GENERIC_END2END_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBSXX) $(LDLIBS_PROTOBUF) $(LDLIBS) $(LDLIBS_SECURE) $(GTEST_LIB) -o $(BINDIR)/$(CONFIG)/generic_end2end_test
 
 endif
 
@@ -8348,7 +8661,7 @@ else
 $(BINDIR)/$(CONFIG)/grpc_cli: $(PROTOBUF_DEP) $(GRPC_CLI_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
 	$(E) "[LD]      Linking $@"
 	$(Q) mkdir -p `dirname $@`
-	$(Q) $(LDXX) $(LDFLAGS) $(GRPC_CLI_OBJS) $(GTEST_LIB) $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBSXX) $(LDLIBS_PROTOBUF) $(LDLIBS) $(LDLIBS_SECURE) -o $(BINDIR)/$(CONFIG)/grpc_cli
+	$(Q) $(LDXX) $(LDFLAGS) $(GRPC_CLI_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBSXX) $(LDLIBS_PROTOBUF) $(LDLIBS) $(LDLIBS_SECURE) $(GTEST_LIB) -o $(BINDIR)/$(CONFIG)/grpc_cli
 
 endif
 
@@ -8486,10 +8799,6 @@ endif
 
 
 INTEROP_CLIENT_SRC = \
-    $(GENDIR)/test/cpp/interop/empty.pb.cc $(GENDIR)/test/cpp/interop/empty.grpc.pb.cc \
-    $(GENDIR)/test/cpp/interop/messages.pb.cc $(GENDIR)/test/cpp/interop/messages.grpc.pb.cc \
-    $(GENDIR)/test/cpp/interop/test.pb.cc $(GENDIR)/test/cpp/interop/test.grpc.pb.cc \
-    test/cpp/interop/client.cc \
 
 INTEROP_CLIENT_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(INTEROP_CLIENT_SRC))))
 
@@ -8510,19 +8819,15 @@ $(BINDIR)/$(CONFIG)/interop_client: protobuf_dep_error
 
 else
 
-$(BINDIR)/$(CONFIG)/interop_client: $(PROTOBUF_DEP) $(INTEROP_CLIENT_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
+$(BINDIR)/$(CONFIG)/interop_client: $(PROTOBUF_DEP) $(INTEROP_CLIENT_OBJS) $(LIBDIR)/$(CONFIG)/libinterop_client_main.a $(LIBDIR)/$(CONFIG)/libinterop_client_helper.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
 	$(E) "[LD]      Linking $@"
 	$(Q) mkdir -p `dirname $@`
-	$(Q) $(LDXX) $(LDFLAGS) $(INTEROP_CLIENT_OBJS) $(GTEST_LIB) $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBSXX) $(LDLIBS_PROTOBUF) $(LDLIBS) $(LDLIBS_SECURE) -o $(BINDIR)/$(CONFIG)/interop_client
+	$(Q) $(LDXX) $(LDFLAGS) $(INTEROP_CLIENT_OBJS) $(LIBDIR)/$(CONFIG)/libinterop_client_main.a $(LIBDIR)/$(CONFIG)/libinterop_client_helper.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBSXX) $(LDLIBS_PROTOBUF) $(LDLIBS) $(LDLIBS_SECURE) $(GTEST_LIB) -o $(BINDIR)/$(CONFIG)/interop_client
 
 endif
 
 endif
 
-$(OBJDIR)/$(CONFIG)/test/cpp/interop/empty.o:  $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
-$(OBJDIR)/$(CONFIG)/test/cpp/interop/messages.o:  $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
-$(OBJDIR)/$(CONFIG)/test/cpp/interop/test.o:  $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
-$(OBJDIR)/$(CONFIG)/test/cpp/interop/client.o:  $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
 
 deps_interop_client: $(INTEROP_CLIENT_OBJS:.o=.dep)
 
@@ -8534,10 +8839,6 @@ endif
 
 
 INTEROP_SERVER_SRC = \
-    $(GENDIR)/test/cpp/interop/empty.pb.cc $(GENDIR)/test/cpp/interop/empty.grpc.pb.cc \
-    $(GENDIR)/test/cpp/interop/messages.pb.cc $(GENDIR)/test/cpp/interop/messages.grpc.pb.cc \
-    $(GENDIR)/test/cpp/interop/test.pb.cc $(GENDIR)/test/cpp/interop/test.grpc.pb.cc \
-    test/cpp/interop/server.cc \
 
 INTEROP_SERVER_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(INTEROP_SERVER_SRC))))
 
@@ -8558,19 +8859,15 @@ $(BINDIR)/$(CONFIG)/interop_server: protobuf_dep_error
 
 else
 
-$(BINDIR)/$(CONFIG)/interop_server: $(PROTOBUF_DEP) $(INTEROP_SERVER_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
+$(BINDIR)/$(CONFIG)/interop_server: $(PROTOBUF_DEP) $(INTEROP_SERVER_OBJS) $(LIBDIR)/$(CONFIG)/libinterop_server_main.a $(LIBDIR)/$(CONFIG)/libinterop_server_helper.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
 	$(E) "[LD]      Linking $@"
 	$(Q) mkdir -p `dirname $@`
-	$(Q) $(LDXX) $(LDFLAGS) $(INTEROP_SERVER_OBJS) $(GTEST_LIB) $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBSXX) $(LDLIBS_PROTOBUF) $(LDLIBS) $(LDLIBS_SECURE) -o $(BINDIR)/$(CONFIG)/interop_server
+	$(Q) $(LDXX) $(LDFLAGS) $(INTEROP_SERVER_OBJS) $(LIBDIR)/$(CONFIG)/libinterop_server_main.a $(LIBDIR)/$(CONFIG)/libinterop_server_helper.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBSXX) $(LDLIBS_PROTOBUF) $(LDLIBS) $(LDLIBS_SECURE) $(GTEST_LIB) -o $(BINDIR)/$(CONFIG)/interop_server
 
 endif
 
 endif
 
-$(OBJDIR)/$(CONFIG)/test/cpp/interop/empty.o:  $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
-$(OBJDIR)/$(CONFIG)/test/cpp/interop/messages.o:  $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
-$(OBJDIR)/$(CONFIG)/test/cpp/interop/test.o:  $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
-$(OBJDIR)/$(CONFIG)/test/cpp/interop/server.o:  $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
 
 deps_interop_server: $(INTEROP_SERVER_OBJS:.o=.dep)
 
@@ -8606,7 +8903,7 @@ else
 $(BINDIR)/$(CONFIG)/interop_test: $(PROTOBUF_DEP) $(INTEROP_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
 	$(E) "[LD]      Linking $@"
 	$(Q) mkdir -p `dirname $@`
-	$(Q) $(LDXX) $(LDFLAGS) $(INTEROP_TEST_OBJS) $(GTEST_LIB) $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBSXX) $(LDLIBS_PROTOBUF) $(LDLIBS) $(LDLIBS_SECURE) -o $(BINDIR)/$(CONFIG)/interop_test
+	$(Q) $(LDXX) $(LDFLAGS) $(INTEROP_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBSXX) $(LDLIBS_PROTOBUF) $(LDLIBS) $(LDLIBS_SECURE) $(GTEST_LIB) -o $(BINDIR)/$(CONFIG)/interop_test
 
 endif
 
@@ -8648,7 +8945,7 @@ else
 $(BINDIR)/$(CONFIG)/pubsub_client: $(PROTOBUF_DEP) $(PUBSUB_CLIENT_OBJS) $(LIBDIR)/$(CONFIG)/libpubsub_client_lib.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
 	$(E) "[LD]      Linking $@"
 	$(Q) mkdir -p `dirname $@`
-	$(Q) $(LDXX) $(LDFLAGS) $(PUBSUB_CLIENT_OBJS) $(GTEST_LIB) $(LIBDIR)/$(CONFIG)/libpubsub_client_lib.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBSXX) $(LDLIBS_PROTOBUF) $(LDLIBS) $(LDLIBS_SECURE) -o $(BINDIR)/$(CONFIG)/pubsub_client
+	$(Q) $(LDXX) $(LDFLAGS) $(PUBSUB_CLIENT_OBJS) $(LIBDIR)/$(CONFIG)/libpubsub_client_lib.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBSXX) $(LDLIBS_PROTOBUF) $(LDLIBS) $(LDLIBS_SECURE) $(GTEST_LIB) -o $(BINDIR)/$(CONFIG)/pubsub_client
 
 endif
 
@@ -8690,7 +8987,7 @@ else
 $(BINDIR)/$(CONFIG)/pubsub_publisher_test: $(PROTOBUF_DEP) $(PUBSUB_PUBLISHER_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libpubsub_client_lib.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
 	$(E) "[LD]      Linking $@"
 	$(Q) mkdir -p `dirname $@`
-	$(Q) $(LDXX) $(LDFLAGS) $(PUBSUB_PUBLISHER_TEST_OBJS) $(GTEST_LIB) $(LIBDIR)/$(CONFIG)/libpubsub_client_lib.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBSXX) $(LDLIBS_PROTOBUF) $(LDLIBS) $(LDLIBS_SECURE) -o $(BINDIR)/$(CONFIG)/pubsub_publisher_test
+	$(Q) $(LDXX) $(LDFLAGS) $(PUBSUB_PUBLISHER_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libpubsub_client_lib.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBSXX) $(LDLIBS_PROTOBUF) $(LDLIBS) $(LDLIBS_SECURE) $(GTEST_LIB) -o $(BINDIR)/$(CONFIG)/pubsub_publisher_test
 
 endif
 
@@ -8732,7 +9029,7 @@ else
 $(BINDIR)/$(CONFIG)/pubsub_subscriber_test: $(PROTOBUF_DEP) $(PUBSUB_SUBSCRIBER_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libpubsub_client_lib.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
 	$(E) "[LD]      Linking $@"
 	$(Q) mkdir -p `dirname $@`
-	$(Q) $(LDXX) $(LDFLAGS) $(PUBSUB_SUBSCRIBER_TEST_OBJS) $(GTEST_LIB) $(LIBDIR)/$(CONFIG)/libpubsub_client_lib.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBSXX) $(LDLIBS_PROTOBUF) $(LDLIBS) $(LDLIBS_SECURE) -o $(BINDIR)/$(CONFIG)/pubsub_subscriber_test
+	$(Q) $(LDXX) $(LDFLAGS) $(PUBSUB_SUBSCRIBER_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libpubsub_client_lib.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBSXX) $(LDLIBS_PROTOBUF) $(LDLIBS) $(LDLIBS_SECURE) $(GTEST_LIB) -o $(BINDIR)/$(CONFIG)/pubsub_subscriber_test
 
 endif
 
@@ -8774,7 +9071,7 @@ else
 $(BINDIR)/$(CONFIG)/qps_driver: $(PROTOBUF_DEP) $(QPS_DRIVER_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
 	$(E) "[LD]      Linking $@"
 	$(Q) mkdir -p `dirname $@`
-	$(Q) $(LDXX) $(LDFLAGS) $(QPS_DRIVER_OBJS) $(GTEST_LIB) $(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 $(LDLIBSXX) $(LDLIBS_PROTOBUF) $(LDLIBS) $(LDLIBS_SECURE) -o $(BINDIR)/$(CONFIG)/qps_driver
+	$(Q) $(LDXX) $(LDFLAGS) $(QPS_DRIVER_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 $(LDLIBSXX) $(LDLIBS_PROTOBUF) $(LDLIBS) $(LDLIBS_SECURE) $(GTEST_LIB) -o $(BINDIR)/$(CONFIG)/qps_driver
 
 endif
 
@@ -8791,6 +9088,48 @@ endif
 endif
 
 
+QPS_SMOKE_TEST_SRC = \
+    test/cpp/qps/smoke_test.cc \
+
+QPS_SMOKE_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(QPS_SMOKE_TEST_SRC))))
+
+ifeq ($(NO_SECURE),true)
+
+# You can't build secure targets if you don't have OpenSSL with ALPN.
+
+$(BINDIR)/$(CONFIG)/qps_smoke_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_smoke_test: protobuf_dep_error
+
+else
+
+$(BINDIR)/$(CONFIG)/qps_smoke_test: $(PROTOBUF_DEP) $(QPS_SMOKE_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
+	$(E) "[LD]      Linking $@"
+	$(Q) mkdir -p `dirname $@`
+	$(Q) $(LDXX) $(LDFLAGS) $(QPS_SMOKE_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 $(LDLIBSXX) $(LDLIBS_PROTOBUF) $(LDLIBS) $(LDLIBS_SECURE) $(GTEST_LIB) -o $(BINDIR)/$(CONFIG)/qps_smoke_test
+
+endif
+
+endif
+
+$(OBJDIR)/$(CONFIG)/test/cpp/qps/smoke_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
+
+deps_qps_smoke_test: $(QPS_SMOKE_TEST_OBJS:.o=.dep)
+
+ifneq ($(NO_SECURE),true)
+ifneq ($(NO_DEPS),true)
+-include $(QPS_SMOKE_TEST_OBJS:.o=.dep)
+endif
+endif
+
+
 QPS_WORKER_SRC = \
     test/cpp/qps/client_async.cc \
     test/cpp/qps/client_sync.cc \
@@ -8820,7 +9159,7 @@ else
 $(BINDIR)/$(CONFIG)/qps_worker: $(PROTOBUF_DEP) $(QPS_WORKER_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
 	$(E) "[LD]      Linking $@"
 	$(Q) mkdir -p `dirname $@`
-	$(Q) $(LDXX) $(LDFLAGS) $(QPS_WORKER_OBJS) $(GTEST_LIB) $(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 $(LDLIBSXX) $(LDLIBS_PROTOBUF) $(LDLIBS) $(LDLIBS_SECURE) -o $(BINDIR)/$(CONFIG)/qps_worker
+	$(Q) $(LDXX) $(LDFLAGS) $(QPS_WORKER_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 $(LDLIBSXX) $(LDLIBS_PROTOBUF) $(LDLIBS) $(LDLIBS_SECURE) $(GTEST_LIB) -o $(BINDIR)/$(CONFIG)/qps_worker
 
 endif
 
@@ -8866,7 +9205,7 @@ else
 $(BINDIR)/$(CONFIG)/status_test: $(PROTOBUF_DEP) $(STATUS_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
 	$(E) "[LD]      Linking $@"
 	$(Q) mkdir -p `dirname $@`
-	$(Q) $(LDXX) $(LDFLAGS) $(STATUS_TEST_OBJS) $(GTEST_LIB) $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBSXX) $(LDLIBS_PROTOBUF) $(LDLIBS) $(LDLIBS_SECURE) -o $(BINDIR)/$(CONFIG)/status_test
+	$(Q) $(LDXX) $(LDFLAGS) $(STATUS_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBSXX) $(LDLIBS_PROTOBUF) $(LDLIBS) $(LDLIBS_SECURE) $(GTEST_LIB) -o $(BINDIR)/$(CONFIG)/status_test
 
 endif
 
@@ -8908,7 +9247,7 @@ else
 $(BINDIR)/$(CONFIG)/thread_pool_test: $(PROTOBUF_DEP) $(THREAD_POOL_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
 	$(E) "[LD]      Linking $@"
 	$(Q) mkdir -p `dirname $@`
-	$(Q) $(LDXX) $(LDFLAGS) $(THREAD_POOL_TEST_OBJS) $(GTEST_LIB) $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBSXX) $(LDLIBS_PROTOBUF) $(LDLIBS) $(LDLIBS_SECURE) -o $(BINDIR)/$(CONFIG)/thread_pool_test
+	$(Q) $(LDXX) $(LDFLAGS) $(THREAD_POOL_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBSXX) $(LDLIBS_PROTOBUF) $(LDLIBS) $(LDLIBS_SECURE) $(GTEST_LIB) -o $(BINDIR)/$(CONFIG)/thread_pool_test
 
 endif
 
diff --git a/build.json b/build.json
index f8f23e0d3355973cc0dbc3ac30f8bdb89e339c66..40df67e5f99ad7054e33b8a4d1c78a798a455a8d 100644
--- a/build.json
+++ b/build.json
@@ -29,6 +29,12 @@
         "include/grpc++/impl/rpc_method.h",
         "include/grpc++/impl/rpc_service_method.h",
         "include/grpc++/impl/service_type.h",
+        "include/grpc++/impl/sync.h",
+        "include/grpc++/impl/sync_cxx11.h",
+        "include/grpc++/impl/sync_no_cxx11.h",
+        "include/grpc++/impl/thd.h",
+        "include/grpc++/impl/thd_cxx11.h",
+        "include/grpc++/impl/thd_no_cxx11.h",
         "include/grpc++/server.h",
         "include/grpc++/server_builder.h",
         "include/grpc++/server_context.h",
@@ -191,6 +197,7 @@
         "src/core/iomgr/alarm_heap.c",
         "src/core/iomgr/endpoint.c",
         "src/core/iomgr/endpoint_pair_posix.c",
+        "src/core/iomgr/endpoint_pair_windows.c",
         "src/core/iomgr/fd_posix.c",
         "src/core/iomgr/iocp_windows.c",
         "src/core/iomgr/iomgr.c",
@@ -297,6 +304,10 @@
         "include/grpc/support/sync_win32.h",
         "include/grpc/support/thd.h",
         "include/grpc/support/time.h",
+        "include/grpc/support/tls.h",
+        "include/grpc/support/tls_gcc.h",
+        "include/grpc/support/tls_msvc.h",
+        "include/grpc/support/tls_pthread.h",
         "include/grpc/support/useful.h"
       ],
       "headers": [
@@ -434,6 +445,7 @@
         "test/core/util/grpc_profiler.c",
         "test/core/util/parse_hexstring.c",
         "test/core/util/port_posix.c",
+        "test/core/util/port_windows.c",
         "test/core/util/slice_splitter.c"
       ],
       "deps": [
@@ -464,6 +476,10 @@
       "name": "grpc++",
       "build": "all",
       "language": "c++",
+      "headers": [
+        "src/cpp/client/secure_credentials.h",
+        "src/cpp/server/secure_server_credentials.h"
+      ],
       "src": [
         "src/cpp/client/secure_credentials.cc",
         "src/cpp/server/secure_server_credentials.cc"
@@ -531,6 +547,74 @@
       "deps": [],
       "secure": "no"
     },
+    {
+      "name": "interop_client_helper",
+      "build": "private",
+      "language": "c++",
+      "src": [
+        "test/cpp/interop/client_helper.cc"
+      ],
+      "deps": [
+        "grpc++_test_util",
+        "grpc_test_util",
+        "grpc++",
+        "grpc",
+        "gpr"
+      ]
+    },
+    {
+      "name": "interop_client_main",
+      "build": "private",
+      "language": "c++",
+      "src": [
+        "test/cpp/interop/empty.proto",
+        "test/cpp/interop/messages.proto",
+        "test/cpp/interop/test.proto",
+        "test/cpp/interop/client.cc",
+        "test/cpp/interop/interop_client.cc"
+      ],
+      "deps": [
+        "grpc++_test_util",
+        "grpc_test_util",
+        "grpc++",
+        "grpc",
+        "gpr_test_util",
+        "gpr"
+      ]
+    },
+    {
+      "name": "interop_server_helper",
+      "build": "private",
+      "language": "c++",
+      "src": [
+        "test/cpp/interop/server_helper.cc"
+      ],
+      "deps": [
+        "grpc_test_util",
+        "grpc++",
+        "grpc",
+        "gpr"
+      ]
+    },
+    {
+      "name": "interop_server_main",
+      "build": "private",
+      "language": "c++",
+      "src": [
+        "test/cpp/interop/empty.proto",
+        "test/cpp/interop/messages.proto",
+        "test/cpp/interop/test.proto",
+        "test/cpp/interop/server.cc"
+      ],
+      "deps": [
+        "grpc++_test_util",
+        "grpc_test_util",
+        "grpc++",
+        "grpc",
+        "gpr_test_util",
+        "gpr"
+      ]
+    },
     {
       "name": "pubsub_client_lib",
       "build": "private",
@@ -554,11 +638,13 @@
       "language": "c++",
       "headers": [
         "test/cpp/qps/driver.h",
+        "test/cpp/qps/report.h",
         "test/cpp/qps/timer.h"
       ],
       "src": [
         "test/cpp/qps/qpstest.proto",
         "test/cpp/qps/driver.cc",
+        "test/cpp/qps/report.cc",
         "test/cpp/qps/timer.cc"
       ]
     },
@@ -857,6 +943,9 @@
         "grpc",
         "gpr_test_util",
         "gpr"
+      ],
+      "platforms": [
+        "posix"
       ]
     },
     {
@@ -1144,6 +1233,18 @@
         "gpr"
       ]
     },
+    {
+      "name": "gpr_tls_test",
+      "build": "test",
+      "language": "c",
+      "src": [
+        "test/core/support/tls_test.c"
+      ],
+      "deps": [
+        "gpr_test_util",
+        "gpr"
+      ]
+    },
     {
       "name": "gpr_useful_test",
       "build": "test",
@@ -1861,13 +1962,10 @@
       "build": "test",
       "run": false,
       "language": "c++",
-      "src": [
-        "test/cpp/interop/empty.proto",
-        "test/cpp/interop/messages.proto",
-        "test/cpp/interop/test.proto",
-        "test/cpp/interop/client.cc"
-      ],
+      "src": [],
       "deps": [
+        "interop_client_main",
+        "interop_client_helper",
         "grpc++_test_util",
         "grpc_test_util",
         "grpc++",
@@ -1881,13 +1979,10 @@
       "build": "test",
       "run": false,
       "language": "c++",
-      "src": [
-        "test/cpp/interop/empty.proto",
-        "test/cpp/interop/messages.proto",
-        "test/cpp/interop/test.proto",
-        "test/cpp/interop/server.cc"
-      ],
+      "src": [],
       "deps": [
+        "interop_server_main",
+        "interop_server_helper",
         "grpc++_test_util",
         "grpc_test_util",
         "grpc++",
@@ -1979,6 +2074,24 @@
         "gpr"
       ]
     },
+    {
+      "name": "qps_smoke_test",
+      "build": "test",
+      "run": false,
+      "language": "c++",
+      "src": [
+        "test/cpp/qps/smoke_test.cc"
+      ],
+      "deps": [
+        "qps",
+        "grpc++_test_util",
+        "grpc_test_util",
+        "grpc++",
+        "grpc",
+        "gpr_test_util",
+        "gpr"
+      ]
+    },
     {
       "name": "qps_worker",
       "build": "test",
diff --git a/include/grpc/support/port_platform.h b/include/grpc/support/port_platform.h
index 41185dbf6401aef41c7f29cdee6d379780c13d3b..0bb3e16c8d106abb136e15a0a2ef5b0fefa12365 100644
--- a/include/grpc/support/port_platform.h
+++ b/include/grpc/support/port_platform.h
@@ -55,14 +55,17 @@
 #define GPR_WINSOCK_SOCKET 1
 #ifdef __GNUC__
 #define GPR_GCC_ATOMIC 1
+#define GPR_GCC_TLS 1
 #else
 #define GPR_WIN32_ATOMIC 1
+#define GPR_MSVC_TLS 1
 #endif
 #elif defined(ANDROID) || defined(__ANDROID__)
 #define GPR_ANDROID 1
 #define GPR_ARCH_32 1
 #define GPR_CPU_LINUX 1
 #define GPR_GCC_SYNC 1
+#define GPR_GCC_TLS 1
 #define GPR_POSIX_MULTIPOLL_WITH_POLL 1
 #define GPR_POSIX_WAKEUP_FD 1
 #define GPR_LINUX_EVENTFD 1
@@ -88,6 +91,7 @@
 #include <features.h>
 #define GPR_CPU_LINUX 1
 #define GPR_GCC_ATOMIC 1
+#define GPR_GCC_TLS 1
 #define GPR_LINUX 1
 #define GPR_LINUX_MULTIPOLL_WITH_EPOLL 1
 #define GPR_POSIX_WAKEUP_FD 1
@@ -134,6 +138,32 @@
 #define GPR_CPU_POSIX 1
 #endif
 #define GPR_GCC_ATOMIC 1
+#define GPR_GCC_TLS 1
+#define GPR_POSIX_LOG 1
+#define GPR_POSIX_MULTIPOLL_WITH_POLL 1
+#define GPR_POSIX_WAKEUP_FD 1
+#define GPR_POSIX_NO_SPECIAL_WAKEUP_FD 1
+#define GPR_POSIX_SOCKET 1
+#define GPR_POSIX_SOCKETADDR 1
+#define GPR_POSIX_SOCKETUTILS 1
+#define GPR_POSIX_ENV 1
+#define GPR_POSIX_FILE 1
+#define GPR_POSIX_STRING 1
+#define GPR_POSIX_SYNC 1
+#define GPR_POSIX_TIME 1
+#define GPR_GETPID_IN_UNISTD_H 1
+#ifdef _LP64
+#define GPR_ARCH_64 1
+#else /* _LP64 */
+#define GPR_ARCH_32 1
+#endif /* _LP64 */
+#elif defined(__FreeBSD__)
+#ifndef _BSD_SOURCE
+#define _BSD_SOURCE
+#endif
+#define GPR_CPU_POSIX 1
+#define GPR_GCC_ATOMIC 1
+#define GPR_GCC_TLS 1
 #define GPR_POSIX_LOG 1
 #define GPR_POSIX_MULTIPOLL_WITH_POLL 1
 #define GPR_POSIX_WAKEUP_FD 1
@@ -190,16 +220,20 @@
 #error Must define exactly one of GPR_ARCH_32, GPR_ARCH_64
 #endif
 
-#if defined(GPR_CPU_LINUX) + defined(GPR_CPU_POSIX) + defined(GPR_WIN32) + defined(GPR_CPU_IPHONE) != 1
-#error Must define exactly one of GPR_CPU_LINUX, GPR_CPU_POSIX, GPR_WIN32, GPR_CPU_IPHONE
+#if defined(GPR_CPU_LINUX) + defined(GPR_CPU_POSIX) + defined(GPR_WIN32) + defined(GPR_CPU_IPHONE) + defined(GPR_CPU_CUSTOM) != 1
+#error Must define exactly one of GPR_CPU_LINUX, GPR_CPU_POSIX, GPR_WIN32, GPR_CPU_IPHONE, GPR_CPU_CUSTOM
 #endif
 
 #if defined(GPR_POSIX_MULTIPOLL_WITH_POLL) && !defined(GPR_POSIX_SOCKET)
 #error Must define GPR_POSIX_SOCKET to use GPR_POSIX_MULTIPOLL_WITH_POLL
 #endif
 
-#if defined(GPR_POSIX_SOCKET) + defined(GPR_WIN32) != 1
-#error Must define exactly one of GPR_POSIX_SOCKET, GPR_WIN32
+#if defined(GPR_POSIX_SOCKET) + defined(GPR_WINSOCK_SOCKET) + defined(GPR_CUSTOM_SOCKET) != 1
+#error Must define exactly one of GPR_POSIX_SOCKET, GPR_WINSOCK_SOCKET, GPR_CUSTOM_SOCKET
+#endif
+
+#if defined(GPR_MSVC_TLS) + defined(GPR_GCC_TLS) + defined(GPR_PTHREAD_TLS) + defined(GPR_CUSTOM_TLS) != 1
+#error Must define exactly one of GPR_MSVC_TLS, GPR_GCC_TLS, GPR_PTHREAD_TLS, defined(GPR_CUSTOM_TLS)
 #endif
 
 typedef int16_t gpr_int16;
diff --git a/include/grpc/support/slice_buffer.h b/include/grpc/support/slice_buffer.h
index c7e5dbc64708449c0a3ef0c17ab2d8562b1c957e..1545dbfd76a8ba9c835704b8618228c60793bb99 100644
--- a/include/grpc/support/slice_buffer.h
+++ b/include/grpc/support/slice_buffer.h
@@ -40,6 +40,8 @@
 extern "C" {
 #endif
 
+#define GRPC_SLICE_BUFFER_INLINE_ELEMENTS 8
+
 /* Represents an expandable array of slices, to be interpreted as a single item
    TODO(ctiller): inline some small number of elements into the struct, to
                   avoid per-call allocations */
@@ -52,6 +54,8 @@ typedef struct {
   size_t capacity;
   /* the combined length of all slices in the array */
   size_t length;
+  /* inlined elements to avoid allocations */
+  gpr_slice inlined[GRPC_SLICE_BUFFER_INLINE_ELEMENTS];
 } gpr_slice_buffer;
 
 /* initialize a slice buffer */
@@ -78,9 +82,11 @@ gpr_uint8 *gpr_slice_buffer_tiny_add(gpr_slice_buffer *sb, unsigned len);
 void gpr_slice_buffer_pop(gpr_slice_buffer *sb);
 /* clear a slice buffer, unref all elements */
 void gpr_slice_buffer_reset_and_unref(gpr_slice_buffer *sb);
+/* swap the contents of two slice buffers */
+void gpr_slice_buffer_swap(gpr_slice_buffer *a, gpr_slice_buffer *b);
 
 #ifdef __cplusplus
 }
 #endif
 
-#endif  /* GRPC_SUPPORT_SLICE_BUFFER_H */
+#endif /* GRPC_SUPPORT_SLICE_BUFFER_H */
diff --git a/include/grpc/support/sync.h b/include/grpc/support/sync.h
index 35b2d12e77486f77bd3369819afb4d6f204487f5..1cdde1d2d04656c816769e724392381f9ac5fab2 100644
--- a/include/grpc/support/sync.h
+++ b/include/grpc/support/sync.h
@@ -60,7 +60,7 @@
 #include <grpc/support/sync_posix.h>
 #elif defined(GPR_WIN32)
 #include <grpc/support/sync_win32.h>
-#else
+#elif !defined(GPR_CUSTOM_SYNC)
 #error Unable to determine platform for sync
 #endif
 
diff --git a/include/grpc/support/tls.h b/include/grpc/support/tls.h
new file mode 100644
index 0000000000000000000000000000000000000000..1077fdec295f70003ebe27bbf80e8ef9eb42240b
--- /dev/null
+++ b/include/grpc/support/tls.h
@@ -0,0 +1,77 @@
+/*
+ *
+ * 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_SUPPORT_TLS_H
+#define GRPC_SUPPORT_TLS_H
+
+#include "port_platform.h"
+
+/* Thread local storage.
+
+   A minimal wrapper that should be implementable across many compilers,
+   and implementable efficiently across most modern compilers.
+
+   Thread locals have type gpr_intptr.
+
+   Declaring a thread local variable 'foo':
+     GPR_TLS_DECL(foo, initial_value);
+   Thread locals always have static scope.
+
+   Initializing a thread local (must be done at library initialization 
+   time):
+     gpr_tls_init(&foo);
+
+   Destroying a thread local:
+     gpr_tls_destroy(&foo);
+
+   Setting a thread local:
+     gpr_tls_set(&foo, new_value);
+
+   Accessing a thread local:
+     current_value = gpr_tls_get(&foo, value); 
+
+   ALL functions here may be implemented as macros. */
+
+#ifdef GPR_GCC_TLS
+#include "tls_gcc.h"
+#endif
+
+#ifdef GPR_MSVC_TLS
+#include "tls_msvc.h"
+#endif
+
+#ifdef GPR_PTHREAD_TLS
+#include "tls_pthread.h"
+#endif
+
+#endif
diff --git a/include/grpc/support/tls_gcc.h b/include/grpc/support/tls_gcc.h
new file mode 100644
index 0000000000000000000000000000000000000000..a078b104ea9594bfe683a80d9f2643ab6012d98d
--- /dev/null
+++ b/include/grpc/support/tls_gcc.h
@@ -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.
+ *
+ */
+
+#ifndef GRPC_SUPPORT_TLS_GCC_H
+#define GRPC_SUPPORT_TLS_GCC_H
+
+/* Thread local storage based on gcc compiler primitives.
+   #include tls.h to use this - and see that file for documentation */
+
+struct gpr_gcc_thread_local {
+  gpr_intptr value;
+};
+
+#define GPR_TLS_DECL(name) \
+    static __thread struct gpr_gcc_thread_local name = {0}
+
+#define gpr_tls_init(tls) do {} while (0)
+#define gpr_tls_destroy(tls) do {} while (0)
+#define gpr_tls_set(tls, new_value) (((tls)->value) = (new_value))
+#define gpr_tls_get(tls) ((tls)->value)
+
+#endif
diff --git a/include/grpc/support/tls_msvc.h b/include/grpc/support/tls_msvc.h
new file mode 100644
index 0000000000000000000000000000000000000000..e574c118844798583e9c77a09f72a6e00c905bf9
--- /dev/null
+++ b/include/grpc/support/tls_msvc.h
@@ -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.
+ *
+ */
+
+#ifndef GRPC_SUPPORT_TLS_GCC_H
+#define GRPC_SUPPORT_TLS_GCC_H
+
+/* Thread local storage based on ms visual c compiler primitives.
+   #include tls.h to use this - and see that file for documentation */
+
+struct gpr_msvc_thread_local {
+  gpr_intptr value;
+};
+
+#define GPR_TLS_DECL(name) \
+    static __thread struct gpr_msvc_thread_local name = {0}
+
+#define gpr_tls_init(tls) do {} while (0)
+#define gpr_tls_destroy(tls) do {} while (0)
+#define gpr_tls_set(tls, new_value) (((tls)->value) = (new_value))
+#define gpr_tls_get(tls) ((tls)->value)
+
+#endif
diff --git a/include/grpc/support/tls_pthread.h b/include/grpc/support/tls_pthread.h
new file mode 100644
index 0000000000000000000000000000000000000000..249c4d1cab673cc549022c00d345d0f15bbfc34c
--- /dev/null
+++ b/include/grpc/support/tls_pthread.h
@@ -0,0 +1,53 @@
+/*
+ *
+ * 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_SUPPORT_TLS_PTHREAD_H
+#define GRPC_SUPPORT_TLS_PTHREAD_H
+
+/* Thread local storage based on pthread library calls.
+   #include tls.h to use this - and see that file for documentation */
+
+struct gpr_pthread_thread_local {
+  pthread_key_t key;
+};
+
+#define GPR_TLS_DECL(name) \
+    static struct gpr_pthread_thread_local name = {0}
+
+#define gpr_tls_init(tls) GPR_ASSERT(0 == pthread_key_create(&(tls)->key, NULL))
+#define gpr_tls_destroy(tls) pthread_key_delete((tls)->key)
+#define gpr_tls_set(tls, new_value) \
+    GPR_ASSERT(pthread_setspecific((tls)->key, (void*)(new_value)) == 0)
+#define gpr_tls_get(tls) ((gpr_intptr)pthread_getspecific((tls)->key))
+
+#endif
diff --git a/src/compiler/cpp_generator.cc b/src/compiler/cpp_generator.cc
index c78f0333d899314f03bf71291792d61483f12039..bd8bf65349ab8677699dc6c644cfa9dd4c5eca77 100644
--- a/src/compiler/cpp_generator.cc
+++ b/src/compiler/cpp_generator.cc
@@ -198,17 +198,18 @@ grpc::string GetHeaderIncludes(const grpc::protobuf::FileDescriptor *file,
 
   temp.append("\n");
 
-  std::vector<grpc::string> parts =
-    grpc_generator::tokenize(file->package(), ".");
+  if (!file->package().empty()) {
+    std::vector<grpc::string> parts =
+        grpc_generator::tokenize(file->package(), ".");
 
-  for (auto part = parts.begin(); part != parts.end(); part++) {
-    temp.append("namespace ");
-    temp.append(*part);
-    temp.append(" {\n");
+    for (auto part = parts.begin(); part != parts.end(); part++) {
+      temp.append("namespace ");
+      temp.append(*part);
+      temp.append(" {\n");
+    }
+    temp.append("\n");
   }
 
-  temp.append("\n");
-
   return temp;
 }
 
@@ -431,15 +432,18 @@ grpc::string GetHeaderEpilogue(const grpc::protobuf::FileDescriptor *file,
   vars["filename"] = file->name();
   vars["filename_identifier"] = FilenameIdentifier(file->name());
 
-  std::vector<grpc::string> parts =
-    grpc_generator::tokenize(file->package(), ".");
+  if (!file->package().empty()) {
+    std::vector<grpc::string> parts =
+        grpc_generator::tokenize(file->package(), ".");
 
-  for (auto part = parts.rbegin(); part != parts.rend(); part++) {
-    vars["part"] = *part;
-    printer.Print(vars, "}  // namespace $part$\n");
+    for (auto part = parts.rbegin(); part != parts.rend(); part++) {
+      vars["part"] = *part;
+      printer.Print(vars, "}  // namespace $part$\n");
+    }
+    printer.Print(vars, "\n");
   }
 
-  printer.Print(vars, "\n\n");
+  printer.Print(vars, "\n");
   printer.Print(vars, "#endif  // GRPC_$filename_identifier$__INCLUDED\n");
 
   return output;
@@ -480,12 +484,14 @@ grpc::string GetSourceIncludes(const grpc::protobuf::FileDescriptor *file,
   printer.Print(vars, "#include <grpc++/impl/service_type.h>\n");
   printer.Print(vars, "#include <grpc++/stream.h>\n");
 
-  std::vector<grpc::string> parts =
-    grpc_generator::tokenize(file->package(), ".");
+  if (!file->package().empty()) {
+    std::vector<grpc::string> parts =
+        grpc_generator::tokenize(file->package(), ".");
 
-  for (auto part = parts.begin(); part != parts.end(); part++) {
-    vars["part"] = *part;
-    printer.Print(vars, "namespace $part$ {\n");
+    for (auto part = parts.begin(); part != parts.end(); part++) {
+      vars["part"] = *part;
+      printer.Print(vars, "namespace $part$ {\n");
+    }
   }
 
   printer.Print(vars, "\n");
@@ -860,17 +866,18 @@ grpc::string GetSourceEpilogue(const grpc::protobuf::FileDescriptor *file,
                                const Parameters &params) {
   grpc::string temp;
 
-  std::vector<grpc::string> parts =
-    grpc_generator::tokenize(file->package(), ".");
+  if (!file->package().empty()) {
+    std::vector<grpc::string> parts =
+        grpc_generator::tokenize(file->package(), ".");
 
-  for (auto part = parts.begin(); part != parts.end(); part++) {
-    temp.append("}  // namespace ");
-    temp.append(*part);
+    for (auto part = parts.begin(); part != parts.end(); part++) {
+      temp.append("}  // namespace ");
+      temp.append(*part);
+      temp.append("\n");
+    }
     temp.append("\n");
   }
 
-  temp.append("\n");
-
   return temp;
 }
 
diff --git a/src/core/iomgr/endpoint_pair_windows.c b/src/core/iomgr/endpoint_pair_windows.c
new file mode 100644
index 0000000000000000000000000000000000000000..d78b6ea957e35b0441a014e62ca9f716b6cd522c
--- /dev/null
+++ b/src/core/iomgr/endpoint_pair_windows.c
@@ -0,0 +1,85 @@
+/*
+ *
+ * Copyright 2015, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <grpc/support/port_platform.h>
+
+#ifdef GPR_WINSOCK_SOCKET
+#include "src/core/iomgr/sockaddr_utils.h"
+#include "src/core/iomgr/endpoint_pair.h"
+
+#include <errno.h>
+#include <fcntl.h>
+#include <string.h>
+
+#include "src/core/iomgr/tcp_windows.h"
+#include "src/core/iomgr/socket_windows.h"
+#include <grpc/support/log.h>
+
+static void create_sockets(SOCKET sv[2]) {
+  SOCKET svr_sock = INVALID_SOCKET;
+  SOCKET lst_sock = INVALID_SOCKET;
+  SOCKET cli_sock = INVALID_SOCKET;
+  SOCKADDR_IN addr;
+  int addr_len;
+
+  lst_sock = WSASocket(AF_INET, SOCK_STREAM, IPPROTO_TCP, NULL, 0, WSA_FLAG_OVERLAPPED);
+  GPR_ASSERT(lst_sock != INVALID_SOCKET);
+
+  memset(&addr, 0, sizeof(addr));
+  GPR_ASSERT(bind(lst_sock, (struct sockaddr*)&addr, sizeof(addr)) != SOCKET_ERROR);
+  GPR_ASSERT(listen(lst_sock, SOMAXCONN) != SOCKET_ERROR);
+  GPR_ASSERT(getsockname(lst_sock, (struct sockaddr*)&addr, &addr_len) != SOCKET_ERROR);
+
+  cli_sock = WSASocket(AF_INET, SOCK_STREAM, IPPROTO_TCP, NULL, 0, WSA_FLAG_OVERLAPPED);
+  GPR_ASSERT(cli_sock != INVALID_SOCKET);
+
+  GPR_ASSERT(WSAConnect(cli_sock, (struct sockaddr*)&addr, addr_len, NULL, NULL, NULL, NULL) == 0);
+  svr_sock = accept(lst_sock, (struct sockaddr*)&addr, &addr_len);
+  GPR_ASSERT(svr_sock != INVALID_SOCKET);
+
+  closesocket(lst_sock);
+
+  sv[1] = cli_sock;
+  sv[0] = svr_sock;
+}
+
+grpc_endpoint_pair grpc_iomgr_create_endpoint_pair(size_t read_slice_size) {
+  SOCKET sv[2];
+  grpc_endpoint_pair p;
+  create_sockets(sv);
+  p.client = grpc_tcp_create(grpc_winsocket_create(sv[1]));
+  p.server = grpc_tcp_create(grpc_winsocket_create(sv[0]));
+  return p;
+}
+
+#endif
diff --git a/src/core/iomgr/pollset_multipoller_with_poll_posix.c b/src/core/iomgr/pollset_multipoller_with_poll_posix.c
index 7570ff18c59d0822b1ba76cebb8cdb330a186336..bcef7c35b5da8dd04bf83e40be8e9ad671203f0b 100644
--- a/src/core/iomgr/pollset_multipoller_with_poll_posix.c
+++ b/src/core/iomgr/pollset_multipoller_with_poll_posix.c
@@ -172,6 +172,9 @@ static int multipoll_with_poll_pollset_maybe_work(
   }
 
   r = poll(h->pfds, h->pfd_count, timeout);
+
+  end_polling(pollset);
+
   if (r < 0) {
     if (errno != EINTR) {
       gpr_log(GPR_ERROR, "poll() failed: %s", strerror(errno));
@@ -192,7 +195,6 @@ static int multipoll_with_poll_pollset_maybe_work(
     }
   }
   grpc_pollset_kick_post_poll(&pollset->kick_state);
-  end_polling(pollset);
 
   gpr_mu_lock(&pollset->mu);
   pollset->counter = 0;
diff --git a/src/core/iomgr/pollset_posix.c b/src/core/iomgr/pollset_posix.c
index 0bb722e2b12c44748d089f68e66cd200c522f2f0..03fd94f136424c0091b2ee19d7063b168825b524 100644
--- a/src/core/iomgr/pollset_posix.c
+++ b/src/core/iomgr/pollset_posix.c
@@ -396,6 +396,9 @@ static int unary_poll_pollset_maybe_work(grpc_pollset *pollset,
   pfd[1].events = grpc_fd_begin_poll(fd, pollset, POLLIN, POLLOUT, &fd_watcher);
 
   r = poll(pfd, GPR_ARRAY_SIZE(pfd), timeout);
+
+  grpc_fd_end_poll(&fd_watcher);
+
   if (r < 0) {
     if (errno != EINTR) {
       gpr_log(GPR_ERROR, "poll() failed: %s", strerror(errno));
@@ -415,7 +418,6 @@ static int unary_poll_pollset_maybe_work(grpc_pollset *pollset,
   }
 
   grpc_pollset_kick_post_poll(&pollset->kick_state);
-  grpc_fd_end_poll(&fd_watcher);
 
   gpr_mu_lock(&pollset->mu);
   pollset->counter = 0;
diff --git a/src/core/iomgr/tcp_server_posix.c b/src/core/iomgr/tcp_server_posix.c
index 895f85fc68273e7ac6a9d9697da948138f007299..7e31f2d7a54b633c03e70d57f409080176d29f9f 100644
--- a/src/core/iomgr/tcp_server_posix.c
+++ b/src/core/iomgr/tcp_server_posix.c
@@ -174,7 +174,6 @@ void grpc_tcp_server_destroy(
   while (s->active_ports) {
     gpr_cv_wait(&s->cv, &s->mu, gpr_inf_future);
   }
-  gpr_mu_unlock(&s->mu);
 
   /* delete ALL the things */
   if (s->nports) {
@@ -185,7 +184,9 @@ void grpc_tcp_server_destroy(
       }
       grpc_fd_orphan(sp->emfd, destroyed_port, s);
     }
+    gpr_mu_unlock(&s->mu);
   } else {
+    gpr_mu_unlock(&s->mu);
     finish_shutdown(s);
   }
 }
diff --git a/src/core/security/factories.c b/src/core/security/factories.c
index 02267d55457c5f0563dd5b2a3275721a761352b6..3d9216aac405a82fce5cf48d168a1ad9addc3417 100644
--- a/src/core/security/factories.c
+++ b/src/core/security/factories.c
@@ -50,3 +50,19 @@ grpc_channel *grpc_secure_channel_create(grpc_credentials *creds,
   return grpc_secure_channel_create_with_factories(
       factories, GPR_ARRAY_SIZE(factories), creds, target, args);
 }
+
+grpc_security_status grpc_server_security_context_create(
+    grpc_server_credentials *creds, grpc_security_context **ctx) {
+  grpc_security_status status = GRPC_SECURITY_ERROR;
+
+  *ctx = NULL;
+  if (strcmp(creds->type, GRPC_CREDENTIALS_TYPE_SSL) == 0) {
+    status = grpc_ssl_server_security_context_create(
+        grpc_ssl_server_credentials_get_config(creds), ctx);
+  } else if (strcmp(creds->type,
+                    GRPC_CREDENTIALS_TYPE_FAKE_TRANSPORT_SECURITY) == 0) {
+    *ctx = grpc_fake_server_security_context_create();
+    status = GRPC_SECURITY_OK;
+  }
+  return status;
+}
diff --git a/src/core/security/security_context.h b/src/core/security/security_context.h
index 0b5821c3c08bd2b939f16f5920e10d4294390cd5..2b4e38f3ea689411322889aee4224a9253737833 100644
--- a/src/core/security/security_context.h
+++ b/src/core/security/security_context.h
@@ -206,10 +206,9 @@ grpc_channel *grpc_secure_channel_create_with_factories(
     const grpc_secure_channel_factory *factories, size_t num_factories,
     grpc_credentials *creds, const char *target, const grpc_channel_args *args);
 
-/* Secure server creation. */
+/* Secure server context creation. */
 
-grpc_server *grpc_secure_server_create_internal(grpc_completion_queue *cq,
-                                                const grpc_channel_args *args,
-                                                grpc_security_context *ctx);
+grpc_security_status grpc_server_security_context_create(
+    grpc_server_credentials *creds, grpc_security_context **ctx);
 
 #endif  /* GRPC_INTERNAL_CORE_SECURITY_SECURITY_CONTEXT_H */
diff --git a/src/core/security/server_secure_chttp2.c b/src/core/security/server_secure_chttp2.c
index 081272724cf32901de18a0a4f4dcdae96863ad5b..165ed5474fe930154a0ccae871b34e793615cd22 100644
--- a/src/core/security/server_secure_chttp2.c
+++ b/src/core/security/server_secure_chttp2.c
@@ -141,16 +141,7 @@ int grpc_server_add_secure_http2_port(grpc_server *server, const char *addr,
 
   /* create security context */
   if (creds == NULL) goto error;
-
-  if (strcmp(creds->type, GRPC_CREDENTIALS_TYPE_SSL) == 0) {
-    status = grpc_ssl_server_security_context_create(
-        grpc_ssl_server_credentials_get_config(creds), &ctx);
-  } else if (strcmp(creds->type,
-                    GRPC_CREDENTIALS_TYPE_FAKE_TRANSPORT_SECURITY) == 0) {
-    ctx = grpc_fake_server_security_context_create();
-    status = GRPC_SECURITY_OK;
-  }
-
+  status = grpc_server_security_context_create(creds, &ctx);
   if (status != GRPC_SECURITY_OK) {
     gpr_log(GPR_ERROR,
             "Unable to create secure server with credentials of type %s.",
diff --git a/src/core/support/slice_buffer.c b/src/core/support/slice_buffer.c
index b280e4bd020014b26f08de866fa75a2ddb460566..3b1daa07c54e5b4baf50aba04e382cb4636b4216 100644
--- a/src/core/support/slice_buffer.c
+++ b/src/core/support/slice_buffer.c
@@ -38,21 +38,34 @@
 #include <grpc/support/alloc.h>
 #include <grpc/support/log.h>
 
-/* initial allocation size (# of slices) */
-#define INITIAL_CAPACITY 4
-/* grow a buffer; requires INITIAL_CAPACITY > 1 */
+/* grow a buffer; requires GRPC_SLICE_BUFFER_INLINE_ELEMENTS > 1 */
 #define GROW(x) (3 * (x) / 2)
 
+static void maybe_embiggen(gpr_slice_buffer *sb) {
+  if (sb->count == sb->capacity) {
+    sb->capacity = GROW(sb->capacity);
+    GPR_ASSERT(sb->capacity > sb->count);
+    if (sb->slices == sb->inlined) {
+      sb->slices = gpr_malloc(sb->capacity * sizeof(gpr_slice));
+      memcpy(sb->slices, sb->inlined, sb->count * sizeof(gpr_slice));
+    } else {
+      sb->slices = gpr_realloc(sb->slices, sb->capacity * sizeof(gpr_slice));
+    }
+  }
+}
+
 void gpr_slice_buffer_init(gpr_slice_buffer *sb) {
   sb->count = 0;
   sb->length = 0;
-  sb->capacity = INITIAL_CAPACITY;
-  sb->slices = gpr_malloc(sizeof(gpr_slice) * INITIAL_CAPACITY);
+  sb->capacity = GRPC_SLICE_BUFFER_INLINE_ELEMENTS;
+  sb->slices = sb->inlined;
 }
 
 void gpr_slice_buffer_destroy(gpr_slice_buffer *sb) {
   gpr_slice_buffer_reset_and_unref(sb);
-  gpr_free(sb->slices);
+  if (sb->slices != sb->inlined) {
+    gpr_free(sb->slices);
+  }
 }
 
 gpr_uint8 *gpr_slice_buffer_tiny_add(gpr_slice_buffer *sb, unsigned n) {
@@ -71,11 +84,7 @@ gpr_uint8 *gpr_slice_buffer_tiny_add(gpr_slice_buffer *sb, unsigned n) {
   return out;
 
 add_new:
-  if (sb->count == sb->capacity) {
-    sb->capacity = GROW(sb->capacity);
-    GPR_ASSERT(sb->capacity > sb->count);
-    sb->slices = gpr_realloc(sb->slices, sb->capacity * sizeof(gpr_slice));
-  }
+  maybe_embiggen(sb);
   back = &sb->slices[sb->count];
   sb->count++;
   back->refcount = NULL;
@@ -85,11 +94,7 @@ add_new:
 
 size_t gpr_slice_buffer_add_indexed(gpr_slice_buffer *sb, gpr_slice s) {
   size_t out = sb->count;
-  if (out == sb->capacity) {
-    sb->capacity = GROW(sb->capacity);
-    GPR_ASSERT(sb->capacity > sb->count);
-    sb->slices = gpr_realloc(sb->slices, sb->capacity * sizeof(gpr_slice));
-  }
+  maybe_embiggen(sb);
   sb->slices[out] = s;
   sb->length += GPR_SLICE_LENGTH(s);
   sb->count = out + 1;
@@ -116,12 +121,7 @@ void gpr_slice_buffer_add(gpr_slice_buffer *sb, gpr_slice s) {
         memcpy(back->data.inlined.bytes + back->data.inlined.length,
                s.data.inlined.bytes, cp1);
         back->data.inlined.length = GPR_SLICE_INLINED_SIZE;
-        if (n == sb->capacity) {
-          sb->capacity = GROW(sb->capacity);
-          GPR_ASSERT(sb->capacity > sb->count);
-          sb->slices =
-              gpr_realloc(sb->slices, sb->capacity * sizeof(gpr_slice));
-        }
+        maybe_embiggen(sb);
         back = &sb->slices[n];
         sb->count = n + 1;
         back->refcount = NULL;
@@ -160,3 +160,16 @@ void gpr_slice_buffer_reset_and_unref(gpr_slice_buffer *sb) {
   sb->count = 0;
   sb->length = 0;
 }
+
+void gpr_slice_buffer_swap(gpr_slice_buffer *a, gpr_slice_buffer *b) {
+  gpr_slice_buffer temp = *a;
+  *a = *b;
+  *b = temp;
+
+  if (a->slices == b->inlined) {
+    a->slices = a->inlined;
+  }
+  if (b->slices == a->inlined) {
+    b->slices = b->inlined;
+  }
+}
diff --git a/src/core/support/time_win32.c b/src/core/support/time_win32.c
index f221cb579033b4c95f61cd13e378c386873787f7..539470bccfe073da448a9649f74a251a650b10a3 100644
--- a/src/core/support/time_win32.c
+++ b/src/core/support/time_win32.c
@@ -39,6 +39,7 @@
 
 #include <grpc/support/time.h>
 #include <sys/timeb.h>
+#include <windows.h>
 
 gpr_timespec gpr_now(void) {
   gpr_timespec now_tv;
@@ -49,4 +50,23 @@ gpr_timespec gpr_now(void) {
   return now_tv;
 }
 
+void gpr_sleep_until(gpr_timespec until) {
+  gpr_timespec now;
+  gpr_timespec delta;
+  DWORD sleep_millis;
+
+  for (;;) {
+    /* We could simplify by using clock_nanosleep instead, but it might be
+     * slightly less portable. */
+    now = gpr_now();
+    if (gpr_time_cmp(until, now) <= 0) {
+      return;
+    }
+
+    delta = gpr_time_sub(until, now);
+    sleep_millis = delta.tv_sec * GPR_MS_PER_SEC + delta.tv_nsec / GPR_NS_PER_MS;
+    Sleep(sleep_millis);
+  }
+}
+
 #endif /* GPR_WIN32 */
diff --git a/src/core/transport/chttp2_transport.c b/src/core/transport/chttp2_transport.c
index 4c0394d46faccf7bd81a2790cda7f0d539c40e10..110a4b544f367613d549236b806ac8edac1c237d 100644
--- a/src/core/transport/chttp2_transport.c
+++ b/src/core/transport/chttp2_transport.c
@@ -834,13 +834,10 @@ static void push_setting(transport *t, grpc_chttp2_setting_id id,
 
 static int prepare_write(transport *t) {
   stream *s;
-  gpr_slice_buffer tempbuf;
   gpr_uint32 window_delta;
 
   /* simple writes are queued to qbuf, and flushed here */
-  tempbuf = t->qbuf;
-  t->qbuf = t->outbuf;
-  t->outbuf = tempbuf;
+  gpr_slice_buffer_swap(&t->qbuf, &t->outbuf);
   GPR_ASSERT(t->qbuf.count == 0);
 
   if (t->dirtied_local_settings && !t->sent_local_settings) {
diff --git a/src/cpp/client/secure_credentials.cc b/src/cpp/client/secure_credentials.cc
index d6f9acc675563c25db05d9543ead6535af615e54..0a73b2c0f676b9154239d784ac156a28f466a941 100644
--- a/src/cpp/client/secure_credentials.cc
+++ b/src/cpp/client/secure_credentials.cc
@@ -31,38 +31,23 @@
  *
  */
 
-#include <grpc/grpc_security.h>
 #include <grpc/support/log.h>
 
 #include <grpc++/channel_arguments.h>
-#include <grpc++/config.h>
-#include <grpc++/credentials.h>
 #include "src/cpp/client/channel.h"
+#include "src/cpp/client/secure_credentials.h"
 
 namespace grpc {
 
-class SecureCredentials GRPC_FINAL : public Credentials {
- public:
-  explicit SecureCredentials(grpc_credentials* c_creds) : c_creds_(c_creds) {}
-  ~SecureCredentials() GRPC_OVERRIDE { grpc_credentials_release(c_creds_); }
-  grpc_credentials* GetRawCreds() { return c_creds_; }
-
-  std::shared_ptr<grpc::ChannelInterface> CreateChannel(
-      const string& target, const grpc::ChannelArguments& args) GRPC_OVERRIDE {
-    grpc_channel_args channel_args;
-    args.SetChannelArgs(&channel_args);
-    return std::shared_ptr<ChannelInterface>(new Channel(
-        args.GetSslTargetNameOverride().empty()
-            ? target
-            : args.GetSslTargetNameOverride(),
-        grpc_secure_channel_create(c_creds_, target.c_str(), &channel_args)));
-  }
-
-  SecureCredentials* AsSecureCredentials() GRPC_OVERRIDE { return this; }
-
- private:
-  grpc_credentials* const c_creds_;
-};
+std::shared_ptr<grpc::ChannelInterface> SecureCredentials::CreateChannel(
+    const string& target, const grpc::ChannelArguments& args) {
+  grpc_channel_args channel_args;
+  args.SetChannelArgs(&channel_args);
+  return std::shared_ptr<ChannelInterface>(new Channel(
+      args.GetSslTargetNameOverride().empty() ? target
+                                              : args.GetSslTargetNameOverride(),
+      grpc_secure_channel_create(c_creds_, target.c_str(), &channel_args)));
+}
 
 namespace {
 std::unique_ptr<Credentials> WrapCredentials(grpc_credentials* creds) {
diff --git a/src/cpp/client/secure_credentials.h b/src/cpp/client/secure_credentials.h
new file mode 100644
index 0000000000000000000000000000000000000000..77d575813eae2968b6139862a385d0aaf1d0b71d
--- /dev/null
+++ b/src/cpp/client/secure_credentials.h
@@ -0,0 +1,61 @@
+/*
+ *
+ * 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_CPP_CLIENT_SECURE_CREDENTIALS_H
+#define GRPC_INTERNAL_CPP_CLIENT_SECURE_CREDENTIALS_H
+
+#include <grpc/grpc_security.h>
+
+#include <grpc++/config.h>
+#include <grpc++/credentials.h>
+
+namespace grpc {
+
+class SecureCredentials GRPC_FINAL : public Credentials {
+ public:
+  explicit SecureCredentials(grpc_credentials* c_creds) : c_creds_(c_creds) {}
+  ~SecureCredentials() GRPC_OVERRIDE { grpc_credentials_release(c_creds_); }
+  grpc_credentials* GetRawCreds() { return c_creds_; }
+
+  std::shared_ptr<grpc::ChannelInterface> CreateChannel(
+      const string& target, const grpc::ChannelArguments& args) GRPC_OVERRIDE;
+  SecureCredentials* AsSecureCredentials() GRPC_OVERRIDE { return this; }
+
+ private:
+  grpc_credentials* const c_creds_;
+};
+
+}  // namespace grpc
+
+#endif  // GRPC_INTERNAL_CPP_CLIENT_SECURE_CREDENTIALS_H
+
diff --git a/src/cpp/server/secure_server_credentials.cc b/src/cpp/server/secure_server_credentials.cc
index 49d69a3fb9a45e7463b8e2744d4d0c275e6d6f4b..3e262dd74f79b1e07ebf0568033785bf702975a4 100644
--- a/src/cpp/server/secure_server_credentials.cc
+++ b/src/cpp/server/secure_server_credentials.cc
@@ -31,39 +31,22 @@
  *
  */
 
-#include <grpc/grpc_security.h>
-
-#include <grpc++/server_credentials.h>
+#include "src/cpp/server/secure_server_credentials.h"
 
 namespace grpc {
 
-namespace {
-class SecureServerCredentials GRPC_FINAL : public ServerCredentials {
- public:
-  explicit SecureServerCredentials(grpc_server_credentials* creds)
-      : creds_(creds) {}
-  ~SecureServerCredentials() GRPC_OVERRIDE {
-    grpc_server_credentials_release(creds_);
-  }
-
-  int AddPortToServer(const grpc::string& addr,
-                      grpc_server* server) GRPC_OVERRIDE {
-    return grpc_server_add_secure_http2_port(server, addr.c_str(), creds_);
-  }
-
- private:
-  grpc_server_credentials* const creds_;
-};
-}  // namespace
+int SecureServerCredentials::AddPortToServer(
+    const grpc::string& addr, grpc_server* server) {
+  return grpc_server_add_secure_http2_port(server, addr.c_str(), creds_);
+}
 
 std::shared_ptr<ServerCredentials> SslServerCredentials(
     const SslServerCredentialsOptions& options) {
   std::vector<grpc_ssl_pem_key_cert_pair> pem_key_cert_pairs;
   for (auto key_cert_pair = options.pem_key_cert_pairs.begin();
-       key_cert_pair != options.pem_key_cert_pairs.end();
-       key_cert_pair++) {
+       key_cert_pair != options.pem_key_cert_pairs.end(); key_cert_pair++) {
     grpc_ssl_pem_key_cert_pair p = {key_cert_pair->private_key.c_str(),
-				    key_cert_pair->cert_chain.c_str()};
+                                    key_cert_pair->cert_chain.c_str()};
     pem_key_cert_pairs.push_back(p);
   }
   grpc_server_credentials* c_creds = grpc_ssl_server_credentials_create(
diff --git a/src/cpp/server/secure_server_credentials.h b/src/cpp/server/secure_server_credentials.h
new file mode 100644
index 0000000000000000000000000000000000000000..b9803f107e5d587774809d2b694ca5ed4f5b4402
--- /dev/null
+++ b/src/cpp/server/secure_server_credentials.h
@@ -0,0 +1,60 @@
+/*
+ *
+ * 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_CPP_SERVER_SECURE_SERVER_CREDENTIALS_H
+#define GRPC_INTERNAL_CPP_SERVER_SECURE_SERVER_CREDENTIALS_H
+
+#include <grpc/grpc_security.h>
+
+#include <grpc++/server_credentials.h>
+
+namespace grpc {
+
+class SecureServerCredentials GRPC_FINAL : public ServerCredentials {
+ public:
+  explicit SecureServerCredentials(grpc_server_credentials* creds)
+      : creds_(creds) {}
+  ~SecureServerCredentials() GRPC_OVERRIDE {
+    grpc_server_credentials_release(creds_);
+  }
+
+  int AddPortToServer(const grpc::string& addr,
+                      grpc_server* server) GRPC_OVERRIDE;
+
+ private:
+  grpc_server_credentials* const creds_;
+};
+
+}  // namespace grpc
+
+#endif  // GRPC_INTERNAL_CPP_SERVER_SECURE_SERVER_CREDENTIALS_H
diff --git a/src/node/examples/math_server.js b/src/node/examples/math_server.js
index ae548c89e402abe08bc8822339a07c5d5e958fc1..3fac193d6419c00da6acc25151c991dcdcda2da6 100644
--- a/src/node/examples/math_server.js
+++ b/src/node/examples/math_server.js
@@ -33,10 +33,6 @@
 
 'use strict';
 
-var util = require('util');
-
-var Transform = require('stream').Transform;
-
 var grpc = require('..');
 var math = grpc.load(__dirname + '/math.proto').math;
 
@@ -54,11 +50,12 @@ function mathDiv(call, cb) {
   // Unary + is explicit coersion to integer
   if (+req.divisor === 0) {
     cb(new Error('cannot divide by zero'));
+  } else {
+    cb(null, {
+      quotient: req.dividend / req.divisor,
+      remainder: req.dividend % req.divisor
+    });
   }
-  cb(null, {
-    quotient: req.dividend / req.divisor,
-    remainder: req.dividend % req.divisor
-  });
 }
 
 /**
@@ -97,24 +94,19 @@ function mathSum(call, cb) {
 }
 
 function mathDivMany(stream) {
-  // Here, call is a standard duplex Node object Stream
-  util.inherits(DivTransform, Transform);
-  function DivTransform() {
-    var options = {objectMode: true};
-    Transform.call(this, options);
-  }
-  DivTransform.prototype._transform = function(div_args, encoding, callback) {
+  stream.on('data', function(div_args) {
     if (+div_args.divisor === 0) {
-      callback(new Error('cannot divide by zero'));
+      stream.emit('error', new Error('cannot divide by zero'));
+    } else {
+      stream.write({
+        quotient: div_args.dividend / div_args.divisor,
+        remainder: div_args.dividend % div_args.divisor
+      });
     }
-    callback(null, {
-      quotient: div_args.dividend / div_args.divisor,
-      remainder: div_args.dividend % div_args.divisor
-    });
-  };
-  var transform = new DivTransform();
-  stream.pipe(transform);
-  transform.pipe(stream);
+  });
+  stream.on('end', function() {
+    stream.end();
+  });
 }
 
 var server = new Server({
diff --git a/src/node/package.json b/src/node/package.json
index 9f52f8c988ebe252284ccfba9484a68ffe1d08ff..fc3ca1f103cfcd602931e74a0faae8ad364a125e 100644
--- a/src/node/package.json
+++ b/src/node/package.json
@@ -1,6 +1,6 @@
 {
   "name": "grpc",
-  "version": "0.6.0",
+  "version": "0.6.1",
   "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 05de16294d4aedc2c3d7853b8ef55685be1626cb..eef705c44c6e97946b7b449bf344eca49a167de3 100644
--- a/src/node/src/server.js
+++ b/src/node/src/server.js
@@ -360,7 +360,9 @@ function handleUnary(call, handler, metadata) {
     }
     handler.func(emitter, function sendUnaryData(err, value, trailer) {
       if (err) {
-        err.metadata = trailer;
+        if (trailer) {
+          err.metadata = trailer;
+        }
         handleError(call, err);
       } else {
         sendUnaryResponse(call, value, handler.serialize, trailer);
@@ -406,7 +408,9 @@ function handleClientStreaming(call, handler, metadata) {
   handler.func(stream, function(err, value, trailer) {
     stream.terminate();
     if (err) {
-      err.metadata = trailer;
+      if (trailer) {
+        err.metadata = trailer;
+      }
       handleError(call, err);
     } else {
       sendUnaryResponse(call, value, handler.serialize, trailer);
diff --git a/src/node/test/math_client_test.js b/src/node/test/math_client_test.js
index d83f64116f71672b2ee23f3b32c1fc8df04e12d2..79df97871bf56172851f9647b3964dc250ea88e4 100644
--- a/src/node/test/math_client_test.js
+++ b/src/node/test/math_client_test.js
@@ -68,6 +68,13 @@ describe('Math client', function() {
       done();
     });
   });
+  it('should handle an error from a unary request', function(done) {
+    var arg = {dividend: 7, divisor: 0};
+    math_client.div(arg, function handleDivResult(err, value) {
+      assert(err);
+      done();
+    });
+  });
   it('should handle a server streaming request', function(done) {
     var call = math_client.fib({limit: 7});
     var expected_results = [1, 1, 2, 3, 5, 8, 13];
@@ -115,4 +122,17 @@ describe('Math client', function() {
       done();
     });
   });
+  it('should handle an error from a bidi request', function(done) {
+    var call = math_client.divMany();
+    call.on('data', function(value) {
+      assert.fail(value, undefined, 'Unexpected data response on failing call',
+                  '!=');
+    });
+    call.write({dividend: 7, divisor: 0});
+    call.end();
+    call.on('status', function checkStatus(status) {
+      assert.notEqual(status.code, grpc.status.OK);
+      done();
+    });
+  });
 });
diff --git a/src/python/interop/interop/client.py b/src/python/interop/interop/client.py
index bae5e1746048c8df82e8d5ec739d58a5eaa998bb..41f0d9453932ad994ff877c8d99822e173df5d8e 100644
--- a/src/python/interop/interop/client.py
+++ b/src/python/interop/interop/client.py
@@ -64,7 +64,7 @@ def _args():
   return parser.parse_args()
 
 def _oauth_access_token(args):
-  credentials = client.GoogleCredentials.get_application_default()
+  credentials = oauth2client_client.GoogleCredentials.get_application_default()
   scoped_credentials = credentials.create_scoped([args.oauth_scope])
   return scoped_credentials.get_access_token().access_token
 
diff --git a/src/python/interop/interop/methods.py b/src/python/interop/interop/methods.py
index c69771dff1ea594e83219549c03224b752f73176..909b738bd10ec4581c492bdc59a5e84b83947023 100644
--- a/src/python/interop/interop/methods.py
+++ b/src/python/interop/interop/methods.py
@@ -292,7 +292,7 @@ def _service_account_creds(stub, args):
   if wanted_email != response.username:
     raise ValueError(
         'expected username %s, got %s' % (wanted_email, response.username))
-  if response.oauth_scope in args.oauth_scope:
+  if args.oauth_scope.find(response.oauth_scope) == -1:
     raise ValueError(
         'expected to find oauth scope "%s" in received "%s"' %
             (response.oauth_scope, args.oauth_scope))
diff --git a/src/python/src/grpc/early_adopter/implementations.py b/src/python/src/grpc/early_adopter/implementations.py
index 35456d38c6bb071d4bd0c786e0136cfe7d8cbe5b..f3f2a043ebd6216edb44c70586507383667311ab 100644
--- a/src/python/src/grpc/early_adopter/implementations.py
+++ b/src/python/src/grpc/early_adopter/implementations.py
@@ -223,7 +223,8 @@ def stub(
   breakdown = _face_utilities.break_down_invocation(service_name, methods)
   return _Stub(
       breakdown, host, port, secure, root_certificates, private_key,
-      certificate_chain, server_host_override=server_host_override)
+      certificate_chain, server_host_override=server_host_override,
+      metadata_transformer=metadata_transformer)
 
 
 def server(
diff --git a/src/ruby/ext/grpc/rb_byte_buffer.c b/src/ruby/ext/grpc/rb_byte_buffer.c
index ff5a114de58048c78250f61a74f5d1533b63fac3..e3a5277f54420cdc082ba7392f10da74ccb2a501 100644
--- a/src/ruby/ext/grpc/rb_byte_buffer.c
+++ b/src/ruby/ext/grpc/rb_byte_buffer.c
@@ -39,203 +39,29 @@
 #include <grpc/support/slice.h>
 #include "rb_grpc.h"
 
-/* grpc_rb_byte_buffer wraps a grpc_byte_buffer.  It provides a peer ruby
- * object, 'mark' to minimize copying when a byte_buffer is created from
- * ruby. */
-typedef struct grpc_rb_byte_buffer {
-  /* Holder of ruby objects involved in constructing the status */
-  VALUE mark;
-  /* The actual status */
-  grpc_byte_buffer *wrapped;
-} grpc_rb_byte_buffer;
-
-/* Destroys ByteBuffer instances. */
-static void grpc_rb_byte_buffer_free(void *p) {
-  grpc_rb_byte_buffer *bb = NULL;
-  if (p == NULL) {
-    return;
-  };
-  bb = (grpc_rb_byte_buffer *)p;
-
-  /* Deletes the wrapped object if the mark object is Qnil, which indicates
-   * that no other object is the actual owner. */
-  if (bb->wrapped != NULL && bb->mark == Qnil) {
-    grpc_byte_buffer_destroy(bb->wrapped);
-  }
-
-  xfree(p);
-}
-
-/* Protects the mark object from GC */
-static void grpc_rb_byte_buffer_mark(void *p) {
-  grpc_rb_byte_buffer *bb = NULL;
-  if (p == NULL) {
-    return;
-  }
-  bb = (grpc_rb_byte_buffer *)p;
-
-  /* If it's not already cleaned up, mark the mark object */
-  if (bb->mark != Qnil && BUILTIN_TYPE(bb->mark) != T_NONE) {
-    rb_gc_mark(bb->mark);
-  }
+grpc_byte_buffer* grpc_rb_s_to_byte_buffer(char *string, size_t length) {
+  gpr_slice slice = gpr_slice_from_copied_buffer(string, length);
+  grpc_byte_buffer *buffer = grpc_byte_buffer_create(&slice, 1);
+  gpr_slice_unref(slice);
+  return buffer;
 }
 
-/* id_source is the name of the hidden ivar the preserves the original
- * byte_buffer source string */
-static ID id_source;
-
-/* Allocates ByteBuffer instances.
-
-   Provides safe default values for the byte_buffer fields. */
-static VALUE grpc_rb_byte_buffer_alloc(VALUE cls) {
-  grpc_rb_byte_buffer *wrapper = ALLOC(grpc_rb_byte_buffer);
-  wrapper->wrapped = NULL;
-  wrapper->mark = Qnil;
-  return Data_Wrap_Struct(cls, grpc_rb_byte_buffer_mark,
-                          grpc_rb_byte_buffer_free, wrapper);
-}
-
-/* Clones ByteBuffer instances.
-
-   Gives ByteBuffer a consistent implementation of Ruby's object copy/dup
-   protocol. */
-static VALUE grpc_rb_byte_buffer_init_copy(VALUE copy, VALUE orig) {
-  grpc_rb_byte_buffer *orig_bb = NULL;
-  grpc_rb_byte_buffer *copy_bb = NULL;
-
-  if (copy == orig) {
-    return copy;
-  }
-
-  /* Raise an error if orig is not a metadata object or a subclass. */
-  if (TYPE(orig) != T_DATA ||
-      RDATA(orig)->dfree != (RUBY_DATA_FUNC)grpc_rb_byte_buffer_free) {
-    rb_raise(rb_eTypeError, "not a %s", rb_obj_classname(rb_cByteBuffer));
-  }
-
-  Data_Get_Struct(orig, grpc_rb_byte_buffer, orig_bb);
-  Data_Get_Struct(copy, grpc_rb_byte_buffer, copy_bb);
-
-  /* use ruby's MEMCPY to make a byte-for-byte copy of the metadata wrapper
-   * object. */
-  MEMCPY(copy_bb, orig_bb, grpc_rb_byte_buffer, 1);
-  return copy;
-}
-
-/* id_empty is used to return the empty string from to_s when necessary. */
-static ID id_empty;
-
-static VALUE grpc_rb_byte_buffer_to_s(VALUE self) {
-  grpc_rb_byte_buffer *wrapper = NULL;
-  grpc_byte_buffer *bb = NULL;
-  grpc_byte_buffer_reader *reader = NULL;
-  char *output = NULL;
+VALUE grpc_rb_byte_buffer_to_s(grpc_byte_buffer *buffer) {
   size_t length = 0;
+  char *string = NULL;
   size_t offset = 0;
-  VALUE output_obj = Qnil;
+  grpc_byte_buffer_reader *reader = NULL;
   gpr_slice next;
+  if (buffer == NULL) {
+    return Qnil;
 
-  Data_Get_Struct(self, grpc_rb_byte_buffer, wrapper);
-  output_obj = rb_ivar_get(wrapper->mark, id_source);
-  if (output_obj != Qnil) {
-    /* From ruby, ByteBuffers are immutable so if a source is set, return that
-     * as the to_s value */
-    return output_obj;
-  }
-
-  /* Read the bytes. */
-  bb = wrapper->wrapped;
-  if (bb == NULL) {
-    return rb_id2str(id_empty);
-  }
-  length = grpc_byte_buffer_length(bb);
-  if (length == 0) {
-    return rb_id2str(id_empty);
   }
-  reader = grpc_byte_buffer_reader_create(bb);
-  output = xmalloc(length);
+  length = grpc_byte_buffer_length(buffer);
+  string = xmalloc(length + 1);
+  reader = grpc_byte_buffer_reader_create(buffer);
   while (grpc_byte_buffer_reader_next(reader, &next) != 0) {
-    memcpy(output + offset, GPR_SLICE_START_PTR(next), GPR_SLICE_LENGTH(next));
+    memcpy(string + offset, GPR_SLICE_START_PTR(next), GPR_SLICE_LENGTH(next));
     offset += GPR_SLICE_LENGTH(next);
   }
-  output_obj = rb_str_new(output, length);
-
-  /* Save a references to the computed string in the mark object so that the
-   * calling to_s does not do any allocations. */
-  wrapper->mark = rb_class_new_instance(0, NULL, rb_cObject);
-  rb_ivar_set(wrapper->mark, id_source, output_obj);
-
-  return output_obj;
-}
-
-/* Initializes ByteBuffer instances. */
-static VALUE grpc_rb_byte_buffer_init(VALUE self, VALUE src) {
-  gpr_slice a_slice;
-  grpc_rb_byte_buffer *wrapper = NULL;
-  grpc_byte_buffer *byte_buffer = NULL;
-
-  if (TYPE(src) != T_STRING) {
-    rb_raise(rb_eTypeError, "bad byte_buffer arg: got <%s>, want <String>",
-             rb_obj_classname(src));
-    return Qnil;
-  }
-  Data_Get_Struct(self, grpc_rb_byte_buffer, wrapper);
-  a_slice = gpr_slice_malloc(RSTRING_LEN(src));
-  memcpy(GPR_SLICE_START_PTR(a_slice), RSTRING_PTR(src), RSTRING_LEN(src));
-  byte_buffer = grpc_byte_buffer_create(&a_slice, 1);
-  gpr_slice_unref(a_slice);
-
-  if (byte_buffer == NULL) {
-    rb_raise(rb_eArgError, "could not create a byte_buffer, not sure why");
-    return Qnil;
-  }
-  wrapper->wrapped = byte_buffer;
-
-  /* Save a references to the original string in the mark object so that the
-   * pointers used there is valid for the lifetime of the object. */
-  wrapper->mark = rb_class_new_instance(0, NULL, rb_cObject);
-  rb_ivar_set(wrapper->mark, id_source, src);
-
-  return self;
-}
-
-/* rb_cByteBuffer is the ruby class that proxies grpc_byte_buffer. */
-VALUE rb_cByteBuffer = Qnil;
-
-void Init_grpc_byte_buffer() {
-  rb_cByteBuffer =
-      rb_define_class_under(rb_mGrpcCore, "ByteBuffer", rb_cObject);
-
-  /* Allocates an object managed by the ruby runtime */
-  rb_define_alloc_func(rb_cByteBuffer, grpc_rb_byte_buffer_alloc);
-
-  /* Provides a ruby constructor and support for dup/clone. */
-  rb_define_method(rb_cByteBuffer, "initialize", grpc_rb_byte_buffer_init, 1);
-  rb_define_method(rb_cByteBuffer, "initialize_copy",
-                   grpc_rb_byte_buffer_init_copy, 1);
-
-  /* Provides a to_s method that returns the buffer value */
-  rb_define_method(rb_cByteBuffer, "to_s", grpc_rb_byte_buffer_to_s, 0);
-
-  id_source = rb_intern("__source");
-  id_empty = rb_intern("");
-}
-
-VALUE grpc_rb_byte_buffer_create_with_mark(VALUE mark, grpc_byte_buffer *bb) {
-  grpc_rb_byte_buffer *byte_buffer = NULL;
-  if (bb == NULL) {
-    return Qnil;
-  }
-  byte_buffer = ALLOC(grpc_rb_byte_buffer);
-  byte_buffer->wrapped = bb;
-  byte_buffer->mark = mark;
-  return Data_Wrap_Struct(rb_cByteBuffer, grpc_rb_byte_buffer_mark,
-                          grpc_rb_byte_buffer_free, byte_buffer);
-}
-
-/* Gets the wrapped byte_buffer from the ruby wrapper */
-grpc_byte_buffer *grpc_rb_get_wrapped_byte_buffer(VALUE v) {
-  grpc_rb_byte_buffer *wrapper = NULL;
-  Data_Get_Struct(v, grpc_rb_byte_buffer, wrapper);
-  return wrapper->wrapped;
+  return rb_str_new(string, length);
 }
diff --git a/src/ruby/ext/grpc/rb_byte_buffer.h b/src/ruby/ext/grpc/rb_byte_buffer.h
index 6ef72f3e757fe2137acacb6159af4229c74ee0cb..96b9009dae99612694669daf3b217c52d1f953f1 100644
--- a/src/ruby/ext/grpc/rb_byte_buffer.h
+++ b/src/ruby/ext/grpc/rb_byte_buffer.h
@@ -37,18 +37,10 @@
 #include <grpc/grpc.h>
 #include <ruby.h>
 
-/* rb_cByteBuffer is the ByteBuffer class whose instances proxy
-   grpc_byte_buffer. */
-extern VALUE rb_cByteBuffer;
+/* Converts a char* with a length to a grpc_byte_buffer */
+grpc_byte_buffer *grpc_rb_s_to_byte_buffer(char *string, size_t length);
 
-/* Initializes the ByteBuffer class. */
-void Init_grpc_byte_buffer();
-
-/* grpc_rb_byte_buffer_create_with_mark creates a grpc_rb_byte_buffer with a
- * ruby mark object that will be kept alive while the byte_buffer is alive. */
-VALUE grpc_rb_byte_buffer_create_with_mark(VALUE mark, grpc_byte_buffer* bb);
-
-/* Gets the wrapped byte_buffer from its ruby object. */
-grpc_byte_buffer* grpc_rb_get_wrapped_byte_buffer(VALUE v);
+/* Converts a grpc_byte_buffer to a ruby string */
+VALUE grpc_rb_byte_buffer_to_s(grpc_byte_buffer *buffer);
 
 #endif /* GRPC_RB_BYTE_BUFFER_H_ */
diff --git a/src/ruby/ext/grpc/rb_call.c b/src/ruby/ext/grpc/rb_call.c
index b5a256d5a67d4b79ff6b8ab342506932761eff32..1b1958fd26337a016188520fcb712dcf277baf97 100644
--- a/src/ruby/ext/grpc/rb_call.c
+++ b/src/ruby/ext/grpc/rb_call.c
@@ -36,11 +36,20 @@
 #include <ruby.h>
 
 #include <grpc/grpc.h>
+#include <grpc/support/alloc.h>
+
 #include "rb_byte_buffer.h"
 #include "rb_completion_queue.h"
-#include "rb_metadata.h"
 #include "rb_grpc.h"
 
+/* grpc_rb_sBatchResult is struct class used to hold the results of a batch
+ * call. */
+static VALUE grpc_rb_sBatchResult;
+
+/* grpc_rb_cMdAry is the MetadataArray class whose instances proxy
+ * grpc_metadata_array. */
+static VALUE grpc_rb_cMdAry;
+
 /* id_cq is the name of the hidden ivar that preserves a reference to a
  * completion queue */
 static ID id_cq;
@@ -62,6 +71,15 @@ static ID id_metadata;
  * received by the call and subsequently saved on it. */
 static ID id_status;
 
+/* sym_* are the symbol for attributes of grpc_rb_sBatchResult. */
+static VALUE sym_send_message;
+static VALUE sym_send_metadata;
+static VALUE sym_send_close;
+static VALUE sym_send_status;
+static VALUE sym_message;
+static VALUE sym_status;
+static VALUE sym_cancelled;
+
 /* hash_all_calls is a hash of Call address -> reference count that is used to
  * track the creation and destruction of rb_call instances.
  */
@@ -101,84 +119,6 @@ const char *grpc_call_error_detail_of(grpc_call_error err) {
   return detail;
 }
 
-/* grpc_rb_call_add_metadata_hash_cb is the hash iteration callback used by
-   grpc_rb_call_add_metadata.
-*/
-int grpc_rb_call_add_metadata_hash_cb(VALUE key, VALUE val, VALUE call_obj) {
-  grpc_call *call = NULL;
-  grpc_metadata *md = NULL;
-  VALUE md_obj = Qnil;
-  VALUE md_obj_args[2];
-  VALUE flags = rb_ivar_get(call_obj, id_flags);
-  grpc_call_error err;
-  int array_length;
-  int i;
-
-  /* Construct a metadata object from key and value and add it */
-  Data_Get_Struct(call_obj, grpc_call, call);
-  md_obj_args[0] = key;
-
-  if (TYPE(val) == T_ARRAY) {
-    /* If the value is an array, add each value in the array separately */
-    array_length = RARRAY_LEN(val);
-    for (i = 0; i < array_length; i++) {
-      md_obj_args[1] = rb_ary_entry(val, i);
-      md_obj = rb_class_new_instance(2, md_obj_args, rb_cMetadata);
-      md = grpc_rb_get_wrapped_metadata(md_obj);
-      err = grpc_call_add_metadata_old(call, md, NUM2UINT(flags));
-      if (err != GRPC_CALL_OK) {
-        rb_raise(rb_eCallError, "add metadata failed: %s (code=%d)",
-                 grpc_call_error_detail_of(err), err);
-        return ST_STOP;
-      }
-    }
-  } else {
-    md_obj_args[1] = val;
-    md_obj = rb_class_new_instance(2, md_obj_args, rb_cMetadata);
-    md = grpc_rb_get_wrapped_metadata(md_obj);
-    err = grpc_call_add_metadata_old(call, md, NUM2UINT(flags));
-    if (err != GRPC_CALL_OK) {
-      rb_raise(rb_eCallError, "add metadata failed: %s (code=%d)",
-               grpc_call_error_detail_of(err), err);
-      return ST_STOP;
-    }
-  }
-
-  return ST_CONTINUE;
-}
-
-/*
-  call-seq:
-     call.add_metadata(completion_queue, hash_elements, flags=nil)
-
-  Add metadata elements to the call from a ruby hash, to be sent upon
-  invocation. flags is a bit-field combination of the write flags defined
-  above.  REQUIRES: grpc_call_invoke/grpc_call_accept have not been
-  called on this call.  Produces no events. */
-
-static VALUE grpc_rb_call_add_metadata(int argc, VALUE *argv, VALUE self) {
-  VALUE metadata;
-  VALUE flags = Qnil;
-  ID id_size = rb_intern("size");
-
-  /* "11" == 1 mandatory args, 1 (flags) is optional */
-  rb_scan_args(argc, argv, "11", &metadata, &flags);
-  if (NIL_P(flags)) {
-    flags = UINT2NUM(0); /* Default to no flags */
-  }
-  if (TYPE(metadata) != T_HASH) {
-    rb_raise(rb_eTypeError, "add metadata failed: metadata should be a hash");
-    return Qnil;
-  }
-  if (NUM2UINT(rb_funcall(metadata, id_size, 0)) == 0) {
-    return Qnil;
-  }
-  rb_ivar_set(self, id_flags, flags);
-  rb_ivar_set(self, id_input_md, metadata);
-  rb_hash_foreach(metadata, grpc_rb_call_add_metadata_hash_cb, self);
-  return Qnil;
-}
-
 /* Called by clients to cancel an RPC on the server.
    Can be called multiple times, from any thread. */
 static VALUE grpc_rb_call_cancel(VALUE self) {
@@ -187,7 +127,7 @@ static VALUE grpc_rb_call_cancel(VALUE self) {
   Data_Get_Struct(self, grpc_call, call);
   err = grpc_call_cancel(call);
   if (err != GRPC_CALL_OK) {
-    rb_raise(rb_eCallError, "cancel failed: %s (code=%d)",
+    rb_raise(grpc_rb_eCallError, "cancel failed: %s (code=%d)",
              grpc_call_error_detail_of(err), err);
   }
 
@@ -196,77 +136,20 @@ static VALUE grpc_rb_call_cancel(VALUE self) {
 
 /*
   call-seq:
-     call.invoke(completion_queue, tag, flags=nil)
-
-   Invoke the RPC. Starts sending metadata and request headers on the wire.
-   flags is a bit-field combination of the write flags defined above.
-   REQUIRES: Can be called at most once per call.
-             Can only be called on the client.
-   Produces a GRPC_INVOKE_ACCEPTED event on completion. */
-static VALUE grpc_rb_call_invoke(int argc, VALUE *argv, VALUE self) {
-  VALUE cqueue = Qnil;
-  VALUE metadata_read_tag = Qnil;
-  VALUE finished_tag = Qnil;
-  VALUE flags = Qnil;
-  grpc_call *call = NULL;
-  grpc_completion_queue *cq = NULL;
-  grpc_call_error err;
+  status = call.status
 
-  /* "31" == 3 mandatory args, 1 (flags) is optional */
-  rb_scan_args(argc, argv, "31", &cqueue, &metadata_read_tag, &finished_tag,
-               &flags);
-  if (NIL_P(flags)) {
-    flags = UINT2NUM(0); /* Default to no flags */
-  }
-  cq = grpc_rb_get_wrapped_completion_queue(cqueue);
-  Data_Get_Struct(self, grpc_call, call);
-  err = grpc_call_invoke_old(call, cq, ROBJECT(metadata_read_tag),
-                             ROBJECT(finished_tag), NUM2UINT(flags));
-  if (err != GRPC_CALL_OK) {
-    rb_raise(rb_eCallError, "invoke failed: %s (code=%d)",
-             grpc_call_error_detail_of(err), err);
-  }
-
-  /* Add the completion queue as an instance attribute, prevents it from being
-   * GCed until this call object is GCed */
-  rb_ivar_set(self, id_cq, cqueue);
-
-  return Qnil;
-}
-
-/* Initiate a read on a call. Output event contains a byte buffer with the
-   result of the read.
-   REQUIRES: No other reads are pending on the call. It is only safe to start
-   the next read after the corresponding read event is received. */
-static VALUE grpc_rb_call_start_read(VALUE self, VALUE tag) {
-  grpc_call *call = NULL;
-  grpc_call_error err;
-  Data_Get_Struct(self, grpc_call, call);
-  err = grpc_call_start_read_old(call, ROBJECT(tag));
-  if (err != GRPC_CALL_OK) {
-    rb_raise(rb_eCallError, "start read failed: %s (code=%d)",
-             grpc_call_error_detail_of(err), err);
-  }
-
-  return Qnil;
-}
-
-/*
-  call-seq:
-    status = call.status
-
-    Gets the status object saved the call.  */
+  Gets the status object saved the call.  */
 static VALUE grpc_rb_call_get_status(VALUE self) {
   return rb_ivar_get(self, id_status);
 }
 
 /*
   call-seq:
-    call.status = status
+  call.status = status
 
-    Saves a status object on the call.  */
+  Saves a status object on the call.  */
 static VALUE grpc_rb_call_set_status(VALUE self, VALUE status) {
-  if (!NIL_P(status) && rb_obj_class(status) != rb_sStatus) {
+  if (!NIL_P(status) && rb_obj_class(status) != grpc_rb_sStatus) {
     rb_raise(rb_eTypeError, "bad status: got:<%s> want: <Struct::Status>",
              rb_obj_classname(status));
     return Qnil;
@@ -277,18 +160,18 @@ static VALUE grpc_rb_call_set_status(VALUE self, VALUE status) {
 
 /*
   call-seq:
-    metadata = call.metadata
+  metadata = call.metadata
 
-    Gets the metadata object saved the call.  */
+  Gets the metadata object saved the call.  */
 static VALUE grpc_rb_call_get_metadata(VALUE self) {
   return rb_ivar_get(self, id_metadata);
 }
 
 /*
   call-seq:
-    call.metadata = metadata
+  call.metadata = metadata
 
-    Saves the metadata hash on the call.  */
+  Saves the metadata hash on the call.  */
 static VALUE grpc_rb_call_set_metadata(VALUE self, VALUE metadata) {
   if (!NIL_P(metadata) && TYPE(metadata) != T_HASH) {
     rb_raise(rb_eTypeError, "bad metadata: got:<%s> want: <Hash>",
@@ -299,176 +182,438 @@ static VALUE grpc_rb_call_set_metadata(VALUE self, VALUE metadata) {
   return rb_ivar_set(self, id_metadata, metadata);
 }
 
-/*
-  call-seq:
-     call.start_write(byte_buffer, tag, flags=nil)
-
-   Queue a byte buffer for writing.
-   flags is a bit-field combination of the write flags defined above.
-   A write with byte_buffer null is allowed, and will not send any bytes on the
-   wire. If this is performed without GRPC_WRITE_BUFFER_HINT flag it provides
-   a mechanism to flush any previously buffered writes to outgoing flow control.
-   REQUIRES: No other writes are pending on the call. It is only safe to
-             start the next write after the corresponding write_accepted event
-             is received.
-             GRPC_INVOKE_ACCEPTED must have been received by the application
-             prior to calling this on the client. On the server,
-             grpc_call_accept must have been called successfully.
-   Produces a GRPC_WRITE_ACCEPTED event. */
-static VALUE grpc_rb_call_start_write(int argc, VALUE *argv, VALUE self) {
-  VALUE byte_buffer = Qnil;
-  VALUE tag = Qnil;
-  VALUE flags = Qnil;
-  grpc_call *call = NULL;
-  grpc_byte_buffer *bfr = NULL;
-  grpc_call_error err;
+/* grpc_rb_md_ary_fill_hash_cb is the hash iteration callback used
+   to fill grpc_metadata_array.
+
+   it's capacity should have been computed via a prior call to
+   grpc_rb_md_ary_fill_hash_cb
+*/
+int grpc_rb_md_ary_fill_hash_cb(VALUE key, VALUE val, VALUE md_ary_obj) {
+  grpc_metadata_array *md_ary = NULL;
+  int array_length;
+  int i;
+
+  /* Construct a metadata object from key and value and add it */
+  Data_Get_Struct(md_ary_obj, grpc_metadata_array, md_ary);
 
-  /* "21" == 2 mandatory args, 1 (flags) is optional */
-  rb_scan_args(argc, argv, "21", &byte_buffer, &tag, &flags);
-  if (NIL_P(flags)) {
-    flags = UINT2NUM(0); /* Default to no flags */
+  if (TYPE(val) == T_ARRAY) {
+    /* If the value is an array, add capacity for each value in the array */
+    array_length = RARRAY_LEN(val);
+    for (i = 0; i < array_length; i++) {
+      if (TYPE(key) == T_SYMBOL) {
+        md_ary->metadata[md_ary->count].key = (char *)rb_id2name(SYM2ID(key));
+      } else { /* StringValueCStr does all other type exclusions for us */
+        md_ary->metadata[md_ary->count].key = StringValueCStr(key);
+      }
+      md_ary->metadata[md_ary->count].value = RSTRING_PTR(rb_ary_entry(val, i));
+      md_ary->metadata[md_ary->count].value_length =
+        RSTRING_LEN(rb_ary_entry(val, i));
+      md_ary->count += 1;
+    }
+  } else {
+    if (TYPE(key) == T_SYMBOL) {
+      md_ary->metadata[md_ary->count].key = (char *)rb_id2name(SYM2ID(key));
+    } else { /* StringValueCStr does all other type exclusions for us */
+      md_ary->metadata[md_ary->count].key = StringValueCStr(key);
+    }
+    md_ary->metadata[md_ary->count].value = RSTRING_PTR(val);
+    md_ary->metadata[md_ary->count].value_length = RSTRING_LEN(val);
+    md_ary->count += 1;
   }
-  bfr = grpc_rb_get_wrapped_byte_buffer(byte_buffer);
-  Data_Get_Struct(self, grpc_call, call);
-  err = grpc_call_start_write_old(call, bfr, ROBJECT(tag), NUM2UINT(flags));
-  if (err != GRPC_CALL_OK) {
-    rb_raise(rb_eCallError, "start write failed: %s (code=%d)",
-             grpc_call_error_detail_of(err), err);
+
+  return ST_CONTINUE;
+}
+
+/* grpc_rb_md_ary_capacity_hash_cb is the hash iteration callback used
+   to pre-compute the capacity a grpc_metadata_array.
+*/
+int grpc_rb_md_ary_capacity_hash_cb(VALUE key, VALUE val, VALUE md_ary_obj) {
+  grpc_metadata_array *md_ary = NULL;
+
+  /* Construct a metadata object from key and value and add it */
+  Data_Get_Struct(md_ary_obj, grpc_metadata_array, md_ary);
+
+  if (TYPE(val) == T_ARRAY) {
+    /* If the value is an array, add capacity for each value in the array */
+    md_ary->capacity += RARRAY_LEN(val);
+  } else {
+    md_ary->capacity += 1;
+  }
+  return ST_CONTINUE;
+}
+
+/* grpc_rb_md_ary_convert converts a ruby metadata hash into
+   a grpc_metadata_array.
+*/
+void grpc_rb_md_ary_convert(VALUE md_ary_hash, grpc_metadata_array *md_ary) {
+  VALUE md_ary_obj = Qnil;
+  if (md_ary_hash == Qnil) {
+    return;  /* Do nothing if the expected has value is nil */
+  }
+  if (TYPE(md_ary_hash) != T_HASH) {
+    rb_raise(rb_eTypeError, "md_ary_convert: got <%s>, want <Hash>",
+             rb_obj_classname(md_ary_hash));
+    return;
   }
 
-  return Qnil;
+  /* Initialize the array, compute it's capacity, then fill it. */
+  grpc_metadata_array_init(md_ary);
+  md_ary_obj =
+      Data_Wrap_Struct(grpc_rb_cMdAry, GC_NOT_MARKED, GC_DONT_FREE, md_ary);
+  rb_hash_foreach(md_ary_hash, grpc_rb_md_ary_capacity_hash_cb, md_ary_obj);
+  md_ary->metadata = gpr_malloc(md_ary->capacity * sizeof(grpc_metadata));
+  rb_hash_foreach(md_ary_hash, grpc_rb_md_ary_fill_hash_cb, md_ary_obj);
 }
 
-/* Queue a status for writing.
-
-   call-seq:
-      tag = Object.new
-      call.write_status(200, "OK", tag)
-
-   REQUIRES: No other writes are pending on the call. It is only safe to
-   start the next write after the corresponding write_accepted event
-   is received.
-   GRPC_INVOKE_ACCEPTED must have been received by the application
-   prior to calling this.
-   Only callable on the server.
-   Produces a GRPC_FINISHED event when the status is sent and the stream is
-   fully closed */
-static VALUE grpc_rb_call_start_write_status(VALUE self, VALUE code,
-                                             VALUE status, VALUE tag) {
-  grpc_call *call = NULL;
-  grpc_call_error err;
-  Data_Get_Struct(self, grpc_call, call);
-  err = grpc_call_start_write_status_old(call, NUM2UINT(code),
-                                         StringValueCStr(status), ROBJECT(tag));
-  if (err != GRPC_CALL_OK) {
-    rb_raise(rb_eCallError, "start write status: %s (code=%d)",
-             grpc_call_error_detail_of(err), err);
+/* Converts a metadata array to a hash. */
+VALUE grpc_rb_md_ary_to_h(grpc_metadata_array *md_ary) {
+  VALUE key = Qnil;
+  VALUE new_ary = Qnil;
+  VALUE value = Qnil;
+  VALUE result = rb_hash_new();
+  size_t i;
+
+  for (i = 0; i < md_ary->count; i++) {
+    key = rb_str_new2(md_ary->metadata[i].key);
+    value = rb_hash_aref(result, key);
+    if (value == Qnil) {
+      value = rb_str_new(md_ary->metadata[i].value,
+                         md_ary->metadata[i].value_length);
+      rb_hash_aset(result, key, value);
+    } else if (TYPE(value) == T_ARRAY) {
+      /* Add the string to the returned array */
+      rb_ary_push(value,
+                  rb_str_new(md_ary->metadata[i].value,
+                             md_ary->metadata[i].value_length));
+    } else {
+      /* Add the current value with this key and the new one to an array */
+      new_ary = rb_ary_new();
+      rb_ary_push(new_ary, value);
+      rb_ary_push(new_ary,
+                  rb_str_new(md_ary->metadata[i].value,
+                             md_ary->metadata[i].value_length));
+      rb_hash_aset(result, key, new_ary);
+    }
   }
+  return result;
+}
 
-  return Qnil;
+/* grpc_rb_call_check_op_keys_hash_cb is a hash iteration func that checks
+   each key of an ops hash is valid.
+*/
+int grpc_rb_call_check_op_keys_hash_cb(VALUE key, VALUE val, VALUE ops_ary) {
+  /* Update the capacity; the value is an array, add capacity for each value in
+   * the array */
+  if (TYPE(key) != T_FIXNUM) {
+    rb_raise(rb_eTypeError, "invalid operation : got <%s>, want <Fixnum>",
+             rb_obj_classname(key));
+    return ST_STOP;
+  }
+  switch(NUM2INT(key)) {
+    case GRPC_OP_SEND_INITIAL_METADATA:
+    case GRPC_OP_SEND_MESSAGE:
+    case GRPC_OP_SEND_CLOSE_FROM_CLIENT:
+    case GRPC_OP_SEND_STATUS_FROM_SERVER:
+    case GRPC_OP_RECV_INITIAL_METADATA:
+    case GRPC_OP_RECV_MESSAGE:
+    case GRPC_OP_RECV_STATUS_ON_CLIENT:
+    case GRPC_OP_RECV_CLOSE_ON_SERVER:
+      rb_ary_push(ops_ary, key);
+      return ST_CONTINUE;
+    default:
+      rb_raise(rb_eTypeError, "invalid operation : bad value %d",
+               NUM2INT(key));
+  };
+  return ST_STOP;
 }
 
-/* No more messages to send.
-   REQUIRES: No other writes are pending on the call. */
-static VALUE grpc_rb_call_writes_done(VALUE self, VALUE tag) {
-  grpc_call *call = NULL;
-  grpc_call_error err;
-  Data_Get_Struct(self, grpc_call, call);
-  err = grpc_call_writes_done_old(call, ROBJECT(tag));
-  if (err != GRPC_CALL_OK) {
-    rb_raise(rb_eCallError, "writes done: %s (code=%d)",
-             grpc_call_error_detail_of(err), err);
+/* grpc_rb_op_update_status_from_server adds the values in a ruby status
+   struct to the 'send_status_from_server' portion of an op.
+*/
+void grpc_rb_op_update_status_from_server(grpc_op *op,
+                                          grpc_metadata_array* md_ary,
+                                          VALUE status) {
+  VALUE code = rb_struct_aref(status, sym_code);
+  VALUE details = rb_struct_aref(status, sym_details);
+  VALUE metadata_hash = rb_struct_aref(status, sym_metadata);
+
+  /* TODO: add check to ensure status is the correct struct type */
+  if (TYPE(code) != T_FIXNUM) {
+    rb_raise(rb_eTypeError, "invalid code : got <%s>, want <Fixnum>",
+             rb_obj_classname(code));
+    return;
+  }
+  if (TYPE(details) != T_STRING) {
+    rb_raise(rb_eTypeError, "invalid details : got <%s>, want <String>",
+             rb_obj_classname(code));
+    return;
   }
+  op->data.send_status_from_server.status = NUM2INT(code);
+  op->data.send_status_from_server.status_details = StringValueCStr(details);
+  grpc_rb_md_ary_convert(metadata_hash, md_ary);
+  op->data.send_status_from_server.trailing_metadata_count = md_ary->count;
+  op->data.send_status_from_server.trailing_metadata = md_ary->metadata;
+}
 
-  return Qnil;
+/* run_batch_stack holds various values used by the
+ * grpc_rb_call_run_batch function */
+typedef struct run_batch_stack {
+  /* The batch ops */
+  grpc_op ops[8];  /* 8 is the maximum number of operations */
+  size_t op_num;   /* tracks the last added operation */
+
+  /* Data being sent */
+  grpc_metadata_array send_metadata;
+  grpc_metadata_array send_trailing_metadata;
+
+  /* Data being received */
+  grpc_byte_buffer *recv_message;
+  grpc_metadata_array recv_metadata;
+  grpc_metadata_array recv_trailing_metadata;
+  int recv_cancelled;
+  grpc_status_code recv_status;
+  char *recv_status_details;
+  size_t recv_status_details_capacity;
+} run_batch_stack;
+
+/* grpc_run_batch_stack_init ensures the run_batch_stack is properly
+ * initialized */
+static void grpc_run_batch_stack_init(run_batch_stack* st) {
+  MEMZERO(st, run_batch_stack, 1);
+  grpc_metadata_array_init(&st->send_metadata);
+  grpc_metadata_array_init(&st->send_trailing_metadata);
+  grpc_metadata_array_init(&st->recv_metadata);
+  grpc_metadata_array_init(&st->recv_trailing_metadata);
+  st->op_num = 0;
 }
 
-/* call-seq:
-     call.server_end_initial_metadata(flag)
-
-   Only to be called on servers, before sending messages.
-   flags is a bit-field combination of the write flags defined above.
-
-   REQUIRES: Can be called at most once per call.
-             Can only be called on the server, must be called after
-             grpc_call_server_accept
-   Produces no events */
-static VALUE grpc_rb_call_server_end_initial_metadata(int argc, VALUE *argv,
-                                                      VALUE self) {
-  VALUE flags = Qnil;
-  grpc_call *call = NULL;
-  grpc_call_error err;
+/* grpc_run_batch_stack_cleanup ensures the run_batch_stack is properly
+ * cleaned up */
+static void grpc_run_batch_stack_cleanup(run_batch_stack* st) {
+  grpc_metadata_array_destroy(&st->send_metadata);
+  grpc_metadata_array_destroy(&st->send_trailing_metadata);
+  grpc_metadata_array_destroy(&st->recv_metadata);
+  grpc_metadata_array_destroy(&st->recv_trailing_metadata);
+  if (st->recv_status_details != NULL) {
+    gpr_free(st->recv_status_details);
+  }
+}
 
-  /* "01" == 1 (flags) is optional */
-  rb_scan_args(argc, argv, "01", &flags);
-  if (NIL_P(flags)) {
-    flags = UINT2NUM(0); /* Default to no flags */
+/* grpc_run_batch_stack_fill_ops fills the run_batch_stack ops array from
+ * ops_hash */
+static void grpc_run_batch_stack_fill_ops(run_batch_stack* st, VALUE ops_hash) {
+  VALUE this_op = Qnil;
+  VALUE this_value = Qnil;
+  VALUE ops_ary = rb_ary_new();
+  size_t i = 0;
+
+  /* Create a ruby array with just the operation keys */
+  rb_hash_foreach(ops_hash, grpc_rb_call_check_op_keys_hash_cb, ops_ary);
+
+  /* Fill the ops array */
+  for (i = 0; i < (size_t)RARRAY_LEN(ops_ary); i++) {
+    this_op = rb_ary_entry(ops_ary, i);
+    this_value = rb_hash_aref(ops_hash, this_op);
+    switch(NUM2INT(this_op)) {
+      case GRPC_OP_SEND_INITIAL_METADATA:
+        /* N.B. later there is no need to explicitly delete the metadata keys
+         * and values, they are references to data in ruby objects. */
+        grpc_rb_md_ary_convert(this_value, &st->send_metadata);
+        st->ops[st->op_num].data.send_initial_metadata.count =
+            st->send_metadata.count;
+        st->ops[st->op_num].data.send_initial_metadata.metadata =
+            st->send_metadata.metadata;
+        break;
+      case GRPC_OP_SEND_MESSAGE:
+        st->ops[st->op_num].data.send_message =
+            grpc_rb_s_to_byte_buffer(RSTRING_PTR(this_value),
+                                     RSTRING_LEN(this_value));
+        break;
+      case GRPC_OP_SEND_CLOSE_FROM_CLIENT:
+        break;
+      case GRPC_OP_SEND_STATUS_FROM_SERVER:
+        /* N.B. later there is no need to explicitly delete the metadata keys
+         * and values, they are references to data in ruby objects. */
+        grpc_rb_op_update_status_from_server(&st->ops[st->op_num],
+                                             &st->send_trailing_metadata,
+                                             this_value);
+        break;
+      case GRPC_OP_RECV_INITIAL_METADATA:
+        st->ops[st->op_num].data.recv_initial_metadata = &st->recv_metadata;
+        break;
+      case GRPC_OP_RECV_MESSAGE:
+        st->ops[st->op_num].data.recv_message = &st->recv_message;
+        break;
+      case GRPC_OP_RECV_STATUS_ON_CLIENT:
+        st->ops[st->op_num].data.recv_status_on_client.trailing_metadata =
+            &st->recv_trailing_metadata;
+        st->ops[st->op_num].data.recv_status_on_client.status =
+            &st->recv_status;
+        st->ops[st->op_num].data.recv_status_on_client.status_details =
+            &st->recv_status_details;
+        st->ops[st->op_num].data.recv_status_on_client.status_details_capacity =
+            &st->recv_status_details_capacity;
+        break;
+      case GRPC_OP_RECV_CLOSE_ON_SERVER:
+        st->ops[st->op_num].data.recv_close_on_server.cancelled =
+            &st->recv_cancelled;
+        break;
+      default:
+        grpc_run_batch_stack_cleanup(st);
+        rb_raise(rb_eTypeError, "invalid operation : bad value %d",
+                 NUM2INT(this_op));
+    };
+    st->ops[st->op_num].op = (grpc_op_type)NUM2INT(this_op);
+    st->op_num++;
   }
-  Data_Get_Struct(self, grpc_call, call);
-  err = grpc_call_server_end_initial_metadata_old(call, NUM2UINT(flags));
-  if (err != GRPC_CALL_OK) {
-    rb_raise(rb_eCallError, "end_initial_metadata failed: %s (code=%d)",
-             grpc_call_error_detail_of(err), err);
+}
+
+/* grpc_run_batch_stack_build_result fills constructs a ruby BatchResult struct
+   after the results have run */
+static VALUE grpc_run_batch_stack_build_result(run_batch_stack* st) {
+  size_t i = 0;
+  VALUE result = rb_struct_new(grpc_rb_sBatchResult, Qnil, Qnil, Qnil, Qnil,
+                               Qnil, Qnil, Qnil, Qnil, NULL);
+  for (i = 0; i < st->op_num; i++) {
+    switch(st->ops[i].op) {
+      case GRPC_OP_SEND_INITIAL_METADATA:
+        rb_struct_aset(result, sym_send_metadata, Qtrue);
+        break;
+      case GRPC_OP_SEND_MESSAGE:
+        rb_struct_aset(result, sym_send_message, Qtrue);
+        grpc_byte_buffer_destroy(st->ops[i].data.send_message);
+        break;
+      case GRPC_OP_SEND_CLOSE_FROM_CLIENT:
+        rb_struct_aset(result, sym_send_close, Qtrue);
+        break;
+      case GRPC_OP_SEND_STATUS_FROM_SERVER:
+        rb_struct_aset(result, sym_send_status, Qtrue);
+        break;
+      case GRPC_OP_RECV_INITIAL_METADATA:
+        rb_struct_aset(result, sym_metadata,
+                       grpc_rb_md_ary_to_h(&st->recv_metadata));
+      case GRPC_OP_RECV_MESSAGE:
+        rb_struct_aset(result, sym_message,
+                       grpc_rb_byte_buffer_to_s(st->recv_message));
+        break;
+      case GRPC_OP_RECV_STATUS_ON_CLIENT:
+        rb_struct_aset(
+            result,
+            sym_status,
+            rb_struct_new(grpc_rb_sStatus,
+                          UINT2NUM(st->recv_status),
+                          (st->recv_status_details == NULL
+                           ? Qnil
+                           : rb_str_new2(st->recv_status_details)),
+                          grpc_rb_md_ary_to_h(&st->recv_trailing_metadata),
+                          NULL));
+        break;
+      case GRPC_OP_RECV_CLOSE_ON_SERVER:
+        rb_struct_aset(result, sym_send_close, Qtrue);
+        break;
+      default:
+        break;
+    }
   }
-  return Qnil;
+  return result;
 }
 
 /* call-seq:
-     call.server_accept(completion_queue, finished_tag)
-
-   Accept an incoming RPC, binding a completion queue to it.
-   To be called before sending or receiving messages.
-
-   REQUIRES: Can be called at most once per call.
-             Can only be called on the server.
-   Produces a GRPC_FINISHED event with finished_tag when the call has been
-       completed (there may be other events for the call pending at this
-       time) */
-static VALUE grpc_rb_call_server_accept(VALUE self, VALUE cqueue,
-                                        VALUE finished_tag) {
+   cq = CompletionQueue.new
+   ops = {
+     GRPC::Core::CallOps::SEND_INITIAL_METADATA => <op_value>,
+     GRPC::Core::CallOps::SEND_MESSAGE => <op_value>,
+     ...
+   }
+   tag = Object.new
+   timeout = 10
+   call.start_batch(cqueue, tag, timeout, ops)
+
+   Start a batch of operations defined in the array ops; when complete, post a
+   completion of type 'tag' to the completion queue bound to the call.
+
+   Also waits for the batch to complete, until timeout is reached.
+   The order of ops specified in the batch has no significance.
+   Only one operation of each type can be active at once in any given
+   batch */
+static VALUE grpc_rb_call_run_batch(VALUE self, VALUE cqueue, VALUE tag,
+                                    VALUE timeout, VALUE ops_hash) {
+  run_batch_stack st;
   grpc_call *call = NULL;
-  grpc_completion_queue *cq = grpc_rb_get_wrapped_completion_queue(cqueue);
+  grpc_event *ev = NULL;
   grpc_call_error err;
+  VALUE result = Qnil;
   Data_Get_Struct(self, grpc_call, call);
-  err = grpc_call_server_accept_old(call, cq, ROBJECT(finished_tag));
+
+  /* Validate the ops args, adding them to a ruby array */
+  if (TYPE(ops_hash) != T_HASH) {
+    rb_raise(rb_eTypeError, "call#run_batch: ops hash should be a hash");
+    return Qnil;
+  }
+  grpc_run_batch_stack_init(&st);
+  grpc_run_batch_stack_fill_ops(&st, ops_hash);
+
+  /* call grpc_call_start_batch, then wait for it to complete using
+   * pluck_event */
+  err = grpc_call_start_batch(call, st.ops, st.op_num, ROBJECT(tag));
   if (err != GRPC_CALL_OK) {
-    rb_raise(rb_eCallError, "server_accept failed: %s (code=%d)",
+    grpc_run_batch_stack_cleanup(&st);
+    rb_raise(grpc_rb_eCallError,
+             "grpc_call_start_batch failed with %s (code=%d)",
              grpc_call_error_detail_of(err), err);
+    return;
+  }
+  ev = grpc_rb_completion_queue_pluck_event(cqueue, tag, timeout);
+  if (ev == NULL) {
+    grpc_run_batch_stack_cleanup(&st);
+    rb_raise(grpc_rb_eOutOfTime, "grpc_call_start_batch timed out");
+    return;
+  }
+  if (ev->data.op_complete != GRPC_OP_OK) {
+    grpc_run_batch_stack_cleanup(&st);
+    rb_raise(grpc_rb_eCallError, "start_batch completion failed, (code=%d)",
+             ev->data.op_complete);
+    return;
   }
 
-  /* Add the completion queue as an instance attribute, prevents it from being
-   * GCed until this call object is GCed */
-  rb_ivar_set(self, id_cq, cqueue);
-  return Qnil;
+  /* Build and return the BatchResult struct result */
+  result = grpc_run_batch_stack_build_result(&st);
+  grpc_run_batch_stack_cleanup(&st);
+  return result;
 }
 
-/* rb_cCall is the ruby class that proxies grpc_call. */
-VALUE rb_cCall = Qnil;
+/* grpc_rb_cCall is the ruby class that proxies grpc_call. */
+VALUE grpc_rb_cCall = Qnil;
 
-/* rb_eCallError is the ruby class of the exception thrown during call
+/* grpc_rb_eCallError is the ruby class of the exception thrown during call
    operations; */
-VALUE rb_eCallError = Qnil;
+VALUE grpc_rb_eCallError = Qnil;
+
+/* grpc_rb_eOutOfTime is the ruby class of the exception thrown to indicate
+   a timeout. */
+VALUE grpc_rb_eOutOfTime = Qnil;
 
 void Init_grpc_error_codes() {
   /* Constants representing the error codes of grpc_call_error in grpc.h */
-  VALUE rb_RpcErrors = rb_define_module_under(rb_mGrpcCore, "RpcErrors");
-  rb_define_const(rb_RpcErrors, "OK", UINT2NUM(GRPC_CALL_OK));
-  rb_define_const(rb_RpcErrors, "ERROR", UINT2NUM(GRPC_CALL_ERROR));
-  rb_define_const(rb_RpcErrors, "NOT_ON_SERVER",
+  VALUE grpc_rb_mRpcErrors =
+      rb_define_module_under(grpc_rb_mGrpcCore, "RpcErrors");
+  rb_define_const(grpc_rb_mRpcErrors, "OK", UINT2NUM(GRPC_CALL_OK));
+  rb_define_const(grpc_rb_mRpcErrors, "ERROR", UINT2NUM(GRPC_CALL_ERROR));
+  rb_define_const(grpc_rb_mRpcErrors, "NOT_ON_SERVER",
                   UINT2NUM(GRPC_CALL_ERROR_NOT_ON_SERVER));
-  rb_define_const(rb_RpcErrors, "NOT_ON_CLIENT",
+  rb_define_const(grpc_rb_mRpcErrors, "NOT_ON_CLIENT",
                   UINT2NUM(GRPC_CALL_ERROR_NOT_ON_CLIENT));
-  rb_define_const(rb_RpcErrors, "ALREADY_ACCEPTED",
+  rb_define_const(grpc_rb_mRpcErrors, "ALREADY_ACCEPTED",
                   UINT2NUM(GRPC_CALL_ERROR_ALREADY_ACCEPTED));
-  rb_define_const(rb_RpcErrors, "ALREADY_INVOKED",
+  rb_define_const(grpc_rb_mRpcErrors, "ALREADY_INVOKED",
                   UINT2NUM(GRPC_CALL_ERROR_ALREADY_INVOKED));
-  rb_define_const(rb_RpcErrors, "NOT_INVOKED",
+  rb_define_const(grpc_rb_mRpcErrors, "NOT_INVOKED",
                   UINT2NUM(GRPC_CALL_ERROR_NOT_INVOKED));
-  rb_define_const(rb_RpcErrors, "ALREADY_FINISHED",
+  rb_define_const(grpc_rb_mRpcErrors, "ALREADY_FINISHED",
                   UINT2NUM(GRPC_CALL_ERROR_ALREADY_FINISHED));
-  rb_define_const(rb_RpcErrors, "TOO_MANY_OPERATIONS",
+  rb_define_const(grpc_rb_mRpcErrors, "TOO_MANY_OPERATIONS",
                   UINT2NUM(GRPC_CALL_ERROR_TOO_MANY_OPERATIONS));
-  rb_define_const(rb_RpcErrors, "INVALID_FLAGS",
+  rb_define_const(grpc_rb_mRpcErrors, "INVALID_FLAGS",
                   UINT2NUM(GRPC_CALL_ERROR_INVALID_FLAGS));
 
   /* Add the detail strings to a Hash */
@@ -496,37 +641,55 @@ void Init_grpc_error_codes() {
                rb_str_new2("outstanding read or write present"));
   rb_hash_aset(rb_error_code_details, UINT2NUM(GRPC_CALL_ERROR_INVALID_FLAGS),
                rb_str_new2("a bad flag was given"));
-  rb_define_const(rb_RpcErrors, "ErrorMessages", rb_error_code_details);
+  rb_define_const(grpc_rb_mRpcErrors, "ErrorMessages", rb_error_code_details);
   rb_obj_freeze(rb_error_code_details);
 }
 
+void Init_grpc_op_codes() {
+  /* Constants representing operation type codes in grpc.h */
+  VALUE grpc_rb_mCallOps =
+      rb_define_module_under(grpc_rb_mGrpcCore, "CallOps");
+  rb_define_const(grpc_rb_mCallOps, "SEND_INITIAL_METADATA",
+                  UINT2NUM(GRPC_OP_SEND_INITIAL_METADATA));
+  rb_define_const(grpc_rb_mCallOps, "SEND_MESSAGE",
+                  UINT2NUM(GRPC_OP_SEND_MESSAGE));
+  rb_define_const(grpc_rb_mCallOps, "SEND_CLOSE_FROM_CLIENT",
+                  UINT2NUM(GRPC_OP_SEND_CLOSE_FROM_CLIENT));
+  rb_define_const(grpc_rb_mCallOps, "SEND_STATUS_FROM_SERVER",
+                  UINT2NUM(GRPC_OP_SEND_STATUS_FROM_SERVER));
+  rb_define_const(grpc_rb_mCallOps, "RECV_INITIAL_METADATA",
+                  UINT2NUM(GRPC_OP_RECV_INITIAL_METADATA));
+  rb_define_const(grpc_rb_mCallOps, "RECV_MESSAGE",
+                  UINT2NUM(GRPC_OP_RECV_MESSAGE));
+  rb_define_const(grpc_rb_mCallOps, "RECV_STATUS_ON_CLIENT",
+                  UINT2NUM(GRPC_OP_RECV_STATUS_ON_CLIENT));
+  rb_define_const(grpc_rb_mCallOps, "RECV_CLOSE_ON_SERVER",
+                  UINT2NUM(GRPC_OP_RECV_CLOSE_ON_SERVER));
+}
+
 void Init_grpc_call() {
   /* CallError inherits from Exception to signal that it is non-recoverable */
-  rb_eCallError =
-      rb_define_class_under(rb_mGrpcCore, "CallError", rb_eException);
-  rb_cCall = rb_define_class_under(rb_mGrpcCore, "Call", rb_cObject);
+  grpc_rb_eCallError =
+      rb_define_class_under(grpc_rb_mGrpcCore, "CallError", rb_eException);
+  grpc_rb_eOutOfTime =
+      rb_define_class_under(grpc_rb_mGrpcCore, "OutOfTime", rb_eException);
+  grpc_rb_cCall = rb_define_class_under(grpc_rb_mGrpcCore, "Call", rb_cObject);
+  grpc_rb_cMdAry = rb_define_class_under(grpc_rb_mGrpcCore, "MetadataArray",
+                                         rb_cObject);
 
   /* Prevent allocation or inialization of the Call class */
-  rb_define_alloc_func(rb_cCall, grpc_rb_cannot_alloc);
-  rb_define_method(rb_cCall, "initialize", grpc_rb_cannot_init, 0);
-  rb_define_method(rb_cCall, "initialize_copy", grpc_rb_cannot_init_copy, 1);
+  rb_define_alloc_func(grpc_rb_cCall, grpc_rb_cannot_alloc);
+  rb_define_method(grpc_rb_cCall, "initialize", grpc_rb_cannot_init, 0);
+  rb_define_method(grpc_rb_cCall, "initialize_copy",
+                   grpc_rb_cannot_init_copy, 1);
 
   /* Add ruby analogues of the Call methods. */
-  rb_define_method(rb_cCall, "server_accept", grpc_rb_call_server_accept, 2);
-  rb_define_method(rb_cCall, "server_end_initial_metadata",
-                   grpc_rb_call_server_end_initial_metadata, -1);
-  rb_define_method(rb_cCall, "add_metadata", grpc_rb_call_add_metadata, -1);
-  rb_define_method(rb_cCall, "cancel", grpc_rb_call_cancel, 0);
-  rb_define_method(rb_cCall, "invoke", grpc_rb_call_invoke, -1);
-  rb_define_method(rb_cCall, "start_read", grpc_rb_call_start_read, 1);
-  rb_define_method(rb_cCall, "start_write", grpc_rb_call_start_write, -1);
-  rb_define_method(rb_cCall, "start_write_status",
-                   grpc_rb_call_start_write_status, 3);
-  rb_define_method(rb_cCall, "writes_done", grpc_rb_call_writes_done, 1);
-  rb_define_method(rb_cCall, "status", grpc_rb_call_get_status, 0);
-  rb_define_method(rb_cCall, "status=", grpc_rb_call_set_status, 1);
-  rb_define_method(rb_cCall, "metadata", grpc_rb_call_get_metadata, 0);
-  rb_define_method(rb_cCall, "metadata=", grpc_rb_call_set_metadata, 1);
+  rb_define_method(grpc_rb_cCall, "run_batch", grpc_rb_call_run_batch, 4);
+  rb_define_method(grpc_rb_cCall, "cancel", grpc_rb_call_cancel, 0);
+  rb_define_method(grpc_rb_cCall, "status", grpc_rb_call_get_status, 0);
+  rb_define_method(grpc_rb_cCall, "status=", grpc_rb_call_set_status, 1);
+  rb_define_method(grpc_rb_cCall, "metadata", grpc_rb_call_get_metadata, 0);
+  rb_define_method(grpc_rb_cCall, "metadata=", grpc_rb_call_set_metadata, 1);
 
   /* Ids used to support call attributes */
   id_metadata = rb_intern("metadata");
@@ -537,12 +700,35 @@ void Init_grpc_call() {
   id_flags = rb_intern("__flags");
   id_input_md = rb_intern("__input_md");
 
+  /* Ids used in constructing the batch result. */
+  sym_send_message = ID2SYM(rb_intern("send_message"));
+  sym_send_metadata = ID2SYM(rb_intern("send_metadata"));
+  sym_send_close = ID2SYM(rb_intern("send_close"));
+  sym_send_status = ID2SYM(rb_intern("send_status"));
+  sym_message = ID2SYM(rb_intern("message"));
+  sym_status = ID2SYM(rb_intern("status"));
+  sym_cancelled = ID2SYM(rb_intern("cancelled"));
+
+  /* The Struct used to return the run_batch result. */
+  grpc_rb_sBatchResult = rb_struct_define(
+      "BatchResult",
+      "send_message",
+      "send_metadata",
+      "send_close",
+      "send_status",
+      "message",
+      "metadata",
+      "status",
+      "cancelled",
+      NULL);
+
   /* The hash for reference counting calls, to ensure they can't be destroyed
    * more than once */
   hash_all_calls = rb_hash_new();
-  rb_define_const(rb_cCall, "INTERNAL_ALL_CALLs", hash_all_calls);
+  rb_define_const(grpc_rb_cCall, "INTERNAL_ALL_CALLs", hash_all_calls);
 
   Init_grpc_error_codes();
+  Init_grpc_op_codes();
 }
 
 /* Gets the call from the ruby object */
@@ -565,5 +751,6 @@ VALUE grpc_rb_wrap_call(grpc_call *c) {
     rb_hash_aset(hash_all_calls, OFFT2NUM((VALUE)c),
                  UINT2NUM(NUM2UINT(obj) + 1));
   }
-  return Data_Wrap_Struct(rb_cCall, GC_NOT_MARKED, grpc_rb_call_destroy, c);
+  return Data_Wrap_Struct(grpc_rb_cCall, GC_NOT_MARKED,
+                          grpc_rb_call_destroy, c);
 }
diff --git a/src/ruby/ext/grpc/rb_call.h b/src/ruby/ext/grpc/rb_call.h
index bb51759a467bdd51b98051fee82e5910e5f48f06..e20a34c74e27a70f2f8e8a058ec3576d24973861 100644
--- a/src/ruby/ext/grpc/rb_call.h
+++ b/src/ruby/ext/grpc/rb_call.h
@@ -46,12 +46,19 @@ VALUE grpc_rb_wrap_call(grpc_call* c);
 /* Provides the details of an call error */
 const char* grpc_call_error_detail_of(grpc_call_error err);
 
-/* rb_cCall is the Call class whose instances proxy grpc_call. */
-extern VALUE rb_cCall;
+/* Converts a metadata array to a hash. */
+VALUE grpc_rb_md_ary_to_h(grpc_metadata_array *md_ary);
 
-/* rb_cCallError is the ruby class of the exception thrown during call
+/* grpc_rb_cCall is the Call class whose instances proxy grpc_call. */
+extern VALUE grpc_rb_cCall;
+
+/* grpc_rb_eCallError is the ruby class of the exception thrown during call
    operations. */
-extern VALUE rb_eCallError;
+extern VALUE grpc_rb_eCallError;
+
+/* grpc_rb_eOutOfTime is the ruby class of the exception thrown to indicate
+   a timeout. */
+extern VALUE grpc_rb_eOutOfTime;
 
 /* Initializes the Call class. */
 void Init_grpc_call();
diff --git a/src/ruby/ext/grpc/rb_channel.c b/src/ruby/ext/grpc/rb_channel.c
index 2a48f46ce2eeaeec1d53aa532f7cd375f4ba8606..3480280a03cab1e3fd08c6980763b1b3f02824c4 100644
--- a/src/ruby/ext/grpc/rb_channel.c
+++ b/src/ruby/ext/grpc/rb_channel.c
@@ -49,12 +49,18 @@
 static ID id_channel;
 
 /* id_target is the name of the hidden ivar that preserves a reference to the
- * target string used to create the call, preserved so that is does not get
+ * target string used to create the call, preserved so that it does not get
  * GCed before the channel */
 static ID id_target;
 
+/* id_cqueue is the name of the hidden ivar that preserves a reference to the
+ * completion queue used to create the call, preserved so that it does not get
+ * GCed before the channel */
+static ID id_cqueue;
+
+
 /* Used during the conversion of a hash to channel args during channel setup */
-static VALUE rb_cChannelArgs;
+static VALUE grpc_rb_cChannelArgs;
 
 /* grpc_rb_channel wraps a grpc_channel.  It provides a peer ruby object,
  * 'mark' to minimize copying when a channel is created from ruby. */
@@ -142,6 +148,7 @@ static VALUE grpc_rb_channel_init(int argc, VALUE *argv, VALUE self) {
   if (ch == NULL) {
     rb_raise(rb_eRuntimeError, "could not create an rpc channel to target:%s",
              target_chars);
+    return Qnil;
   }
   rb_ivar_set(self, id_target, target);
   wrapper->wrapped = ch;
@@ -163,7 +170,8 @@ static VALUE grpc_rb_channel_init_copy(VALUE copy, VALUE orig) {
   /* Raise an error if orig is not a channel object or a subclass. */
   if (TYPE(orig) != T_DATA ||
       RDATA(orig)->dfree != (RUBY_DATA_FUNC)grpc_rb_channel_free) {
-    rb_raise(rb_eTypeError, "not a %s", rb_obj_classname(rb_cChannel));
+    rb_raise(rb_eTypeError, "not a %s", rb_obj_classname(grpc_rb_cChannel));
+    return Qnil;
   }
 
   Data_Get_Struct(orig, grpc_rb_channel, orig_ch);
@@ -177,34 +185,42 @@ static VALUE grpc_rb_channel_init_copy(VALUE copy, VALUE orig) {
 
 /* Create a call given a grpc_channel, in order to call method. The request
    is not sent until grpc_call_invoke is called. */
-static VALUE grpc_rb_channel_create_call(VALUE self, VALUE method, VALUE host,
-                                         VALUE deadline) {
+static VALUE grpc_rb_channel_create_call(VALUE self, VALUE cqueue, VALUE method,
+                                         VALUE host, VALUE deadline) {
   VALUE res = Qnil;
   grpc_rb_channel *wrapper = NULL;
-  grpc_channel *ch = NULL;
   grpc_call *call = NULL;
+  grpc_channel *ch = NULL;
+  grpc_completion_queue *cq = NULL;
   char *method_chars = StringValueCStr(method);
   char *host_chars = StringValueCStr(host);
 
+  cq = grpc_rb_get_wrapped_completion_queue(cqueue);
   Data_Get_Struct(self, grpc_rb_channel, wrapper);
   ch = wrapper->wrapped;
   if (ch == NULL) {
     rb_raise(rb_eRuntimeError, "closed!");
+    return Qnil;
   }
 
   call =
-      grpc_channel_create_call_old(ch, method_chars, host_chars,
-                                   grpc_rb_time_timeval(deadline,
-                                                        /* absolute time */ 0));
+      grpc_channel_create_call(ch, cq, method_chars, host_chars,
+                               grpc_rb_time_timeval(deadline,
+                                                    /* absolute time */ 0));
   if (call == NULL) {
     rb_raise(rb_eRuntimeError, "cannot create call with method %s",
              method_chars);
+    return Qnil;
   }
   res = grpc_rb_wrap_call(call);
 
-  /* Make this channel an instance attribute of the call so that is is not GCed
+  /* Make this channel an instance attribute of the call so that it is not GCed
    * before the call. */
   rb_ivar_set(res, id_channel, self);
+
+  /* Make the completion queue an instance attribute of the call so that it is
+   * not GCed before the call. */
+  rb_ivar_set(res, id_cqueue, cqueue);
   return res;
 }
 
@@ -224,35 +240,38 @@ static VALUE grpc_rb_channel_destroy(VALUE self) {
   return Qnil;
 }
 
-/* rb_cChannel is the ruby class that proxies grpc_channel. */
-VALUE rb_cChannel = Qnil;
+/* grpc_rb_cChannel is the ruby class that proxies grpc_channel. */
+VALUE grpc_rb_cChannel = Qnil;
 
 void Init_grpc_channel() {
-  rb_cChannelArgs = rb_define_class("TmpChannelArgs", rb_cObject);
-  rb_cChannel = rb_define_class_under(rb_mGrpcCore, "Channel", rb_cObject);
+  grpc_rb_cChannelArgs = rb_define_class("TmpChannelArgs", rb_cObject);
+  grpc_rb_cChannel =
+      rb_define_class_under(grpc_rb_mGrpcCore, "Channel", rb_cObject);
 
   /* Allocates an object managed by the ruby runtime */
-  rb_define_alloc_func(rb_cChannel, grpc_rb_channel_alloc);
+  rb_define_alloc_func(grpc_rb_cChannel, grpc_rb_channel_alloc);
 
   /* Provides a ruby constructor and support for dup/clone. */
-  rb_define_method(rb_cChannel, "initialize", grpc_rb_channel_init, -1);
-  rb_define_method(rb_cChannel, "initialize_copy", grpc_rb_channel_init_copy,
-                   1);
+  rb_define_method(grpc_rb_cChannel, "initialize", grpc_rb_channel_init, -1);
+  rb_define_method(grpc_rb_cChannel, "initialize_copy",
+                   grpc_rb_channel_init_copy, 1);
 
   /* Add ruby analogues of the Channel methods. */
-  rb_define_method(rb_cChannel, "create_call", grpc_rb_channel_create_call, 3);
-  rb_define_method(rb_cChannel, "destroy", grpc_rb_channel_destroy, 0);
-  rb_define_alias(rb_cChannel, "close", "destroy");
+  rb_define_method(grpc_rb_cChannel, "create_call",
+                   grpc_rb_channel_create_call, 4);
+  rb_define_method(grpc_rb_cChannel, "destroy", grpc_rb_channel_destroy, 0);
+  rb_define_alias(grpc_rb_cChannel, "close", "destroy");
 
   id_channel = rb_intern("__channel");
+  id_cqueue = rb_intern("__cqueue");
   id_target = rb_intern("__target");
-  rb_define_const(rb_cChannel, "SSL_TARGET",
+  rb_define_const(grpc_rb_cChannel, "SSL_TARGET",
                   ID2SYM(rb_intern(GRPC_SSL_TARGET_NAME_OVERRIDE_ARG)));
-  rb_define_const(rb_cChannel, "ENABLE_CENSUS",
+  rb_define_const(grpc_rb_cChannel, "ENABLE_CENSUS",
                   ID2SYM(rb_intern(GRPC_ARG_ENABLE_CENSUS)));
-  rb_define_const(rb_cChannel, "MAX_CONCURRENT_STREAMS",
+  rb_define_const(grpc_rb_cChannel, "MAX_CONCURRENT_STREAMS",
                   ID2SYM(rb_intern(GRPC_ARG_MAX_CONCURRENT_STREAMS)));
-  rb_define_const(rb_cChannel, "MAX_MESSAGE_LENGTH",
+  rb_define_const(grpc_rb_cChannel, "MAX_MESSAGE_LENGTH",
                   ID2SYM(rb_intern(GRPC_ARG_MAX_MESSAGE_LENGTH)));
 }
 
diff --git a/src/ruby/ext/grpc/rb_channel.h b/src/ruby/ext/grpc/rb_channel.h
index a582869cda4b32b00cfa617b3fb493e4d015388c..5c57b31fb2831ad740c42cbc90834a15abd49582 100644
--- a/src/ruby/ext/grpc/rb_channel.h
+++ b/src/ruby/ext/grpc/rb_channel.h
@@ -37,8 +37,8 @@
 #include <ruby.h>
 #include <grpc/grpc.h>
 
-/* rb_cChannel is the Channel class whose instances proxy grpc_channel. */
-extern VALUE rb_cChannel;
+/* grpc_rb_cChannel is the Channel class whose instances proxy grpc_channel. */
+extern VALUE grpc_rb_cChannel;
 
 /* Initializes the Channel class. */
 void Init_grpc_channel();
diff --git a/src/ruby/ext/grpc/rb_channel_args.c b/src/ruby/ext/grpc/rb_channel_args.c
index 532ee5e78599822ccad0e3895b1ada48b8a59cbc..9b92ec1514ec497b0815cddc3cdd1081f5e5500f 100644
--- a/src/ruby/ext/grpc/rb_channel_args.c
+++ b/src/ruby/ext/grpc/rb_channel_args.c
@@ -109,7 +109,7 @@ typedef struct channel_convert_params {
 
 static VALUE grpc_rb_hash_convert_to_channel_args0(VALUE as_value) {
   ID id_size = rb_intern("size");
-  VALUE rb_cChannelArgs = rb_define_class("TmpChannelArgs", rb_cObject);
+  VALUE grpc_rb_cChannelArgs = rb_define_class("TmpChannelArgs", rb_cObject);
   channel_convert_params* params = (channel_convert_params*)as_value;
   size_t num_args = 0;
 
@@ -126,7 +126,7 @@ static VALUE grpc_rb_hash_convert_to_channel_args0(VALUE as_value) {
     MEMZERO(params->dst->args, grpc_arg, num_args);
     rb_hash_foreach(params->src_hash,
                     grpc_rb_channel_create_in_process_add_args_hash_cb,
-                    Data_Wrap_Struct(rb_cChannelArgs, GC_NOT_MARKED,
+                    Data_Wrap_Struct(grpc_rb_cChannelArgs, GC_NOT_MARKED,
                                      GC_DONT_FREE, params->dst));
     /* reset num_args as grpc_rb_channel_create_in_process_add_args_hash_cb
      * decrements it during has processing */
diff --git a/src/ruby/ext/grpc/rb_completion_queue.c b/src/ruby/ext/grpc/rb_completion_queue.c
index 3fdbdd837a7e7866d3a245053695e52f6e484964..20ce1b909c16ccc388c42e752f8a24b1e127d25b 100644
--- a/src/ruby/ext/grpc/rb_completion_queue.c
+++ b/src/ruby/ext/grpc/rb_completion_queue.c
@@ -38,7 +38,6 @@
 #include <grpc/grpc.h>
 #include <grpc/support/time.h>
 #include "rb_grpc.h"
-#include "rb_event.h"
 
 /* Used to allow grpc_completion_queue_next call to release the GIL */
 typedef struct next_call_stack {
@@ -140,8 +139,19 @@ static VALUE grpc_rb_completion_queue_next(VALUE self, VALUE timeout) {
 
 /* Blocks until the next event for given tag is available, and returns the
  * event. */
-static VALUE grpc_rb_completion_queue_pluck(VALUE self, VALUE tag,
-                                            VALUE timeout) {
+VALUE grpc_rb_completion_queue_pluck(VALUE self, VALUE tag,
+                                     VALUE timeout) {
+  grpc_event *ev = grpc_rb_completion_queue_pluck_event(self, tag, timeout);
+  if (ev == NULL) {
+    return Qnil;
+  }
+  return grpc_rb_new_event(ev);
+}
+
+/* Blocks until the next event for given tag is available, and returns the
+ * event. */
+grpc_event* grpc_rb_completion_queue_pluck_event(VALUE self, VALUE tag,
+                                                 VALUE timeout) {
   next_call_stack next_call;
   MEMZERO(&next_call, next_call_stack, 1);
   Data_Get_Struct(self, grpc_completion_queue, next_call.cq);
@@ -151,30 +161,32 @@ static VALUE grpc_rb_completion_queue_pluck(VALUE self, VALUE tag,
   rb_thread_call_without_gvl(grpc_rb_completion_queue_pluck_no_gil,
                              (void *)&next_call, NULL, NULL);
   if (next_call.event == NULL) {
-    return Qnil;
+    return NULL;
   }
-  return grpc_rb_new_event(next_call.event);
+  return next_call.event;
 }
 
-/* rb_cCompletionQueue is the ruby class that proxies grpc_completion_queue. */
-VALUE rb_cCompletionQueue = Qnil;
+/* grpc_rb_cCompletionQueue is the ruby class that proxies
+ * grpc_completion_queue. */
+VALUE grpc_rb_cCompletionQueue = Qnil;
 
 void Init_grpc_completion_queue() {
-  rb_cCompletionQueue =
-      rb_define_class_under(rb_mGrpcCore, "CompletionQueue", rb_cObject);
+  grpc_rb_cCompletionQueue =
+      rb_define_class_under(grpc_rb_mGrpcCore, "CompletionQueue", rb_cObject);
 
   /* constructor: uses an alloc func without an initializer. Using a simple
      alloc func works here as the grpc header does not specify any args for
      this func, so no separate initialization step is necessary. */
-  rb_define_alloc_func(rb_cCompletionQueue, grpc_rb_completion_queue_alloc);
+  rb_define_alloc_func(grpc_rb_cCompletionQueue,
+                       grpc_rb_completion_queue_alloc);
 
   /* Add the next method that waits for the next event. */
-  rb_define_method(rb_cCompletionQueue, "next", grpc_rb_completion_queue_next,
-                   1);
+  rb_define_method(grpc_rb_cCompletionQueue, "next",
+                   grpc_rb_completion_queue_next, 1);
 
   /* Add the pluck method that waits for the next event of given tag */
-  rb_define_method(rb_cCompletionQueue, "pluck", grpc_rb_completion_queue_pluck,
-                   2);
+  rb_define_method(grpc_rb_cCompletionQueue, "pluck",
+                   grpc_rb_completion_queue_pluck, 2);
 }
 
 /* Gets the wrapped completion queue from the ruby wrapper */
diff --git a/src/ruby/ext/grpc/rb_completion_queue.h b/src/ruby/ext/grpc/rb_completion_queue.h
index 38025ea2d2e2488d81b7b879a89a1fa8f05e4c55..1bfb80e49950bbc8d14aedc06b445307e7f6dc2d 100644
--- a/src/ruby/ext/grpc/rb_completion_queue.h
+++ b/src/ruby/ext/grpc/rb_completion_queue.h
@@ -40,9 +40,17 @@
 /* Gets the wrapped completion queue from the ruby wrapper */
 grpc_completion_queue *grpc_rb_get_wrapped_completion_queue(VALUE v);
 
-/* rb_cCompletionQueue is the CompletionQueue class whose instances proxy
+/**
+ * Makes the implementation of CompletionQueue#pluck available in other files
+ *
+ * This avoids having code that holds the GIL repeated at multiple sites.
+ */
+grpc_event* grpc_rb_completion_queue_pluck_event(VALUE cqueue, VALUE tag,
+                                                 VALUE timeout);
+
+/* grpc_rb_cCompletionQueue is the CompletionQueue class whose instances proxy
    grpc_completion_queue. */
-extern VALUE rb_cCompletionQueue;
+extern VALUE grpc_rb_cCompletionQueue;
 
 /* Initializes the CompletionQueue class. */
 void Init_grpc_completion_queue();
diff --git a/src/ruby/ext/grpc/rb_credentials.c b/src/ruby/ext/grpc/rb_credentials.c
index 4ee5d6b51c863de454a7ce2f78ff2108fed5e51c..1504a4884ea3a47dc3b0c424ed62bce8e35fdc1e 100644
--- a/src/ruby/ext/grpc/rb_credentials.c
+++ b/src/ruby/ext/grpc/rb_credentials.c
@@ -107,7 +107,7 @@ static VALUE grpc_rb_credentials_init_copy(VALUE copy, VALUE orig) {
   /* Raise an error if orig is not a credentials object or a subclass. */
   if (TYPE(orig) != T_DATA ||
       RDATA(orig)->dfree != (RUBY_DATA_FUNC)grpc_rb_credentials_free) {
-    rb_raise(rb_eTypeError, "not a %s", rb_obj_classname(rb_cCredentials));
+    rb_raise(rb_eTypeError, "not a %s", rb_obj_classname(grpc_rb_cCredentials));
   }
 
   Data_Get_Struct(orig, grpc_rb_credentials, orig_cred);
@@ -178,7 +178,7 @@ static VALUE grpc_rb_composite_credentials_create(VALUE self, VALUE other) {
   }
 
   wrapper->mark = Qnil;
-  return Data_Wrap_Struct(rb_cCredentials, grpc_rb_credentials_mark,
+  return Data_Wrap_Struct(grpc_rb_cCredentials, grpc_rb_credentials_mark,
                           grpc_rb_credentials_free, wrapper);
 }
 
@@ -242,30 +242,31 @@ static VALUE grpc_rb_credentials_init(int argc, VALUE *argv, VALUE self) {
   return self;
 }
 
-/* rb_cCredentials is the ruby class that proxies grpc_credentials. */
-VALUE rb_cCredentials = Qnil;
+/* grpc_rb_cCredentials is the ruby class that proxies grpc_credentials. */
+VALUE grpc_rb_cCredentials = Qnil;
 
 void Init_grpc_credentials() {
-  rb_cCredentials =
-      rb_define_class_under(rb_mGrpcCore, "Credentials", rb_cObject);
+  grpc_rb_cCredentials =
+      rb_define_class_under(grpc_rb_mGrpcCore, "Credentials", rb_cObject);
 
   /* Allocates an object managed by the ruby runtime */
-  rb_define_alloc_func(rb_cCredentials, grpc_rb_credentials_alloc);
+  rb_define_alloc_func(grpc_rb_cCredentials, grpc_rb_credentials_alloc);
 
   /* Provides a ruby constructor and support for dup/clone. */
-  rb_define_method(rb_cCredentials, "initialize", grpc_rb_credentials_init, -1);
-  rb_define_method(rb_cCredentials, "initialize_copy",
+  rb_define_method(grpc_rb_cCredentials, "initialize",
+                   grpc_rb_credentials_init, -1);
+  rb_define_method(grpc_rb_cCredentials, "initialize_copy",
                    grpc_rb_credentials_init_copy, 1);
 
   /* Provide static funcs that create new special instances. */
-  rb_define_singleton_method(rb_cCredentials, "default",
+  rb_define_singleton_method(grpc_rb_cCredentials, "default",
                              grpc_rb_default_credentials_create, 0);
 
-  rb_define_singleton_method(rb_cCredentials, "compute_engine",
+  rb_define_singleton_method(grpc_rb_cCredentials, "compute_engine",
                              grpc_rb_compute_engine_credentials_create, 0);
 
   /* Provide other methods. */
-  rb_define_method(rb_cCredentials, "compose",
+  rb_define_method(grpc_rb_cCredentials, "compose",
                    grpc_rb_composite_credentials_create, 1);
 
   id_pem_cert_chain = rb_intern("__pem_cert_chain");
diff --git a/src/ruby/ext/grpc/rb_credentials.h b/src/ruby/ext/grpc/rb_credentials.h
index 3b24397173639725f497006e7b7044556a7e23d2..dc0a3d01e81b99194534f412dade71747c552369 100644
--- a/src/ruby/ext/grpc/rb_credentials.h
+++ b/src/ruby/ext/grpc/rb_credentials.h
@@ -37,9 +37,9 @@
 #include <ruby.h>
 #include <grpc/grpc_security.h>
 
-/* rb_cCredentials is the ruby class whose instances proxy
+/* grpc_rb_cCredentials is the ruby class whose instances proxy
    grpc_credentials. */
-extern VALUE rb_cCredentials;
+extern VALUE grpc_rb_cCredentials;
 
 /* Initializes the ruby Credentials class. */
 void Init_grpc_credentials();
diff --git a/src/ruby/ext/grpc/rb_event.c b/src/ruby/ext/grpc/rb_event.c
deleted file mode 100644
index 2e64af4c847cac31b4b9daea0128de4394375abd..0000000000000000000000000000000000000000
--- a/src/ruby/ext/grpc/rb_event.c
+++ /dev/null
@@ -1,361 +0,0 @@
-/*
- *
- * Copyright 2015, Google Inc.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- *     * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *     * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#include "rb_event.h"
-
-#include <ruby.h>
-
-#include <grpc/grpc.h>
-#include "rb_grpc.h"
-#include "rb_byte_buffer.h"
-#include "rb_call.h"
-#include "rb_metadata.h"
-
-/* grpc_rb_event wraps a grpc_event.  It provides a peer ruby object,
- * 'mark' to minimize copying when an event is created from ruby. */
-typedef struct grpc_rb_event {
-  /* Holder of ruby objects involved in constructing the channel */
-  VALUE mark;
-  /* The actual event */
-  grpc_event *wrapped;
-} grpc_rb_event;
-
-/* rb_mCompletionType is a ruby module that holds the completion type values */
-VALUE rb_mCompletionType = Qnil;
-
-/* Destroys Event instances. */
-static void grpc_rb_event_free(void *p) {
-  grpc_rb_event *ev = NULL;
-  if (p == NULL) {
-    return;
-  };
-  ev = (grpc_rb_event *)p;
-
-  /* Deletes the wrapped object if the mark object is Qnil, which indicates
-   * that no other object is the actual owner. */
-  if (ev->wrapped != NULL && ev->mark == Qnil) {
-    grpc_event_finish(ev->wrapped);
-    rb_warning("event gc: destroyed the c event");
-  } else {
-    rb_warning("event gc: did not destroy the c event");
-  }
-
-  xfree(p);
-}
-
-/* Protects the mark object from GC */
-static void grpc_rb_event_mark(void *p) {
-  grpc_rb_event *event = NULL;
-  if (p == NULL) {
-    return;
-  }
-  event = (grpc_rb_event *)p;
-  if (event->mark != Qnil) {
-    rb_gc_mark(event->mark);
-  }
-}
-
-static VALUE grpc_rb_event_result(VALUE self);
-
-/* Obtains the type of an event. */
-static VALUE grpc_rb_event_type(VALUE self) {
-  grpc_event *event = NULL;
-  grpc_rb_event *wrapper = NULL;
-  Data_Get_Struct(self, grpc_rb_event, wrapper);
-  if (wrapper->wrapped == NULL) {
-    rb_raise(rb_eRuntimeError, "finished!");
-    return Qnil;
-  }
-
-  event = wrapper->wrapped;
-  switch (event->type) {
-    case GRPC_QUEUE_SHUTDOWN:
-      return rb_const_get(rb_mCompletionType, rb_intern("QUEUE_SHUTDOWN"));
-
-    case GRPC_READ:
-      return rb_const_get(rb_mCompletionType, rb_intern("READ"));
-
-    case GRPC_WRITE_ACCEPTED:
-      grpc_rb_event_result(self); /* validates the result */
-      return rb_const_get(rb_mCompletionType, rb_intern("WRITE_ACCEPTED"));
-
-    case GRPC_FINISH_ACCEPTED:
-      grpc_rb_event_result(self); /* validates the result */
-      return rb_const_get(rb_mCompletionType, rb_intern("FINISH_ACCEPTED"));
-
-    case GRPC_CLIENT_METADATA_READ:
-      return rb_const_get(rb_mCompletionType,
-                          rb_intern("CLIENT_METADATA_READ"));
-
-    case GRPC_FINISHED:
-      return rb_const_get(rb_mCompletionType, rb_intern("FINISHED"));
-
-    case GRPC_SERVER_RPC_NEW:
-      return rb_const_get(rb_mCompletionType, rb_intern("SERVER_RPC_NEW"));
-
-    default:
-      rb_raise(rb_eRuntimeError, "unrecognized event code for an rpc event:%d",
-               event->type);
-  }
-  return Qnil; /* should not be reached */
-}
-
-/* Obtains the tag associated with an event. */
-static VALUE grpc_rb_event_tag(VALUE self) {
-  grpc_event *event = NULL;
-  grpc_rb_event *wrapper = NULL;
-  Data_Get_Struct(self, grpc_rb_event, wrapper);
-  if (wrapper->wrapped == NULL) {
-    rb_raise(rb_eRuntimeError, "finished!");
-    return Qnil;
-  }
-
-  event = wrapper->wrapped;
-  if (event->tag == NULL) {
-    return Qnil;
-  }
-  return (VALUE)event->tag;
-}
-
-/* Obtains the call associated with an event. */
-static VALUE grpc_rb_event_call(VALUE self) {
-  grpc_event *event = NULL;
-  grpc_rb_event *wrapper = NULL;
-  Data_Get_Struct(self, grpc_rb_event, wrapper);
-  if (wrapper->wrapped == NULL) {
-    rb_raise(rb_eRuntimeError, "finished!");
-    return Qnil;
-  }
-
-  event = wrapper->wrapped;
-  if (event->call != NULL) {
-    return grpc_rb_wrap_call(event->call);
-  }
-  return Qnil;
-}
-
-/* Obtains the metadata associated with an event. */
-static VALUE grpc_rb_event_metadata(VALUE self) {
-  grpc_event *event = NULL;
-  grpc_rb_event *wrapper = NULL;
-  grpc_metadata *metadata = NULL;
-  VALUE key = Qnil;
-  VALUE new_ary = Qnil;
-  VALUE result = Qnil;
-  VALUE value = Qnil;
-  size_t count = 0;
-  size_t i = 0;
-  Data_Get_Struct(self, grpc_rb_event, wrapper);
-  if (wrapper->wrapped == NULL) {
-    rb_raise(rb_eRuntimeError, "finished!");
-    return Qnil;
-  }
-
-  /* Figure out which metadata to read. */
-  event = wrapper->wrapped;
-  switch (event->type) {
-    case GRPC_CLIENT_METADATA_READ:
-      count = event->data.client_metadata_read.count;
-      metadata = event->data.client_metadata_read.elements;
-      break;
-
-    case GRPC_FINISHED:
-      count = event->data.finished.metadata_count;
-      metadata = event->data.finished.metadata_elements;
-      break;
-
-    case GRPC_SERVER_RPC_NEW:
-      count = event->data.server_rpc_new.metadata_count;
-      metadata = event->data.server_rpc_new.metadata_elements;
-      break;
-
-    default:
-      rb_raise(rb_eRuntimeError,
-               "bug: bad event type metadata. got %d; want %d|%d:%d",
-               event->type, GRPC_CLIENT_METADATA_READ, GRPC_FINISHED,
-               GRPC_SERVER_RPC_NEW);
-      return Qnil;
-  }
-
-  result = rb_hash_new();
-  for (i = 0; i < count; i++) {
-    key = rb_str_new2(metadata[i].key);
-    value = rb_hash_aref(result, key);
-    if (value == Qnil) {
-      value = rb_str_new(metadata[i].value, metadata[i].value_length);
-      rb_hash_aset(result, key, value);
-    } else if (TYPE(value) == T_ARRAY) {
-      /* Add the string to the returned array */
-      rb_ary_push(value,
-                  rb_str_new(metadata[i].value, metadata[i].value_length));
-    } else {
-      /* Add the current value with this key and the new one to an array */
-      new_ary = rb_ary_new();
-      rb_ary_push(new_ary, value);
-      rb_ary_push(new_ary,
-                  rb_str_new(metadata[i].value, metadata[i].value_length));
-      rb_hash_aset(result, key, new_ary);
-    }
-  }
-  return result;
-}
-
-/* Obtains the data associated with an event. */
-static VALUE grpc_rb_event_result(VALUE self) {
-  grpc_event *event = NULL;
-  grpc_rb_event *wrapper = NULL;
-  Data_Get_Struct(self, grpc_rb_event, wrapper);
-  if (wrapper->wrapped == NULL) {
-    rb_raise(rb_eRuntimeError, "finished!");
-    return Qnil;
-  }
-  event = wrapper->wrapped;
-
-  switch (event->type) {
-    case GRPC_QUEUE_SHUTDOWN:
-      return Qnil;
-
-    case GRPC_READ:
-      return grpc_rb_byte_buffer_create_with_mark(self, event->data.read);
-
-    case GRPC_FINISH_ACCEPTED:
-      if (event->data.finish_accepted == GRPC_OP_OK) {
-        return Qnil;
-      }
-      rb_raise(rb_eEventError, "finish failed, not sure why (code=%d)",
-               event->data.finish_accepted);
-      break;
-
-    case GRPC_WRITE_ACCEPTED:
-      if (event->data.write_accepted == GRPC_OP_OK) {
-        return Qnil;
-      }
-      rb_raise(rb_eEventError, "write failed, not sure why (code=%d)",
-               event->data.write_accepted);
-      break;
-
-    case GRPC_CLIENT_METADATA_READ:
-      return grpc_rb_event_metadata(self);
-
-    case GRPC_FINISHED:
-      return rb_struct_new(rb_sStatus, UINT2NUM(event->data.finished.status),
-                           (event->data.finished.details == NULL
-                                ? Qnil
-                                : rb_str_new2(event->data.finished.details)),
-                           grpc_rb_event_metadata(self), NULL);
-      break;
-
-    case GRPC_SERVER_RPC_NEW:
-      return rb_struct_new(
-          rb_sNewServerRpc, rb_str_new2(event->data.server_rpc_new.method),
-          rb_str_new2(event->data.server_rpc_new.host),
-          Data_Wrap_Struct(rb_cTimeVal, GC_NOT_MARKED, GC_DONT_FREE,
-                           (void *)&event->data.server_rpc_new.deadline),
-          grpc_rb_event_metadata(self), NULL);
-
-    default:
-      rb_raise(rb_eRuntimeError, "unrecognized event code for an rpc event:%d",
-               event->type);
-  }
-
-  return Qfalse;
-}
-
-static VALUE grpc_rb_event_finish(VALUE self) {
-  grpc_event *event = NULL;
-  grpc_rb_event *wrapper = NULL;
-  Data_Get_Struct(self, grpc_rb_event, wrapper);
-  if (wrapper->wrapped == NULL) { /* already closed  */
-    return Qnil;
-  }
-  event = wrapper->wrapped;
-  grpc_event_finish(event);
-  wrapper->wrapped = NULL;
-  wrapper->mark = Qnil;
-  return Qnil;
-}
-
-/* rb_cEvent is the Event class whose instances proxy grpc_event */
-VALUE rb_cEvent = Qnil;
-
-/* rb_eEventError is the ruby class of the exception thrown on failures during
-   rpc event processing. */
-VALUE rb_eEventError = Qnil;
-
-void Init_grpc_event() {
-  rb_eEventError =
-      rb_define_class_under(rb_mGrpcCore, "EventError", rb_eStandardError);
-  rb_cEvent = rb_define_class_under(rb_mGrpcCore, "Event", rb_cObject);
-
-  /* Prevent allocation or inialization from ruby. */
-  rb_define_alloc_func(rb_cEvent, grpc_rb_cannot_alloc);
-  rb_define_method(rb_cEvent, "initialize", grpc_rb_cannot_init, 0);
-  rb_define_method(rb_cEvent, "initialize_copy", grpc_rb_cannot_init_copy, 1);
-
-  /* Accessors for the data available in an event. */
-  rb_define_method(rb_cEvent, "call", grpc_rb_event_call, 0);
-  rb_define_method(rb_cEvent, "result", grpc_rb_event_result, 0);
-  rb_define_method(rb_cEvent, "tag", grpc_rb_event_tag, 0);
-  rb_define_method(rb_cEvent, "type", grpc_rb_event_type, 0);
-  rb_define_method(rb_cEvent, "finish", grpc_rb_event_finish, 0);
-  rb_define_alias(rb_cEvent, "close", "finish");
-
-  /* Constants representing the completion types */
-  rb_mCompletionType =
-      rb_define_module_under(rb_mGrpcCore, "CompletionType");
-  rb_define_const(rb_mCompletionType, "QUEUE_SHUTDOWN",
-                  INT2NUM(GRPC_QUEUE_SHUTDOWN));
-  rb_define_const(rb_mCompletionType, "OP_COMPLETE", INT2NUM(GRPC_OP_COMPLETE));
-  rb_define_const(rb_mCompletionType, "READ", INT2NUM(GRPC_READ));
-  rb_define_const(rb_mCompletionType, "WRITE_ACCEPTED",
-                  INT2NUM(GRPC_WRITE_ACCEPTED));
-  rb_define_const(rb_mCompletionType, "FINISH_ACCEPTED",
-                  INT2NUM(GRPC_FINISH_ACCEPTED));
-  rb_define_const(rb_mCompletionType, "CLIENT_METADATA_READ",
-                  INT2NUM(GRPC_CLIENT_METADATA_READ));
-  rb_define_const(rb_mCompletionType, "FINISHED", INT2NUM(GRPC_FINISHED));
-  rb_define_const(rb_mCompletionType, "SERVER_RPC_NEW",
-                  INT2NUM(GRPC_SERVER_RPC_NEW));
-  rb_define_const(rb_mCompletionType, "SERVER_SHUTDOWN",
-                  INT2NUM(GRPC_SERVER_SHUTDOWN));
-  rb_define_const(rb_mCompletionType, "RESERVED",
-                  INT2NUM(GRPC_COMPLETION_DO_NOT_USE));
-}
-
-VALUE grpc_rb_new_event(grpc_event *ev) {
-  grpc_rb_event *wrapper = ALLOC(grpc_rb_event);
-  wrapper->wrapped = ev;
-  wrapper->mark = Qnil;
-  return Data_Wrap_Struct(rb_cEvent, grpc_rb_event_mark, grpc_rb_event_free,
-                          wrapper);
-}
diff --git a/src/ruby/ext/grpc/rb_grpc.c b/src/ruby/ext/grpc/rb_grpc.c
index 400efd0dfad8d3909e7fe4049a3e6ebef235f351..4f30a6216a3514727dedefb694d3da8ded98df8a 100644
--- a/src/ruby/ext/grpc/rb_grpc.c
+++ b/src/ruby/ext/grpc/rb_grpc.c
@@ -39,12 +39,9 @@
 
 #include <grpc/grpc.h>
 #include <grpc/support/time.h>
-#include "rb_byte_buffer.h"
 #include "rb_call.h"
 #include "rb_channel.h"
 #include "rb_completion_queue.h"
-#include "rb_event.h"
-#include "rb_metadata.h"
 #include "rb_server.h"
 #include "rb_credentials.h"
 #include "rb_server_credentials.h"
@@ -53,7 +50,7 @@
 const RUBY_DATA_FUNC GC_NOT_MARKED = NULL;
 const RUBY_DATA_FUNC GC_DONT_FREE = NULL;
 
-VALUE rb_cTimeVal = Qnil;
+VALUE grpc_rb_cTimeVal = Qnil;
 
 /* Alloc func that blocks allocation of a given object by raising an
  * exception. */
@@ -99,7 +96,7 @@ gpr_timespec grpc_rb_time_timeval(VALUE time, int interval) {
 
   switch (TYPE(time)) {
     case T_DATA:
-      if (CLASS_OF(time) == rb_cTimeVal) {
+      if (CLASS_OF(time) == grpc_rb_cTimeVal) {
         Data_Get_Struct(time, gpr_timespec, time_const);
         t = *time_const;
       } else if (CLASS_OF(time) == rb_cTime) {
@@ -155,35 +152,41 @@ gpr_timespec grpc_rb_time_timeval(VALUE time, int interval) {
 
 void Init_grpc_status_codes() {
   /* Constants representing the status codes or grpc_status_code in status.h */
-  VALUE rb_mStatusCodes =
-      rb_define_module_under(rb_mGrpcCore, "StatusCodes");
-  rb_define_const(rb_mStatusCodes, "OK", INT2NUM(GRPC_STATUS_OK));
-  rb_define_const(rb_mStatusCodes, "CANCELLED", INT2NUM(GRPC_STATUS_CANCELLED));
-  rb_define_const(rb_mStatusCodes, "UNKNOWN", INT2NUM(GRPC_STATUS_UNKNOWN));
-  rb_define_const(rb_mStatusCodes, "INVALID_ARGUMENT",
+  VALUE grpc_rb_mStatusCodes =
+      rb_define_module_under(grpc_rb_mGrpcCore, "StatusCodes");
+  rb_define_const(grpc_rb_mStatusCodes, "OK", INT2NUM(GRPC_STATUS_OK));
+  rb_define_const(grpc_rb_mStatusCodes, "CANCELLED",
+                  INT2NUM(GRPC_STATUS_CANCELLED));
+  rb_define_const(grpc_rb_mStatusCodes, "UNKNOWN",
+                  INT2NUM(GRPC_STATUS_UNKNOWN));
+  rb_define_const(grpc_rb_mStatusCodes, "INVALID_ARGUMENT",
                   INT2NUM(GRPC_STATUS_INVALID_ARGUMENT));
-  rb_define_const(rb_mStatusCodes, "DEADLINE_EXCEEDED",
+  rb_define_const(grpc_rb_mStatusCodes, "DEADLINE_EXCEEDED",
                   INT2NUM(GRPC_STATUS_DEADLINE_EXCEEDED));
-  rb_define_const(rb_mStatusCodes, "NOT_FOUND", INT2NUM(GRPC_STATUS_NOT_FOUND));
-  rb_define_const(rb_mStatusCodes, "ALREADY_EXISTS",
+  rb_define_const(grpc_rb_mStatusCodes, "NOT_FOUND",
+                  INT2NUM(GRPC_STATUS_NOT_FOUND));
+  rb_define_const(grpc_rb_mStatusCodes, "ALREADY_EXISTS",
                   INT2NUM(GRPC_STATUS_ALREADY_EXISTS));
-  rb_define_const(rb_mStatusCodes, "PERMISSION_DENIED",
+  rb_define_const(grpc_rb_mStatusCodes, "PERMISSION_DENIED",
                   INT2NUM(GRPC_STATUS_PERMISSION_DENIED));
-  rb_define_const(rb_mStatusCodes, "UNAUTHENTICATED",
+  rb_define_const(grpc_rb_mStatusCodes, "UNAUTHENTICATED",
                   INT2NUM(GRPC_STATUS_UNAUTHENTICATED));
-  rb_define_const(rb_mStatusCodes, "RESOURCE_EXHAUSTED",
+  rb_define_const(grpc_rb_mStatusCodes, "RESOURCE_EXHAUSTED",
                   INT2NUM(GRPC_STATUS_RESOURCE_EXHAUSTED));
-  rb_define_const(rb_mStatusCodes, "FAILED_PRECONDITION",
+  rb_define_const(grpc_rb_mStatusCodes, "FAILED_PRECONDITION",
                   INT2NUM(GRPC_STATUS_FAILED_PRECONDITION));
-  rb_define_const(rb_mStatusCodes, "ABORTED", INT2NUM(GRPC_STATUS_ABORTED));
-  rb_define_const(rb_mStatusCodes, "OUT_OF_RANGE",
+  rb_define_const(grpc_rb_mStatusCodes, "ABORTED",
+                  INT2NUM(GRPC_STATUS_ABORTED));
+  rb_define_const(grpc_rb_mStatusCodes, "OUT_OF_RANGE",
                   INT2NUM(GRPC_STATUS_OUT_OF_RANGE));
-  rb_define_const(rb_mStatusCodes, "UNIMPLEMENTED",
+  rb_define_const(grpc_rb_mStatusCodes, "UNIMPLEMENTED",
                   INT2NUM(GRPC_STATUS_UNIMPLEMENTED));
-  rb_define_const(rb_mStatusCodes, "INTERNAL", INT2NUM(GRPC_STATUS_INTERNAL));
-  rb_define_const(rb_mStatusCodes, "UNAVAILABLE",
+  rb_define_const(grpc_rb_mStatusCodes, "INTERNAL",
+                  INT2NUM(GRPC_STATUS_INTERNAL));
+  rb_define_const(grpc_rb_mStatusCodes, "UNAVAILABLE",
                   INT2NUM(GRPC_STATUS_UNAVAILABLE));
-  rb_define_const(rb_mStatusCodes, "DATA_LOSS", INT2NUM(GRPC_STATUS_DATA_LOSS));
+  rb_define_const(grpc_rb_mStatusCodes, "DATA_LOSS",
+                  INT2NUM(GRPC_STATUS_DATA_LOSS));
 }
 
 /* id_at is the constructor method of the ruby standard Time class. */
@@ -195,7 +198,7 @@ static ID id_inspect;
 /* id_to_s is the to_s method found on various ruby objects. */
 static ID id_to_s;
 
-/* Converts `a wrapped time constant to a standard time. */
+/* Converts a wrapped time constant to a standard time. */
 VALUE grpc_rb_time_val_to_time(VALUE self) {
   gpr_timespec *time_const = NULL;
   Data_Get_Struct(self, gpr_timespec, time_const);
@@ -215,22 +218,25 @@ VALUE grpc_rb_time_val_to_s(VALUE self) {
 
 /* Adds a module with constants that map to gpr's static timeval structs. */
 void Init_grpc_time_consts() {
-  VALUE rb_mTimeConsts =
-      rb_define_module_under(rb_mGrpcCore, "TimeConsts");
-  rb_cTimeVal =
-      rb_define_class_under(rb_mGrpcCore, "TimeSpec", rb_cObject);
-  rb_define_const(rb_mTimeConsts, "ZERO",
-                  Data_Wrap_Struct(rb_cTimeVal, GC_NOT_MARKED, GC_DONT_FREE,
+  VALUE grpc_rb_mTimeConsts =
+      rb_define_module_under(grpc_rb_mGrpcCore, "TimeConsts");
+  grpc_rb_cTimeVal =
+      rb_define_class_under(grpc_rb_mGrpcCore, "TimeSpec", rb_cObject);
+  rb_define_const(grpc_rb_mTimeConsts, "ZERO",
+                  Data_Wrap_Struct(grpc_rb_cTimeVal,
+                                   GC_NOT_MARKED, GC_DONT_FREE,
                                    (void *)&gpr_time_0));
-  rb_define_const(rb_mTimeConsts, "INFINITE_FUTURE",
-                  Data_Wrap_Struct(rb_cTimeVal, GC_NOT_MARKED, GC_DONT_FREE,
+  rb_define_const(grpc_rb_mTimeConsts, "INFINITE_FUTURE",
+                  Data_Wrap_Struct(grpc_rb_cTimeVal,
+                                   GC_NOT_MARKED, GC_DONT_FREE,
                                    (void *)&gpr_inf_future));
-  rb_define_const(rb_mTimeConsts, "INFINITE_PAST",
-                  Data_Wrap_Struct(rb_cTimeVal, GC_NOT_MARKED, GC_DONT_FREE,
+  rb_define_const(grpc_rb_mTimeConsts, "INFINITE_PAST",
+                  Data_Wrap_Struct(grpc_rb_cTimeVal,
+                                   GC_NOT_MARKED, GC_DONT_FREE,
                                    (void *)&gpr_inf_past));
-  rb_define_method(rb_cTimeVal, "to_time", grpc_rb_time_val_to_time, 0);
-  rb_define_method(rb_cTimeVal, "inspect", grpc_rb_time_val_inspect, 0);
-  rb_define_method(rb_cTimeVal, "to_s", grpc_rb_time_val_to_s, 0);
+  rb_define_method(grpc_rb_cTimeVal, "to_time", grpc_rb_time_val_to_time, 0);
+  rb_define_method(grpc_rb_cTimeVal, "inspect", grpc_rb_time_val_inspect, 0);
+  rb_define_method(grpc_rb_cTimeVal, "to_s", grpc_rb_time_val_to_s, 0);
   id_at = rb_intern("at");
   id_inspect = rb_intern("inspect");
   id_to_s = rb_intern("to_s");
@@ -242,31 +248,33 @@ void grpc_rb_shutdown(void *vm) { grpc_shutdown(); }
 
 /* Initialize the GRPC module structs */
 
-/* rb_sNewServerRpc is the struct that holds new server rpc details. */
-VALUE rb_sNewServerRpc = Qnil;
-/* rb_sStatus is the struct that holds status details. */
-VALUE rb_sStatus = Qnil;
+/* grpc_rb_sNewServerRpc is the struct that holds new server rpc details. */
+VALUE grpc_rb_sNewServerRpc = Qnil;
+/* grpc_rb_sStatus is the struct that holds status details. */
+VALUE grpc_rb_sStatus = Qnil;
 
 /* Initialize the GRPC module. */
-VALUE rb_mGRPC = Qnil;
-VALUE rb_mGrpcCore = Qnil;
+VALUE grpc_rb_mGRPC = Qnil;
+VALUE grpc_rb_mGrpcCore = Qnil;
 
 void Init_grpc() {
   grpc_init();
   ruby_vm_at_exit(grpc_rb_shutdown);
-  rb_mGRPC = rb_define_module("GRPC");
-  rb_mGrpcCore = rb_define_module_under(rb_mGRPC, "Core");
-  rb_sNewServerRpc = rb_struct_define("NewServerRpc", "method", "host",
-                                      "deadline", "metadata", NULL);
-  rb_sStatus = rb_struct_define("Status", "code", "details", "metadata", NULL);
+  grpc_rb_mGRPC = rb_define_module("GRPC");
+  grpc_rb_mGrpcCore = rb_define_module_under(grpc_rb_mGRPC, "Core");
+  grpc_rb_sNewServerRpc =
+      rb_struct_define("NewServerRpc", "method", "host",
+                       "deadline", "metadata", "call", NULL);
+  grpc_rb_sStatus =
+      rb_struct_define("Status", "code", "details", "metadata", NULL);
+  sym_code = ID2SYM(rb_intern("code"));
+  sym_details = ID2SYM(rb_intern("details"));
+  sym_metadata = ID2SYM(rb_intern("metadata"));
 
-  Init_grpc_byte_buffer();
-  Init_grpc_event();
   Init_grpc_channel();
   Init_grpc_completion_queue();
   Init_grpc_call();
   Init_grpc_credentials();
-  Init_grpc_metadata();
   Init_grpc_server();
   Init_grpc_server_credentials();
   Init_grpc_status_codes();
diff --git a/src/ruby/ext/grpc/rb_grpc.h b/src/ruby/ext/grpc/rb_grpc.h
index 851f5ee69fa67c864e6c17fc9b5c79ccbe8de4a3..3a93029556f53997f305794abfad72048f1c165f 100644
--- a/src/ruby/ext/grpc/rb_grpc.h
+++ b/src/ruby/ext/grpc/rb_grpc.h
@@ -38,17 +38,26 @@
 #include <ruby.h>
 #include <grpc/support/time.h>
 
-/* rb_mGrpcCore is the module containing the ruby wrapper GRPC classes. */
-extern VALUE rb_mGrpcCore;
+/* grpc_rb_mGrpcCore is the module containing the ruby wrapper GRPC classes. */
+extern VALUE grpc_rb_mGrpcCore;
 
 /* Class used to wrap timeval structs. */
-extern VALUE rb_cTimeVal;
+extern VALUE grpc_rb_cTimeVal;
 
-/* rb_sNewServerRpc is the struct that holds new server rpc details. */
-extern VALUE rb_sNewServerRpc;
+/* grpc_rb_sNewServerRpc is the struct that holds new server rpc details. */
+extern VALUE grpc_rb_sNewServerRpc;
 
-/* rb_sStruct is the struct that holds status details. */
-extern VALUE rb_sStatus;
+/* grpc_rb_sStruct is the struct that holds status details. */
+extern VALUE grpc_rb_sStatus;
+
+/* sym_code is the symbol for the code attribute of grpc_rb_sStatus. */
+VALUE sym_code;
+
+/* sym_details is the symbol for the details attribute of grpc_rb_sStatus. */
+VALUE sym_details;
+
+/* sym_metadata is the symbol for the metadata attribute of grpc_rb_sStatus. */
+VALUE sym_metadata;
 
 /* GC_NOT_MARKED is used in calls to Data_Wrap_Struct to indicate that the
    wrapped struct does not need to participate in ruby gc. */
diff --git a/src/ruby/ext/grpc/rb_metadata.c b/src/ruby/ext/grpc/rb_metadata.c
deleted file mode 100644
index 7622a8c57ed036f2fefd7d1d6255079cd56b0a3e..0000000000000000000000000000000000000000
--- a/src/ruby/ext/grpc/rb_metadata.c
+++ /dev/null
@@ -1,215 +0,0 @@
-/*
- *
- * Copyright 2015, Google Inc.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- *     * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *     * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#include "rb_metadata.h"
-
-#include <ruby.h>
-#include <string.h>
-
-#include <grpc/grpc.h>
-#include "rb_grpc.h"
-
-/* grpc_rb_metadata wraps a grpc_metadata.  It provides a peer ruby object,
- * 'mark' to minimize copying when a metadata is created from ruby. */
-typedef struct grpc_rb_metadata {
-  /* Holder of ruby objects involved in constructing the metadata */
-  VALUE mark;
-  /* The actual metadata */
-  grpc_metadata *wrapped;
-} grpc_rb_metadata;
-
-/* Destroys Metadata instances. */
-static void grpc_rb_metadata_free(void *p) {
-  if (p == NULL) {
-    return;
-  };
-
-  /* Because metadata is only created during a call to grpc_call_add_metadata,
-   * and the call takes ownership of the metadata, this does not free the
-   * wrapped struct, only the wrapper */
-  xfree(p);
-}
-
-/* Protects the mark object from GC */
-static void grpc_rb_metadata_mark(void *p) {
-  grpc_rb_metadata *md = NULL;
-  if (p == NULL) {
-    return;
-  }
-
-  md = (grpc_rb_metadata *)p;
-  /* If it's not already cleaned up, mark the mark object */
-  if (md->mark != Qnil && BUILTIN_TYPE(md->mark) != T_NONE) {
-    rb_gc_mark(md->mark);
-  }
-}
-
-/* Allocates Metadata instances.
-
-   Provides safe default values for the Metadata fields. */
-static VALUE grpc_rb_metadata_alloc(VALUE cls) {
-  grpc_rb_metadata *wrapper = ALLOC(grpc_rb_metadata);
-  wrapper->wrapped = NULL;
-  wrapper->mark = Qnil;
-  return Data_Wrap_Struct(cls, grpc_rb_metadata_mark, grpc_rb_metadata_free,
-                          wrapper);
-}
-
-/* id_key and id_value are the names of the hidden ivars that preserve the
- * original byte_buffer source string */
-static ID id_key;
-static ID id_value;
-
-/* Initializes Metadata instances. */
-static VALUE grpc_rb_metadata_init(VALUE self, VALUE key, VALUE value) {
-  grpc_rb_metadata *wrapper = NULL;
-  grpc_metadata *md = ALLOC(grpc_metadata);
-
-  /* Use direct pointers to the strings wrapped by the ruby object to avoid
-   * copying */
-  Data_Get_Struct(self, grpc_rb_metadata, wrapper);
-  wrapper->wrapped = md;
-  if (TYPE(key) == T_SYMBOL) {
-    md->key = (char *)rb_id2name(SYM2ID(key));
-  } else { /* StringValueCStr does all other type exclusions for us */
-    md->key = StringValueCStr(key);
-  }
-  md->value = RSTRING_PTR(value);
-  md->value_length = RSTRING_LEN(value);
-
-  /* Save references to the original values on the mark object so that the
-   * pointers used there are valid for the lifetime of the object. */
-  wrapper->mark = rb_class_new_instance(0, NULL, rb_cObject);
-  rb_ivar_set(wrapper->mark, id_key, key);
-  rb_ivar_set(wrapper->mark, id_value, value);
-
-  return self;
-}
-
-/* Clones Metadata instances.
-
-   Gives Metadata a consistent implementation of Ruby's object copy/dup
-   protocol. */
-static VALUE grpc_rb_metadata_init_copy(VALUE copy, VALUE orig) {
-  grpc_rb_metadata *orig_md = NULL;
-  grpc_rb_metadata *copy_md = NULL;
-
-  if (copy == orig) {
-    return copy;
-  }
-
-  /* Raise an error if orig is not a metadata object or a subclass. */
-  if (TYPE(orig) != T_DATA ||
-      RDATA(orig)->dfree != (RUBY_DATA_FUNC)grpc_rb_metadata_free) {
-    rb_raise(rb_eTypeError, "not a %s", rb_obj_classname(rb_cMetadata));
-  }
-
-  Data_Get_Struct(orig, grpc_rb_metadata, orig_md);
-  Data_Get_Struct(copy, grpc_rb_metadata, copy_md);
-
-  /* use ruby's MEMCPY to make a byte-for-byte copy of the metadata wrapper
-   * object. */
-  MEMCPY(copy_md, orig_md, grpc_rb_metadata, 1);
-  return copy;
-}
-
-/* Gets the key from a metadata instance. */
-static VALUE grpc_rb_metadata_key(VALUE self) {
-  VALUE key = Qnil;
-  grpc_rb_metadata *wrapper = NULL;
-  grpc_metadata *md = NULL;
-
-  Data_Get_Struct(self, grpc_rb_metadata, wrapper);
-  if (wrapper->mark != Qnil) {
-    key = rb_ivar_get(wrapper->mark, id_key);
-    if (key != Qnil) {
-      return key;
-    }
-  }
-
-  md = wrapper->wrapped;
-  if (md == NULL || md->key == NULL) {
-    return Qnil;
-  }
-  return rb_str_new2(md->key);
-}
-
-/* Gets the value from a metadata instance. */
-static VALUE grpc_rb_metadata_value(VALUE self) {
-  VALUE val = Qnil;
-  grpc_rb_metadata *wrapper = NULL;
-  grpc_metadata *md = NULL;
-
-  Data_Get_Struct(self, grpc_rb_metadata, wrapper);
-  if (wrapper->mark != Qnil) {
-    val = rb_ivar_get(wrapper->mark, id_value);
-    if (val != Qnil) {
-      return val;
-    }
-  }
-
-  md = wrapper->wrapped;
-  if (md == NULL || md->value == NULL) {
-    return Qnil;
-  }
-  return rb_str_new2(md->value);
-}
-
-/* rb_cMetadata is the Metadata class whose instances proxy grpc_metadata. */
-VALUE rb_cMetadata = Qnil;
-void Init_grpc_metadata() {
-  rb_cMetadata =
-      rb_define_class_under(rb_mGrpcCore, "Metadata", rb_cObject);
-
-  /* Allocates an object managed by the ruby runtime */
-  rb_define_alloc_func(rb_cMetadata, grpc_rb_metadata_alloc);
-
-  /* Provides a ruby constructor and support for dup/clone. */
-  rb_define_method(rb_cMetadata, "initialize", grpc_rb_metadata_init, 2);
-  rb_define_method(rb_cMetadata, "initialize_copy", grpc_rb_metadata_init_copy,
-                   1);
-
-  /* Provides accessors for the code and details. */
-  rb_define_method(rb_cMetadata, "key", grpc_rb_metadata_key, 0);
-  rb_define_method(rb_cMetadata, "value", grpc_rb_metadata_value, 0);
-
-  id_key = rb_intern("__key");
-  id_value = rb_intern("__value");
-}
-
-/* Gets the wrapped metadata from the ruby wrapper */
-grpc_metadata *grpc_rb_get_wrapped_metadata(VALUE v) {
-  grpc_rb_metadata *wrapper = NULL;
-  Data_Get_Struct(v, grpc_rb_metadata, wrapper);
-  return wrapper->wrapped;
-}
diff --git a/src/ruby/ext/grpc/rb_server.c b/src/ruby/ext/grpc/rb_server.c
index c54f02e87afac11a2ea8f3c4a28406a460fe51dd..33d9d695008de2adbff78b2a324a03fc6a3418ac 100644
--- a/src/ruby/ext/grpc/rb_server.c
+++ b/src/ruby/ext/grpc/rb_server.c
@@ -43,8 +43,11 @@
 #include "rb_server_credentials.h"
 #include "rb_grpc.h"
 
-/* rb_cServer is the ruby class that proxies grpc_server. */
-VALUE rb_cServer = Qnil;
+/* grpc_rb_cServer is the ruby class that proxies grpc_server. */
+VALUE grpc_rb_cServer = Qnil;
+
+/* id_at is the constructor method of the ruby standard Time class. */
+static ID id_at;
 
 /* grpc_rb_server wraps a grpc_server.  It provides a peer ruby object,
   'mark' to minimize copying when a server is created from ruby. */
@@ -140,7 +143,7 @@ static VALUE grpc_rb_server_init_copy(VALUE copy, VALUE orig) {
   /* Raise an error if orig is not a server object or a subclass. */
   if (TYPE(orig) != T_DATA ||
       RDATA(orig)->dfree != (RUBY_DATA_FUNC)grpc_rb_server_free) {
-    rb_raise(rb_eTypeError, "not a %s", rb_obj_classname(rb_cServer));
+    rb_raise(rb_eTypeError, "not a %s", rb_obj_classname(grpc_rb_cServer));
   }
 
   Data_Get_Struct(orig, grpc_rb_server, orig_srv);
@@ -152,18 +155,90 @@ static VALUE grpc_rb_server_init_copy(VALUE copy, VALUE orig) {
   return copy;
 }
 
-static VALUE grpc_rb_server_request_call(VALUE self, VALUE tag_new) {
-  grpc_call_error err;
+/* request_call_stack holds various values used by the
+ * grpc_rb_server_request_call function */
+typedef struct request_call_stack {
+  grpc_call_details details;
+  grpc_metadata_array md_ary;
+} request_call_stack;
+
+/* grpc_request_call_stack_init ensures the request_call_stack is properly
+ * initialized */
+static void grpc_request_call_stack_init(request_call_stack* st) {
+  MEMZERO(st, request_call_stack, 1);
+  grpc_metadata_array_init(&st->md_ary);
+  grpc_call_details_init(&st->details);
+  st->details.method = NULL;
+  st->details.host = NULL;
+}
+
+/* grpc_request_call_stack_cleanup ensures the request_call_stack is properly
+ * cleaned up */
+static void grpc_request_call_stack_cleanup(request_call_stack* st) {
+  grpc_metadata_array_destroy(&st->md_ary);
+  grpc_call_details_destroy(&st->details);
+}
+
+/* call-seq:
+   cq = CompletionQueue.new
+   tag = Object.new
+   timeout = 10
+   server.request_call(cqueue, tag, timeout)
+
+   Requests notification of a new call on a server. */
+static VALUE grpc_rb_server_request_call(VALUE self, VALUE cqueue,
+                                         VALUE tag_new, VALUE timeout) {
   grpc_rb_server *s = NULL;
+  grpc_call *call = NULL;
+  grpc_event *ev = NULL;
+  grpc_call_error err;
+  request_call_stack st;
+  VALUE result;
   Data_Get_Struct(self, grpc_rb_server, s);
   if (s->wrapped == NULL) {
     rb_raise(rb_eRuntimeError, "closed!");
+    return Qnil;
   } else {
-    err = grpc_server_request_call_old(s->wrapped, ROBJECT(tag_new));
+    grpc_request_call_stack_init(&st);
+    /* call grpc_server_request_call, then wait for it to complete using
+     * pluck_event */
+    err = grpc_server_request_call(
+        s->wrapped, &call, &st.details, &st.md_ary,
+        grpc_rb_get_wrapped_completion_queue(cqueue),
+        ROBJECT(tag_new));
     if (err != GRPC_CALL_OK) {
-      rb_raise(rb_eCallError, "server request failed: %s (code=%d)",
+      grpc_request_call_stack_cleanup(&st);
+      rb_raise(grpc_rb_eCallError,
+              "grpc_server_request_call failed: %s (code=%d)",
                grpc_call_error_detail_of(err), err);
+      return Qnil;
     }
+    ev = grpc_rb_completion_queue_pluck_event(cqueue, tag_new, timeout);
+    if (ev == NULL) {
+      grpc_request_call_stack_cleanup(&st);
+      return Qnil;
+    }
+    if (ev->data.op_complete != GRPC_OP_OK) {
+      grpc_request_call_stack_cleanup(&st);
+      grpc_event_finish(ev);
+      rb_raise(grpc_rb_eCallError, "request_call completion failed: (code=%d)",
+               ev->data.op_complete);
+      return Qnil;
+    }
+
+    /* build the NewServerRpc struct result */
+    result = rb_struct_new(
+        grpc_rb_sNewServerRpc,
+        rb_str_new2(st.details.method),
+        rb_str_new2(st.details.host),
+        rb_funcall(rb_cTime, id_at, 2, INT2NUM(st.details.deadline.tv_sec),
+                   INT2NUM(st.details.deadline.tv_nsec)),
+        grpc_rb_md_ary_to_h(&st.md_ary),
+        grpc_rb_wrap_call(call),
+        NULL);
+    grpc_event_finish(ev);
+    grpc_request_call_stack_cleanup(&st);
+    return result;
   }
   return Qnil;
 }
@@ -239,22 +314,27 @@ static VALUE grpc_rb_server_add_http2_port(int argc, VALUE *argv, VALUE self) {
 }
 
 void Init_grpc_server() {
-  rb_cServer = rb_define_class_under(rb_mGrpcCore, "Server", rb_cObject);
+  grpc_rb_cServer =
+      rb_define_class_under(grpc_rb_mGrpcCore, "Server", rb_cObject);
 
   /* Allocates an object managed by the ruby runtime */
-  rb_define_alloc_func(rb_cServer, grpc_rb_server_alloc);
+  rb_define_alloc_func(grpc_rb_cServer, grpc_rb_server_alloc);
 
   /* Provides a ruby constructor and support for dup/clone. */
-  rb_define_method(rb_cServer, "initialize", grpc_rb_server_init, 2);
-  rb_define_method(rb_cServer, "initialize_copy", grpc_rb_server_init_copy, 1);
+  rb_define_method(grpc_rb_cServer, "initialize", grpc_rb_server_init, 2);
+  rb_define_method(grpc_rb_cServer, "initialize_copy",
+                   grpc_rb_server_init_copy, 1);
 
   /* Add the server methods. */
-  rb_define_method(rb_cServer, "request_call", grpc_rb_server_request_call, 1);
-  rb_define_method(rb_cServer, "start", grpc_rb_server_start, 0);
-  rb_define_method(rb_cServer, "destroy", grpc_rb_server_destroy, 0);
-  rb_define_alias(rb_cServer, "close", "destroy");
-  rb_define_method(rb_cServer, "add_http2_port", grpc_rb_server_add_http2_port,
+  rb_define_method(grpc_rb_cServer, "request_call",
+                   grpc_rb_server_request_call, 3);
+  rb_define_method(grpc_rb_cServer, "start", grpc_rb_server_start, 0);
+  rb_define_method(grpc_rb_cServer, "destroy", grpc_rb_server_destroy, 0);
+  rb_define_alias(grpc_rb_cServer, "close", "destroy");
+  rb_define_method(grpc_rb_cServer, "add_http2_port",
+                   grpc_rb_server_add_http2_port,
                    -1);
+  id_at = rb_intern("at");
 }
 
 /* Gets the wrapped server from the ruby wrapper */
diff --git a/src/ruby/ext/grpc/rb_server.h b/src/ruby/ext/grpc/rb_server.h
index 2726b9a50af422e24571d66c67b6536b0b24425a..22e88a7d46e9eb52f172bee882802b9e1b93d48c 100644
--- a/src/ruby/ext/grpc/rb_server.h
+++ b/src/ruby/ext/grpc/rb_server.h
@@ -37,9 +37,9 @@
 #include <ruby.h>
 #include <grpc/grpc.h>
 
-/* rb_cServer is the Server class whose instances proxy
+/* grpc_rb_cServer is the Server class whose instances proxy
    grpc_byte_buffer. */
-extern VALUE rb_cServer;
+extern VALUE grpc_rb_cServer;
 
 /* Initializes the Server class. */
 void Init_grpc_server();
diff --git a/src/ruby/ext/grpc/rb_server_credentials.c b/src/ruby/ext/grpc/rb_server_credentials.c
index fb02987870622e2a1f62bb6a2fd431fa099b06ea..8b813eaca1cfd954aef740562d3f62055a7d3342 100644
--- a/src/ruby/ext/grpc/rb_server_credentials.c
+++ b/src/ruby/ext/grpc/rb_server_credentials.c
@@ -109,7 +109,7 @@ static VALUE grpc_rb_server_credentials_init_copy(VALUE copy, VALUE orig) {
   if (TYPE(orig) != T_DATA ||
       RDATA(orig)->dfree != (RUBY_DATA_FUNC)grpc_rb_server_credentials_free) {
     rb_raise(rb_eTypeError, "not a %s",
-             rb_obj_classname(rb_cServerCredentials));
+             rb_obj_classname(grpc_rb_cServerCredentials));
   }
 
   Data_Get_Struct(orig, grpc_rb_server_credentials, orig_ch);
@@ -180,21 +180,22 @@ static VALUE grpc_rb_server_credentials_init(VALUE self, VALUE pem_root_certs,
   return self;
 }
 
-/* rb_cServerCredentials is the ruby class that proxies
+/* grpc_rb_cServerCredentials is the ruby class that proxies
    grpc_server_credentials. */
-VALUE rb_cServerCredentials = Qnil;
+VALUE grpc_rb_cServerCredentials = Qnil;
 
 void Init_grpc_server_credentials() {
-  rb_cServerCredentials =
-      rb_define_class_under(rb_mGrpcCore, "ServerCredentials", rb_cObject);
+  grpc_rb_cServerCredentials =
+      rb_define_class_under(grpc_rb_mGrpcCore, "ServerCredentials", rb_cObject);
 
   /* Allocates an object managed by the ruby runtime */
-  rb_define_alloc_func(rb_cServerCredentials, grpc_rb_server_credentials_alloc);
+  rb_define_alloc_func(grpc_rb_cServerCredentials,
+                       grpc_rb_server_credentials_alloc);
 
   /* Provides a ruby constructor and support for dup/clone. */
-  rb_define_method(rb_cServerCredentials, "initialize",
+  rb_define_method(grpc_rb_cServerCredentials, "initialize",
                    grpc_rb_server_credentials_init, 3);
-  rb_define_method(rb_cServerCredentials, "initialize_copy",
+  rb_define_method(grpc_rb_cServerCredentials, "initialize_copy",
                    grpc_rb_server_credentials_init_copy, 1);
 
   id_pem_cert_chain = rb_intern("__pem_cert_chain");
diff --git a/src/ruby/ext/grpc/rb_server_credentials.h b/src/ruby/ext/grpc/rb_server_credentials.h
index ef377195a0535b51d2d8e0b5b85c87a346c712fb..f79a8693581ebebfec22cc842e55cbe709af133e 100644
--- a/src/ruby/ext/grpc/rb_server_credentials.h
+++ b/src/ruby/ext/grpc/rb_server_credentials.h
@@ -37,9 +37,9 @@
 #include <ruby.h>
 #include <grpc/grpc_security.h>
 
-/* rb_cServerCredentials is the ruby class whose instances proxy
+/* grpc_rb_cServerCredentials is the ruby class whose instances proxy
    grpc_server_credentials. */
-extern VALUE rb_cServerCredentials;
+extern VALUE grpc_rb_cServerCredentials;
 
 /* Initializes the ruby ServerCredentials class. */
 void Init_grpc_server_credentials();
diff --git a/src/ruby/lib/grpc.rb b/src/ruby/lib/grpc.rb
index dd02ef7666a8d1875931860e19c444882ac40dc2..b0f68035cd6d8dae0653333ac51c98ddaf8c9ee9 100644
--- a/src/ruby/lib/grpc.rb
+++ b/src/ruby/lib/grpc.rb
@@ -31,7 +31,6 @@ require 'grpc/errors'
 require 'grpc/grpc'
 require 'grpc/logconfig'
 require 'grpc/version'
-require 'grpc/core/event'
 require 'grpc/core/time_consts'
 require 'grpc/generic/active_call'
 require 'grpc/generic/client_stub'
diff --git a/src/ruby/lib/grpc/core/event.rb b/src/ruby/lib/grpc/core/event.rb
deleted file mode 100644
index 194aa8ecac93026d5dbffe31c159ccefbbb2a690..0000000000000000000000000000000000000000
--- a/src/ruby/lib/grpc/core/event.rb
+++ /dev/null
@@ -1,44 +0,0 @@
-# Copyright 2015, Google Inc.
-# All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions are
-# met:
-#
-#     * Redistributions of source code must retain the above copyright
-# notice, this list of conditions and the following disclaimer.
-#     * Redistributions in binary form must reproduce the above
-# copyright notice, this list of conditions and the following disclaimer
-# in the documentation and/or other materials provided with the
-# distribution.
-#     * Neither the name of Google Inc. nor the names of its
-# contributors may be used to endorse or promote products derived from
-# this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-require 'grpc'
-
-# GRPC contains the General RPC module.
-module GRPC
-  module Core
-    # Event is a class defined in the c extension
-    #
-    # Here, we add an inspect method.
-    class Event
-      def inspect
-        "<#{self.class}: type:#{type}, tag:#{tag} result:#{result}>"
-      end
-    end
-  end
-end
diff --git a/src/ruby/lib/grpc/errors.rb b/src/ruby/lib/grpc/errors.rb
index 58944872b54196d5e810202c9fc6e60698e32099..b23793730f7b4e96ddd0411e16433c064d0325fb 100644
--- a/src/ruby/lib/grpc/errors.rb
+++ b/src/ruby/lib/grpc/errors.rb
@@ -31,10 +31,6 @@ require 'grpc'
 
 # GRPC contains the General RPC module.
 module GRPC
-  # OutOfTime is an exception class that indicates that an RPC exceeded its
-  # deadline.
-  OutOfTime = Class.new(StandardError)
-
   # BadStatus is an exception class that indicates that an error occurred at
   # either end of a GRPC connection.  When raised, it indicates that a status
   # error should be returned to the other end of a GRPC connection; when
diff --git a/src/ruby/lib/grpc/generic/active_call.rb b/src/ruby/lib/grpc/generic/active_call.rb
index 6256330e88e420a9d1c270b8760e0bdf7a9ffb45..489349c2c996fb4578c0fc0a13563b51d4613413 100644
--- a/src/ruby/lib/grpc/generic/active_call.rb
+++ b/src/ruby/lib/grpc/generic/active_call.rb
@@ -30,20 +30,14 @@
 require 'forwardable'
 require 'grpc/generic/bidi_call'
 
-def assert_event_type(ev, want)
-  fail OutOfTime if ev.nil?
-  got = ev.type
-  fail "Unexpected rpc event: got #{got}, want #{want}" unless got == want
-end
-
 # GRPC contains the General RPC module.
 module GRPC
   # The ActiveCall class provides simple methods for sending marshallable
   # data to a call
   class ActiveCall
-    include Core::CompletionType
     include Core::StatusCodes
     include Core::TimeConsts
+    include Core::CallOps
     attr_reader(:deadline)
 
     # client_invoke begins a client invocation.
@@ -61,15 +55,14 @@ module GRPC
     # @param q [CompletionQueue] the completion queue
     # @param deadline [Fixnum,TimeSpec] the deadline
     def self.client_invoke(call, q, _deadline, **kw)
-      fail(ArgumentError, 'not a call') unless call.is_a? Core::Call
+      fail(TypeError, '!Core::Call') unless call.is_a? Core::Call
       unless q.is_a? Core::CompletionQueue
-        fail(ArgumentError, 'not a CompletionQueue')
+        fail(TypeError, '!Core::CompletionQueue')
       end
-      call.add_metadata(kw) if kw.length > 0
-      client_metadata_read = Object.new
-      finished_tag = Object.new
-      call.invoke(q, client_metadata_read, finished_tag)
-      [finished_tag, client_metadata_read]
+      metadata_tag = Object.new
+      call.run_batch(q, metadata_tag, INFINITE_FUTURE,
+                     SEND_INITIAL_METADATA => kw)
+      metadata_tag
     end
 
     # Creates an ActiveCall.
@@ -91,25 +84,21 @@ module GRPC
     # @param marshal [Function] f(obj)->string that marshal requests
     # @param unmarshal [Function] f(string)->obj that unmarshals responses
     # @param deadline [Fixnum] the deadline for the call to complete
-    # @param finished_tag [Object] the object used as the call's finish tag,
-    #                              if the call has begun
-    # @param read_metadata_tag [Object] the object used as the call's finish
-    #                                   tag, if the call has begun
+    # @param metadata_tag [Object] the object use obtain metadata for clients
     # @param started [true|false] indicates if the call has begun
-    def initialize(call, q, marshal, unmarshal, deadline, finished_tag: nil,
-                   read_metadata_tag: nil, started: true)
-      fail(ArgumentError, 'not a call') unless call.is_a? Core::Call
+    def initialize(call, q, marshal, unmarshal, deadline, started: true,
+                   metadata_tag: nil)
+      fail(TypeError, '!Core::Call') unless call.is_a? Core::Call
       unless q.is_a? Core::CompletionQueue
-        fail(ArgumentError, 'not a CompletionQueue')
+        fail(TypeError, '!Core::CompletionQueue')
       end
       @call = call
       @cq = q
       @deadline = deadline
-      @finished_tag = finished_tag
-      @read_metadata_tag = read_metadata_tag
       @marshal = marshal
       @started = started
       @unmarshal = unmarshal
+      @metadata_tag = metadata_tag
     end
 
     # Obtains the status of the call.
@@ -176,51 +165,38 @@ module GRPC
 
     # writes_done indicates that all writes are completed.
     #
-    # It blocks until the remote endpoint acknowledges by sending a FINISHED
-    # event, unless assert_finished is set to false.  Any calls to
-    # #remote_send after this call will fail.
+    # It blocks until the remote endpoint acknowledges with at status unless
+    # assert_finished is set to false.  Any calls to #remote_send after this
+    # call will fail.
     #
     # @param assert_finished [true, false] when true(default), waits for
     # FINISHED.
     def writes_done(assert_finished = true)
-      @call.writes_done(self)
-      ev = @cq.pluck(self, INFINITE_FUTURE)
-      begin
-        assert_event_type(ev, FINISH_ACCEPTED)
-        logger.debug("Writes done: waiting for finish? #{assert_finished}")
-      ensure
-        ev.close
-      end
-
+      ops = {
+        SEND_CLOSE_FROM_CLIENT => nil
+      }
+      ops[RECV_STATUS_ON_CLIENT] = nil if assert_finished
+      @call.run_batch(@cq, self, INFINITE_FUTURE, ops)
       return unless assert_finished
-      ev = @cq.pluck(@finished_tag, INFINITE_FUTURE)
-      fail 'unexpected nil event' if ev.nil?
-      ev.close
       @call.status
     end
 
-    # finished waits until the call is completed.
+    # finished waits until a client call is completed.
     #
-    # It blocks until the remote endpoint acknowledges by sending a FINISHED
-    # event.
+    # It blocks until the remote endpoint acknowledges by sending a status.
     def finished
-      ev = @cq.pluck(@finished_tag, INFINITE_FUTURE)
-      begin
-        fail "unexpected event: #{ev.inspect}" unless ev.type == FINISHED
-        if @call.metadata.nil?
-          @call.metadata = ev.result.metadata
-        else
-          @call.metadata.merge!(ev.result.metadata)
-        end
-
-        if ev.result.code != Core::StatusCodes::OK
-          fail BadStatus.new(ev.result.code, ev.result.details)
-        end
-        res = ev.result
-      ensure
-        ev.close
+      batch_result = @call.run_batch(@cq, self, INFINITE_FUTURE,
+                                     RECV_STATUS_ON_CLIENT => nil)
+      if @call.metadata.nil?
+        @call.metadata = batch_result.metadata
+      elsif !batch_result.metadata.nil?
+        @call.metadata.merge!(batch_result.metadata)
       end
-      res
+      if batch_result.status.code != Core::StatusCodes::OK
+        fail BadStatus.new(batch_result.status.code,
+                           batch_result.status.details)
+      end
+      batch_result
     end
 
     # remote_send sends a request to the remote endpoint.
@@ -232,72 +208,50 @@ module GRPC
     # @param marshalled [false, true] indicates if the object is already
     # marshalled.
     def remote_send(req, marshalled = false)
-      assert_queue_is_ready
       logger.debug("sending #{req.inspect}, marshalled? #{marshalled}")
       if marshalled
         payload = req
       else
         payload = @marshal.call(req)
       end
-      @call.start_write(Core::ByteBuffer.new(payload), self)
-
-      # call queue#pluck, and wait for WRITE_ACCEPTED, so as not to return
-      # until the flow control allows another send on this call.
-      ev = @cq.pluck(self, INFINITE_FUTURE)
-      begin
-        assert_event_type(ev, WRITE_ACCEPTED)
-      ensure
-        ev.close
-      end
+      @call.run_batch(@cq, self, INFINITE_FUTURE, SEND_MESSAGE => payload)
     end
 
-    # send_status sends a status to the remote endpoint
+    # send_status sends a status to the remote endpoint.
     #
     # @param code [int] the status code to send
     # @param details [String] details
     # @param assert_finished [true, false] when true(default), waits for
     # FINISHED.
     def send_status(code = OK, details = '', assert_finished = false)
-      assert_queue_is_ready
-      @call.start_write_status(code, details, self)
-      ev = @cq.pluck(self, INFINITE_FUTURE)
-      begin
-        assert_event_type(ev, FINISH_ACCEPTED)
-      ensure
-        ev.close
-      end
-      logger.debug("Status sent: #{code}:'#{details}'")
-      return finished if assert_finished
+      ops = {
+        SEND_STATUS_FROM_SERVER => Struct::Status.new(code, details)
+      }
+      ops[RECV_CLOSE_ON_SERVER] = nil if assert_finished
+      @call.run_batch(@cq, self, INFINITE_FUTURE, ops)
       nil
     end
 
     # remote_read reads a response from the remote endpoint.
     #
-    # It blocks until the remote endpoint sends a READ or FINISHED event.  On
-    # a READ, it returns the response after unmarshalling it. On
-    # FINISHED, it returns nil if the status is OK, otherwise raising
-    # BadStatus
+    # It blocks until the remote endpoint replies with a message or status.
+    # On receiving a message, it returns the response after unmarshalling it.
+    # On receiving a status, it returns nil if the status is OK, otherwise
+    # raising BadStatus
     def remote_read
-      if @call.metadata.nil? && !@read_metadata_tag.nil?
-        ev = @cq.pluck(@read_metadata_tag, INFINITE_FUTURE)
-        assert_event_type(ev, CLIENT_METADATA_READ)
-        @call.metadata = ev.result
-        @read_metadata_tag = nil
+      ops = { RECV_MESSAGE => nil }
+      ops[RECV_INITIAL_METADATA] = nil unless @metadata_tag.nil?
+      batch_result = @call.run_batch(@cq, self, INFINITE_FUTURE, ops)
+      unless @metadata_tag.nil?
+        @call.metadata = batch_result.metadata
+        @metadata_tag = nil
       end
-
-      @call.start_read(self)
-      ev = @cq.pluck(self, INFINITE_FUTURE)
-      begin
-        assert_event_type(ev, READ)
-        logger.debug("received req: #{ev.result.inspect}")
-        unless ev.result.nil?
-          logger.debug("received req.to_s: #{ev.result}")
-          res = @unmarshal.call(ev.result.to_s)
-          logger.debug("received_req (unmarshalled): #{res.inspect}")
-          return res
-        end
-      ensure
-        ev.close
+      logger.debug("received req: #{batch_result}")
+      unless batch_result.nil? || batch_result.message.nil?
+        logger.debug("received req.to_s: #{batch_result.message}")
+        res = @unmarshal.call(batch_result.message)
+        logger.debug("received_req (unmarshalled): #{res.inspect}")
+        return res
       end
       logger.debug('found nil; the final response has been sent')
       nil
@@ -324,7 +278,6 @@ module GRPC
       return enum_for(:each_remote_read) unless block_given?
       loop do
         resp = remote_read
-        break if resp.is_a? Struct::Status  # is an OK status
         break if resp.nil?  # the last response was received
         yield resp
       end
@@ -461,8 +414,7 @@ module GRPC
     # @return [Enumerator, nil] a response Enumerator
     def bidi_streamer(requests, **kw, &blk)
       start_call(**kw) unless @started
-      bd = BidiCall.new(@call, @cq, @marshal, @unmarshal, @deadline,
-                        @finished_tag)
+      bd = BidiCall.new(@call, @cq, @marshal, @unmarshal, @deadline)
       bd.run_on_client(requests, &blk)
     end
 
@@ -478,8 +430,7 @@ module GRPC
     #
     # @param gen_each_reply [Proc] generates the BiDi stream replies
     def run_server_bidi(gen_each_reply)
-      bd = BidiCall.new(@call, @cq, @marshal, @unmarshal, @deadline,
-                        @finished_tag)
+      bd = BidiCall.new(@call, @cq, @marshal, @unmarshal, @deadline)
       bd.run_on_server(gen_each_reply)
     end
 
@@ -516,21 +467,5 @@ module GRPC
     # a Operation on the client.
     Operation = view_class(:cancel, :cancelled, :deadline, :execute,
                            :metadata, :status)
-
-    # confirms that no events are enqueued, and that the queue is not
-    # shutdown.
-    def assert_queue_is_ready
-      ev = nil
-      begin
-        ev = @cq.pluck(self, ZERO)
-        fail "unexpected event #{ev.inspect}" unless ev.nil?
-      rescue OutOfTime
-        logging.debug('timed out waiting for next event')
-        # expected, nothing should be on the queue and the deadline was ZERO,
-        # except things using another tag
-      ensure
-        ev.close unless ev.nil?
-      end
-    end
   end
 end
diff --git a/src/ruby/lib/grpc/generic/bidi_call.rb b/src/ruby/lib/grpc/generic/bidi_call.rb
index c66deaae60836e6396c269e65214da698e0f37a5..1c1b3b0db78a20d5491d81bb639559b74eda57e8 100644
--- a/src/ruby/lib/grpc/generic/bidi_call.rb
+++ b/src/ruby/lib/grpc/generic/bidi_call.rb
@@ -30,18 +30,12 @@
 require 'forwardable'
 require 'grpc/grpc'
 
-def assert_event_type(ev, want)
-  fail OutOfTime if ev.nil?
-  got = ev.type
-  fail("Unexpected rpc event: got #{got}, want #{want}") unless got == want
-end
-
 # GRPC contains the General RPC module.
 module GRPC
   # The BiDiCall class orchestrates exection of a BiDi stream on a client or
   # server.
   class BidiCall
-    include Core::CompletionType
+    include Core::CallOps
     include Core::StatusCodes
     include Core::TimeConsts
 
@@ -63,8 +57,7 @@ module GRPC
     # @param marshal [Function] f(obj)->string that marshal requests
     # @param unmarshal [Function] f(string)->obj that unmarshals responses
     # @param deadline [Fixnum] the deadline for the call to complete
-    # @param finished_tag [Object] the object used as the call's finish tag,
-    def initialize(call, q, marshal, unmarshal, deadline, finished_tag)
+    def initialize(call, q, marshal, unmarshal, deadline)
       fail(ArgumentError, 'not a call') unless call.is_a? Core::Call
       unless q.is_a? Core::CompletionQueue
         fail(ArgumentError, 'not a CompletionQueue')
@@ -72,7 +65,6 @@ module GRPC
       @call = call
       @cq = q
       @deadline = deadline
-      @finished_tag = finished_tag
       @marshal = marshal
       @readq = Queue.new
       @unmarshal = unmarshal
@@ -146,30 +138,14 @@ module GRPC
           requests.each do |req|
             count += 1
             payload = @marshal.call(req)
-            @call.start_write(Core::ByteBuffer.new(payload), write_tag)
-            ev = @cq.pluck(write_tag, INFINITE_FUTURE)
-            begin
-              assert_event_type(ev, WRITE_ACCEPTED)
-            ensure
-              ev.close
-            end
+            @call.run_batch(@cq, write_tag, INFINITE_FUTURE,
+                            SEND_MESSAGE => payload)
           end
           if is_client
-            @call.writes_done(write_tag)
-            ev = @cq.pluck(write_tag, INFINITE_FUTURE)
-            begin
-              assert_event_type(ev, FINISH_ACCEPTED)
-            ensure
-              ev.close
-            end
             logger.debug("bidi-client: sent #{count} reqs, waiting to finish")
-            ev = @cq.pluck(@finished_tag, INFINITE_FUTURE)
-            begin
-              assert_event_type(ev, FINISHED)
-            ensure
-              ev.close
-            end
-            logger.debug('bidi-client: finished received')
+            @call.run_batch(@cq, write_tag, INFINITE_FUTURE,
+                            SEND_CLOSE_FROM_CLIENT => nil,
+                            RECV_STATUS_ON_CLIENT => nil)
           end
         rescue StandardError => e
           logger.warn('bidi: write_loop failed')
@@ -189,25 +165,20 @@ module GRPC
           loop do
             logger.debug("waiting for read #{count}")
             count += 1
-            @call.start_read(read_tag)
-            ev = @cq.pluck(read_tag, INFINITE_FUTURE)
-            begin
-              assert_event_type(ev, READ)
-
-              # handle the next event.
-              if ev.result.nil?
-                @readq.push(END_OF_READS)
-                logger.debug('done reading!')
-                break
-              end
-
-              # push the latest read onto the queue and continue reading
-              logger.debug("received req: #{ev.result}")
-              res = @unmarshal.call(ev.result.to_s)
-              @readq.push(res)
-            ensure
-              ev.close
+            # TODO: ensure metadata is read if available, currently it's not
+            batch_result = @call.run_batch(@cq, read_tag, INFINITE_FUTURE,
+                                           RECV_MESSAGE => nil)
+            # handle the next message
+            if batch_result.message.nil?
+              @readq.push(END_OF_READS)
+              logger.debug('done reading!')
+              break
             end
+
+            # push the latest read onto the queue and continue reading
+            logger.debug("received req: #{batch_result.message}")
+            res = @unmarshal.call(batch_result.message)
+            @readq.push(res)
           end
 
         rescue StandardError => e
diff --git a/src/ruby/lib/grpc/generic/client_stub.rb b/src/ruby/lib/grpc/generic/client_stub.rb
index 01328d4a5bc68895716942b1f360ed0c9b911d7e..6547a1499ec881e516f3da416c3eaf1dd089e4ee 100644
--- a/src/ruby/lib/grpc/generic/client_stub.rb
+++ b/src/ruby/lib/grpc/generic/client_stub.rb
@@ -35,9 +35,10 @@ module GRPC
   # ClientStub represents an endpoint used to send requests to GRPC servers.
   class ClientStub
     include Core::StatusCodes
+    include Core::TimeConsts
 
-    # Default deadline is 5 seconds.
-    DEFAULT_DEADLINE = 5
+    # Default timeout is 5 seconds.
+    DEFAULT_TIMEOUT = 5
 
     # setup_channel is used by #initialize to constuct a channel from its
     # arguments.
@@ -76,8 +77,8 @@ module GRPC
     # present the host and arbitrary keyword arg areignored, and the RPC
     # connection uses this channel.
     #
-    # - :deadline
-    # when present, this is the default deadline used for calls
+    # - :timeout
+    # when present, this is the default timeout used for calls
     #
     # - :update_metadata
     # when present, this a func that takes a hash and returns a hash
@@ -87,13 +88,13 @@ module GRPC
     # @param host [String] the host the stub connects to
     # @param q [Core::CompletionQueue] used to wait for events
     # @param channel_override [Core::Channel] a pre-created channel
-    # @param deadline [Number] the default deadline to use in requests
+    # @param timeout [Number] the default timeout to use in requests
     # @param creds [Core::Credentials] the channel
     # @param update_metadata a func that updates metadata as described above
     # @param kw [KeywordArgs]the channel arguments
     def initialize(host, q,
                    channel_override: nil,
-                   deadline: DEFAULT_DEADLINE,
+                   timeout: nil,
                    creds: nil,
                    update_metadata: nil,
                    **kw)
@@ -103,7 +104,7 @@ module GRPC
       @update_metadata = ClientStub.check_update_metadata(update_metadata)
       alt_host = kw[Core::Channel::SSL_TARGET]
       @host = alt_host.nil? ? host : alt_host
-      @deadline = deadline
+      @timeout = timeout.nil? ? DEFAULT_TIMEOUT : timeout
     end
 
     # request_response sends a request to a GRPC server, and returns the
@@ -140,12 +141,12 @@ module GRPC
     # @param req [Object] the request sent to the server
     # @param marshal [Function] f(obj)->string that marshals requests
     # @param unmarshal [Function] f(string)->obj that unmarshals responses
-    # @param deadline [Numeric] (optional) the max completion time in seconds
+    # @param timeout [Numeric] (optional) the max completion time in seconds
     # @param return_op [true|false] return an Operation if true
     # @return [Object] the response received from the server
-    def request_response(method, req, marshal, unmarshal, deadline = nil,
+    def request_response(method, req, marshal, unmarshal, timeout = nil,
                          return_op: false, **kw)
-      c = new_active_call(method, marshal, unmarshal, deadline || @deadline)
+      c = new_active_call(method, marshal, unmarshal, timeout)
       md = @update_metadata.nil? ? kw : @update_metadata.call(kw.clone)
       return c.request_response(req, **md) unless return_op
 
@@ -197,12 +198,12 @@ module GRPC
     # @param requests [Object] an Enumerable of requests to send
     # @param marshal [Function] f(obj)->string that marshals requests
     # @param unmarshal [Function] f(string)->obj that unmarshals responses
-    # @param deadline [Numeric] the max completion time in seconds
+    # @param timeout [Numeric] the max completion time in seconds
     # @param return_op [true|false] return an Operation if true
     # @return [Object|Operation] the response received from the server
-    def client_streamer(method, requests, marshal, unmarshal, deadline = nil,
+    def client_streamer(method, requests, marshal, unmarshal, timeout = nil,
                         return_op: false, **kw)
-      c = new_active_call(method, marshal, unmarshal, deadline || @deadline)
+      c = new_active_call(method, marshal, unmarshal, timeout)
       md = @update_metadata.nil? ? kw : @update_metadata.call(kw.clone)
       return c.client_streamer(requests, **md) unless return_op
 
@@ -262,13 +263,13 @@ module GRPC
     # @param req [Object] the request sent to the server
     # @param marshal [Function] f(obj)->string that marshals requests
     # @param unmarshal [Function] f(string)->obj that unmarshals responses
-    # @param deadline [Numeric] the max completion time in seconds
+    # @param timeout [Numeric] the max completion time in seconds
     # @param return_op [true|false]return an Operation if true
     # @param blk [Block] when provided, is executed for each response
     # @return [Enumerator|Operation|nil] as discussed above
-    def server_streamer(method, req, marshal, unmarshal, deadline = nil,
+    def server_streamer(method, req, marshal, unmarshal, timeout = nil,
                         return_op: false, **kw, &blk)
-      c = new_active_call(method, marshal, unmarshal, deadline || @deadline)
+      c = new_active_call(method, marshal, unmarshal, timeout)
       md = @update_metadata.nil? ? kw : @update_metadata.call(kw.clone)
       return c.server_streamer(req, **md, &blk) unless return_op
 
@@ -367,13 +368,13 @@ module GRPC
     # @param requests [Object] an Enumerable of requests to send
     # @param marshal [Function] f(obj)->string that marshals requests
     # @param unmarshal [Function] f(string)->obj that unmarshals responses
-    # @param deadline [Numeric] (optional) the max completion time in seconds
+    # @param timeout [Numeric] (optional) the max completion time in seconds
     # @param blk [Block] when provided, is executed for each response
     # @param return_op [true|false] return an Operation if true
     # @return [Enumerator|nil|Operation] as discussed above
-    def bidi_streamer(method, requests, marshal, unmarshal, deadline = nil,
+    def bidi_streamer(method, requests, marshal, unmarshal, timeout = nil,
                       return_op: false, **kw, &blk)
-      c = new_active_call(method, marshal, unmarshal, deadline || @deadline)
+      c = new_active_call(method, marshal, unmarshal, timeout)
       md = @update_metadata.nil? ? kw : @update_metadata.call(kw.clone)
       return c.bidi_streamer(requests, **md, &blk) unless return_op
 
@@ -390,15 +391,14 @@ module GRPC
 
     # Creates a new active stub
     #
-    # @param ch [GRPC::Channel] the channel used to create the stub.
+    # @param method [string] the method being called.
     # @param marshal [Function] f(obj)->string that marshals requests
     # @param unmarshal [Function] f(string)->obj that unmarshals responses
-    # @param deadline [TimeConst]
-    def new_active_call(ch, marshal, unmarshal, deadline = nil)
-      absolute_deadline = Core::TimeConsts.from_relative_time(deadline)
-      call = @ch.create_call(ch, @host, absolute_deadline)
-      ActiveCall.new(call, @queue, marshal, unmarshal, absolute_deadline,
-                     started: false)
+    # @param timeout [TimeConst]
+    def new_active_call(method, marshal, unmarshal, timeout = nil)
+      deadline = from_relative_time(timeout.nil? ? @timeout : timeout)
+      call = @ch.create_call(@queue, method, @host, deadline)
+      ActiveCall.new(call, @queue, marshal, unmarshal, deadline, started: false)
     end
   end
 end
diff --git a/src/ruby/lib/grpc/generic/rpc_desc.rb b/src/ruby/lib/grpc/generic/rpc_desc.rb
index 2cb3d2eebf43744be89af19c5caa972c1985fbe5..3e48b8e51d723dba00f54e058b4df809d610d28c 100644
--- a/src/ruby/lib/grpc/generic/rpc_desc.rb
+++ b/src/ruby/lib/grpc/generic/rpc_desc.rb
@@ -81,7 +81,6 @@ module GRPC
         active_call.run_server_bidi(mth)
       end
       send_status(active_call, OK, 'OK')
-      active_call.finished
     rescue BadStatus => e
       # this is raised by handlers that want GRPC to send an application
       # error code and detail message.
@@ -91,15 +90,11 @@ module GRPC
       # This is raised by GRPC internals but should rarely, if ever happen.
       # Log it, but don't notify the other endpoint..
       logger.warn("failed call: #{active_call}\n#{e}")
-    rescue OutOfTime
+    rescue Core::OutOfTime
       # This is raised when active_call#method.call exceeeds the deadline
       # event.  Send a status of deadline exceeded
       logger.warn("late call: #{active_call}")
       send_status(active_call, DEADLINE_EXCEEDED, 'late')
-    rescue Core::EventError => e
-      # This is raised by GRPC internals but should rarely, if ever happen.
-      # Log it, but don't notify the other endpoint..
-      logger.warn("failed call: #{active_call}\n#{e}")
     rescue StandardError => e
       # This will usuaally be an unhandled error in the handling code.
       # Send back a UNKNOWN status to the client
@@ -142,7 +137,7 @@ module GRPC
 
     def send_status(active_client, code, details)
       details = 'Not sure why' if details.nil?
-      active_client.send_status(code, details)
+      active_client.send_status(code, details, code == OK)
     rescue StandardError => e
       logger.warn("Could not send status #{code}:#{details}")
       logger.warn(e)
diff --git a/src/ruby/lib/grpc/generic/rpc_server.rb b/src/ruby/lib/grpc/generic/rpc_server.rb
index 35e84023be952df4fa5e846a14a8d26d4c166e26..30a4bf15325c15c4769a2b461ce24ee9d494f68c 100644
--- a/src/ruby/lib/grpc/generic/rpc_server.rb
+++ b/src/ruby/lib/grpc/generic/rpc_server.rb
@@ -38,7 +38,7 @@ module GRPC
   # RpcServer hosts a number of services and makes them available on the
   # network.
   class RpcServer
-    include Core::CompletionType
+    include Core::CallOps
     include Core::TimeConsts
     extend ::Forwardable
 
@@ -202,20 +202,14 @@ module GRPC
       end
       @pool.start
       @server.start
-      server_tag = Object.new
+      request_call_tag = Object.new
       until stopped?
-        @server.request_call(server_tag)
-        ev = @cq.pluck(server_tag, @poll_period)
-        next if ev.nil?
-        if ev.type != SERVER_RPC_NEW
-          logger.warn("bad evt: got:#{ev.type}, want:#{SERVER_RPC_NEW}")
-          ev.close
-          next
-        end
-        c = new_active_server_call(ev.call, ev.result)
+        deadline = from_relative_time(@poll_period)
+        an_rpc = @server.request_call(@cq, request_call_tag, deadline)
+        next if an_rpc.nil?
+        c = new_active_server_call(an_rpc)
         unless c.nil?
-          mth = ev.result.method.to_sym
-          ev.close
+          mth = an_rpc.method.to_sym
           @pool.schedule(c) do |call|
             rpc_descs[mth].run_server_method(call, rpc_handlers[mth])
           end
@@ -224,46 +218,49 @@ module GRPC
       @running = false
     end
 
-    def new_active_server_call(call, new_server_rpc)
-      # Accept the call.  This is necessary even if a status is to be sent
-      # back immediately
-      finished_tag = Object.new
-      call_queue = Core::CompletionQueue.new
-      call.metadata = new_server_rpc.metadata  # store the metadata
-      call.server_accept(call_queue, finished_tag)
-      call.server_end_initial_metadata
-
-      # Send UNAVAILABLE if there are too many unprocessed jobs
+    # Sends UNAVAILABLE if there are too many unprocessed jobs
+    def available?(an_rpc)
       jobs_count, max = @pool.jobs_waiting, @max_waiting_requests
       logger.info("waiting: #{jobs_count}, max: #{max}")
-      if @pool.jobs_waiting > @max_waiting_requests
-        logger.warn("NOT AVAILABLE: too many jobs_waiting: #{new_server_rpc}")
-        noop = proc { |x| x }
-        c = ActiveCall.new(call, call_queue, noop, noop,
-                           new_server_rpc.deadline,
-                           finished_tag: finished_tag)
-        c.send_status(StatusCodes::UNAVAILABLE, '')
-        return nil
-      end
+      return an_rpc if @pool.jobs_waiting <= @max_waiting_requests
+      logger.warn("NOT AVAILABLE: too many jobs_waiting: #{an_rpc}")
+      noop = proc { |x| x }
+      c = ActiveCall.new(an_rpc.call, @cq, noop, noop, an_rpc.deadline)
+      c.send_status(StatusCodes::UNAVAILABLE, '')
+      nil
+    end
 
-      # Send NOT_FOUND if the method does not exist
-      mth = new_server_rpc.method.to_sym
-      unless rpc_descs.key?(mth)
-        logger.warn("NOT_FOUND: #{new_server_rpc}")
-        noop = proc { |x| x }
-        c = ActiveCall.new(call, call_queue, noop, noop,
-                           new_server_rpc.deadline,
-                           finished_tag: finished_tag)
-        c.send_status(StatusCodes::NOT_FOUND, '')
-        return nil
-      end
+    # Sends NOT_FOUND if the method can't be found
+    def found?(an_rpc)
+      mth = an_rpc.method.to_sym
+      return an_rpc if rpc_descs.key?(mth)
+      logger.warn("NOT_FOUND: #{an_rpc}")
+      noop = proc { |x| x }
+      c = ActiveCall.new(an_rpc.call, @cq, noop, noop, an_rpc.deadline)
+      c.send_status(StatusCodes::NOT_FOUND, '')
+      nil
+    end
+
+    def new_active_server_call(an_rpc)
+      # Accept the call.  This is necessary even if a status is to be sent
+      # back immediately
+      return nil if an_rpc.nil? || an_rpc.call.nil?
+
+      # allow the metadata to be accessed from the call
+      handle_call_tag = Object.new
+      an_rpc.call.metadata = an_rpc.metadata
+      # TODO: add a hook to send md
+      an_rpc.call.run_batch(@cq, handle_call_tag, INFINITE_FUTURE,
+                            SEND_INITIAL_METADATA => nil)
+      return nil unless available?(an_rpc)
+      return nil unless found?(an_rpc)
 
       # Create the ActiveCall
-      rpc_desc = rpc_descs[mth]
-      logger.info("deadline is #{new_server_rpc.deadline}; (now=#{Time.now})")
-      ActiveCall.new(call, call_queue,
+      logger.info("deadline is #{an_rpc.deadline}; (now=#{Time.now})")
+      rpc_desc = rpc_descs[an_rpc.method.to_sym]
+      ActiveCall.new(an_rpc.call, @cq,
                      rpc_desc.marshal_proc, rpc_desc.unmarshal_proc(:input),
-                     new_server_rpc.deadline, finished_tag: finished_tag)
+                     an_rpc.deadline)
     end
 
     # Pool is a simple thread pool for running server requests.
diff --git a/src/ruby/spec/byte_buffer_spec.rb b/src/ruby/spec/byte_buffer_spec.rb
deleted file mode 100644
index e1833ebb3a0b479da1bae75f4aa8378cc282fb1a..0000000000000000000000000000000000000000
--- a/src/ruby/spec/byte_buffer_spec.rb
+++ /dev/null
@@ -1,67 +0,0 @@
-# Copyright 2015, Google Inc.
-# All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions are
-# met:
-#
-#     * Redistributions of source code must retain the above copyright
-# notice, this list of conditions and the following disclaimer.
-#     * Redistributions in binary form must reproduce the above
-# copyright notice, this list of conditions and the following disclaimer
-# in the documentation and/or other materials provided with the
-# distribution.
-#     * Neither the name of Google Inc. nor the names of its
-# contributors may be used to endorse or promote products derived from
-# this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-require 'grpc'
-
-describe GRPC::Core::ByteBuffer do
-  describe '#new' do
-    it 'is constructed from a string' do
-      expect { GRPC::Core::ByteBuffer.new('#new') }.not_to raise_error
-    end
-
-    it 'can be constructed from the empty string' do
-      expect { GRPC::Core::ByteBuffer.new('') }.not_to raise_error
-    end
-
-    it 'cannot be constructed from nil' do
-      expect { GRPC::Core::ByteBuffer.new(nil) }.to raise_error TypeError
-    end
-
-    it 'cannot be constructed from non-strings' do
-      [1, Object.new, :a_symbol].each do |x|
-        expect { GRPC::Core::ByteBuffer.new(x) }.to raise_error TypeError
-      end
-    end
-  end
-
-  describe '#to_s' do
-    it 'is the string value the ByteBuffer was constructed with' do
-      expect(GRPC::Core::ByteBuffer.new('#to_s').to_s).to eq('#to_s')
-    end
-  end
-
-  describe '#dup' do
-    it 'makes an instance whose #to_s is the original string value' do
-      bb = GRPC::Core::ByteBuffer.new('#dup')
-      a_copy = bb.dup
-      expect(a_copy.to_s).to eq('#dup')
-      expect(a_copy.dup.to_s).to eq('#dup')
-    end
-  end
-end
diff --git a/src/ruby/spec/call_spec.rb b/src/ruby/spec/call_spec.rb
index 26175645719e31f5cf4e6c8bf509f9be0e47644f..4977c10a7e183fcd692b652c507454546967682a 100644
--- a/src/ruby/spec/call_spec.rb
+++ b/src/ruby/spec/call_spec.rb
@@ -66,51 +66,34 @@ describe GRPC::Core::RpcErrors do
   end
 end
 
-describe GRPC::Core::Call do
+describe GRPC::Core::CallOps do
   before(:each) do
-    @tag = Object.new
-    @client_queue = GRPC::Core::CompletionQueue.new
-    fake_host = 'localhost:10101'
-    @ch = GRPC::Core::Channel.new(fake_host, nil)
-  end
-
-  describe '#start_read' do
-    xit 'should fail if called immediately' do
-      blk = proc { make_test_call.start_read(@tag) }
-      expect(&blk).to raise_error GRPC::Core::CallError
-    end
-  end
-
-  describe '#start_write' do
-    xit 'should fail if called immediately' do
-      bytes = GRPC::Core::ByteBuffer.new('test string')
-      blk = proc { make_test_call.start_write(bytes, @tag) }
-      expect(&blk).to raise_error GRPC::Core::CallError
-    end
+    @known_types = {
+      SEND_INITIAL_METADATA: 0,
+      SEND_MESSAGE: 1,
+      SEND_CLOSE_FROM_CLIENT: 2,
+      SEND_STATUS_FROM_SERVER: 3,
+      RECV_INITIAL_METADATA: 4,
+      RECV_MESSAGE: 5,
+      RECV_STATUS_ON_CLIENT: 6,
+      RECV_CLOSE_ON_SERVER: 7
+    }
   end
 
-  describe '#start_write_status' do
-    xit 'should fail if called immediately' do
-      blk = proc { make_test_call.start_write_status(153, 'x', @tag) }
-      expect(&blk).to raise_error GRPC::Core::CallError
-    end
+  it 'should have symbols for all the known operation types' do
+    m = GRPC::Core::CallOps
+    syms_and_codes = m.constants.collect { |c| [c, m.const_get(c)] }
+    expect(Hash[syms_and_codes]).to eq(@known_types)
   end
+end
 
-  describe '#writes_done' do
-    xit 'should fail if called immediately' do
-      blk = proc { make_test_call.writes_done(Object.new) }
-      expect(&blk).to raise_error GRPC::Core::CallError
-    end
-  end
+describe GRPC::Core::Call do
+  let(:client_queue) { GRPC::Core::CompletionQueue.new }
+  let(:test_tag)  { Object.new }
+  let(:fake_host) { 'localhost:10101' }
 
-  describe '#add_metadata' do
-    it 'adds metadata to a call without fail' do
-      call = make_test_call
-      n = 37
-      one_md = proc { |x| [sprintf('key%d', x), sprintf('value%d', x)] }
-      metadata = Hash[n.times.collect { |i| one_md.call i }]
-      expect { call.add_metadata(metadata) }.to_not raise_error
-    end
+  before(:each) do
+    @ch = GRPC::Core::Channel.new(fake_host, nil)
   end
 
   describe '#status' do
@@ -154,7 +137,7 @@ describe GRPC::Core::Call do
   end
 
   def make_test_call
-    @ch.create_call('dummy_method', 'dummy_host', deadline)
+    @ch.create_call(client_queue, 'dummy_method', 'dummy_host', deadline)
   end
 
   def deadline
diff --git a/src/ruby/spec/channel_spec.rb b/src/ruby/spec/channel_spec.rb
index af73294abe429ad80478f42d8591fbb4afc53e62..31e38d71b81ee71aeaefa634db7a2e7d87024832 100644
--- a/src/ruby/spec/channel_spec.rb
+++ b/src/ruby/spec/channel_spec.rb
@@ -36,16 +36,13 @@ def load_test_certs
 end
 
 describe GRPC::Core::Channel do
-  FAKE_HOST = 'localhost:0'
+  let(:fake_host) { 'localhost:0' }
+  let(:cq) { GRPC::Core::CompletionQueue.new }
 
   def create_test_cert
     GRPC::Core::Credentials.new(load_test_certs[0])
   end
 
-  before(:each) do
-    @cq = GRPC::Core::CompletionQueue.new
-  end
-
   shared_examples '#new' do
     it 'take a host name without channel args' do
       expect { GRPC::Core::Channel.new('dummy_host', nil) }.not_to raise_error
@@ -115,25 +112,23 @@ describe GRPC::Core::Channel do
 
   describe '#create_call' do
     it 'creates a call OK' do
-      host = FAKE_HOST
-      ch = GRPC::Core::Channel.new(host, nil)
+      ch = GRPC::Core::Channel.new(fake_host, nil)
 
       deadline = Time.now + 5
 
       blk = proc do
-        ch.create_call('dummy_method', 'dummy_host', deadline)
+        ch.create_call(cq, 'dummy_method', 'dummy_host', deadline)
       end
       expect(&blk).to_not raise_error
     end
 
     it 'raises an error if called on a closed channel' do
-      host = FAKE_HOST
-      ch = GRPC::Core::Channel.new(host, nil)
+      ch = GRPC::Core::Channel.new(fake_host, nil)
       ch.close
 
       deadline = Time.now + 5
       blk = proc do
-        ch.create_call('dummy_method', 'dummy_host', deadline)
+        ch.create_call(cq, 'dummy_method', 'dummy_host', deadline)
       end
       expect(&blk).to raise_error(RuntimeError)
     end
@@ -141,15 +136,13 @@ describe GRPC::Core::Channel do
 
   describe '#destroy' do
     it 'destroys a channel ok' do
-      host = FAKE_HOST
-      ch = GRPC::Core::Channel.new(host, nil)
+      ch = GRPC::Core::Channel.new(fake_host, nil)
       blk = proc { ch.destroy }
       expect(&blk).to_not raise_error
     end
 
     it 'can be called more than once without error' do
-      host = FAKE_HOST
-      ch = GRPC::Core::Channel.new(host, nil)
+      ch = GRPC::Core::Channel.new(fake_host, nil)
       blk = proc { ch.destroy }
       blk.call
       expect(&blk).to_not raise_error
@@ -164,15 +157,13 @@ describe GRPC::Core::Channel do
 
   describe '#close' do
     it 'closes a channel ok' do
-      host = FAKE_HOST
-      ch = GRPC::Core::Channel.new(host, nil)
+      ch = GRPC::Core::Channel.new(fake_host, nil)
       blk = proc { ch.close }
       expect(&blk).to_not raise_error
     end
 
     it 'can be called more than once without error' do
-      host = FAKE_HOST
-      ch = GRPC::Core::Channel.new(host, nil)
+      ch = GRPC::Core::Channel.new(fake_host, nil)
       blk = proc { ch.close }
       blk.call
       expect(&blk).to_not raise_error
diff --git a/src/ruby/spec/client_server_spec.rb b/src/ruby/spec/client_server_spec.rb
index 49a2d3bb4df9fd00b7f5955b3fb70f66bba77e6d..1a2afbe1f9a72161b951d204635913b2edf2429a 100644
--- a/src/ruby/spec/client_server_spec.rb
+++ b/src/ruby/spec/client_server_spec.rb
@@ -30,7 +30,6 @@
 require 'grpc'
 require 'spec_helper'
 
-include GRPC::Core::CompletionType
 include GRPC::Core
 
 def load_test_certs
@@ -40,6 +39,8 @@ def load_test_certs
 end
 
 shared_context 'setup: tags' do
+  let(:sent_message) { 'sent message' }
+  let(:reply_text) { 'the reply' }
   before(:example) do
     @server_finished_tag = Object.new
     @client_finished_tag = Object.new
@@ -52,153 +53,136 @@ shared_context 'setup: tags' do
     Time.now + 2
   end
 
-  def expect_next_event_on(queue, type, tag)
-    ev = queue.pluck(tag, deadline)
-    if type.nil?
-      expect(ev).to be_nil
-    else
-      expect(ev).to_not be_nil
-      expect(ev.type).to be(type)
-    end
-    ev
-  end
-
   def server_allows_client_to_proceed
-    @server.request_call(@server_tag)
-    ev = @server_queue.pluck(@server_tag, deadline)
-    expect(ev).not_to be_nil
-    expect(ev.type).to be(SERVER_RPC_NEW)
-    server_call = ev.call
-    server_call.server_accept(@server_queue, @server_finished_tag)
-    server_call.server_end_initial_metadata
+    recvd_rpc = @server.request_call(@server_queue, @server_tag, deadline)
+    expect(recvd_rpc).to_not eq nil
+    server_call = recvd_rpc.call
+    ops = { CallOps::SEND_INITIAL_METADATA => {} }
+    svr_batch = server_call.run_batch(@server_queue, @server_tag, deadline, ops)
+    expect(svr_batch.send_metadata).to be true
     server_call
   end
 
-  def server_responds_with(server_call, reply_text)
-    reply = ByteBuffer.new(reply_text)
-    server_call.start_read(@server_tag)
-    ev = @server_queue.pluck(@server_tag, TimeConsts::INFINITE_FUTURE)
-    expect(ev.type).to be(READ)
-    server_call.start_write(reply, @server_tag)
-    ev = @server_queue.pluck(@server_tag, TimeConsts::INFINITE_FUTURE)
-    expect(ev).not_to be_nil
-    expect(ev.type).to be(WRITE_ACCEPTED)
-  end
-
-  def client_sends(call, sent = 'a message')
-    req = ByteBuffer.new(sent)
-    call.start_write(req, @tag)
-    ev = @client_queue.pluck(@tag, TimeConsts::INFINITE_FUTURE)
-    expect(ev).not_to be_nil
-    expect(ev.type).to be(WRITE_ACCEPTED)
-    sent
-  end
-
   def new_client_call
-    @ch.create_call('/method', 'foo.test.google.fr', deadline)
+    @ch.create_call(@client_queue, '/method', 'foo.test.google.fr', deadline)
   end
 end
 
 shared_examples 'basic GRPC message delivery is OK' do
+  include GRPC::Core
   include_context 'setup: tags'
 
-  it 'servers receive requests from clients and start responding' do
-    reply = ByteBuffer.new('the server payload')
+  it 'servers receive requests from clients and can respond' do
     call = new_client_call
-    call.invoke(@client_queue, @client_metadata_tag, @client_finished_tag)
-
-    # check the server rpc new was received
-    # @server.request_call(@server_tag)
-    # ev = expect_next_event_on(@server_queue, SERVER_RPC_NEW, @server_tag)
-
-    # accept the call
-    # server_call = ev.call
-    # server_call.server_accept(@server_queue, @server_finished_tag)
-    # server_call.server_end_initial_metadata
-    server_call = server_allows_client_to_proceed
-
-    # client sends a message
-    msg = client_sends(call)
+    client_ops = {
+      CallOps::SEND_INITIAL_METADATA => {},
+      CallOps::SEND_MESSAGE => sent_message
+    }
+    batch_result = call.run_batch(@client_queue, @client_tag, deadline,
+                                  client_ops)
+    expect(batch_result.send_metadata).to be true
+    expect(batch_result.send_message).to be true
 
     # confirm the server can read the inbound message
-    server_call.start_read(@server_tag)
-    ev = expect_next_event_on(@server_queue, READ, @server_tag)
-    expect(ev.result.to_s).to eq(msg)
-
-    #  the server response
-    server_call.start_write(reply, @server_tag)
-    expect_next_event_on(@server_queue, WRITE_ACCEPTED, @server_tag)
+    server_call = server_allows_client_to_proceed
+    server_ops = {
+      CallOps::RECV_MESSAGE => nil
+    }
+    svr_batch = server_call.run_batch(@server_queue, @server_tag, deadline,
+                                      server_ops)
+    expect(svr_batch.message).to eq(sent_message)
   end
 
   it 'responses written by servers are received by the client' do
     call = new_client_call
-    call.invoke(@client_queue, @client_metadata_tag, @client_finished_tag)
-    server_call = server_allows_client_to_proceed
-    client_sends(call)
-    server_responds_with(server_call, 'server_response')
+    client_ops = {
+      CallOps::SEND_INITIAL_METADATA => {},
+      CallOps::SEND_MESSAGE => sent_message
+    }
+    batch_result = call.run_batch(@client_queue, @client_tag, deadline,
+                                  client_ops)
+    expect(batch_result.send_metadata).to be true
+    expect(batch_result.send_message).to be true
 
-    call.start_read(@tag)
-    ev = expect_next_event_on(@client_queue, READ, @tag)
-    expect(ev.result.to_s).to eq('server_response')
+    # confirm the server can read the inbound message
+    server_call = server_allows_client_to_proceed
+    server_ops = {
+      CallOps::RECV_MESSAGE => nil,
+      CallOps::SEND_MESSAGE => reply_text
+    }
+    svr_batch = server_call.run_batch(@server_queue, @server_tag, deadline,
+                                      server_ops)
+    expect(svr_batch.message).to eq(sent_message)
+    expect(svr_batch.send_message).to be true
   end
 
   it 'servers can ignore a client write and send a status' do
     call = new_client_call
-    call.invoke(@client_queue, @client_metadata_tag, @client_finished_tag)
-
-    # check the server rpc new was received
-    @server.request_call(@server_tag)
-    ev = expect_next_event_on(@server_queue, SERVER_RPC_NEW, @server_tag)
-    expect(ev.tag).to be(@server_tag)
-
-    # accept the call - need to do this to sent status.
-    server_call = ev.call
-    server_call.server_accept(@server_queue, @server_finished_tag)
-    server_call.server_end_initial_metadata
-    server_call.start_write_status(StatusCodes::NOT_FOUND, 'not found',
-                                   @server_tag)
-
-    # Client sends some data
-    client_sends(call)
-
-    # client gets an empty response for the read, preceeded by some metadata.
-    call.start_read(@tag)
-    expect_next_event_on(@client_queue, CLIENT_METADATA_READ,
-                         @client_metadata_tag)
-    ev = expect_next_event_on(@client_queue, READ, @tag)
-    expect(ev.tag).to be(@tag)
-    expect(ev.result.to_s).to eq('')
-
-    # finally, after client sends writes_done, they get the finished.
-    call.writes_done(@tag)
-    expect_next_event_on(@client_queue, FINISH_ACCEPTED, @tag)
-    ev = expect_next_event_on(@client_queue, FINISHED, @client_finished_tag)
-    expect(ev.result.code).to eq(StatusCodes::NOT_FOUND)
+    client_ops = {
+      CallOps::SEND_INITIAL_METADATA => {},
+      CallOps::SEND_MESSAGE => sent_message
+    }
+    batch_result = call.run_batch(@client_queue, @client_tag, deadline,
+                                  client_ops)
+    expect(batch_result.send_metadata).to be true
+    expect(batch_result.send_message).to be true
+
+    # confirm the server can read the inbound message
+    the_status = Struct::Status.new(StatusCodes::OK, 'OK')
+    server_call = server_allows_client_to_proceed
+    server_ops = {
+      CallOps::SEND_STATUS_FROM_SERVER => the_status
+    }
+    svr_batch = server_call.run_batch(@server_queue, @server_tag, deadline,
+                                      server_ops)
+    expect(svr_batch.message).to eq nil
+    expect(svr_batch.send_status).to be true
   end
 
   it 'completes calls by sending status to client and server' do
     call = new_client_call
-    call.invoke(@client_queue, @client_metadata_tag, @client_finished_tag)
+    client_ops = {
+      CallOps::SEND_INITIAL_METADATA => {},
+      CallOps::SEND_MESSAGE => sent_message
+    }
+    batch_result = call.run_batch(@client_queue, @client_tag, deadline,
+                                  client_ops)
+    expect(batch_result.send_metadata).to be true
+    expect(batch_result.send_message).to be true
+
+    # confirm the server can read the inbound message and respond
+    the_status = Struct::Status.new(StatusCodes::OK, 'OK', {})
     server_call = server_allows_client_to_proceed
-    client_sends(call)
-    server_responds_with(server_call, 'server_response')
-    server_call.start_write_status(10_101, 'status code is 10101', @server_tag)
-
-    # first the client says writes are done
-    call.start_read(@tag)
-    expect_next_event_on(@client_queue, READ, @tag)
-    call.writes_done(@tag)
-
-    # but nothing happens until the server sends a status
-    expect_next_event_on(@server_queue, FINISH_ACCEPTED, @server_tag)
-    ev = expect_next_event_on(@server_queue, FINISHED, @server_finished_tag)
-    expect(ev.result).to be_a(Struct::Status)
-
-    # client gets FINISHED
-    expect_next_event_on(@client_queue, FINISH_ACCEPTED, @tag)
-    ev = expect_next_event_on(@client_queue, FINISHED, @client_finished_tag)
-    expect(ev.result.details).to eq('status code is 10101')
-    expect(ev.result.code).to eq(10_101)
+    server_ops = {
+      CallOps::RECV_MESSAGE => nil,
+      CallOps::SEND_MESSAGE => reply_text,
+      CallOps::SEND_STATUS_FROM_SERVER => the_status
+    }
+    svr_batch = server_call.run_batch(@server_queue, @server_tag, deadline,
+                                      server_ops)
+    expect(svr_batch.message).to eq sent_message
+    expect(svr_batch.send_status).to be true
+    expect(svr_batch.send_message).to be true
+
+    # confirm the client can receive the server response and status.
+    client_ops = {
+      CallOps::SEND_CLOSE_FROM_CLIENT => nil,
+      CallOps::RECV_MESSAGE => nil,
+      CallOps::RECV_STATUS_ON_CLIENT => nil
+    }
+    batch_result = call.run_batch(@client_queue, @client_tag, deadline,
+                                  client_ops)
+    expect(batch_result.send_close).to be true
+    expect(batch_result.message).to eq reply_text
+    expect(batch_result.status).to eq the_status
+
+    # confirm the server can receive the client close.
+    server_ops = {
+      CallOps::RECV_CLOSE_ON_SERVER => nil
+    }
+    svr_batch = server_call.run_batch(@server_queue, @server_tag, deadline,
+                                      server_ops)
+    expect(svr_batch.send_close).to be true
   end
 end
 
@@ -224,25 +208,33 @@ shared_examples 'GRPC metadata delivery works OK' do
     it 'raises an exception if a metadata key is invalid' do
       @bad_keys.each do |md|
         call = new_client_call
-        expect { call.add_metadata(md) }.to raise_error
+        client_ops = {
+          CallOps::SEND_INITIAL_METADATA => md
+        }
+        blk = proc do
+          call.run_batch(@client_queue, @client_tag, deadline,
+                         client_ops)
+        end
+        expect(&blk).to raise_error
       end
     end
 
     it 'sends all the metadata pairs when keys and values are valid' do
       @valid_metadata.each do |md|
         call = new_client_call
-        call.add_metadata(md)
-
-        # Client begins a call OK
-        call.invoke(@client_queue, @client_metadata_tag, @client_finished_tag)
-
-        # ... server has all metadata available even though the client did not
-        # send a write
-        @server.request_call(@server_tag)
-        ev = expect_next_event_on(@server_queue, SERVER_RPC_NEW, @server_tag)
+        client_ops = {
+          CallOps::SEND_INITIAL_METADATA => md
+        }
+        batch_result = call.run_batch(@client_queue, @client_tag, deadline,
+                                      client_ops)
+        expect(batch_result.send_metadata).to be true
+
+        # confirm the server can receive the client metadata
+        recvd_rpc = @server.request_call(@server_queue, @server_tag, deadline)
+        expect(recvd_rpc).to_not eq nil
+        recvd_md = recvd_rpc.metadata
         replace_symbols = Hash[md.each_pair.collect { |x, y| [x.to_s, y] }]
-        result = ev.result.metadata
-        expect(result.merge(replace_symbols)).to eq(result)
+        expect(recvd_md).to eq(recvd_md.merge(replace_symbols))
       end
     end
   end
@@ -266,55 +258,81 @@ shared_examples 'GRPC metadata delivery works OK' do
     it 'raises an exception if a metadata key is invalid' do
       @bad_keys.each do |md|
         call = new_client_call
-        call.invoke(@client_queue, @client_metadata_tag, @client_finished_tag)
+        # client signals that it's done sending metadata to allow server to
+        # respond
+        client_ops = {
+          CallOps::SEND_INITIAL_METADATA => nil
+        }
+        call.run_batch(@client_queue, @client_tag, deadline, client_ops)
 
         # server gets the invocation
-        @server.request_call(@server_tag)
-        ev = expect_next_event_on(@server_queue, SERVER_RPC_NEW, @server_tag)
-        expect { ev.call.add_metadata(md) }.to raise_error
+        recvd_rpc = @server.request_call(@server_queue, @server_tag, deadline)
+        expect(recvd_rpc).to_not eq nil
+        server_ops = {
+          CallOps::SEND_INITIAL_METADATA => md
+        }
+        blk = proc do
+          recvd_rpc.call.run_batch(@server_queue, @server_tag, deadline,
+                                   server_ops)
+        end
+        expect(&blk).to raise_error
       end
     end
 
-    it 'sends a hash that contains the status when no metadata is added' do
+    it 'sends an empty hash if no metadata is added' do
       call = new_client_call
-      call.invoke(@client_queue, @client_metadata_tag, @client_finished_tag)
-
-      # server gets the invocation
-      @server.request_call(@server_tag)
-      ev = expect_next_event_on(@server_queue, SERVER_RPC_NEW, @server_tag)
-      server_call = ev.call
-
-      # ... server accepts the call without adding metadata
-      server_call.server_accept(@server_queue, @server_finished_tag)
-      server_call.server_end_initial_metadata
-
-      # there is the HTTP status metadata, though there should not be any
-      # TODO: update this with the bug number to be resolved
-      ev = expect_next_event_on(@client_queue, CLIENT_METADATA_READ,
-                                @client_metadata_tag)
-      expect(ev.result).to eq({})
+      # client signals that it's done sending metadata to allow server to
+      # respond
+      client_ops = {
+        CallOps::SEND_INITIAL_METADATA => nil
+      }
+      call.run_batch(@client_queue, @client_tag, deadline, client_ops)
+
+      # server gets the invocation but sends no metadata back
+      recvd_rpc = @server.request_call(@server_queue, @server_tag, deadline)
+      expect(recvd_rpc).to_not eq nil
+      server_call = recvd_rpc.call
+      server_ops = {
+        CallOps::SEND_INITIAL_METADATA => nil
+      }
+      server_call.run_batch(@server_queue, @server_tag, deadline, server_ops)
+
+      # client receives nothing as expected
+      client_ops = {
+        CallOps::RECV_INITIAL_METADATA => nil
+      }
+      batch_result = call.run_batch(@client_queue, @client_tag, deadline,
+                                    client_ops)
+      expect(batch_result.metadata).to eq({})
     end
 
     it 'sends all the pairs when keys and values are valid' do
       @valid_metadata.each do |md|
         call = new_client_call
-        call.invoke(@client_queue, @client_metadata_tag, @client_finished_tag)
-
-        # server gets the invocation
-        @server.request_call(@server_tag)
-        ev = expect_next_event_on(@server_queue, SERVER_RPC_NEW, @server_tag)
-        server_call = ev.call
-
-        # ... server adds metadata and accepts the call
-        server_call.add_metadata(md)
-        server_call.server_accept(@server_queue, @server_finished_tag)
-        server_call.server_end_initial_metadata
-
-        # Now the client can read the metadata
-        ev = expect_next_event_on(@client_queue, CLIENT_METADATA_READ,
-                                  @client_metadata_tag)
+        # client signals that it's done sending metadata to allow server to
+        # respond
+        client_ops = {
+          CallOps::SEND_INITIAL_METADATA => nil
+        }
+        call.run_batch(@client_queue, @client_tag, deadline, client_ops)
+
+        # server gets the invocation but sends no metadata back
+        recvd_rpc = @server.request_call(@server_queue, @server_tag, deadline)
+        expect(recvd_rpc).to_not eq nil
+        server_call = recvd_rpc.call
+        server_ops = {
+          CallOps::SEND_INITIAL_METADATA => md
+        }
+        server_call.run_batch(@server_queue, @server_tag, deadline, server_ops)
+
+        # client receives nothing as expected
+        client_ops = {
+          CallOps::RECV_INITIAL_METADATA => nil
+        }
+        batch_result = call.run_batch(@client_queue, @client_tag, deadline,
+                                      client_ops)
         replace_symbols = Hash[md.each_pair.collect { |x, y| [x.to_s, y] }]
-        expect(ev.result).to eq(replace_symbols)
+        expect(batch_result.metadata).to eq(replace_symbols)
       end
     end
   end
diff --git a/src/ruby/spec/event_spec.rb b/src/ruby/spec/event_spec.rb
deleted file mode 100644
index 7d92fcd792870c07c937a6213f780f01d2b89cb2..0000000000000000000000000000000000000000
--- a/src/ruby/spec/event_spec.rb
+++ /dev/null
@@ -1,53 +0,0 @@
-# Copyright 2015, Google Inc.
-# All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions are
-# met:
-#
-#     * Redistributions of source code must retain the above copyright
-# notice, this list of conditions and the following disclaimer.
-#     * Redistributions in binary form must reproduce the above
-# copyright notice, this list of conditions and the following disclaimer
-# in the documentation and/or other materials provided with the
-# distribution.
-#     * Neither the name of Google Inc. nor the names of its
-# contributors may be used to endorse or promote products derived from
-# this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-require 'grpc'
-
-describe GRPC::Core::CompletionType do
-  before(:each) do
-    @known_types = {
-      QUEUE_SHUTDOWN: 0,
-      OP_COMPLETE: 1,
-      READ: 2,
-      WRITE_ACCEPTED: 3,
-      FINISH_ACCEPTED: 4,
-      CLIENT_METADATA_READ: 5,
-      FINISHED: 6,
-      SERVER_RPC_NEW: 7,
-      SERVER_SHUTDOWN: 8,
-      RESERVED: 9
-    }
-  end
-
-  it 'should have all the known types' do
-    mod = GRPC::Core::CompletionType
-    blk = proc { Hash[mod.constants.collect { |c| [c, mod.const_get(c)] }] }
-    expect(blk.call).to eq(@known_types)
-  end
-end
diff --git a/src/ruby/spec/generic/active_call_spec.rb b/src/ruby/spec/generic/active_call_spec.rb
index 96e07cacb44ae3351a6a502225742e23b8653784..575871afb110aa1de18dad5c34ec6c2fc215c3be 100644
--- a/src/ruby/spec/generic/active_call_spec.rb
+++ b/src/ruby/spec/generic/active_call_spec.rb
@@ -34,12 +34,11 @@ include GRPC::Core::StatusCodes
 describe GRPC::ActiveCall do
   ActiveCall = GRPC::ActiveCall
   Call = GRPC::Core::Call
-  CompletionType = GRPC::Core::CompletionType
+  CallOps = GRPC::Core::CallOps
 
   before(:each) do
     @pass_through = proc { |x| x }
     @server_tag = Object.new
-    @server_done_tag = Object.new
     @tag = Object.new
 
     @client_queue = GRPC::Core::CompletionQueue.new
@@ -48,7 +47,7 @@ describe GRPC::ActiveCall do
     @server = GRPC::Core::Server.new(@server_queue, nil)
     server_port = @server.add_http2_port(host)
     @server.start
-    @ch = GRPC::Core::Channel.new("localhost:#{server_port}", nil)
+    @ch = GRPC::Core::Channel.new("0.0.0.0:#{server_port}", nil)
   end
 
   after(:each) do
@@ -58,12 +57,10 @@ describe GRPC::ActiveCall do
   describe 'restricted view methods' do
     before(:each) do
       call = make_test_call
-      done_tag, meta_tag = ActiveCall.client_invoke(call, @client_queue,
-                                                    deadline)
+      md_tag = ActiveCall.client_invoke(call, @client_queue, deadline)
       @client_call = ActiveCall.new(call, @client_queue, @pass_through,
                                     @pass_through, deadline,
-                                    finished_tag: done_tag,
-                                    read_metadata_tag: meta_tag)
+                                    metadata_tag: md_tag)
     end
 
     describe '#multi_req_view' do
@@ -90,48 +87,45 @@ describe GRPC::ActiveCall do
   describe '#remote_send' do
     it 'allows a client to send a payload to the server' do
       call = make_test_call
-      done_tag, meta_tag = ActiveCall.client_invoke(call, @client_queue,
-                                                    deadline)
+      md_tag = ActiveCall.client_invoke(call, @client_queue, deadline)
       @client_call = ActiveCall.new(call, @client_queue, @pass_through,
                                     @pass_through, deadline,
-                                    finished_tag: done_tag,
-                                    read_metadata_tag: meta_tag)
+                                    metadata_tag: md_tag)
       msg = 'message is a string'
       @client_call.remote_send(msg)
 
       # check that server rpc new was received
-      @server.request_call(@server_tag)
-      ev = @server_queue.next(deadline)
-      expect(ev.type).to be(CompletionType::SERVER_RPC_NEW)
-      expect(ev.call).to be_a(Call)
-      expect(ev.tag).to be(@server_tag)
+      recvd_rpc = @server.request_call(@server_queue, @server_tag, deadline)
+      expect(recvd_rpc).to_not eq nil
+      recvd_call = recvd_rpc.call
 
       # Accept the call, and verify that the server reads the response ok.
-      ev.call.server_accept(@client_queue, @server_tag)
-      ev.call.server_end_initial_metadata
-      server_call = ActiveCall.new(ev.call, @client_queue, @pass_through,
+      server_ops = {
+        CallOps::SEND_INITIAL_METADATA => {}
+      }
+      recvd_call.run_batch(@server_queue, @server_tag, deadline, server_ops)
+      server_call = ActiveCall.new(recvd_call, @server_queue, @pass_through,
                                    @pass_through, deadline)
       expect(server_call.remote_read).to eq(msg)
     end
 
     it 'marshals the payload using the marshal func' do
       call = make_test_call
-      done_tag, meta_tag = ActiveCall.client_invoke(call, @client_queue,
-                                                    deadline)
+      ActiveCall.client_invoke(call, @client_queue, deadline)
       marshal = proc { |x| 'marshalled:' + x }
       client_call = ActiveCall.new(call, @client_queue, marshal,
-                                   @pass_through, deadline,
-                                   finished_tag: done_tag,
-                                   read_metadata_tag: meta_tag)
+                                   @pass_through, deadline)
       msg = 'message is a string'
       client_call.remote_send(msg)
 
       # confirm that the message was marshalled
-      @server.request_call(@server_tag)
-      ev = @server_queue.next(deadline)
-      ev.call.server_accept(@client_queue, @server_tag)
-      ev.call.server_end_initial_metadata
-      server_call = ActiveCall.new(ev.call, @client_queue, @pass_through,
+      recvd_rpc =  @server.request_call(@server_queue, @server_tag, deadline)
+      recvd_call = recvd_rpc.call
+      server_ops = {
+        CallOps::SEND_INITIAL_METADATA => nil
+      }
+      recvd_call.run_batch(@server_queue, @server_tag, deadline, server_ops)
+      server_call = ActiveCall.new(recvd_call, @server_queue, @pass_through,
                                    @pass_through, deadline)
       expect(server_call.remote_read).to eq('marshalled:' + msg)
     end
@@ -142,23 +136,22 @@ describe GRPC::ActiveCall do
       call = make_test_call
       ActiveCall.client_invoke(call, @client_queue, deadline,
                                k1: 'v1', k2: 'v2')
-      @server.request_call(@server_tag)
-      ev = @server_queue.next(deadline)
-      expect(ev).to_not be_nil
-      expect(ev.result.metadata['k1']).to eq('v1')
-      expect(ev.result.metadata['k2']).to eq('v2')
+      recvd_rpc =  @server.request_call(@server_queue, @server_tag, deadline)
+      recvd_call = recvd_rpc.call
+      expect(recvd_call).to_not be_nil
+      expect(recvd_rpc.metadata).to_not be_nil
+      expect(recvd_rpc.metadata['k1']).to eq('v1')
+      expect(recvd_rpc.metadata['k2']).to eq('v2')
     end
   end
 
   describe '#remote_read' do
     it 'reads the response sent by a server' do
       call = make_test_call
-      done_tag, meta_tag = ActiveCall.client_invoke(call, @client_queue,
-                                                    deadline)
+      md_tag = ActiveCall.client_invoke(call, @client_queue, deadline)
       client_call = ActiveCall.new(call, @client_queue, @pass_through,
                                    @pass_through, deadline,
-                                   finished_tag: done_tag,
-                                   read_metadata_tag: meta_tag)
+                                   metadata_tag: md_tag)
       msg = 'message is a string'
       client_call.remote_send(msg)
       server_call = expect_server_to_receive(msg)
@@ -168,12 +161,10 @@ describe GRPC::ActiveCall do
 
     it 'saves no metadata when the server adds no metadata' do
       call = make_test_call
-      done_tag, meta_tag = ActiveCall.client_invoke(call, @client_queue,
-                                                    deadline)
+      md_tag = ActiveCall.client_invoke(call, @client_queue, deadline)
       client_call = ActiveCall.new(call, @client_queue, @pass_through,
                                    @pass_through, deadline,
-                                   finished_tag: done_tag,
-                                   read_metadata_tag: meta_tag)
+                                   metadata_tag: md_tag)
       msg = 'message is a string'
       client_call.remote_send(msg)
       server_call = expect_server_to_receive(msg)
@@ -185,12 +176,10 @@ describe GRPC::ActiveCall do
 
     it 'saves metadata add by the server' do
       call = make_test_call
-      done_tag, meta_tag = ActiveCall.client_invoke(call, @client_queue,
-                                                    deadline)
+      md_tag = ActiveCall.client_invoke(call, @client_queue, deadline)
       client_call = ActiveCall.new(call, @client_queue, @pass_through,
                                    @pass_through, deadline,
-                                   finished_tag: done_tag,
-                                   read_metadata_tag: meta_tag)
+                                   metadata_tag: md_tag)
       msg = 'message is a string'
       client_call.remote_send(msg)
       server_call = expect_server_to_receive(msg, k1: 'v1', k2: 'v2')
@@ -203,12 +192,10 @@ describe GRPC::ActiveCall do
 
     it 'get a nil msg before a status when an OK status is sent' do
       call = make_test_call
-      done_tag, meta_tag = ActiveCall.client_invoke(call, @client_queue,
-                                                    deadline)
+      md_tag = ActiveCall.client_invoke(call, @client_queue, deadline)
       client_call = ActiveCall.new(call, @client_queue, @pass_through,
                                    @pass_through, deadline,
-                                   finished_tag: done_tag,
-                                   read_metadata_tag: meta_tag)
+                                   metadata_tag: md_tag)
       msg = 'message is a string'
       client_call.remote_send(msg)
       client_call.writes_done(false)
@@ -222,13 +209,11 @@ describe GRPC::ActiveCall do
 
     it 'unmarshals the response using the unmarshal func' do
       call = make_test_call
-      done_tag, meta_tag = ActiveCall.client_invoke(call, @client_queue,
-                                                    deadline)
+      md_tag = ActiveCall.client_invoke(call, @client_queue, deadline)
       unmarshal = proc { |x| 'unmarshalled:' + x }
       client_call = ActiveCall.new(call, @client_queue, @pass_through,
                                    unmarshal, deadline,
-                                   finished_tag: done_tag,
-                                   read_metadata_tag: meta_tag)
+                                   metadata_tag: md_tag)
 
       # confirm the client receives the unmarshalled message
       msg = 'message is a string'
@@ -249,13 +234,11 @@ describe GRPC::ActiveCall do
 
     it 'the returns an enumerator that can read n responses' do
       call = make_test_call
-      done_tag, meta_tag = ActiveCall.client_invoke(call, @client_queue,
-                                                    deadline)
+      md_tag = ActiveCall.client_invoke(call, @client_queue, deadline)
       client_call = ActiveCall.new(call, @client_queue, @pass_through,
                                    @pass_through, deadline,
-                                   finished_tag: done_tag,
-                                   read_metadata_tag: meta_tag)
-      msg = 'message is 4a string'
+                                   metadata_tag: md_tag)
+      msg = 'message is a string'
       reply = 'server_response'
       client_call.remote_send(msg)
       server_call = expect_server_to_receive(msg)
@@ -269,12 +252,10 @@ describe GRPC::ActiveCall do
 
     it 'the returns an enumerator that stops after an OK Status' do
       call = make_test_call
-      done_tag, meta_tag = ActiveCall.client_invoke(call, @client_queue,
-                                                    deadline)
+      md_tag = ActiveCall.client_invoke(call, @client_queue, deadline)
       client_call = ActiveCall.new(call, @client_queue, @pass_through,
                                    @pass_through, deadline,
-                                   read_metadata_tag: meta_tag,
-                                   finished_tag: done_tag)
+                                   metadata_tag: md_tag)
       msg = 'message is a string'
       reply = 'server_response'
       client_call.remote_send(msg)
@@ -294,12 +275,10 @@ describe GRPC::ActiveCall do
   describe '#writes_done' do
     it 'finishes ok if the server sends a status response' do
       call = make_test_call
-      done_tag, meta_tag = ActiveCall.client_invoke(call, @client_queue,
-                                                    deadline)
+      md_tag = ActiveCall.client_invoke(call, @client_queue, deadline)
       client_call = ActiveCall.new(call, @client_queue, @pass_through,
                                    @pass_through, deadline,
-                                   finished_tag: done_tag,
-                                   read_metadata_tag: meta_tag)
+                                   metadata_tag: md_tag)
       msg = 'message is a string'
       client_call.remote_send(msg)
       expect { client_call.writes_done(false) }.to_not raise_error
@@ -312,12 +291,10 @@ describe GRPC::ActiveCall do
 
     it 'finishes ok if the server sends an early status response' do
       call = make_test_call
-      done_tag, meta_tag = ActiveCall.client_invoke(call, @client_queue,
-                                                    deadline)
+      md_tag = ActiveCall.client_invoke(call, @client_queue, deadline)
       client_call = ActiveCall.new(call, @client_queue, @pass_through,
                                    @pass_through, deadline,
-                                   read_metadata_tag: meta_tag,
-                                   finished_tag: done_tag)
+                                   metadata_tag: md_tag)
       msg = 'message is a string'
       client_call.remote_send(msg)
       server_call = expect_server_to_receive(msg)
@@ -330,12 +307,10 @@ describe GRPC::ActiveCall do
 
     it 'finishes ok if writes_done is true' do
       call = make_test_call
-      done_tag, meta_tag = ActiveCall.client_invoke(call, @client_queue,
-                                                    deadline)
+      md_tag = ActiveCall.client_invoke(call, @client_queue, deadline)
       client_call = ActiveCall.new(call, @client_queue, @pass_through,
                                    @pass_through, deadline,
-                                   read_metadata_tag: meta_tag,
-                                   finished_tag: done_tag)
+                                   metadata_tag: md_tag)
       msg = 'message is a string'
       client_call.remote_send(msg)
       server_call = expect_server_to_receive(msg)
@@ -353,21 +328,20 @@ describe GRPC::ActiveCall do
   end
 
   def expect_server_to_be_invoked(**kw)
-    @server.request_call(@server_tag)
-    ev = @server_queue.next(deadline)
-    ev.call.add_metadata(kw)
-    ev.call.server_accept(@client_queue, @server_done_tag)
-    ev.call.server_end_initial_metadata
-    ActiveCall.new(ev.call, @client_queue, @pass_through,
-                   @pass_through, deadline,
-                   finished_tag: @server_done_tag)
+    recvd_rpc =  @server.request_call(@server_queue, @server_tag, deadline)
+    expect(recvd_rpc).to_not eq nil
+    recvd_call = recvd_rpc.call
+    recvd_call.run_batch(@server_queue, @server_tag, deadline,
+                         CallOps::SEND_INITIAL_METADATA => kw)
+    ActiveCall.new(recvd_call, @server_queue, @pass_through,
+                   @pass_through, deadline)
   end
 
   def make_test_call
-    @ch.create_call('dummy_method', 'dummy_host', deadline)
+    @ch.create_call(@client_queue, '/method', 'a.dummy.host', deadline)
   end
 
   def deadline
-    Time.now + 1  # in 1 second; arbitrary
+    Time.now + 2  # in 2 seconds; arbitrary
   end
 end
diff --git a/src/ruby/spec/generic/client_stub_spec.rb b/src/ruby/spec/generic/client_stub_spec.rb
index 0c98fc40d91a5949d2142c232d75e0151b4273c7..193c5f2a0387b23c2eca5a7ddf64620de3b5d1f8 100644
--- a/src/ruby/spec/generic/client_stub_spec.rb
+++ b/src/ruby/spec/generic/client_stub_spec.rb
@@ -30,15 +30,41 @@
 require 'grpc'
 require 'xray/thread_dump_signal_handler'
 
-NOOP = proc { |x| x }
-FAKE_HOST = 'localhost:0'
+# Notifier is useful high-level synchronization primitive.
+class Notifier
+  attr_reader :payload, :notified
+  alias_method :notified?, :notified
+
+  def initialize
+    @mutex    = Mutex.new
+    @cvar     = ConditionVariable.new
+    @notified = false
+    @payload  = nil
+  end
+
+  def wait
+    @mutex.synchronize do
+      @cvar.wait(@mutex) until notified?
+    end
+  end
+
+  def notify(payload)
+    @mutex.synchronize do
+      return Error.new('already notified') if notified?
+      @payload  = payload
+      @notified = true
+      @cvar.signal
+      return nil
+    end
+  end
+end
 
 def wakey_thread(&blk)
-  awake_mutex, awake_cond = Mutex.new, ConditionVariable.new
+  n = Notifier.new
   t = Thread.new do
-    blk.call(awake_mutex, awake_cond)
+    blk.call(n)
   end
-  awake_mutex.synchronize { awake_cond.wait(awake_mutex) }
+  n.wait
   t
 end
 
@@ -50,8 +76,11 @@ end
 
 include GRPC::Core::StatusCodes
 include GRPC::Core::TimeConsts
+include GRPC::Core::CallOps
 
 describe 'ClientStub' do
+  let(:noop) { proc { |x| x } }
+
   before(:each) do
     Thread.abort_on_exception = true
     @server = nil
@@ -66,61 +95,56 @@ describe 'ClientStub' do
   end
 
   describe '#new' do
+    let(:fake_host) { 'localhost:0' }
     it 'can be created from a host and args' do
-      host = FAKE_HOST
       opts = { a_channel_arg: 'an_arg' }
       blk = proc do
-        GRPC::ClientStub.new(host, @cq, **opts)
+        GRPC::ClientStub.new(fake_host, @cq, **opts)
       end
       expect(&blk).not_to raise_error
     end
 
     it 'can be created with a default deadline' do
-      host = FAKE_HOST
       opts = { a_channel_arg: 'an_arg', deadline: 5 }
       blk = proc do
-        GRPC::ClientStub.new(host, @cq, **opts)
+        GRPC::ClientStub.new(fake_host, @cq, **opts)
       end
       expect(&blk).not_to raise_error
     end
 
     it 'can be created with an channel override' do
-      host = FAKE_HOST
       opts = { a_channel_arg: 'an_arg', channel_override: @ch }
       blk = proc do
-        GRPC::ClientStub.new(host, @cq, **opts)
+        GRPC::ClientStub.new(fake_host, @cq, **opts)
       end
       expect(&blk).not_to raise_error
     end
 
     it 'cannot be created with a bad channel override' do
-      host = FAKE_HOST
       blk = proc do
         opts = { a_channel_arg: 'an_arg', channel_override: Object.new }
-        GRPC::ClientStub.new(host, @cq, **opts)
+        GRPC::ClientStub.new(fake_host, @cq, **opts)
       end
       expect(&blk).to raise_error
     end
 
     it 'cannot be created with bad credentials' do
-      host = FAKE_HOST
       blk = proc do
         opts = { a_channel_arg: 'an_arg', creds: Object.new }
-        GRPC::ClientStub.new(host, @cq, **opts)
+        GRPC::ClientStub.new(fake_host, @cq, **opts)
       end
       expect(&blk).to raise_error
     end
 
     it 'can be created with test test credentials' do
       certs = load_test_certs
-      host = FAKE_HOST
       blk = proc do
         opts = {
           GRPC::Core::Channel::SSL_TARGET => 'foo.test.google.fr',
           a_channel_arg: 'an_arg',
           creds: GRPC::Core::Credentials.new(certs[0], nil, nil)
         }
-        GRPC::ClientStub.new(host, @cq, **opts)
+        GRPC::ClientStub.new(fake_host, @cq, **opts)
       end
       expect(&blk).to_not raise_error
     end
@@ -187,7 +211,7 @@ describe 'ClientStub' do
 
     describe 'without a call operation' do
       def get_response(stub)
-        stub.request_response(@method, @sent_msg, NOOP, NOOP,
+        stub.request_response(@method, @sent_msg, noop, noop,
                               k1: 'v1', k2: 'v2')
       end
 
@@ -196,7 +220,7 @@ describe 'ClientStub' do
 
     describe 'via a call operation' do
       def get_response(stub)
-        op = stub.request_response(@method, @sent_msg, NOOP, NOOP,
+        op = stub.request_response(@method, @sent_msg, noop, noop,
                                    return_op: true, k1: 'v1', k2: 'v2')
         expect(op).to be_a(GRPC::ActiveCall::Operation)
         op.execute
@@ -259,7 +283,7 @@ describe 'ClientStub' do
 
     describe 'without a call operation' do
       def get_response(stub)
-        stub.client_streamer(@method, @sent_msgs, NOOP, NOOP,
+        stub.client_streamer(@method, @sent_msgs, noop, noop,
                              k1: 'v1', k2: 'v2')
       end
 
@@ -268,7 +292,7 @@ describe 'ClientStub' do
 
     describe 'via a call operation' do
       def get_response(stub)
-        op = stub.client_streamer(@method, @sent_msgs, NOOP, NOOP,
+        op = stub.client_streamer(@method, @sent_msgs, noop, noop,
                                   return_op: true, k1: 'v1', k2: 'v2')
         expect(op).to be_a(GRPC::ActiveCall::Operation)
         op.execute
@@ -333,7 +357,7 @@ describe 'ClientStub' do
 
     describe 'without a call operation' do
       def get_responses(stub)
-        e = stub.server_streamer(@method, @sent_msg, NOOP, NOOP,
+        e = stub.server_streamer(@method, @sent_msg, noop, noop,
                                  k1: 'v1', k2: 'v2')
         expect(e).to be_a(Enumerator)
         e
@@ -344,7 +368,7 @@ describe 'ClientStub' do
 
     describe 'via a call operation' do
       def get_responses(stub)
-        op = stub.server_streamer(@method, @sent_msg, NOOP, NOOP,
+        op = stub.server_streamer(@method, @sent_msg, noop, noop,
                                   return_op: true, k1: 'v1', k2: 'v2')
         expect(op).to be_a(GRPC::ActiveCall::Operation)
         e = op.execute
@@ -361,34 +385,30 @@ describe 'ClientStub' do
       before(:each) do
         @sent_msgs = Array.new(3) { |i| 'msg_' + (i + 1).to_s }
         @replys = Array.new(3) { |i| 'reply_' + (i + 1).to_s }
+        server_port = create_test_server
+        @host = "localhost:#{server_port}"
       end
 
       it 'supports sending all the requests first', bidi: true do
-        server_port = create_test_server
-        host = "localhost:#{server_port}"
         th = run_bidi_streamer_handle_inputs_first(@sent_msgs, @replys,
                                                    @pass)
-        stub = GRPC::ClientStub.new(host, @cq)
+        stub = GRPC::ClientStub.new(@host, @cq)
         e = get_responses(stub)
         expect(e.collect { |r| r }).to eq(@replys)
         th.join
       end
 
       it 'supports client-initiated ping pong', bidi: true do
-        server_port = create_test_server
-        host = "localhost:#{server_port}"
         th = run_bidi_streamer_echo_ping_pong(@sent_msgs, @pass, true)
-        stub = GRPC::ClientStub.new(host, @cq)
+        stub = GRPC::ClientStub.new(@host, @cq)
         e = get_responses(stub)
         expect(e.collect { |r| r }).to eq(@sent_msgs)
         th.join
       end
 
       it 'supports a server-initiated ping pong', bidi: true do
-        server_port = create_test_server
-        host = "localhost:#{server_port}"
         th = run_bidi_streamer_echo_ping_pong(@sent_msgs, @pass, false)
-        stub = GRPC::ClientStub.new(host, @cq)
+        stub = GRPC::ClientStub.new(@host, @cq)
         e = get_responses(stub)
         expect(e.collect { |r| r }).to eq(@sent_msgs)
         th.join
@@ -397,7 +417,7 @@ describe 'ClientStub' do
 
     describe 'without a call operation' do
       def get_responses(stub)
-        e = stub.bidi_streamer(@method, @sent_msgs, NOOP, NOOP)
+        e = stub.bidi_streamer(@method, @sent_msgs, noop, noop)
         expect(e).to be_a(Enumerator)
         e
       end
@@ -407,7 +427,7 @@ describe 'ClientStub' do
 
     describe 'via a call operation' do
       def get_responses(stub)
-        op = stub.bidi_streamer(@method, @sent_msgs, NOOP, NOOP,
+        op = stub.bidi_streamer(@method, @sent_msgs, noop, noop,
                                 return_op: true)
         expect(op).to be_a(GRPC::ActiveCall::Operation)
         e = op.execute
@@ -421,8 +441,8 @@ describe 'ClientStub' do
 
   def run_server_streamer(expected_input, replys, status, **kw)
     wanted_metadata = kw.clone
-    wakey_thread do |mtx, cnd|
-      c = expect_server_to_be_invoked(mtx, cnd)
+    wakey_thread do |notifier|
+      c = expect_server_to_be_invoked(notifier)
       wanted_metadata.each do |k, v|
         expect(c.metadata[k.to_s]).to eq(v)
       end
@@ -434,8 +454,8 @@ describe 'ClientStub' do
 
   def run_bidi_streamer_handle_inputs_first(expected_inputs, replys,
                                             status)
-    wakey_thread do |mtx, cnd|
-      c = expect_server_to_be_invoked(mtx, cnd)
+    wakey_thread do |notifier|
+      c = expect_server_to_be_invoked(notifier)
       expected_inputs.each { |i| expect(c.remote_read).to eq(i) }
       replys.each { |r| c.remote_send(r) }
       c.send_status(status, status == @pass ? 'OK' : 'NOK', true)
@@ -443,8 +463,8 @@ describe 'ClientStub' do
   end
 
   def run_bidi_streamer_echo_ping_pong(expected_inputs, status, client_starts)
-    wakey_thread do |mtx, cnd|
-      c = expect_server_to_be_invoked(mtx, cnd)
+    wakey_thread do |notifier|
+      c = expect_server_to_be_invoked(notifier)
       expected_inputs.each do |i|
         if client_starts
           expect(c.remote_read).to eq(i)
@@ -460,8 +480,8 @@ describe 'ClientStub' do
 
   def run_client_streamer(expected_inputs, resp, status, **kw)
     wanted_metadata = kw.clone
-    wakey_thread do |mtx, cnd|
-      c = expect_server_to_be_invoked(mtx, cnd)
+    wakey_thread do |notifier|
+      c = expect_server_to_be_invoked(notifier)
       expected_inputs.each { |i| expect(c.remote_read).to eq(i) }
       wanted_metadata.each do |k, v|
         expect(c.metadata[k.to_s]).to eq(v)
@@ -473,8 +493,8 @@ describe 'ClientStub' do
 
   def run_request_response(expected_input, resp, status, **kw)
     wanted_metadata = kw.clone
-    wakey_thread do |mtx, cnd|
-      c = expect_server_to_be_invoked(mtx, cnd)
+    wakey_thread do |notifier|
+      c = expect_server_to_be_invoked(notifier)
       expect(c.remote_read).to eq(expected_input)
       wanted_metadata.each do |k, v|
         expect(c.metadata[k.to_s]).to eq(v)
@@ -490,24 +510,16 @@ describe 'ClientStub' do
     @server.add_http2_port('0.0.0.0:0')
   end
 
-  def start_test_server(awake_mutex, awake_cond)
+  def expect_server_to_be_invoked(notifier)
     @server.start
-    @server_tag = Object.new
-    @server.request_call(@server_tag)
-    awake_mutex.synchronize { awake_cond.signal }
-  end
-
-  def expect_server_to_be_invoked(awake_mutex, awake_cond)
-    start_test_server(awake_mutex, awake_cond)
-    ev = @server_queue.pluck(@server_tag, INFINITE_FUTURE)
-    fail OutOfTime if ev.nil?
-    server_call = ev.call
-    server_call.metadata = ev.result.metadata
-    finished_tag = Object.new
-    server_call.server_accept(@server_queue, finished_tag)
-    server_call.server_end_initial_metadata
-    GRPC::ActiveCall.new(server_call, @server_queue, NOOP, NOOP,
-                         INFINITE_FUTURE,
-                         finished_tag: finished_tag)
+    notifier.notify(nil)
+    server_tag = Object.new
+    recvd_rpc = @server.request_call(@server_queue, server_tag,
+                                     INFINITE_FUTURE)
+    recvd_call = recvd_rpc.call
+    recvd_call.metadata = recvd_rpc.metadata
+    recvd_call.run_batch(@server_queue, server_tag, Time.now + 2,
+                         SEND_INITIAL_METADATA => nil)
+    GRPC::ActiveCall.new(recvd_call, @server_queue, noop, noop, INFINITE_FUTURE)
   end
 end
diff --git a/src/ruby/spec/generic/rpc_desc_spec.rb b/src/ruby/spec/generic/rpc_desc_spec.rb
index 39d1e83748bf4d2812278851ed2b1fbd3fef7a56..a68299465ce35e46433c6cb2cd75d552c61a41c7 100644
--- a/src/ruby/spec/generic/rpc_desc_spec.rb
+++ b/src/ruby/spec/generic/rpc_desc_spec.rb
@@ -37,7 +37,6 @@ describe GRPC::RpcDesc do
   INTERNAL = GRPC::Core::StatusCodes::INTERNAL
   UNKNOWN = GRPC::Core::StatusCodes::UNKNOWN
   CallError = GRPC::Core::CallError
-  EventError = GRPC::Core::EventError
 
   before(:each) do
     @request_response = RpcDesc.new('rr', Object.new, Object.new, 'encode',
@@ -63,24 +62,17 @@ describe GRPC::RpcDesc do
 
       it 'sends the specified status if BadStatus is raised' do
         expect(@call).to receive(:remote_read).once.and_return(Object.new)
-        expect(@call).to receive(:send_status).once.with(@bs_code, 'NOK')
+        expect(@call).to receive(:send_status).once.with(@bs_code, 'NOK', false)
         @request_response.run_server_method(@call, method(:bad_status))
       end
 
       it 'sends status UNKNOWN if other StandardErrors are raised' do
         expect(@call).to receive(:remote_read).once.and_return(Object.new)
-        expect(@call).to receive(:send_status) .once.with(UNKNOWN, @no_reason)
+        expect(@call).to receive(:send_status) .once.with(UNKNOWN, @no_reason,
+                                                          false)
         @request_response.run_server_method(@call, method(:other_error))
       end
 
-      it 'absorbs EventError  with no further action' do
-        expect(@call).to receive(:remote_read).once.and_raise(EventError)
-        blk = proc do
-          @request_response.run_server_method(@call, method(:fake_reqresp))
-        end
-        expect(&blk).to_not raise_error
-      end
-
       it 'absorbs CallError with no further action' do
         expect(@call).to receive(:remote_read).once.and_raise(CallError)
         blk = proc do
@@ -93,8 +85,7 @@ describe GRPC::RpcDesc do
         req = Object.new
         expect(@call).to receive(:remote_read).once.and_return(req)
         expect(@call).to receive(:remote_send).once.with(@ok_response)
-        expect(@call).to receive(:send_status).once.with(OK, 'OK')
-        expect(@call).to receive(:finished).once
+        expect(@call).to receive(:send_status).once.with(OK, 'OK', true)
         @request_response.run_server_method(@call, method(:fake_reqresp))
       end
     end
@@ -107,23 +98,16 @@ describe GRPC::RpcDesc do
       end
 
       it 'sends the specified status if BadStatus is raised' do
-        expect(@call).to receive(:send_status).once.with(@bs_code, 'NOK')
+        expect(@call).to receive(:send_status).once.with(@bs_code, 'NOK', false)
         @client_streamer.run_server_method(@call, method(:bad_status_alt))
       end
 
       it 'sends status UNKNOWN if other StandardErrors are raised' do
-        expect(@call).to receive(:send_status) .once.with(UNKNOWN, @no_reason)
+        expect(@call).to receive(:send_status) .once.with(UNKNOWN, @no_reason,
+                                                          false)
         @client_streamer.run_server_method(@call, method(:other_error_alt))
       end
 
-      it 'absorbs EventError  with no further action' do
-        expect(@call).to receive(:remote_send).once.and_raise(EventError)
-        blk = proc do
-          @client_streamer.run_server_method(@call, method(:fake_clstream))
-        end
-        expect(&blk).to_not raise_error
-      end
-
       it 'absorbs CallError with no further action' do
         expect(@call).to receive(:remote_send).once.and_raise(CallError)
         blk = proc do
@@ -134,8 +118,7 @@ describe GRPC::RpcDesc do
 
       it 'sends a response and closes the stream if there no errors' do
         expect(@call).to receive(:remote_send).once.with(@ok_response)
-        expect(@call).to receive(:send_status).once.with(OK, 'OK')
-        expect(@call).to receive(:finished).once
+        expect(@call).to receive(:send_status).once.with(OK, 'OK', true)
         @client_streamer.run_server_method(@call, method(:fake_clstream))
       end
     end
@@ -149,24 +132,17 @@ describe GRPC::RpcDesc do
 
       it 'sends the specified status if BadStatus is raised' do
         expect(@call).to receive(:remote_read).once.and_return(Object.new)
-        expect(@call).to receive(:send_status).once.with(@bs_code, 'NOK')
+        expect(@call).to receive(:send_status).once.with(@bs_code, 'NOK', false)
         @server_streamer.run_server_method(@call, method(:bad_status))
       end
 
       it 'sends status UNKNOWN if other StandardErrors are raised' do
         expect(@call).to receive(:remote_read).once.and_return(Object.new)
-        expect(@call).to receive(:send_status) .once.with(UNKNOWN, @no_reason)
+        expect(@call).to receive(:send_status) .once.with(UNKNOWN, @no_reason,
+                                                          false)
         @server_streamer.run_server_method(@call, method(:other_error))
       end
 
-      it 'absorbs EventError  with no further action' do
-        expect(@call).to receive(:remote_read).once.and_raise(EventError)
-        blk = proc do
-          @server_streamer.run_server_method(@call, method(:fake_svstream))
-        end
-        expect(&blk).to_not raise_error
-      end
-
       it 'absorbs CallError with no further action' do
         expect(@call).to receive(:remote_read).once.and_raise(CallError)
         blk = proc do
@@ -179,8 +155,7 @@ describe GRPC::RpcDesc do
         req = Object.new
         expect(@call).to receive(:remote_read).once.and_return(req)
         expect(@call).to receive(:remote_send).twice.with(@ok_response)
-        expect(@call).to receive(:send_status).once.with(OK, 'OK')
-        expect(@call).to receive(:finished).once
+        expect(@call).to receive(:send_status).once.with(OK, 'OK', true)
         @server_streamer.run_server_method(@call, method(:fake_svstream))
       end
     end
@@ -197,20 +172,20 @@ describe GRPC::RpcDesc do
       it 'sends the specified status if BadStatus is raised' do
         e = GRPC::BadStatus.new(@bs_code, 'NOK')
         expect(@call).to receive(:run_server_bidi).and_raise(e)
-        expect(@call).to receive(:send_status).once.with(@bs_code, 'NOK')
+        expect(@call).to receive(:send_status).once.with(@bs_code, 'NOK', false)
         @bidi_streamer.run_server_method(@call, method(:bad_status_alt))
       end
 
       it 'sends status UNKNOWN if other StandardErrors are raised' do
         expect(@call).to receive(:run_server_bidi).and_raise(StandardError)
-        expect(@call).to receive(:send_status).once.with(UNKNOWN, @no_reason)
+        expect(@call).to receive(:send_status).once.with(UNKNOWN, @no_reason,
+                                                         false)
         @bidi_streamer.run_server_method(@call, method(:other_error_alt))
       end
 
       it 'closes the stream if there no errors' do
         expect(@call).to receive(:run_server_bidi)
-        expect(@call).to receive(:send_status).once.with(OK, 'OK')
-        expect(@call).to receive(:finished).once
+        expect(@call).to receive(:send_status).once.with(OK, 'OK', true)
         @bidi_streamer.run_server_method(@call, method(:fake_bidistream))
       end
     end
diff --git a/src/ruby/spec/generic/rpc_server_spec.rb b/src/ruby/spec/generic/rpc_server_spec.rb
index 34e5cdcd04cd9389e02ed845c9a3dc5d27dae8b9..f409d73e2fed3ddb19f12b9b6bd2756019294739 100644
--- a/src/ruby/spec/generic/rpc_server_spec.rb
+++ b/src/ruby/spec/generic/rpc_server_spec.rb
@@ -364,7 +364,7 @@ describe GRPC::RpcServer do
         @srv.wait_till_running
         req = EchoMsg.new
         stub = SlowStub.new(@host, **@client_opts)
-        deadline = service.delay + 0.5 # wait for long enough
+        deadline = service.delay + 1.0 # wait for long enough
         expect(stub.an_rpc(req, deadline, k1: 'v1', k2: 'v2')).to be_a(EchoMsg)
         wanted_md = [{ 'k1' => 'v1', 'k2' => 'v2' }]
         expect(service.received_md).to eq(wanted_md)
diff --git a/src/ruby/spec/metadata_spec.rb b/src/ruby/spec/metadata_spec.rb
deleted file mode 100644
index 247286669210b5f1c56b172574e04f5aa658bd76..0000000000000000000000000000000000000000
--- a/src/ruby/spec/metadata_spec.rb
+++ /dev/null
@@ -1,64 +0,0 @@
-# Copyright 2015, Google Inc.
-# All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions are
-# met:
-#
-#     * Redistributions of source code must retain the above copyright
-# notice, this list of conditions and the following disclaimer.
-#     * Redistributions in binary form must reproduce the above
-# copyright notice, this list of conditions and the following disclaimer
-# in the documentation and/or other materials provided with the
-# distribution.
-#     * Neither the name of Google Inc. nor the names of its
-# contributors may be used to endorse or promote products derived from
-# this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-require 'grpc'
-
-describe GRPC::Core::Metadata do
-  describe '#new' do
-    it 'should create instances' do
-      expect { GRPC::Core::Metadata.new('a key', 'a value') }.to_not raise_error
-    end
-  end
-
-  describe '#key' do
-    md = GRPC::Core::Metadata.new('a key', 'a value')
-    it 'should be the constructor value' do
-      expect(md.key).to eq('a key')
-    end
-  end
-
-  describe '#value' do
-    md = GRPC::Core::Metadata.new('a key', 'a value')
-    it 'should be the constuctor value' do
-      expect(md.value).to eq('a value')
-    end
-  end
-
-  describe '#dup' do
-    it 'should create a copy that returns the correct key' do
-      md = GRPC::Core::Metadata.new('a key', 'a value')
-      expect(md.dup.key).to eq('a key')
-    end
-
-    it 'should create a copy that returns the correct value' do
-      md = GRPC::Core::Metadata.new('a key', 'a value')
-      expect(md.dup.value).to eq('a value')
-    end
-  end
-end
diff --git a/templates/BUILD.template b/templates/BUILD.template
index 997c55b1c89f83148572d4788bab10d8606a9fca..8303b9f8e9631a40ebe12da611c24f003cf56f4c 100644
--- a/templates/BUILD.template
+++ b/templates/BUILD.template
@@ -32,38 +32,79 @@
 
 licenses(["notice"])  # 3-clause BSD
 
+package(default_visibility = ["//visibility:public"])
+
+<%!
+def get_deps(target_dict):
+  deps = []
+  if target_dict.get('secure', 'no') == 'yes':
+    deps = [
+      "//external:libssl",
+    ]
+  if target_dict.get('build', None) == 'protoc':
+    deps.append("//external:protobuf_compiler")
+  if target_dict['name'] == 'grpc++_unsecure' or target_dict['name'] == 'grpc++':
+    deps.append("//external:protobuf_clib")
+  for d in target_dict.get('deps', []):
+    if d.find('//') == 0 or d[0] == ':':
+      deps.append(d)
+    else:
+      deps.append(':%s' % (d))
+  return deps
+%>
+
 % for lib in libs:
-% if lib.build == "all" and lib.language == 'c':
-${makelib(lib)}
+% if lib.build != "private":
+${cc_library(lib)}
 % endif
 % endfor
 
-<%def name="makelib(lib)">
+% for tgt in targets:
+% if tgt.build == 'protoc':
+${cc_binary(tgt)}
+% endif
+% endfor
 
+<%def name="cc_library(lib)">
 cc_library(
-    name = "${lib.name}",
-    srcs = [
+  name = "${lib.name}",
+  srcs = [
 % for hdr in lib.get("headers", []):
-        "${hdr}",
+    "${hdr}",
 % endfor
 % for src in lib.src:
-        "${src}",
+    "${src}",
 % endfor
-    ],
-    hdrs = [
+  ],
+  hdrs = [
 % for hdr in lib.get("public_headers", []):
-        "${hdr}",
+    "${hdr}",
 % endfor
-    ],
-    includes = [
-        "include",
-        ".",
-    ],
-    deps = [
-% for dep in lib.get("deps", []):
-        ":${dep}",
+  ],
+  includes = [
+    "include",
+    ".",
+  ],
+  deps = [
+% for dep in get_deps(lib):
+    "${dep}",
 % endfor
-    ],
+  ],
 )
+</%def>
 
+<%def name="cc_binary(tgt)">
+cc_binary(
+  name = "${tgt.name}",
+  srcs = [
+% for src in tgt.src:
+    "${src}",
+% endfor
+  ],
+  deps = [
+% for dep in get_deps(tgt):
+    "${dep}",
+% endfor
+  ],
+)
 </%def>
diff --git a/templates/Makefile.template b/templates/Makefile.template
index 776ee7a49b9c358f68313df5b644ad8bb2ec77a3..331141fb24572c3b355028cd8ad18870b7684ec7 100644
--- a/templates/Makefile.template
+++ b/templates/Makefile.template
@@ -930,6 +930,7 @@ else
 	$(Q) $(INSTALL) -d $(prefix)/lib
 	$(Q) $(INSTALL) $(LIBDIR)/$(CONFIG)/lib${lib.name}.$(SHARED_EXT) $(prefix)/lib/lib${lib.name}.$(SHARED_EXT)
 ifneq ($(SYSTEM),Darwin)
+	$(Q) ln -sf lib${lib.name}.$(SHARED_EXT) $(prefix)/lib/lib${lib.name}.so.${settings.version.major}
 	$(Q) ln -sf lib${lib.name}.$(SHARED_EXT) $(prefix)/lib/lib${lib.name}.so
 endif
 endif
@@ -1268,9 +1269,6 @@ $(BINDIR)/$(CONFIG)/${tgt.name}: $(${tgt.name.upper()}_OBJS)\
 	$(Q) mkdir -p `dirname $@`
 	$(Q) $(LDXX) $(LDFLAGS) $(${tgt.name.upper()}_OBJS)\
 % endif
-% if tgt.build == 'test':
- $(GTEST_LIB)\
-% endif
 % else:
 ## C-only targets specificities.
 	$(E) "[LD]      Linking $@"
@@ -1296,6 +1294,9 @@ $(BINDIR)/$(CONFIG)/${tgt.name}: $(${tgt.name.upper()}_OBJS)\
  $(HOST_LDLIBS_PROTOC)\
 % elif tgt.get('secure', 'check') == 'yes' or tgt.get('secure', 'check') == 'check':
  $(LDLIBS_SECURE)\
+% endif
+% if tgt.language == 'c++' and tgt.build == 'test':
+ $(GTEST_LIB)\
 % endif
  -o $(BINDIR)/$(CONFIG)/${tgt.name}
 % if tgt.build == 'protoc' or tgt.language == 'c++':
diff --git a/templates/tools/run_tests/tests.json.template b/templates/tools/run_tests/tests.json.template
index 6d7520bc0f82fee3d153c285cce4ff8c10cf3edc..337858d9f1f3e1672e1c7c42a6440a7096df0f6a 100644
--- a/templates/tools/run_tests/tests.json.template
+++ b/templates/tools/run_tests/tests.json.template
@@ -4,7 +4,8 @@ import json
 
 ${json.dumps([{"name": tgt.name,
                "language": tgt.language,
-               "flaky": tgt.get("flaky", False)}
+	       "platforms": tgt.platforms,
+               "flaky": tgt.flaky}
               for tgt in targets
               if tgt.get('run', True) and tgt.build == 'test'],
              sort_keys=True, indent=2)}
diff --git a/templates/vsprojects/vs2013/Grpc.mak.template b/templates/vsprojects/vs2013/Grpc.mak.template
index 8e1b33bba76c33790861d538a1f34d0ff19bedf9..c1c15df5c686e38d50fb66a9cfbe36517b2f7a05 100644
--- a/templates/vsprojects/vs2013/Grpc.mak.template
+++ b/templates/vsprojects/vs2013/Grpc.mak.template
@@ -32,8 +32,12 @@
 <%def name="to_windows_path(path)">${path.replace('/','\\')}</%def>\
 <%
   allowed_dependencies = set(['gpr', 'grpc', 'gpr_test_util', 'grpc_test_util'])
-  buildable_targets = [ target for target in targets if set(target.deps).issubset(allowed_dependencies) and all([src.endswith('.c') for src in target.src])]
-  test_targets = [ target for target in buildable_targets if target.name.endswith('_test') ]
+  buildable_targets = [ target for target in targets
+                        if set(target.deps).issubset(allowed_dependencies) and
+		           all([src.endswith('.c') for src in target.src]) and
+			   'windows' in target.platforms ]
+  c_test_targets = [ target for target in buildable_targets if target.build == 'test' and not target.language == 'c++' ]
+  cxx_test_targets = [ target for target in buildable_targets if target.build == 'test' and target.language == 'c++' ]
 %>\
 # NMake file to build secondary gRPC targets on Windows.
 # Use grpc.sln to solution to build the gRPC libraries.
@@ -62,29 +66,24 @@ grpc_test_util:
 $(OUT_DIR):
 	mkdir $(OUT_DIR)
 
-buildtests: \
-% for target in test_targets:
+buildtests: buildtests_c buildtests_cxx
+
+buildtests_c: \
+% for target in c_test_targets:
 ${target.name}.exe \
 % endfor
 
 	echo All tests built.
 
-test: \
-% for target in test_targets:
-${target.name} \
-% endfor
-
-	echo All tests ran.
-
-test_gpr: \
-% for target in [ tgt for tgt in test_targets if tgt.name.startswith('gpr_')]:
-${target.name} \
+buildtests_cxx: \
+% for target in cxx_test_targets:
+${target.name}.exe \
 % endfor
 
-	echo All tests ran.
+	echo All tests built.
 
 % for target in buildable_targets:
-${target.name}.exe: grpc_test_util
+${target.name}.exe: grpc_test_util $(OUT_DIR)
 	echo Building ${target.name}
 	$(CC) $(CFLAGS) /Fo:$(OUT_DIR)\ \
 %for source in target.src:
diff --git a/test/core/end2end/dualstack_socket_test.c b/test/core/end2end/dualstack_socket_test.c
index 66b76dc0523bb59ddc810bc94b96fcb5e5084e57..29097661bced78e98eb6bc956059ef7a0010efcb 100644
--- a/test/core/end2end/dualstack_socket_test.c
+++ b/test/core/end2end/dualstack_socket_test.c
@@ -192,7 +192,7 @@ int main(int argc, char **argv) {
     do_ipv6 = 0;
   }
 
-    /* For coverage, test with and without dualstack sockets. */
+  /* For coverage, test with and without dualstack sockets. */
   for (grpc_forbid_dualstack_sockets_for_testing = 0;
        grpc_forbid_dualstack_sockets_for_testing <= 1;
        grpc_forbid_dualstack_sockets_for_testing++) {
diff --git a/test/core/iomgr/alarm_test.c b/test/core/iomgr/alarm_test.c
index 8d49332fa65c1dd85a1b77df76523432176b74c4..e677ba30dde1318ccf6eaab145336a9f9b03ed51 100644
--- a/test/core/iomgr/alarm_test.c
+++ b/test/core/iomgr/alarm_test.c
@@ -37,13 +37,9 @@
 #include <ctype.h>
 #include <errno.h>
 #include <fcntl.h>
-#include <netinet/in.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
-#include <sys/socket.h>
-#include <sys/time.h>
-#include <unistd.h>
 
 #include <grpc/support/alloc.h>
 #include <grpc/support/log.h>
diff --git a/test/core/iomgr/tcp_server_posix_test.c b/test/core/iomgr/tcp_server_posix_test.c
index 6b80ee1ee8cc8294798e24a9df5ec65a3e046c24..1c02c4b2f8078a350938613c4cccd185f136877a 100644
--- a/test/core/iomgr/tcp_server_posix_test.c
+++ b/test/core/iomgr/tcp_server_posix_test.c
@@ -38,6 +38,7 @@
 #include <grpc/support/time.h>
 #include "test/core/util/test_config.h"
 
+#include <sys/socket.h>
 #include <netinet/in.h>
 #include <string.h>
 #include <unistd.h>
diff --git a/test/core/support/tls_test.c b/test/core/support/tls_test.c
new file mode 100644
index 0000000000000000000000000000000000000000..8632fd44901dfea5f407d4394f07a30e2c76703d
--- /dev/null
+++ b/test/core/support/tls_test.c
@@ -0,0 +1,82 @@
+/*
+ *
+ * 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 of gpr thread local storage support. */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <grpc/support/log.h>
+#include <grpc/support/sync.h>
+#include <grpc/support/thd.h>
+#include <grpc/support/tls.h>
+#include "test/core/util/test_config.h"
+
+#define NUM_THREADS 100
+
+GPR_TLS_DECL(test_var);
+
+static void thd_body(void *arg) {
+  gpr_intptr i;
+
+  GPR_ASSERT(gpr_tls_get(&test_var) == 0);
+
+  for (i = 0; i < 10000000; i++) {
+    gpr_tls_set(&test_var, i);
+    GPR_ASSERT(gpr_tls_get(&test_var) == i);
+  }
+}
+
+/* ------------------------------------------------- */
+
+int main(int argc, char *argv[]) {
+  gpr_thd_options opt = gpr_thd_options_default();
+  int i;
+  gpr_thd_id threads[NUM_THREADS];
+
+  grpc_test_init(argc, argv);
+
+  gpr_tls_init(&test_var);
+
+  gpr_thd_options_set_joinable(&opt);
+
+  for (i = 0; i < NUM_THREADS; i++) {
+    gpr_thd_new(&threads[i], thd_body, NULL, &opt);
+  }
+  for (i = 0; i < NUM_THREADS; i++) {
+    gpr_thd_join(threads[i]);
+  }
+
+  gpr_tls_destroy(&test_var);
+
+  return 0;
+}
diff --git a/test/core/transport/chttp2_transport_end2end_test.c b/test/core/transport/chttp2_transport_end2end_test.c
index b90fe2299993766e33cd1ae91d57dd551916c3ef..766fd19960eb6f77e8f2d3a84f9eb208f415f329 100644
--- a/test/core/transport/chttp2_transport_end2end_test.c
+++ b/test/core/transport/chttp2_transport_end2end_test.c
@@ -38,8 +38,6 @@
 #include <string.h>
 #include <signal.h>
 #include <sys/types.h>
-#include <sys/socket.h>
-#include <unistd.h>
 
 #include "test/core/util/test_config.h"
 #include "src/core/iomgr/iomgr.h"
diff --git a/test/core/util/port_windows.c b/test/core/util/port_windows.c
new file mode 100644
index 0000000000000000000000000000000000000000..17058c335339c63d3cf0ad1129290e1c0dbf1cc7
--- /dev/null
+++ b/test/core/util/port_windows.c
@@ -0,0 +1,158 @@
+/*
+ *
+ * Copyright 2015, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <grpc/support/port_platform.h>
+#include "test/core/util/test_config.h"
+#if defined(GPR_WINSOCK_SOCKET) && defined(GRPC_TEST_PICK_PORT)
+
+#include "src/core/iomgr/sockaddr_utils.h"
+#include "test/core/util/port.h"
+
+#include <process.h>
+#include <stdio.h>
+#include <errno.h>
+#include <string.h>
+
+#include <grpc/support/log.h>
+
+#define NUM_RANDOM_PORTS_TO_PICK 100
+
+static int is_port_available(int *port, int is_tcp) {
+  const int proto = is_tcp ? IPPROTO_TCP : 0;
+  const SOCKET fd = socket(AF_INET, is_tcp ? SOCK_STREAM : SOCK_DGRAM, proto);
+  int one = 1;
+  struct sockaddr_in addr;
+  socklen_t alen = sizeof(addr);
+  int actual_port;
+
+  GPR_ASSERT(*port >= 0);
+  GPR_ASSERT(*port <= 65535);
+  if (fd < 0) {
+    gpr_log(GPR_ERROR, "socket() failed: %s", strerror(errno));
+    return 0;
+  }
+
+  /* Reuseaddr lets us start up a server immediately after it exits */
+  if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (const char*)&one, sizeof(one)) < 0) {
+    gpr_log(GPR_ERROR, "setsockopt() failed: %s", strerror(errno));
+    closesocket(fd);
+    return 0;
+  }
+
+  /* Try binding to port */
+  addr.sin_family = AF_INET;
+  addr.sin_addr.s_addr = INADDR_ANY;
+  addr.sin_port = htons(*port);
+  if (bind(fd, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
+    gpr_log(GPR_DEBUG, "bind(port=%d) failed: %s", *port, strerror(errno));
+	closesocket(fd);
+    return 0;
+  }
+
+  /* Get the bound port number */
+  if (getsockname(fd, (struct sockaddr *)&addr, &alen) < 0) {
+    gpr_log(GPR_ERROR, "getsockname() failed: %s", strerror(errno));
+	closesocket(fd);
+    return 0;
+  }
+  GPR_ASSERT(alen <= sizeof(addr));
+  actual_port = ntohs(addr.sin_port);
+  GPR_ASSERT(actual_port > 0);
+  if (*port == 0) {
+    *port = actual_port;
+  } else {
+    GPR_ASSERT(*port == actual_port);
+  }
+
+  closesocket(fd);
+  return 1;
+}
+
+int grpc_pick_unused_port(void) {
+  /* We repeatedly pick a port and then see whether or not it is
+     available for use both as a TCP socket and a UDP socket.  First, we
+     pick a random large port number.  For subsequent
+     iterations, we bind to an anonymous port and let the OS pick the
+     port number.  The random port picking reduces the probability of
+     races with other processes on kernels that want to reuse the same
+     port numbers over and over. */
+
+  /* In alternating iterations we try UDP ports before TCP ports UDP
+     ports -- it could be the case that this machine has been using up
+     UDP ports and they are scarcer. */
+
+  /* Type of port to first pick in next iteration */
+  int is_tcp = 1;
+  int try = 0;
+
+  for (;;) {
+    int port;
+    try++;
+    if (try == 1) {
+      port = _getpid() % (65536 - 30000) + 30000;
+    } else if (try <= NUM_RANDOM_PORTS_TO_PICK) {
+      port = rand() % (65536 - 30000) + 30000;
+    } else {
+      port = 0;
+    }
+
+    if (!is_port_available(&port, is_tcp)) {
+      continue;
+    }
+
+    GPR_ASSERT(port > 0);
+    /* Check that the port # is free for the other type of socket also */
+    if (!is_port_available(&port, !is_tcp)) {
+      /* In the next iteration try to bind to the other type first
+         because perhaps it is more rare. */
+      is_tcp = !is_tcp;
+      continue;
+    }
+
+    /* TODO(ctiller): consider caching this port in some structure, to avoid
+                      handing it out again */
+
+    return port;
+  }
+
+  /* The port iterator reached the end without finding a suitable port. */
+  return 0;
+}
+
+int grpc_pick_unused_port_or_die(void) {
+  int port = grpc_pick_unused_port();
+  GPR_ASSERT(port > 0);
+  return port;
+}
+
+#endif /* GPR_WINSOCK_SOCKET && GRPC_TEST_PICK_PORT */
diff --git a/test/cpp/interop/client.cc b/test/cpp/interop/client.cc
index 7c5e1aa715aa1e7a040550b7bf60ac4a0d4e1126..189cdeb0eedc4fd804c430b8ffa3ce19bba62368 100644
--- a/test/cpp/interop/client.cc
+++ b/test/cpp/interop/client.cc
@@ -31,29 +31,19 @@
  *
  */
 
-#include <chrono>
-#include <fstream>
 #include <memory>
-#include <sstream>
-#include <string>
-#include <thread>
 
 #include <unistd.h>
 
 #include <grpc/grpc.h>
 #include <grpc/support/log.h>
 #include <gflags/gflags.h>
-#include <grpc++/channel_arguments.h>
 #include <grpc++/channel_interface.h>
 #include <grpc++/client_context.h>
-#include <grpc++/create_channel.h>
-#include <grpc++/credentials.h>
 #include <grpc++/status.h>
 #include <grpc++/stream.h>
-#include "test/cpp/util/create_test_channel.h"
-#include "test/cpp/interop/test.grpc.pb.h"
-#include "test/cpp/interop/empty.grpc.pb.h"
-#include "test/cpp/interop/messages.grpc.pb.h"
+#include "test/cpp/interop/client_helper.h"
+#include "test/cpp/interop/interop_client.h"
 
 DEFINE_bool(enable_ssl, false, "Whether to use ssl/tls.");
 DEFINE_bool(use_prod_roots, false, "True to use SSL roots for google");
@@ -81,21 +71,8 @@ DEFINE_string(service_account_key_file, "",
               "Path to service account json key file.");
 DEFINE_string(oauth_scope, "", "Scope for OAuth tokens.");
 
-using grpc::ChannelInterface;
-using grpc::ClientContext;
-using grpc::ComputeEngineCredentials;
-using grpc::CreateTestChannel;
-using grpc::Credentials;
-using grpc::JWTCredentials;
-using grpc::ServiceAccountCredentials;
-using grpc::testing::ResponseParameters;
-using grpc::testing::SimpleRequest;
-using grpc::testing::SimpleResponse;
-using grpc::testing::StreamingInputCallRequest;
-using grpc::testing::StreamingInputCallResponse;
-using grpc::testing::StreamingOutputCallRequest;
-using grpc::testing::StreamingOutputCallResponse;
-using grpc::testing::TestService;
+using grpc::testing::CreateChannelForTestCase;
+using grpc::testing::GetServiceAccountJsonKey;
 
 // In some distros, gflags is in the namespace google, and in some others,
 // in gflags. This hack is enabling us to find both.
@@ -104,362 +81,48 @@ namespace gflags {}
 using namespace google;
 using namespace gflags;
 
-namespace {
-// The same value is defined by the Java client.
-const std::vector<int> request_stream_sizes = {27182, 8, 1828, 45904};
-const std::vector<int> response_stream_sizes = {31415, 9, 2653, 58979};
-const int kNumResponseMessages = 2000;
-const int kResponseMessageSize = 1030;
-const int kReceiveDelayMilliSeconds = 20;
-const int kLargeRequestSize = 314159;
-const int kLargeResponseSize = 271812;
-}  // namespace
-
-grpc::string GetServiceAccountJsonKey() {
-  static grpc::string json_key;
-  if (json_key.empty()) {
-    std::ifstream json_key_file(FLAGS_service_account_key_file);
-    std::stringstream key_stream;
-    key_stream << json_key_file.rdbuf();
-    json_key = key_stream.str();
-  }
-  return json_key;
-}
-
-std::shared_ptr<ChannelInterface> CreateChannelForTestCase(
-    const grpc::string& test_case) {
-  GPR_ASSERT(FLAGS_server_port);
-  const int host_port_buf_size = 1024;
-  char host_port[host_port_buf_size];
-  snprintf(host_port, host_port_buf_size, "%s:%d", FLAGS_server_host.c_str(),
-           FLAGS_server_port);
-
-  if (test_case == "service_account_creds") {
-    std::unique_ptr<Credentials> creds;
-    GPR_ASSERT(FLAGS_enable_ssl);
-    grpc::string json_key = GetServiceAccountJsonKey();
-    creds = ServiceAccountCredentials(json_key, FLAGS_oauth_scope,
-                                      std::chrono::hours(1));
-    return CreateTestChannel(host_port, FLAGS_server_host_override,
-                             FLAGS_enable_ssl, FLAGS_use_prod_roots, creds);
-  } else if (test_case == "compute_engine_creds") {
-    std::unique_ptr<Credentials> creds;
-    GPR_ASSERT(FLAGS_enable_ssl);
-    creds = ComputeEngineCredentials();
-    return CreateTestChannel(host_port, FLAGS_server_host_override,
-                             FLAGS_enable_ssl, FLAGS_use_prod_roots, creds);
-  } else if (test_case == "jwt_token_creds") {
-    std::unique_ptr<Credentials> creds;
-    GPR_ASSERT(FLAGS_enable_ssl);
-    grpc::string json_key = GetServiceAccountJsonKey();
-    creds = JWTCredentials(json_key, std::chrono::hours(1));
-    return CreateTestChannel(host_port, FLAGS_server_host_override,
-                             FLAGS_enable_ssl, FLAGS_use_prod_roots, creds);
-  } else {
-    return CreateTestChannel(host_port, FLAGS_server_host_override,
-                             FLAGS_enable_ssl, FLAGS_use_prod_roots);
-  }
-}
-
-void AssertOkOrPrintErrorStatus(const grpc::Status& s) {
-  if (s.IsOk()) {
-    return;
-  }
-  gpr_log(GPR_INFO, "Error status code: %d, message: %s", s.code(),
-          s.details().c_str());
-  GPR_ASSERT(0);
-}
-
-void DoEmpty() {
-  gpr_log(GPR_INFO, "Sending an empty rpc...");
-  std::shared_ptr<ChannelInterface> channel =
-      CreateChannelForTestCase("empty_unary");
-  std::unique_ptr<TestService::Stub> stub(TestService::NewStub(channel));
-
-  grpc::testing::Empty request = grpc::testing::Empty::default_instance();
-  grpc::testing::Empty response = grpc::testing::Empty::default_instance();
-  ClientContext context;
-
-  grpc::Status s = stub->EmptyCall(&context, request, &response);
-  AssertOkOrPrintErrorStatus(s);
-
-  gpr_log(GPR_INFO, "Empty rpc done.");
-}
-
-// Shared code to set large payload, make rpc and check response payload.
-void PerformLargeUnary(std::shared_ptr<ChannelInterface> channel,
-                       SimpleRequest* request, SimpleResponse* response) {
-  std::unique_ptr<TestService::Stub> stub(TestService::NewStub(channel));
-
-  ClientContext context;
-  request->set_response_type(grpc::testing::PayloadType::COMPRESSABLE);
-  request->set_response_size(kLargeResponseSize);
-  grpc::string payload(kLargeRequestSize, '\0');
-  request->mutable_payload()->set_body(payload.c_str(), kLargeRequestSize);
-
-  grpc::Status s = stub->UnaryCall(&context, *request, response);
-
-  AssertOkOrPrintErrorStatus(s);
-  GPR_ASSERT(response->payload().type() ==
-             grpc::testing::PayloadType::COMPRESSABLE);
-  GPR_ASSERT(response->payload().body() ==
-             grpc::string(kLargeResponseSize, '\0'));
-}
-
-void DoComputeEngineCreds() {
-  gpr_log(GPR_INFO,
-          "Sending a large unary rpc with compute engine credentials ...");
-  std::shared_ptr<ChannelInterface> channel =
-      CreateChannelForTestCase("compute_engine_creds");
-  SimpleRequest request;
-  SimpleResponse response;
-  request.set_fill_username(true);
-  request.set_fill_oauth_scope(true);
-  PerformLargeUnary(channel, &request, &response);
-  gpr_log(GPR_INFO, "Got username %s", response.username().c_str());
-  gpr_log(GPR_INFO, "Got oauth_scope %s", response.oauth_scope().c_str());
-  GPR_ASSERT(!response.username().empty());
-  GPR_ASSERT(response.username().c_str() == FLAGS_default_service_account);
-  GPR_ASSERT(!response.oauth_scope().empty());
-  const char* oauth_scope_str = response.oauth_scope().c_str();
-  GPR_ASSERT(FLAGS_oauth_scope.find(oauth_scope_str) != grpc::string::npos);
-  gpr_log(GPR_INFO, "Large unary with compute engine creds done.");
-}
-
-void DoServiceAccountCreds() {
-  gpr_log(GPR_INFO,
-          "Sending a large unary rpc with service account credentials ...");
-  std::shared_ptr<ChannelInterface> channel =
-      CreateChannelForTestCase("service_account_creds");
-  SimpleRequest request;
-  SimpleResponse response;
-  request.set_fill_username(true);
-  request.set_fill_oauth_scope(true);
-  PerformLargeUnary(channel, &request, &response);
-  GPR_ASSERT(!response.username().empty());
-  GPR_ASSERT(!response.oauth_scope().empty());
-  grpc::string json_key = GetServiceAccountJsonKey();
-  GPR_ASSERT(json_key.find(response.username()) != grpc::string::npos);
-  const char* oauth_scope_str = response.oauth_scope().c_str();
-  GPR_ASSERT(FLAGS_oauth_scope.find(oauth_scope_str) != grpc::string::npos);
-  gpr_log(GPR_INFO, "Large unary with service account creds done.");
-}
-
-void DoJwtTokenCreds() {
-  gpr_log(GPR_INFO, "Sending a large unary rpc with JWT token credentials ...");
-  std::shared_ptr<ChannelInterface> channel =
-      CreateChannelForTestCase("jwt_token_creds");
-  SimpleRequest request;
-  SimpleResponse response;
-  request.set_fill_username(true);
-  PerformLargeUnary(channel, &request, &response);
-  GPR_ASSERT(!response.username().empty());
-  grpc::string json_key = GetServiceAccountJsonKey();
-  GPR_ASSERT(json_key.find(response.username()) != grpc::string::npos);
-  gpr_log(GPR_INFO, "Large unary with JWT token creds done.");
-}
-
-void DoLargeUnary() {
-  gpr_log(GPR_INFO, "Sending a large unary rpc...");
-  std::shared_ptr<ChannelInterface> channel =
-      CreateChannelForTestCase("large_unary");
-  SimpleRequest request;
-  SimpleResponse response;
-  PerformLargeUnary(channel, &request, &response);
-  gpr_log(GPR_INFO, "Large unary done.");
-}
-
-void DoRequestStreaming() {
-  gpr_log(GPR_INFO, "Sending request steaming rpc ...");
-  std::shared_ptr<ChannelInterface> channel =
-      CreateChannelForTestCase("client_streaming");
-  std::unique_ptr<TestService::Stub> stub(TestService::NewStub(channel));
-
-  grpc::ClientContext context;
-  StreamingInputCallRequest request;
-  StreamingInputCallResponse response;
-
-  std::unique_ptr<grpc::ClientWriter<StreamingInputCallRequest>> stream(
-      stub->StreamingInputCall(&context, &response));
-
-  int aggregated_payload_size = 0;
-  for (unsigned int i = 0; i < request_stream_sizes.size(); ++i) {
-    grpc::testing::Payload* payload = request.mutable_payload();
-    payload->set_body(grpc::string(request_stream_sizes[i], '\0'));
-    GPR_ASSERT(stream->Write(request));
-    aggregated_payload_size += request_stream_sizes[i];
-  }
-  stream->WritesDone();
-  grpc::Status s = stream->Finish();
-
-  GPR_ASSERT(response.aggregated_payload_size() == aggregated_payload_size);
-  AssertOkOrPrintErrorStatus(s);
-  gpr_log(GPR_INFO, "Request streaming done.");
-}
-
-void DoResponseStreaming() {
-  gpr_log(GPR_INFO, "Receiving response steaming rpc ...");
-  std::shared_ptr<ChannelInterface> channel =
-      CreateChannelForTestCase("server_streaming");
-  std::unique_ptr<TestService::Stub> stub(TestService::NewStub(channel));
-
-  grpc::ClientContext context;
-  StreamingOutputCallRequest request;
-  for (unsigned int i = 0; i < response_stream_sizes.size(); ++i) {
-    ResponseParameters* response_parameter = request.add_response_parameters();
-    response_parameter->set_size(response_stream_sizes[i]);
-  }
-  StreamingOutputCallResponse response;
-  std::unique_ptr<grpc::ClientReader<StreamingOutputCallResponse>> stream(
-      stub->StreamingOutputCall(&context, request));
-
-  unsigned int i = 0;
-  while (stream->Read(&response)) {
-    GPR_ASSERT(response.payload().body() ==
-               grpc::string(response_stream_sizes[i], '\0'));
-    ++i;
-  }
-  GPR_ASSERT(response_stream_sizes.size() == i);
-  grpc::Status s = stream->Finish();
-
-  AssertOkOrPrintErrorStatus(s);
-  gpr_log(GPR_INFO, "Response streaming done.");
-}
-
-void DoResponseStreamingWithSlowConsumer() {
-  gpr_log(GPR_INFO, "Receiving response steaming rpc with slow consumer ...");
-  std::shared_ptr<ChannelInterface> channel =
-      CreateChannelForTestCase("slow_consumer");
-  std::unique_ptr<TestService::Stub> stub(TestService::NewStub(channel));
-
-  grpc::ClientContext context;
-  StreamingOutputCallRequest request;
-
-  for (int i = 0; i < kNumResponseMessages; ++i) {
-    ResponseParameters* response_parameter = request.add_response_parameters();
-    response_parameter->set_size(kResponseMessageSize);
-  }
-  StreamingOutputCallResponse response;
-  std::unique_ptr<grpc::ClientReader<StreamingOutputCallResponse>> stream(
-      stub->StreamingOutputCall(&context, request));
-
-  int i = 0;
-  while (stream->Read(&response)) {
-    GPR_ASSERT(response.payload().body() ==
-               grpc::string(kResponseMessageSize, '\0'));
-    gpr_log(GPR_INFO, "received message %d", i);
-    usleep(kReceiveDelayMilliSeconds * 1000);
-    ++i;
-  }
-  GPR_ASSERT(kNumResponseMessages == i);
-  grpc::Status s = stream->Finish();
-
-  AssertOkOrPrintErrorStatus(s);
-  gpr_log(GPR_INFO, "Response streaming done.");
-}
-
-void DoHalfDuplex() {
-  gpr_log(GPR_INFO, "Sending half-duplex streaming rpc ...");
-  std::shared_ptr<ChannelInterface> channel =
-      CreateChannelForTestCase("half_duplex");
-  std::unique_ptr<TestService::Stub> stub(TestService::NewStub(channel));
-
-  grpc::ClientContext context;
-  std::unique_ptr<grpc::ClientReaderWriter<StreamingOutputCallRequest,
-                                           StreamingOutputCallResponse>>
-      stream(stub->HalfDuplexCall(&context));
-
-  StreamingOutputCallRequest request;
-  ResponseParameters* response_parameter = request.add_response_parameters();
-  for (unsigned int i = 0; i < response_stream_sizes.size(); ++i) {
-    response_parameter->set_size(response_stream_sizes[i]);
-    GPR_ASSERT(stream->Write(request));
-  }
-  stream->WritesDone();
-
-  unsigned int i = 0;
-  StreamingOutputCallResponse response;
-  while (stream->Read(&response)) {
-    GPR_ASSERT(response.payload().has_body());
-    GPR_ASSERT(response.payload().body() ==
-               grpc::string(response_stream_sizes[i], '\0'));
-    ++i;
-  }
-  GPR_ASSERT(response_stream_sizes.size() == i);
-  grpc::Status s = stream->Finish();
-  AssertOkOrPrintErrorStatus(s);
-  gpr_log(GPR_INFO, "Half-duplex streaming rpc done.");
-}
-
-void DoPingPong() {
-  gpr_log(GPR_INFO, "Sending Ping Pong streaming rpc ...");
-  std::shared_ptr<ChannelInterface> channel =
-      CreateChannelForTestCase("ping_pong");
-  std::unique_ptr<TestService::Stub> stub(TestService::NewStub(channel));
-
-  grpc::ClientContext context;
-  std::unique_ptr<grpc::ClientReaderWriter<StreamingOutputCallRequest,
-                                           StreamingOutputCallResponse>>
-      stream(stub->FullDuplexCall(&context));
-
-  StreamingOutputCallRequest request;
-  request.set_response_type(grpc::testing::PayloadType::COMPRESSABLE);
-  ResponseParameters* response_parameter = request.add_response_parameters();
-  grpc::testing::Payload* payload = request.mutable_payload();
-  StreamingOutputCallResponse response;
-  for (unsigned int i = 0; i < request_stream_sizes.size(); ++i) {
-    response_parameter->set_size(response_stream_sizes[i]);
-    payload->set_body(grpc::string(request_stream_sizes[i], '\0'));
-    GPR_ASSERT(stream->Write(request));
-    GPR_ASSERT(stream->Read(&response));
-    GPR_ASSERT(response.payload().has_body());
-    GPR_ASSERT(response.payload().body() ==
-               grpc::string(response_stream_sizes[i], '\0'));
-  }
-
-  stream->WritesDone();
-  GPR_ASSERT(!stream->Read(&response));
-  grpc::Status s = stream->Finish();
-  AssertOkOrPrintErrorStatus(s);
-  gpr_log(GPR_INFO, "Ping pong streaming done.");
-}
-
 int main(int argc, char** argv) {
   grpc_init();
 
   ParseCommandLineFlags(&argc, &argv, true);
 
+  grpc::testing::InteropClient client(
+      CreateChannelForTestCase(FLAGS_test_case));
   if (FLAGS_test_case == "empty_unary") {
-    DoEmpty();
+    client.DoEmpty();
   } else if (FLAGS_test_case == "large_unary") {
-    DoLargeUnary();
+    client.DoLargeUnary();
   } else if (FLAGS_test_case == "client_streaming") {
-    DoRequestStreaming();
+    client.DoRequestStreaming();
   } else if (FLAGS_test_case == "server_streaming") {
-    DoResponseStreaming();
+    client.DoResponseStreaming();
   } else if (FLAGS_test_case == "slow_consumer") {
-    DoResponseStreamingWithSlowConsumer();
+    client.DoResponseStreamingWithSlowConsumer();
   } else if (FLAGS_test_case == "half_duplex") {
-    DoHalfDuplex();
+    client.DoHalfDuplex();
   } else if (FLAGS_test_case == "ping_pong") {
-    DoPingPong();
+    client.DoPingPong();
   } else if (FLAGS_test_case == "service_account_creds") {
-    DoServiceAccountCreds();
+    grpc::string json_key = GetServiceAccountJsonKey();
+    client.DoServiceAccountCreds(json_key, FLAGS_oauth_scope);
   } else if (FLAGS_test_case == "compute_engine_creds") {
-    DoComputeEngineCreds();
+    client.DoComputeEngineCreds(FLAGS_default_service_account,
+                                FLAGS_oauth_scope);
   } else if (FLAGS_test_case == "jwt_token_creds") {
-    DoJwtTokenCreds();
+    grpc::string json_key = GetServiceAccountJsonKey();
+    client.DoJwtTokenCreds(json_key);
   } else if (FLAGS_test_case == "all") {
-    DoEmpty();
-    DoLargeUnary();
-    DoRequestStreaming();
-    DoResponseStreaming();
-    DoHalfDuplex();
-    DoPingPong();
+    client.DoEmpty();
+    client.DoLargeUnary();
+    client.DoRequestStreaming();
+    client.DoResponseStreaming();
+    client.DoHalfDuplex();
+    client.DoPingPong();
     // service_account_creds and jwt_token_creds can only run with ssl.
     if (FLAGS_enable_ssl) {
-      DoServiceAccountCreds();
-      DoJwtTokenCreds();
+      grpc::string json_key = GetServiceAccountJsonKey();
+      client.DoServiceAccountCreds(json_key, FLAGS_oauth_scope);
+      client.DoJwtTokenCreds(json_key);
     }
     // compute_engine_creds only runs in GCE.
   } else {
@@ -470,6 +133,7 @@ int main(int argc, char** argv) {
         "service_account_creds|compute_engine_creds|jwt_token_creds",
         FLAGS_test_case.c_str());
   }
+  client.Reset(nullptr);
 
   grpc_shutdown();
   return 0;
diff --git a/test/cpp/interop/client_helper.cc b/test/cpp/interop/client_helper.cc
new file mode 100644
index 0000000000000000000000000000000000000000..362e6af353bab5c967ed55695e377fe3bfd03c5d
--- /dev/null
+++ b/test/cpp/interop/client_helper.cc
@@ -0,0 +1,119 @@
+/*
+ *
+ * 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 "test/cpp/interop/client_helper.h"
+
+#include <fstream>
+#include <memory>
+#include <sstream>
+
+#include <unistd.h>
+
+#include <grpc/grpc.h>
+#include <grpc/support/log.h>
+#include <gflags/gflags.h>
+#include <grpc++/channel_arguments.h>
+#include <grpc++/channel_interface.h>
+#include <grpc++/create_channel.h>
+#include <grpc++/credentials.h>
+#include <grpc++/stream.h>
+#include "test/cpp/util/create_test_channel.h"
+
+DECLARE_bool(enable_ssl);
+DECLARE_bool(use_prod_roots);
+DECLARE_int32(server_port);
+DECLARE_string(server_host);
+DECLARE_string(server_host_override);
+DECLARE_string(test_case);
+DECLARE_string(default_service_account);
+DECLARE_string(service_account_key_file);
+DECLARE_string(oauth_scope);
+
+// In some distros, gflags is in the namespace google, and in some others,
+// in gflags. This hack is enabling us to find both.
+namespace google {}
+namespace gflags {}
+using namespace google;
+using namespace gflags;
+
+namespace grpc {
+namespace testing {
+
+grpc::string GetServiceAccountJsonKey() {
+  static grpc::string json_key;
+  if (json_key.empty()) {
+    std::ifstream json_key_file(FLAGS_service_account_key_file);
+    std::stringstream key_stream;
+    key_stream << json_key_file.rdbuf();
+    json_key = key_stream.str();
+  }
+  return json_key;
+}
+
+std::shared_ptr<ChannelInterface> CreateChannelForTestCase(
+    const grpc::string& test_case) {
+  GPR_ASSERT(FLAGS_server_port);
+  const int host_port_buf_size = 1024;
+  char host_port[host_port_buf_size];
+  snprintf(host_port, host_port_buf_size, "%s:%d", FLAGS_server_host.c_str(),
+           FLAGS_server_port);
+
+  if (test_case == "service_account_creds") {
+    std::unique_ptr<Credentials> creds;
+    GPR_ASSERT(FLAGS_enable_ssl);
+    grpc::string json_key = GetServiceAccountJsonKey();
+    creds = ServiceAccountCredentials(json_key, FLAGS_oauth_scope,
+                                      std::chrono::hours(1));
+    return CreateTestChannel(host_port, FLAGS_server_host_override,
+                             FLAGS_enable_ssl, FLAGS_use_prod_roots, creds);
+  } else if (test_case == "compute_engine_creds") {
+    std::unique_ptr<Credentials> creds;
+    GPR_ASSERT(FLAGS_enable_ssl);
+    creds = ComputeEngineCredentials();
+    return CreateTestChannel(host_port, FLAGS_server_host_override,
+                             FLAGS_enable_ssl, FLAGS_use_prod_roots, creds);
+  } else if (test_case == "jwt_token_creds") {
+    std::unique_ptr<Credentials> creds;
+    GPR_ASSERT(FLAGS_enable_ssl);
+    grpc::string json_key = GetServiceAccountJsonKey();
+    creds = JWTCredentials(json_key, std::chrono::hours(1));
+    return CreateTestChannel(host_port, FLAGS_server_host_override,
+                             FLAGS_enable_ssl, FLAGS_use_prod_roots, creds);
+  } else {
+    return CreateTestChannel(host_port, FLAGS_server_host_override,
+                             FLAGS_enable_ssl, FLAGS_use_prod_roots);
+  }
+}
+
+}  // namespace testing
+}  // namespace grpc
diff --git a/src/ruby/ext/grpc/rb_event.h b/test/cpp/interop/client_helper.h
similarity index 75%
rename from src/ruby/ext/grpc/rb_event.h
rename to test/cpp/interop/client_helper.h
index 3105934b110dd7c66b539e9caf9d845dbe0fbe53..897f974026feeb94be3e871d0c8b8f811d560a3b 100644
--- a/src/ruby/ext/grpc/rb_event.h
+++ b/test/cpp/interop/client_helper.h
@@ -31,23 +31,23 @@
  *
  */
 
-#ifndef GRPC_RB_EVENT_H_
-#define GRPC_RB_EVENT_H_
+#ifndef GRPC_TEST_CPP_INTEROP_CLIENT_HELPER_H
+#define GRPC_TEST_CPP_INTEROP_CLIENT_HELPER_H
 
-#include <ruby.h>
-#include <grpc/grpc.h>
+#include <memory>
 
-/* rb_cEvent is the Event class whose instances proxy grpc_event. */
-extern VALUE rb_cEvent;
+#include <grpc++/config.h>
+#include <grpc++/channel_interface.h>
 
-/* rb_cEventError is the ruby class that acts the exception thrown during rpc
-   event processing. */
-extern VALUE rb_eEventError;
+namespace grpc {
+namespace testing {
 
-/* Used to create new ruby event objects */
-VALUE grpc_rb_new_event(grpc_event *ev);
+grpc::string GetServiceAccountJsonKey();
 
-/* Initializes the Event and EventError classes. */
-void Init_grpc_event();
+std::shared_ptr<ChannelInterface> CreateChannelForTestCase(
+    const grpc::string& test_case);
 
-#endif /* GRPC_RB_EVENT_H_ */
+}  // namespace testing
+}  // namespace grpc
+
+#endif  // GRPC_TEST_CPP_INTEROP_CLIENT_HELPER_H
diff --git a/test/cpp/interop/interop_client.cc b/test/cpp/interop/interop_client.cc
new file mode 100644
index 0000000000000000000000000000000000000000..fd9c2e024abff923279cb35490c8c89a4c6b799e
--- /dev/null
+++ b/test/cpp/interop/interop_client.cc
@@ -0,0 +1,311 @@
+/*
+ *
+ * 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 "test/cpp/interop/interop_client.h"
+
+#include <memory>
+
+#include <unistd.h>
+
+#include <grpc/grpc.h>
+#include <grpc/support/log.h>
+#include <grpc++/channel_interface.h>
+#include <grpc++/client_context.h>
+#include <grpc++/status.h>
+#include <grpc++/stream.h>
+#include "test/cpp/interop/test.grpc.pb.h"
+#include "test/cpp/interop/empty.grpc.pb.h"
+#include "test/cpp/interop/messages.grpc.pb.h"
+
+namespace grpc {
+namespace testing {
+
+namespace {
+// The same value is defined by the Java client.
+const std::vector<int> request_stream_sizes = {27182, 8, 1828, 45904};
+const std::vector<int> response_stream_sizes = {31415, 9, 2653, 58979};
+const int kNumResponseMessages = 2000;
+const int kResponseMessageSize = 1030;
+const int kReceiveDelayMilliSeconds = 20;
+const int kLargeRequestSize = 314159;
+const int kLargeResponseSize = 271812;
+}  // namespace
+
+InteropClient::InteropClient(std::shared_ptr<ChannelInterface> channel)
+    : channel_(channel) {}
+
+void InteropClient::AssertOkOrPrintErrorStatus(const Status& s) {
+  if (s.IsOk()) {
+    return;
+  }
+  gpr_log(GPR_INFO, "Error status code: %d, message: %s", s.code(),
+          s.details().c_str());
+  GPR_ASSERT(0);
+}
+
+void InteropClient::DoEmpty() {
+  gpr_log(GPR_INFO, "Sending an empty rpc...");
+  std::unique_ptr<TestService::Stub> stub(TestService::NewStub(channel_));
+
+  Empty request = Empty::default_instance();
+  Empty response = Empty::default_instance();
+  ClientContext context;
+
+  Status s = stub->EmptyCall(&context, request, &response);
+  AssertOkOrPrintErrorStatus(s);
+
+  gpr_log(GPR_INFO, "Empty rpc done.");
+}
+
+// Shared code to set large payload, make rpc and check response payload.
+void InteropClient::PerformLargeUnary(SimpleRequest* request,
+                                      SimpleResponse* response) {
+  std::unique_ptr<TestService::Stub> stub(TestService::NewStub(channel_));
+
+  ClientContext context;
+  request->set_response_type(PayloadType::COMPRESSABLE);
+  request->set_response_size(kLargeResponseSize);
+  grpc::string payload(kLargeRequestSize, '\0');
+  request->mutable_payload()->set_body(payload.c_str(), kLargeRequestSize);
+
+  Status s = stub->UnaryCall(&context, *request, response);
+
+  AssertOkOrPrintErrorStatus(s);
+  GPR_ASSERT(response->payload().type() == PayloadType::COMPRESSABLE);
+  GPR_ASSERT(response->payload().body() ==
+             grpc::string(kLargeResponseSize, '\0'));
+}
+
+void InteropClient::DoComputeEngineCreds(
+    const grpc::string& default_service_account,
+    const grpc::string& oauth_scope) {
+  gpr_log(GPR_INFO,
+          "Sending a large unary rpc with compute engine credentials ...");
+  SimpleRequest request;
+  SimpleResponse response;
+  request.set_fill_username(true);
+  request.set_fill_oauth_scope(true);
+  PerformLargeUnary(&request, &response);
+  gpr_log(GPR_INFO, "Got username %s", response.username().c_str());
+  gpr_log(GPR_INFO, "Got oauth_scope %s", response.oauth_scope().c_str());
+  GPR_ASSERT(!response.username().empty());
+  GPR_ASSERT(response.username().c_str() == default_service_account);
+  GPR_ASSERT(!response.oauth_scope().empty());
+  const char* oauth_scope_str = response.oauth_scope().c_str();
+  GPR_ASSERT(oauth_scope.find(oauth_scope_str) != grpc::string::npos);
+  gpr_log(GPR_INFO, "Large unary with compute engine creds done.");
+}
+
+void InteropClient::DoServiceAccountCreds(const grpc::string& username,
+                                          const grpc::string& oauth_scope) {
+  gpr_log(GPR_INFO,
+          "Sending a large unary rpc with service account credentials ...");
+  SimpleRequest request;
+  SimpleResponse response;
+  request.set_fill_username(true);
+  request.set_fill_oauth_scope(true);
+  PerformLargeUnary(&request, &response);
+  GPR_ASSERT(!response.username().empty());
+  GPR_ASSERT(!response.oauth_scope().empty());
+  GPR_ASSERT(username.find(response.username()) != grpc::string::npos);
+  const char* oauth_scope_str = response.oauth_scope().c_str();
+  GPR_ASSERT(oauth_scope.find(oauth_scope_str) != grpc::string::npos);
+  gpr_log(GPR_INFO, "Large unary with service account creds done.");
+}
+
+void InteropClient::DoJwtTokenCreds(const grpc::string& username) {
+  gpr_log(GPR_INFO, "Sending a large unary rpc with JWT token credentials ...");
+  SimpleRequest request;
+  SimpleResponse response;
+  request.set_fill_username(true);
+  PerformLargeUnary(&request, &response);
+  GPR_ASSERT(!response.username().empty());
+  GPR_ASSERT(username.find(response.username()) != grpc::string::npos);
+  gpr_log(GPR_INFO, "Large unary with JWT token creds done.");
+}
+
+void InteropClient::DoLargeUnary() {
+  gpr_log(GPR_INFO, "Sending a large unary rpc...");
+  SimpleRequest request;
+  SimpleResponse response;
+  PerformLargeUnary(&request, &response);
+  gpr_log(GPR_INFO, "Large unary done.");
+}
+
+void InteropClient::DoRequestStreaming() {
+  gpr_log(GPR_INFO, "Sending request steaming rpc ...");
+  std::unique_ptr<TestService::Stub> stub(TestService::NewStub(channel_));
+
+  ClientContext context;
+  StreamingInputCallRequest request;
+  StreamingInputCallResponse response;
+
+  std::unique_ptr<ClientWriter<StreamingInputCallRequest>> stream(
+      stub->StreamingInputCall(&context, &response));
+
+  int aggregated_payload_size = 0;
+  for (unsigned int i = 0; i < request_stream_sizes.size(); ++i) {
+    Payload* payload = request.mutable_payload();
+    payload->set_body(grpc::string(request_stream_sizes[i], '\0'));
+    GPR_ASSERT(stream->Write(request));
+    aggregated_payload_size += request_stream_sizes[i];
+  }
+  stream->WritesDone();
+  Status s = stream->Finish();
+
+  GPR_ASSERT(response.aggregated_payload_size() == aggregated_payload_size);
+  AssertOkOrPrintErrorStatus(s);
+  gpr_log(GPR_INFO, "Request streaming done.");
+}
+
+void InteropClient::DoResponseStreaming() {
+  gpr_log(GPR_INFO, "Receiving response steaming rpc ...");
+  std::unique_ptr<TestService::Stub> stub(TestService::NewStub(channel_));
+
+  ClientContext context;
+  StreamingOutputCallRequest request;
+  for (unsigned int i = 0; i < response_stream_sizes.size(); ++i) {
+    ResponseParameters* response_parameter = request.add_response_parameters();
+    response_parameter->set_size(response_stream_sizes[i]);
+  }
+  StreamingOutputCallResponse response;
+  std::unique_ptr<ClientReader<StreamingOutputCallResponse>> stream(
+      stub->StreamingOutputCall(&context, request));
+
+  unsigned int i = 0;
+  while (stream->Read(&response)) {
+    GPR_ASSERT(response.payload().body() ==
+               grpc::string(response_stream_sizes[i], '\0'));
+    ++i;
+  }
+  GPR_ASSERT(response_stream_sizes.size() == i);
+  Status s = stream->Finish();
+
+  AssertOkOrPrintErrorStatus(s);
+  gpr_log(GPR_INFO, "Response streaming done.");
+}
+
+void InteropClient::DoResponseStreamingWithSlowConsumer() {
+  gpr_log(GPR_INFO, "Receiving response steaming rpc with slow consumer ...");
+  std::unique_ptr<TestService::Stub> stub(TestService::NewStub(channel_));
+
+  ClientContext context;
+  StreamingOutputCallRequest request;
+
+  for (int i = 0; i < kNumResponseMessages; ++i) {
+    ResponseParameters* response_parameter = request.add_response_parameters();
+    response_parameter->set_size(kResponseMessageSize);
+  }
+  StreamingOutputCallResponse response;
+  std::unique_ptr<ClientReader<StreamingOutputCallResponse>> stream(
+      stub->StreamingOutputCall(&context, request));
+
+  int i = 0;
+  while (stream->Read(&response)) {
+    GPR_ASSERT(response.payload().body() ==
+               grpc::string(kResponseMessageSize, '\0'));
+    gpr_log(GPR_INFO, "received message %d", i);
+    usleep(kReceiveDelayMilliSeconds * 1000);
+    ++i;
+  }
+  GPR_ASSERT(kNumResponseMessages == i);
+  Status s = stream->Finish();
+
+  AssertOkOrPrintErrorStatus(s);
+  gpr_log(GPR_INFO, "Response streaming done.");
+}
+
+void InteropClient::DoHalfDuplex() {
+  gpr_log(GPR_INFO, "Sending half-duplex streaming rpc ...");
+  std::unique_ptr<TestService::Stub> stub(TestService::NewStub(channel_));
+
+  ClientContext context;
+  std::unique_ptr<ClientReaderWriter<StreamingOutputCallRequest,
+                                     StreamingOutputCallResponse>>
+      stream(stub->HalfDuplexCall(&context));
+
+  StreamingOutputCallRequest request;
+  ResponseParameters* response_parameter = request.add_response_parameters();
+  for (unsigned int i = 0; i < response_stream_sizes.size(); ++i) {
+    response_parameter->set_size(response_stream_sizes[i]);
+    GPR_ASSERT(stream->Write(request));
+  }
+  stream->WritesDone();
+
+  unsigned int i = 0;
+  StreamingOutputCallResponse response;
+  while (stream->Read(&response)) {
+    GPR_ASSERT(response.payload().has_body());
+    GPR_ASSERT(response.payload().body() ==
+               grpc::string(response_stream_sizes[i], '\0'));
+    ++i;
+  }
+  GPR_ASSERT(response_stream_sizes.size() == i);
+  Status s = stream->Finish();
+  AssertOkOrPrintErrorStatus(s);
+  gpr_log(GPR_INFO, "Half-duplex streaming rpc done.");
+}
+
+void InteropClient::DoPingPong() {
+  gpr_log(GPR_INFO, "Sending Ping Pong streaming rpc ...");
+  std::unique_ptr<TestService::Stub> stub(TestService::NewStub(channel_));
+
+  ClientContext context;
+  std::unique_ptr<ClientReaderWriter<StreamingOutputCallRequest,
+                                     StreamingOutputCallResponse>>
+      stream(stub->FullDuplexCall(&context));
+
+  StreamingOutputCallRequest request;
+  request.set_response_type(PayloadType::COMPRESSABLE);
+  ResponseParameters* response_parameter = request.add_response_parameters();
+  Payload* payload = request.mutable_payload();
+  StreamingOutputCallResponse response;
+  for (unsigned int i = 0; i < request_stream_sizes.size(); ++i) {
+    response_parameter->set_size(response_stream_sizes[i]);
+    payload->set_body(grpc::string(request_stream_sizes[i], '\0'));
+    GPR_ASSERT(stream->Write(request));
+    GPR_ASSERT(stream->Read(&response));
+    GPR_ASSERT(response.payload().has_body());
+    GPR_ASSERT(response.payload().body() ==
+               grpc::string(response_stream_sizes[i], '\0'));
+  }
+
+  stream->WritesDone();
+  GPR_ASSERT(!stream->Read(&response));
+  Status s = stream->Finish();
+  AssertOkOrPrintErrorStatus(s);
+  gpr_log(GPR_INFO, "Ping pong streaming done.");
+}
+
+}  // namespace testing
+}  // namespace grpc
diff --git a/test/cpp/interop/interop_client.h b/test/cpp/interop/interop_client.h
new file mode 100644
index 0000000000000000000000000000000000000000..b0ab320f8dc78d4c5e741c6e62c3b64c90903576
--- /dev/null
+++ b/test/cpp/interop/interop_client.h
@@ -0,0 +1,79 @@
+/*
+ *
+ * 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_TEST_CPP_INTEROP_INTEROP_CLIENT_H
+#define GRPC_TEST_CPP_INTEROP_INTEROP_CLIENT_H
+#include <memory>
+
+#include <grpc/grpc.h>
+#include <grpc++/channel_interface.h>
+#include <grpc++/status.h>
+#include "test/cpp/interop/messages.grpc.pb.h"
+
+namespace grpc {
+namespace testing {
+
+class InteropClient {
+ public:
+  explicit InteropClient(std::shared_ptr<ChannelInterface> channel);
+  ~InteropClient() {}
+
+  void Reset(std::shared_ptr<ChannelInterface> channel) { channel_ = channel; }
+
+  void DoEmpty();
+  void DoLargeUnary();
+  void DoPingPong();
+  void DoHalfDuplex();
+  void DoRequestStreaming();
+  void DoResponseStreaming();
+  void DoResponseStreamingWithSlowConsumer();
+  // Auth tests.
+  // username is a string containing the user email
+  void DoJwtTokenCreds(const grpc::string& username);
+  void DoComputeEngineCreds(const grpc::string& default_service_account,
+                            const grpc::string& oauth_scope);
+  // username is a string containing the user email
+  void DoServiceAccountCreds(const grpc::string& username,
+                             const grpc::string& oauth_scope);
+
+ private:
+  void PerformLargeUnary(SimpleRequest* request, SimpleResponse* response);
+  void AssertOkOrPrintErrorStatus(const Status& s);
+
+  std::shared_ptr<ChannelInterface> channel_;
+};
+
+}  // namespace testing
+}  // namespace grpc
+
+#endif  // GRPC_TEST_CPP_INTEROP_INTEROP_CLIENT_H
diff --git a/test/cpp/interop/server.cc b/test/cpp/interop/server.cc
index 87bf48938bc87c0cc2ad5a54ed19978a2866de62..d87493b8132b4d2c6f4d6fd0510a18a3fe8637e7 100644
--- a/test/cpp/interop/server.cc
+++ b/test/cpp/interop/server.cc
@@ -41,7 +41,6 @@
 #include <gflags/gflags.h>
 #include <grpc/grpc.h>
 #include <grpc/support/log.h>
-#include "test/core/end2end/data/ssl_test_data.h"
 #include <grpc++/config.h>
 #include <grpc++/server.h>
 #include <grpc++/server_builder.h>
@@ -52,6 +51,7 @@
 #include "test/cpp/interop/test.grpc.pb.h"
 #include "test/cpp/interop/empty.grpc.pb.h"
 #include "test/cpp/interop/messages.grpc.pb.h"
+#include "test/cpp/interop/server_helper.h"
 
 DEFINE_bool(enable_ssl, false, "Whether to use ssl/tls.");
 DEFINE_int32(port, 0, "Server port.");
@@ -211,15 +211,8 @@ void RunServer() {
 
   ServerBuilder builder;
   builder.RegisterService(&service);
-  std::shared_ptr<ServerCredentials> creds = grpc::InsecureServerCredentials();
-  if (FLAGS_enable_ssl) {
-    SslServerCredentialsOptions::PemKeyCertPair pkcp = {test_server1_key,
-							test_server1_cert};
-    SslServerCredentialsOptions ssl_opts;
-    ssl_opts.pem_root_certs = "";
-    ssl_opts.pem_key_cert_pairs.push_back(pkcp);
-    creds = grpc::SslServerCredentials(ssl_opts);
-  }
+  std::shared_ptr<ServerCredentials> creds =
+      grpc::testing::CreateInteropServerCredentials();
   builder.AddListeningPort(server_address.str(), creds);
   std::unique_ptr<Server> server(builder.BuildAndStart());
   gpr_log(GPR_INFO, "Server listening on %s", server_address.str().c_str());
diff --git a/test/cpp/interop/server_helper.cc b/test/cpp/interop/server_helper.cc
new file mode 100644
index 0000000000000000000000000000000000000000..56597c83c4ca3c8e332c491be6a89949f8b108fa
--- /dev/null
+++ b/test/cpp/interop/server_helper.cc
@@ -0,0 +1,69 @@
+/*
+ *
+ * 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 "test/cpp/interop/server_helper.h"
+
+#include <memory>
+
+#include <gflags/gflags.h>
+#include "test/core/end2end/data/ssl_test_data.h"
+#include <grpc++/config.h>
+#include <grpc++/server_credentials.h>
+
+DECLARE_bool(enable_ssl);
+
+// In some distros, gflags is in the namespace google, and in some others,
+// in gflags. This hack is enabling us to find both.
+namespace google {}
+namespace gflags {}
+using namespace google;
+using namespace gflags;
+
+namespace grpc {
+namespace testing {
+
+std::shared_ptr<ServerCredentials> CreateInteropServerCredentials() {
+  if (FLAGS_enable_ssl) {
+    SslServerCredentialsOptions::PemKeyCertPair pkcp = {test_server1_key,
+                                                        test_server1_cert};
+    SslServerCredentialsOptions ssl_opts;
+    ssl_opts.pem_root_certs = "";
+    ssl_opts.pem_key_cert_pairs.push_back(pkcp);
+    return SslServerCredentials(ssl_opts);
+  } else {
+    return InsecureServerCredentials();
+  }
+}
+
+}  // namespace testing
+}  // namespace grpc
diff --git a/src/ruby/ext/grpc/rb_metadata.h b/test/cpp/interop/server_helper.h
similarity index 71%
rename from src/ruby/ext/grpc/rb_metadata.h
rename to test/cpp/interop/server_helper.h
index 251072f658d885a37096c0757602d84d86e157ac..f98e67bb67341d63ab4287420b5dbb0fdf1598fb 100644
--- a/src/ruby/ext/grpc/rb_metadata.h
+++ b/test/cpp/interop/server_helper.h
@@ -31,23 +31,19 @@
  *
  */
 
-#ifndef GRPC_RB_METADATA_H_
-#define GRPC_RB_METADATA_H_
+#ifndef GRPC_TEST_CPP_INTEROP_SERVER_HELPER_H
+#define GRPC_TEST_CPP_INTEROP_SERVER_HELPER_H
 
-#include <grpc/grpc.h>
-#include <ruby.h>
+#include <memory>
 
-/* rb_cMetadata is the Metadata class whose instances proxy grpc_metadata. */
-extern VALUE rb_cMetadata;
+#include <grpc++/server_credentials.h>
 
-/* grpc_rb_metadata_create_with_mark creates a grpc_rb_metadata with a ruby mark
- * object that will be kept alive while the metadata is alive. */
-extern VALUE grpc_rb_metadata_create_with_mark(VALUE mark, grpc_metadata* md);
+namespace grpc {
+namespace testing {
 
-/* Gets the wrapped metadata from the ruby wrapper */
-grpc_metadata* grpc_rb_get_wrapped_metadata(VALUE v);
+std::shared_ptr<ServerCredentials> CreateInteropServerCredentials();
 
-/* Initializes the Metadata class. */
-void Init_grpc_metadata();
+}  // namespace testing
+}  // namespace grpc
 
-#endif /* GRPC_RB_METADATA_H_ */
+#endif  // GRPC_TEST_CPP_INTEROP_SERVER_HELPER_H
diff --git a/test/cpp/qps/client.h b/test/cpp/qps/client.h
index 08b338c7473a52d5a5e5c96f669a1f0ac2b70f83..2dc5b3860f3852cff54750388546f7d8377e4bdb 100644
--- a/test/cpp/qps/client.h
+++ b/test/cpp/qps/client.h
@@ -104,7 +104,7 @@ class Client {
 
   void EndThreads() { threads_.clear(); }
 
-  virtual void ThreadFunc(Histogram* histogram, size_t thread_idx) = 0;
+  virtual bool ThreadFunc(Histogram* histogram, size_t thread_idx) = 0;
 
  private:
   class Thread {
@@ -113,20 +113,24 @@ class Client {
         : done_(false),
           new_(nullptr),
           impl_([this, idx, client]() {
-            for (;;) {
-              // run the loop body
-	      client->ThreadFunc(&histogram_, idx);
-              // lock, see if we're done
-              std::lock_guard<std::mutex> g(mu_);
-              if (done_) {return;}
-	      // check if we're marking, swap out the histogram if so
-	      if (new_) {
-                new_->Swap(&histogram_);
-                new_ = nullptr;
-                cv_.notify_one();
+              for (;;) {
+                // run the loop body
+        	      bool thread_still_ok = client->ThreadFunc(&histogram_, idx);
+                // lock, see if we're done
+                std::lock_guard<std::mutex> g(mu_);
+                if (!thread_still_ok) {
+                  gpr_log(GPR_ERROR, "Finishing client thread due to RPC error");
+                  done_ = true;
+                }
+                if (done_) {return;}
+        	      // check if we're marking, swap out the histogram if so
+        	      if (new_) {
+                        new_->Swap(&histogram_);
+                        new_ = nullptr;
+                        cv_.notify_one();
+                }
               }
-            }
-          }) {}
+            }) {}
 
     ~Thread() {
       {
diff --git a/test/cpp/qps/client_async.cc b/test/cpp/qps/client_async.cc
index c01d84017816dd4442fa10bc8e9bebac47f64996..0a6d9beeca6ca156020814b7e27f5066c0232603 100644
--- a/test/cpp/qps/client_async.cc
+++ b/test/cpp/qps/client_async.cc
@@ -137,13 +137,7 @@ class AsyncUnaryClient GRPC_FINAL : public Client {
       cli_cqs_.emplace_back(new CompletionQueue);
     }
 
-    auto payload_size = config.payload_size();
-    auto check_done = [payload_size](grpc::Status s, SimpleResponse* response) {
-      GPR_ASSERT(s.IsOk() && (response->payload().type() ==
-                              grpc::testing::PayloadType::COMPRESSABLE) &&
-                 (response->payload().body().length() ==
-                  static_cast<size_t>(payload_size)));
-    };
+    auto check_done = [](grpc::Status s, SimpleResponse* response) {};
 
     int t = 0;
     for (int i = 0; i < config.outstanding_rpcs_per_channel(); i++) {
@@ -179,10 +173,14 @@ class AsyncUnaryClient GRPC_FINAL : public Client {
     }
   }
 
-  void ThreadFunc(Histogram* histogram, size_t thread_idx) GRPC_OVERRIDE {
+  bool ThreadFunc(Histogram* histogram, size_t thread_idx) GRPC_OVERRIDE {
     void* got_tag;
     bool ok;
-    cli_cqs_[thread_idx]->Next(&got_tag, &ok);
+    switch (cli_cqs_[thread_idx]->AsyncNext(&got_tag, &ok, std::chrono::system_clock::now() + std::chrono::seconds(1))) {
+      case CompletionQueue::SHUTDOWN: return false;
+      case CompletionQueue::TIMEOUT: return true;
+      case CompletionQueue::GOT_EVENT: break;
+    }
 
     ClientRpcContext* ctx = ClientRpcContext::detag(got_tag);
     if (ctx->RunNextState(ok, histogram) == false) {
@@ -191,6 +189,8 @@ class AsyncUnaryClient GRPC_FINAL : public Client {
       ctx->StartNewClone();
       delete ctx;
     }
+
+    return true;
   }
 
   std::vector<std::unique_ptr<CompletionQueue>> cli_cqs_;
@@ -270,13 +270,7 @@ class AsyncStreamingClient GRPC_FINAL : public Client {
       cli_cqs_.emplace_back(new CompletionQueue);
     }
 
-    auto payload_size = config.payload_size();
-    auto check_done = [payload_size](grpc::Status s, SimpleResponse *response) {
-      GPR_ASSERT(s.IsOk() && (response->payload().type() ==
-                              grpc::testing::PayloadType::COMPRESSABLE) &&
-                 (response->payload().body().length() ==
-                  static_cast<size_t>(payload_size)));
-    };
+    auto check_done = [](grpc::Status s, SimpleResponse* response) {};
 
     int t = 0;
     for (int i = 0; i < config.outstanding_rpcs_per_channel(); i++) {
@@ -313,10 +307,14 @@ class AsyncStreamingClient GRPC_FINAL : public Client {
     }
   }
 
-  void ThreadFunc(Histogram *histogram, size_t thread_idx) GRPC_OVERRIDE {
+  bool ThreadFunc(Histogram *histogram, size_t thread_idx) GRPC_OVERRIDE {
     void *got_tag;
     bool ok;
-    cli_cqs_[thread_idx]->Next(&got_tag, &ok);
+    switch (cli_cqs_[thread_idx]->AsyncNext(&got_tag, &ok, std::chrono::system_clock::now() + std::chrono::seconds(1))) {
+      case CompletionQueue::SHUTDOWN: return false;
+      case CompletionQueue::TIMEOUT: return true;
+      case CompletionQueue::GOT_EVENT: break;
+    }
 
     ClientRpcContext *ctx = ClientRpcContext::detag(got_tag);
     if (ctx->RunNextState(ok, histogram) == false) {
@@ -325,6 +323,8 @@ class AsyncStreamingClient GRPC_FINAL : public Client {
       ctx->StartNewClone();
       delete ctx;
     }
+
+    return true;
   }
 
   std::vector<std::unique_ptr<CompletionQueue>> cli_cqs_;
diff --git a/test/cpp/qps/client_sync.cc b/test/cpp/qps/client_sync.cc
index 947618121b3ae687a7fa39d47360147a797fda7e..aea5a0fb27acd1cf75e0e10aff1ca47362df1199 100644
--- a/test/cpp/qps/client_sync.cc
+++ b/test/cpp/qps/client_sync.cc
@@ -83,13 +83,14 @@ class SynchronousUnaryClient GRPC_FINAL : public SynchronousClient {
     SynchronousClient(config) {StartThreads(num_threads_);}
   ~SynchronousUnaryClient() {}
   
-  void ThreadFunc(Histogram* histogram, size_t thread_idx) GRPC_OVERRIDE {
+  bool ThreadFunc(Histogram* histogram, size_t thread_idx) GRPC_OVERRIDE {
     auto* stub = channels_[thread_idx % channels_.size()].get_stub();
     double start = Timer::Now();
     grpc::ClientContext context;
     grpc::Status s =
         stub->UnaryCall(&context, request_, &responses_[thread_idx]);
     histogram->Add((Timer::Now() - start) * 1e9);
+    return s.IsOk();
   }
 };
 
@@ -111,11 +112,13 @@ class SynchronousStreamingClient GRPC_FINAL : public SynchronousClient {
     }
   }
 
-  void ThreadFunc(Histogram* histogram, size_t thread_idx) GRPC_OVERRIDE {
+  bool ThreadFunc(Histogram* histogram, size_t thread_idx) GRPC_OVERRIDE {
     double start = Timer::Now();
-    EXPECT_TRUE(stream_->Write(request_));
-    EXPECT_TRUE(stream_->Read(&responses_[thread_idx]));
-    histogram->Add((Timer::Now() - start) * 1e9);
+    if (stream_->Write(request_) && stream_->Read(&responses_[thread_idx])) {
+      histogram->Add((Timer::Now() - start) * 1e9);
+      return true;
+    }
+    return false;
   }
   private:
     grpc::ClientContext context_;
diff --git a/test/cpp/qps/histogram.h b/test/cpp/qps/histogram.h
index eb17821cdc9e699942f25e3cb962a1453a87d42f..0547b7283a7203edf569993ba473c498e5b36245 100644
--- a/test/cpp/qps/histogram.h
+++ b/test/cpp/qps/histogram.h
@@ -50,10 +50,10 @@ class Histogram {
 
   void Merge(Histogram* h) { gpr_histogram_merge(impl_, h->impl_); }
   void Add(double value) { gpr_histogram_add(impl_, value); }
-  double Percentile(double pctile) {
+  double Percentile(double pctile) const {
     return gpr_histogram_percentile(impl_, pctile);
   }
-  double Count() { return gpr_histogram_count(impl_); }
+  double Count() const { return gpr_histogram_count(impl_); }
   void Swap(Histogram* other) { std::swap(impl_, other->impl_); }
   void FillProto(HistogramData* p) {
     size_t n;
diff --git a/test/cpp/qps/qps_driver.cc b/test/cpp/qps/qps_driver.cc
index f42d538b165615a5cc8107b49d99ebac4d17b57d..220f826118f21f976ce5f7e6ca588b54af55a510 100644
--- a/test/cpp/qps/qps_driver.cc
+++ b/test/cpp/qps/qps_driver.cc
@@ -35,7 +35,7 @@
 #include <grpc/support/log.h>
 
 #include "test/cpp/qps/driver.h"
-#include "test/cpp/qps/stats.h"
+#include "test/cpp/qps/report.h"
 
 DEFINE_int32(num_clients, 1, "Number of client binaries");
 DEFINE_int32(num_servers, 1, "Number of server binaries");
@@ -65,7 +65,6 @@ using grpc::testing::ClientType;
 using grpc::testing::ServerType;
 using grpc::testing::RpcType;
 using grpc::testing::ResourceUsage;
-using grpc::testing::sum;
 
 // In some distros, gflags is in the namespace google, and in some others,
 // in gflags. This hack is enabling us to find both.
@@ -105,37 +104,9 @@ int main(int argc, char** argv) {
                             server_config, FLAGS_num_servers,
                             FLAGS_warmup_seconds, FLAGS_benchmark_seconds);
 
-  gpr_log(GPR_INFO, "QPS: %.1f",
-          result.latencies.Count() /
-              average(result.client_resources,
-                      [](ResourceUsage u) { return u.wall_time; }));
-
-  gpr_log(GPR_INFO, "Latencies (50/95/99/99.9%%-ile): %.1f/%.1f/%.1f/%.1f us",
-          result.latencies.Percentile(50) / 1000,
-          result.latencies.Percentile(95) / 1000,
-          result.latencies.Percentile(99) / 1000,
-          result.latencies.Percentile(99.9) / 1000);
-
-  gpr_log(GPR_INFO, "Server system time: %.2f%%",
-          100.0 * sum(result.server_resources,
-                      [](ResourceUsage u) { return u.system_time; }) /
-              sum(result.server_resources,
-                  [](ResourceUsage u) { return u.wall_time; }));
-  gpr_log(GPR_INFO, "Server user time:   %.2f%%",
-          100.0 * sum(result.server_resources,
-                      [](ResourceUsage u) { return u.user_time; }) /
-              sum(result.server_resources,
-                  [](ResourceUsage u) { return u.wall_time; }));
-  gpr_log(GPR_INFO, "Client system time: %.2f%%",
-          100.0 * sum(result.client_resources,
-                      [](ResourceUsage u) { return u.system_time; }) /
-              sum(result.client_resources,
-                  [](ResourceUsage u) { return u.wall_time; }));
-  gpr_log(GPR_INFO, "Client user time:   %.2f%%",
-          100.0 * sum(result.client_resources,
-                      [](ResourceUsage u) { return u.user_time; }) /
-              sum(result.client_resources,
-                  [](ResourceUsage u) { return u.wall_time; }));
+  ReportQPSPerCore(result, server_config);
+  ReportLatency(result);
+  ReportTimes(result);
 
   grpc_shutdown();
   return 0;
diff --git a/test/cpp/qps/report.cc b/test/cpp/qps/report.cc
new file mode 100644
index 0000000000000000000000000000000000000000..29d88da344a23f0b6492fdba9f8e0183ef755a74
--- /dev/null
+++ b/test/cpp/qps/report.cc
@@ -0,0 +1,94 @@
+/*
+ *
+ * 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 "test/cpp/qps/report.h"
+
+#include <grpc/support/log.h>
+#include "test/cpp/qps/stats.h"
+
+namespace grpc {
+namespace testing {
+
+// QPS: XXX
+void ReportQPS(const ScenarioResult& result) {
+  gpr_log(GPR_INFO, "QPS: %.1f",
+          result.latencies.Count() /
+              average(result.client_resources,
+                      [](ResourceUsage u) { return u.wall_time; }));
+}
+
+// QPS: XXX (YYY/server core)
+void ReportQPSPerCore(const ScenarioResult& result, const ServerConfig& server_config) {
+  auto qps = 
+      result.latencies.Count() /
+      average(result.client_resources,
+          [](ResourceUsage u) { return u.wall_time; });
+
+  gpr_log(GPR_INFO, "QPS: %.1f (%.1f/server core)", qps, qps/server_config.threads());
+}
+
+// Latency (50/90/95/99/99.9%-ile): AA/BB/CC/DD/EE us
+void ReportLatency(const ScenarioResult& result) {
+  gpr_log(GPR_INFO, "Latencies (50/90/95/99/99.9%%-ile): %.1f/%.1f/%.1f/%.1f/%.1f us",
+          result.latencies.Percentile(50) / 1000,
+          result.latencies.Percentile(90) / 1000,
+          result.latencies.Percentile(95) / 1000,
+          result.latencies.Percentile(99) / 1000,
+          result.latencies.Percentile(99.9) / 1000);
+}
+
+void ReportTimes(const ScenarioResult& result) {
+  gpr_log(GPR_INFO, "Server system time: %.2f%%",
+          100.0 * sum(result.server_resources,
+                      [](ResourceUsage u) { return u.system_time; }) /
+              sum(result.server_resources,
+                  [](ResourceUsage u) { return u.wall_time; }));
+  gpr_log(GPR_INFO, "Server user time:   %.2f%%",
+          100.0 * sum(result.server_resources,
+                      [](ResourceUsage u) { return u.user_time; }) /
+              sum(result.server_resources,
+                  [](ResourceUsage u) { return u.wall_time; }));
+  gpr_log(GPR_INFO, "Client system time: %.2f%%",
+          100.0 * sum(result.client_resources,
+                      [](ResourceUsage u) { return u.system_time; }) /
+              sum(result.client_resources,
+                  [](ResourceUsage u) { return u.wall_time; }));
+  gpr_log(GPR_INFO, "Client user time:   %.2f%%",
+          100.0 * sum(result.client_resources,
+                      [](ResourceUsage u) { return u.user_time; }) /
+              sum(result.client_resources,
+                  [](ResourceUsage u) { return u.wall_time; }));
+}
+
+}  // namespace testing
+}  // namespace grpc
diff --git a/test/cpp/qps/report.h b/test/cpp/qps/report.h
new file mode 100644
index 0000000000000000000000000000000000000000..343e426ca4ac74ecd877d7d5010933ac9550bde9
--- /dev/null
+++ b/test/cpp/qps/report.h
@@ -0,0 +1,57 @@
+/*
+ *
+ * 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 TEST_QPS_REPORT_H
+#define TEST_QPS_REPORT_H
+
+#include "test/cpp/qps/driver.h"
+
+namespace grpc {
+namespace testing {
+
+// QPS: XXX
+void ReportQPS(const ScenarioResult& result);
+// QPS: XXX (YYY/server core)
+void ReportQPSPerCore(const ScenarioResult& result, const ServerConfig& config);
+// Latency (50/90/95/99/99.9%-ile): AA/BB/CC/DD/EE us
+void ReportLatency(const ScenarioResult& result);
+// Server system time: XX%
+// Server user time: XX%
+// Client system time: XX%
+// Client user time: XX%
+void ReportTimes(const ScenarioResult& result);
+
+}  // namespace testing
+}  // namespace grpc
+
+#endif
diff --git a/test/cpp/qps/server_async.cc b/test/cpp/qps/server_async.cc
index 2e366a8d722e49925d60117275b8ac7e3bfb88aa..b19c443c82333647f0602e70231821c5ffd1c819 100644
--- a/test/cpp/qps/server_async.cc
+++ b/test/cpp/qps/server_async.cc
@@ -97,15 +97,15 @@ class AsyncQpsServerTest : public Server {
         bool ok;
         void* got_tag;
         while (srv_cq_.Next(&got_tag, &ok)) {
-	  ServerRpcContext* ctx = detag(got_tag);
-	  // The tag is a pointer to an RPC context to invoke
-	  if (ctx->RunNextState(ok) == false) {
-	    // this RPC context is done, so refresh it
+          ServerRpcContext* ctx = detag(got_tag);
+          // The tag is a pointer to an RPC context to invoke
+          if (ctx->RunNextState(ok) == false) {
+            // this RPC context is done, so refresh it
             std::lock_guard<std::mutex> g(shutdown_mutex_);
             if (!shutdown_) {
               ctx->Reset();
             }
-	  }
+          }
         }
         return;
       }));
@@ -175,8 +175,9 @@ class AsyncQpsServerTest : public Server {
    private:
     bool finisher(bool) { return false; }
     bool invoker(bool ok) {
-      if (!ok)
-	return false;
+      if (!ok) {
+        return false;
+      }
 
       ResponseType response;
 
@@ -230,8 +231,9 @@ class AsyncQpsServerTest : public Server {
 
    private:
     bool request_done(bool ok) {
-      if (!ok)
-	return false;
+      if (!ok) {
+        return false;
+      }
       stream_.Read(&req_, AsyncQpsServerTest::tag(this));
       next_state_ = &ServerRpcContextStreamingImpl::read_done;
       return true;
diff --git a/test/cpp/qps/smoke_test.cc b/test/cpp/qps/smoke_test.cc
new file mode 100644
index 0000000000000000000000000000000000000000..c9d321f133c43fdc8247c90e8ed65b701d68945e
--- /dev/null
+++ b/test/cpp/qps/smoke_test.cc
@@ -0,0 +1,149 @@
+/*
+ *
+ * Copyright 2015, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <grpc/support/log.h>
+
+#include "test/cpp/qps/driver.h"
+#include "test/cpp/qps/report.h"
+
+namespace grpc {
+namespace testing {
+
+static const int WARMUP = 5;
+static const int BENCHMARK = 10;
+
+static void RunSynchronousUnaryPingPong() {
+  gpr_log(GPR_INFO, "Running Synchronous Unary Ping Pong");
+
+  ClientConfig client_config;
+  client_config.set_client_type(SYNCHRONOUS_CLIENT);
+  client_config.set_enable_ssl(false);
+  client_config.set_outstanding_rpcs_per_channel(1);
+  client_config.set_client_channels(1);
+  client_config.set_payload_size(1);
+  client_config.set_rpc_type(UNARY);
+
+  ServerConfig server_config;
+  server_config.set_server_type(SYNCHRONOUS_SERVER);
+  server_config.set_enable_ssl(false);
+  server_config.set_threads(1);
+
+  auto result = RunScenario(client_config, 1, server_config, 1, WARMUP, BENCHMARK);
+
+  ReportQPS(result);
+  ReportLatency(result);
+}
+
+static void RunSynchronousStreamingPingPong() {
+  gpr_log(GPR_INFO, "Running Synchronous Streaming Ping Pong");
+
+  ClientConfig client_config;
+  client_config.set_client_type(SYNCHRONOUS_CLIENT);
+  client_config.set_enable_ssl(false);
+  client_config.set_outstanding_rpcs_per_channel(1);
+  client_config.set_client_channels(1);
+  client_config.set_payload_size(1);
+  client_config.set_rpc_type(STREAMING);
+
+  ServerConfig server_config;
+  server_config.set_server_type(SYNCHRONOUS_SERVER);
+  server_config.set_enable_ssl(false);
+  server_config.set_threads(1);
+
+  auto result = RunScenario(client_config, 1, server_config, 1, WARMUP, BENCHMARK);
+
+  ReportQPS(result);
+  ReportLatency(result);
+}
+
+static void RunAsyncUnaryPingPong() {
+  gpr_log(GPR_INFO, "Running Async Unary Ping Pong");
+
+  ClientConfig client_config;
+  client_config.set_client_type(ASYNC_CLIENT);
+  client_config.set_enable_ssl(false);
+  client_config.set_outstanding_rpcs_per_channel(1);
+  client_config.set_client_channels(1);
+  client_config.set_payload_size(1);
+  client_config.set_async_client_threads(1);
+  client_config.set_rpc_type(UNARY);
+
+  ServerConfig server_config;
+  server_config.set_server_type(ASYNC_SERVER);
+  server_config.set_enable_ssl(false);
+  server_config.set_threads(1);
+
+  auto result = RunScenario(client_config, 1, server_config, 1, WARMUP, BENCHMARK);
+
+  ReportQPS(result);
+  ReportLatency(result);
+}
+
+static void RunQPS() {
+  gpr_log(GPR_INFO, "Running QPS test");
+
+  ClientConfig client_config;
+  client_config.set_client_type(ASYNC_CLIENT);
+  client_config.set_enable_ssl(false);
+  client_config.set_outstanding_rpcs_per_channel(1000);
+  client_config.set_client_channels(8);
+  client_config.set_payload_size(1);
+  client_config.set_async_client_threads(8);
+  client_config.set_rpc_type(UNARY);
+
+  ServerConfig server_config;
+  server_config.set_server_type(ASYNC_SERVER);
+  server_config.set_enable_ssl(false);
+  server_config.set_threads(4);
+
+  auto result = RunScenario(client_config, 1, server_config, 1, WARMUP, BENCHMARK);
+
+  ReportQPSPerCore(result, server_config);
+  ReportLatency(result);
+}
+
+}  // namespace testing
+}  // namespace grpc
+
+int main(int argc, char** argv) {
+  grpc_init();
+
+  using namespace grpc::testing;
+  RunSynchronousStreamingPingPong();
+  RunSynchronousUnaryPingPong();
+  RunAsyncUnaryPingPong();
+  RunQPS();
+
+  grpc_shutdown();
+  return 0;
+}
diff --git a/test/cpp/qps/smoke_test.sh b/test/cpp/qps/smoke_test.sh
new file mode 100755
index 0000000000000000000000000000000000000000..ba7f0a4f27dd427bf38a3d9fe9a022fdc550c20d
--- /dev/null
+++ b/test/cpp/qps/smoke_test.sh
@@ -0,0 +1,28 @@
+#!/bin/sh
+
+# performs a single qps run with one client and one server
+
+set -ex
+
+cd $(dirname $0)/../../..
+
+killall qps_worker || true
+
+config=opt
+
+NUMCPUS=`python2.7 -c 'import multiprocessing; print multiprocessing.cpu_count()'`
+
+make CONFIG=$config qps_worker qps_smoke_test -j$NUMCPUS
+
+bins/$config/qps_worker -driver_port 10000 -server_port 10001 &
+PID1=$!
+bins/$config/qps_worker -driver_port 10010 -server_port 10011 &
+PID2=$!
+
+export QPS_WORKERS="localhost:10000,localhost:10010"
+
+bins/$config/qps_smoke_test $*
+
+kill -2 $PID1 $PID2
+wait
+
diff --git a/tools/buildgen/generate_projects.sh b/tools/buildgen/generate_projects.sh
index 7a12440db2c0b277a5ade6d8c7b131409953c2d5..45f08df38fecbb18491a4547a41dd1863bd56030 100755
--- a/tools/buildgen/generate_projects.sh
+++ b/tools/buildgen/generate_projects.sh
@@ -1,4 +1,4 @@
-#!/bin/bash
+#!/bin/sh
 # Copyright 2015, Google Inc.
 # All rights reserved.
 #
@@ -31,7 +31,7 @@
 
 set -e
 
-if [ "x$TEST" == "x" ] ; then
+if [ "x$TEST" = "x" ] ; then
   TEST=false
 fi
 
@@ -61,12 +61,12 @@ for dir in . ; do
     out=${out%.*}  # strip template extension
     json_files="build.json $end2end_test_build"
     data=`for i in $json_files; do echo -n "-d $i "; done`
-    if [ $TEST == true ] ; then
+    if [ "x$TEST" = "xtrue" ] ; then
       actual_out=$out
       out=`mktemp /tmp/gentXXXXXX`
     fi
     $mako_renderer $plugins $data -o $out $file
-    if [ $TEST == true ] ; then
+    if [ "x$TEST" = "xtrue" ] ; then
       diff -q $out $actual_out
       rm $out
     fi
diff --git a/src/ruby/spec/alloc_spec.rb b/tools/buildgen/plugins/expand_bin_attrs.py
old mode 100644
new mode 100755
similarity index 73%
rename from src/ruby/spec/alloc_spec.rb
rename to tools/buildgen/plugins/expand_bin_attrs.py
index 88e7e2b3e7ac10441f5cad7af6fe28c888449da1..0896a5a1652b6f2c4cde4ed460f87e343b9a3723
--- a/src/ruby/spec/alloc_spec.rb
+++ b/tools/buildgen/plugins/expand_bin_attrs.py
@@ -27,18 +27,25 @@
 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
-require 'grpc'
-
-describe 'Wrapped classes where .new cannot create an instance' do
-  describe GRPC::Core::Event do
-    it 'should fail .new fail with a runtime error' do
-      expect { GRPC::Core::Event.new }.to raise_error(TypeError)
-    end
-  end
-
-  describe GRPC::Core::Call do
-    it 'should fail .new fail with a runtime error' do
-      expect { GRPC::Core::Event.new }.to raise_error(TypeError)
-    end
-  end
-end
+"""Buildgen expand binary attributes plugin.
+
+This fills in any optional attributes.
+
+"""
+
+
+def mako_plugin(dictionary):
+  """The exported plugin code for expand_filegroups.
+
+  The list of libs in the build.json file can contain "filegroups" tags.
+  These refer to the filegroups in the root object. We will expand and
+  merge filegroups on the src, headers and public_headers properties.
+
+  """
+
+  targets = dictionary.get('targets')
+
+  for tgt in targets:
+    tgt['flaky'] = tgt.get('flaky', False)
+    tgt['platforms'] = tgt.get('platforms', ['windows', 'posix'])
+
diff --git a/tools/dockerfile/grpc_python/Dockerfile b/tools/dockerfile/grpc_python/Dockerfile
index 62ef785a3184384a334de3bf50e73580ba1d7901..aa29685beee06e2a2ae076cf57385137a704b7a6 100644
--- a/tools/dockerfile/grpc_python/Dockerfile
+++ b/tools/dockerfile/grpc_python/Dockerfile
@@ -66,5 +66,8 @@ RUN cd /var/local/git/grpc \
 # Add a cacerts directory containing the Google root pem file, allowing the interop client to access the production test instance
 ADD cacerts cacerts
 
+# Add a service_account directory containing the auth creds file
+ADD service_account service_account
+
 # Specify the default command such that the interop server runs on its known testing port
 CMD ["/bin/bash", "-l", "-c", "python2.7 -m interop.server --use_tls --port 8050"]
diff --git a/tools/gce_setup/grpc_docker.sh b/tools/gce_setup/grpc_docker.sh
index 40634291cf9b5467fa6825262ac511b4cd37fe77..c68903b816407503f2fc679b501f4018f925d53c 100755
--- a/tools/gce_setup/grpc_docker.sh
+++ b/tools/gce_setup/grpc_docker.sh
@@ -1047,7 +1047,7 @@ grpc_interop_gen_python_cmd() {
 #   flags= .... # generic flags to include the command
 #   cmd=$($grpc_gen_test_cmd $flags)
 grpc_cloud_prod_auth_service_account_creds_gen_python_cmd() {
-  local cmd_prefix="sudo docker run grpc/ruby bin/bash -l -c";
+  local cmd_prefix="sudo docker run grpc/python bin/bash -l -c";
   local gfe_flags=$(_grpc_prod_gfe_flags)
   local added_gfe_flags=$(_grpc_default_creds_test_flags)
   local env_prefix="SSL_CERT_FILE=/cacerts/roots.pem"
@@ -1062,7 +1062,7 @@ grpc_cloud_prod_auth_service_account_creds_gen_python_cmd() {
 #   flags= .... # generic flags to include the command
 #   cmd=$($grpc_gen_test_cmd $flags)
 grpc_cloud_prod_auth_compute_engine_creds_gen_python_cmd() {
-  local cmd_prefix="sudo docker run grpc/ruby bin/bash -l -c";
+  local cmd_prefix="sudo docker run grpc/python bin/bash -l -c";
   local gfe_flags=$(_grpc_prod_gfe_flags)
   local added_gfe_flags=$(_grpc_gce_test_flags)
   local env_prefix="SSL_CERT_FILE=/cacerts/roots.pem"
diff --git a/tools/gce_setup/interop_test_runner.sh b/tools/gce_setup/interop_test_runner.sh
index 7f0b5bab1a91c6d8d7cfd10fba5ff69737a2a2cb..1c6122e9ae15752e1497594672bf63727ab7e693 100755
--- a/tools/gce_setup/interop_test_runner.sh
+++ b/tools/gce_setup/interop_test_runner.sh
@@ -36,7 +36,7 @@ echo $result_file_name
 main() {
   source grpc_docker.sh
   test_cases=(large_unary empty_unary ping_pong client_streaming server_streaming cancel_after_begin cancel_after_first_response)
-  clients=(cxx java go ruby node python csharp_mono)
+  clients=(cxx java go ruby node python csharp_mono php)
   servers=(cxx java go ruby node python csharp_mono)
   for test_case in "${test_cases[@]}"
   do
diff --git a/tools/run_tests/jobset.py b/tools/run_tests/jobset.py
index 81cdd0e6e407e8888aceefccb935c4fd3360c563..efe040aeb6525039c6ea58b4b240bf1c3122e131 100755
--- a/tools/run_tests/jobset.py
+++ b/tools/run_tests/jobset.py
@@ -32,6 +32,7 @@
 import hashlib
 import multiprocessing
 import os
+import platform
 import random
 import signal
 import subprocess
@@ -43,17 +44,19 @@ import time
 _DEFAULT_MAX_JOBS = 16 * multiprocessing.cpu_count()
 
 
-have_alarm = False
-def alarm_handler(unused_signum, unused_frame):
-  global have_alarm
-  have_alarm = False
-
-
 # setup a signal handler so that signal.pause registers 'something'
 # when a child finishes
 # not using futures and threading to avoid a dependency on subprocess32
-signal.signal(signal.SIGCHLD, lambda unused_signum, unused_frame: None)
-signal.signal(signal.SIGALRM, alarm_handler)
+if platform.system() == "Windows":
+  pass
+else:
+  have_alarm = False
+  def alarm_handler(unused_signum, unused_frame):
+    global have_alarm
+    have_alarm = False
+
+  signal.signal(signal.SIGCHLD, lambda unused_signum, unused_frame: None)
+  signal.signal(signal.SIGALRM, alarm_handler)
 
 
 def shuffle_iteratable(it):
@@ -109,6 +112,11 @@ _TAG_COLOR = {
 
 
 def message(tag, message, explanatory_text=None, do_newline=False):
+  if platform.system() == 'Windows':
+    if explanatory_text:
+      print explanatory_text
+    print '%s: %s' % (tag, message)
+    return
   try:
     sys.stdout.write('%s%s%s\x1b[%d;%dm%s\x1b[0m: %s%s' % (
         _BEGINNING_OF_LINE,
@@ -136,7 +144,7 @@ def which(filename):
 class JobSpec(object):
   """Specifies what to run for a job."""
 
-  def __init__(self, cmdline, shortname=None, environ=None, hash_targets=None):
+  def __init__(self, cmdline, shortname=None, environ=None, hash_targets=None, cwd=None):
     """
     Arguments:
       cmdline: a list of arguments to pass as the command line
@@ -152,6 +160,7 @@ class JobSpec(object):
     self.environ = environ
     self.shortname = cmdline[0] if shortname is None else shortname
     self.hash_targets = hash_targets or []
+    self.cwd = cwd
 
   def identity(self):
     return '%r %r %r' % (self.cmdline, self.environ, self.hash_targets)
@@ -177,6 +186,7 @@ class Job(object):
     self._process = subprocess.Popen(args=spec.cmdline,
                                      stderr=subprocess.STDOUT,
                                      stdout=self._tempfile,
+                                     cwd=spec.cwd,
                                      env=env)
     self._state = _RUNNING
     self._newline_on_success = newline_on_success
@@ -241,10 +251,15 @@ class Jobset(object):
       bin_hash = None
       should_run = True
     if should_run:
-      self._running.add(Job(spec,
-                            bin_hash,
-                            self._newline_on_success,
-                            self._travis))
+      try:
+        self._running.add(Job(spec,
+                              bin_hash,
+                              self._newline_on_success,
+                              self._travis))
+      except:
+        message('FAILED', spec.shortname)
+        self._cancelled = True
+        return False
     return True
 
   def reap(self):
@@ -264,11 +279,14 @@ class Jobset(object):
       if (not self._travis):
         message('WAITING', '%d jobs running, %d complete, %d failed' % (
             len(self._running), self._completed, self._failures))
-      global have_alarm
-      if not have_alarm:
-        have_alarm = True
-        signal.alarm(10)
-      signal.pause()
+      if platform.system() == 'Windows':
+        time.sleep(0.1)
+      else:
+        global have_alarm
+        if not have_alarm:
+          have_alarm = True
+          signal.alarm(10)
+        signal.pause()
 
   def cancelled(self):
     """Poll for cancellation."""
diff --git a/tools/run_tests/run_tests.py b/tools/run_tests/run_tests.py
index 1e3516567e279ecfbc873e80cfa4cd23c27c8a3c..a443b17a971152e0adb84bd5509d41db6df1371c 100755
--- a/tools/run_tests/run_tests.py
+++ b/tools/run_tests/run_tests.py
@@ -1,4 +1,4 @@
-#!/usr/bin/python2.7
+#!/usr/bin/env python
 # Copyright 2015, Google Inc.
 # All rights reserved.
 #
@@ -39,6 +39,7 @@ import os
 import re
 import sys
 import time
+import platform
 
 import jobset
 import watch_dirs
@@ -101,9 +102,16 @@ class CLanguage(object):
 
   def __init__(self, make_target, test_lang):
     self.make_target = make_target
+    if platform.system() == 'Windows':
+      plat = 'windows'
+    else:
+      plat = 'posix'
     with open('tools/run_tests/tests.json') as f:
       js = json.load(f)
-      self.binaries = [tgt for tgt in js if tgt['language'] == test_lang]
+      self.binaries = [tgt
+                       for tgt in js
+                       if tgt['language'] == test_lang and
+                          plat in tgt['platforms']]
 
   def test_specs(self, config, travis):
     out = []
@@ -190,6 +198,7 @@ class PythonLanguage(object):
   def __str__(self):
     return 'python'
 
+
 class RubyLanguage(object):
 
   def test_specs(self, config, travis):
@@ -207,6 +216,7 @@ class RubyLanguage(object):
   def __str__(self):
     return 'ruby'
 
+
 class CSharpLanguage(object):
 
   def test_specs(self, config, travis):
@@ -224,6 +234,7 @@ class CSharpLanguage(object):
   def __str__(self):
     return 'csharp'
 
+
 class Sanity(object):
 
   def test_specs(self, config, travis):
@@ -241,6 +252,7 @@ class Sanity(object):
   def __str__(self):
     return 'sanity'
 
+
 class Build(object):
 
   def test_specs(self, config, travis):
@@ -332,17 +344,27 @@ if len(build_configs) > 1:
       print language, 'does not support multiple build configurations'
       sys.exit(1)
 
-build_steps = [jobset.JobSpec(['make',
-                               '-j', '%d' % (multiprocessing.cpu_count() + 1),
-                               'EXTRA_DEFINES=GRPC_TEST_SLOWDOWN_MACHINE_FACTOR=%f' % args.slowdown,
-                               'CONFIG=%s' % cfg] + list(set(
-                                   itertools.chain.from_iterable(
-                                       l.make_targets() for l in languages))))
-               for cfg in build_configs] + list(set(
+if platform.system() == 'Windows':
+  def make_jobspec(cfg, targets):
+    return jobset.JobSpec(['nmake', '/f', 'Grpc.mak', 'CONFIG=%s' % cfg] + targets,
+                          cwd='vsprojects\\vs2013')
+else:
+  def make_jobspec(cfg, targets):
+    return jobset.JobSpec(['make',
+                           '-j', '%d' % (multiprocessing.cpu_count() + 1),
+                           'EXTRA_DEFINES=GRPC_TEST_SLOWDOWN_MACHINE_FACTOR=%f' % 
+                               args.slowdown,
+                           'CONFIG=%s' % cfg] + targets)
+
+build_steps = [make_jobspec(cfg, 
+                            list(set(itertools.chain.from_iterable(
+                                         l.make_targets() for l in languages))))
+               for cfg in build_configs]
+build_steps.extend(set(
                    jobset.JobSpec(cmdline, environ={'CONFIG': cfg})
                    for cfg in build_configs
                    for l in languages
-                   for cmdline in l.build_steps()))
+                   for cmdline in l.build_steps()))               
 one_run = set(
     spec
     for config in run_configs
diff --git a/tools/run_tests/tests.json b/tools/run_tests/tests.json
index eab07040e7c73f1ae25f652c5058e6421f5c675d..cb379863f1f10dcb056f10ba60931cc92744c98f 100644
--- a/tools/run_tests/tests.json
+++ b/tools/run_tests/tests.json
@@ -4,2112 +4,3808 @@
   {
     "flaky": false, 
     "language": "c", 
-    "name": "alarm_heap_test"
+    "name": "alarm_heap_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "alarm_list_test"
+    "name": "alarm_list_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "alarm_test"
+    "name": "alarm_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "alpn_test"
+    "name": "alpn_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "bin_encoder_test"
+    "name": "bin_encoder_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "census_hash_table_test"
+    "name": "census_hash_table_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": true, 
     "language": "c", 
-    "name": "census_statistics_multiple_writers_circular_buffer_test"
+    "name": "census_statistics_multiple_writers_circular_buffer_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "census_statistics_multiple_writers_test"
+    "name": "census_statistics_multiple_writers_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "census_statistics_performance_test"
+    "name": "census_statistics_performance_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "census_statistics_quick_test"
+    "name": "census_statistics_quick_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": true, 
     "language": "c", 
-    "name": "census_statistics_small_log_test"
+    "name": "census_statistics_small_log_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "census_stub_test"
+    "name": "census_stub_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "census_window_stats_test"
+    "name": "census_window_stats_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_status_conversion_test"
+    "name": "chttp2_status_conversion_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_stream_encoder_test"
+    "name": "chttp2_stream_encoder_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_stream_map_test"
+    "name": "chttp2_stream_map_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_transport_end2end_test"
+    "name": "chttp2_transport_end2end_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "dualstack_socket_test"
+    "name": "dualstack_socket_test", 
+    "platforms": [
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "echo_test"
+    "name": "echo_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "fd_posix_test"
+    "name": "fd_posix_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "fling_stream_test"
+    "name": "fling_stream_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "fling_test"
+    "name": "fling_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "gpr_cancellable_test"
+    "name": "gpr_cancellable_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "gpr_cmdline_test"
+    "name": "gpr_cmdline_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "gpr_env_test"
+    "name": "gpr_env_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "gpr_file_test"
+    "name": "gpr_file_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "gpr_histogram_test"
+    "name": "gpr_histogram_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "gpr_host_port_test"
+    "name": "gpr_host_port_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "gpr_log_test"
+    "name": "gpr_log_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "gpr_slice_buffer_test"
+    "name": "gpr_slice_buffer_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "gpr_slice_test"
+    "name": "gpr_slice_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "gpr_string_test"
+    "name": "gpr_string_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "gpr_sync_test"
+    "name": "gpr_sync_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "gpr_thd_test"
+    "name": "gpr_thd_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "gpr_time_test"
+    "name": "gpr_time_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "gpr_useful_test"
+    "name": "gpr_tls_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "grpc_base64_test"
+    "name": "gpr_useful_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "grpc_byte_buffer_reader_test"
+    "name": "grpc_base64_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "grpc_channel_stack_test"
+    "name": "grpc_byte_buffer_reader_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "grpc_completion_queue_test"
+    "name": "grpc_channel_stack_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "grpc_credentials_test"
+    "name": "grpc_completion_queue_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "grpc_json_token_test"
+    "name": "grpc_credentials_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "grpc_stream_op_test"
+    "name": "grpc_json_token_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "hpack_parser_test"
+    "name": "grpc_stream_op_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "hpack_table_test"
+    "name": "hpack_parser_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "httpcli_format_request_test"
+    "name": "hpack_table_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "httpcli_parser_test"
+    "name": "httpcli_format_request_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "json_rewrite_test"
+    "name": "httpcli_parser_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "json_test"
+    "name": "json_rewrite_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "lame_client_test"
+    "name": "json_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "message_compress_test"
+    "name": "lame_client_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "metadata_buffer_test"
+    "name": "message_compress_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "multi_init_test"
+    "name": "metadata_buffer_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "murmur_hash_test"
+    "name": "multi_init_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "no_server_test"
+    "name": "murmur_hash_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "poll_kick_posix_test"
+    "name": "no_server_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "resolve_address_test"
+    "name": "poll_kick_posix_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "secure_endpoint_test"
+    "name": "resolve_address_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "sockaddr_utils_test"
+    "name": "secure_endpoint_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "tcp_client_posix_test"
+    "name": "sockaddr_utils_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "tcp_posix_test"
+    "name": "tcp_client_posix_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "tcp_server_posix_test"
+    "name": "tcp_posix_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "time_averaged_stats_test"
+    "name": "tcp_server_posix_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "time_test"
+    "name": "time_averaged_stats_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "timeout_encoding_test"
+    "name": "time_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "transport_metadata_test"
+    "name": "timeout_encoding_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "transport_security_test"
+    "name": "transport_metadata_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
+  }, 
+  {
+    "flaky": false, 
+    "language": "c", 
+    "name": "transport_security_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c++", 
-    "name": "async_end2end_test"
+    "name": "async_end2end_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c++", 
-    "name": "channel_arguments_test"
+    "name": "channel_arguments_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c++", 
-    "name": "cli_call_test"
+    "name": "cli_call_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c++", 
-    "name": "credentials_test"
+    "name": "credentials_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c++", 
-    "name": "cxx_time_test"
+    "name": "cxx_time_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c++", 
-    "name": "end2end_test"
+    "name": "end2end_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c++", 
-    "name": "generic_end2end_test"
+    "name": "generic_end2end_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c++", 
-    "name": "interop_test"
+    "name": "interop_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c++", 
-    "name": "pubsub_publisher_test"
+    "name": "pubsub_publisher_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c++", 
-    "name": "pubsub_subscriber_test"
+    "name": "pubsub_subscriber_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c++", 
-    "name": "status_test"
+    "name": "status_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c++", 
-    "name": "thread_pool_test"
+    "name": "thread_pool_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_fake_security_bad_hostname_test"
+    "name": "chttp2_fake_security_bad_hostname_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_fake_security_cancel_after_accept_test"
+    "name": "chttp2_fake_security_cancel_after_accept_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_fake_security_cancel_after_accept_and_writes_closed_test"
+    "name": "chttp2_fake_security_cancel_after_accept_and_writes_closed_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_fake_security_cancel_after_invoke_test"
+    "name": "chttp2_fake_security_cancel_after_invoke_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_fake_security_cancel_before_invoke_test"
+    "name": "chttp2_fake_security_cancel_before_invoke_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_fake_security_cancel_in_a_vacuum_test"
+    "name": "chttp2_fake_security_cancel_in_a_vacuum_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_fake_security_census_simple_request_test"
+    "name": "chttp2_fake_security_census_simple_request_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_fake_security_disappearing_server_test"
+    "name": "chttp2_fake_security_disappearing_server_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_fake_security_early_server_shutdown_finishes_inflight_calls_test"
+    "name": "chttp2_fake_security_early_server_shutdown_finishes_inflight_calls_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_fake_security_early_server_shutdown_finishes_tags_test"
+    "name": "chttp2_fake_security_early_server_shutdown_finishes_tags_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_fake_security_empty_batch_test"
+    "name": "chttp2_fake_security_empty_batch_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_fake_security_graceful_server_shutdown_test"
+    "name": "chttp2_fake_security_graceful_server_shutdown_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_fake_security_invoke_large_request_test"
+    "name": "chttp2_fake_security_invoke_large_request_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_fake_security_max_concurrent_streams_test"
+    "name": "chttp2_fake_security_max_concurrent_streams_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_fake_security_no_op_test"
+    "name": "chttp2_fake_security_no_op_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_fake_security_ping_pong_streaming_test"
+    "name": "chttp2_fake_security_ping_pong_streaming_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_fake_security_request_response_with_binary_metadata_and_payload_test"
+    "name": "chttp2_fake_security_request_response_with_binary_metadata_and_payload_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_fake_security_request_response_with_metadata_and_payload_test"
+    "name": "chttp2_fake_security_request_response_with_metadata_and_payload_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_fake_security_request_response_with_payload_test"
+    "name": "chttp2_fake_security_request_response_with_payload_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_fake_security_request_with_large_metadata_test"
+    "name": "chttp2_fake_security_request_with_large_metadata_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_fake_security_request_with_payload_test"
+    "name": "chttp2_fake_security_request_with_payload_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_fake_security_simple_delayed_request_test"
+    "name": "chttp2_fake_security_simple_delayed_request_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_fake_security_simple_request_test"
+    "name": "chttp2_fake_security_simple_request_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_fake_security_thread_stress_test"
+    "name": "chttp2_fake_security_thread_stress_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_fake_security_writes_done_hangs_with_pending_read_test"
+    "name": "chttp2_fake_security_writes_done_hangs_with_pending_read_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_fake_security_cancel_after_accept_legacy_test"
+    "name": "chttp2_fake_security_cancel_after_accept_legacy_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_fake_security_cancel_after_accept_and_writes_closed_legacy_test"
+    "name": "chttp2_fake_security_cancel_after_accept_and_writes_closed_legacy_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_fake_security_cancel_after_invoke_legacy_test"
+    "name": "chttp2_fake_security_cancel_after_invoke_legacy_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_fake_security_cancel_before_invoke_legacy_test"
+    "name": "chttp2_fake_security_cancel_before_invoke_legacy_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_fake_security_cancel_in_a_vacuum_legacy_test"
+    "name": "chttp2_fake_security_cancel_in_a_vacuum_legacy_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_fake_security_census_simple_request_legacy_test"
+    "name": "chttp2_fake_security_census_simple_request_legacy_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_fake_security_disappearing_server_legacy_test"
+    "name": "chttp2_fake_security_disappearing_server_legacy_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_fake_security_early_server_shutdown_finishes_inflight_calls_legacy_test"
+    "name": "chttp2_fake_security_early_server_shutdown_finishes_inflight_calls_legacy_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_fake_security_early_server_shutdown_finishes_tags_legacy_test"
+    "name": "chttp2_fake_security_early_server_shutdown_finishes_tags_legacy_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_fake_security_graceful_server_shutdown_legacy_test"
+    "name": "chttp2_fake_security_graceful_server_shutdown_legacy_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_fake_security_invoke_large_request_legacy_test"
+    "name": "chttp2_fake_security_invoke_large_request_legacy_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_fake_security_max_concurrent_streams_legacy_test"
+    "name": "chttp2_fake_security_max_concurrent_streams_legacy_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_fake_security_no_op_legacy_test"
+    "name": "chttp2_fake_security_no_op_legacy_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_fake_security_ping_pong_streaming_legacy_test"
+    "name": "chttp2_fake_security_ping_pong_streaming_legacy_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_fake_security_request_response_with_binary_metadata_and_payload_legacy_test"
+    "name": "chttp2_fake_security_request_response_with_binary_metadata_and_payload_legacy_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_fake_security_request_response_with_metadata_and_payload_legacy_test"
+    "name": "chttp2_fake_security_request_response_with_metadata_and_payload_legacy_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_fake_security_request_response_with_payload_legacy_test"
+    "name": "chttp2_fake_security_request_response_with_payload_legacy_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_fake_security_request_response_with_trailing_metadata_and_payload_legacy_test"
+    "name": "chttp2_fake_security_request_response_with_trailing_metadata_and_payload_legacy_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_fake_security_request_with_large_metadata_legacy_test"
+    "name": "chttp2_fake_security_request_with_large_metadata_legacy_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_fake_security_request_with_payload_legacy_test"
+    "name": "chttp2_fake_security_request_with_payload_legacy_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_fake_security_simple_delayed_request_legacy_test"
+    "name": "chttp2_fake_security_simple_delayed_request_legacy_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_fake_security_simple_request_legacy_test"
+    "name": "chttp2_fake_security_simple_request_legacy_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_fake_security_thread_stress_legacy_test"
+    "name": "chttp2_fake_security_thread_stress_legacy_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_fake_security_writes_done_hangs_with_pending_read_legacy_test"
+    "name": "chttp2_fake_security_writes_done_hangs_with_pending_read_legacy_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_fullstack_bad_hostname_test"
+    "name": "chttp2_fullstack_bad_hostname_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_fullstack_cancel_after_accept_test"
+    "name": "chttp2_fullstack_cancel_after_accept_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_fullstack_cancel_after_accept_and_writes_closed_test"
+    "name": "chttp2_fullstack_cancel_after_accept_and_writes_closed_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_fullstack_cancel_after_invoke_test"
+    "name": "chttp2_fullstack_cancel_after_invoke_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_fullstack_cancel_before_invoke_test"
+    "name": "chttp2_fullstack_cancel_before_invoke_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_fullstack_cancel_in_a_vacuum_test"
+    "name": "chttp2_fullstack_cancel_in_a_vacuum_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_fullstack_census_simple_request_test"
+    "name": "chttp2_fullstack_census_simple_request_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_fullstack_disappearing_server_test"
+    "name": "chttp2_fullstack_disappearing_server_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_fullstack_early_server_shutdown_finishes_inflight_calls_test"
+    "name": "chttp2_fullstack_early_server_shutdown_finishes_inflight_calls_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_fullstack_early_server_shutdown_finishes_tags_test"
+    "name": "chttp2_fullstack_early_server_shutdown_finishes_tags_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_fullstack_empty_batch_test"
+    "name": "chttp2_fullstack_empty_batch_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_fullstack_graceful_server_shutdown_test"
+    "name": "chttp2_fullstack_graceful_server_shutdown_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_fullstack_invoke_large_request_test"
+    "name": "chttp2_fullstack_invoke_large_request_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_fullstack_max_concurrent_streams_test"
+    "name": "chttp2_fullstack_max_concurrent_streams_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_fullstack_no_op_test"
+    "name": "chttp2_fullstack_no_op_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_fullstack_ping_pong_streaming_test"
+    "name": "chttp2_fullstack_ping_pong_streaming_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_fullstack_request_response_with_binary_metadata_and_payload_test"
+    "name": "chttp2_fullstack_request_response_with_binary_metadata_and_payload_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_fullstack_request_response_with_metadata_and_payload_test"
+    "name": "chttp2_fullstack_request_response_with_metadata_and_payload_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_fullstack_request_response_with_payload_test"
+    "name": "chttp2_fullstack_request_response_with_payload_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_fullstack_request_with_large_metadata_test"
+    "name": "chttp2_fullstack_request_with_large_metadata_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_fullstack_request_with_payload_test"
+    "name": "chttp2_fullstack_request_with_payload_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_fullstack_simple_delayed_request_test"
+    "name": "chttp2_fullstack_simple_delayed_request_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_fullstack_simple_request_test"
+    "name": "chttp2_fullstack_simple_request_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_fullstack_thread_stress_test"
+    "name": "chttp2_fullstack_thread_stress_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_fullstack_writes_done_hangs_with_pending_read_test"
+    "name": "chttp2_fullstack_writes_done_hangs_with_pending_read_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_fullstack_cancel_after_accept_legacy_test"
+    "name": "chttp2_fullstack_cancel_after_accept_legacy_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_fullstack_cancel_after_accept_and_writes_closed_legacy_test"
+    "name": "chttp2_fullstack_cancel_after_accept_and_writes_closed_legacy_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_fullstack_cancel_after_invoke_legacy_test"
+    "name": "chttp2_fullstack_cancel_after_invoke_legacy_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_fullstack_cancel_before_invoke_legacy_test"
+    "name": "chttp2_fullstack_cancel_before_invoke_legacy_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_fullstack_cancel_in_a_vacuum_legacy_test"
+    "name": "chttp2_fullstack_cancel_in_a_vacuum_legacy_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_fullstack_census_simple_request_legacy_test"
+    "name": "chttp2_fullstack_census_simple_request_legacy_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_fullstack_disappearing_server_legacy_test"
+    "name": "chttp2_fullstack_disappearing_server_legacy_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_fullstack_early_server_shutdown_finishes_inflight_calls_legacy_test"
+    "name": "chttp2_fullstack_early_server_shutdown_finishes_inflight_calls_legacy_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_fullstack_early_server_shutdown_finishes_tags_legacy_test"
+    "name": "chttp2_fullstack_early_server_shutdown_finishes_tags_legacy_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_fullstack_graceful_server_shutdown_legacy_test"
+    "name": "chttp2_fullstack_graceful_server_shutdown_legacy_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_fullstack_invoke_large_request_legacy_test"
+    "name": "chttp2_fullstack_invoke_large_request_legacy_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_fullstack_max_concurrent_streams_legacy_test"
+    "name": "chttp2_fullstack_max_concurrent_streams_legacy_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_fullstack_no_op_legacy_test"
+    "name": "chttp2_fullstack_no_op_legacy_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_fullstack_ping_pong_streaming_legacy_test"
+    "name": "chttp2_fullstack_ping_pong_streaming_legacy_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_fullstack_request_response_with_binary_metadata_and_payload_legacy_test"
+    "name": "chttp2_fullstack_request_response_with_binary_metadata_and_payload_legacy_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_fullstack_request_response_with_metadata_and_payload_legacy_test"
+    "name": "chttp2_fullstack_request_response_with_metadata_and_payload_legacy_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_fullstack_request_response_with_payload_legacy_test"
+    "name": "chttp2_fullstack_request_response_with_payload_legacy_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_fullstack_request_response_with_trailing_metadata_and_payload_legacy_test"
+    "name": "chttp2_fullstack_request_response_with_trailing_metadata_and_payload_legacy_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_fullstack_request_with_large_metadata_legacy_test"
+    "name": "chttp2_fullstack_request_with_large_metadata_legacy_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_fullstack_request_with_payload_legacy_test"
+    "name": "chttp2_fullstack_request_with_payload_legacy_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_fullstack_simple_delayed_request_legacy_test"
+    "name": "chttp2_fullstack_simple_delayed_request_legacy_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_fullstack_simple_request_legacy_test"
+    "name": "chttp2_fullstack_simple_request_legacy_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_fullstack_thread_stress_legacy_test"
+    "name": "chttp2_fullstack_thread_stress_legacy_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_fullstack_writes_done_hangs_with_pending_read_legacy_test"
+    "name": "chttp2_fullstack_writes_done_hangs_with_pending_read_legacy_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_fullstack_uds_bad_hostname_test"
+    "name": "chttp2_fullstack_uds_bad_hostname_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_fullstack_uds_cancel_after_accept_test"
+    "name": "chttp2_fullstack_uds_cancel_after_accept_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_fullstack_uds_cancel_after_accept_and_writes_closed_test"
+    "name": "chttp2_fullstack_uds_cancel_after_accept_and_writes_closed_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_fullstack_uds_cancel_after_invoke_test"
+    "name": "chttp2_fullstack_uds_cancel_after_invoke_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_fullstack_uds_cancel_before_invoke_test"
+    "name": "chttp2_fullstack_uds_cancel_before_invoke_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_fullstack_uds_cancel_in_a_vacuum_test"
+    "name": "chttp2_fullstack_uds_cancel_in_a_vacuum_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_fullstack_uds_census_simple_request_test"
+    "name": "chttp2_fullstack_uds_census_simple_request_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_fullstack_uds_disappearing_server_test"
+    "name": "chttp2_fullstack_uds_disappearing_server_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_fullstack_uds_early_server_shutdown_finishes_inflight_calls_test"
+    "name": "chttp2_fullstack_uds_early_server_shutdown_finishes_inflight_calls_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_fullstack_uds_early_server_shutdown_finishes_tags_test"
+    "name": "chttp2_fullstack_uds_early_server_shutdown_finishes_tags_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_fullstack_uds_empty_batch_test"
+    "name": "chttp2_fullstack_uds_empty_batch_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_fullstack_uds_graceful_server_shutdown_test"
+    "name": "chttp2_fullstack_uds_graceful_server_shutdown_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_fullstack_uds_invoke_large_request_test"
+    "name": "chttp2_fullstack_uds_invoke_large_request_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_fullstack_uds_max_concurrent_streams_test"
+    "name": "chttp2_fullstack_uds_max_concurrent_streams_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_fullstack_uds_no_op_test"
+    "name": "chttp2_fullstack_uds_no_op_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_fullstack_uds_ping_pong_streaming_test"
+    "name": "chttp2_fullstack_uds_ping_pong_streaming_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_fullstack_uds_request_response_with_binary_metadata_and_payload_test"
+    "name": "chttp2_fullstack_uds_request_response_with_binary_metadata_and_payload_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_fullstack_uds_request_response_with_metadata_and_payload_test"
+    "name": "chttp2_fullstack_uds_request_response_with_metadata_and_payload_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_fullstack_uds_request_response_with_payload_test"
+    "name": "chttp2_fullstack_uds_request_response_with_payload_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_fullstack_uds_request_with_large_metadata_test"
+    "name": "chttp2_fullstack_uds_request_with_large_metadata_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_fullstack_uds_request_with_payload_test"
+    "name": "chttp2_fullstack_uds_request_with_payload_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_fullstack_uds_simple_delayed_request_test"
+    "name": "chttp2_fullstack_uds_simple_delayed_request_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_fullstack_uds_simple_request_test"
+    "name": "chttp2_fullstack_uds_simple_request_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_fullstack_uds_thread_stress_test"
+    "name": "chttp2_fullstack_uds_thread_stress_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_fullstack_uds_writes_done_hangs_with_pending_read_test"
+    "name": "chttp2_fullstack_uds_writes_done_hangs_with_pending_read_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_fullstack_uds_cancel_after_accept_legacy_test"
+    "name": "chttp2_fullstack_uds_cancel_after_accept_legacy_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_fullstack_uds_cancel_after_accept_and_writes_closed_legacy_test"
+    "name": "chttp2_fullstack_uds_cancel_after_accept_and_writes_closed_legacy_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_fullstack_uds_cancel_after_invoke_legacy_test"
+    "name": "chttp2_fullstack_uds_cancel_after_invoke_legacy_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_fullstack_uds_cancel_before_invoke_legacy_test"
+    "name": "chttp2_fullstack_uds_cancel_before_invoke_legacy_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_fullstack_uds_cancel_in_a_vacuum_legacy_test"
+    "name": "chttp2_fullstack_uds_cancel_in_a_vacuum_legacy_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_fullstack_uds_census_simple_request_legacy_test"
+    "name": "chttp2_fullstack_uds_census_simple_request_legacy_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_fullstack_uds_disappearing_server_legacy_test"
+    "name": "chttp2_fullstack_uds_disappearing_server_legacy_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_fullstack_uds_early_server_shutdown_finishes_inflight_calls_legacy_test"
+    "name": "chttp2_fullstack_uds_early_server_shutdown_finishes_inflight_calls_legacy_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_fullstack_uds_early_server_shutdown_finishes_tags_legacy_test"
+    "name": "chttp2_fullstack_uds_early_server_shutdown_finishes_tags_legacy_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_fullstack_uds_graceful_server_shutdown_legacy_test"
+    "name": "chttp2_fullstack_uds_graceful_server_shutdown_legacy_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_fullstack_uds_invoke_large_request_legacy_test"
+    "name": "chttp2_fullstack_uds_invoke_large_request_legacy_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_fullstack_uds_max_concurrent_streams_legacy_test"
+    "name": "chttp2_fullstack_uds_max_concurrent_streams_legacy_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_fullstack_uds_no_op_legacy_test"
+    "name": "chttp2_fullstack_uds_no_op_legacy_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_fullstack_uds_ping_pong_streaming_legacy_test"
+    "name": "chttp2_fullstack_uds_ping_pong_streaming_legacy_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_fullstack_uds_request_response_with_binary_metadata_and_payload_legacy_test"
+    "name": "chttp2_fullstack_uds_request_response_with_binary_metadata_and_payload_legacy_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_fullstack_uds_request_response_with_metadata_and_payload_legacy_test"
+    "name": "chttp2_fullstack_uds_request_response_with_metadata_and_payload_legacy_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_fullstack_uds_request_response_with_payload_legacy_test"
+    "name": "chttp2_fullstack_uds_request_response_with_payload_legacy_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_fullstack_uds_request_response_with_trailing_metadata_and_payload_legacy_test"
+    "name": "chttp2_fullstack_uds_request_response_with_trailing_metadata_and_payload_legacy_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_fullstack_uds_request_with_large_metadata_legacy_test"
+    "name": "chttp2_fullstack_uds_request_with_large_metadata_legacy_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_fullstack_uds_request_with_payload_legacy_test"
+    "name": "chttp2_fullstack_uds_request_with_payload_legacy_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_fullstack_uds_simple_delayed_request_legacy_test"
+    "name": "chttp2_fullstack_uds_simple_delayed_request_legacy_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_fullstack_uds_simple_request_legacy_test"
+    "name": "chttp2_fullstack_uds_simple_request_legacy_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_fullstack_uds_thread_stress_legacy_test"
+    "name": "chttp2_fullstack_uds_thread_stress_legacy_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_fullstack_uds_writes_done_hangs_with_pending_read_legacy_test"
+    "name": "chttp2_fullstack_uds_writes_done_hangs_with_pending_read_legacy_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_simple_ssl_fullstack_bad_hostname_test"
+    "name": "chttp2_simple_ssl_fullstack_bad_hostname_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_simple_ssl_fullstack_cancel_after_accept_test"
+    "name": "chttp2_simple_ssl_fullstack_cancel_after_accept_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_simple_ssl_fullstack_cancel_after_accept_and_writes_closed_test"
+    "name": "chttp2_simple_ssl_fullstack_cancel_after_accept_and_writes_closed_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_simple_ssl_fullstack_cancel_after_invoke_test"
+    "name": "chttp2_simple_ssl_fullstack_cancel_after_invoke_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_simple_ssl_fullstack_cancel_before_invoke_test"
+    "name": "chttp2_simple_ssl_fullstack_cancel_before_invoke_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_simple_ssl_fullstack_cancel_in_a_vacuum_test"
+    "name": "chttp2_simple_ssl_fullstack_cancel_in_a_vacuum_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_simple_ssl_fullstack_census_simple_request_test"
+    "name": "chttp2_simple_ssl_fullstack_census_simple_request_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_simple_ssl_fullstack_disappearing_server_test"
+    "name": "chttp2_simple_ssl_fullstack_disappearing_server_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_simple_ssl_fullstack_early_server_shutdown_finishes_inflight_calls_test"
+    "name": "chttp2_simple_ssl_fullstack_early_server_shutdown_finishes_inflight_calls_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_simple_ssl_fullstack_early_server_shutdown_finishes_tags_test"
+    "name": "chttp2_simple_ssl_fullstack_early_server_shutdown_finishes_tags_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_simple_ssl_fullstack_empty_batch_test"
+    "name": "chttp2_simple_ssl_fullstack_empty_batch_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_simple_ssl_fullstack_graceful_server_shutdown_test"
+    "name": "chttp2_simple_ssl_fullstack_graceful_server_shutdown_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_simple_ssl_fullstack_invoke_large_request_test"
+    "name": "chttp2_simple_ssl_fullstack_invoke_large_request_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_simple_ssl_fullstack_max_concurrent_streams_test"
+    "name": "chttp2_simple_ssl_fullstack_max_concurrent_streams_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_simple_ssl_fullstack_no_op_test"
+    "name": "chttp2_simple_ssl_fullstack_no_op_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_simple_ssl_fullstack_ping_pong_streaming_test"
+    "name": "chttp2_simple_ssl_fullstack_ping_pong_streaming_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_simple_ssl_fullstack_request_response_with_binary_metadata_and_payload_test"
+    "name": "chttp2_simple_ssl_fullstack_request_response_with_binary_metadata_and_payload_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_simple_ssl_fullstack_request_response_with_metadata_and_payload_test"
+    "name": "chttp2_simple_ssl_fullstack_request_response_with_metadata_and_payload_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_simple_ssl_fullstack_request_response_with_payload_test"
+    "name": "chttp2_simple_ssl_fullstack_request_response_with_payload_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_simple_ssl_fullstack_request_with_large_metadata_test"
+    "name": "chttp2_simple_ssl_fullstack_request_with_large_metadata_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_simple_ssl_fullstack_request_with_payload_test"
+    "name": "chttp2_simple_ssl_fullstack_request_with_payload_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_simple_ssl_fullstack_simple_delayed_request_test"
+    "name": "chttp2_simple_ssl_fullstack_simple_delayed_request_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_simple_ssl_fullstack_simple_request_test"
+    "name": "chttp2_simple_ssl_fullstack_simple_request_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_simple_ssl_fullstack_thread_stress_test"
+    "name": "chttp2_simple_ssl_fullstack_thread_stress_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_simple_ssl_fullstack_writes_done_hangs_with_pending_read_test"
+    "name": "chttp2_simple_ssl_fullstack_writes_done_hangs_with_pending_read_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_simple_ssl_fullstack_cancel_after_accept_legacy_test"
+    "name": "chttp2_simple_ssl_fullstack_cancel_after_accept_legacy_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_simple_ssl_fullstack_cancel_after_accept_and_writes_closed_legacy_test"
+    "name": "chttp2_simple_ssl_fullstack_cancel_after_accept_and_writes_closed_legacy_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_simple_ssl_fullstack_cancel_after_invoke_legacy_test"
+    "name": "chttp2_simple_ssl_fullstack_cancel_after_invoke_legacy_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_simple_ssl_fullstack_cancel_before_invoke_legacy_test"
+    "name": "chttp2_simple_ssl_fullstack_cancel_before_invoke_legacy_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_simple_ssl_fullstack_cancel_in_a_vacuum_legacy_test"
+    "name": "chttp2_simple_ssl_fullstack_cancel_in_a_vacuum_legacy_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_simple_ssl_fullstack_census_simple_request_legacy_test"
+    "name": "chttp2_simple_ssl_fullstack_census_simple_request_legacy_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_simple_ssl_fullstack_disappearing_server_legacy_test"
+    "name": "chttp2_simple_ssl_fullstack_disappearing_server_legacy_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_simple_ssl_fullstack_early_server_shutdown_finishes_inflight_calls_legacy_test"
+    "name": "chttp2_simple_ssl_fullstack_early_server_shutdown_finishes_inflight_calls_legacy_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_simple_ssl_fullstack_early_server_shutdown_finishes_tags_legacy_test"
+    "name": "chttp2_simple_ssl_fullstack_early_server_shutdown_finishes_tags_legacy_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_simple_ssl_fullstack_graceful_server_shutdown_legacy_test"
+    "name": "chttp2_simple_ssl_fullstack_graceful_server_shutdown_legacy_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_simple_ssl_fullstack_invoke_large_request_legacy_test"
+    "name": "chttp2_simple_ssl_fullstack_invoke_large_request_legacy_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_simple_ssl_fullstack_max_concurrent_streams_legacy_test"
+    "name": "chttp2_simple_ssl_fullstack_max_concurrent_streams_legacy_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_simple_ssl_fullstack_no_op_legacy_test"
+    "name": "chttp2_simple_ssl_fullstack_no_op_legacy_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_simple_ssl_fullstack_ping_pong_streaming_legacy_test"
+    "name": "chttp2_simple_ssl_fullstack_ping_pong_streaming_legacy_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_simple_ssl_fullstack_request_response_with_binary_metadata_and_payload_legacy_test"
+    "name": "chttp2_simple_ssl_fullstack_request_response_with_binary_metadata_and_payload_legacy_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_simple_ssl_fullstack_request_response_with_metadata_and_payload_legacy_test"
+    "name": "chttp2_simple_ssl_fullstack_request_response_with_metadata_and_payload_legacy_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_simple_ssl_fullstack_request_response_with_payload_legacy_test"
+    "name": "chttp2_simple_ssl_fullstack_request_response_with_payload_legacy_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_simple_ssl_fullstack_request_response_with_trailing_metadata_and_payload_legacy_test"
+    "name": "chttp2_simple_ssl_fullstack_request_response_with_trailing_metadata_and_payload_legacy_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_simple_ssl_fullstack_request_with_large_metadata_legacy_test"
+    "name": "chttp2_simple_ssl_fullstack_request_with_large_metadata_legacy_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_simple_ssl_fullstack_request_with_payload_legacy_test"
+    "name": "chttp2_simple_ssl_fullstack_request_with_payload_legacy_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_simple_ssl_fullstack_simple_delayed_request_legacy_test"
+    "name": "chttp2_simple_ssl_fullstack_simple_delayed_request_legacy_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_simple_ssl_fullstack_simple_request_legacy_test"
+    "name": "chttp2_simple_ssl_fullstack_simple_request_legacy_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_simple_ssl_fullstack_thread_stress_legacy_test"
+    "name": "chttp2_simple_ssl_fullstack_thread_stress_legacy_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_simple_ssl_fullstack_writes_done_hangs_with_pending_read_legacy_test"
+    "name": "chttp2_simple_ssl_fullstack_writes_done_hangs_with_pending_read_legacy_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_simple_ssl_with_oauth2_fullstack_bad_hostname_test"
+    "name": "chttp2_simple_ssl_with_oauth2_fullstack_bad_hostname_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_simple_ssl_with_oauth2_fullstack_cancel_after_accept_test"
+    "name": "chttp2_simple_ssl_with_oauth2_fullstack_cancel_after_accept_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_simple_ssl_with_oauth2_fullstack_cancel_after_accept_and_writes_closed_test"
+    "name": "chttp2_simple_ssl_with_oauth2_fullstack_cancel_after_accept_and_writes_closed_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_simple_ssl_with_oauth2_fullstack_cancel_after_invoke_test"
+    "name": "chttp2_simple_ssl_with_oauth2_fullstack_cancel_after_invoke_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_simple_ssl_with_oauth2_fullstack_cancel_before_invoke_test"
+    "name": "chttp2_simple_ssl_with_oauth2_fullstack_cancel_before_invoke_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_simple_ssl_with_oauth2_fullstack_cancel_in_a_vacuum_test"
+    "name": "chttp2_simple_ssl_with_oauth2_fullstack_cancel_in_a_vacuum_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_simple_ssl_with_oauth2_fullstack_census_simple_request_test"
+    "name": "chttp2_simple_ssl_with_oauth2_fullstack_census_simple_request_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_simple_ssl_with_oauth2_fullstack_disappearing_server_test"
+    "name": "chttp2_simple_ssl_with_oauth2_fullstack_disappearing_server_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_simple_ssl_with_oauth2_fullstack_early_server_shutdown_finishes_inflight_calls_test"
+    "name": "chttp2_simple_ssl_with_oauth2_fullstack_early_server_shutdown_finishes_inflight_calls_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_simple_ssl_with_oauth2_fullstack_early_server_shutdown_finishes_tags_test"
+    "name": "chttp2_simple_ssl_with_oauth2_fullstack_early_server_shutdown_finishes_tags_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_simple_ssl_with_oauth2_fullstack_empty_batch_test"
+    "name": "chttp2_simple_ssl_with_oauth2_fullstack_empty_batch_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_simple_ssl_with_oauth2_fullstack_graceful_server_shutdown_test"
+    "name": "chttp2_simple_ssl_with_oauth2_fullstack_graceful_server_shutdown_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_simple_ssl_with_oauth2_fullstack_invoke_large_request_test"
+    "name": "chttp2_simple_ssl_with_oauth2_fullstack_invoke_large_request_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_simple_ssl_with_oauth2_fullstack_max_concurrent_streams_test"
+    "name": "chttp2_simple_ssl_with_oauth2_fullstack_max_concurrent_streams_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_simple_ssl_with_oauth2_fullstack_no_op_test"
+    "name": "chttp2_simple_ssl_with_oauth2_fullstack_no_op_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_simple_ssl_with_oauth2_fullstack_ping_pong_streaming_test"
+    "name": "chttp2_simple_ssl_with_oauth2_fullstack_ping_pong_streaming_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_simple_ssl_with_oauth2_fullstack_request_response_with_binary_metadata_and_payload_test"
+    "name": "chttp2_simple_ssl_with_oauth2_fullstack_request_response_with_binary_metadata_and_payload_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_simple_ssl_with_oauth2_fullstack_request_response_with_metadata_and_payload_test"
+    "name": "chttp2_simple_ssl_with_oauth2_fullstack_request_response_with_metadata_and_payload_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_simple_ssl_with_oauth2_fullstack_request_response_with_payload_test"
+    "name": "chttp2_simple_ssl_with_oauth2_fullstack_request_response_with_payload_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_simple_ssl_with_oauth2_fullstack_request_with_large_metadata_test"
+    "name": "chttp2_simple_ssl_with_oauth2_fullstack_request_with_large_metadata_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_simple_ssl_with_oauth2_fullstack_request_with_payload_test"
+    "name": "chttp2_simple_ssl_with_oauth2_fullstack_request_with_payload_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_simple_ssl_with_oauth2_fullstack_simple_delayed_request_test"
+    "name": "chttp2_simple_ssl_with_oauth2_fullstack_simple_delayed_request_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_simple_ssl_with_oauth2_fullstack_simple_request_test"
+    "name": "chttp2_simple_ssl_with_oauth2_fullstack_simple_request_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_simple_ssl_with_oauth2_fullstack_thread_stress_test"
+    "name": "chttp2_simple_ssl_with_oauth2_fullstack_thread_stress_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_simple_ssl_with_oauth2_fullstack_writes_done_hangs_with_pending_read_test"
+    "name": "chttp2_simple_ssl_with_oauth2_fullstack_writes_done_hangs_with_pending_read_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_simple_ssl_with_oauth2_fullstack_cancel_after_accept_legacy_test"
+    "name": "chttp2_simple_ssl_with_oauth2_fullstack_cancel_after_accept_legacy_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_simple_ssl_with_oauth2_fullstack_cancel_after_accept_and_writes_closed_legacy_test"
+    "name": "chttp2_simple_ssl_with_oauth2_fullstack_cancel_after_accept_and_writes_closed_legacy_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_simple_ssl_with_oauth2_fullstack_cancel_after_invoke_legacy_test"
+    "name": "chttp2_simple_ssl_with_oauth2_fullstack_cancel_after_invoke_legacy_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_simple_ssl_with_oauth2_fullstack_cancel_before_invoke_legacy_test"
+    "name": "chttp2_simple_ssl_with_oauth2_fullstack_cancel_before_invoke_legacy_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_simple_ssl_with_oauth2_fullstack_cancel_in_a_vacuum_legacy_test"
+    "name": "chttp2_simple_ssl_with_oauth2_fullstack_cancel_in_a_vacuum_legacy_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_simple_ssl_with_oauth2_fullstack_census_simple_request_legacy_test"
+    "name": "chttp2_simple_ssl_with_oauth2_fullstack_census_simple_request_legacy_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_simple_ssl_with_oauth2_fullstack_disappearing_server_legacy_test"
+    "name": "chttp2_simple_ssl_with_oauth2_fullstack_disappearing_server_legacy_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_simple_ssl_with_oauth2_fullstack_early_server_shutdown_finishes_inflight_calls_legacy_test"
+    "name": "chttp2_simple_ssl_with_oauth2_fullstack_early_server_shutdown_finishes_inflight_calls_legacy_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_simple_ssl_with_oauth2_fullstack_early_server_shutdown_finishes_tags_legacy_test"
+    "name": "chttp2_simple_ssl_with_oauth2_fullstack_early_server_shutdown_finishes_tags_legacy_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_simple_ssl_with_oauth2_fullstack_graceful_server_shutdown_legacy_test"
+    "name": "chttp2_simple_ssl_with_oauth2_fullstack_graceful_server_shutdown_legacy_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_simple_ssl_with_oauth2_fullstack_invoke_large_request_legacy_test"
+    "name": "chttp2_simple_ssl_with_oauth2_fullstack_invoke_large_request_legacy_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_simple_ssl_with_oauth2_fullstack_max_concurrent_streams_legacy_test"
+    "name": "chttp2_simple_ssl_with_oauth2_fullstack_max_concurrent_streams_legacy_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_simple_ssl_with_oauth2_fullstack_no_op_legacy_test"
+    "name": "chttp2_simple_ssl_with_oauth2_fullstack_no_op_legacy_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_simple_ssl_with_oauth2_fullstack_ping_pong_streaming_legacy_test"
+    "name": "chttp2_simple_ssl_with_oauth2_fullstack_ping_pong_streaming_legacy_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_simple_ssl_with_oauth2_fullstack_request_response_with_binary_metadata_and_payload_legacy_test"
+    "name": "chttp2_simple_ssl_with_oauth2_fullstack_request_response_with_binary_metadata_and_payload_legacy_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_simple_ssl_with_oauth2_fullstack_request_response_with_metadata_and_payload_legacy_test"
+    "name": "chttp2_simple_ssl_with_oauth2_fullstack_request_response_with_metadata_and_payload_legacy_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_simple_ssl_with_oauth2_fullstack_request_response_with_payload_legacy_test"
+    "name": "chttp2_simple_ssl_with_oauth2_fullstack_request_response_with_payload_legacy_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_simple_ssl_with_oauth2_fullstack_request_response_with_trailing_metadata_and_payload_legacy_test"
+    "name": "chttp2_simple_ssl_with_oauth2_fullstack_request_response_with_trailing_metadata_and_payload_legacy_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_simple_ssl_with_oauth2_fullstack_request_with_large_metadata_legacy_test"
+    "name": "chttp2_simple_ssl_with_oauth2_fullstack_request_with_large_metadata_legacy_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_simple_ssl_with_oauth2_fullstack_request_with_payload_legacy_test"
+    "name": "chttp2_simple_ssl_with_oauth2_fullstack_request_with_payload_legacy_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_simple_ssl_with_oauth2_fullstack_simple_delayed_request_legacy_test"
+    "name": "chttp2_simple_ssl_with_oauth2_fullstack_simple_delayed_request_legacy_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_simple_ssl_with_oauth2_fullstack_simple_request_legacy_test"
+    "name": "chttp2_simple_ssl_with_oauth2_fullstack_simple_request_legacy_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_simple_ssl_with_oauth2_fullstack_thread_stress_legacy_test"
+    "name": "chttp2_simple_ssl_with_oauth2_fullstack_thread_stress_legacy_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_simple_ssl_with_oauth2_fullstack_writes_done_hangs_with_pending_read_legacy_test"
+    "name": "chttp2_simple_ssl_with_oauth2_fullstack_writes_done_hangs_with_pending_read_legacy_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_socket_pair_bad_hostname_test"
+    "name": "chttp2_socket_pair_bad_hostname_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_socket_pair_cancel_after_accept_test"
+    "name": "chttp2_socket_pair_cancel_after_accept_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_socket_pair_cancel_after_accept_and_writes_closed_test"
+    "name": "chttp2_socket_pair_cancel_after_accept_and_writes_closed_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_socket_pair_cancel_after_invoke_test"
+    "name": "chttp2_socket_pair_cancel_after_invoke_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_socket_pair_cancel_before_invoke_test"
+    "name": "chttp2_socket_pair_cancel_before_invoke_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_socket_pair_cancel_in_a_vacuum_test"
+    "name": "chttp2_socket_pair_cancel_in_a_vacuum_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_socket_pair_census_simple_request_test"
+    "name": "chttp2_socket_pair_census_simple_request_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_socket_pair_disappearing_server_test"
+    "name": "chttp2_socket_pair_disappearing_server_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_socket_pair_early_server_shutdown_finishes_inflight_calls_test"
+    "name": "chttp2_socket_pair_early_server_shutdown_finishes_inflight_calls_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_socket_pair_early_server_shutdown_finishes_tags_test"
+    "name": "chttp2_socket_pair_early_server_shutdown_finishes_tags_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_socket_pair_empty_batch_test"
+    "name": "chttp2_socket_pair_empty_batch_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_socket_pair_graceful_server_shutdown_test"
+    "name": "chttp2_socket_pair_graceful_server_shutdown_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_socket_pair_invoke_large_request_test"
+    "name": "chttp2_socket_pair_invoke_large_request_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_socket_pair_max_concurrent_streams_test"
+    "name": "chttp2_socket_pair_max_concurrent_streams_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_socket_pair_no_op_test"
+    "name": "chttp2_socket_pair_no_op_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_socket_pair_ping_pong_streaming_test"
+    "name": "chttp2_socket_pair_ping_pong_streaming_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_socket_pair_request_response_with_binary_metadata_and_payload_test"
+    "name": "chttp2_socket_pair_request_response_with_binary_metadata_and_payload_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_socket_pair_request_response_with_metadata_and_payload_test"
+    "name": "chttp2_socket_pair_request_response_with_metadata_and_payload_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_socket_pair_request_response_with_payload_test"
+    "name": "chttp2_socket_pair_request_response_with_payload_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_socket_pair_request_with_large_metadata_test"
+    "name": "chttp2_socket_pair_request_with_large_metadata_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_socket_pair_request_with_payload_test"
+    "name": "chttp2_socket_pair_request_with_payload_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_socket_pair_simple_delayed_request_test"
+    "name": "chttp2_socket_pair_simple_delayed_request_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_socket_pair_simple_request_test"
+    "name": "chttp2_socket_pair_simple_request_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_socket_pair_thread_stress_test"
+    "name": "chttp2_socket_pair_thread_stress_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_socket_pair_writes_done_hangs_with_pending_read_test"
+    "name": "chttp2_socket_pair_writes_done_hangs_with_pending_read_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_socket_pair_cancel_after_accept_legacy_test"
+    "name": "chttp2_socket_pair_cancel_after_accept_legacy_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_socket_pair_cancel_after_accept_and_writes_closed_legacy_test"
+    "name": "chttp2_socket_pair_cancel_after_accept_and_writes_closed_legacy_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_socket_pair_cancel_after_invoke_legacy_test"
+    "name": "chttp2_socket_pair_cancel_after_invoke_legacy_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_socket_pair_cancel_before_invoke_legacy_test"
+    "name": "chttp2_socket_pair_cancel_before_invoke_legacy_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_socket_pair_cancel_in_a_vacuum_legacy_test"
+    "name": "chttp2_socket_pair_cancel_in_a_vacuum_legacy_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_socket_pair_census_simple_request_legacy_test"
+    "name": "chttp2_socket_pair_census_simple_request_legacy_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_socket_pair_disappearing_server_legacy_test"
+    "name": "chttp2_socket_pair_disappearing_server_legacy_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_socket_pair_early_server_shutdown_finishes_inflight_calls_legacy_test"
+    "name": "chttp2_socket_pair_early_server_shutdown_finishes_inflight_calls_legacy_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_socket_pair_early_server_shutdown_finishes_tags_legacy_test"
+    "name": "chttp2_socket_pair_early_server_shutdown_finishes_tags_legacy_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_socket_pair_graceful_server_shutdown_legacy_test"
+    "name": "chttp2_socket_pair_graceful_server_shutdown_legacy_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_socket_pair_invoke_large_request_legacy_test"
+    "name": "chttp2_socket_pair_invoke_large_request_legacy_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_socket_pair_max_concurrent_streams_legacy_test"
+    "name": "chttp2_socket_pair_max_concurrent_streams_legacy_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_socket_pair_no_op_legacy_test"
+    "name": "chttp2_socket_pair_no_op_legacy_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_socket_pair_ping_pong_streaming_legacy_test"
+    "name": "chttp2_socket_pair_ping_pong_streaming_legacy_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_socket_pair_request_response_with_binary_metadata_and_payload_legacy_test"
+    "name": "chttp2_socket_pair_request_response_with_binary_metadata_and_payload_legacy_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_socket_pair_request_response_with_metadata_and_payload_legacy_test"
+    "name": "chttp2_socket_pair_request_response_with_metadata_and_payload_legacy_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_socket_pair_request_response_with_payload_legacy_test"
+    "name": "chttp2_socket_pair_request_response_with_payload_legacy_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_socket_pair_request_response_with_trailing_metadata_and_payload_legacy_test"
+    "name": "chttp2_socket_pair_request_response_with_trailing_metadata_and_payload_legacy_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_socket_pair_request_with_large_metadata_legacy_test"
+    "name": "chttp2_socket_pair_request_with_large_metadata_legacy_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_socket_pair_request_with_payload_legacy_test"
+    "name": "chttp2_socket_pair_request_with_payload_legacy_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_socket_pair_simple_delayed_request_legacy_test"
+    "name": "chttp2_socket_pair_simple_delayed_request_legacy_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_socket_pair_simple_request_legacy_test"
+    "name": "chttp2_socket_pair_simple_request_legacy_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_socket_pair_thread_stress_legacy_test"
+    "name": "chttp2_socket_pair_thread_stress_legacy_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_socket_pair_writes_done_hangs_with_pending_read_legacy_test"
+    "name": "chttp2_socket_pair_writes_done_hangs_with_pending_read_legacy_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_socket_pair_one_byte_at_a_time_bad_hostname_test"
+    "name": "chttp2_socket_pair_one_byte_at_a_time_bad_hostname_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_socket_pair_one_byte_at_a_time_cancel_after_accept_test"
+    "name": "chttp2_socket_pair_one_byte_at_a_time_cancel_after_accept_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_socket_pair_one_byte_at_a_time_cancel_after_accept_and_writes_closed_test"
+    "name": "chttp2_socket_pair_one_byte_at_a_time_cancel_after_accept_and_writes_closed_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_socket_pair_one_byte_at_a_time_cancel_after_invoke_test"
+    "name": "chttp2_socket_pair_one_byte_at_a_time_cancel_after_invoke_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_socket_pair_one_byte_at_a_time_cancel_before_invoke_test"
+    "name": "chttp2_socket_pair_one_byte_at_a_time_cancel_before_invoke_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_socket_pair_one_byte_at_a_time_cancel_in_a_vacuum_test"
+    "name": "chttp2_socket_pair_one_byte_at_a_time_cancel_in_a_vacuum_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_socket_pair_one_byte_at_a_time_census_simple_request_test"
+    "name": "chttp2_socket_pair_one_byte_at_a_time_census_simple_request_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_socket_pair_one_byte_at_a_time_disappearing_server_test"
+    "name": "chttp2_socket_pair_one_byte_at_a_time_disappearing_server_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_socket_pair_one_byte_at_a_time_early_server_shutdown_finishes_inflight_calls_test"
+    "name": "chttp2_socket_pair_one_byte_at_a_time_early_server_shutdown_finishes_inflight_calls_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_socket_pair_one_byte_at_a_time_early_server_shutdown_finishes_tags_test"
+    "name": "chttp2_socket_pair_one_byte_at_a_time_early_server_shutdown_finishes_tags_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_socket_pair_one_byte_at_a_time_empty_batch_test"
+    "name": "chttp2_socket_pair_one_byte_at_a_time_empty_batch_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_socket_pair_one_byte_at_a_time_graceful_server_shutdown_test"
+    "name": "chttp2_socket_pair_one_byte_at_a_time_graceful_server_shutdown_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_socket_pair_one_byte_at_a_time_invoke_large_request_test"
+    "name": "chttp2_socket_pair_one_byte_at_a_time_invoke_large_request_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_socket_pair_one_byte_at_a_time_max_concurrent_streams_test"
+    "name": "chttp2_socket_pair_one_byte_at_a_time_max_concurrent_streams_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_socket_pair_one_byte_at_a_time_no_op_test"
+    "name": "chttp2_socket_pair_one_byte_at_a_time_no_op_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_socket_pair_one_byte_at_a_time_ping_pong_streaming_test"
+    "name": "chttp2_socket_pair_one_byte_at_a_time_ping_pong_streaming_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_socket_pair_one_byte_at_a_time_request_response_with_binary_metadata_and_payload_test"
+    "name": "chttp2_socket_pair_one_byte_at_a_time_request_response_with_binary_metadata_and_payload_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_socket_pair_one_byte_at_a_time_request_response_with_metadata_and_payload_test"
+    "name": "chttp2_socket_pair_one_byte_at_a_time_request_response_with_metadata_and_payload_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_socket_pair_one_byte_at_a_time_request_response_with_payload_test"
+    "name": "chttp2_socket_pair_one_byte_at_a_time_request_response_with_payload_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_socket_pair_one_byte_at_a_time_request_with_large_metadata_test"
+    "name": "chttp2_socket_pair_one_byte_at_a_time_request_with_large_metadata_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_socket_pair_one_byte_at_a_time_request_with_payload_test"
+    "name": "chttp2_socket_pair_one_byte_at_a_time_request_with_payload_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_socket_pair_one_byte_at_a_time_simple_delayed_request_test"
+    "name": "chttp2_socket_pair_one_byte_at_a_time_simple_delayed_request_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_socket_pair_one_byte_at_a_time_simple_request_test"
+    "name": "chttp2_socket_pair_one_byte_at_a_time_simple_request_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_socket_pair_one_byte_at_a_time_thread_stress_test"
+    "name": "chttp2_socket_pair_one_byte_at_a_time_thread_stress_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_socket_pair_one_byte_at_a_time_writes_done_hangs_with_pending_read_test"
+    "name": "chttp2_socket_pair_one_byte_at_a_time_writes_done_hangs_with_pending_read_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_socket_pair_one_byte_at_a_time_cancel_after_accept_legacy_test"
+    "name": "chttp2_socket_pair_one_byte_at_a_time_cancel_after_accept_legacy_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_socket_pair_one_byte_at_a_time_cancel_after_accept_and_writes_closed_legacy_test"
+    "name": "chttp2_socket_pair_one_byte_at_a_time_cancel_after_accept_and_writes_closed_legacy_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_socket_pair_one_byte_at_a_time_cancel_after_invoke_legacy_test"
+    "name": "chttp2_socket_pair_one_byte_at_a_time_cancel_after_invoke_legacy_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_socket_pair_one_byte_at_a_time_cancel_before_invoke_legacy_test"
+    "name": "chttp2_socket_pair_one_byte_at_a_time_cancel_before_invoke_legacy_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_socket_pair_one_byte_at_a_time_cancel_in_a_vacuum_legacy_test"
+    "name": "chttp2_socket_pair_one_byte_at_a_time_cancel_in_a_vacuum_legacy_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_socket_pair_one_byte_at_a_time_census_simple_request_legacy_test"
+    "name": "chttp2_socket_pair_one_byte_at_a_time_census_simple_request_legacy_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_socket_pair_one_byte_at_a_time_disappearing_server_legacy_test"
+    "name": "chttp2_socket_pair_one_byte_at_a_time_disappearing_server_legacy_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_socket_pair_one_byte_at_a_time_early_server_shutdown_finishes_inflight_calls_legacy_test"
+    "name": "chttp2_socket_pair_one_byte_at_a_time_early_server_shutdown_finishes_inflight_calls_legacy_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_socket_pair_one_byte_at_a_time_early_server_shutdown_finishes_tags_legacy_test"
+    "name": "chttp2_socket_pair_one_byte_at_a_time_early_server_shutdown_finishes_tags_legacy_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_socket_pair_one_byte_at_a_time_graceful_server_shutdown_legacy_test"
+    "name": "chttp2_socket_pair_one_byte_at_a_time_graceful_server_shutdown_legacy_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_socket_pair_one_byte_at_a_time_invoke_large_request_legacy_test"
+    "name": "chttp2_socket_pair_one_byte_at_a_time_invoke_large_request_legacy_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_socket_pair_one_byte_at_a_time_max_concurrent_streams_legacy_test"
+    "name": "chttp2_socket_pair_one_byte_at_a_time_max_concurrent_streams_legacy_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_socket_pair_one_byte_at_a_time_no_op_legacy_test"
+    "name": "chttp2_socket_pair_one_byte_at_a_time_no_op_legacy_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_socket_pair_one_byte_at_a_time_ping_pong_streaming_legacy_test"
+    "name": "chttp2_socket_pair_one_byte_at_a_time_ping_pong_streaming_legacy_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_socket_pair_one_byte_at_a_time_request_response_with_binary_metadata_and_payload_legacy_test"
+    "name": "chttp2_socket_pair_one_byte_at_a_time_request_response_with_binary_metadata_and_payload_legacy_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_socket_pair_one_byte_at_a_time_request_response_with_metadata_and_payload_legacy_test"
+    "name": "chttp2_socket_pair_one_byte_at_a_time_request_response_with_metadata_and_payload_legacy_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_socket_pair_one_byte_at_a_time_request_response_with_payload_legacy_test"
+    "name": "chttp2_socket_pair_one_byte_at_a_time_request_response_with_payload_legacy_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_socket_pair_one_byte_at_a_time_request_response_with_trailing_metadata_and_payload_legacy_test"
+    "name": "chttp2_socket_pair_one_byte_at_a_time_request_response_with_trailing_metadata_and_payload_legacy_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_socket_pair_one_byte_at_a_time_request_with_large_metadata_legacy_test"
+    "name": "chttp2_socket_pair_one_byte_at_a_time_request_with_large_metadata_legacy_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_socket_pair_one_byte_at_a_time_request_with_payload_legacy_test"
+    "name": "chttp2_socket_pair_one_byte_at_a_time_request_with_payload_legacy_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_socket_pair_one_byte_at_a_time_simple_delayed_request_legacy_test"
+    "name": "chttp2_socket_pair_one_byte_at_a_time_simple_delayed_request_legacy_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_socket_pair_one_byte_at_a_time_simple_request_legacy_test"
+    "name": "chttp2_socket_pair_one_byte_at_a_time_simple_request_legacy_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_socket_pair_one_byte_at_a_time_thread_stress_legacy_test"
+    "name": "chttp2_socket_pair_one_byte_at_a_time_thread_stress_legacy_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }, 
   {
     "flaky": false, 
     "language": "c", 
-    "name": "chttp2_socket_pair_one_byte_at_a_time_writes_done_hangs_with_pending_read_legacy_test"
+    "name": "chttp2_socket_pair_one_byte_at_a_time_writes_done_hangs_with_pending_read_legacy_test", 
+    "platforms": [
+      "windows", 
+      "posix"
+    ]
   }
 ]
 
diff --git a/vsprojects/vs2010/Grpc.mak b/vsprojects/vs2010/Grpc.mak
index 203c78728789dd84f003373710ca9ae841f93caf..727aa37781697dfb28b57c838d84ee6038993094 100644
--- a/vsprojects/vs2010/Grpc.mak
+++ b/vsprojects/vs2010/Grpc.mak
@@ -53,13 +53,13 @@ grpc_test_util:
 $(OUT_DIR):
 	mkdir $(OUT_DIR)
 
-buildtests: alarm_heap_test.exe alarm_list_test.exe alarm_test.exe alpn_test.exe bin_encoder_test.exe census_hash_table_test.exe census_statistics_multiple_writers_circular_buffer_test.exe census_statistics_multiple_writers_test.exe census_statistics_performance_test.exe census_statistics_quick_test.exe census_statistics_small_log_test.exe census_stats_store_test.exe census_stub_test.exe census_trace_store_test.exe census_window_stats_test.exe chttp2_status_conversion_test.exe chttp2_stream_encoder_test.exe chttp2_stream_map_test.exe chttp2_transport_end2end_test.exe dualstack_socket_test.exe echo_test.exe fd_posix_test.exe fling_stream_test.exe fling_test.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_useful_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_stream_op_test.exe hpack_parser_test.exe hpack_table_test.exe httpcli_format_request_test.exe httpcli_parser_test.exe httpcli_test.exe json_rewrite_test.exe json_test.exe lame_client_test.exe message_compress_test.exe metadata_buffer_test.exe multi_init_test.exe murmur_hash_test.exe no_server_test.exe poll_kick_posix_test.exe resolve_address_test.exe secure_endpoint_test.exe sockaddr_utils_test.exe tcp_client_posix_test.exe tcp_posix_test.exe tcp_server_posix_test.exe time_averaged_stats_test.exe time_test.exe timeout_encoding_test.exe transport_metadata_test.exe transport_security_test.exe 
+buildtests: alarm_heap_test.exe alarm_list_test.exe alarm_test.exe alpn_test.exe bin_encoder_test.exe census_hash_table_test.exe census_statistics_multiple_writers_circular_buffer_test.exe census_statistics_multiple_writers_test.exe census_statistics_performance_test.exe census_statistics_quick_test.exe census_statistics_small_log_test.exe census_stats_store_test.exe census_stub_test.exe census_trace_store_test.exe census_window_stats_test.exe chttp2_status_conversion_test.exe chttp2_stream_encoder_test.exe chttp2_stream_map_test.exe chttp2_transport_end2end_test.exe dualstack_socket_test.exe echo_test.exe fd_posix_test.exe fling_stream_test.exe fling_test.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_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_stream_op_test.exe hpack_parser_test.exe hpack_table_test.exe httpcli_format_request_test.exe httpcli_parser_test.exe httpcli_test.exe json_rewrite_test.exe json_test.exe lame_client_test.exe message_compress_test.exe metadata_buffer_test.exe multi_init_test.exe murmur_hash_test.exe no_server_test.exe poll_kick_posix_test.exe resolve_address_test.exe secure_endpoint_test.exe sockaddr_utils_test.exe tcp_client_posix_test.exe tcp_posix_test.exe tcp_server_posix_test.exe time_averaged_stats_test.exe time_test.exe timeout_encoding_test.exe transport_metadata_test.exe transport_security_test.exe 
 	echo All tests built.
 
-test: alarm_heap_test alarm_list_test alarm_test alpn_test bin_encoder_test census_hash_table_test census_statistics_multiple_writers_circular_buffer_test census_statistics_multiple_writers_test census_statistics_performance_test census_statistics_quick_test census_statistics_small_log_test census_stats_store_test census_stub_test census_trace_store_test census_window_stats_test chttp2_status_conversion_test chttp2_stream_encoder_test chttp2_stream_map_test chttp2_transport_end2end_test dualstack_socket_test echo_test fd_posix_test fling_stream_test fling_test gpr_cancellable_test gpr_cmdline_test gpr_env_test gpr_file_test gpr_histogram_test gpr_host_port_test gpr_log_test gpr_slice_buffer_test gpr_slice_test gpr_string_test gpr_sync_test gpr_thd_test gpr_time_test gpr_useful_test grpc_base64_test grpc_byte_buffer_reader_test grpc_channel_stack_test grpc_completion_queue_test grpc_credentials_test grpc_json_token_test grpc_stream_op_test hpack_parser_test hpack_table_test httpcli_format_request_test httpcli_parser_test httpcli_test json_rewrite_test json_test lame_client_test message_compress_test metadata_buffer_test multi_init_test murmur_hash_test no_server_test poll_kick_posix_test resolve_address_test secure_endpoint_test sockaddr_utils_test tcp_client_posix_test tcp_posix_test tcp_server_posix_test time_averaged_stats_test time_test timeout_encoding_test transport_metadata_test transport_security_test 
+test: alarm_heap_test alarm_list_test alarm_test alpn_test bin_encoder_test census_hash_table_test census_statistics_multiple_writers_circular_buffer_test census_statistics_multiple_writers_test census_statistics_performance_test census_statistics_quick_test census_statistics_small_log_test census_stats_store_test census_stub_test census_trace_store_test census_window_stats_test chttp2_status_conversion_test chttp2_stream_encoder_test chttp2_stream_map_test chttp2_transport_end2end_test dualstack_socket_test echo_test fd_posix_test fling_stream_test fling_test gpr_cancellable_test gpr_cmdline_test gpr_env_test gpr_file_test gpr_histogram_test gpr_host_port_test gpr_log_test gpr_slice_buffer_test gpr_slice_test gpr_string_test gpr_sync_test gpr_thd_test gpr_time_test gpr_tls_test gpr_useful_test grpc_base64_test grpc_byte_buffer_reader_test grpc_channel_stack_test grpc_completion_queue_test grpc_credentials_test grpc_json_token_test grpc_stream_op_test hpack_parser_test hpack_table_test httpcli_format_request_test httpcli_parser_test httpcli_test json_rewrite_test json_test lame_client_test message_compress_test metadata_buffer_test multi_init_test murmur_hash_test no_server_test poll_kick_posix_test resolve_address_test secure_endpoint_test sockaddr_utils_test tcp_client_posix_test tcp_posix_test tcp_server_posix_test time_averaged_stats_test time_test timeout_encoding_test transport_metadata_test transport_security_test 
 	echo All tests ran.
 
-test_gpr: gpr_cancellable_test gpr_cmdline_test gpr_env_test gpr_file_test gpr_histogram_test gpr_host_port_test gpr_log_test gpr_slice_buffer_test gpr_slice_test gpr_string_test gpr_sync_test gpr_thd_test gpr_time_test gpr_useful_test 
+test_gpr: gpr_cancellable_test gpr_cmdline_test gpr_env_test gpr_file_test gpr_histogram_test gpr_host_port_test gpr_log_test gpr_slice_buffer_test gpr_slice_test gpr_string_test gpr_sync_test gpr_thd_test gpr_time_test gpr_tls_test gpr_useful_test 
 	echo All tests ran.
 
 alarm_heap_test.exe: grpc_test_util
@@ -398,6 +398,14 @@ gpr_time_test: gpr_time_test.exe
 	echo Running gpr_time_test
 	$(OUT_DIR)\gpr_time_test.exe
 
+gpr_tls_test.exe: grpc_test_util
+	echo Building gpr_tls_test
+	$(CC) $(CFLAGS) /Fo:$(OUT_DIR)\ ..\..\test\core\support\tls_test.c 
+	$(LINK) $(LFLAGS) /OUT:"$(OUT_DIR)\gpr_tls_test.exe" Debug\gpr_test_util.lib Debug\gpr.lib $(LIBS) $(OUT_DIR)\tls_test.obj 
+gpr_tls_test: gpr_tls_test.exe
+	echo Running gpr_tls_test
+	$(OUT_DIR)\gpr_tls_test.exe
+
 gpr_useful_test.exe: grpc_test_util
 	echo Building gpr_useful_test
 	$(CC) $(CFLAGS) /Fo:$(OUT_DIR)\ ..\..\test\core\support\useful_test.c 
diff --git a/vsprojects/vs2010/gpr.vcxproj b/vsprojects/vs2010/gpr.vcxproj
index d23124c86c0d46acf0d01fb178c666fcc30e24ac..62ab6f3bd0932f7aec522ea919c84f685384a3d0 100644
--- a/vsprojects/vs2010/gpr.vcxproj
+++ b/vsprojects/vs2010/gpr.vcxproj
@@ -97,6 +97,10 @@
     <ClInclude Include="..\..\include\grpc\support\sync_win32.h" />
     <ClInclude Include="..\..\include\grpc\support\thd.h" />
     <ClInclude Include="..\..\include\grpc\support\time.h" />
+    <ClInclude Include="..\..\include\grpc\support\tls.h" />
+    <ClInclude Include="..\..\include\grpc\support\tls_gcc.h" />
+    <ClInclude Include="..\..\include\grpc\support\tls_msvc.h" />
+    <ClInclude Include="..\..\include\grpc\support\tls_pthread.h" />
     <ClInclude Include="..\..\include\grpc\support\useful.h" />
   </ItemGroup>
   <ItemGroup>
diff --git a/vsprojects/vs2010/gpr.vcxproj.filters b/vsprojects/vs2010/gpr.vcxproj.filters
index 1f8794441ba5138f68017d9db3f64b7e804f4ae0..13fdb3fef84549df8a9da8b0b01db03702f757d2 100644
--- a/vsprojects/vs2010/gpr.vcxproj.filters
+++ b/vsprojects/vs2010/gpr.vcxproj.filters
@@ -171,6 +171,18 @@
     <ClInclude Include="..\..\include\grpc\support\time.h">
       <Filter>include\grpc\support</Filter>
     </ClInclude>
+    <ClInclude Include="..\..\include\grpc\support\tls.h">
+      <Filter>include\grpc\support</Filter>
+    </ClInclude>
+    <ClInclude Include="..\..\include\grpc\support\tls_gcc.h">
+      <Filter>include\grpc\support</Filter>
+    </ClInclude>
+    <ClInclude Include="..\..\include\grpc\support\tls_msvc.h">
+      <Filter>include\grpc\support</Filter>
+    </ClInclude>
+    <ClInclude Include="..\..\include\grpc\support\tls_pthread.h">
+      <Filter>include\grpc\support</Filter>
+    </ClInclude>
     <ClInclude Include="..\..\include\grpc\support\useful.h">
       <Filter>include\grpc\support</Filter>
     </ClInclude>
diff --git a/vsprojects/vs2010/grpc++.vcxproj b/vsprojects/vs2010/grpc++.vcxproj
index 0ee433163c88a9ab43920ede0b828cff1009d987..003355eabf8bd76a307cc165e939d6d0cedf6805 100644
--- a/vsprojects/vs2010/grpc++.vcxproj
+++ b/vsprojects/vs2010/grpc++.vcxproj
@@ -93,6 +93,12 @@
     <ClInclude Include="..\..\include\grpc++\impl\rpc_method.h" />
     <ClInclude Include="..\..\include\grpc++\impl\rpc_service_method.h" />
     <ClInclude Include="..\..\include\grpc++\impl\service_type.h" />
+    <ClInclude Include="..\..\include\grpc++\impl\sync.h" />
+    <ClInclude Include="..\..\include\grpc++\impl\sync_cxx11.h" />
+    <ClInclude Include="..\..\include\grpc++\impl\sync_no_cxx11.h" />
+    <ClInclude Include="..\..\include\grpc++\impl\thd.h" />
+    <ClInclude Include="..\..\include\grpc++\impl\thd_cxx11.h" />
+    <ClInclude Include="..\..\include\grpc++\impl\thd_no_cxx11.h" />
     <ClInclude Include="..\..\include\grpc++\server.h" />
     <ClInclude Include="..\..\include\grpc++\server_builder.h" />
     <ClInclude Include="..\..\include\grpc++\server_context.h" />
@@ -104,6 +110,8 @@
     <ClInclude Include="..\..\include\grpc++\thread_pool_interface.h" />
   </ItemGroup>
   <ItemGroup>
+    <ClInclude Include="..\..\src\cpp\client\secure_credentials.h" />
+    <ClInclude Include="..\..\src\cpp\server\secure_server_credentials.h" />
     <ClInclude Include="..\..\src\cpp\client\channel.h" />
     <ClInclude Include="..\..\src\cpp\proto\proto_utils.h" />
     <ClInclude Include="..\..\src\cpp\server\thread_pool.h" />
diff --git a/vsprojects/vs2010/grpc++.vcxproj.filters b/vsprojects/vs2010/grpc++.vcxproj.filters
index ed93daee0441d19170e0c6cfb07c202089f107ee..6466a0fa26e523fe65de1185fb678edabc8e8432 100644
--- a/vsprojects/vs2010/grpc++.vcxproj.filters
+++ b/vsprojects/vs2010/grpc++.vcxproj.filters
@@ -132,6 +132,24 @@
     <ClInclude Include="..\..\include\grpc++\impl\service_type.h">
       <Filter>include\grpc++\impl</Filter>
     </ClInclude>
+    <ClInclude Include="..\..\include\grpc++\impl\sync.h">
+      <Filter>include\grpc++\impl</Filter>
+    </ClInclude>
+    <ClInclude Include="..\..\include\grpc++\impl\sync_cxx11.h">
+      <Filter>include\grpc++\impl</Filter>
+    </ClInclude>
+    <ClInclude Include="..\..\include\grpc++\impl\sync_no_cxx11.h">
+      <Filter>include\grpc++\impl</Filter>
+    </ClInclude>
+    <ClInclude Include="..\..\include\grpc++\impl\thd.h">
+      <Filter>include\grpc++\impl</Filter>
+    </ClInclude>
+    <ClInclude Include="..\..\include\grpc++\impl\thd_cxx11.h">
+      <Filter>include\grpc++\impl</Filter>
+    </ClInclude>
+    <ClInclude Include="..\..\include\grpc++\impl\thd_no_cxx11.h">
+      <Filter>include\grpc++\impl</Filter>
+    </ClInclude>
     <ClInclude Include="..\..\include\grpc++\server.h">
       <Filter>include\grpc++</Filter>
     </ClInclude>
@@ -161,6 +179,12 @@
     </ClInclude>
   </ItemGroup>
   <ItemGroup>
+    <ClInclude Include="..\..\src\cpp\client\secure_credentials.h">
+      <Filter>src\cpp\client</Filter>
+    </ClInclude>
+    <ClInclude Include="..\..\src\cpp\server\secure_server_credentials.h">
+      <Filter>src\cpp\server</Filter>
+    </ClInclude>
     <ClInclude Include="..\..\src\cpp\client\channel.h">
       <Filter>src\cpp\client</Filter>
     </ClInclude>
diff --git a/vsprojects/vs2010/grpc.vcxproj b/vsprojects/vs2010/grpc.vcxproj
index 203ca347d3f5e6cc0e7f2cc85ed1a7e87001a847..02d1f2643e1d5a6714c9a6767b2d61f3bd52699e 100644
--- a/vsprojects/vs2010/grpc.vcxproj
+++ b/vsprojects/vs2010/grpc.vcxproj
@@ -270,6 +270,8 @@
     </ClCompile>
     <ClCompile Include="..\..\src\core\iomgr\endpoint_pair_posix.c">
     </ClCompile>
+    <ClCompile Include="..\..\src\core\iomgr\endpoint_pair_windows.c">
+    </ClCompile>
     <ClCompile Include="..\..\src\core\iomgr\fd_posix.c">
     </ClCompile>
     <ClCompile Include="..\..\src\core\iomgr\iocp_windows.c">
diff --git a/vsprojects/vs2010/grpc.vcxproj.filters b/vsprojects/vs2010/grpc.vcxproj.filters
index 20dbe8c444f65b7b702adc357d380b352d5c5459..a010639ad1333cf6b4acdf89176a65a731233cc3 100644
--- a/vsprojects/vs2010/grpc.vcxproj.filters
+++ b/vsprojects/vs2010/grpc.vcxproj.filters
@@ -124,6 +124,9 @@
     <ClCompile Include="..\..\src\core\iomgr\endpoint_pair_posix.c">
       <Filter>src\core\iomgr</Filter>
     </ClCompile>
+    <ClCompile Include="..\..\src\core\iomgr\endpoint_pair_windows.c">
+      <Filter>src\core\iomgr</Filter>
+    </ClCompile>
     <ClCompile Include="..\..\src\core\iomgr\fd_posix.c">
       <Filter>src\core\iomgr</Filter>
     </ClCompile>
diff --git a/vsprojects/vs2010/grpc_test_util.vcxproj b/vsprojects/vs2010/grpc_test_util.vcxproj
index 967543f78a88b948cc43bb8bd023fa9fd5a7701c..d3559d4dde0efbde7128481e92ff0935036e8f7f 100644
--- a/vsprojects/vs2010/grpc_test_util.vcxproj
+++ b/vsprojects/vs2010/grpc_test_util.vcxproj
@@ -96,6 +96,8 @@
     </ClCompile>
     <ClCompile Include="..\..\test\core\util\port_posix.c">
     </ClCompile>
+    <ClCompile Include="..\..\test\core\util\port_windows.c">
+    </ClCompile>
     <ClCompile Include="..\..\test\core\util\slice_splitter.c">
     </ClCompile>
   </ItemGroup>
diff --git a/vsprojects/vs2010/grpc_unsecure.vcxproj b/vsprojects/vs2010/grpc_unsecure.vcxproj
index 1558d72514d7f0082c2761808307eb39088d1666..651f38ae34296f6f2147399df2ae1c0a1e281105 100644
--- a/vsprojects/vs2010/grpc_unsecure.vcxproj
+++ b/vsprojects/vs2010/grpc_unsecure.vcxproj
@@ -214,6 +214,8 @@
     </ClCompile>
     <ClCompile Include="..\..\src\core\iomgr\endpoint_pair_posix.c">
     </ClCompile>
+    <ClCompile Include="..\..\src\core\iomgr\endpoint_pair_windows.c">
+    </ClCompile>
     <ClCompile Include="..\..\src\core\iomgr\fd_posix.c">
     </ClCompile>
     <ClCompile Include="..\..\src\core\iomgr\iocp_windows.c">
diff --git a/vsprojects/vs2010/grpc_unsecure.vcxproj.filters b/vsprojects/vs2010/grpc_unsecure.vcxproj.filters
index 4b758d61132ff7371c8c4874c31359702218fa9e..7757a44aecb92d5f5d2bfcbfecd39e809e6acb98 100644
--- a/vsprojects/vs2010/grpc_unsecure.vcxproj.filters
+++ b/vsprojects/vs2010/grpc_unsecure.vcxproj.filters
@@ -64,6 +64,9 @@
     <ClCompile Include="..\..\src\core\iomgr\endpoint_pair_posix.c">
       <Filter>src\core\iomgr</Filter>
     </ClCompile>
+    <ClCompile Include="..\..\src\core\iomgr\endpoint_pair_windows.c">
+      <Filter>src\core\iomgr</Filter>
+    </ClCompile>
     <ClCompile Include="..\..\src\core\iomgr\fd_posix.c">
       <Filter>src\core\iomgr</Filter>
     </ClCompile>
diff --git a/vsprojects/vs2013/Grpc.mak b/vsprojects/vs2013/Grpc.mak
index 203c78728789dd84f003373710ca9ae841f93caf..c2c25ced69a417d113f171d0ddf2be3c73684330 100644
--- a/vsprojects/vs2013/Grpc.mak
+++ b/vsprojects/vs2013/Grpc.mak
@@ -53,16 +53,15 @@ grpc_test_util:
 $(OUT_DIR):
 	mkdir $(OUT_DIR)
 
-buildtests: alarm_heap_test.exe alarm_list_test.exe alarm_test.exe alpn_test.exe bin_encoder_test.exe census_hash_table_test.exe census_statistics_multiple_writers_circular_buffer_test.exe census_statistics_multiple_writers_test.exe census_statistics_performance_test.exe census_statistics_quick_test.exe census_statistics_small_log_test.exe census_stats_store_test.exe census_stub_test.exe census_trace_store_test.exe census_window_stats_test.exe chttp2_status_conversion_test.exe chttp2_stream_encoder_test.exe chttp2_stream_map_test.exe chttp2_transport_end2end_test.exe dualstack_socket_test.exe echo_test.exe fd_posix_test.exe fling_stream_test.exe fling_test.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_useful_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_stream_op_test.exe hpack_parser_test.exe hpack_table_test.exe httpcli_format_request_test.exe httpcli_parser_test.exe httpcli_test.exe json_rewrite_test.exe json_test.exe lame_client_test.exe message_compress_test.exe metadata_buffer_test.exe multi_init_test.exe murmur_hash_test.exe no_server_test.exe poll_kick_posix_test.exe resolve_address_test.exe secure_endpoint_test.exe sockaddr_utils_test.exe tcp_client_posix_test.exe tcp_posix_test.exe tcp_server_posix_test.exe time_averaged_stats_test.exe time_test.exe timeout_encoding_test.exe transport_metadata_test.exe transport_security_test.exe 
-	echo All tests built.
+buildtests: buildtests_c buildtests_cxx
 
-test: alarm_heap_test alarm_list_test alarm_test alpn_test bin_encoder_test census_hash_table_test census_statistics_multiple_writers_circular_buffer_test census_statistics_multiple_writers_test census_statistics_performance_test census_statistics_quick_test census_statistics_small_log_test census_stats_store_test census_stub_test census_trace_store_test census_window_stats_test chttp2_status_conversion_test chttp2_stream_encoder_test chttp2_stream_map_test chttp2_transport_end2end_test dualstack_socket_test echo_test fd_posix_test fling_stream_test fling_test gpr_cancellable_test gpr_cmdline_test gpr_env_test gpr_file_test gpr_histogram_test gpr_host_port_test gpr_log_test gpr_slice_buffer_test gpr_slice_test gpr_string_test gpr_sync_test gpr_thd_test gpr_time_test gpr_useful_test grpc_base64_test grpc_byte_buffer_reader_test grpc_channel_stack_test grpc_completion_queue_test grpc_credentials_test grpc_json_token_test grpc_stream_op_test hpack_parser_test hpack_table_test httpcli_format_request_test httpcli_parser_test httpcli_test json_rewrite_test json_test lame_client_test message_compress_test metadata_buffer_test multi_init_test murmur_hash_test no_server_test poll_kick_posix_test resolve_address_test secure_endpoint_test sockaddr_utils_test tcp_client_posix_test tcp_posix_test tcp_server_posix_test time_averaged_stats_test time_test timeout_encoding_test transport_metadata_test transport_security_test 
-	echo All tests ran.
+buildtests_c: alarm_heap_test.exe alarm_list_test.exe alarm_test.exe alpn_test.exe bin_encoder_test.exe census_hash_table_test.exe census_statistics_multiple_writers_circular_buffer_test.exe census_statistics_multiple_writers_test.exe census_statistics_performance_test.exe census_statistics_quick_test.exe census_statistics_small_log_test.exe census_stub_test.exe census_window_stats_test.exe chttp2_status_conversion_test.exe chttp2_stream_encoder_test.exe chttp2_stream_map_test.exe chttp2_transport_end2end_test.exe echo_client.exe echo_server.exe echo_test.exe fd_posix_test.exe fling_client.exe fling_server.exe fling_stream_test.exe fling_test.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_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_stream_op_test.exe hpack_parser_test.exe hpack_table_test.exe httpcli_format_request_test.exe httpcli_parser_test.exe httpcli_test.exe json_rewrite.exe json_rewrite_test.exe json_test.exe lame_client_test.exe message_compress_test.exe metadata_buffer_test.exe multi_init_test.exe murmur_hash_test.exe no_server_test.exe poll_kick_posix_test.exe resolve_address_test.exe secure_endpoint_test.exe sockaddr_utils_test.exe tcp_client_posix_test.exe tcp_posix_test.exe tcp_server_posix_test.exe time_averaged_stats_test.exe time_test.exe timeout_encoding_test.exe transport_metadata_test.exe transport_security_test.exe 
+	echo All tests built.
 
-test_gpr: gpr_cancellable_test gpr_cmdline_test gpr_env_test gpr_file_test gpr_histogram_test gpr_host_port_test gpr_log_test gpr_slice_buffer_test gpr_slice_test gpr_string_test gpr_sync_test gpr_thd_test gpr_time_test gpr_useful_test 
-	echo All tests ran.
+buildtests_cxx: 
+	echo All tests built.
 
-alarm_heap_test.exe: grpc_test_util
+alarm_heap_test.exe: grpc_test_util $(OUT_DIR)
 	echo Building alarm_heap_test
 	$(CC) $(CFLAGS) /Fo:$(OUT_DIR)\ ..\..\test\core\iomgr\alarm_heap_test.c 
 	$(LINK) $(LFLAGS) /OUT:"$(OUT_DIR)\alarm_heap_test.exe" Debug\grpc_test_util.lib Debug\grpc.lib Debug\gpr_test_util.lib Debug\gpr.lib $(LIBS) $(OUT_DIR)\alarm_heap_test.obj 
@@ -70,7 +69,7 @@ alarm_heap_test: alarm_heap_test.exe
 	echo Running alarm_heap_test
 	$(OUT_DIR)\alarm_heap_test.exe
 
-alarm_list_test.exe: grpc_test_util
+alarm_list_test.exe: grpc_test_util $(OUT_DIR)
 	echo Building alarm_list_test
 	$(CC) $(CFLAGS) /Fo:$(OUT_DIR)\ ..\..\test\core\iomgr\alarm_list_test.c 
 	$(LINK) $(LFLAGS) /OUT:"$(OUT_DIR)\alarm_list_test.exe" Debug\grpc_test_util.lib Debug\grpc.lib Debug\gpr_test_util.lib Debug\gpr.lib $(LIBS) $(OUT_DIR)\alarm_list_test.obj 
@@ -78,7 +77,7 @@ alarm_list_test: alarm_list_test.exe
 	echo Running alarm_list_test
 	$(OUT_DIR)\alarm_list_test.exe
 
-alarm_test.exe: grpc_test_util
+alarm_test.exe: grpc_test_util $(OUT_DIR)
 	echo Building alarm_test
 	$(CC) $(CFLAGS) /Fo:$(OUT_DIR)\ ..\..\test\core\iomgr\alarm_test.c 
 	$(LINK) $(LFLAGS) /OUT:"$(OUT_DIR)\alarm_test.exe" Debug\grpc_test_util.lib Debug\grpc.lib Debug\gpr_test_util.lib Debug\gpr.lib $(LIBS) $(OUT_DIR)\alarm_test.obj 
@@ -86,7 +85,7 @@ alarm_test: alarm_test.exe
 	echo Running alarm_test
 	$(OUT_DIR)\alarm_test.exe
 
-alpn_test.exe: grpc_test_util
+alpn_test.exe: grpc_test_util $(OUT_DIR)
 	echo Building alpn_test
 	$(CC) $(CFLAGS) /Fo:$(OUT_DIR)\ ..\..\test\core\transport\chttp2\alpn_test.c 
 	$(LINK) $(LFLAGS) /OUT:"$(OUT_DIR)\alpn_test.exe" Debug\grpc_test_util.lib Debug\grpc.lib Debug\gpr_test_util.lib Debug\gpr.lib $(LIBS) $(OUT_DIR)\alpn_test.obj 
@@ -94,7 +93,7 @@ alpn_test: alpn_test.exe
 	echo Running alpn_test
 	$(OUT_DIR)\alpn_test.exe
 
-bin_encoder_test.exe: grpc_test_util
+bin_encoder_test.exe: grpc_test_util $(OUT_DIR)
 	echo Building bin_encoder_test
 	$(CC) $(CFLAGS) /Fo:$(OUT_DIR)\ ..\..\test\core\transport\chttp2\bin_encoder_test.c 
 	$(LINK) $(LFLAGS) /OUT:"$(OUT_DIR)\bin_encoder_test.exe" Debug\grpc_test_util.lib Debug\grpc.lib Debug\gpr_test_util.lib Debug\gpr.lib $(LIBS) $(OUT_DIR)\bin_encoder_test.obj 
@@ -102,7 +101,7 @@ bin_encoder_test: bin_encoder_test.exe
 	echo Running bin_encoder_test
 	$(OUT_DIR)\bin_encoder_test.exe
 
-census_hash_table_test.exe: grpc_test_util
+census_hash_table_test.exe: grpc_test_util $(OUT_DIR)
 	echo Building census_hash_table_test
 	$(CC) $(CFLAGS) /Fo:$(OUT_DIR)\ ..\..\test\core\statistics\hash_table_test.c 
 	$(LINK) $(LFLAGS) /OUT:"$(OUT_DIR)\census_hash_table_test.exe" Debug\grpc_test_util.lib Debug\grpc.lib Debug\gpr_test_util.lib Debug\gpr.lib $(LIBS) $(OUT_DIR)\hash_table_test.obj 
@@ -110,7 +109,7 @@ census_hash_table_test: census_hash_table_test.exe
 	echo Running census_hash_table_test
 	$(OUT_DIR)\census_hash_table_test.exe
 
-census_statistics_multiple_writers_circular_buffer_test.exe: grpc_test_util
+census_statistics_multiple_writers_circular_buffer_test.exe: grpc_test_util $(OUT_DIR)
 	echo Building census_statistics_multiple_writers_circular_buffer_test
 	$(CC) $(CFLAGS) /Fo:$(OUT_DIR)\ ..\..\test\core\statistics\multiple_writers_circular_buffer_test.c 
 	$(LINK) $(LFLAGS) /OUT:"$(OUT_DIR)\census_statistics_multiple_writers_circular_buffer_test.exe" Debug\grpc_test_util.lib Debug\grpc.lib Debug\gpr_test_util.lib Debug\gpr.lib $(LIBS) $(OUT_DIR)\multiple_writers_circular_buffer_test.obj 
@@ -118,7 +117,7 @@ census_statistics_multiple_writers_circular_buffer_test: census_statistics_multi
 	echo Running census_statistics_multiple_writers_circular_buffer_test
 	$(OUT_DIR)\census_statistics_multiple_writers_circular_buffer_test.exe
 
-census_statistics_multiple_writers_test.exe: grpc_test_util
+census_statistics_multiple_writers_test.exe: grpc_test_util $(OUT_DIR)
 	echo Building census_statistics_multiple_writers_test
 	$(CC) $(CFLAGS) /Fo:$(OUT_DIR)\ ..\..\test\core\statistics\multiple_writers_test.c 
 	$(LINK) $(LFLAGS) /OUT:"$(OUT_DIR)\census_statistics_multiple_writers_test.exe" Debug\grpc_test_util.lib Debug\grpc.lib Debug\gpr_test_util.lib Debug\gpr.lib $(LIBS) $(OUT_DIR)\multiple_writers_test.obj 
@@ -126,7 +125,7 @@ census_statistics_multiple_writers_test: census_statistics_multiple_writers_test
 	echo Running census_statistics_multiple_writers_test
 	$(OUT_DIR)\census_statistics_multiple_writers_test.exe
 
-census_statistics_performance_test.exe: grpc_test_util
+census_statistics_performance_test.exe: grpc_test_util $(OUT_DIR)
 	echo Building census_statistics_performance_test
 	$(CC) $(CFLAGS) /Fo:$(OUT_DIR)\ ..\..\test\core\statistics\performance_test.c 
 	$(LINK) $(LFLAGS) /OUT:"$(OUT_DIR)\census_statistics_performance_test.exe" Debug\grpc_test_util.lib Debug\grpc.lib Debug\gpr_test_util.lib Debug\gpr.lib $(LIBS) $(OUT_DIR)\performance_test.obj 
@@ -134,7 +133,7 @@ census_statistics_performance_test: census_statistics_performance_test.exe
 	echo Running census_statistics_performance_test
 	$(OUT_DIR)\census_statistics_performance_test.exe
 
-census_statistics_quick_test.exe: grpc_test_util
+census_statistics_quick_test.exe: grpc_test_util $(OUT_DIR)
 	echo Building census_statistics_quick_test
 	$(CC) $(CFLAGS) /Fo:$(OUT_DIR)\ ..\..\test\core\statistics\quick_test.c 
 	$(LINK) $(LFLAGS) /OUT:"$(OUT_DIR)\census_statistics_quick_test.exe" Debug\grpc_test_util.lib Debug\grpc.lib Debug\gpr_test_util.lib Debug\gpr.lib $(LIBS) $(OUT_DIR)\quick_test.obj 
@@ -142,7 +141,7 @@ census_statistics_quick_test: census_statistics_quick_test.exe
 	echo Running census_statistics_quick_test
 	$(OUT_DIR)\census_statistics_quick_test.exe
 
-census_statistics_small_log_test.exe: grpc_test_util
+census_statistics_small_log_test.exe: grpc_test_util $(OUT_DIR)
 	echo Building census_statistics_small_log_test
 	$(CC) $(CFLAGS) /Fo:$(OUT_DIR)\ ..\..\test\core\statistics\small_log_test.c 
 	$(LINK) $(LFLAGS) /OUT:"$(OUT_DIR)\census_statistics_small_log_test.exe" Debug\grpc_test_util.lib Debug\grpc.lib Debug\gpr_test_util.lib Debug\gpr.lib $(LIBS) $(OUT_DIR)\small_log_test.obj 
@@ -150,7 +149,7 @@ census_statistics_small_log_test: census_statistics_small_log_test.exe
 	echo Running census_statistics_small_log_test
 	$(OUT_DIR)\census_statistics_small_log_test.exe
 
-census_stats_store_test.exe: grpc_test_util
+census_stats_store_test.exe: grpc_test_util $(OUT_DIR)
 	echo Building census_stats_store_test
 	$(CC) $(CFLAGS) /Fo:$(OUT_DIR)\ ..\..\test\core\statistics\rpc_stats_test.c 
 	$(LINK) $(LFLAGS) /OUT:"$(OUT_DIR)\census_stats_store_test.exe" Debug\grpc_test_util.lib Debug\grpc.lib Debug\gpr_test_util.lib Debug\gpr.lib $(LIBS) $(OUT_DIR)\rpc_stats_test.obj 
@@ -158,7 +157,7 @@ census_stats_store_test: census_stats_store_test.exe
 	echo Running census_stats_store_test
 	$(OUT_DIR)\census_stats_store_test.exe
 
-census_stub_test.exe: grpc_test_util
+census_stub_test.exe: grpc_test_util $(OUT_DIR)
 	echo Building census_stub_test
 	$(CC) $(CFLAGS) /Fo:$(OUT_DIR)\ ..\..\test\core\statistics\census_stub_test.c 
 	$(LINK) $(LFLAGS) /OUT:"$(OUT_DIR)\census_stub_test.exe" Debug\grpc_test_util.lib Debug\grpc.lib Debug\gpr_test_util.lib Debug\gpr.lib $(LIBS) $(OUT_DIR)\census_stub_test.obj 
@@ -166,7 +165,7 @@ census_stub_test: census_stub_test.exe
 	echo Running census_stub_test
 	$(OUT_DIR)\census_stub_test.exe
 
-census_trace_store_test.exe: grpc_test_util
+census_trace_store_test.exe: grpc_test_util $(OUT_DIR)
 	echo Building census_trace_store_test
 	$(CC) $(CFLAGS) /Fo:$(OUT_DIR)\ ..\..\test\core\statistics\trace_test.c 
 	$(LINK) $(LFLAGS) /OUT:"$(OUT_DIR)\census_trace_store_test.exe" Debug\grpc_test_util.lib Debug\grpc.lib Debug\gpr_test_util.lib Debug\gpr.lib $(LIBS) $(OUT_DIR)\trace_test.obj 
@@ -174,7 +173,7 @@ census_trace_store_test: census_trace_store_test.exe
 	echo Running census_trace_store_test
 	$(OUT_DIR)\census_trace_store_test.exe
 
-census_window_stats_test.exe: grpc_test_util
+census_window_stats_test.exe: grpc_test_util $(OUT_DIR)
 	echo Building census_window_stats_test
 	$(CC) $(CFLAGS) /Fo:$(OUT_DIR)\ ..\..\test\core\statistics\window_stats_test.c 
 	$(LINK) $(LFLAGS) /OUT:"$(OUT_DIR)\census_window_stats_test.exe" Debug\grpc_test_util.lib Debug\grpc.lib Debug\gpr_test_util.lib Debug\gpr.lib $(LIBS) $(OUT_DIR)\window_stats_test.obj 
@@ -182,7 +181,7 @@ census_window_stats_test: census_window_stats_test.exe
 	echo Running census_window_stats_test
 	$(OUT_DIR)\census_window_stats_test.exe
 
-chttp2_status_conversion_test.exe: grpc_test_util
+chttp2_status_conversion_test.exe: grpc_test_util $(OUT_DIR)
 	echo Building chttp2_status_conversion_test
 	$(CC) $(CFLAGS) /Fo:$(OUT_DIR)\ ..\..\test\core\transport\chttp2\status_conversion_test.c 
 	$(LINK) $(LFLAGS) /OUT:"$(OUT_DIR)\chttp2_status_conversion_test.exe" Debug\grpc_test_util.lib Debug\grpc.lib Debug\gpr_test_util.lib Debug\gpr.lib $(LIBS) $(OUT_DIR)\status_conversion_test.obj 
@@ -190,7 +189,7 @@ chttp2_status_conversion_test: chttp2_status_conversion_test.exe
 	echo Running chttp2_status_conversion_test
 	$(OUT_DIR)\chttp2_status_conversion_test.exe
 
-chttp2_stream_encoder_test.exe: grpc_test_util
+chttp2_stream_encoder_test.exe: grpc_test_util $(OUT_DIR)
 	echo Building chttp2_stream_encoder_test
 	$(CC) $(CFLAGS) /Fo:$(OUT_DIR)\ ..\..\test\core\transport\chttp2\stream_encoder_test.c 
 	$(LINK) $(LFLAGS) /OUT:"$(OUT_DIR)\chttp2_stream_encoder_test.exe" Debug\grpc_test_util.lib Debug\grpc.lib Debug\gpr_test_util.lib Debug\gpr.lib $(LIBS) $(OUT_DIR)\stream_encoder_test.obj 
@@ -198,7 +197,7 @@ chttp2_stream_encoder_test: chttp2_stream_encoder_test.exe
 	echo Running chttp2_stream_encoder_test
 	$(OUT_DIR)\chttp2_stream_encoder_test.exe
 
-chttp2_stream_map_test.exe: grpc_test_util
+chttp2_stream_map_test.exe: grpc_test_util $(OUT_DIR)
 	echo Building chttp2_stream_map_test
 	$(CC) $(CFLAGS) /Fo:$(OUT_DIR)\ ..\..\test\core\transport\chttp2\stream_map_test.c 
 	$(LINK) $(LFLAGS) /OUT:"$(OUT_DIR)\chttp2_stream_map_test.exe" Debug\grpc_test_util.lib Debug\grpc.lib Debug\gpr_test_util.lib Debug\gpr.lib $(LIBS) $(OUT_DIR)\stream_map_test.obj 
@@ -206,7 +205,7 @@ chttp2_stream_map_test: chttp2_stream_map_test.exe
 	echo Running chttp2_stream_map_test
 	$(OUT_DIR)\chttp2_stream_map_test.exe
 
-chttp2_transport_end2end_test.exe: grpc_test_util
+chttp2_transport_end2end_test.exe: grpc_test_util $(OUT_DIR)
 	echo Building chttp2_transport_end2end_test
 	$(CC) $(CFLAGS) /Fo:$(OUT_DIR)\ ..\..\test\core\transport\chttp2_transport_end2end_test.c 
 	$(LINK) $(LFLAGS) /OUT:"$(OUT_DIR)\chttp2_transport_end2end_test.exe" Debug\grpc_test_util.lib Debug\grpc.lib Debug\gpr_test_util.lib Debug\gpr.lib $(LIBS) $(OUT_DIR)\chttp2_transport_end2end_test.obj 
@@ -214,15 +213,7 @@ chttp2_transport_end2end_test: chttp2_transport_end2end_test.exe
 	echo Running chttp2_transport_end2end_test
 	$(OUT_DIR)\chttp2_transport_end2end_test.exe
 
-dualstack_socket_test.exe: grpc_test_util
-	echo Building dualstack_socket_test
-	$(CC) $(CFLAGS) /Fo:$(OUT_DIR)\ ..\..\test\core\end2end\dualstack_socket_test.c 
-	$(LINK) $(LFLAGS) /OUT:"$(OUT_DIR)\dualstack_socket_test.exe" Debug\grpc_test_util.lib Debug\grpc.lib Debug\gpr_test_util.lib Debug\gpr.lib $(LIBS) $(OUT_DIR)\dualstack_socket_test.obj 
-dualstack_socket_test: dualstack_socket_test.exe
-	echo Running dualstack_socket_test
-	$(OUT_DIR)\dualstack_socket_test.exe
-
-echo_client.exe: grpc_test_util
+echo_client.exe: grpc_test_util $(OUT_DIR)
 	echo Building echo_client
 	$(CC) $(CFLAGS) /Fo:$(OUT_DIR)\ ..\..\test\core\echo\client.c 
 	$(LINK) $(LFLAGS) /OUT:"$(OUT_DIR)\echo_client.exe" Debug\grpc_test_util.lib Debug\grpc.lib Debug\gpr_test_util.lib Debug\gpr.lib $(LIBS) $(OUT_DIR)\client.obj 
@@ -230,7 +221,7 @@ echo_client: echo_client.exe
 	echo Running echo_client
 	$(OUT_DIR)\echo_client.exe
 
-echo_server.exe: grpc_test_util
+echo_server.exe: grpc_test_util $(OUT_DIR)
 	echo Building echo_server
 	$(CC) $(CFLAGS) /Fo:$(OUT_DIR)\ ..\..\test\core\echo\server.c 
 	$(LINK) $(LFLAGS) /OUT:"$(OUT_DIR)\echo_server.exe" Debug\grpc_test_util.lib Debug\grpc.lib Debug\gpr_test_util.lib Debug\gpr.lib $(LIBS) $(OUT_DIR)\server.obj 
@@ -238,7 +229,7 @@ echo_server: echo_server.exe
 	echo Running echo_server
 	$(OUT_DIR)\echo_server.exe
 
-echo_test.exe: grpc_test_util
+echo_test.exe: grpc_test_util $(OUT_DIR)
 	echo Building echo_test
 	$(CC) $(CFLAGS) /Fo:$(OUT_DIR)\ ..\..\test\core\echo\echo_test.c 
 	$(LINK) $(LFLAGS) /OUT:"$(OUT_DIR)\echo_test.exe" Debug\grpc_test_util.lib Debug\grpc.lib Debug\gpr_test_util.lib Debug\gpr.lib $(LIBS) $(OUT_DIR)\echo_test.obj 
@@ -246,7 +237,7 @@ echo_test: echo_test.exe
 	echo Running echo_test
 	$(OUT_DIR)\echo_test.exe
 
-fd_posix_test.exe: grpc_test_util
+fd_posix_test.exe: grpc_test_util $(OUT_DIR)
 	echo Building fd_posix_test
 	$(CC) $(CFLAGS) /Fo:$(OUT_DIR)\ ..\..\test\core\iomgr\fd_posix_test.c 
 	$(LINK) $(LFLAGS) /OUT:"$(OUT_DIR)\fd_posix_test.exe" Debug\grpc_test_util.lib Debug\grpc.lib Debug\gpr_test_util.lib Debug\gpr.lib $(LIBS) $(OUT_DIR)\fd_posix_test.obj 
@@ -254,7 +245,7 @@ fd_posix_test: fd_posix_test.exe
 	echo Running fd_posix_test
 	$(OUT_DIR)\fd_posix_test.exe
 
-fling_client.exe: grpc_test_util
+fling_client.exe: grpc_test_util $(OUT_DIR)
 	echo Building fling_client
 	$(CC) $(CFLAGS) /Fo:$(OUT_DIR)\ ..\..\test\core\fling\client.c 
 	$(LINK) $(LFLAGS) /OUT:"$(OUT_DIR)\fling_client.exe" Debug\grpc_test_util.lib Debug\grpc.lib Debug\gpr_test_util.lib Debug\gpr.lib $(LIBS) $(OUT_DIR)\client.obj 
@@ -262,7 +253,7 @@ fling_client: fling_client.exe
 	echo Running fling_client
 	$(OUT_DIR)\fling_client.exe
 
-fling_server.exe: grpc_test_util
+fling_server.exe: grpc_test_util $(OUT_DIR)
 	echo Building fling_server
 	$(CC) $(CFLAGS) /Fo:$(OUT_DIR)\ ..\..\test\core\fling\server.c 
 	$(LINK) $(LFLAGS) /OUT:"$(OUT_DIR)\fling_server.exe" Debug\grpc_test_util.lib Debug\grpc.lib Debug\gpr_test_util.lib Debug\gpr.lib $(LIBS) $(OUT_DIR)\server.obj 
@@ -270,7 +261,7 @@ fling_server: fling_server.exe
 	echo Running fling_server
 	$(OUT_DIR)\fling_server.exe
 
-fling_stream_test.exe: grpc_test_util
+fling_stream_test.exe: grpc_test_util $(OUT_DIR)
 	echo Building fling_stream_test
 	$(CC) $(CFLAGS) /Fo:$(OUT_DIR)\ ..\..\test\core\fling\fling_stream_test.c 
 	$(LINK) $(LFLAGS) /OUT:"$(OUT_DIR)\fling_stream_test.exe" Debug\grpc_test_util.lib Debug\grpc.lib Debug\gpr_test_util.lib Debug\gpr.lib $(LIBS) $(OUT_DIR)\fling_stream_test.obj 
@@ -278,7 +269,7 @@ fling_stream_test: fling_stream_test.exe
 	echo Running fling_stream_test
 	$(OUT_DIR)\fling_stream_test.exe
 
-fling_test.exe: grpc_test_util
+fling_test.exe: grpc_test_util $(OUT_DIR)
 	echo Building fling_test
 	$(CC) $(CFLAGS) /Fo:$(OUT_DIR)\ ..\..\test\core\fling\fling_test.c 
 	$(LINK) $(LFLAGS) /OUT:"$(OUT_DIR)\fling_test.exe" Debug\grpc_test_util.lib Debug\grpc.lib Debug\gpr_test_util.lib Debug\gpr.lib $(LIBS) $(OUT_DIR)\fling_test.obj 
@@ -286,7 +277,7 @@ fling_test: fling_test.exe
 	echo Running fling_test
 	$(OUT_DIR)\fling_test.exe
 
-gen_hpack_tables.exe: grpc_test_util
+gen_hpack_tables.exe: grpc_test_util $(OUT_DIR)
 	echo Building gen_hpack_tables
 	$(CC) $(CFLAGS) /Fo:$(OUT_DIR)\ ..\..\src\core\transport\chttp2\gen_hpack_tables.c 
 	$(LINK) $(LFLAGS) /OUT:"$(OUT_DIR)\gen_hpack_tables.exe" Debug\grpc_test_util.lib Debug\gpr.lib Debug\grpc.lib $(LIBS) $(OUT_DIR)\gen_hpack_tables.obj 
@@ -294,7 +285,7 @@ gen_hpack_tables: gen_hpack_tables.exe
 	echo Running gen_hpack_tables
 	$(OUT_DIR)\gen_hpack_tables.exe
 
-gpr_cancellable_test.exe: grpc_test_util
+gpr_cancellable_test.exe: grpc_test_util $(OUT_DIR)
 	echo Building gpr_cancellable_test
 	$(CC) $(CFLAGS) /Fo:$(OUT_DIR)\ ..\..\test\core\support\cancellable_test.c 
 	$(LINK) $(LFLAGS) /OUT:"$(OUT_DIR)\gpr_cancellable_test.exe" Debug\gpr_test_util.lib Debug\gpr.lib $(LIBS) $(OUT_DIR)\cancellable_test.obj 
@@ -302,7 +293,7 @@ gpr_cancellable_test: gpr_cancellable_test.exe
 	echo Running gpr_cancellable_test
 	$(OUT_DIR)\gpr_cancellable_test.exe
 
-gpr_cmdline_test.exe: grpc_test_util
+gpr_cmdline_test.exe: grpc_test_util $(OUT_DIR)
 	echo Building gpr_cmdline_test
 	$(CC) $(CFLAGS) /Fo:$(OUT_DIR)\ ..\..\test\core\support\cmdline_test.c 
 	$(LINK) $(LFLAGS) /OUT:"$(OUT_DIR)\gpr_cmdline_test.exe" Debug\gpr_test_util.lib Debug\gpr.lib $(LIBS) $(OUT_DIR)\cmdline_test.obj 
@@ -310,7 +301,7 @@ gpr_cmdline_test: gpr_cmdline_test.exe
 	echo Running gpr_cmdline_test
 	$(OUT_DIR)\gpr_cmdline_test.exe
 
-gpr_env_test.exe: grpc_test_util
+gpr_env_test.exe: grpc_test_util $(OUT_DIR)
 	echo Building gpr_env_test
 	$(CC) $(CFLAGS) /Fo:$(OUT_DIR)\ ..\..\test\core\support\env_test.c 
 	$(LINK) $(LFLAGS) /OUT:"$(OUT_DIR)\gpr_env_test.exe" Debug\gpr_test_util.lib Debug\gpr.lib $(LIBS) $(OUT_DIR)\env_test.obj 
@@ -318,7 +309,7 @@ gpr_env_test: gpr_env_test.exe
 	echo Running gpr_env_test
 	$(OUT_DIR)\gpr_env_test.exe
 
-gpr_file_test.exe: grpc_test_util
+gpr_file_test.exe: grpc_test_util $(OUT_DIR)
 	echo Building gpr_file_test
 	$(CC) $(CFLAGS) /Fo:$(OUT_DIR)\ ..\..\test\core\support\file_test.c 
 	$(LINK) $(LFLAGS) /OUT:"$(OUT_DIR)\gpr_file_test.exe" Debug\gpr_test_util.lib Debug\gpr.lib $(LIBS) $(OUT_DIR)\file_test.obj 
@@ -326,7 +317,7 @@ gpr_file_test: gpr_file_test.exe
 	echo Running gpr_file_test
 	$(OUT_DIR)\gpr_file_test.exe
 
-gpr_histogram_test.exe: grpc_test_util
+gpr_histogram_test.exe: grpc_test_util $(OUT_DIR)
 	echo Building gpr_histogram_test
 	$(CC) $(CFLAGS) /Fo:$(OUT_DIR)\ ..\..\test\core\support\histogram_test.c 
 	$(LINK) $(LFLAGS) /OUT:"$(OUT_DIR)\gpr_histogram_test.exe" Debug\gpr_test_util.lib Debug\gpr.lib $(LIBS) $(OUT_DIR)\histogram_test.obj 
@@ -334,7 +325,7 @@ gpr_histogram_test: gpr_histogram_test.exe
 	echo Running gpr_histogram_test
 	$(OUT_DIR)\gpr_histogram_test.exe
 
-gpr_host_port_test.exe: grpc_test_util
+gpr_host_port_test.exe: grpc_test_util $(OUT_DIR)
 	echo Building gpr_host_port_test
 	$(CC) $(CFLAGS) /Fo:$(OUT_DIR)\ ..\..\test\core\support\host_port_test.c 
 	$(LINK) $(LFLAGS) /OUT:"$(OUT_DIR)\gpr_host_port_test.exe" Debug\gpr_test_util.lib Debug\gpr.lib $(LIBS) $(OUT_DIR)\host_port_test.obj 
@@ -342,7 +333,7 @@ gpr_host_port_test: gpr_host_port_test.exe
 	echo Running gpr_host_port_test
 	$(OUT_DIR)\gpr_host_port_test.exe
 
-gpr_log_test.exe: grpc_test_util
+gpr_log_test.exe: grpc_test_util $(OUT_DIR)
 	echo Building gpr_log_test
 	$(CC) $(CFLAGS) /Fo:$(OUT_DIR)\ ..\..\test\core\support\log_test.c 
 	$(LINK) $(LFLAGS) /OUT:"$(OUT_DIR)\gpr_log_test.exe" Debug\gpr_test_util.lib Debug\gpr.lib $(LIBS) $(OUT_DIR)\log_test.obj 
@@ -350,7 +341,7 @@ gpr_log_test: gpr_log_test.exe
 	echo Running gpr_log_test
 	$(OUT_DIR)\gpr_log_test.exe
 
-gpr_slice_buffer_test.exe: grpc_test_util
+gpr_slice_buffer_test.exe: grpc_test_util $(OUT_DIR)
 	echo Building gpr_slice_buffer_test
 	$(CC) $(CFLAGS) /Fo:$(OUT_DIR)\ ..\..\test\core\support\slice_buffer_test.c 
 	$(LINK) $(LFLAGS) /OUT:"$(OUT_DIR)\gpr_slice_buffer_test.exe" Debug\gpr_test_util.lib Debug\gpr.lib $(LIBS) $(OUT_DIR)\slice_buffer_test.obj 
@@ -358,7 +349,7 @@ gpr_slice_buffer_test: gpr_slice_buffer_test.exe
 	echo Running gpr_slice_buffer_test
 	$(OUT_DIR)\gpr_slice_buffer_test.exe
 
-gpr_slice_test.exe: grpc_test_util
+gpr_slice_test.exe: grpc_test_util $(OUT_DIR)
 	echo Building gpr_slice_test
 	$(CC) $(CFLAGS) /Fo:$(OUT_DIR)\ ..\..\test\core\support\slice_test.c 
 	$(LINK) $(LFLAGS) /OUT:"$(OUT_DIR)\gpr_slice_test.exe" Debug\gpr_test_util.lib Debug\gpr.lib $(LIBS) $(OUT_DIR)\slice_test.obj 
@@ -366,7 +357,7 @@ gpr_slice_test: gpr_slice_test.exe
 	echo Running gpr_slice_test
 	$(OUT_DIR)\gpr_slice_test.exe
 
-gpr_string_test.exe: grpc_test_util
+gpr_string_test.exe: grpc_test_util $(OUT_DIR)
 	echo Building gpr_string_test
 	$(CC) $(CFLAGS) /Fo:$(OUT_DIR)\ ..\..\test\core\support\string_test.c 
 	$(LINK) $(LFLAGS) /OUT:"$(OUT_DIR)\gpr_string_test.exe" Debug\gpr_test_util.lib Debug\gpr.lib $(LIBS) $(OUT_DIR)\string_test.obj 
@@ -374,7 +365,7 @@ gpr_string_test: gpr_string_test.exe
 	echo Running gpr_string_test
 	$(OUT_DIR)\gpr_string_test.exe
 
-gpr_sync_test.exe: grpc_test_util
+gpr_sync_test.exe: grpc_test_util $(OUT_DIR)
 	echo Building gpr_sync_test
 	$(CC) $(CFLAGS) /Fo:$(OUT_DIR)\ ..\..\test\core\support\sync_test.c 
 	$(LINK) $(LFLAGS) /OUT:"$(OUT_DIR)\gpr_sync_test.exe" Debug\gpr_test_util.lib Debug\gpr.lib $(LIBS) $(OUT_DIR)\sync_test.obj 
@@ -382,7 +373,7 @@ gpr_sync_test: gpr_sync_test.exe
 	echo Running gpr_sync_test
 	$(OUT_DIR)\gpr_sync_test.exe
 
-gpr_thd_test.exe: grpc_test_util
+gpr_thd_test.exe: grpc_test_util $(OUT_DIR)
 	echo Building gpr_thd_test
 	$(CC) $(CFLAGS) /Fo:$(OUT_DIR)\ ..\..\test\core\support\thd_test.c 
 	$(LINK) $(LFLAGS) /OUT:"$(OUT_DIR)\gpr_thd_test.exe" Debug\gpr_test_util.lib Debug\gpr.lib $(LIBS) $(OUT_DIR)\thd_test.obj 
@@ -390,7 +381,7 @@ gpr_thd_test: gpr_thd_test.exe
 	echo Running gpr_thd_test
 	$(OUT_DIR)\gpr_thd_test.exe
 
-gpr_time_test.exe: grpc_test_util
+gpr_time_test.exe: grpc_test_util $(OUT_DIR)
 	echo Building gpr_time_test
 	$(CC) $(CFLAGS) /Fo:$(OUT_DIR)\ ..\..\test\core\support\time_test.c 
 	$(LINK) $(LFLAGS) /OUT:"$(OUT_DIR)\gpr_time_test.exe" Debug\gpr_test_util.lib Debug\gpr.lib $(LIBS) $(OUT_DIR)\time_test.obj 
@@ -398,7 +389,15 @@ gpr_time_test: gpr_time_test.exe
 	echo Running gpr_time_test
 	$(OUT_DIR)\gpr_time_test.exe
 
-gpr_useful_test.exe: grpc_test_util
+gpr_tls_test.exe: grpc_test_util $(OUT_DIR)
+	echo Building gpr_tls_test
+	$(CC) $(CFLAGS) /Fo:$(OUT_DIR)\ ..\..\test\core\support\tls_test.c 
+	$(LINK) $(LFLAGS) /OUT:"$(OUT_DIR)\gpr_tls_test.exe" Debug\gpr_test_util.lib Debug\gpr.lib $(LIBS) $(OUT_DIR)\tls_test.obj 
+gpr_tls_test: gpr_tls_test.exe
+	echo Running gpr_tls_test
+	$(OUT_DIR)\gpr_tls_test.exe
+
+gpr_useful_test.exe: grpc_test_util $(OUT_DIR)
 	echo Building gpr_useful_test
 	$(CC) $(CFLAGS) /Fo:$(OUT_DIR)\ ..\..\test\core\support\useful_test.c 
 	$(LINK) $(LFLAGS) /OUT:"$(OUT_DIR)\gpr_useful_test.exe" Debug\gpr_test_util.lib Debug\gpr.lib $(LIBS) $(OUT_DIR)\useful_test.obj 
@@ -406,7 +405,7 @@ gpr_useful_test: gpr_useful_test.exe
 	echo Running gpr_useful_test
 	$(OUT_DIR)\gpr_useful_test.exe
 
-grpc_base64_test.exe: grpc_test_util
+grpc_base64_test.exe: grpc_test_util $(OUT_DIR)
 	echo Building grpc_base64_test
 	$(CC) $(CFLAGS) /Fo:$(OUT_DIR)\ ..\..\test\core\security\base64_test.c 
 	$(LINK) $(LFLAGS) /OUT:"$(OUT_DIR)\grpc_base64_test.exe" Debug\grpc_test_util.lib Debug\grpc.lib Debug\gpr_test_util.lib Debug\gpr.lib $(LIBS) $(OUT_DIR)\base64_test.obj 
@@ -414,7 +413,7 @@ grpc_base64_test: grpc_base64_test.exe
 	echo Running grpc_base64_test
 	$(OUT_DIR)\grpc_base64_test.exe
 
-grpc_byte_buffer_reader_test.exe: grpc_test_util
+grpc_byte_buffer_reader_test.exe: grpc_test_util $(OUT_DIR)
 	echo Building grpc_byte_buffer_reader_test
 	$(CC) $(CFLAGS) /Fo:$(OUT_DIR)\ ..\..\test\core\surface\byte_buffer_reader_test.c 
 	$(LINK) $(LFLAGS) /OUT:"$(OUT_DIR)\grpc_byte_buffer_reader_test.exe" Debug\grpc_test_util.lib Debug\grpc.lib Debug\gpr_test_util.lib Debug\gpr.lib $(LIBS) $(OUT_DIR)\byte_buffer_reader_test.obj 
@@ -422,7 +421,7 @@ grpc_byte_buffer_reader_test: grpc_byte_buffer_reader_test.exe
 	echo Running grpc_byte_buffer_reader_test
 	$(OUT_DIR)\grpc_byte_buffer_reader_test.exe
 
-grpc_channel_stack_test.exe: grpc_test_util
+grpc_channel_stack_test.exe: grpc_test_util $(OUT_DIR)
 	echo Building grpc_channel_stack_test
 	$(CC) $(CFLAGS) /Fo:$(OUT_DIR)\ ..\..\test\core\channel\channel_stack_test.c 
 	$(LINK) $(LFLAGS) /OUT:"$(OUT_DIR)\grpc_channel_stack_test.exe" Debug\grpc_test_util.lib Debug\grpc.lib Debug\gpr_test_util.lib Debug\gpr.lib $(LIBS) $(OUT_DIR)\channel_stack_test.obj 
@@ -430,7 +429,7 @@ grpc_channel_stack_test: grpc_channel_stack_test.exe
 	echo Running grpc_channel_stack_test
 	$(OUT_DIR)\grpc_channel_stack_test.exe
 
-grpc_completion_queue_benchmark.exe: grpc_test_util
+grpc_completion_queue_benchmark.exe: grpc_test_util $(OUT_DIR)
 	echo Building grpc_completion_queue_benchmark
 	$(CC) $(CFLAGS) /Fo:$(OUT_DIR)\ ..\..\test\core\surface\completion_queue_benchmark.c 
 	$(LINK) $(LFLAGS) /OUT:"$(OUT_DIR)\grpc_completion_queue_benchmark.exe" Debug\grpc_test_util.lib Debug\grpc.lib Debug\gpr_test_util.lib Debug\gpr.lib $(LIBS) $(OUT_DIR)\completion_queue_benchmark.obj 
@@ -438,7 +437,7 @@ grpc_completion_queue_benchmark: grpc_completion_queue_benchmark.exe
 	echo Running grpc_completion_queue_benchmark
 	$(OUT_DIR)\grpc_completion_queue_benchmark.exe
 
-grpc_completion_queue_test.exe: grpc_test_util
+grpc_completion_queue_test.exe: grpc_test_util $(OUT_DIR)
 	echo Building grpc_completion_queue_test
 	$(CC) $(CFLAGS) /Fo:$(OUT_DIR)\ ..\..\test\core\surface\completion_queue_test.c 
 	$(LINK) $(LFLAGS) /OUT:"$(OUT_DIR)\grpc_completion_queue_test.exe" Debug\grpc_test_util.lib Debug\grpc.lib Debug\gpr_test_util.lib Debug\gpr.lib $(LIBS) $(OUT_DIR)\completion_queue_test.obj 
@@ -446,7 +445,7 @@ grpc_completion_queue_test: grpc_completion_queue_test.exe
 	echo Running grpc_completion_queue_test
 	$(OUT_DIR)\grpc_completion_queue_test.exe
 
-grpc_create_jwt.exe: grpc_test_util
+grpc_create_jwt.exe: grpc_test_util $(OUT_DIR)
 	echo Building grpc_create_jwt
 	$(CC) $(CFLAGS) /Fo:$(OUT_DIR)\ ..\..\test\core\security\create_jwt.c 
 	$(LINK) $(LFLAGS) /OUT:"$(OUT_DIR)\grpc_create_jwt.exe" Debug\grpc_test_util.lib Debug\grpc.lib Debug\gpr_test_util.lib Debug\gpr.lib $(LIBS) $(OUT_DIR)\create_jwt.obj 
@@ -454,7 +453,7 @@ grpc_create_jwt: grpc_create_jwt.exe
 	echo Running grpc_create_jwt
 	$(OUT_DIR)\grpc_create_jwt.exe
 
-grpc_credentials_test.exe: grpc_test_util
+grpc_credentials_test.exe: grpc_test_util $(OUT_DIR)
 	echo Building grpc_credentials_test
 	$(CC) $(CFLAGS) /Fo:$(OUT_DIR)\ ..\..\test\core\security\credentials_test.c 
 	$(LINK) $(LFLAGS) /OUT:"$(OUT_DIR)\grpc_credentials_test.exe" Debug\grpc_test_util.lib Debug\grpc.lib Debug\gpr_test_util.lib Debug\gpr.lib $(LIBS) $(OUT_DIR)\credentials_test.obj 
@@ -462,7 +461,7 @@ grpc_credentials_test: grpc_credentials_test.exe
 	echo Running grpc_credentials_test
 	$(OUT_DIR)\grpc_credentials_test.exe
 
-grpc_fetch_oauth2.exe: grpc_test_util
+grpc_fetch_oauth2.exe: grpc_test_util $(OUT_DIR)
 	echo Building grpc_fetch_oauth2
 	$(CC) $(CFLAGS) /Fo:$(OUT_DIR)\ ..\..\test\core\security\fetch_oauth2.c 
 	$(LINK) $(LFLAGS) /OUT:"$(OUT_DIR)\grpc_fetch_oauth2.exe" Debug\grpc_test_util.lib Debug\grpc.lib Debug\gpr_test_util.lib Debug\gpr.lib $(LIBS) $(OUT_DIR)\fetch_oauth2.obj 
@@ -470,7 +469,7 @@ grpc_fetch_oauth2: grpc_fetch_oauth2.exe
 	echo Running grpc_fetch_oauth2
 	$(OUT_DIR)\grpc_fetch_oauth2.exe
 
-grpc_json_token_test.exe: grpc_test_util
+grpc_json_token_test.exe: grpc_test_util $(OUT_DIR)
 	echo Building grpc_json_token_test
 	$(CC) $(CFLAGS) /Fo:$(OUT_DIR)\ ..\..\test\core\security\json_token_test.c 
 	$(LINK) $(LFLAGS) /OUT:"$(OUT_DIR)\grpc_json_token_test.exe" Debug\grpc_test_util.lib Debug\grpc.lib Debug\gpr_test_util.lib Debug\gpr.lib $(LIBS) $(OUT_DIR)\json_token_test.obj 
@@ -478,7 +477,7 @@ grpc_json_token_test: grpc_json_token_test.exe
 	echo Running grpc_json_token_test
 	$(OUT_DIR)\grpc_json_token_test.exe
 
-grpc_print_google_default_creds_token.exe: grpc_test_util
+grpc_print_google_default_creds_token.exe: grpc_test_util $(OUT_DIR)
 	echo Building grpc_print_google_default_creds_token
 	$(CC) $(CFLAGS) /Fo:$(OUT_DIR)\ ..\..\test\core\security\print_google_default_creds_token.c 
 	$(LINK) $(LFLAGS) /OUT:"$(OUT_DIR)\grpc_print_google_default_creds_token.exe" Debug\grpc_test_util.lib Debug\grpc.lib Debug\gpr_test_util.lib Debug\gpr.lib $(LIBS) $(OUT_DIR)\print_google_default_creds_token.obj 
@@ -486,7 +485,7 @@ grpc_print_google_default_creds_token: grpc_print_google_default_creds_token.exe
 	echo Running grpc_print_google_default_creds_token
 	$(OUT_DIR)\grpc_print_google_default_creds_token.exe
 
-grpc_stream_op_test.exe: grpc_test_util
+grpc_stream_op_test.exe: grpc_test_util $(OUT_DIR)
 	echo Building grpc_stream_op_test
 	$(CC) $(CFLAGS) /Fo:$(OUT_DIR)\ ..\..\test\core\transport\stream_op_test.c 
 	$(LINK) $(LFLAGS) /OUT:"$(OUT_DIR)\grpc_stream_op_test.exe" Debug\grpc_test_util.lib Debug\grpc.lib Debug\gpr_test_util.lib Debug\gpr.lib $(LIBS) $(OUT_DIR)\stream_op_test.obj 
@@ -494,7 +493,7 @@ grpc_stream_op_test: grpc_stream_op_test.exe
 	echo Running grpc_stream_op_test
 	$(OUT_DIR)\grpc_stream_op_test.exe
 
-hpack_parser_test.exe: grpc_test_util
+hpack_parser_test.exe: grpc_test_util $(OUT_DIR)
 	echo Building hpack_parser_test
 	$(CC) $(CFLAGS) /Fo:$(OUT_DIR)\ ..\..\test\core\transport\chttp2\hpack_parser_test.c 
 	$(LINK) $(LFLAGS) /OUT:"$(OUT_DIR)\hpack_parser_test.exe" Debug\grpc_test_util.lib Debug\grpc.lib Debug\gpr_test_util.lib Debug\gpr.lib $(LIBS) $(OUT_DIR)\hpack_parser_test.obj 
@@ -502,7 +501,7 @@ hpack_parser_test: hpack_parser_test.exe
 	echo Running hpack_parser_test
 	$(OUT_DIR)\hpack_parser_test.exe
 
-hpack_table_test.exe: grpc_test_util
+hpack_table_test.exe: grpc_test_util $(OUT_DIR)
 	echo Building hpack_table_test
 	$(CC) $(CFLAGS) /Fo:$(OUT_DIR)\ ..\..\test\core\transport\chttp2\hpack_table_test.c 
 	$(LINK) $(LFLAGS) /OUT:"$(OUT_DIR)\hpack_table_test.exe" Debug\grpc_test_util.lib Debug\grpc.lib Debug\gpr_test_util.lib Debug\gpr.lib $(LIBS) $(OUT_DIR)\hpack_table_test.obj 
@@ -510,7 +509,7 @@ hpack_table_test: hpack_table_test.exe
 	echo Running hpack_table_test
 	$(OUT_DIR)\hpack_table_test.exe
 
-httpcli_format_request_test.exe: grpc_test_util
+httpcli_format_request_test.exe: grpc_test_util $(OUT_DIR)
 	echo Building httpcli_format_request_test
 	$(CC) $(CFLAGS) /Fo:$(OUT_DIR)\ ..\..\test\core\httpcli\format_request_test.c 
 	$(LINK) $(LFLAGS) /OUT:"$(OUT_DIR)\httpcli_format_request_test.exe" Debug\grpc_test_util.lib Debug\grpc.lib Debug\gpr_test_util.lib Debug\gpr.lib $(LIBS) $(OUT_DIR)\format_request_test.obj 
@@ -518,7 +517,7 @@ httpcli_format_request_test: httpcli_format_request_test.exe
 	echo Running httpcli_format_request_test
 	$(OUT_DIR)\httpcli_format_request_test.exe
 
-httpcli_parser_test.exe: grpc_test_util
+httpcli_parser_test.exe: grpc_test_util $(OUT_DIR)
 	echo Building httpcli_parser_test
 	$(CC) $(CFLAGS) /Fo:$(OUT_DIR)\ ..\..\test\core\httpcli\parser_test.c 
 	$(LINK) $(LFLAGS) /OUT:"$(OUT_DIR)\httpcli_parser_test.exe" Debug\grpc_test_util.lib Debug\grpc.lib Debug\gpr_test_util.lib Debug\gpr.lib $(LIBS) $(OUT_DIR)\parser_test.obj 
@@ -526,7 +525,7 @@ httpcli_parser_test: httpcli_parser_test.exe
 	echo Running httpcli_parser_test
 	$(OUT_DIR)\httpcli_parser_test.exe
 
-httpcli_test.exe: grpc_test_util
+httpcli_test.exe: grpc_test_util $(OUT_DIR)
 	echo Building httpcli_test
 	$(CC) $(CFLAGS) /Fo:$(OUT_DIR)\ ..\..\test\core\httpcli\httpcli_test.c 
 	$(LINK) $(LFLAGS) /OUT:"$(OUT_DIR)\httpcli_test.exe" Debug\grpc_test_util.lib Debug\grpc.lib Debug\gpr_test_util.lib Debug\gpr.lib $(LIBS) $(OUT_DIR)\httpcli_test.obj 
@@ -534,7 +533,7 @@ httpcli_test: httpcli_test.exe
 	echo Running httpcli_test
 	$(OUT_DIR)\httpcli_test.exe
 
-json_rewrite.exe: grpc_test_util
+json_rewrite.exe: grpc_test_util $(OUT_DIR)
 	echo Building json_rewrite
 	$(CC) $(CFLAGS) /Fo:$(OUT_DIR)\ ..\..\test\core\json\json_rewrite.c 
 	$(LINK) $(LFLAGS) /OUT:"$(OUT_DIR)\json_rewrite.exe" Debug\grpc.lib Debug\gpr.lib $(LIBS) $(OUT_DIR)\json_rewrite.obj 
@@ -542,7 +541,7 @@ json_rewrite: json_rewrite.exe
 	echo Running json_rewrite
 	$(OUT_DIR)\json_rewrite.exe
 
-json_rewrite_test.exe: grpc_test_util
+json_rewrite_test.exe: grpc_test_util $(OUT_DIR)
 	echo Building json_rewrite_test
 	$(CC) $(CFLAGS) /Fo:$(OUT_DIR)\ ..\..\test\core\json\json_rewrite_test.c 
 	$(LINK) $(LFLAGS) /OUT:"$(OUT_DIR)\json_rewrite_test.exe" Debug\grpc_test_util.lib Debug\grpc.lib Debug\gpr_test_util.lib Debug\gpr.lib $(LIBS) $(OUT_DIR)\json_rewrite_test.obj 
@@ -550,7 +549,7 @@ json_rewrite_test: json_rewrite_test.exe
 	echo Running json_rewrite_test
 	$(OUT_DIR)\json_rewrite_test.exe
 
-json_test.exe: grpc_test_util
+json_test.exe: grpc_test_util $(OUT_DIR)
 	echo Building json_test
 	$(CC) $(CFLAGS) /Fo:$(OUT_DIR)\ ..\..\test\core\json\json_test.c 
 	$(LINK) $(LFLAGS) /OUT:"$(OUT_DIR)\json_test.exe" Debug\grpc_test_util.lib Debug\grpc.lib Debug\gpr_test_util.lib Debug\gpr.lib $(LIBS) $(OUT_DIR)\json_test.obj 
@@ -558,7 +557,7 @@ json_test: json_test.exe
 	echo Running json_test
 	$(OUT_DIR)\json_test.exe
 
-lame_client_test.exe: grpc_test_util
+lame_client_test.exe: grpc_test_util $(OUT_DIR)
 	echo Building lame_client_test
 	$(CC) $(CFLAGS) /Fo:$(OUT_DIR)\ ..\..\test\core\surface\lame_client_test.c 
 	$(LINK) $(LFLAGS) /OUT:"$(OUT_DIR)\lame_client_test.exe" Debug\grpc_test_util.lib Debug\grpc.lib Debug\gpr_test_util.lib Debug\gpr.lib $(LIBS) $(OUT_DIR)\lame_client_test.obj 
@@ -566,7 +565,7 @@ lame_client_test: lame_client_test.exe
 	echo Running lame_client_test
 	$(OUT_DIR)\lame_client_test.exe
 
-low_level_ping_pong_benchmark.exe: grpc_test_util
+low_level_ping_pong_benchmark.exe: grpc_test_util $(OUT_DIR)
 	echo Building low_level_ping_pong_benchmark
 	$(CC) $(CFLAGS) /Fo:$(OUT_DIR)\ ..\..\test\core\network_benchmarks\low_level_ping_pong.c 
 	$(LINK) $(LFLAGS) /OUT:"$(OUT_DIR)\low_level_ping_pong_benchmark.exe" Debug\grpc_test_util.lib Debug\grpc.lib Debug\gpr_test_util.lib Debug\gpr.lib $(LIBS) $(OUT_DIR)\low_level_ping_pong.obj 
@@ -574,7 +573,7 @@ low_level_ping_pong_benchmark: low_level_ping_pong_benchmark.exe
 	echo Running low_level_ping_pong_benchmark
 	$(OUT_DIR)\low_level_ping_pong_benchmark.exe
 
-message_compress_test.exe: grpc_test_util
+message_compress_test.exe: grpc_test_util $(OUT_DIR)
 	echo Building message_compress_test
 	$(CC) $(CFLAGS) /Fo:$(OUT_DIR)\ ..\..\test\core\compression\message_compress_test.c 
 	$(LINK) $(LFLAGS) /OUT:"$(OUT_DIR)\message_compress_test.exe" Debug\grpc_test_util.lib Debug\grpc.lib Debug\gpr_test_util.lib Debug\gpr.lib $(LIBS) $(OUT_DIR)\message_compress_test.obj 
@@ -582,7 +581,7 @@ message_compress_test: message_compress_test.exe
 	echo Running message_compress_test
 	$(OUT_DIR)\message_compress_test.exe
 
-metadata_buffer_test.exe: grpc_test_util
+metadata_buffer_test.exe: grpc_test_util $(OUT_DIR)
 	echo Building metadata_buffer_test
 	$(CC) $(CFLAGS) /Fo:$(OUT_DIR)\ ..\..\test\core\channel\metadata_buffer_test.c 
 	$(LINK) $(LFLAGS) /OUT:"$(OUT_DIR)\metadata_buffer_test.exe" Debug\grpc_test_util.lib Debug\grpc.lib Debug\gpr_test_util.lib Debug\gpr.lib $(LIBS) $(OUT_DIR)\metadata_buffer_test.obj 
@@ -590,7 +589,7 @@ metadata_buffer_test: metadata_buffer_test.exe
 	echo Running metadata_buffer_test
 	$(OUT_DIR)\metadata_buffer_test.exe
 
-multi_init_test.exe: grpc_test_util
+multi_init_test.exe: grpc_test_util $(OUT_DIR)
 	echo Building multi_init_test
 	$(CC) $(CFLAGS) /Fo:$(OUT_DIR)\ ..\..\test\core\surface\multi_init_test.c 
 	$(LINK) $(LFLAGS) /OUT:"$(OUT_DIR)\multi_init_test.exe" Debug\grpc_test_util.lib Debug\grpc.lib Debug\gpr_test_util.lib Debug\gpr.lib $(LIBS) $(OUT_DIR)\multi_init_test.obj 
@@ -598,7 +597,7 @@ multi_init_test: multi_init_test.exe
 	echo Running multi_init_test
 	$(OUT_DIR)\multi_init_test.exe
 
-murmur_hash_test.exe: grpc_test_util
+murmur_hash_test.exe: grpc_test_util $(OUT_DIR)
 	echo Building murmur_hash_test
 	$(CC) $(CFLAGS) /Fo:$(OUT_DIR)\ ..\..\test\core\support\murmur_hash_test.c 
 	$(LINK) $(LFLAGS) /OUT:"$(OUT_DIR)\murmur_hash_test.exe" Debug\gpr_test_util.lib Debug\gpr.lib $(LIBS) $(OUT_DIR)\murmur_hash_test.obj 
@@ -606,7 +605,7 @@ murmur_hash_test: murmur_hash_test.exe
 	echo Running murmur_hash_test
 	$(OUT_DIR)\murmur_hash_test.exe
 
-no_server_test.exe: grpc_test_util
+no_server_test.exe: grpc_test_util $(OUT_DIR)
 	echo Building no_server_test
 	$(CC) $(CFLAGS) /Fo:$(OUT_DIR)\ ..\..\test\core\end2end\no_server_test.c 
 	$(LINK) $(LFLAGS) /OUT:"$(OUT_DIR)\no_server_test.exe" Debug\grpc_test_util.lib Debug\grpc.lib Debug\gpr_test_util.lib Debug\gpr.lib $(LIBS) $(OUT_DIR)\no_server_test.obj 
@@ -614,7 +613,7 @@ no_server_test: no_server_test.exe
 	echo Running no_server_test
 	$(OUT_DIR)\no_server_test.exe
 
-poll_kick_posix_test.exe: grpc_test_util
+poll_kick_posix_test.exe: grpc_test_util $(OUT_DIR)
 	echo Building poll_kick_posix_test
 	$(CC) $(CFLAGS) /Fo:$(OUT_DIR)\ ..\..\test\core\iomgr\poll_kick_posix_test.c 
 	$(LINK) $(LFLAGS) /OUT:"$(OUT_DIR)\poll_kick_posix_test.exe" Debug\grpc_test_util.lib Debug\grpc.lib Debug\gpr_test_util.lib Debug\gpr.lib $(LIBS) $(OUT_DIR)\poll_kick_posix_test.obj 
@@ -622,7 +621,7 @@ poll_kick_posix_test: poll_kick_posix_test.exe
 	echo Running poll_kick_posix_test
 	$(OUT_DIR)\poll_kick_posix_test.exe
 
-resolve_address_test.exe: grpc_test_util
+resolve_address_test.exe: grpc_test_util $(OUT_DIR)
 	echo Building resolve_address_test
 	$(CC) $(CFLAGS) /Fo:$(OUT_DIR)\ ..\..\test\core\iomgr\resolve_address_test.c 
 	$(LINK) $(LFLAGS) /OUT:"$(OUT_DIR)\resolve_address_test.exe" Debug\grpc_test_util.lib Debug\grpc.lib Debug\gpr_test_util.lib Debug\gpr.lib $(LIBS) $(OUT_DIR)\resolve_address_test.obj 
@@ -630,7 +629,7 @@ resolve_address_test: resolve_address_test.exe
 	echo Running resolve_address_test
 	$(OUT_DIR)\resolve_address_test.exe
 
-secure_endpoint_test.exe: grpc_test_util
+secure_endpoint_test.exe: grpc_test_util $(OUT_DIR)
 	echo Building secure_endpoint_test
 	$(CC) $(CFLAGS) /Fo:$(OUT_DIR)\ ..\..\test\core\security\secure_endpoint_test.c 
 	$(LINK) $(LFLAGS) /OUT:"$(OUT_DIR)\secure_endpoint_test.exe" Debug\grpc_test_util.lib Debug\grpc.lib Debug\gpr_test_util.lib Debug\gpr.lib $(LIBS) $(OUT_DIR)\secure_endpoint_test.obj 
@@ -638,7 +637,7 @@ secure_endpoint_test: secure_endpoint_test.exe
 	echo Running secure_endpoint_test
 	$(OUT_DIR)\secure_endpoint_test.exe
 
-sockaddr_utils_test.exe: grpc_test_util
+sockaddr_utils_test.exe: grpc_test_util $(OUT_DIR)
 	echo Building sockaddr_utils_test
 	$(CC) $(CFLAGS) /Fo:$(OUT_DIR)\ ..\..\test\core\iomgr\sockaddr_utils_test.c 
 	$(LINK) $(LFLAGS) /OUT:"$(OUT_DIR)\sockaddr_utils_test.exe" Debug\grpc_test_util.lib Debug\grpc.lib Debug\gpr_test_util.lib Debug\gpr.lib $(LIBS) $(OUT_DIR)\sockaddr_utils_test.obj 
@@ -646,7 +645,7 @@ sockaddr_utils_test: sockaddr_utils_test.exe
 	echo Running sockaddr_utils_test
 	$(OUT_DIR)\sockaddr_utils_test.exe
 
-tcp_client_posix_test.exe: grpc_test_util
+tcp_client_posix_test.exe: grpc_test_util $(OUT_DIR)
 	echo Building tcp_client_posix_test
 	$(CC) $(CFLAGS) /Fo:$(OUT_DIR)\ ..\..\test\core\iomgr\tcp_client_posix_test.c 
 	$(LINK) $(LFLAGS) /OUT:"$(OUT_DIR)\tcp_client_posix_test.exe" Debug\grpc_test_util.lib Debug\grpc.lib Debug\gpr_test_util.lib Debug\gpr.lib $(LIBS) $(OUT_DIR)\tcp_client_posix_test.obj 
@@ -654,7 +653,7 @@ tcp_client_posix_test: tcp_client_posix_test.exe
 	echo Running tcp_client_posix_test
 	$(OUT_DIR)\tcp_client_posix_test.exe
 
-tcp_posix_test.exe: grpc_test_util
+tcp_posix_test.exe: grpc_test_util $(OUT_DIR)
 	echo Building tcp_posix_test
 	$(CC) $(CFLAGS) /Fo:$(OUT_DIR)\ ..\..\test\core\iomgr\tcp_posix_test.c 
 	$(LINK) $(LFLAGS) /OUT:"$(OUT_DIR)\tcp_posix_test.exe" Debug\grpc_test_util.lib Debug\grpc.lib Debug\gpr_test_util.lib Debug\gpr.lib $(LIBS) $(OUT_DIR)\tcp_posix_test.obj 
@@ -662,7 +661,7 @@ tcp_posix_test: tcp_posix_test.exe
 	echo Running tcp_posix_test
 	$(OUT_DIR)\tcp_posix_test.exe
 
-tcp_server_posix_test.exe: grpc_test_util
+tcp_server_posix_test.exe: grpc_test_util $(OUT_DIR)
 	echo Building tcp_server_posix_test
 	$(CC) $(CFLAGS) /Fo:$(OUT_DIR)\ ..\..\test\core\iomgr\tcp_server_posix_test.c 
 	$(LINK) $(LFLAGS) /OUT:"$(OUT_DIR)\tcp_server_posix_test.exe" Debug\grpc_test_util.lib Debug\grpc.lib Debug\gpr_test_util.lib Debug\gpr.lib $(LIBS) $(OUT_DIR)\tcp_server_posix_test.obj 
@@ -670,7 +669,7 @@ tcp_server_posix_test: tcp_server_posix_test.exe
 	echo Running tcp_server_posix_test
 	$(OUT_DIR)\tcp_server_posix_test.exe
 
-time_averaged_stats_test.exe: grpc_test_util
+time_averaged_stats_test.exe: grpc_test_util $(OUT_DIR)
 	echo Building time_averaged_stats_test
 	$(CC) $(CFLAGS) /Fo:$(OUT_DIR)\ ..\..\test\core\iomgr\time_averaged_stats_test.c 
 	$(LINK) $(LFLAGS) /OUT:"$(OUT_DIR)\time_averaged_stats_test.exe" Debug\grpc_test_util.lib Debug\grpc.lib Debug\gpr_test_util.lib Debug\gpr.lib $(LIBS) $(OUT_DIR)\time_averaged_stats_test.obj 
@@ -678,7 +677,7 @@ time_averaged_stats_test: time_averaged_stats_test.exe
 	echo Running time_averaged_stats_test
 	$(OUT_DIR)\time_averaged_stats_test.exe
 
-time_test.exe: grpc_test_util
+time_test.exe: grpc_test_util $(OUT_DIR)
 	echo Building time_test
 	$(CC) $(CFLAGS) /Fo:$(OUT_DIR)\ ..\..\test\core\support\time_test.c 
 	$(LINK) $(LFLAGS) /OUT:"$(OUT_DIR)\time_test.exe" Debug\grpc_test_util.lib Debug\grpc.lib Debug\gpr_test_util.lib Debug\gpr.lib $(LIBS) $(OUT_DIR)\time_test.obj 
@@ -686,7 +685,7 @@ time_test: time_test.exe
 	echo Running time_test
 	$(OUT_DIR)\time_test.exe
 
-timeout_encoding_test.exe: grpc_test_util
+timeout_encoding_test.exe: grpc_test_util $(OUT_DIR)
 	echo Building timeout_encoding_test
 	$(CC) $(CFLAGS) /Fo:$(OUT_DIR)\ ..\..\test\core\transport\chttp2\timeout_encoding_test.c 
 	$(LINK) $(LFLAGS) /OUT:"$(OUT_DIR)\timeout_encoding_test.exe" Debug\grpc_test_util.lib Debug\grpc.lib Debug\gpr_test_util.lib Debug\gpr.lib $(LIBS) $(OUT_DIR)\timeout_encoding_test.obj 
@@ -694,7 +693,7 @@ timeout_encoding_test: timeout_encoding_test.exe
 	echo Running timeout_encoding_test
 	$(OUT_DIR)\timeout_encoding_test.exe
 
-transport_metadata_test.exe: grpc_test_util
+transport_metadata_test.exe: grpc_test_util $(OUT_DIR)
 	echo Building transport_metadata_test
 	$(CC) $(CFLAGS) /Fo:$(OUT_DIR)\ ..\..\test\core\transport\metadata_test.c 
 	$(LINK) $(LFLAGS) /OUT:"$(OUT_DIR)\transport_metadata_test.exe" Debug\grpc_test_util.lib Debug\grpc.lib Debug\gpr_test_util.lib Debug\gpr.lib $(LIBS) $(OUT_DIR)\metadata_test.obj 
@@ -702,7 +701,7 @@ transport_metadata_test: transport_metadata_test.exe
 	echo Running transport_metadata_test
 	$(OUT_DIR)\transport_metadata_test.exe
 
-transport_security_test.exe: grpc_test_util
+transport_security_test.exe: grpc_test_util $(OUT_DIR)
 	echo Building transport_security_test
 	$(CC) $(CFLAGS) /Fo:$(OUT_DIR)\ ..\..\test\core\tsi\transport_security_test.c 
 	$(LINK) $(LFLAGS) /OUT:"$(OUT_DIR)\transport_security_test.exe" Debug\grpc_test_util.lib Debug\grpc.lib Debug\gpr_test_util.lib Debug\gpr.lib $(LIBS) $(OUT_DIR)\transport_security_test.obj 
diff --git a/vsprojects/vs2013/gpr.vcxproj b/vsprojects/vs2013/gpr.vcxproj
index e0fa68e03512411e4dcff64aef02af0ea5417a99..1876c0ff0a51145d9f9dfb05a1b617a622eb0a33 100644
--- a/vsprojects/vs2013/gpr.vcxproj
+++ b/vsprojects/vs2013/gpr.vcxproj
@@ -99,6 +99,10 @@
     <ClInclude Include="..\..\include\grpc\support\sync_win32.h" />
     <ClInclude Include="..\..\include\grpc\support\thd.h" />
     <ClInclude Include="..\..\include\grpc\support\time.h" />
+    <ClInclude Include="..\..\include\grpc\support\tls.h" />
+    <ClInclude Include="..\..\include\grpc\support\tls_gcc.h" />
+    <ClInclude Include="..\..\include\grpc\support\tls_msvc.h" />
+    <ClInclude Include="..\..\include\grpc\support\tls_pthread.h" />
     <ClInclude Include="..\..\include\grpc\support\useful.h" />
   </ItemGroup>
   <ItemGroup>
diff --git a/vsprojects/vs2013/gpr.vcxproj.filters b/vsprojects/vs2013/gpr.vcxproj.filters
index 1f8794441ba5138f68017d9db3f64b7e804f4ae0..13fdb3fef84549df8a9da8b0b01db03702f757d2 100644
--- a/vsprojects/vs2013/gpr.vcxproj.filters
+++ b/vsprojects/vs2013/gpr.vcxproj.filters
@@ -171,6 +171,18 @@
     <ClInclude Include="..\..\include\grpc\support\time.h">
       <Filter>include\grpc\support</Filter>
     </ClInclude>
+    <ClInclude Include="..\..\include\grpc\support\tls.h">
+      <Filter>include\grpc\support</Filter>
+    </ClInclude>
+    <ClInclude Include="..\..\include\grpc\support\tls_gcc.h">
+      <Filter>include\grpc\support</Filter>
+    </ClInclude>
+    <ClInclude Include="..\..\include\grpc\support\tls_msvc.h">
+      <Filter>include\grpc\support</Filter>
+    </ClInclude>
+    <ClInclude Include="..\..\include\grpc\support\tls_pthread.h">
+      <Filter>include\grpc\support</Filter>
+    </ClInclude>
     <ClInclude Include="..\..\include\grpc\support\useful.h">
       <Filter>include\grpc\support</Filter>
     </ClInclude>
diff --git a/vsprojects/vs2013/grpc++.vcxproj b/vsprojects/vs2013/grpc++.vcxproj
index d545a949cb3090e326848d54b88fb7f46a2ddd03..dff588166b19712404712373a94c46f8e6fd4c67 100644
--- a/vsprojects/vs2013/grpc++.vcxproj
+++ b/vsprojects/vs2013/grpc++.vcxproj
@@ -95,6 +95,12 @@
     <ClInclude Include="..\..\include\grpc++\impl\rpc_method.h" />
     <ClInclude Include="..\..\include\grpc++\impl\rpc_service_method.h" />
     <ClInclude Include="..\..\include\grpc++\impl\service_type.h" />
+    <ClInclude Include="..\..\include\grpc++\impl\sync.h" />
+    <ClInclude Include="..\..\include\grpc++\impl\sync_cxx11.h" />
+    <ClInclude Include="..\..\include\grpc++\impl\sync_no_cxx11.h" />
+    <ClInclude Include="..\..\include\grpc++\impl\thd.h" />
+    <ClInclude Include="..\..\include\grpc++\impl\thd_cxx11.h" />
+    <ClInclude Include="..\..\include\grpc++\impl\thd_no_cxx11.h" />
     <ClInclude Include="..\..\include\grpc++\server.h" />
     <ClInclude Include="..\..\include\grpc++\server_builder.h" />
     <ClInclude Include="..\..\include\grpc++\server_context.h" />
@@ -106,6 +112,8 @@
     <ClInclude Include="..\..\include\grpc++\thread_pool_interface.h" />
   </ItemGroup>
   <ItemGroup>
+    <ClInclude Include="..\..\src\cpp\client\secure_credentials.h" />
+    <ClInclude Include="..\..\src\cpp\server\secure_server_credentials.h" />
     <ClInclude Include="..\..\src\cpp\client\channel.h" />
     <ClInclude Include="..\..\src\cpp\proto\proto_utils.h" />
     <ClInclude Include="..\..\src\cpp\server\thread_pool.h" />
diff --git a/vsprojects/vs2013/grpc++.vcxproj.filters b/vsprojects/vs2013/grpc++.vcxproj.filters
index ed93daee0441d19170e0c6cfb07c202089f107ee..6466a0fa26e523fe65de1185fb678edabc8e8432 100644
--- a/vsprojects/vs2013/grpc++.vcxproj.filters
+++ b/vsprojects/vs2013/grpc++.vcxproj.filters
@@ -132,6 +132,24 @@
     <ClInclude Include="..\..\include\grpc++\impl\service_type.h">
       <Filter>include\grpc++\impl</Filter>
     </ClInclude>
+    <ClInclude Include="..\..\include\grpc++\impl\sync.h">
+      <Filter>include\grpc++\impl</Filter>
+    </ClInclude>
+    <ClInclude Include="..\..\include\grpc++\impl\sync_cxx11.h">
+      <Filter>include\grpc++\impl</Filter>
+    </ClInclude>
+    <ClInclude Include="..\..\include\grpc++\impl\sync_no_cxx11.h">
+      <Filter>include\grpc++\impl</Filter>
+    </ClInclude>
+    <ClInclude Include="..\..\include\grpc++\impl\thd.h">
+      <Filter>include\grpc++\impl</Filter>
+    </ClInclude>
+    <ClInclude Include="..\..\include\grpc++\impl\thd_cxx11.h">
+      <Filter>include\grpc++\impl</Filter>
+    </ClInclude>
+    <ClInclude Include="..\..\include\grpc++\impl\thd_no_cxx11.h">
+      <Filter>include\grpc++\impl</Filter>
+    </ClInclude>
     <ClInclude Include="..\..\include\grpc++\server.h">
       <Filter>include\grpc++</Filter>
     </ClInclude>
@@ -161,6 +179,12 @@
     </ClInclude>
   </ItemGroup>
   <ItemGroup>
+    <ClInclude Include="..\..\src\cpp\client\secure_credentials.h">
+      <Filter>src\cpp\client</Filter>
+    </ClInclude>
+    <ClInclude Include="..\..\src\cpp\server\secure_server_credentials.h">
+      <Filter>src\cpp\server</Filter>
+    </ClInclude>
     <ClInclude Include="..\..\src\cpp\client\channel.h">
       <Filter>src\cpp\client</Filter>
     </ClInclude>
diff --git a/vsprojects/vs2013/grpc.vcxproj b/vsprojects/vs2013/grpc.vcxproj
index a88eb34ab8892a47000ab583260715146b7911d1..cb87334eab67f63481b744b8ebe560ff1dfeb437 100644
--- a/vsprojects/vs2013/grpc.vcxproj
+++ b/vsprojects/vs2013/grpc.vcxproj
@@ -272,6 +272,8 @@
     </ClCompile>
     <ClCompile Include="..\..\src\core\iomgr\endpoint_pair_posix.c">
     </ClCompile>
+    <ClCompile Include="..\..\src\core\iomgr\endpoint_pair_windows.c">
+    </ClCompile>
     <ClCompile Include="..\..\src\core\iomgr\fd_posix.c">
     </ClCompile>
     <ClCompile Include="..\..\src\core\iomgr\iocp_windows.c">
diff --git a/vsprojects/vs2013/grpc.vcxproj.filters b/vsprojects/vs2013/grpc.vcxproj.filters
index 20dbe8c444f65b7b702adc357d380b352d5c5459..a010639ad1333cf6b4acdf89176a65a731233cc3 100644
--- a/vsprojects/vs2013/grpc.vcxproj.filters
+++ b/vsprojects/vs2013/grpc.vcxproj.filters
@@ -124,6 +124,9 @@
     <ClCompile Include="..\..\src\core\iomgr\endpoint_pair_posix.c">
       <Filter>src\core\iomgr</Filter>
     </ClCompile>
+    <ClCompile Include="..\..\src\core\iomgr\endpoint_pair_windows.c">
+      <Filter>src\core\iomgr</Filter>
+    </ClCompile>
     <ClCompile Include="..\..\src\core\iomgr\fd_posix.c">
       <Filter>src\core\iomgr</Filter>
     </ClCompile>
diff --git a/vsprojects/vs2013/grpc_test_util.vcxproj b/vsprojects/vs2013/grpc_test_util.vcxproj
index 4756f539289169b659b626de5b41d3e3ae447cb1..d25fd7cbf153ac64324f29b7f13c23af12f1a161 100644
--- a/vsprojects/vs2013/grpc_test_util.vcxproj
+++ b/vsprojects/vs2013/grpc_test_util.vcxproj
@@ -98,6 +98,8 @@
     </ClCompile>
     <ClCompile Include="..\..\test\core\util\port_posix.c">
     </ClCompile>
+    <ClCompile Include="..\..\test\core\util\port_windows.c">
+    </ClCompile>
     <ClCompile Include="..\..\test\core\util\slice_splitter.c">
     </ClCompile>
   </ItemGroup>
diff --git a/vsprojects/vs2013/grpc_unsecure.vcxproj b/vsprojects/vs2013/grpc_unsecure.vcxproj
index 98c14c2fdb498dedce20d2cb382ef3fbc15c76ff..098ce340c1105b175bf80ce8e32ef30a0b9010e8 100644
--- a/vsprojects/vs2013/grpc_unsecure.vcxproj
+++ b/vsprojects/vs2013/grpc_unsecure.vcxproj
@@ -216,6 +216,8 @@
     </ClCompile>
     <ClCompile Include="..\..\src\core\iomgr\endpoint_pair_posix.c">
     </ClCompile>
+    <ClCompile Include="..\..\src\core\iomgr\endpoint_pair_windows.c">
+    </ClCompile>
     <ClCompile Include="..\..\src\core\iomgr\fd_posix.c">
     </ClCompile>
     <ClCompile Include="..\..\src\core\iomgr\iocp_windows.c">
diff --git a/vsprojects/vs2013/grpc_unsecure.vcxproj.filters b/vsprojects/vs2013/grpc_unsecure.vcxproj.filters
index 4b758d61132ff7371c8c4874c31359702218fa9e..7757a44aecb92d5f5d2bfcbfecd39e809e6acb98 100644
--- a/vsprojects/vs2013/grpc_unsecure.vcxproj.filters
+++ b/vsprojects/vs2013/grpc_unsecure.vcxproj.filters
@@ -64,6 +64,9 @@
     <ClCompile Include="..\..\src\core\iomgr\endpoint_pair_posix.c">
       <Filter>src\core\iomgr</Filter>
     </ClCompile>
+    <ClCompile Include="..\..\src\core\iomgr\endpoint_pair_windows.c">
+      <Filter>src\core\iomgr</Filter>
+    </ClCompile>
     <ClCompile Include="..\..\src\core\iomgr\fd_posix.c">
       <Filter>src\core\iomgr</Filter>
     </ClCompile>