diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 03d2e276a825e33e9cc348b64f74afcf419731de..b4e958d3b2a841ae8a49c347c6159ad6b4ce697d 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -21,6 +21,15 @@ In order to run all of the tests we provide, you will need valgrind and clang.
 More specifically, under debian, you will need the package libc++-dev to
 properly run all the tests.
 
+Compiling and running grpc C++ tests depend on protobuf 3.0.0, gtest and gflags.
+Although gflags is provided in third_party, you will need to manually install
+that dependency on your system to run these tests. Under a Debian or Ubuntu
+system, you can install the gtests and gflags packages using apt-get:
+
+```sh
+ $ [sudo] apt-get install libgflags-dev libgtest-dev
+```
+
 If you are planning to work on any of the languages other than C and C++, you
 will also need their appropriate development environments.
 
@@ -36,9 +45,13 @@ In order to run most of the available tests, one would need to run:
 
 `./tools/run_tests/run_tests.py`
 
-If you want to run all the possible tests for any of the languages {c, c++, node, php, python}, do this:
+If you want to run tests for any of the languages {c, c++, csharp, node, objc, php, python, ruby}, do this:
+
+`./tools/run_tests/run_tests.py -l <lang>`
+
+To know about the list of available commands, do this:
 
-`./tools/run_tests/run_tests.py -l <lang> -c all`
+`./tools/run_tests/run_tests.py -h`
 
 ## Adding or removing source code
 
diff --git a/INSTALL.md b/INSTALL.md
index d9411db021d5784771951d06fdd13070b7fcf449..454a8b7b2fdf68590fe77e15a9b3d1c6ea7ccc08 100644
--- a/INSTALL.md
+++ b/INSTALL.md
@@ -3,7 +3,7 @@
 For language-specific installation instructions for gRPC runtime, please
 refer to these documents
 
- * [C++](examples/cpp)
+ * [C++](examples/cpp): Currently to install gRPC for C++, you need to build from source as described below.
  * [C#](src/csharp): NuGet package `Grpc`
  * [Go](https://github.com/grpc/grpc-go): `go get google.golang.org/grpc`
  * [Java](https://github.com/grpc/grpc-java)
@@ -32,6 +32,17 @@ terminal:
  $ [sudo] xcode-select --install
 ```
 
+##Protoc
+
+By default gRPC uses [protocol buffers](https://github.com/google/protobuf),
+you will need the `protoc` compiler to generate stub server and client code.
+
+If you compile gRPC from source, as described below, the Makefile will
+automatically try and compile the `protoc` in third_party if you cloned the
+repository recursively and it detects that you don't already have it
+installed.
+
+
 #Build from Source
 
 For developers who are interested to contribute, here is how to compile the
diff --git a/Makefile b/Makefile
index 5be0d146afc88f7e5c7dfc129fadd3a3a1da5ffb..171a83c2a3a111d039647d8b65e970dd63b0fbd2 100644
--- a/Makefile
+++ b/Makefile
@@ -849,6 +849,7 @@ chttp2_status_conversion_test: $(BINDIR)/$(CONFIG)/chttp2_status_conversion_test
 chttp2_stream_map_test: $(BINDIR)/$(CONFIG)/chttp2_stream_map_test
 chttp2_varint_test: $(BINDIR)/$(CONFIG)/chttp2_varint_test
 compression_test: $(BINDIR)/$(CONFIG)/compression_test
+dns_resolver_connectivity_test: $(BINDIR)/$(CONFIG)/dns_resolver_connectivity_test
 dns_resolver_test: $(BINDIR)/$(CONFIG)/dns_resolver_test
 dualstack_socket_test: $(BINDIR)/$(CONFIG)/dualstack_socket_test
 endpoint_pair_test: $(BINDIR)/$(CONFIG)/endpoint_pair_test
@@ -1159,6 +1160,7 @@ buildtests_c: privatelibs_c \
   $(BINDIR)/$(CONFIG)/chttp2_stream_map_test \
   $(BINDIR)/$(CONFIG)/chttp2_varint_test \
   $(BINDIR)/$(CONFIG)/compression_test \
+  $(BINDIR)/$(CONFIG)/dns_resolver_connectivity_test \
   $(BINDIR)/$(CONFIG)/dns_resolver_test \
   $(BINDIR)/$(CONFIG)/dualstack_socket_test \
   $(BINDIR)/$(CONFIG)/endpoint_pair_test \
@@ -1402,6 +1404,8 @@ test_c: buildtests_c
 	$(Q) $(BINDIR)/$(CONFIG)/chttp2_varint_test || ( echo test chttp2_varint_test failed ; exit 1 )
 	$(E) "[RUN]     Testing compression_test"
 	$(Q) $(BINDIR)/$(CONFIG)/compression_test || ( echo test compression_test failed ; exit 1 )
+	$(E) "[RUN]     Testing dns_resolver_connectivity_test"
+	$(Q) $(BINDIR)/$(CONFIG)/dns_resolver_connectivity_test || ( echo test dns_resolver_connectivity_test failed ; exit 1 )
 	$(E) "[RUN]     Testing dns_resolver_test"
 	$(Q) $(BINDIR)/$(CONFIG)/dns_resolver_test || ( echo test dns_resolver_test failed ; exit 1 )
 	$(E) "[RUN]     Testing dualstack_socket_test"
@@ -6075,6 +6079,38 @@ endif
 endif
 
 
+DNS_RESOLVER_CONNECTIVITY_TEST_SRC = \
+    test/core/client_config/resolvers/dns_resolver_connectivity_test.c \
+
+DNS_RESOLVER_CONNECTIVITY_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(DNS_RESOLVER_CONNECTIVITY_TEST_SRC))))
+ifeq ($(NO_SECURE),true)
+
+# You can't build secure targets if you don't have OpenSSL.
+
+$(BINDIR)/$(CONFIG)/dns_resolver_connectivity_test: openssl_dep_error
+
+else
+
+
+
+$(BINDIR)/$(CONFIG)/dns_resolver_connectivity_test: $(DNS_RESOLVER_CONNECTIVITY_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
+	$(E) "[LD]      Linking $@"
+	$(Q) mkdir -p `dirname $@`
+	$(Q) $(LD) $(LDFLAGS) $(DNS_RESOLVER_CONNECTIVITY_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBS) $(LDLIBS_SECURE) -o $(BINDIR)/$(CONFIG)/dns_resolver_connectivity_test
+
+endif
+
+$(OBJDIR)/$(CONFIG)/test/core/client_config/resolvers/dns_resolver_connectivity_test.o:  $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
+
+deps_dns_resolver_connectivity_test: $(DNS_RESOLVER_CONNECTIVITY_TEST_OBJS:.o=.dep)
+
+ifneq ($(NO_SECURE),true)
+ifneq ($(NO_DEPS),true)
+-include $(DNS_RESOLVER_CONNECTIVITY_TEST_OBJS:.o=.dep)
+endif
+endif
+
+
 DNS_RESOLVER_TEST_SRC = \
     test/core/client_config/resolvers/dns_resolver_test.c \
 
diff --git a/build.yaml b/build.yaml
index a277539a054b9ef85fc52924c6d70e132787f665..e003dd83396d77779215382dac6c717f44e8f378 100644
--- a/build.yaml
+++ b/build.yaml
@@ -1057,6 +1057,17 @@ targets:
   - grpc
   - gpr_test_util
   - gpr
+- name: dns_resolver_connectivity_test
+  cpu_cost: 0.1
+  build: test
+  language: c
+  src:
+  - test/core/client_config/resolvers/dns_resolver_connectivity_test.c
+  deps:
+  - grpc_test_util
+  - grpc
+  - gpr_test_util
+  - gpr
 - name: dns_resolver_test
   build: test
   language: c
diff --git a/composer.json b/composer.json
index 61f81e02bf4bdda922a4d1237d4e7017b7c259f8..97b1a5cb49bfd7621ce324db30a41581f5581e0e 100644
--- a/composer.json
+++ b/composer.json
@@ -2,13 +2,20 @@
   "name": "grpc/grpc",
   "type": "library",
   "description": "gRPC library for PHP",
-  "version": "0.6.0",
+  "version": "0.14.0",
   "keywords": ["rpc"],
   "homepage": "http://grpc.io",
   "license": "BSD-3-Clause",
+  "repositories": [
+    {
+      "type": "vcs",
+      "url": "https://github.com/stanley-cheung/Protobuf-PHP"
+    }
+  ],
   "require": {
     "php": ">=5.5.0",
-    "google/auth": "dev-master"
+    "datto/protobuf-php": "dev-master",
+    "google/auth": "v0.7"
   },
   "autoload": {
     "psr-4": {
diff --git a/examples/README.md b/examples/README.md
index cd85417ca202d41c47e155a539d9284185363b0e..287a80266c92d5de832d3fed34341110882e2468 100644
--- a/examples/README.md
+++ b/examples/README.md
@@ -1,450 +1,27 @@
+# Examples
 
-# Getting started
+This directory contains code examples for all the C-based gRPC implementations: C++, Node.js, Python, Ruby, Objective-C, PHP, and C#. You can find examples and instructions specific to your
+favourite language in the relevant subdirectory.
+
+Examples for Go and Java gRPC live in their own repositories:
 
-Welcome to the developer documentation for gRPC, a language-neutral,
-platform-neutral remote procedure call (RPC) system developed at Google.
+* [Java](https://github.com/grpc/grpc-java/tree/master/examples)
+* [Android Java](https://github.com/grpc/grpc-java/tree/master/examples/android)
+* [Go](https://github.com/grpc/grpc-go/tree/master/examples)
 
-This document introduces you to gRPC with a quick overview and a simple
-Hello World example. You'll find more tutorials and reference docs in this repository - more documentation is coming soon!
+For more comprehensive documentation, including an [overview](http://www.grpc.io/docs/) and tutorials that use this example code, visit [grpc.io](http://www.grpc.io/docs/).
 
-<a name="quickstart"></a>
 ## Quick start
-You can find quick start guides for each language, including installation instructions, examples, and tutorials here:
+
+Each example directory has quick start instructions for the appropriate language, including installation instructions and how to run our simplest Hello World example:
+
 * [C++](cpp)
-* [Java](https://github.com/grpc/grpc-java/tree/master/examples)
-* [Go](https://github.com/grpc/grpc-go/tree/master/examples)
 * [Ruby](ruby)
 * [Node.js](node)
-* [Android Java](https://github.com/grpc/grpc-java/tree/master/examples/android)
 * [Python](python/helloworld)
 * [C#](csharp)
 * [Objective-C](objective-c/helloworld)
 * [PHP](php)
 
-## What's in this repository?
-
-The `examples` directory contains documentation, resources, and examples
-for all gRPC users. You can find examples and instructions specific to your
-favourite language in the relevant subdirectory.
-
-You can find out about the gRPC source code repositories in
-[`grpc`](https://github.com/grpc/grpc). Each repository provides instructions
-for building the appropriate libraries for your language.
-
-
-## What is gRPC?
-
-In gRPC a *client* application can directly call
-methods on a *server* application on a different machine as if it was a
-local object, making it easier for you to create distributed applications and
-services. As in many RPC systems, gRPC is based around the idea of defining
-a *service*, specifying the methods that can be called remotely with their
-parameters and return types. On the server side, the server implements this
-interface and runs a gRPC server to handle client calls. On the client side,
-the client has a *stub* that provides exactly the same methods as the server.
-
-<!--TODO: diagram-->
-
-gRPC clients and servers can run and talk to each other in a variety of
-environments - from servers inside Google to your own desktop - and can
-be written in any of gRPC's [supported languages](#quickstart). So, for
-example, you can easily create a gRPC server in Java with clients in Go,
-Python, or Ruby. In addition, the latest Google APIs will have gRPC versions
-of their interfaces, letting you easily build Google functionality into
-your applications.
-
-<a name="protocolbuffers"></a>
-### Working with protocol buffers
-
-By default gRPC uses *protocol buffers*, Google’s
-mature open source mechanism for serializing structured data (although it
-can be used with other data formats such as JSON). As you'll
-see in our example below, you define gRPC services using *proto files*,
-with method parameters and return types specified as protocol buffer message
-types. You
-can find out lots more about protocol buffers in the [Protocol Buffers
-documentation](https://developers.google.com/protocol-buffers/docs/overview).
-
-#### Protocol buffer versions
-
-While protocol buffers have been available for open source users for some
-time, our examples use a new flavour of protocol buffers called proto3,
-which has a slightly simplified syntax, some useful new features, and supports
-lots more languages. This is currently available as an alpha release in
-Java, C++, Java_nano (Android Java), Python, and Ruby from [the protocol buffers Github
-repo](https://github.com/google/protobuf/releases), as well as a Go language
-generator from [the golang/protobuf Github repo](https://github.com/golang/protobuf), with more languages in development. You can find out more in the [proto3 language guide](https://developers.google.com/protocol-buffers/docs/proto3), and see
-the major differences from the current default version in the [release notes](https://github.com/google/protobuf/releases). More proto3 documentation is coming soon.
-
-In general, while you *can* use proto2 (the current default protocol buffers version), we recommend that you use proto3 with gRPC as it lets you use the full range of gRPC-supported languages, as well as avoiding compatibility
-issues with proto2 clients talking to proto3 servers and vice versa.
-
-<a name="hello"></a>
-## Hello gRPC!
-
-Now that you know a bit more about gRPC, the easiest way to see how it
-works is to look at a simple example. Our Hello World walks you through the
-construction of a simple gRPC client-server application, showing you how to:
-
-- Create a protocol buffers schema that defines a simple RPC service with
-a single
-Hello World method.
-- Create a Java server that implements this interface.
-- Create a Java client that accesses the Java server.
-- Create a Go client that accesses
-the same Java server.
-
-The complete code for the example is available in the `examples`
-directory. We use the Git versioning system for source code management:
-however, you don't need to know anything about Git to follow along other
-than how to install and run a few git commands.
-
-This is an introductory example rather than a comprehensive tutorial, so
-don't worry if you're not a Go or
-Java developer - the concepts are similar for all languages, and you can
-find more implementations of our Hello World example in other languages (and full tutorials where available) in
-the [language-specific folders](#quickstart) in this repository. Complete tutorials and
-reference documentation for all gRPC languages are coming soon.
-
-<a name="setup"></a>
-### Setup
-
-This section explains how to set up your local machine to work with
-the example code. If you just want to read the example, you can go straight
-to the [next step](#servicedef).
-
-#### Install Git
-
-You can download and install Git from http://git-scm.com/download. Once
-installed you should have access to the git command line tool. The main
-commands that you will need to use are:
-
-- git clone ... : clone a remote repository onto your local machine
-- git checkout ... : check out a particular branch or a tagged version of
-the code to hack on
-
-#### Install gRPC
-
-To build and install gRPC plugins and related tools:
-- For Java, see the [Java quick start](https://github.com/grpc/grpc-java).
-- For Go, see the [Go quick start](https://github.com/grpc/grpc-go).
-
-#### Get the source code
-
-The example code for our Java example lives in the `grpc-java`
-GitHub repository. Clone this repository to your local machine by running the
-following command:
-
-
-```
-git clone https://github.com/grpc/grpc-java.git
-```
-
-Change your current directory to grpc-java/examples
-
-```
-cd grpc-java/examples
-```
-
-
-
-<a name="servicedef"></a>
-### Defining a service
-
-The first step in creating our example is to define a *service*: an RPC
-service specifies the methods that can be called remotely with their parameters
-and return types. As you saw in the
-[overview](#protocolbuffers) above, gRPC does this using [protocol
-buffers](https://developers.google.com/protocol-buffers/docs/overview). We
-use the protocol buffers interface definition language (IDL) to define our
-service methods, and define the parameters and return
-types as protocol buffer message types. Both the client and the
-server use interface code generated from the service definition.
-
-Here's our example service definition, defined using protocol buffers IDL in
-[helloworld.proto](https://github.com/grpc/grpc-java/tree/master/examples/src/main/proto). The `Greeter`
-service has one method, `SayHello`, that lets the server receive a single
-`HelloRequest`
-message from the remote client containing the user's name, then send back
-a greeting in a single `HelloReply`. This is the simplest type of RPC you
-can specify in gRPC - you can find out about other types in the tutorial for your chosen language.
-
-```proto
-syntax = "proto3";
-
-option java_package = "io.grpc.examples";
-
-package helloworld;
-
-// The greeter service definition.
-service Greeter {
-  // Sends a greeting
-  rpc SayHello (HelloRequest) returns (HelloReply) {}
-}
-
-// The request message containing the user's name.
-message HelloRequest {
-  string name = 1;
-}
-
-// The response message containing the greetings
-message HelloReply {
-  string message = 1;
-}
-
-```
-
-<a name="generating"></a>
-### Generating gRPC code
-
-Once we've defined our service, we use the protocol buffer compiler
-`protoc` to generate the special client and server code we need to create
-our application - right now we're going to generate Java code, though you
-can generate gRPC code in any gRPC-supported language (as you'll see later
-in this example). The generated code contains both stub code for clients to
-use and an abstract interface for servers to implement, both with the method
-defined in our `Greeter` service.
-
-(If you didn't install the gRPC plugins and protoc on your system and are just reading along with
-the example, you can skip this step and move
-onto the next one where we examine the generated code.)
-
-For simplicity, we've provided a [Gradle build file](https://github.com/grpc/grpc-java/blob/master/examples/build.gradle) with our Java examples that runs `protoc` for you with the appropriate plugin, input, and output:
-
-```shell
-../gradlew build
-```
-
-This generates the following classes from our .proto, which contain all the generated code
-we need to create our example:
-
-- `Helloworld.java`, which
-has all the protocol buffer code to populate, serialize, and retrieve our
-`HelloRequest` and `HelloReply` message types
-- `GreeterGrpc.java`, which contains (along with some other useful code):
-    - an interface for `Greeter` servers to implement
-
-    ```java
-  public static interface Greeter {
-      public void sayHello(io.grpc.examples.Helloworld.HelloRequest request,
-          io.grpc.stub.StreamObserver<io.grpc.examples.Helloworld.HelloReply> responseObserver);
-  }
-    ```
-
-    - _stub_ classes that clients can use to talk to a `Greeter` server. As you can see, they also implement the `Greeter` interface.
-
-  ```java
-  public static class GreeterStub extends
-      io.grpc.stub.AbstractStub<GreeterStub, GreeterServiceDescriptor>
-      implements Greeter {
-   ...
-  }
-  ```
-
-<a name="server"></a>
-### Writing a server
-
-Now let's write some code! First we'll create a server application to implement
-our service. Note that we're not going to go into a lot of detail about how
-to create a server in this section. More detailed information will be in the
-tutorial for your chosen language: check if there's one available yet in the relevant [quick start](#quickstart).
-
-Our server application has two classes:
-
-- a main server class that hosts the service implementation and allows access over the
-network: [HelloWorldServer.java](https://github.com/grpc/grpc-java/blob/master/examples/src/main/java/io/grpc/examples/helloworld/HelloWorldServer.java).
-
-
-- a simple service implementation class [GreeterImpl.java](https://github.com/grpc/grpc-java/blob/master/examples/src/main/java/io/grpc/examples/helloworld/HelloWorldServer.java#L51).
-
-
-#### Service implementation
-
-[GreeterImpl.java](https://github.com/grpc/grpc-java/blob/master/examples/src/main/java/io/grpc/examples/helloworld/HelloWorldServer.java#L51)
-actually implements our `Greeter` service's required behaviour.
-
-As you can see, the class `GreeterImpl` implements the interface
-`GreeterGrpc.Greeter` that we [generated](#generating) from our proto
-[IDL](https://github.com/grpc/grpc-java/tree/master/examples/src/main/proto) by implementing the method `sayHello`:
-
-```java
-    @Override
-    public void sayHello(HelloRequest req, StreamObserver<HelloReply> responseObserver) {
-      HelloReply reply = HelloReply.newBuilder().setMessage("Hello " + req.getName()).build();
-      responseObserver.onValue(reply);
-      responseObserver.onCompleted();
-    }
-```
-- `sayHello` takes two parameters:
-    - `HelloRequest`: the request
-    - `StreamObserver<HelloReply>`: a response observer, which is
-    a special interface for the server to call with its response
-
-To return our response to the client and complete the call:
-
-1. We construct and populate a `HelloReply` response object with our exciting
-message, as specified in our interface definition.
-2. We return the `HelloReply` to the client and then specify that we've finished dealing with the RPC.
-
-
-#### Server implementation
-
-[HelloWorldServer.java](https://github.com/grpc/grpc-java/blob/master/examples/src/main/java/io/grpc/examples/helloworld/HelloWorldServer.java)
-shows the other main feature required to provide a gRPC service; making the service
-implementation available from the network.
-
-```java
-  /* The port on which the server should run */
-  private int port = 50051;
-  private ServerImpl server;
-
-  private void start() throws Exception {
-    server = NettyServerBuilder.forPort(port)
-        .addService(GreeterGrpc.bindService(new GreeterImpl()))
-        .build().start();
-    logger.info("Server started, listening on " + port);
-    Runtime.getRuntime().addShutdownHook(new Thread() {
-      @Override
-      public void run() {
-        // Use stderr here since the logger may have been reset by its JVM shutdown hook.
-        System.err.println("*** shutting down gRPC server since JVM is shutting down");
-        HelloWorldServer.this.stop();
-        System.err.println("*** server shut down");
-      }
-    });
-  }
-
-```
-
-Here we create an appropriate gRPC server, binding the `Greeter` service
-implementation that we created to a port. Then we start the server running: the server is now ready to receive
-requests from `Greeter` service clients on our specified port. We'll cover
-how all this works in a bit more detail in our language-specific documentation.
-
-<a name="client"></a>
-### Writing a client
-
-Client-side gRPC is pretty simple. In this step, we'll use the generated code
-to write a simple client that can access the `Greeter` server we created
-in the [previous section](#server). You can see the complete client code in
-[HelloWorldClient.java](https://github.com/grpc/grpc-java/blob/master/examples/src/main/java/io/grpc/examples/helloworld/HelloWorldClient.java).
-
-Again, we're not going to go into much detail about how to implement a client;
-we'll leave that for the tutorial.
-
-#### Connecting to the service
-
-First let's look at how we connect to the `Greeter` server. First we need
-to create a gRPC channel, specifying the hostname and port of the server we
-want to connect to. Then we use the channel to construct the stub instance.
-
-
-```java
-  private final ChannelImpl channel;
-  private final GreeterGrpc.GreeterBlockingStub blockingStub;
-
-  public HelloWorldClient(String host, int port) {
-    channel =
-        NettyChannelBuilder.forAddress(host, port).negotiationType(NegotiationType.PLAINTEXT)
-            .build();
-    blockingStub = GreeterGrpc.newBlockingStub(channel);
-  }
-
-```
-
-In this case, we create a blocking stub. This means that the RPC call waits
-for the server to respond, and will either return a response or raise an
-exception. gRPC Java has other kinds of stubs that make non-blocking calls
-to the server, where the response is returned asynchronously.
-
-#### Calling an RPC
-
-Now we can contact the service and obtain a greeting:
-
-1. We construct and fill in a `HelloRequest` to send to the service.
-2. We call the stub's `hello()` RPC with our request and get a `HelloReply`
-back, from which we can get our greeting.
-
-
-```java
-    HelloRequest req = HelloRequest.newBuilder().setName(name).build();
-    HelloReply reply = blockingStub.sayHello(req);
-
-```
-
-<a name="run"></a>
-### Try it out!
-
-Our [Gradle build file](https://github.com/grpc/grpc-java/blob/master/examples/build.gradle) simplifies building and running the examples.
-
-You can build and run the server from the `grpc-java` root folder with:
-
-```sh
-$ ./gradlew :grpc-examples:helloWorldServer
-```
-
-and in another terminal window confirm that it receives a message.
-
-```sh
-$  ./gradlew :grpc-examples:helloWorldClient
-```
-
-### Adding another client
-
-Finally, let's look at one of gRPC's most useful features - interoperability
-between code in different languages. So far, we've just looked at Java code
-generated from and implementing our `Greeter` service definition. However,
-as you'll see if you look at the language-specific subdirectories
-in this repository, we've also generated and implemented `Greeter`
-in some of gRPC's other supported languages. Each service
-and client uses interface code generated from the same proto
-that we used for the Java example.
-
-So, for example, if we visit the [`go` example
-directory](https://github.com/grpc/grpc-go/tree/master/examples) and look at the
-[`greeter_client`](https://github.com/grpc/grpc-go/blob/master/examples/greeter_client/main.go),
-we can see that like the Java client, it connects to a `Greeter` service
-at `localhost:50051` and uses a stub to call the `SayHello` method with a
-`HelloRequest`:
-
-```go
-const (
-	address = "localhost:50051"
-	defaultName = "world"
-)
-
-func main() {
-	// Set up a connection to the server.
-	conn, err := grpc.Dial(address)
-	if err != nil {
-		log.Fatalf("did not connect: %v", err)
-	}
-	defer conn.Close()
-	c := pb.NewGreeterClient(conn)
-
-	// Contact the server and print out its response.
-	name := defaultName
-	if len(os.Args) > 1 {
-		name = os.Args[1]
-	}
-	r, err := c.SayHello(context.Background(), &pb.HelloRequest{Name:
-	name})
-	if err != nil {
-		log.Fatalf("could not greet: %v", err)
-	}
-	log.Printf("Greeting: %s", r.Message)
-}
-```
-
-
-If we run the Java server from earlier in another terminal window, we can
-run the Go client and connect to it just like the Java client, even though
-it's written in a different language.
 
-```
-$ greeter_client
-```
-## Read more!
 
-- You can find links to language-specific tutorials, examples, and other docs in each language's [quick start](#quickstart).
-- [gRPC Authentication Support](http://www.grpc.io/docs/guides/auth.html) introduces authentication support in gRPC with supported mechanisms and examples.
diff --git a/examples/cpp/README.md b/examples/cpp/README.md
index e4b0eb698bffe5f536885bd85d0120cc3a2dd578..d93cbacf7b276c673f17595e62b64821c22b4236 100644
--- a/examples/cpp/README.md
+++ b/examples/cpp/README.md
@@ -2,7 +2,7 @@
 
 ## Installation
 
-To install gRPC on your system, follow the instructions [here](../../INSTALL.md).
+To install gRPC on your system, follow the instructions to build from source [here](../../INSTALL.md). This also installs the protocol buffer compiler `protoc` (if you don't have it already), and the C++ gRPC plugin for `protoc`.
 
 ## Hello C++ gRPC!
 
diff --git a/examples/php/README.md b/examples/php/README.md
index 8fb060863a3f6077cd99aa3f653752081c80c028..ea9ccb679086a53587f6c9ef908310a8216441e5 100644
--- a/examples/php/README.md
+++ b/examples/php/README.md
@@ -4,16 +4,15 @@ gRPC in 3 minutes (PHP)
 PREREQUISITES
 -------------
 
-This requires PHP 5.5 or greater.
+This requires `php` >=5.5, `phpize`, `pecl`, `phpunit`
 
 INSTALL
 -------
- - On Mac OS X, install [homebrew][]. Run the following command to install gRPC.
+ - Install the gRPC PHP extension
 
    ```sh
-   $ curl -fsSL https://goo.gl/getgrpc | bash -s php
+   $ [sudo] pecl install grpc-beta
    ```
-   This will download and run the [gRPC install script][] and compile the gRPC PHP extension.
 
  - Clone this repository
 
@@ -37,6 +36,7 @@ TRY IT!
    Please follow the instruction in [Node][] to run the server
    ```
    $ cd examples/node
+   $ npm install
    $ nodejs greeter_server.js
    ```
 
@@ -58,7 +58,5 @@ TUTORIAL
 
 You can find a more detailed tutorial in [gRPC Basics: PHP][]
 
-[homebrew]:http://brew.sh
-[gRPC install script]:https://raw.githubusercontent.com/grpc/homebrew-grpc/master/scripts/install
 [Node]:https://github.com/grpc/grpc/tree/master/examples/node
 [gRPC Basics: PHP]:http://www.grpc.io/docs/tutorials/basic/php.html
diff --git a/examples/php/composer.json b/examples/php/composer.json
index 9f44f0b186ae536428f17da5ce2eeeac16193bf5..c837bf7ac0febe029f3fe41eb641884ff15ba13c 100644
--- a/examples/php/composer.json
+++ b/examples/php/composer.json
@@ -1,17 +1,14 @@
 {
+  "name": "grpc/grpc-demo",
+  "description": "gRPC example for PHP",
+  "minimum-stability": "dev",
   "repositories": [
     {
       "type": "vcs",
       "url": "https://github.com/stanley-cheung/Protobuf-PHP"
     }
   ],
-  "name": "grpc/grpc-demo",
-  "description": "gRPC example for PHP",
-  "minimum-stability": "dev",
   "require": {
-    "php": ">=5.5.0",
-    "datto/protobuf-php": "dev-master",
-    "google/auth": "dev-master",
-    "grpc/grpc": "dev-release-0_11"
+    "grpc/grpc": "dev-release-0_13"
   }
 }
diff --git a/examples/php/greeter_client.php b/examples/php/greeter_client.php
index e5e4c2651e92851a5f59c69ba4c73d485ca600a8..3fab14f33e168f0ee90dcae9458f3d1de39bf071 100644
--- a/examples/php/greeter_client.php
+++ b/examples/php/greeter_client.php
@@ -1,7 +1,7 @@
 <?php
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -36,7 +36,9 @@ require dirname(__FILE__) . '/vendor/autoload.php';
 require dirname(__FILE__) . '/helloworld.php';
 
 function greet($name) {
-  $client = new helloworld\GreeterClient('localhost:50051', []);
+  $client = new helloworld\GreeterClient('localhost:50051', [
+    'credentials' => Grpc\ChannelCredentials::createInsecure()
+  ]);
   $request = new helloworld\HelloRequest();
   $request->setName($name);
   list($reply, $status) = $client->SayHello($request)->wait();
diff --git a/examples/php/route_guide/route_guide_client.php b/examples/php/route_guide/route_guide_client.php
index 3cd1df725417095e78c32ba5a2d0f6fdb4472e86..cc8640cf702879a65081402e79d67ed1996b0d72 100644
--- a/examples/php/route_guide/route_guide_client.php
+++ b/examples/php/route_guide/route_guide_client.php
@@ -1,7 +1,7 @@
 <?php
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -37,7 +37,9 @@ require dirname(__FILE__) . '/route_guide.php';
 
 define('COORD_FACTOR', 1e7);
 
-$client = new routeguide\RouteGuideClient('localhost:50051', []);
+$client = new routeguide\RouteGuideClient('localhost:50051', [
+  'credentials' => Grpc\ChannelCredentials::createInsecure()
+]);
 
 function printFeature($feature) {
   $name = $feature->getName();
diff --git a/examples/python/route_guide/route_guide_server.py b/examples/python/route_guide/route_guide_server.py
index f23b98bf3673c191f2641f05e9adcaf7f127e228..f95b36b07366c9378d7730cbdf293be1ffcc6284 100644
--- a/examples/python/route_guide/route_guide_server.py
+++ b/examples/python/route_guide/route_guide_server.py
@@ -1,4 +1,4 @@
-# Copyright 2015, Google Inc.
+# Copyright 2015-2016, Google Inc.
 # All rights reserved.
 #
 # Redistribution and use in source and binary forms, with or without
@@ -128,7 +128,7 @@ def serve():
     while True:
       time.sleep(_ONE_DAY_IN_SECONDS)
   except KeyboardInterrupt:
-    server.stop()
+    server.stop(0)
 
 if __name__ == '__main__':
   serve()
diff --git a/package.xml b/package.xml
index e65ab73b54abcfd702aeaa87ea669a0a74694833..bb4dcc2037a50c818c5fe1a22fa60e794c08f44c 100644
--- a/package.xml
+++ b/package.xml
@@ -27,9 +27,9 @@
  <contents>
   <dir baseinstalldir="/" name="/">
     <file baseinstalldir="/" name="config.m4" role="src" />
+    <file baseinstalldir="/" name="src/php/README.md" role="src" />
     <file baseinstalldir="/" name="src/php/ext/grpc/CREDITS" role="src" />
     <file baseinstalldir="/" name="src/php/ext/grpc/LICENSE" role="src" />
-    <file baseinstalldir="/" name="src/php/ext/grpc/README.md" role="src" />
     <file baseinstalldir="/" name="src/php/ext/grpc/byte_buffer.c" role="src" />
     <file baseinstalldir="/" name="src/php/ext/grpc/call.c" role="src" />
     <file baseinstalldir="/" name="src/php/ext/grpc/call_credentials.c" role="src" />
diff --git a/setup.py b/setup.py
index cfb578e21581645985c72e23c6acd820a470c041..45ff2cec89b1f93007be535776e4d14f51c04451 100644
--- a/setup.py
+++ b/setup.py
@@ -108,8 +108,13 @@ if "linux" in sys.platform or "darwin" in sys.platform:
 
 def cython_extensions(package_names, module_names, extra_sources, include_dirs,
                       libraries, define_macros, build_with_cython=False):
+  # Set compiler directives linetrace argument only if we care about tracing;
+  # this is due to Cython having different behavior between linetrace being
+  # False and linetrace being unset. See issue #5689.
+  cython_compiler_directives = {}
   if ENABLE_CYTHON_TRACING:
     define_macros = define_macros + [('CYTHON_TRACE_NOGIL', 1)]
+    cython_compiler_directives['linetrace'] = True
   file_extension = 'pyx' if build_with_cython else 'c'
   module_files = [os.path.join(PYTHON_STEM,
                                name.replace('.', '/') + '.' + file_extension)
@@ -129,7 +134,7 @@ def cython_extensions(package_names, module_names, extra_sources, include_dirs,
     return Cython.Build.cythonize(
         extensions,
         include_path=include_dirs,
-        compiler_directives={'linetrace': bool(ENABLE_CYTHON_TRACING)})
+        compiler_directives=cython_compiler_directives)
   else:
     return extensions
 
@@ -154,6 +159,7 @@ INSTALL_REQUIRES = (
 
 SETUP_REQUIRES = (
     'sphinx>=1.3',
+    'sphinx_rtd_theme>=0.1.8'
 ) + INSTALL_REQUIRES
 
 COMMAND_CLASS = {
@@ -165,6 +171,7 @@ COMMAND_CLASS = {
     'build_tagged_ext': precompiled.BuildTaggedExt,
     'gather': commands.Gather,
     'run_interop': commands.RunInterop,
+    'test_lite': commands.TestLite
 }
 
 # Ensure that package data is copied over before any commands have been run:
diff --git a/src/core/channel/client_channel.c b/src/core/channel/client_channel.c
index d4ba9508185284e912a5e49cd0ac6adbe6f16f22..f021a8ae32920904441ef362c3ec30ebaae71944 100644
--- a/src/core/channel/client_channel.c
+++ b/src/core/channel/client_channel.c
@@ -165,7 +165,6 @@ static void cc_on_config_changed(grpc_exec_ctx *exec_ctx, void *arg,
   channel_data *chand = arg;
   grpc_lb_policy *lb_policy = NULL;
   grpc_lb_policy *old_lb_policy;
-  grpc_resolver *old_resolver;
   grpc_connectivity_state state = GRPC_CHANNEL_TRANSIENT_FAILURE;
   int exit_idle = 0;
 
@@ -201,28 +200,25 @@ static void cc_on_config_changed(grpc_exec_ctx *exec_ctx, void *arg,
   }
 
   if (iomgr_success && chand->resolver) {
-    grpc_resolver *resolver = chand->resolver;
-    GRPC_RESOLVER_REF(resolver, "channel-next");
     grpc_connectivity_state_set(exec_ctx, &chand->state_tracker, state,
                                 "new_lb+resolver");
     if (lb_policy != NULL) {
       watch_lb_policy(exec_ctx, chand, lb_policy, state);
     }
-    gpr_mu_unlock(&chand->mu_config);
     GRPC_CHANNEL_STACK_REF(chand->owning_stack, "resolver");
-    grpc_resolver_next(exec_ctx, resolver, &chand->incoming_configuration,
+    grpc_resolver_next(exec_ctx, chand->resolver,
+                       &chand->incoming_configuration,
                        &chand->on_config_changed);
-    GRPC_RESOLVER_UNREF(exec_ctx, resolver, "channel-next");
+    gpr_mu_unlock(&chand->mu_config);
   } else {
-    old_resolver = chand->resolver;
-    chand->resolver = NULL;
+    if (chand->resolver != NULL) {
+      grpc_resolver_shutdown(exec_ctx, chand->resolver);
+      GRPC_RESOLVER_UNREF(exec_ctx, chand->resolver, "channel");
+      chand->resolver = NULL;
+    }
     grpc_connectivity_state_set(exec_ctx, &chand->state_tracker,
                                 GRPC_CHANNEL_FATAL_FAILURE, "resolver_gone");
     gpr_mu_unlock(&chand->mu_config);
-    if (old_resolver != NULL) {
-      grpc_resolver_shutdown(exec_ctx, old_resolver);
-      GRPC_RESOLVER_UNREF(exec_ctx, old_resolver, "channel");
-    }
   }
 
   if (exit_idle) {
@@ -247,7 +243,6 @@ static void cc_start_transport_op(grpc_exec_ctx *exec_ctx,
                                   grpc_channel_element *elem,
                                   grpc_transport_op *op) {
   channel_data *chand = elem->channel_data;
-  grpc_resolver *destroy_resolver = NULL;
 
   grpc_exec_ctx_enqueue(exec_ctx, op->on_consumed, true, NULL);
 
@@ -279,7 +274,8 @@ static void cc_start_transport_op(grpc_exec_ctx *exec_ctx,
   if (op->disconnect && chand->resolver != NULL) {
     grpc_connectivity_state_set(exec_ctx, &chand->state_tracker,
                                 GRPC_CHANNEL_FATAL_FAILURE, "disconnect");
-    destroy_resolver = chand->resolver;
+    grpc_resolver_shutdown(exec_ctx, chand->resolver);
+    GRPC_RESOLVER_UNREF(exec_ctx, chand->resolver, "channel");
     chand->resolver = NULL;
     if (chand->lb_policy != NULL) {
       grpc_pollset_set_del_pollset_set(exec_ctx,
@@ -290,11 +286,6 @@ static void cc_start_transport_op(grpc_exec_ctx *exec_ctx,
     }
   }
   gpr_mu_unlock(&chand->mu_config);
-
-  if (destroy_resolver) {
-    grpc_resolver_shutdown(exec_ctx, destroy_resolver);
-    GRPC_RESOLVER_UNREF(exec_ctx, destroy_resolver, "channel");
-  }
 }
 
 typedef struct {
diff --git a/src/core/channel/subchannel_call_holder.c b/src/core/channel/subchannel_call_holder.c
index 81297c8d4490eff53d0015aa11ff3268b5ba8e46..9c087dc2a1d477d30e6a56aba7c7a952790a8800 100644
--- a/src/core/channel/subchannel_call_holder.c
+++ b/src/core/channel/subchannel_call_holder.c
@@ -168,15 +168,15 @@ retry:
 
 static void subchannel_ready(grpc_exec_ctx *exec_ctx, void *arg, bool success) {
   grpc_subchannel_call_holder *holder = arg;
-  grpc_subchannel_call *call;
   gpr_mu_lock(&holder->mu);
   GPR_ASSERT(holder->creation_phase ==
              GRPC_SUBCHANNEL_CALL_HOLDER_PICKING_SUBCHANNEL);
-  call = GET_CALL(holder);
-  GPR_ASSERT(call == NULL || call == CANCELLED_CALL);
   holder->creation_phase = GRPC_SUBCHANNEL_CALL_HOLDER_NOT_CREATING;
   if (holder->connected_subchannel == NULL) {
     fail_locked(exec_ctx, holder);
+  } else if (1 == gpr_atm_acq_load(&holder->subchannel_call)) {
+    /* already cancelled before subchannel became ready */
+    fail_locked(exec_ctx, holder);
   } else {
     gpr_atm_rel_store(
         &holder->subchannel_call,
diff --git a/src/core/client_config/client_config.c b/src/core/client_config/client_config.c
index 6ecffb3854144e9d87a09e0d67585f8771b910e2..c500af25eec775bab60a79b0451510a11f905801 100644
--- a/src/core/client_config/client_config.c
+++ b/src/core/client_config/client_config.c
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -53,7 +53,9 @@ void grpc_client_config_ref(grpc_client_config *c) { gpr_ref(&c->refs); }
 
 void grpc_client_config_unref(grpc_exec_ctx *exec_ctx, grpc_client_config *c) {
   if (gpr_unref(&c->refs)) {
-    GRPC_LB_POLICY_UNREF(exec_ctx, c->lb_policy, "client_config");
+    if (c->lb_policy != NULL) {
+      GRPC_LB_POLICY_UNREF(exec_ctx, c->lb_policy, "client_config");
+    }
     gpr_free(c);
   }
 }
diff --git a/src/core/client_config/lb_policies/pick_first.c b/src/core/client_config/lb_policies/pick_first.c
index 81167b31c8c77b6116fa795bbcbaae3a39a48075..8ed1223d3993db84f3d900b6156163ac20f3b0f8 100644
--- a/src/core/client_config/lb_policies/pick_first.c
+++ b/src/core/client_config/lb_policies/pick_first.c
@@ -387,8 +387,8 @@ static void pick_first_factory_unref(grpc_lb_policy_factory *factory) {}
 
 static grpc_lb_policy *create_pick_first(grpc_lb_policy_factory *factory,
                                          grpc_lb_policy_args *args) {
+  if (args->num_subchannels == 0) return NULL;
   pick_first_lb_policy *p = gpr_malloc(sizeof(*p));
-  GPR_ASSERT(args->num_subchannels > 0);
   memset(p, 0, sizeof(*p));
   grpc_lb_policy_init(&p->base, &pick_first_lb_policy_vtable);
   p->subchannels =
diff --git a/src/core/client_config/resolvers/dns_resolver.c b/src/core/client_config/resolvers/dns_resolver.c
index 376b6b3d7681e4e5e172935276be9b25a5d5a418..e28e4757a107bfa01a5d53864885f06509d7114f 100644
--- a/src/core/client_config/resolvers/dns_resolver.c
+++ b/src/core/client_config/resolvers/dns_resolver.c
@@ -41,6 +41,7 @@
 
 #include "src/core/client_config/lb_policy_registry.h"
 #include "src/core/iomgr/resolve_address.h"
+#include "src/core/iomgr/timer.h"
 #include "src/core/support/string.h"
 
 typedef struct {
@@ -71,6 +72,9 @@ typedef struct {
   grpc_client_config **target_config;
   /** current (fully resolved) config */
   grpc_client_config *resolved_config;
+  /** retry timer */
+  bool have_retry_timer;
+  grpc_timer retry_timer;
 } dns_resolver;
 
 static void dns_destroy(grpc_exec_ctx *exec_ctx, grpc_resolver *r);
@@ -91,6 +95,9 @@ static const grpc_resolver_vtable dns_resolver_vtable = {
 static void dns_shutdown(grpc_exec_ctx *exec_ctx, grpc_resolver *resolver) {
   dns_resolver *r = (dns_resolver *)resolver;
   gpr_mu_lock(&r->mu);
+  if (r->have_retry_timer) {
+    grpc_timer_cancel(exec_ctx, &r->retry_timer);
+  }
   if (r->next_completion != NULL) {
     *r->target_config = NULL;
     grpc_exec_ctx_enqueue(exec_ctx, r->next_completion, true, NULL);
@@ -125,6 +132,22 @@ static void dns_next(grpc_exec_ctx *exec_ctx, grpc_resolver *resolver,
   gpr_mu_unlock(&r->mu);
 }
 
+static void dns_on_retry_timer(grpc_exec_ctx *exec_ctx, void *arg,
+                               bool success) {
+  dns_resolver *r = arg;
+
+  gpr_mu_lock(&r->mu);
+  r->have_retry_timer = false;
+  if (success) {
+    if (!r->resolving) {
+      dns_start_resolving_locked(r);
+    }
+  }
+  gpr_mu_unlock(&r->mu);
+
+  GRPC_RESOLVER_UNREF(exec_ctx, &r->base, "retry-timer");
+}
+
 static void dns_on_resolved(grpc_exec_ctx *exec_ctx, void *arg,
                             grpc_resolved_addresses *addresses) {
   dns_resolver *r = arg;
@@ -133,29 +156,47 @@ static void dns_on_resolved(grpc_exec_ctx *exec_ctx, void *arg,
   grpc_subchannel_args args;
   grpc_lb_policy *lb_policy;
   size_t i;
-  if (addresses) {
+  gpr_mu_lock(&r->mu);
+  GPR_ASSERT(r->resolving);
+  r->resolving = 0;
+  if (addresses != NULL) {
     grpc_lb_policy_args lb_policy_args;
     config = grpc_client_config_create();
     subchannels = gpr_malloc(sizeof(grpc_subchannel *) * addresses->naddrs);
+    size_t naddrs = 0;
     for (i = 0; i < addresses->naddrs; i++) {
       memset(&args, 0, sizeof(args));
       args.addr = (struct sockaddr *)(addresses->addrs[i].addr);
       args.addr_len = (size_t)addresses->addrs[i].len;
-      subchannels[i] = grpc_subchannel_factory_create_subchannel(
+      grpc_subchannel *subchannel = grpc_subchannel_factory_create_subchannel(
           exec_ctx, r->subchannel_factory, &args);
+      if (subchannel != NULL) {
+        subchannels[naddrs++] = subchannel;
+      }
     }
     memset(&lb_policy_args, 0, sizeof(lb_policy_args));
     lb_policy_args.subchannels = subchannels;
-    lb_policy_args.num_subchannels = addresses->naddrs;
+    lb_policy_args.num_subchannels = naddrs;
     lb_policy = grpc_lb_policy_create(r->lb_policy_name, &lb_policy_args);
-    grpc_client_config_set_lb_policy(config, lb_policy);
-    GRPC_LB_POLICY_UNREF(exec_ctx, lb_policy, "construction");
+    if (lb_policy != NULL) {
+      grpc_client_config_set_lb_policy(config, lb_policy);
+      GRPC_LB_POLICY_UNREF(exec_ctx, lb_policy, "construction");
+    }
     grpc_resolved_addresses_destroy(addresses);
     gpr_free(subchannels);
+  } else {
+    int retry_seconds = 15;
+    gpr_log(GPR_DEBUG, "dns resolution failed: retrying in %d seconds",
+            retry_seconds);
+    GPR_ASSERT(!r->have_retry_timer);
+    r->have_retry_timer = true;
+    gpr_timespec now = gpr_now(GPR_CLOCK_MONOTONIC);
+    GRPC_RESOLVER_REF(&r->base, "retry-timer");
+    grpc_timer_init(
+        exec_ctx, &r->retry_timer,
+        gpr_time_add(now, gpr_time_from_seconds(retry_seconds, GPR_TIMESPAN)),
+        dns_on_retry_timer, r, now);
   }
-  gpr_mu_lock(&r->mu);
-  GPR_ASSERT(r->resolving);
-  r->resolving = 0;
   if (r->resolved_config) {
     grpc_client_config_unref(exec_ctx, r->resolved_config);
   }
diff --git a/src/core/iomgr/iocp_windows.c b/src/core/iomgr/iocp_windows.c
index 807729708ea7e1cc726dcd4fa8c0028a83b6627a..fa87e5246b07b4d6bd4c5327aa9000a70e7902c9 100644
--- a/src/core/iomgr/iocp_windows.c
+++ b/src/core/iomgr/iocp_windows.c
@@ -71,7 +71,8 @@ static DWORD deadline_to_millis_timeout(gpr_timespec deadline,
       timeout, gpr_time_from_nanos(GPR_NS_PER_MS - 1, GPR_TIMESPAN)));
 }
 
-void grpc_iocp_work(grpc_exec_ctx *exec_ctx, gpr_timespec deadline) {
+grpc_iocp_work_status grpc_iocp_work(grpc_exec_ctx *exec_ctx,
+                                     gpr_timespec deadline) {
   BOOL success;
   DWORD bytes = 0;
   DWORD flags = 0;
@@ -84,14 +85,14 @@ void grpc_iocp_work(grpc_exec_ctx *exec_ctx, gpr_timespec deadline) {
       g_iocp, &bytes, &completion_key, &overlapped,
       deadline_to_millis_timeout(deadline, gpr_now(deadline.clock_type)));
   if (success == 0 && overlapped == NULL) {
-    return;
+    return GRPC_IOCP_WORK_TIMEOUT;
   }
   GPR_ASSERT(completion_key && overlapped);
   if (overlapped == &g_iocp_custom_overlap) {
     gpr_atm_full_fetch_add(&g_custom_events, -1);
     if (completion_key == (ULONG_PTR)&g_iocp_kick_token) {
       /* We were awoken from a kick. */
-      return;
+      return GRPC_IOCP_WORK_KICK;
     }
     gpr_log(GPR_ERROR, "Unknown custom completion key.");
     abort();
@@ -121,6 +122,7 @@ void grpc_iocp_work(grpc_exec_ctx *exec_ctx, gpr_timespec deadline) {
   }
   gpr_mu_unlock(&socket->state_mu);
   grpc_exec_ctx_enqueue(exec_ctx, closure, true, NULL);
+  return GRPC_IOCP_WORK_WORK;
 }
 
 void grpc_iocp_init(void) {
@@ -140,10 +142,12 @@ void grpc_iocp_kick(void) {
 
 void grpc_iocp_flush(void) {
   grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+  grpc_iocp_work_status work_status;
 
   do {
-    grpc_iocp_work(&exec_ctx, gpr_inf_past(GPR_CLOCK_MONOTONIC));
-  } while (grpc_exec_ctx_flush(&exec_ctx));
+    work_status = grpc_iocp_work(&exec_ctx, gpr_inf_past(GPR_CLOCK_MONOTONIC));
+  } while (work_status == GRPC_IOCP_WORK_KICK ||
+           grpc_exec_ctx_flush(&exec_ctx));
 }
 
 void grpc_iocp_shutdown(void) {
diff --git a/src/core/iomgr/iocp_windows.h b/src/core/iomgr/iocp_windows.h
index 75f3ba84770fca354814d332b437a83f2ae5e511..8b2b1aeb5c2a950c0e440a19f19040257cc78a3c 100644
--- a/src/core/iomgr/iocp_windows.h
+++ b/src/core/iomgr/iocp_windows.h
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -38,7 +38,14 @@
 
 #include "src/core/iomgr/socket_windows.h"
 
-void grpc_iocp_work(grpc_exec_ctx *exec_ctx, gpr_timespec deadline);
+typedef enum {
+  GRPC_IOCP_WORK_WORK,
+  GRPC_IOCP_WORK_TIMEOUT,
+  GRPC_IOCP_WORK_KICK
+} grpc_iocp_work_status;
+
+grpc_iocp_work_status grpc_iocp_work(grpc_exec_ctx *exec_ctx,
+                                     gpr_timespec deadline);
 void grpc_iocp_init(void);
 void grpc_iocp_kick(void);
 void grpc_iocp_flush(void);
diff --git a/src/core/iomgr/resolve_address.h b/src/core/iomgr/resolve_address.h
index 01eedffa889fae5cdcca3cac0a860613f1ee2c62..b059630457656bc5676335e7621c2591dcc8e8fc 100644
--- a/src/core/iomgr/resolve_address.h
+++ b/src/core/iomgr/resolve_address.h
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -66,7 +66,7 @@ void grpc_resolved_addresses_destroy(grpc_resolved_addresses *addresses);
 
 /* Resolve addr in a blocking fashion. Returns NULL on failure. On success,
    result must be freed with grpc_resolved_addresses_destroy. */
-grpc_resolved_addresses *grpc_blocking_resolve_address(
-    const char *addr, const char *default_port);
+extern grpc_resolved_addresses *(*grpc_blocking_resolve_address)(
+    const char *name, const char *default_port);
 
 #endif /* GRPC_INTERNAL_CORE_IOMGR_RESOLVE_ADDRESS_H */
diff --git a/src/core/iomgr/resolve_address_posix.c b/src/core/iomgr/resolve_address_posix.c
index c51745b9187a0a4b04f3e7ef79bba795451bb7a6..a6c9893f2310bd1728e1b468646500532efec5fa 100644
--- a/src/core/iomgr/resolve_address_posix.c
+++ b/src/core/iomgr/resolve_address_posix.c
@@ -34,18 +34,13 @@
 #include <grpc/support/port_platform.h>
 #ifdef GPR_POSIX_SOCKET
 
-#include "src/core/iomgr/sockaddr.h"
 #include "src/core/iomgr/resolve_address.h"
+#include "src/core/iomgr/sockaddr.h"
 
+#include <string.h>
 #include <sys/types.h>
 #include <sys/un.h>
-#include <string.h>
 
-#include "src/core/iomgr/executor.h"
-#include "src/core/iomgr/iomgr_internal.h"
-#include "src/core/iomgr/sockaddr_utils.h"
-#include "src/core/support/block_annotate.h"
-#include "src/core/support/string.h"
 #include <grpc/support/alloc.h>
 #include <grpc/support/host_port.h>
 #include <grpc/support/log.h>
@@ -53,6 +48,11 @@
 #include <grpc/support/thd.h>
 #include <grpc/support/time.h>
 #include <grpc/support/useful.h>
+#include "src/core/iomgr/executor.h"
+#include "src/core/iomgr/iomgr_internal.h"
+#include "src/core/iomgr/sockaddr_utils.h"
+#include "src/core/support/block_annotate.h"
+#include "src/core/support/string.h"
 
 typedef struct {
   char *name;
@@ -62,7 +62,7 @@ typedef struct {
   void *arg;
 } request;
 
-grpc_resolved_addresses *grpc_blocking_resolve_address(
+static grpc_resolved_addresses *blocking_resolve_address_impl(
     const char *name, const char *default_port) {
   struct addrinfo hints;
   struct addrinfo *result = NULL, *resp;
@@ -150,6 +150,9 @@ done:
   return addrs;
 }
 
+grpc_resolved_addresses *(*grpc_blocking_resolve_address)(
+    const char *name, const char *default_port) = blocking_resolve_address_impl;
+
 /* Callback to be passed to grpc_executor to asynch-ify
  * grpc_blocking_resolve_address */
 static void do_request_thread(grpc_exec_ctx *exec_ctx, void *rp, bool success) {
diff --git a/src/core/iomgr/resolve_address_windows.c b/src/core/iomgr/resolve_address_windows.c
index 28c8661e73b1738adf208488b603080d285477cf..472e79716342b86ecd5adbbd9621ef686c512bd5 100644
--- a/src/core/iomgr/resolve_address_windows.c
+++ b/src/core/iomgr/resolve_address_windows.c
@@ -34,17 +34,12 @@
 #include <grpc/support/port_platform.h>
 #ifdef GPR_WINSOCK_SOCKET
 
-#include "src/core/iomgr/sockaddr.h"
 #include "src/core/iomgr/resolve_address.h"
+#include "src/core/iomgr/sockaddr.h"
 
-#include <sys/types.h>
 #include <string.h>
+#include <sys/types.h>
 
-#include "src/core/iomgr/executor.h"
-#include "src/core/iomgr/iomgr_internal.h"
-#include "src/core/iomgr/sockaddr_utils.h"
-#include "src/core/support/block_annotate.h"
-#include "src/core/support/string.h"
 #include <grpc/support/alloc.h>
 #include <grpc/support/host_port.h>
 #include <grpc/support/log.h>
@@ -52,6 +47,11 @@
 #include <grpc/support/string_util.h>
 #include <grpc/support/thd.h>
 #include <grpc/support/time.h>
+#include "src/core/iomgr/executor.h"
+#include "src/core/iomgr/iomgr_internal.h"
+#include "src/core/iomgr/sockaddr_utils.h"
+#include "src/core/support/block_annotate.h"
+#include "src/core/support/string.h"
 
 typedef struct {
   char *name;
@@ -61,7 +61,7 @@ typedef struct {
   void *arg;
 } request;
 
-grpc_resolved_addresses *grpc_blocking_resolve_address(
+static grpc_resolved_addresses *blocking_resolve_address_impl(
     const char *name, const char *default_port) {
   struct addrinfo hints;
   struct addrinfo *result = NULL, *resp;
@@ -133,6 +133,9 @@ done:
   return addrs;
 }
 
+grpc_resolved_addresses *(*grpc_blocking_resolve_address)(
+    const char *name, const char *default_port) = blocking_resolve_address_impl;
+
 /* Callback to be passed to grpc_executor to asynch-ify
  * grpc_blocking_resolve_address */
 static void do_request_thread(grpc_exec_ctx *exec_ctx, void *rp, bool success) {
diff --git a/src/core/iomgr/tcp_server_windows.c b/src/core/iomgr/tcp_server_windows.c
index ce930b8f41d4e9f4d828478efedb7e05e8c91dc3..a4abc5b9743a0f103df7bbd50e41ac2d1493b4d1 100644
--- a/src/core/iomgr/tcp_server_windows.c
+++ b/src/core/iomgr/tcp_server_windows.c
@@ -240,8 +240,7 @@ static void decrement_active_ports_and_notify(grpc_exec_ctx *exec_ctx,
   sp->shutting_down = 0;
   gpr_mu_lock(&sp->server->mu);
   GPR_ASSERT(sp->server->active_ports > 0);
-  if (0 == --sp->server->active_ports &&
-      sp->server->shutdown_complete != NULL) {
+  if (0 == --sp->server->active_ports) {
     notify = 1;
   }
   gpr_mu_unlock(&sp->server->mu);
diff --git a/src/core/iomgr/timer_heap.c b/src/core/iomgr/timer_heap.c
index 9d8be5c1fcb56b7a0818081c5fd50e932ecbad83..b5df566c453d3ee606af96bc35f3d2e7fd8f185e 100644
--- a/src/core/iomgr/timer_heap.c
+++ b/src/core/iomgr/timer_heap.c
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -46,7 +46,7 @@
 static void adjust_upwards(grpc_timer **first, uint32_t i, grpc_timer *t) {
   while (i > 0) {
     uint32_t parent = (uint32_t)(((int)i - 1) / 2);
-    if (gpr_time_cmp(first[parent]->deadline, t->deadline) >= 0) break;
+    if (gpr_time_cmp(first[parent]->deadline, t->deadline) <= 0) break;
     first[i] = first[parent];
     first[i]->heap_index = i;
     i = parent;
@@ -62,16 +62,14 @@ static void adjust_downwards(grpc_timer **first, uint32_t i, uint32_t length,
                              grpc_timer *t) {
   for (;;) {
     uint32_t left_child = 1u + 2u * i;
-    uint32_t right_child;
-    uint32_t next_i;
     if (left_child >= length) break;
-    right_child = left_child + 1;
-    next_i = right_child < length &&
-                     gpr_time_cmp(first[left_child]->deadline,
-                                  first[right_child]->deadline) < 0
-                 ? right_child
-                 : left_child;
-    if (gpr_time_cmp(t->deadline, first[next_i]->deadline) >= 0) break;
+    uint32_t right_child = left_child + 1;
+    uint32_t next_i = right_child < length &&
+                              gpr_time_cmp(first[left_child]->deadline,
+                                           first[right_child]->deadline) > 0
+                          ? right_child
+                          : left_child;
+    if (gpr_time_cmp(t->deadline, first[next_i]->deadline) <= 0) break;
     first[i] = first[next_i];
     first[i]->heap_index = i;
     i = next_i;
@@ -95,7 +93,7 @@ static void maybe_shrink(grpc_timer_heap *heap) {
 static void note_changed_priority(grpc_timer_heap *heap, grpc_timer *timer) {
   uint32_t i = timer->heap_index;
   uint32_t parent = (uint32_t)(((int)i - 1) / 2);
-  if (gpr_time_cmp(heap->timers[parent]->deadline, timer->deadline) < 0) {
+  if (gpr_time_cmp(heap->timers[parent]->deadline, timer->deadline) > 0) {
     adjust_upwards(heap->timers, i, timer);
   } else {
     adjust_downwards(heap->timers, i, heap->timer_count, timer);
diff --git a/src/core/transport/chttp2_transport.c b/src/core/transport/chttp2_transport.c
index 19265252ca36f7029a79784ea0bc763fc9a60cd4..03444fd4c248ad63132ea7b52bebcc9aad667d6c 100644
--- a/src/core/transport/chttp2_transport.c
+++ b/src/core/transport/chttp2_transport.c
@@ -851,9 +851,11 @@ static void perform_stream_op_locked(
     if (stream_global->write_closed) {
       grpc_chttp2_complete_closure_step(
           exec_ctx, &stream_global->send_message_finished, 0);
-    } else if (stream_global->id != 0) {
+    } else {
       stream_global->send_message = op->send_message;
-      grpc_chttp2_become_writable(transport_global, stream_global);
+      if (stream_global->id != 0) {
+        grpc_chttp2_become_writable(transport_global, stream_global);
+      }
     }
   }
 
diff --git a/src/cpp/README.md b/src/cpp/README.md
index baeba0831555228bc6789a557511930e66082ce1..83d37aa2ed8b9459163d9993de985159273fd096 100644
--- a/src/cpp/README.md
+++ b/src/cpp/README.md
@@ -6,3 +6,77 @@ This directory contains source code for C++ implementation of gRPC.
 #Status
 
 Beta
+
+#Pre-requisites
+
+##Linux
+
+```sh
+ $ [sudo] apt-get install build-essential autoconf libtool
+```
+
+##Mac OSX
+
+For a Mac system, git is not available by default. You will first need to
+install Xcode from the Mac AppStore and then run the following command from a
+terminal:
+
+```sh
+ $ [sudo] xcode-select --install
+```
+
+##Protoc
+
+By default gRPC uses [protocol buffers](https://github.com/google/protobuf),
+you will need the `protoc` compiler to generate stub server and client code.
+
+If you compile gRPC from source, as described below, this also installs the
+`protoc` compiler.
+
+If it hasn't been installed, you can run the following commands to install it.
+
+```sh
+$ cd grpc/third_party/protobuf
+$ sudo make install   # 'make' should have been run by core grpc
+```
+
+Alternatively, you can download `protoc` binaries from
+[the protocol buffers Github repository](https://github.com/google/protobuf/releases).
+
+#Installation
+
+Currently to install gRPC for C++, you need to build from source as described
+below.
+
+#Build from Source
+
+```sh
+ $ git clone https://github.com/grpc/grpc.git
+ $ cd grpc
+ $ git submodule update --init
+ $ make
+ $ [sudo] make install
+```
+
+#Documentation
+
+You can find out how to build and run our simplest gRPC C++ example in our
+[C++ quick start](https://github.com/grpc/grpc/tree/{{ site.data.config.grpc_release_branch }}/examples/cpp).
+
+For more detailed documentation on using gRPC in C++ , see our main
+documentation site at [grpc.io](http://grpc.io), specifically:
+
+* [Overview](http://www.grpc.io/docs/): An introduction to gRPC with a simple
+  Hello World example in all our supported languages, including C++.
+* [gRPC Basics - C++](http://www.grpc.io/docs/tutorials/basic/c.html):
+  A tutorial that steps you through creating a simple gRPC C++ example
+  application.
+* [Asynchronous Basics - C++](http://www.grpc.io/docs/tutorials/async/helloasync-cpp.html):
+  A tutorial that shows you how to use gRPC C++'s asynchronous/non-blocking
+  APIs.
+
+
+# Examples
+
+Code examples for gRPC C++ live in this repository's
+[examples/cpp](https://github.com/grpc/grpc/tree/{{ site.data.config.grpc_release_branch }}/examples/cpp) directory.
diff --git a/src/csharp/Grpc.Core/Metadata.cs b/src/csharp/Grpc.Core/Metadata.cs
index aa22f840d6c31a03dc7fc690ab99900067b05272..52cef96f40565a9209b0c17cfbd510803dfe897c 100644
--- a/src/csharp/Grpc.Core/Metadata.cs
+++ b/src/csharp/Grpc.Core/Metadata.cs
@@ -323,7 +323,7 @@ namespace Grpc.Core
 
             private static string NormalizeKey(string key)
             {
-                var normalized = GrpcPreconditions.CheckNotNull(key, "key").ToLower(CultureInfo.InvariantCulture);
+                var normalized = GrpcPreconditions.CheckNotNull(key, "key").ToLowerInvariant();
                 GrpcPreconditions.CheckArgument(ValidKeyRegex.IsMatch(normalized), 
                     "Metadata entry key not valid. Keys can only contain lowercase alphanumeric characters, underscores and hyphens.");
                 return normalized;
diff --git a/src/node/README.md b/src/node/README.md
index b46b98624327d3a6569fd73fa3b0d0d9306c340c..3501b54a6654d6ededd90c8f7de8da7771376d2a 100644
--- a/src/node/README.md
+++ b/src/node/README.md
@@ -5,7 +5,7 @@
 Beta
 
 ## PREREQUISITES
-- `node`: This requires `node` to be installed. If you instead have the `nodejs` executable on Debian, you should install the [`nodejs-legacy`](https://packages.debian.org/sid/nodejs-legacy) package.
+- `node`: This requires `node` to be installed, version `0.12` or above. If you instead have the `nodejs` executable on Debian, you should install the [`nodejs-legacy`](https://packages.debian.org/sid/nodejs-legacy) package.
 
 ## INSTALLATION
 
diff --git a/src/node/src/client.js b/src/node/src/client.js
index 9acf51bd98b26bec5051d8f6480b13336bb29403..2459e283214a2e58ee415870692e2c41891c9a5a 100644
--- a/src/node/src/client.js
+++ b/src/node/src/client.js
@@ -149,6 +149,9 @@ function _readsDone(status) {
   if (!status) {
     status = {code: grpc.status.OK, details: 'OK'};
   }
+  if (status.code !== grpc.status.OK) {
+    this.call.cancelWithStatus(status.code, status.details);
+  }
   this.finished = true;
   this.read_status = status;
   this._emitStatusIfDone();
@@ -408,7 +411,7 @@ function makeUnaryRequestFunction(method, serialize, deserialize) {
         }
       }
       if (status.code !== grpc.status.OK) {
-        error = new Error(response.status.details);
+        error = new Error(status.details);
         error.code = status.code;
         error.metadata = status.metadata;
         callback(error);
diff --git a/src/objective-c/GRPCClient/GRPCCall.m b/src/objective-c/GRPCClient/GRPCCall.m
index f79b7d0bc0cf08920c78619eca04c41de2d9112c..2d45818b6e960ac9f9d8aff5dcb321b3413ab833 100644
--- a/src/objective-c/GRPCClient/GRPCCall.m
+++ b/src/objective-c/GRPCClient/GRPCCall.m
@@ -37,6 +37,8 @@
 #include <grpc/support/time.h>
 #import <RxLibrary/GRXConcurrentWriteable.h>
 
+#import "private/GRPCConnectivityMonitor.h"
+#import "private/GRPCHost.h"
 #import "private/GRPCRequestHeaders.h"
 #import "private/GRPCWrappedCall.h"
 #import "private/NSData+GRPC.h"
@@ -71,8 +73,11 @@ NSString * const kGRPCTrailersKey = @"io.grpc.TrailersKey";
 @implementation GRPCCall {
   dispatch_queue_t _callQueue;
 
+  NSString *_host;
+  NSString *_path;
   GRPCWrappedCall *_wrappedCall;
   dispatch_once_t _callAlreadyInvoked;
+  GRPCConnectivityMonitor *_connectivityMonitor;
 
   // The C gRPC library has less guarantees on the ordering of events than we
   // do. Particularly, in the face of errors, there's no ordering guarantee at
@@ -115,13 +120,11 @@ NSString * const kGRPCTrailersKey = @"io.grpc.TrailersKey";
                 format:@"The requests writer can't be already started."];
   }
   if ((self = [super init])) {
-    _wrappedCall = [[GRPCWrappedCall alloc] initWithHost:host path:path];
-    if (!_wrappedCall) {
-      return nil;
-    }
+    _host = [host copy];
+    _path = [path copy];
 
     // Serial queue to invoke the non-reentrant methods of the grpc_call object.
-    _callQueue = dispatch_queue_create("org.grpc.call", NULL);
+    _callQueue = dispatch_queue_create("io.grpc.call", NULL);
 
     _requestWriter = requestWriter;
 
@@ -156,7 +159,7 @@ NSString * const kGRPCTrailersKey = @"io.grpc.TrailersKey";
 - (void)cancel {
   [self finishWithError:[NSError errorWithDomain:kGRPCErrorDomain
                                             code:GRPCErrorCodeCancelled
-                                        userInfo:nil]];
+                                        userInfo:@{NSLocalizedDescriptionKey: @"Canceled by app"}]];
   [self cancelCall];
 }
 
@@ -354,8 +357,29 @@ NSString * const kGRPCTrailersKey = @"io.grpc.TrailersKey";
   _retainSelf = self;
 
   _responseWriteable = [[GRXConcurrentWriteable alloc] initWithWriteable:writeable];
+
+  _wrappedCall = [[GRPCWrappedCall alloc] initWithHost:_host path:_path];
+  NSAssert(_wrappedCall, @"Error allocating RPC objects. Low memory?");
+
   [self sendHeaders:_requestHeaders];
   [self invokeCall];
+  // TODO(jcanizales): Extract this logic somewhere common.
+  NSString *host = [NSURL URLWithString:[@"https://" stringByAppendingString:_host]].host;
+  if (!host) {
+    // TODO(jcanizales): Check this on init.
+    [NSException raise:NSInvalidArgumentException format:@"host of %@ is nil", _host];
+  }
+  __weak typeof(self) weakSelf = self;
+  _connectivityMonitor = [GRPCConnectivityMonitor monitorWithHost:host];
+  [_connectivityMonitor handleLossWithHandler:^{
+    typeof(self) strongSelf = weakSelf;
+    if (strongSelf) {
+      [strongSelf finishWithError:[NSError errorWithDomain:kGRPCErrorDomain
+                                                      code:GRPCErrorCodeUnavailable
+                                                  userInfo:@{NSLocalizedDescriptionKey: @"Connectivity lost."}]];
+      [[GRPCHost hostWithAddress:strongSelf->_host] disconnect];
+    }
+  }];
 }
 
 - (void)setState:(GRXWriterState)newState {
@@ -385,4 +409,5 @@ NSString * const kGRPCTrailersKey = @"io.grpc.TrailersKey";
       return;
   }
 }
+
 @end
diff --git a/src/objective-c/GRPCClient/private/GRPCChannel.h b/src/objective-c/GRPCClient/private/GRPCChannel.h
index 8661ae6f97273d0258c4f747133b28f8ef5f7eea..e49a6aca2972c08b194ed9f488d76073c775640a 100644
--- a/src/objective-c/GRPCClient/private/GRPCChannel.h
+++ b/src/objective-c/GRPCClient/private/GRPCChannel.h
@@ -35,6 +35,7 @@
 
 #include <grpc/grpc.h>
 
+@class GRPCCompletionQueue;
 struct grpc_channel_credentials;
 
 
@@ -80,4 +81,6 @@ struct grpc_channel_credentials;
 + (nonnull GRPCChannel *)insecureChannelWithHost:(nonnull NSString *)host
                                      channelArgs:(nullable NSDictionary *)channelArgs;
 
+- (nullable grpc_call *)unmanagedCallWithPath:(nonnull NSString *)path
+                              completionQueue:(nonnull GRPCCompletionQueue *)queue;
 @end
diff --git a/src/objective-c/GRPCClient/private/GRPCChannel.m b/src/objective-c/GRPCClient/private/GRPCChannel.m
index 7e55a473d74689f1fa27298200d59a30b24e9cd1..d7de025e21da1c8079a2b1acec534026e38bd987 100644
--- a/src/objective-c/GRPCClient/private/GRPCChannel.m
+++ b/src/objective-c/GRPCClient/private/GRPCChannel.m
@@ -38,6 +38,8 @@
 #include <grpc/support/log.h>
 #include <grpc/support/string_util.h>
 
+#import "GRPCCompletionQueue.h"
+
 /**
  * Returns @c grpc_channel_credentials from the specified @c path. If the file at the path could not
  * be read then NULL is returned. If NULL is returned, @c errorPtr may not be NULL if there are
@@ -205,4 +207,16 @@ grpc_channel_args * buildChannelArgs(NSDictionary *dictionary) {
                                channelArgs:channelArgs];
 }
 
+- (grpc_call *)unmanagedCallWithPath:(NSString *)path
+                     completionQueue:(GRPCCompletionQueue *)queue {
+  return grpc_channel_create_call(_unmanagedChannel,
+                                  NULL, GRPC_PROPAGATE_DEFAULTS,
+                                  queue.unmanagedQueue,
+                                  path.UTF8String,
+                                  // Get "host" from "host:port"
+                                  // TODO(jcanizales): Use NSURLs throughout, to clarify these.
+                                  [_host componentsSeparatedByString:@":"][0].UTF8String,
+                                  gpr_inf_future(GPR_CLOCK_REALTIME), NULL);
+}
+
 @end
diff --git a/src/objective-c/GRPCClient/private/GRPCCompletionQueue.h b/src/objective-c/GRPCClient/private/GRPCCompletionQueue.h
index 7b66cd4c32902fa43e1d2b1c9cd6574a429376d0..a52095dd011c832ab82971605dbb028234e9c1ac 100644
--- a/src/objective-c/GRPCClient/private/GRPCCompletionQueue.h
+++ b/src/objective-c/GRPCClient/private/GRPCCompletionQueue.h
@@ -36,6 +36,8 @@
 
 typedef void(^GRPCQueueCompletionHandler)(bool success);
 
+extern const int64_t kGRPCCompletionQueueDefaultTimeoutSecs;
+
 /**
  * This class lets one more easily use |grpc_completion_queue|. To use it, pass the value of the
  * |unmanagedQueue| property of an instance of this class to |grpc_channel_create_call|. Then for
@@ -49,6 +51,11 @@ typedef void(^GRPCQueueCompletionHandler)(bool success);
  */
 @interface GRPCCompletionQueue : NSObject
 @property(nonatomic, readonly) grpc_completion_queue *unmanagedQueue;
+@property(nonatomic, readonly) int64_t timeoutSecs;
 
 + (instancetype)completionQueue;
+
+- (instancetype)init;
+- (instancetype)initWithTimeout:(int64_t)timeoutSecs NS_DESIGNATED_INITIALIZER;
+
 @end
diff --git a/src/objective-c/GRPCClient/private/GRPCCompletionQueue.m b/src/objective-c/GRPCClient/private/GRPCCompletionQueue.m
index ff3031678c5d72efe78243f1c0627cad8275f34a..250bbf03a66d8a95f7807c303f43896878a623f3 100644
--- a/src/objective-c/GRPCClient/private/GRPCCompletionQueue.m
+++ b/src/objective-c/GRPCClient/private/GRPCCompletionQueue.m
@@ -35,6 +35,9 @@
 
 #import <grpc/grpc.h>
 
+
+const int64_t kGRPCCompletionQueueDefaultTimeoutSecs = 60;
+
 @implementation GRPCCompletionQueue
 
 + (instancetype)completionQueue {
@@ -42,8 +45,13 @@
 }
 
 - (instancetype)init {
+  return [self initWithTimeout:kGRPCCompletionQueueDefaultTimeoutSecs];
+}
+
+- (instancetype)initWithTimeout:(int64_t)timeoutSecs {
   if ((self = [super init])) {
     _unmanagedQueue = grpc_completion_queue_create(NULL);
+    _timeoutSecs = timeoutSecs;
 
     // This is for the following block to capture the pointer by value (instead
     // of retaining self and doing self->_unmanagedQueue). This is essential
@@ -61,22 +69,28 @@
       gDefaultConcurrentQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
     });
     dispatch_async(gDefaultConcurrentQueue, ^{
+      // Using a non-infinite deadline to re-enter grpc_completion_queue_next()
+      // alleviates https://github.com/grpc/grpc/issues/5593
+      gpr_timespec deadline = (timeoutSecs < 0)
+          ? gpr_inf_future(GPR_CLOCK_REALTIME)
+          : gpr_time_from_seconds(timeoutSecs, GPR_CLOCK_REALTIME);
       while (YES) {
-        // The following call blocks until an event is available.
-        grpc_event event = grpc_completion_queue_next(unmanagedQueue,
-                                                      gpr_inf_future(GPR_CLOCK_REALTIME),
-                                                      NULL);
+        // The following call blocks until an event is available or the deadline elapses.
+        grpc_event event = grpc_completion_queue_next(unmanagedQueue, deadline, NULL);
         GRPCQueueCompletionHandler handler;
         switch (event.type) {
           case GRPC_OP_COMPLETE:
             handler = (__bridge_transfer GRPCQueueCompletionHandler)event.tag;
             handler(event.success);
             break;
+          case GRPC_QUEUE_TIMEOUT:
+            // Nothing to do here
+            break;
           case GRPC_QUEUE_SHUTDOWN:
             grpc_completion_queue_destroy(unmanagedQueue);
             return;
           default:
-            [NSException raise:@"Unrecognized completion type" format:@""];
+            [NSException raise:@"Unrecognized completion type" format:@"type=%d", event.type];
         }
       };
     });
diff --git a/src/objective-c/GRPCClient/private/GRPCConnectivityMonitor.h b/src/objective-c/GRPCClient/private/GRPCConnectivityMonitor.h
new file mode 100644
index 0000000000000000000000000000000000000000..2fae410331517e9739964683402706fd6f1e1e65
--- /dev/null
+++ b/src/objective-c/GRPCClient/private/GRPCConnectivityMonitor.h
@@ -0,0 +1,77 @@
+/*
+ *
+ * Copyright 2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#import <Foundation/Foundation.h>
+#import <SystemConfiguration/SystemConfiguration.h>
+
+@interface GRPCReachabilityFlags : NSObject
+
++ (nonnull instancetype)flagsWithFlags:(SCNetworkReachabilityFlags)flags;
+
+/**
+ * One accessor method to query each of the different flags. Example:
+
+@property(nonatomic, readonly) BOOL isCell;
+
+ */
+#define GRPC_XMACRO_ITEM(methodName, FlagName) \
+@property(nonatomic, readonly) BOOL methodName;
+
+#include "GRPCReachabilityFlagNames.xmacro.h"
+#undef GRPC_XMACRO_ITEM
+
+@property(nonatomic, readonly) BOOL isHostReachable;
+@end
+
+
+@interface GRPCConnectivityMonitor : NSObject
+
++ (nullable instancetype)monitorWithHost:(nonnull NSString *)hostName;
+
+- (nonnull instancetype)init NS_UNAVAILABLE;
+
+/**
+ * Queue on which callbacks will be dispatched. Default is the main queue. Set it before calling
+ * handleLossWithHandler:.
+ */
+// TODO(jcanizales): Default to a serial background queue instead.
+@property(nonatomic, strong, null_resettable) dispatch_queue_t queue;
+
+/**
+ * Calls handler every time the connectivity to this instance's host is lost. If this instance is
+ * released before that happens, the handler won't be called.
+ * Only one handler is active at a time, so if this method is called again before the previous
+ * handler has been called, it might never be called at all (or yes, if it has already been queued).
+ */
+- (void)handleLossWithHandler:(nonnull void (^)())handler;
+@end
diff --git a/src/objective-c/GRPCClient/private/GRPCConnectivityMonitor.m b/src/objective-c/GRPCClient/private/GRPCConnectivityMonitor.m
new file mode 100644
index 0000000000000000000000000000000000000000..b4061bd5ef52e5100c75c00b15d948cadda1bbc3
--- /dev/null
+++ b/src/objective-c/GRPCClient/private/GRPCConnectivityMonitor.m
@@ -0,0 +1,192 @@
+/*
+ *
+ * Copyright 2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#import "GRPCConnectivityMonitor.h"
+
+#pragma mark Flags
+
+@implementation GRPCReachabilityFlags {
+  SCNetworkReachabilityFlags _flags;
+}
+
++ (instancetype)flagsWithFlags:(SCNetworkReachabilityFlags)flags {
+  return [[self alloc] initWithFlags:flags];
+}
+
+- (instancetype)initWithFlags:(SCNetworkReachabilityFlags)flags {
+  if ((self = [super init])) {
+    _flags = flags;
+  }
+  return self;
+}
+
+/*
+ * One accessor method implementation per flag. Example:
+
+- (BOOL)isCell { \
+  return !!(_flags & kSCNetworkReachabilityFlagsIsWWAN); \
+}
+
+ */
+#define GRPC_XMACRO_ITEM(methodName, FlagName) \
+- (BOOL)methodName { \
+  return !!(_flags & kSCNetworkReachabilityFlags ## FlagName); \
+}
+#include "GRPCReachabilityFlagNames.xmacro.h"
+#undef GRPC_XMACRO_ITEM
+
+- (BOOL)isHostReachable {
+  // Note: connectionOnDemand means it'll be reachable only if using the CFSocketStream API or APIs
+  // on top of it.
+  // connectionRequired means we can't tell until a connection is attempted (e.g. for VPN on
+  // demand).
+  return self.reachable && !self.interventionRequired && !self.connectionOnDemand;
+}
+
+- (NSString *)description {
+  NSMutableArray *activeOptions = [NSMutableArray arrayWithCapacity:9];
+
+  /*
+   * For each flag, add its name to the array if it's ON. Example:
+
+  if (self.isCell) {
+    [activeOptions addObject:@"isCell"];
+  }
+
+   */
+#define GRPC_XMACRO_ITEM(methodName, FlagName) \
+  if (self.methodName) { \
+    [activeOptions addObject:@#methodName]; \
+  }
+#include "GRPCReachabilityFlagNames.xmacro.h"
+#undef GRPC_XMACRO_ITEM
+
+  return activeOptions.count == 0 ? @"(none)" : [activeOptions componentsJoinedByString:@", "];
+}
+
+- (BOOL)isEqual:(id)object {
+  return [object isKindOfClass:[GRPCReachabilityFlags class]] &&
+      _flags == ((GRPCReachabilityFlags *)object)->_flags;
+}
+
+- (NSUInteger)hash {
+  return _flags;
+}
+@end
+
+#pragma mark Connectivity Monitor
+
+// Assumes the third argument is a block that accepts a GRPCReachabilityFlags object, and passes the
+// received ones to it.
+static void PassFlagsToContextInfoBlock(SCNetworkReachabilityRef target,
+                                        SCNetworkReachabilityFlags flags,
+                                        void *info) {
+  #pragma unused (target)
+  // This can be called many times with the same info. The info is retained by SCNetworkReachability
+  // while this function is being executed.
+  void (^handler)(GRPCReachabilityFlags *) = (__bridge void (^)(GRPCReachabilityFlags *))info;
+  handler([[GRPCReachabilityFlags alloc] initWithFlags:flags]);
+}
+
+@implementation GRPCConnectivityMonitor {
+  SCNetworkReachabilityRef _reachabilityRef;
+}
+
+- (nullable instancetype)initWithReachability:(nullable SCNetworkReachabilityRef)reachability {
+  if (!reachability) {
+    return nil;
+  }
+  if ((self = [super init])) {
+    _reachabilityRef = CFRetain(reachability);
+    _queue = dispatch_get_main_queue();
+  }
+  return self;
+}
+
++ (nullable instancetype)monitorWithHost:(nonnull NSString *)host {
+  const char *hostName = host.UTF8String;
+  if (!hostName) {
+    [NSException raise:NSInvalidArgumentException
+                format:@"host.UTF8String returns NULL for %@", host];
+  }
+  SCNetworkReachabilityRef reachability =
+      SCNetworkReachabilityCreateWithName(NULL, hostName);
+
+  GRPCConnectivityMonitor *returnValue = [[self alloc] initWithReachability:reachability];
+  if (reachability) {
+    CFRelease(reachability);
+  }
+  return returnValue;
+}
+
+- (void)handleLossWithHandler:(void (^)())handler {
+  [self startListeningWithHandler:^(GRPCReachabilityFlags *flags) {
+    if (!flags.isHostReachable) {
+      handler();
+    }
+  }];
+}
+
+- (void)startListeningWithHandler:(void (^)(GRPCReachabilityFlags *))handler {
+  // Copy to ensure the handler block is in the heap (and so can't be deallocated when this method
+  // returns).
+  void (^copiedHandler)(GRPCReachabilityFlags *) = [handler copy];
+  SCNetworkReachabilityContext context = {
+    .version = 0,
+    .info = (__bridge void *)copiedHandler,
+    .retain = CFRetain,
+    .release = CFRelease,
+  };
+  // The following will retain context.info, and release it when the callback is set to NULL.
+  SCNetworkReachabilitySetCallback(_reachabilityRef, PassFlagsToContextInfoBlock, &context);
+  SCNetworkReachabilitySetDispatchQueue(_reachabilityRef, _queue);
+}
+
+- (void)stopListening {
+  // This releases the block on context.info.
+  SCNetworkReachabilitySetCallback(_reachabilityRef, NULL, NULL);
+  SCNetworkReachabilitySetDispatchQueue(_reachabilityRef, NULL);
+}
+
+- (void)setQueue:(dispatch_queue_t)queue {
+  _queue = queue ?: dispatch_get_main_queue();
+}
+
+- (void)dealloc {
+  if (_reachabilityRef) {
+    [self stopListening];
+    CFRelease(_reachabilityRef);
+  }
+}
+
+@end
diff --git a/src/objective-c/GRPCClient/private/GRPCHost.h b/src/objective-c/GRPCClient/private/GRPCHost.h
index 82c0ad6cf631fd56f7e7904df7421da9efc94b50..987d3e9f5970073210c5e3cf61b221e25a00f48a 100644
--- a/src/objective-c/GRPCClient/private/GRPCHost.h
+++ b/src/objective-c/GRPCClient/private/GRPCHost.h
@@ -33,27 +33,39 @@
 
 #import <Foundation/Foundation.h>
 
+NS_ASSUME_NONNULL_BEGIN
+
 @class GRPCCompletionQueue;
 struct grpc_call;
 
 @interface GRPCHost : NSObject
 
 @property(nonatomic, readonly) NSString *address;
-@property(nonatomic, copy) NSString *userAgentPrefix;
+@property(nonatomic, copy, nullable) NSString *userAgentPrefix;
 
 /** The following properties should only be modified for testing: */
 
 @property(nonatomic, getter=isSecure) BOOL secure;
 
-@property(nonatomic, copy) NSString *pathToCertificates;
-@property(nonatomic, copy) NSString *hostNameOverride;
+@property(nonatomic, copy, nullable) NSString *pathToCertificates;
+@property(nonatomic, copy, nullable) NSString *hostNameOverride;
 
+- (nullable instancetype)init NS_UNAVAILABLE;
 /** Host objects initialized with the same address are the same. */
-+ (instancetype)hostWithAddress:(NSString *)address;
-- (instancetype)initWithAddress:(NSString *)address NS_DESIGNATED_INITIALIZER;
++ (nullable instancetype)hostWithAddress:(NSString *)address;
+- (nullable instancetype)initWithAddress:(NSString *)address NS_DESIGNATED_INITIALIZER;
 
 /** Create a grpc_call object to the provided path on this host. */
-- (struct grpc_call *)unmanagedCallWithPath:(NSString *)path
-                            completionQueue:(GRPCCompletionQueue *)queue;
+- (nullable struct grpc_call *)unmanagedCallWithPath:(NSString *)path
+                                     completionQueue:(GRPCCompletionQueue *)queue;
 
+// TODO: There's a race when a new RPC is coming through just as an existing one is getting
+// notified that there's no connectivity. If connectivity comes back at that moment, the new RPC
+// will have its channel destroyed by the other RPC, and will never get notified of a problem, so
+// it'll hang (the C layer logs a timeout, with exponential back off). One solution could be to pass
+// the GRPCChannel to the GRPCCall, renaming this as "disconnectChannel:channel", which would only
+// act on that specific channel.
+- (void)disconnect;
 @end
+
+NS_ASSUME_NONNULL_END
diff --git a/src/objective-c/GRPCClient/private/GRPCHost.m b/src/objective-c/GRPCClient/private/GRPCHost.m
index eb1db899b700b8d899b8d47ee6a44825e779e5a6..508cb206444e04a343626db5d0d26315317c3f5c 100644
--- a/src/objective-c/GRPCClient/private/GRPCHost.m
+++ b/src/objective-c/GRPCClient/private/GRPCHost.m
@@ -34,33 +34,30 @@
 #import "GRPCHost.h"
 
 #include <grpc/grpc.h>
+#import <GRPCClient/GRPCCall.h>
 #import <GRPCClient/GRPCCall+ChannelArg.h>
 
 #import "GRPCChannel.h"
 #import "GRPCCompletionQueue.h"
 #import "NSDictionary+GRPC.h"
 
+NS_ASSUME_NONNULL_BEGIN
+
 // TODO(jcanizales): Generate the version in a standalone header, from templates. Like
 // templates/src/core/surface/version.c.template .
 #define GRPC_OBJC_VERSION_STRING @"0.13.0"
 
-@interface GRPCHost ()
-// TODO(mlumish): Investigate whether caching channels with strong links is a good idea.
-@property(nonatomic, strong) GRPCChannel *channel;
-@end
-
-@implementation GRPCHost
-
-+ (instancetype)hostWithAddress:(NSString *)address {
-  return [[self alloc] initWithAddress:address];
+@implementation GRPCHost {
+  // TODO(mlumish): Investigate whether caching channels with strong links is a good idea.
+  GRPCChannel *_channel;
 }
 
-- (instancetype)init {
-  return [self initWithAddress:nil];
++ (nullable instancetype)hostWithAddress:(NSString *)address {
+  return [[self alloc] initWithAddress:address];
 }
 
 // Default initializer.
-- (instancetype)initWithAddress:(NSString *)address {
+- (nullable instancetype)initWithAddress:(NSString *)address {
   if (!address) {
     return nil;
   }
@@ -95,46 +92,45 @@
   return self;
 }
 
-- (grpc_call *)unmanagedCallWithPath:(NSString *)path completionQueue:(GRPCCompletionQueue *)queue {
-  if (!queue || !path || !self.channel) {
-    return NULL;
+- (nullable grpc_call *)unmanagedCallWithPath:(NSString *)path
+                              completionQueue:(GRPCCompletionQueue *)queue {
+  GRPCChannel *channel;
+  // This is racing -[GRPCHost disconnect].
+  @synchronized(self) {
+    if (!_channel) {
+      _channel = [self newChannel];
+    }
+    channel = _channel;
   }
-  return grpc_channel_create_call(self.channel.unmanagedChannel,
-                                  NULL, GRPC_PROPAGATE_DEFAULTS,
-                                  queue.unmanagedQueue,
-                                  path.UTF8String,
-                                  self.hostName.UTF8String,
-                                  gpr_inf_future(GPR_CLOCK_REALTIME), NULL);
+  return [channel unmanagedCallWithPath:path completionQueue:queue];
 }
 
-- (GRPCChannel *)channel {
-  // Create it lazily, because we don't want to open a connection just because someone is
-  // configuring a host.
+- (NSDictionary *)channelArgs {
+  NSMutableDictionary *args = [NSMutableDictionary dictionary];
 
-  if (!_channel) {
-    NSMutableDictionary *args = [NSMutableDictionary dictionary];
+  // TODO(jcanizales): Add OS and device information (see
+  // https://github.com/grpc/grpc/blob/master/doc/PROTOCOL-HTTP2.md#user-agents ).
+  NSString *userAgent = @"grpc-objc/" GRPC_OBJC_VERSION_STRING;
+  if (_userAgentPrefix) {
+    userAgent = [_userAgentPrefix stringByAppendingFormat:@" %@", userAgent];
+  }
+  args[@GRPC_ARG_PRIMARY_USER_AGENT_STRING] = userAgent;
 
-    // TODO(jcanizales): Add OS and device information (see
-    // https://github.com/grpc/grpc/blob/master/doc/PROTOCOL-HTTP2.md#user-agents ).
-    NSString *userAgent = @"grpc-objc/" GRPC_OBJC_VERSION_STRING;
-    if (_userAgentPrefix) {
-      userAgent = [@[_userAgentPrefix, userAgent] componentsJoinedByString:@" "];
-    }
-    args[@GRPC_ARG_PRIMARY_USER_AGENT_STRING] = userAgent;
-
-    if (_secure) {
-      if (_hostNameOverride) {
-        args[@GRPC_SSL_TARGET_NAME_OVERRIDE_ARG] = _hostNameOverride;
-      }
-
-      _channel = [GRPCChannel secureChannelWithHost:_address
-                                 pathToCertificates:_pathToCertificates
-                                        channelArgs:args];
-    } else {
-      _channel = [GRPCChannel insecureChannelWithHost:_address channelArgs:args];
-    }
+  if (_secure && _hostNameOverride) {
+    args[@GRPC_SSL_TARGET_NAME_OVERRIDE_ARG] = _hostNameOverride;
+  }
+  return args;
+}
+
+- (GRPCChannel *)newChannel {
+  NSDictionary *args = [self channelArgs];
+  if (_secure) {
+    return [GRPCChannel secureChannelWithHost:_address
+                           pathToCertificates:_pathToCertificates
+                                  channelArgs:args];
+  } else {
+    return [GRPCChannel insecureChannelWithHost:_address channelArgs:args];
   }
-  return _channel;
 }
 
 - (NSString *)hostName {
@@ -142,7 +138,16 @@
   return _hostNameOverride ?: _address;
 }
 
+- (void)disconnect {
+  // This is racing -[GRPCHost unmanagedCallWithPath:completionQueue:].
+  @synchronized(self) {
+    _channel = nil;
+  }
+}
+
 // TODO(jcanizales): Don't let set |secure| to |NO| if |pathToCertificates| or |hostNameOverride|
 // have been set. Don't let set either of the latter if |secure| has been set to |NO|.
 
 @end
+
+NS_ASSUME_NONNULL_END
diff --git a/src/objective-c/GRPCClient/private/GRPCReachabilityFlagNames.xmacro.h b/src/objective-c/GRPCClient/private/GRPCReachabilityFlagNames.xmacro.h
new file mode 100644
index 0000000000000000000000000000000000000000..02871d5d02856f1f3f64a215caadc37583324440
--- /dev/null
+++ b/src/objective-c/GRPCClient/private/GRPCReachabilityFlagNames.xmacro.h
@@ -0,0 +1,65 @@
+/*
+ *
+ * Copyright 2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+/**
+ * "X-macro" file that lists the flags names of Apple's Network Reachability API, along with a nice
+ * Objective-C method name used to query each of them.
+ *
+ * Example usage: To generate a dictionary from flag value to name, one can do:
+
+  NSDictionary *flagNames = @{
+#define GRPC_XMACRO_ITEM(methodName, FlagName) \
+    @(kSCNetworkReachabilityFlags ## FlagName): @#methodName,
+#include "GRXReachabilityFlagNames.xmacro.h"
+#undef GRPC_XMACRO_ITEM
+  };
+
+  XCTAssertEqualObjects(flagNames[@(kSCNetworkReachabilityFlagsIsWWAN)], @"isCell");
+
+ */
+
+#ifndef GRPC_XMACRO_ITEM
+#error This file is to be used with the "X-macro" pattern: Please #define \
+       GRPC_XMACRO_ITEM(methodName, FlagName), then #include this file, and then #undef \
+       GRPC_XMACRO_ITEM.
+#endif
+
+GRPC_XMACRO_ITEM(isCell, IsWWAN)
+GRPC_XMACRO_ITEM(reachable, Reachable)
+GRPC_XMACRO_ITEM(transientConnection, TransientConnection)
+GRPC_XMACRO_ITEM(connectionRequired, ConnectionRequired)
+GRPC_XMACRO_ITEM(connectionOnTraffic, ConnectionOnTraffic)
+GRPC_XMACRO_ITEM(interventionRequired, InterventionRequired)
+GRPC_XMACRO_ITEM(connectionOnDemand, ConnectionOnDemand)
+GRPC_XMACRO_ITEM(isLocalAddress, IsLocalAddress)
+GRPC_XMACRO_ITEM(isDirect, IsDirect)
diff --git a/src/objective-c/GRPCClient/private/GRPCWrappedCall.h b/src/objective-c/GRPCClient/private/GRPCWrappedCall.h
index 71e7e0e54eeb87f8b451b56d1040b6a0678f1009..e37ed1b59fb7ba530a3ebc7d0f246591cc8aa7d9 100644
--- a/src/objective-c/GRPCClient/private/GRPCWrappedCall.h
+++ b/src/objective-c/GRPCClient/private/GRPCWrappedCall.h
@@ -34,7 +34,6 @@
 #import <Foundation/Foundation.h>
 #include <grpc/grpc.h>
 
-#import "GRPCChannel.h"
 #import "GRPCRequestHeaders.h"
 
 @interface GRPCOperation : NSObject
@@ -94,4 +93,5 @@
 - (void)startBatchWithOperations:(NSArray *)ops;
 
 - (void)cancel;
+
 @end
diff --git a/src/php/README.md b/src/php/README.md
index b368482f068dec1b3b88b28020b2e8eec93de12d..cf8f2c11b0fa5e1aca376ffd6f7212e94ce41095 100644
--- a/src/php/README.md
+++ b/src/php/README.md
@@ -9,14 +9,21 @@ Beta
 
 ## Environment
 
-Prerequisite: PHP 5.5 or later, `phpunit`, `pecl`
+Prerequisite: `php` >=5.5, `phpize`, `pecl`, `phpunit`
 
-**Linux:**
+**Linux (Debian):**
 
 ```sh
 $ sudo apt-get install php5 php5-dev php-pear
 ```
 
+**Linux (CentOS):**
+
+```sh
+$ yum install php55w
+$ yum --enablerepo=remi,remi-php55 install php-devel php-pear
+```
+
 **Mac OS X:**
 
 ```sh
@@ -24,11 +31,11 @@ $ curl -O http://pear.php.net/go-pear.phar
 $ sudo php -d detect_unicode=0 go-pear.phar
 ```
 
-**PHPUnit: (Both Linux and Mac OS X)**
+**PHPUnit:**
 ```sh
-$ curl https://phar.phpunit.de/phpunit.phar -o phpunit.phar
-$ chmod +x phpunit.phar
-$ sudo mv phpunit.phar /usr/local/bin/phpunit
+$ wget https://phar.phpunit.de/phpunit-old.phar
+$ chmod +x phpunit-old.phar
+$ sudo mv phpunit-old.phar /usr/bin/phpunit
 ```
 
 ## Quick Install
@@ -39,15 +46,22 @@ Install the gRPC PHP extension
 sudo pecl install grpc-beta
 ```
 
+This will compile and install the gRPC PHP extension into the standard PHP extension directory. You should be able to run the [unit tests](#unit-tests), with the PHP extension installed.
+
+To run tests with generated stub code from `.proto` files, you will also need the `composer`, `protoc` and `protoc-gen-php` binaries. You can find out how to get these [below](#generated-code-tests).
+
 ## Build from Source
 
+
+### gRPC C core library
+
 Clone this repository
 
 ```sh
 $ git clone https://github.com/grpc/grpc.git
 ```
 
-Build and install the gRPC C core libraries
+Build and install the gRPC C core library
 
 ```sh
 $ cd grpc
@@ -56,20 +70,15 @@ $ make
 $ sudo make install
 ```
 
-Note: you may encounter a warning about the Protobuf compiler `protoc` 3.0.0+ not being installed. The following might help, and will be useful later on when we need to compile the `protoc-gen-php` tool.
+### gRPC PHP extension
 
-```sh
-$ cd grpc/third_party/protobuf
-$ sudo make install   # 'make' should have been run by core grpc
-```
-
-Install the gRPC PHP extension
+Install the gRPC PHP extension from PECL
 
 ```sh
 $ sudo pecl install grpc-beta
 ```
 
-OR
+Or, compile from source
 
 ```sh
 $ cd grpc/src/php/ext/grpc
@@ -79,58 +88,98 @@ $ make
 $ sudo make install
 ```
 
+### Update php.ini
+
 Add this line to your `php.ini` file, e.g. `/etc/php5/cli/php.ini`
 
 ```sh
 extension=grpc.so
 ```
 
-Install Composer
+## Unit Tests
+
+You will need the source code to run tests
+
+```sh
+$ git clone https://github.com/grpc/grpc.git
+$ cd grpc
+$ git pull --recurse-submodules && git submodule update --init --recursive
+```
+
+Run unit tests
 
 ```sh
 $ cd grpc/src/php
+$ ./bin/run_tests.sh
+```
+
+## Generated Code Tests
+
+This section specifies the prerequisites for running the generated code tests, as well as how to run the tests themselves.
+
+### Composer
+
+If you don't have it already, install `composer` to pull in some runtime dependencies based on the `composer.json` file.
+
+```sh
 $ curl -sS https://getcomposer.org/installer | php
 $ sudo mv composer.phar /usr/local/bin/composer
+
+$ cd grpc/src/php
 $ composer install
 ```
 
-## Unit Tests
+### Protobuf compiler
 
-Run unit tests
+Again if you don't have it already, you need to install the protobuf compiler `protoc`, version 3.0.0+.
+
+If you compiled the gRPC C core library from source above, the `protoc` binary should have been installed as well. If it hasn't been installed, you can run the following commands to install it.
 
 ```sh
-$ cd grpc/src/php
-$ ./bin/run_tests.sh
+$ cd grpc/third_party/protobuf
+$ sudo make install   # 'make' should have been run by core grpc
 ```
 
-## Generated Code Tests
+Alternatively, you can download `protoc` binaries from [the protocol buffers Github repository](https://github.com/google/protobuf/releases).
 
-Install `protoc-gen-php`
+
+### PHP protobuf compiler
+
+You need to install `protoc-gen-php` to generate stub class `.php` files from service definition `.proto` files.
 
 ```sh
-$ cd grpc/src/php/vendor/datto/protobuf-php
+$ cd grpc/src/php/vendor/datto/protobuf-php # if you had run `composer install` in the previous step
+
+OR
+
+$ git clone https://github.com/stanley-cheung/Protobuf-PHP # clone from github repo
+
 $ gem install rake ronn
 $ rake pear:package version=1.0
 $ sudo pear install Protobuf-1.0.tgz
 ```
 
-Generate client stub code
+### Client Stub
+
+Generate client stub classes from `.proto` files
 
 ```sh
 $ cd grpc/src/php
 $ ./bin/generate_proto_php.sh
 ```
 
-Run a local server serving the math services
+### Run test server
 
- - Please see [Node][] on how to run an example server
+Run a local server serving the math services. Please see [Node][] for how to run an example server.
 
 ```sh
-$ cd grpc/src/node
+$ cd grpc
 $ npm install
-$ nodejs examples/math_server.js
+$ nodejs src/node/test/math/math_server.js
 ```
 
+### Run test client
+
 Run the generated code tests
 
 ```sh
@@ -161,13 +210,15 @@ $ sudo service apache2 restart
 Make sure the Node math server is still running, as above. 
 
 ```sh
-$ cd grpc/src/node
-$ nodejs examples/math_server.js
+$ cd grpc
+$ npm install
+$ nodejs src/node/test/math/math_server.js
 ```
 
 Make sure you have run `composer install` to generate the `vendor/autoload.php` file
 
 ```sh
+$ cd grpc/src/php
 $ composer install
 ```
 
@@ -229,13 +280,15 @@ $ sudo service php5-fpm restart
 Make sure the Node math server is still running, as above. 
 
 ```sh
-$ cd grpc/src/node
-$ nodejs examples/math_server.js
+$ cd grpc
+$ npm install
+$ nodejs src/node/test/math/math_server.js
 ```
 
 Make sure you have run `composer install` to generate the `vendor/autoload.php` file
 
 ```sh
+$ cd grpc/src/php
 $ composer install
 ```
 
diff --git a/src/php/composer.json b/src/php/composer.json
index 1d41f847ac03bf25a7be2976c52abbe2ad9bdd7d..01674a25db8168143d0e255e2c8f9e7eca5ce1d7 100644
--- a/src/php/composer.json
+++ b/src/php/composer.json
@@ -1,7 +1,9 @@
 {
   "name": "grpc/grpc",
+  "type": "library",
   "description": "gRPC library for PHP",
-  "version": "0.6.0",
+  "version": "0.14.0",
+  "keywords": ["rpc"],
   "homepage": "http://grpc.io",
   "license": "BSD-3-Clause",
   "repositories": [
@@ -13,7 +15,7 @@
   "require": {
     "php": ">=5.5.0",
     "datto/protobuf-php": "dev-master",
-    "google/auth": "dev-master"
+    "google/auth": "v0.7"
   },
   "autoload": {
     "psr-4": {
diff --git a/src/php/ext/grpc/README.md b/src/php/ext/grpc/README.md
deleted file mode 100644
index 6e1cb2002f5c96e1fbb57c8189f06205acc3a315..0000000000000000000000000000000000000000
--- a/src/php/ext/grpc/README.md
+++ /dev/null
@@ -1,67 +0,0 @@
-gRPC PHP Extension
-==================
-
-# Requirements
-
- * PHP 5.5+
- * [gRPC core library](https://github.com/grpc/grpc) 0.11.0
-
-# Installation
-
-## Install PHP 5
-
-```
-$ sudo apt-get install git php5 php5-dev php-pear unzip
-```
-
-## Compile gRPC Core Library
-
-Clone the gRPC source code repository
-
-```
-$ git clone https://github.com/grpc/grpc.git
-```
-
-Build and install the gRPC C core libraries
-
-```sh
-$ cd grpc
-$ git checkout --track origin/release-0_11
-$ git pull --recurse-submodules && git submodule update --init --recursive
-$ make
-$ sudo make install
-```
-
-Note: you may encounter a warning about the Protobuf compiler `protoc` 3.0.0+ not being installed. The following might help, and will be useful later on when we need to compile the `protoc-gen-php` tool.
-
-```sh
-$ cd grpc/third_party/protobuf
-$ sudo make install   # 'make' should have been run by core grpc
-```
-
-## Install the gRPC PHP extension
-
-Quick install
-
-```sh
-$ sudo pecl install grpc
-```
-
-Note: before a stable release, you may need to do
-
-```sh
-$ sudo pecl install grpc-beta
-```
-
-OR
-
-Compile from source
-
-```sh
-$ # from grpc
-$ cd src/php/ext/grpc
-$ phpize
-$ ./configure
-$ make
-$ sudo make install
-```
diff --git a/src/php/tests/generated_code/math_client.php b/src/php/tests/generated_code/math_client.php
index 76ccabc0684972d5878b8d8924dc8c7d234f7588..2085560d19e03dad9ef44619a5954325a479192b 100644
--- a/src/php/tests/generated_code/math_client.php
+++ b/src/php/tests/generated_code/math_client.php
@@ -1,7 +1,7 @@
 <?php
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -43,7 +43,9 @@ function p($line)
 
 $host = 'localhost:50051';
 p("Connecting to host: $host");
-$client = new math\MathClient($host, []);
+$client = new math\MathClient($host, [
+    'credentials' => Grpc\ChannelCredentials::createInsecure()
+]);
 p('Client class: '.get_class($client));
 p('');
 
diff --git a/src/python/grpcio/README.rst b/src/python/grpcio/README.rst
index f3e962c1971fb322b96a51250de90bc1b91fe7a1..3dfae50b4bc030b12bc401c75f52caabe3f6b2b4 100644
--- a/src/python/grpcio/README.rst
+++ b/src/python/grpcio/README.rst
@@ -6,7 +6,7 @@ Package for gRPC Python.
 Installation
 ------------
 
-gRPC Python is available for Linux and Mac OS X running Python 2.7.
+gRPC Python is available for Linux, Mac OS X, and Windows running Python 2.7.
 
 From PyPI
 ~~~~~~~~~
@@ -23,11 +23,15 @@ Else system wide (on Ubuntu)...
 
   $ sudo pip install grpcio
 
+n.b. On Windows and on Mac OS X one *must* have a recent release of :code:`pip`
+to retrieve the proper wheel from PyPI. Be sure to upgrade to the latest
+version!
+
 From Source
 ~~~~~~~~~~~
 
 Building from source requires that you have the Python headers (usually a
-package named `python-dev`).
+package named :code:`python-dev`).
 
 ::
 
@@ -36,8 +40,8 @@ package named `python-dev`).
   $ cd $REPO_ROOT
   $ pip install .
 
-Note that `$REPO_ROOT` can be assigned to whatever directory name floats your
-fancy.
+Note that :code:`$REPO_ROOT` can be assigned to whatever directory name floats
+your fancy.
 
 Troubleshooting
 ~~~~~~~~~~~~~~~
diff --git a/src/python/grpcio/commands.py b/src/python/grpcio/commands.py
index aa29c728f259e6e47e2689e8978fd07b6bea7213..c1f444f6f1f07911aa1c8d50acd84d3b8bd3e354 100644
--- a/src/python/grpcio/commands.py
+++ b/src/python/grpcio/commands.py
@@ -119,8 +119,7 @@ class SphinxDocumentation(setuptools.Command):
     import sphinx
     import sphinx.apidoc
     metadata = self.distribution.metadata
-    src_dir = os.path.join(
-        PYTHON_STEM, self.distribution.package_dir[''], 'grpc')
+    src_dir = os.path.join(PYTHON_STEM, 'grpc')
     sys.path.append(src_dir)
     sphinx.apidoc.main([
         '', '--force', '--full', '-H', metadata.name, '-A', metadata.author,
@@ -264,6 +263,42 @@ class Gather(setuptools.Command):
       self.distribution.fetch_build_eggs(self.distribution.tests_require)
 
 
+class TestLite(setuptools.Command):
+  """Command to run tests without fetching or building anything."""
+
+  description = 'run tests without fetching or building anything.'
+  user_options = []
+
+  def initialize_options(self):
+    pass
+
+  def finalize_options(self):
+    # distutils requires this override.
+    pass
+
+  def run(self):
+    self._add_eggs_to_path()
+
+    import tests
+    loader = tests.Loader()
+    loader.loadTestsFromNames(['tests'])
+    runner = tests.Runner()
+    result = runner.run(loader.suite)
+    if not result.wasSuccessful():
+      sys.exit('Test failure')
+
+  def _add_eggs_to_path(self):
+    """Adds all egg files under .eggs to sys.path"""
+    # TODO(jtattemusch): there has to be a cleaner way to do this
+    import pkg_resources
+    eggs_dir = os.path.join(PYTHON_STEM, '../../../.eggs')
+    eggs = [os.path.join(eggs_dir, filename)
+            for filename in os.listdir(eggs_dir)
+            if filename.endswith('.egg')]
+    for egg in eggs:
+      sys.path.insert(0, pkg_resources.normalize_path(egg))
+
+
 class RunInterop(test.test):
 
   description = 'run interop test client/server'
diff --git a/src/python/grpcio/grpc/_cython/_cygrpc/channel.pyx.pxi b/src/python/grpcio/grpc/_cython/_cygrpc/channel.pyx.pxi
index 1f1833d5eccb26d9aa94ca550c953447588ee239..bc03c4dcf1948f9f0c9972e5fa3b5c583a999b91 100644
--- a/src/python/grpcio/grpc/_cython/_cygrpc/channel.pyx.pxi
+++ b/src/python/grpcio/grpc/_cython/_cygrpc/channel.pyx.pxi
@@ -95,7 +95,6 @@ cdef class Channel:
       self, grpc_connectivity_state last_observed_state,
       Timespec deadline not None, CompletionQueue queue not None, tag):
     cdef OperationTag operation_tag = OperationTag(tag)
-    operation_tag.references = [self, queue]
     cpython.Py_INCREF(operation_tag)
     grpc_channel_watch_connectivity_state(
         self.c_channel, last_observed_state, deadline.c_time,
diff --git a/src/python/grpcio/grpc/_cython/_cygrpc/completion_queue.pyx.pxi b/src/python/grpcio/grpc/_cython/_cygrpc/completion_queue.pyx.pxi
index c139147114bc8f20177451d537de6e1d79a7fd08..e11138b1cd8ac690256d47a227801f3a24ac48ae 100644
--- a/src/python/grpcio/grpc/_cython/_cygrpc/completion_queue.pyx.pxi
+++ b/src/python/grpcio/grpc/_cython/_cygrpc/completion_queue.pyx.pxi
@@ -140,7 +140,8 @@ cdef class CompletionQueue:
         grpc_completion_queue_shutdown(self.c_completion_queue)
       # Pump the queue
       while not self.is_shutdown:
-        event = grpc_completion_queue_next(
-            self.c_completion_queue, c_deadline, NULL)
+        with nogil:
+          event = grpc_completion_queue_next(
+              self.c_completion_queue, c_deadline, NULL)
         self._interpret_event(event)
       grpc_completion_queue_destroy(self.c_completion_queue)
diff --git a/src/python/grpcio/grpc/_cython/_cygrpc/server.pyx.pxi b/src/python/grpcio/grpc/_cython/_cygrpc/server.pyx.pxi
index fe93da6c1244fd1a3528f6811be6c8d21d755252..5f859235246569c306b71719b8320be85bfd0c1c 100644
--- a/src/python/grpcio/grpc/_cython/_cygrpc/server.pyx.pxi
+++ b/src/python/grpcio/grpc/_cython/_cygrpc/server.pyx.pxi
@@ -106,7 +106,6 @@ cdef class Server:
     self.is_shutting_down = True
     operation_tag = OperationTag(tag)
     operation_tag.shutting_down_server = self
-    operation_tag.references.extend([self, queue])
     cpython.Py_INCREF(operation_tag)
     grpc_server_shutdown_and_notify(
         self.c_server, queue.c_completion_queue,
diff --git a/src/python/grpcio/precompiled.py b/src/python/grpcio/precompiled.py
index ae2a0c835a0786867c14bb5c8974cf06642adb97..d34250b02c4130f7db0596f7194420731428d0d3 100644
--- a/src/python/grpcio/precompiled.py
+++ b/src/python/grpcio/precompiled.py
@@ -31,6 +31,7 @@ import os
 import platform
 import shutil
 import sys
+import sysconfig
 
 import setuptools
 
@@ -51,9 +52,15 @@ USE_PRECOMPILED_BINARIES = bool(int(os.environ.get(
 
 def _tagged_ext_name(base):
   uname = platform.uname()
-  tags = '-'.join((grpc_version.VERSION, uname[0], uname[4]))
-  flavor = 'ucs2' if sys.maxunicode == 65535 else 'ucs4'
-  return '{base}-{tags}-{flavor}'.format(base=base, tags=tags, flavor=flavor)
+  tags = (
+      grpc_version.VERSION,
+      'py{}'.format(sysconfig.get_python_version()),
+      uname[0],
+      uname[4],
+  )
+  ucs = 'ucs{}'.format(sysconfig.get_config_var('Py_UNICODE_SIZE'))
+  return '{base}-{tags}-{ucs}'.format(
+      base=base, tags='-'.join(tags), ucs=ucs)
 
 
 class BuildTaggedExt(setuptools.Command):
diff --git a/src/python/grpcio/tests/_runner.py b/src/python/grpcio/tests/_runner.py
index 38a5432e791790db21eb4cff98a4c8d17b51a0e2..b0dbd92a4955e8a2e093ebb6b03348ec4d15a281 100644
--- a/src/python/grpcio/tests/_runner.py
+++ b/src/python/grpcio/tests/_runner.py
@@ -144,7 +144,7 @@ class Runner(object):
   def run(self, suite):
     """See setuptools' test_runner setup argument for information."""
     # only run test cases with id starting with given prefix
-    testcase_filter = os.getenv('GPRC_PYTHON_TESTRUNNER_FILTER')
+    testcase_filter = os.getenv('GRPC_PYTHON_TESTRUNNER_FILTER')
     filtered_cases = []
     for case in _loader.iterate_suite_cases(suite):
       if not testcase_filter or case.id().startswith(testcase_filter):
diff --git a/src/python/grpcio/tests/tests.json b/src/python/grpcio/tests/tests.json
index 388d040d5caa67c97da8352c2d1a4539b689c00a..84870aaa5cb7777ea29c6d6e09394641cb56c8fc 100644
--- a/src/python/grpcio/tests/tests.json
+++ b/src/python/grpcio/tests/tests.json
@@ -12,31 +12,22 @@
   "_core_over_links_base_interface_test.SyncEasyTest", 
   "_core_over_links_base_interface_test.SyncPeasyTest", 
   "_crust_over_core_face_interface_test.DynamicInvokerBlockingInvocationInlineServiceTest", 
-  "_crust_over_core_face_interface_test.DynamicInvokerEventInvocationSynchronousEventServiceTest", 
   "_crust_over_core_face_interface_test.DynamicInvokerFutureInvocationAsynchronousEventServiceTest", 
   "_crust_over_core_face_interface_test.GenericInvokerBlockingInvocationInlineServiceTest", 
-  "_crust_over_core_face_interface_test.GenericInvokerEventInvocationSynchronousEventServiceTest", 
   "_crust_over_core_face_interface_test.GenericInvokerFutureInvocationAsynchronousEventServiceTest", 
   "_crust_over_core_face_interface_test.MultiCallableInvokerBlockingInvocationInlineServiceTest", 
-  "_crust_over_core_face_interface_test.MultiCallableInvokerEventInvocationSynchronousEventServiceTest", 
   "_crust_over_core_face_interface_test.MultiCallableInvokerFutureInvocationAsynchronousEventServiceTest", 
   "_crust_over_core_over_links_face_interface_test.DynamicInvokerBlockingInvocationInlineServiceTest", 
-  "_crust_over_core_over_links_face_interface_test.DynamicInvokerEventInvocationSynchronousEventServiceTest", 
   "_crust_over_core_over_links_face_interface_test.DynamicInvokerFutureInvocationAsynchronousEventServiceTest", 
   "_crust_over_core_over_links_face_interface_test.GenericInvokerBlockingInvocationInlineServiceTest", 
-  "_crust_over_core_over_links_face_interface_test.GenericInvokerEventInvocationSynchronousEventServiceTest", 
   "_crust_over_core_over_links_face_interface_test.GenericInvokerFutureInvocationAsynchronousEventServiceTest", 
   "_crust_over_core_over_links_face_interface_test.MultiCallableInvokerBlockingInvocationInlineServiceTest", 
-  "_crust_over_core_over_links_face_interface_test.MultiCallableInvokerEventInvocationSynchronousEventServiceTest", 
   "_crust_over_core_over_links_face_interface_test.MultiCallableInvokerFutureInvocationAsynchronousEventServiceTest", 
   "_face_interface_test.DynamicInvokerBlockingInvocationInlineServiceTest", 
-  "_face_interface_test.DynamicInvokerEventInvocationSynchronousEventServiceTest", 
   "_face_interface_test.DynamicInvokerFutureInvocationAsynchronousEventServiceTest", 
   "_face_interface_test.GenericInvokerBlockingInvocationInlineServiceTest", 
-  "_face_interface_test.GenericInvokerEventInvocationSynchronousEventServiceTest", 
   "_face_interface_test.GenericInvokerFutureInvocationAsynchronousEventServiceTest", 
   "_face_interface_test.MultiCallableInvokerBlockingInvocationInlineServiceTest", 
-  "_face_interface_test.MultiCallableInvokerEventInvocationSynchronousEventServiceTest", 
   "_face_interface_test.MultiCallableInvokerFutureInvocationAsynchronousEventServiceTest", 
   "_implementations_test.ChannelCredentialsTest", 
   "_insecure_interop_test.InsecureInteropTest", 
diff --git a/src/python/grpcio/tests/unit/framework/interfaces/face/_event_invocation_synchronous_event_service.py b/src/python/grpcio/tests/unit/framework/interfaces/face/_event_invocation_synchronous_event_service.py
deleted file mode 100644
index 34db6c3e55f47bb4a2b59ede6d04b40b70a383eb..0000000000000000000000000000000000000000
--- a/src/python/grpcio/tests/unit/framework/interfaces/face/_event_invocation_synchronous_event_service.py
+++ /dev/null
@@ -1,381 +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.
-
-"""Test code for the Face layer of RPC Framework."""
-
-import abc
-import unittest
-
-# test_interfaces is referenced from specification in this module.
-from grpc.framework.interfaces.face import face
-from tests.unit.framework.common import test_constants
-from tests.unit.framework.common import test_control
-from tests.unit.framework.common import test_coverage
-from tests.unit.framework.interfaces.face import _3069_test_constant
-from tests.unit.framework.interfaces.face import _digest
-from tests.unit.framework.interfaces.face import _receiver
-from tests.unit.framework.interfaces.face import _stock_service
-from tests.unit.framework.interfaces.face import test_interfaces  # pylint: disable=unused-import
-
-
-class TestCase(test_coverage.Coverage, unittest.TestCase):
-  """A test of the Face layer of RPC Framework.
-
-  Concrete subclasses must have an "implementation" attribute of type
-  test_interfaces.Implementation and an "invoker_constructor" attribute of type
-  _invocation.InvokerConstructor.
-  """
-  __metaclass__ = abc.ABCMeta
-
-  NAME = 'EventInvocationSynchronousEventServiceTest'
-
-  def setUp(self):
-    """See unittest.TestCase.setUp for full specification.
-
-    Overriding implementations must call this implementation.
-    """
-    self._control = test_control.PauseFailControl()
-    self._digest = _digest.digest(
-        _stock_service.STOCK_TEST_SERVICE, self._control, None)
-
-    generic_stub, dynamic_stubs, self._memo = self.implementation.instantiate(
-        self._digest.methods, self._digest.event_method_implementations, None)
-    self._invoker = self.invoker_constructor.construct_invoker(
-        generic_stub, dynamic_stubs, self._digest.methods)
-
-  def tearDown(self):
-    """See unittest.TestCase.tearDown for full specification.
-
-    Overriding implementations must call this implementation.
-    """
-    self._invoker = None
-    self.implementation.destantiate(self._memo)
-
-  def testSuccessfulUnaryRequestUnaryResponse(self):
-    for (group, method), test_messages_sequence in (
-        self._digest.unary_unary_messages_sequences.iteritems()):
-      for test_messages in test_messages_sequence:
-        request = test_messages.request()
-        receiver = _receiver.Receiver()
-
-        self._invoker.event(group, method)(
-            request, receiver, receiver.abort, test_constants.LONG_TIMEOUT)
-        receiver.block_until_terminated()
-        response = receiver.unary_response()
-
-        test_messages.verify(request, response, self)
-
-  def testSuccessfulUnaryRequestStreamResponse(self):
-    for (group, method), test_messages_sequence in (
-        self._digest.unary_stream_messages_sequences.iteritems()):
-      for test_messages in test_messages_sequence:
-        request = test_messages.request()
-        receiver = _receiver.Receiver()
-
-        self._invoker.event(group, method)(
-            request, receiver, receiver.abort, test_constants.LONG_TIMEOUT)
-        receiver.block_until_terminated()
-        responses = receiver.stream_responses()
-
-        test_messages.verify(request, responses, self)
-
-  def testSuccessfulStreamRequestUnaryResponse(self):
-    for (group, method), test_messages_sequence in (
-        self._digest.stream_unary_messages_sequences.iteritems()):
-      for test_messages in test_messages_sequence:
-        requests = test_messages.requests()
-        receiver = _receiver.Receiver()
-
-        call_consumer = self._invoker.event(group, method)(
-            receiver, receiver.abort, test_constants.LONG_TIMEOUT)
-        for request in requests:
-          call_consumer.consume(request)
-        call_consumer.terminate()
-        receiver.block_until_terminated()
-        response = receiver.unary_response()
-
-        test_messages.verify(requests, response, self)
-
-  def testSuccessfulStreamRequestStreamResponse(self):
-    for (group, method), test_messages_sequence in (
-        self._digest.stream_stream_messages_sequences.iteritems()):
-      for test_messages in test_messages_sequence:
-        requests = test_messages.requests()
-        receiver = _receiver.Receiver()
-
-        call_consumer = self._invoker.event(group, method)(
-            receiver, receiver.abort, test_constants.LONG_TIMEOUT)
-        for request in requests:
-          call_consumer.consume(request)
-        call_consumer.terminate()
-        receiver.block_until_terminated()
-        responses = receiver.stream_responses()
-
-        test_messages.verify(requests, responses, self)
-
-  def testSequentialInvocations(self):
-    # pylint: disable=cell-var-from-loop
-    for (group, method), test_messages_sequence in (
-        self._digest.unary_unary_messages_sequences.iteritems()):
-      for test_messages in test_messages_sequence:
-        first_request = test_messages.request()
-        second_request = test_messages.request()
-        second_receiver = _receiver.Receiver()
-
-        def make_second_invocation():
-          self._invoker.event(group, method)(
-              second_request, second_receiver, second_receiver.abort,
-              test_constants.LONG_TIMEOUT)
-
-        class FirstReceiver(_receiver.Receiver):
-
-          def complete(self, terminal_metadata, code, details):
-            super(FirstReceiver, self).complete(
-                terminal_metadata, code, details)
-            make_second_invocation()
-
-        first_receiver = FirstReceiver()
-
-        self._invoker.event(group, method)(
-            first_request, first_receiver, first_receiver.abort,
-            test_constants.LONG_TIMEOUT)
-        second_receiver.block_until_terminated()
-
-        first_response = first_receiver.unary_response()
-        second_response = second_receiver.unary_response()
-        test_messages.verify(first_request, first_response, self)
-        test_messages.verify(second_request, second_response, self)
-
-  def testParallelInvocations(self):
-    for (group, method), test_messages_sequence in (
-        self._digest.unary_unary_messages_sequences.iteritems()):
-      for test_messages in test_messages_sequence:
-        first_request = test_messages.request()
-        first_receiver = _receiver.Receiver()
-        second_request = test_messages.request()
-        second_receiver = _receiver.Receiver()
-
-        self._invoker.event(group, method)(
-            first_request, first_receiver, first_receiver.abort,
-            test_constants.LONG_TIMEOUT)
-        self._invoker.event(group, method)(
-            second_request, second_receiver, second_receiver.abort,
-            test_constants.LONG_TIMEOUT)
-        first_receiver.block_until_terminated()
-        second_receiver.block_until_terminated()
-
-        first_response = first_receiver.unary_response()
-        second_response = second_receiver.unary_response()
-        test_messages.verify(first_request, first_response, self)
-        test_messages.verify(second_request, second_response, self)
-
-  @unittest.skip('TODO(nathaniel): implement.')
-  def testWaitingForSomeButNotAllParallelInvocations(self):
-    raise NotImplementedError()
-
-  def testCancelledUnaryRequestUnaryResponse(self):
-    for (group, method), test_messages_sequence in (
-        self._digest.unary_unary_messages_sequences.iteritems()):
-      for test_messages in test_messages_sequence:
-        request = test_messages.request()
-        receiver = _receiver.Receiver()
-
-        with self._control.pause():
-          call = self._invoker.event(group, method)(
-              request, receiver, receiver.abort, test_constants.LONG_TIMEOUT)
-          call.cancel()
-          receiver.block_until_terminated()
-
-        self.assertIs(face.Abortion.Kind.CANCELLED, receiver.abortion().kind)
-
-  def testCancelledUnaryRequestStreamResponse(self):
-    for (group, method), test_messages_sequence in (
-        self._digest.unary_stream_messages_sequences.iteritems()):
-      for test_messages in test_messages_sequence:
-        request = test_messages.request()
-        receiver = _receiver.Receiver()
-
-        call = self._invoker.event(group, method)(
-            request, receiver, receiver.abort, test_constants.LONG_TIMEOUT)
-        call.cancel()
-        receiver.block_until_terminated()
-
-        self.assertIs(face.Abortion.Kind.CANCELLED, receiver.abortion().kind)
-
-  def testCancelledStreamRequestUnaryResponse(self):
-    for (group, method), test_messages_sequence in (
-        self._digest.stream_unary_messages_sequences.iteritems()):
-      for test_messages in test_messages_sequence:
-        requests = test_messages.requests()
-        receiver = _receiver.Receiver()
-
-        call_consumer = self._invoker.event(group, method)(
-            receiver, receiver.abort, test_constants.LONG_TIMEOUT)
-        for request in requests:
-          call_consumer.consume(request)
-        call_consumer.cancel()
-        receiver.block_until_terminated()
-
-        self.assertIs(face.Abortion.Kind.CANCELLED, receiver.abortion().kind)
-
-  def testCancelledStreamRequestStreamResponse(self):
-    for (group, method), test_messages_sequence in (
-        self._digest.stream_stream_messages_sequences.iteritems()):
-      for unused_test_messages in test_messages_sequence:
-        receiver = _receiver.Receiver()
-
-        call_consumer = self._invoker.event(group, method)(
-            receiver, receiver.abort, test_constants.LONG_TIMEOUT)
-        call_consumer.cancel()
-        receiver.block_until_terminated()
-
-        self.assertIs(face.Abortion.Kind.CANCELLED, receiver.abortion().kind)
-
-  def testExpiredUnaryRequestUnaryResponse(self):
-    for (group, method), test_messages_sequence in (
-        self._digest.unary_unary_messages_sequences.iteritems()):
-      for test_messages in test_messages_sequence:
-        request = test_messages.request()
-        receiver = _receiver.Receiver()
-
-        with self._control.pause():
-          self._invoker.event(group, method)(
-              request, receiver, receiver.abort,
-              _3069_test_constant.REALLY_SHORT_TIMEOUT)
-          receiver.block_until_terminated()
-
-        self.assertIs(face.Abortion.Kind.EXPIRED, receiver.abortion().kind)
-
-  def testExpiredUnaryRequestStreamResponse(self):
-    for (group, method), test_messages_sequence in (
-        self._digest.unary_stream_messages_sequences.iteritems()):
-      for test_messages in test_messages_sequence:
-        request = test_messages.request()
-        receiver = _receiver.Receiver()
-
-        with self._control.pause():
-          self._invoker.event(group, method)(
-              request, receiver, receiver.abort,
-              _3069_test_constant.REALLY_SHORT_TIMEOUT)
-          receiver.block_until_terminated()
-
-        self.assertIs(face.Abortion.Kind.EXPIRED, receiver.abortion().kind)
-
-  def testExpiredStreamRequestUnaryResponse(self):
-    for (group, method), test_messages_sequence in (
-        self._digest.stream_unary_messages_sequences.iteritems()):
-      for unused_test_messages in test_messages_sequence:
-        receiver = _receiver.Receiver()
-
-        self._invoker.event(group, method)(
-            receiver, receiver.abort, _3069_test_constant.REALLY_SHORT_TIMEOUT)
-        receiver.block_until_terminated()
-
-        self.assertIs(face.Abortion.Kind.EXPIRED, receiver.abortion().kind)
-
-  def testExpiredStreamRequestStreamResponse(self):
-    for (group, method), test_messages_sequence in (
-        self._digest.stream_stream_messages_sequences.iteritems()):
-      for test_messages in test_messages_sequence:
-        requests = test_messages.requests()
-        receiver = _receiver.Receiver()
-
-        call_consumer = self._invoker.event(group, method)(
-            receiver, receiver.abort, _3069_test_constant.REALLY_SHORT_TIMEOUT)
-        for request in requests:
-          call_consumer.consume(request)
-        receiver.block_until_terminated()
-
-        self.assertIs(face.Abortion.Kind.EXPIRED, receiver.abortion().kind)
-
-  def testFailedUnaryRequestUnaryResponse(self):
-    for (group, method), test_messages_sequence in (
-        self._digest.unary_unary_messages_sequences.iteritems()):
-      for test_messages in test_messages_sequence:
-        request = test_messages.request()
-        receiver = _receiver.Receiver()
-
-        with self._control.fail():
-          self._invoker.event(group, method)(
-              request, receiver, receiver.abort, test_constants.LONG_TIMEOUT)
-          receiver.block_until_terminated()
-
-        self.assertIs(
-            face.Abortion.Kind.REMOTE_FAILURE, receiver.abortion().kind)
-
-  def testFailedUnaryRequestStreamResponse(self):
-    for (group, method), test_messages_sequence in (
-        self._digest.unary_stream_messages_sequences.iteritems()):
-      for test_messages in test_messages_sequence:
-        request = test_messages.request()
-        receiver = _receiver.Receiver()
-
-        with self._control.fail():
-          self._invoker.event(group, method)(
-              request, receiver, receiver.abort, test_constants.LONG_TIMEOUT)
-          receiver.block_until_terminated()
-
-        self.assertIs(
-            face.Abortion.Kind.REMOTE_FAILURE, receiver.abortion().kind)
-
-  def testFailedStreamRequestUnaryResponse(self):
-    for (group, method), test_messages_sequence in (
-        self._digest.stream_unary_messages_sequences.iteritems()):
-      for test_messages in test_messages_sequence:
-        requests = test_messages.requests()
-        receiver = _receiver.Receiver()
-
-        with self._control.fail():
-          call_consumer = self._invoker.event(group, method)(
-              receiver, receiver.abort, test_constants.LONG_TIMEOUT)
-          for request in requests:
-            call_consumer.consume(request)
-          call_consumer.terminate()
-          receiver.block_until_terminated()
-
-        self.assertIs(
-            face.Abortion.Kind.REMOTE_FAILURE, receiver.abortion().kind)
-
-  def testFailedStreamRequestStreamResponse(self):
-    for (group, method), test_messages_sequence in (
-        self._digest.stream_stream_messages_sequences.iteritems()):
-      for test_messages in test_messages_sequence:
-        requests = test_messages.requests()
-        receiver = _receiver.Receiver()
-
-        with self._control.fail():
-          call_consumer = self._invoker.event(group, method)(
-              receiver, receiver.abort, test_constants.LONG_TIMEOUT)
-          for request in requests:
-            call_consumer.consume(request)
-          call_consumer.terminate()
-          receiver.block_until_terminated()
-
-        self.assertIs(
-            face.Abortion.Kind.REMOTE_FAILURE, receiver.abortion().kind)
diff --git a/src/python/grpcio/tests/unit/framework/interfaces/face/test_cases.py b/src/python/grpcio/tests/unit/framework/interfaces/face/test_cases.py
index 462829b66066880ff790986513264b56f14d96f8..06b9d77e52164457a3fd1c212a07b86d18116eb1 100644
--- a/src/python/grpcio/tests/unit/framework/interfaces/face/test_cases.py
+++ b/src/python/grpcio/tests/unit/framework/interfaces/face/test_cases.py
@@ -1,4 +1,4 @@
-# Copyright 2015, Google Inc.
+# Copyright 2015-2016, Google Inc.
 # All rights reserved.
 #
 # Redistribution and use in source and binary forms, with or without
@@ -34,14 +34,12 @@ import unittest  # pylint: disable=unused-import
 
 # test_interfaces is referenced from specification in this module.
 from tests.unit.framework.interfaces.face import _blocking_invocation_inline_service
-from tests.unit.framework.interfaces.face import _event_invocation_synchronous_event_service
 from tests.unit.framework.interfaces.face import _future_invocation_asynchronous_event_service
 from tests.unit.framework.interfaces.face import _invocation
 from tests.unit.framework.interfaces.face import test_interfaces  # pylint: disable=unused-import
 
 _TEST_CASE_SUPERCLASSES = (
     _blocking_invocation_inline_service.TestCase,
-    _event_invocation_synchronous_event_service.TestCase,
     _future_invocation_asynchronous_event_service.TestCase,
 )
 
diff --git a/src/ruby/.rubocop.yml b/src/ruby/.rubocop.yml
index ff5cf8db83190a6fab07d6c37cbf4f626a2fb29e..d13ce4265537732de5770455009f6008dc43c4e8 100644
--- a/src/ruby/.rubocop.yml
+++ b/src/ruby/.rubocop.yml
@@ -15,3 +15,6 @@ Metrics/CyclomaticComplexity:
 
 Metrics/PerceivedComplexity:
   Max: 8
+
+Metrics/ClassLength:
+  Max: 250
diff --git a/src/ruby/lib/grpc/generic/rpc_server.rb b/src/ruby/lib/grpc/generic/rpc_server.rb
index ef2997c991809acadc435df9242dc641a1096a2c..b30d19dd2bbb676ef989b460f500b3eeaad25754 100644
--- a/src/ruby/lib/grpc/generic/rpc_server.rb
+++ b/src/ruby/lib/grpc/generic/rpc_server.rb
@@ -107,7 +107,9 @@ module GRPC
 
     # Starts running the jobs in the thread pool.
     def start
-      fail 'already stopped' if @stopped
+      @stop_mutex.synchronize do
+        fail 'already stopped' if @stopped
+      end
       until @workers.size == @size.to_i
         next_thread = Thread.new do
           catch(:exit) do  # allows { throw :exit } to kill a thread
@@ -264,10 +266,10 @@ module GRPC
       @pool = Pool.new(@pool_size)
       @run_cond = ConditionVariable.new
       @run_mutex = Mutex.new
-      @running = false
+      # running_state can take 4 values: :not_started, :running, :stopping, and
+      # :stopped. State transitions can only proceed in that order.
+      @running_state = :not_started
       @server = RpcServer.setup_srv(server_override, @cq, **kw)
-      @stopped = false
-      @stop_mutex = Mutex.new
     end
 
     # stops a running server
@@ -275,27 +277,42 @@ module GRPC
     # the call has no impact if the server is already stopped, otherwise
     # server's current call loop is it's last.
     def stop
-      return unless @running
-      @stop_mutex.synchronize do
-        @stopped = true
+      @run_mutex.synchronize do
+        fail 'Cannot stop before starting' if @running_state == :not_started
+        return if @running_state != :running
+        transition_running_state(:stopping)
       end
       deadline = from_relative_time(@poll_period)
-      return if @server.close(@cq, deadline)
-      deadline = from_relative_time(@poll_period)
       @server.close(@cq, deadline)
       @pool.stop
     end
 
-    # determines if the server has been stopped
-    def stopped?
-      @stop_mutex.synchronize do
-        return @stopped
+    def running_state
+      @run_mutex.synchronize do
+        return @running_state
+      end
+    end
+
+    # Can only be called while holding @run_mutex
+    def transition_running_state(target_state)
+      state_transitions = {
+        not_started: :running,
+        running: :stopping,
+        stopping: :stopped
+      }
+      if state_transitions[@running_state] == target_state
+        @running_state = target_state
+      else
+        fail "Bad server state transition: #{@running_state}->#{target_state}"
       end
     end
 
-    # determines if the server is currently running
     def running?
-      @running
+      running_state == :running
+    end
+
+    def stopped?
+      running_state == :stopped
     end
 
     # Is called from other threads to wait for #run to start up the server.
@@ -304,13 +321,11 @@ module GRPC
     #
     # @param timeout [Numeric] number of seconds to wait
     # @result [true, false] true if the server is running, false otherwise
-    def wait_till_running(timeout = 0.1)
-      end_time, sleep_period = Time.now + timeout, (1.0 * timeout) / 100
-      while Time.now < end_time
-        @run_mutex.synchronize { @run_cond.wait(@run_mutex) } unless running?
-        sleep(sleep_period)
+    def wait_till_running(timeout = nil)
+      @run_mutex.synchronize do
+        @run_cond.wait(@run_mutex, timeout) if @running_state == :not_started
+        return @running_state == :running
       end
-      running?
     end
 
     # Runs the server in its own thread, then waits for signal INT or TERM on
@@ -360,11 +375,14 @@ module GRPC
     # @param service [Object|Class] a service class or object as described
     #        above
     def handle(service)
-      fail 'cannot add services if the server is running' if running?
-      fail 'cannot add services if the server is stopped' if stopped?
-      cls = service.is_a?(Class) ? service : service.class
-      assert_valid_service_class(cls)
-      add_rpc_descs_for(service)
+      @run_mutex.synchronize do
+        unless @running_state == :not_started
+          fail 'cannot add services if the server has been started'
+        end
+        cls = service.is_a?(Class) ? service : service.class
+        assert_valid_service_class(cls)
+        add_rpc_descs_for(service)
+      end
     end
 
     # runs the server
@@ -375,16 +393,13 @@ module GRPC
     # - #running? returns true after this is called, until #stop cause the
     #   the server to stop.
     def run
-      if rpc_descs.size.zero?
-        GRPC.logger.warn('did not run as no services were present')
-        return
-      end
       @run_mutex.synchronize do
-        @running = true
-        @run_cond.signal
+        fail 'cannot run without registering services' if rpc_descs.size.zero?
+        @pool.start
+        @server.start
+        transition_running_state(:running)
+        @run_cond.broadcast
       end
-      @pool.start
-      @server.start
       loop_handle_server_calls
     end
 
@@ -413,9 +428,9 @@ module GRPC
 
     # handles calls to the server
     def loop_handle_server_calls
-      fail 'not running' unless @running
+      fail 'not started' if running_state == :not_started
       loop_tag = Object.new
-      until stopped?
+      while running_state == :running
         begin
           an_rpc = @server.request_call(@cq, loop_tag, INFINITE_FUTURE)
           break if (!an_rpc.nil?) && an_rpc.call.nil?
@@ -430,11 +445,14 @@ module GRPC
         rescue Core::CallError, RuntimeError => e
           # these might happen for various reasonse.  The correct behaviour of
           # the server is to log them and continue, if it's not shutting down.
-          GRPC.logger.warn("server call failed: #{e}") unless stopped?
+          if running_state == :running
+            GRPC.logger.warn("server call failed: #{e}")
+          end
           next
         end
       end
-      @running = false
+      # @running_state should be :stopping here
+      @run_mutex.synchronize { transition_running_state(:stopped) }
       GRPC.logger.info("stopped: #{self}")
     end
 
@@ -484,9 +502,10 @@ module GRPC
       cls.assert_rpc_descs_have_methods
     end
 
+    # This should be called while holding @run_mutex
     def add_rpc_descs_for(service)
       cls = service.is_a?(Class) ? service : service.class
-      specs, handlers = rpc_descs, rpc_handlers
+      specs, handlers = (@rpc_descs ||= {}), (@rpc_handlers ||= {})
       cls.rpc_descs.each_pair do |name, spec|
         route = "/#{cls.service_name}/#{name}".to_sym
         fail "already registered: rpc #{route} from #{spec}" if specs.key? route
diff --git a/src/ruby/spec/generic/rpc_server_spec.rb b/src/ruby/spec/generic/rpc_server_spec.rb
index be6331d68bb9a392d773af59a8c3dceb53ca187a..dfaec6d6edc01dabb9be8b0b70a4a04e44a3c946 100644
--- a/src/ruby/spec/generic/rpc_server_spec.rb
+++ b/src/ruby/spec/generic/rpc_server_spec.rb
@@ -1,4 +1,4 @@
-# Copyright 2015, Google Inc.
+# Copyright 2015-2016, Google Inc.
 # All rights reserved.
 #
 # Redistribution and use in source and binary forms, with or without
@@ -220,19 +220,10 @@ describe GRPC::RpcServer do
       @srv = RpcServer.new(**opts)
     end
 
-    after(:each) do
-      @srv.stop
-    end
-
     it 'starts out false' do
       expect(@srv.stopped?).to be(false)
     end
 
-    it 'stays false after a #stop is called before #run' do
-      @srv.stop
-      expect(@srv.stopped?).to be(false)
-    end
-
     it 'stays false after the server starts running', server: true do
       @srv.handle(EchoService)
       t = Thread.new { @srv.run }
@@ -247,8 +238,8 @@ describe GRPC::RpcServer do
       t = Thread.new { @srv.run }
       @srv.wait_till_running
       @srv.stop
-      expect(@srv.stopped?).to be(true)
       t.join
+      expect(@srv.stopped?).to be(true)
     end
   end
 
@@ -266,9 +257,7 @@ describe GRPC::RpcServer do
         server_override: @server
       }
       r = RpcServer.new(**opts)
-      r.run
-      expect(r.running?).to be(false)
-      r.stop
+      expect { r.run }.to raise_error(RuntimeError)
     end
 
     it 'is true after run is called with a registered service' do
@@ -293,10 +282,6 @@ describe GRPC::RpcServer do
       @srv = RpcServer.new(**@opts)
     end
 
-    after(:each) do
-      @srv.stop
-    end
-
     it 'raises if #run has already been called' do
       @srv.handle(EchoService)
       t = Thread.new { @srv.run }
@@ -528,10 +513,6 @@ describe GRPC::RpcServer do
         @srv = RpcServer.new(**server_opts)
       end
 
-      after(:each) do
-        @srv.stop
-      end
-
       it 'should be added to BadStatus when requests fail', server: true do
         service = FailingService.new
         @srv.handle(service)
diff --git a/summerofcode/ideas.md b/summerofcode/ideas.md
index c7f368e7cc2f9d66e40069e68136047f8baf859f..83f2cecd48c508348ad5a691daf9e4d6a8f09f9b 100644
--- a/summerofcode/ideas.md
+++ b/summerofcode/ideas.md
@@ -19,7 +19,9 @@ gRPC C Core:
 
 1. Port gRPC to  one of the major BSD platforms ([FreeBSD](https://freebsd.org), [NetBSD](https://netbsd.org), and [OpenBSD](https://openbsd.org)) and create packages for them. Add [kqueue](https://www.freebsd.org/cgi/man.cgi?query=kqueue) support in the process.
  * **Required skills:** C programming language, BSD operating system.
- * **Likely mentors:** [Craig Tiller](https://github.com/ctiller), [Nicolas Noble](https://github.com/nicolasnoble).
+ * **Likely mentors:** [Craig Tiller](https://github.com/ctiller),
+ [Nicolas Noble](https://github.com/nicolasnoble),
+ [Vijay Pai](https://github.com/vjpai).
 1. Fix gRPC C-core's URI parser. The current parser does not qualify as a standard parser according to [RFC3986]( https://tools.ietf.org/html/rfc3986). Write test suites to verify this and make changes necessary to make the URI parser compliant.
  * **Required skills:** C programming language, HTTP standard compliance.
  * **Likely mentors:** [Craig Tiller](https://github.com/ctiller).
diff --git a/templates/package.xml.template b/templates/package.xml.template
index d309bfddbc3199b9dcedfd14d2c415198bd21098..8f757401e4c1771d31c843cb811fbaa5882fd6e1 100644
--- a/templates/package.xml.template
+++ b/templates/package.xml.template
@@ -29,9 +29,9 @@
    <contents>
     <dir baseinstalldir="/" name="/">
       <file baseinstalldir="/" name="config.m4" role="src" />
+      <file baseinstalldir="/" name="src/php/README.md" role="src" />
       <file baseinstalldir="/" name="src/php/ext/grpc/CREDITS" role="src" />
       <file baseinstalldir="/" name="src/php/ext/grpc/LICENSE" role="src" />
-      <file baseinstalldir="/" name="src/php/ext/grpc/README.md" role="src" />
       % for source in php_config_m4.src + php_config_m4.headers:
       <file baseinstalldir="/" name="${source}" role="src" />
       % endfor
diff --git a/templates/tools/dockerfile/test/cxx_ubuntu1404_x64/Dockerfile.template b/templates/tools/dockerfile/test/cxx_ubuntu1404_x64/Dockerfile.template
new file mode 100644
index 0000000000000000000000000000000000000000..d824220afeaf335d3814430e736afcc0f7342439
--- /dev/null
+++ b/templates/tools/dockerfile/test/cxx_ubuntu1404_x64/Dockerfile.template
@@ -0,0 +1,39 @@
+%YAML 1.2
+--- |
+  # Copyright 2015-2016, Google Inc.
+  # All rights reserved.
+  #
+  # Redistribution and use in source and binary forms, with or without
+  # modification, are permitted provided that the following conditions are
+  # met:
+  #
+  #     * Redistributions of source code must retain the above copyright
+  # notice, this list of conditions and the following disclaimer.
+  #     * Redistributions in binary form must reproduce the above
+  # copyright notice, this list of conditions and the following disclaimer
+  # in the documentation and/or other materials provided with the
+  # distribution.
+  #     * Neither the name of Google Inc. nor the names of its
+  # contributors may be used to endorse or promote products derived from
+  # this software without specific prior written permission.
+  #
+  # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+  # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+  # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+  # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+  # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+  # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+  # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+  # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+  # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+  # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+  # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+  
+  FROM ubuntu:14.04
+  
+  <%include file="../../apt_get_basic.include"/>
+  <%include file="../../cxx_deps.include"/>
+  <%include file="../../run_tests_addons.include"/>
+  # Define the default command.
+  CMD ["bash"]
+  
\ No newline at end of file
diff --git a/test/core/client_config/resolvers/dns_resolver_connectivity_test.c b/test/core/client_config/resolvers/dns_resolver_connectivity_test.c
new file mode 100644
index 0000000000000000000000000000000000000000..75d1eb674f6a4dfb670e33a1a9503fa8b80ebc41
--- /dev/null
+++ b/test/core/client_config/resolvers/dns_resolver_connectivity_test.c
@@ -0,0 +1,148 @@
+/*
+ *
+ * Copyright 2015-2016, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "src/core/client_config/resolvers/dns_resolver.h"
+
+#include <string.h>
+
+#include <grpc/grpc.h>
+#include <grpc/support/alloc.h>
+
+#include "src/core/iomgr/resolve_address.h"
+#include "src/core/iomgr/timer.h"
+#include "test/core/util/test_config.h"
+
+static void subchannel_factory_ref(grpc_subchannel_factory *scv) {}
+static void subchannel_factory_unref(grpc_exec_ctx *exec_ctx,
+                                     grpc_subchannel_factory *scv) {}
+static grpc_subchannel *subchannel_factory_create_subchannel(
+    grpc_exec_ctx *exec_ctx, grpc_subchannel_factory *factory,
+    grpc_subchannel_args *args) {
+  return NULL;
+}
+
+static const grpc_subchannel_factory_vtable sc_vtable = {
+    subchannel_factory_ref, subchannel_factory_unref,
+    subchannel_factory_create_subchannel};
+
+static grpc_subchannel_factory sc_factory = {&sc_vtable};
+
+static gpr_mu g_mu;
+static bool g_fail_resolution = true;
+
+static grpc_resolved_addresses *my_resolve_address(const char *name,
+                                                   const char *addr) {
+  gpr_mu_lock(&g_mu);
+  GPR_ASSERT(0 == strcmp("test", name));
+  if (g_fail_resolution) {
+    g_fail_resolution = false;
+    gpr_mu_unlock(&g_mu);
+    return NULL;
+  } else {
+    gpr_mu_unlock(&g_mu);
+    grpc_resolved_addresses *addrs = gpr_malloc(sizeof(*addrs));
+    addrs->naddrs = 1;
+    addrs->addrs = gpr_malloc(sizeof(*addrs->addrs));
+    addrs->addrs[0].len = 123;
+    return addrs;
+  }
+}
+
+static grpc_resolver *create_resolver(const char *name) {
+  grpc_resolver_factory *factory = grpc_dns_resolver_factory_create();
+  grpc_uri *uri = grpc_uri_parse(name, 0);
+  GPR_ASSERT(uri);
+  grpc_resolver_args args;
+  memset(&args, 0, sizeof(args));
+  args.uri = uri;
+  args.subchannel_factory = &sc_factory;
+  grpc_resolver *resolver =
+      grpc_resolver_factory_create_resolver(factory, &args);
+  grpc_resolver_factory_unref(factory);
+  grpc_uri_destroy(uri);
+  return resolver;
+}
+
+static void on_done(grpc_exec_ctx *exec_ctx, void *ev, bool success) {
+  gpr_event_set(ev, (void *)1);
+}
+
+// interleave waiting for an event with a timer check
+static bool wait_loop(int deadline_seconds, gpr_event *ev) {
+  while (deadline_seconds) {
+    gpr_log(GPR_DEBUG, "Test: waiting for %d more seconds", deadline_seconds);
+    if (gpr_event_wait(ev, GRPC_TIMEOUT_SECONDS_TO_DEADLINE(1))) return true;
+    deadline_seconds--;
+
+    grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+    grpc_timer_check(&exec_ctx, gpr_now(GPR_CLOCK_MONOTONIC), NULL);
+    grpc_exec_ctx_finish(&exec_ctx);
+  }
+  return false;
+}
+
+int main(int argc, char **argv) {
+  grpc_test_init(argc, argv);
+
+  grpc_init();
+  gpr_mu_init(&g_mu);
+  grpc_blocking_resolve_address = my_resolve_address;
+
+  grpc_resolver *resolver = create_resolver("dns:test");
+
+  grpc_client_config *config = (grpc_client_config *)1;
+
+  grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+  gpr_event ev1;
+  gpr_event_init(&ev1);
+  grpc_resolver_next(&exec_ctx, resolver, &config,
+                     grpc_closure_create(on_done, &ev1));
+  grpc_exec_ctx_flush(&exec_ctx);
+  GPR_ASSERT(wait_loop(5, &ev1));
+  GPR_ASSERT(config == NULL);
+
+  gpr_event ev2;
+  gpr_event_init(&ev2);
+  grpc_resolver_next(&exec_ctx, resolver, &config,
+                     grpc_closure_create(on_done, &ev2));
+  grpc_exec_ctx_flush(&exec_ctx);
+  GPR_ASSERT(wait_loop(30, &ev2));
+  GPR_ASSERT(config != NULL);
+
+  grpc_client_config_unref(&exec_ctx, config);
+  GRPC_RESOLVER_UNREF(&exec_ctx, resolver, "test");
+  grpc_exec_ctx_finish(&exec_ctx);
+
+  grpc_shutdown();
+  gpr_mu_destroy(&g_mu);
+}
diff --git a/test/core/iomgr/timer_heap_test.c b/test/core/iomgr/timer_heap_test.c
index 077a9fd6bd87142847818f6604e6c6db29d446cd..cd34696f7ddeb15d8be27a90d48e21bb3a316dfd 100644
--- a/test/core/iomgr/timer_heap_test.c
+++ b/test/core/iomgr/timer_heap_test.c
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -38,6 +38,8 @@
 
 #include <grpc/support/alloc.h>
 #include <grpc/support/log.h>
+#include <grpc/support/useful.h>
+
 #include "test/core/util/test_config.h"
 
 static gpr_timespec random_deadline(void) {
@@ -57,79 +59,6 @@ static grpc_timer *create_test_elements(size_t num_elements) {
   return elems;
 }
 
-static int cmp_elem(const void *a, const void *b) {
-  int i = *(const int *)a;
-  int j = *(const int *)b;
-  return i - j;
-}
-
-static size_t *all_top(grpc_timer_heap *pq, size_t *n) {
-  size_t *vec = NULL;
-  size_t *need_to_check_children;
-  size_t num_need_to_check_children = 0;
-
-  *n = 0;
-  if (pq->timer_count == 0) return vec;
-  need_to_check_children =
-      gpr_malloc(pq->timer_count * sizeof(*need_to_check_children));
-  need_to_check_children[num_need_to_check_children++] = 0;
-  vec = gpr_malloc(pq->timer_count * sizeof(*vec));
-  while (num_need_to_check_children > 0) {
-    size_t ind = need_to_check_children[0];
-    size_t leftchild, rightchild;
-    num_need_to_check_children--;
-    memmove(need_to_check_children, need_to_check_children + 1,
-            num_need_to_check_children * sizeof(*need_to_check_children));
-    vec[(*n)++] = ind;
-    leftchild = 1u + 2u * ind;
-    if (leftchild < pq->timer_count) {
-      if (gpr_time_cmp(pq->timers[leftchild]->deadline,
-                       pq->timers[ind]->deadline) >= 0) {
-        need_to_check_children[num_need_to_check_children++] = leftchild;
-      }
-      rightchild = leftchild + 1;
-      if (rightchild < pq->timer_count &&
-          gpr_time_cmp(pq->timers[rightchild]->deadline,
-                       pq->timers[ind]->deadline) >= 0) {
-        need_to_check_children[num_need_to_check_children++] = rightchild;
-      }
-    }
-  }
-
-  gpr_free(need_to_check_children);
-
-  return vec;
-}
-
-static void check_pq_top(grpc_timer *elements, grpc_timer_heap *pq,
-                         uint8_t *inpq, size_t num_elements) {
-  gpr_timespec max_deadline = gpr_inf_past(GPR_CLOCK_REALTIME);
-  size_t *max_deadline_indices =
-      gpr_malloc(num_elements * sizeof(*max_deadline_indices));
-  size_t *top_elements;
-  size_t num_max_deadline_indices = 0;
-  size_t num_top_elements;
-  size_t i;
-  for (i = 0; i < num_elements; ++i) {
-    if (inpq[i] && gpr_time_cmp(elements[i].deadline, max_deadline) >= 0) {
-      if (gpr_time_cmp(elements[i].deadline, max_deadline) > 0) {
-        num_max_deadline_indices = 0;
-        max_deadline = elements[i].deadline;
-      }
-      max_deadline_indices[num_max_deadline_indices++] = elements[i].heap_index;
-    }
-  }
-  qsort(max_deadline_indices, num_max_deadline_indices,
-        sizeof(*max_deadline_indices), cmp_elem);
-  top_elements = all_top(pq, &num_top_elements);
-  GPR_ASSERT(num_top_elements == num_max_deadline_indices);
-  for (i = 0; i < num_top_elements; i++) {
-    GPR_ASSERT(max_deadline_indices[i] == top_elements[i]);
-  }
-  gpr_free(max_deadline_indices);
-  gpr_free(top_elements);
-}
-
 static int contains(grpc_timer_heap *pq, grpc_timer *el) {
   size_t i;
   for (i = 0; i < pq->timer_count; i++) {
@@ -145,15 +74,19 @@ static void check_valid(grpc_timer_heap *pq) {
     size_t right_child = left_child + 1u;
     if (left_child < pq->timer_count) {
       GPR_ASSERT(gpr_time_cmp(pq->timers[i]->deadline,
-                              pq->timers[left_child]->deadline) >= 0);
+                              pq->timers[left_child]->deadline) <= 0);
     }
     if (right_child < pq->timer_count) {
       GPR_ASSERT(gpr_time_cmp(pq->timers[i]->deadline,
-                              pq->timers[right_child]->deadline) >= 0);
+                              pq->timers[right_child]->deadline) <= 0);
     }
   }
 }
 
+/*******************************************************************************
+ * test1
+ */
+
 static void test1(void) {
   grpc_timer_heap pq;
   const size_t num_test_elements = 200;
@@ -162,6 +95,8 @@ static void test1(void) {
   grpc_timer *test_elements = create_test_elements(num_test_elements);
   uint8_t *inpq = gpr_malloc(num_test_elements);
 
+  gpr_log(GPR_INFO, "test1");
+
   grpc_timer_heap_init(&pq);
   memset(inpq, 0, num_test_elements);
   GPR_ASSERT(grpc_timer_heap_is_empty(&pq));
@@ -172,7 +107,6 @@ static void test1(void) {
     check_valid(&pq);
     GPR_ASSERT(contains(&pq, &test_elements[i]));
     inpq[i] = 1;
-    check_pq_top(test_elements, &pq, inpq, num_test_elements);
   }
   for (i = 0; i < num_test_elements; ++i) {
     /* Test that check still succeeds even for element that wasn't just
@@ -182,7 +116,7 @@ static void test1(void) {
 
   GPR_ASSERT(pq.timer_count == num_test_elements);
 
-  check_pq_top(test_elements, &pq, inpq, num_test_elements);
+  check_valid(&pq);
 
   for (i = 0; i < num_test_operations; ++i) {
     size_t elem_num = (size_t)rand() % num_test_elements;
@@ -193,14 +127,12 @@ static void test1(void) {
       grpc_timer_heap_add(&pq, el);
       GPR_ASSERT(contains(&pq, el));
       inpq[elem_num] = 1;
-      check_pq_top(test_elements, &pq, inpq, num_test_elements);
       check_valid(&pq);
     } else {
       GPR_ASSERT(contains(&pq, el));
       grpc_timer_heap_remove(&pq, el);
       GPR_ASSERT(!contains(&pq, el));
       inpq[elem_num] = 0;
-      check_pq_top(test_elements, &pq, inpq, num_test_elements);
       check_valid(&pq);
     }
   }
@@ -210,7 +142,108 @@ static void test1(void) {
   gpr_free(inpq);
 }
 
+/*******************************************************************************
+ * test2
+ */
+
+typedef struct {
+  grpc_timer elem;
+  bool inserted;
+} elem_struct;
+
+static elem_struct *search_elems(elem_struct *elems, size_t count,
+                                 bool inserted) {
+  size_t *search_order = gpr_malloc(count * sizeof(*search_order));
+  for (size_t i = 0; i < count; i++) {
+    search_order[i] = i;
+  }
+  for (size_t i = 0; i < count * 2; i++) {
+    size_t a = (size_t)rand() % count;
+    size_t b = (size_t)rand() % count;
+    GPR_SWAP(size_t, search_order[a], search_order[b]);
+  }
+  elem_struct *out = NULL;
+  for (size_t i = 0; out == NULL && i < count; i++) {
+    if (elems[search_order[i]].inserted == inserted) {
+      out = &elems[search_order[i]];
+    }
+  }
+  gpr_free(search_order);
+  return out;
+}
+
+static void test2(void) {
+  gpr_log(GPR_INFO, "test2");
+
+  grpc_timer_heap pq;
+
+  elem_struct elems[1000];
+  size_t num_inserted = 0;
+
+  grpc_timer_heap_init(&pq);
+  memset(elems, 0, sizeof(elems));
+
+  for (size_t round = 0; round < 10000; round++) {
+    int r = rand() % 1000;
+    if (r <= 550) {
+      /* 55% of the time we try to add something */
+      elem_struct *el = search_elems(elems, GPR_ARRAY_SIZE(elems), false);
+      if (el != NULL) {
+        el->elem.deadline = random_deadline();
+        grpc_timer_heap_add(&pq, &el->elem);
+        el->inserted = true;
+        num_inserted++;
+        check_valid(&pq);
+      }
+    } else if (r <= 650) {
+      /* 10% of the time we try to remove something */
+      elem_struct *el = search_elems(elems, GPR_ARRAY_SIZE(elems), true);
+      if (el != NULL) {
+        grpc_timer_heap_remove(&pq, &el->elem);
+        el->inserted = false;
+        num_inserted--;
+        check_valid(&pq);
+      }
+    } else {
+      /* the remaining times we pop */
+      if (num_inserted > 0) {
+        grpc_timer *top = grpc_timer_heap_top(&pq);
+        grpc_timer_heap_pop(&pq);
+        for (size_t i = 0; i < GPR_ARRAY_SIZE(elems); i++) {
+          if (top == &elems[i].elem) {
+            GPR_ASSERT(elems[i].inserted);
+            elems[i].inserted = false;
+          }
+        }
+        num_inserted--;
+        check_valid(&pq);
+      }
+    }
+
+    if (num_inserted) {
+      gpr_timespec *min_deadline = NULL;
+      for (size_t i = 0; i < GPR_ARRAY_SIZE(elems); i++) {
+        if (elems[i].inserted) {
+          if (min_deadline == NULL) {
+            min_deadline = &elems[i].elem.deadline;
+          } else {
+            if (gpr_time_cmp(elems[i].elem.deadline, *min_deadline) < 0) {
+              min_deadline = &elems[i].elem.deadline;
+            }
+          }
+        }
+      }
+      GPR_ASSERT(
+          0 == gpr_time_cmp(grpc_timer_heap_top(&pq)->deadline, *min_deadline));
+    }
+  }
+
+  grpc_timer_heap_destroy(&pq);
+}
+
 static void shrink_test(void) {
+  gpr_log(GPR_INFO, "shrink_test");
+
   grpc_timer_heap pq;
   size_t i;
   size_t expected_size;
@@ -274,6 +307,7 @@ int main(int argc, char **argv) {
 
   for (i = 0; i < 5; i++) {
     test1();
+    test2();
     shrink_test();
   }
 
diff --git a/test/cpp/qps/client.h b/test/cpp/qps/client.h
index 2dc83f0f29292a0042201300b5fb26f1f16562e9..92e77eed9b2f6373f203a5f84b134f615ffcb146 100644
--- a/test/cpp/qps/client.h
+++ b/test/cpp/qps/client.h
@@ -123,15 +123,13 @@ class Client {
     if (reset) {
       Histogram* to_merge = new Histogram[threads_.size()];
       for (size_t i = 0; i < threads_.size(); i++) {
-        threads_[i]->BeginSwap(&to_merge[i]);
-      }
-      std::unique_ptr<UsageTimer> timer(new UsageTimer);
-      timer_.swap(timer);
-      for (size_t i = 0; i < threads_.size(); i++) {
-        threads_[i]->EndSwap();
+        threads_[i]->Swap(&to_merge[i]);
         latencies.Merge(to_merge[i]);
       }
       delete[] to_merge;
+
+      std::unique_ptr<UsageTimer> timer(new UsageTimer);
+      timer_.swap(timer);
       timer_result = timer->Mark();
     } else {
       // merge snapshots of each thread histogram
@@ -227,7 +225,6 @@ class Client {
    public:
     Thread(Client* client, size_t idx)
         : done_(false),
-          new_stats_(nullptr),
           client_(client),
           idx_(idx),
           impl_(&Thread::ThreadFunc, this) {}
@@ -240,16 +237,9 @@ class Client {
       impl_.join();
     }
 
-    void BeginSwap(Histogram* n) {
+    void Swap(Histogram* n) {
       std::lock_guard<std::mutex> g(mu_);
-      new_stats_ = n;
-    }
-
-    void EndSwap() {
-      std::unique_lock<std::mutex> g(mu_);
-      while (new_stats_ != nullptr) {
-        cv_.wait(g);
-      };
+      n->Swap(&histogram_);
     }
 
     void MergeStatsInto(Histogram* hist) {
@@ -263,10 +253,11 @@ class Client {
 
     void ThreadFunc() {
       for (;;) {
+        // lock since the thread should only be doing one thing at a time
+        std::lock_guard<std::mutex> g(mu_);
         // run the loop body
         const bool thread_still_ok = client_->ThreadFunc(&histogram_, idx_);
-        // lock, see if we're done
-        std::lock_guard<std::mutex> g(mu_);
+        // see if we're done
         if (!thread_still_ok) {
           gpr_log(GPR_ERROR, "Finishing client thread due to RPC error");
           done_ = true;
@@ -274,19 +265,11 @@ class Client {
         if (done_) {
           return;
         }
-        // check if we're resetting stats, swap out the histogram if so
-        if (new_stats_) {
-          new_stats_->Swap(&histogram_);
-          new_stats_ = nullptr;
-          cv_.notify_one();
-        }
       }
     }
 
     std::mutex mu_;
-    std::condition_variable cv_;
     bool done_;
-    Histogram* new_stats_;
     Histogram histogram_;
     Client* client_;
     const size_t idx_;
diff --git a/test/cpp/qps/driver.cc b/test/cpp/qps/driver.cc
index 1c7fdf8796090053dbb3d27c75e4f87e029f6a16..bc8780f74d58229f475b1de81d0894fa923c09d8 100644
--- a/test/cpp/qps/driver.cc
+++ b/test/cpp/qps/driver.cc
@@ -348,19 +348,10 @@ std::unique_ptr<ScenarioResult> RunScenario(
   std::unique_ptr<ScenarioResult> result(new ScenarioResult);
   result->client_config = result_client_config;
   result->server_config = result_server_config;
-  gpr_log(GPR_INFO, "Finishing");
-  for (auto server = &servers[0]; server != &servers[num_servers]; server++) {
-    GPR_ASSERT(server->stream->Write(server_mark));
-  }
+  gpr_log(GPR_INFO, "Finishing clients");
   for (auto client = &clients[0]; client != &clients[num_clients]; client++) {
     GPR_ASSERT(client->stream->Write(client_mark));
-  }
-  for (auto server = &servers[0]; server != &servers[num_servers]; server++) {
-    GPR_ASSERT(server->stream->Read(&server_status));
-    const auto& stats = server_status.stats();
-    result->server_resources.emplace_back(
-        stats.time_elapsed(), stats.time_user(), stats.time_system(),
-        server_status.cores());
+    GPR_ASSERT(client->stream->WritesDone());
   }
   for (auto client = &clients[0]; client != &clients[num_clients]; client++) {
     GPR_ASSERT(client->stream->Read(&client_status));
@@ -368,17 +359,30 @@ std::unique_ptr<ScenarioResult> RunScenario(
     result->latencies.MergeProto(stats.latencies());
     result->client_resources.emplace_back(
         stats.time_elapsed(), stats.time_user(), stats.time_system(), -1);
+    GPR_ASSERT(!client->stream->Read(&client_status));
   }
-
   for (auto client = &clients[0]; client != &clients[num_clients]; client++) {
-    GPR_ASSERT(client->stream->WritesDone());
     GPR_ASSERT(client->stream->Finish().ok());
   }
+  delete[] clients;
+
+  gpr_log(GPR_INFO, "Finishing servers");
   for (auto server = &servers[0]; server != &servers[num_servers]; server++) {
+    GPR_ASSERT(server->stream->Write(server_mark));
     GPR_ASSERT(server->stream->WritesDone());
+  }
+  for (auto server = &servers[0]; server != &servers[num_servers]; server++) {
+    GPR_ASSERT(server->stream->Read(&server_status));
+    const auto& stats = server_status.stats();
+    result->server_resources.emplace_back(
+        stats.time_elapsed(), stats.time_user(), stats.time_system(),
+        server_status.cores());
+    GPR_ASSERT(!server->stream->Read(&server_status));
+  }
+  for (auto server = &servers[0]; server != &servers[num_servers]; server++) {
     GPR_ASSERT(server->stream->Finish().ok());
   }
-  delete[] clients;
+
   delete[] servers;
   return result;
 }
diff --git a/test/cpp/qps/qps_worker.cc b/test/cpp/qps/qps_worker.cc
index 9442017ddf525bb3ecb886a90925dd2fa9587c2c..b83e9d1dd7f0337620b7a44ee8bc0cf913726a6e 100644
--- a/test/cpp/qps/qps_worker.cc
+++ b/test/cpp/qps/qps_worker.cc
@@ -101,6 +101,19 @@ static std::unique_ptr<Server> CreateServer(const ServerConfig& config) {
   abort();
 }
 
+class ScopedProfile GRPC_FINAL {
+ public:
+  ScopedProfile(const char* filename, bool enable) : enable_(enable) {
+    if (enable_) grpc_profiler_start(filename);
+  }
+  ~ScopedProfile() {
+    if (enable_) grpc_profiler_stop();
+  }
+
+ private:
+  const bool enable_;
+};
+
 class WorkerServiceImpl GRPC_FINAL : public WorkerService::Service {
  public:
   WorkerServiceImpl(int server_port, QpsWorker* worker)
@@ -114,9 +127,8 @@ class WorkerServiceImpl GRPC_FINAL : public WorkerService::Service {
       return Status(StatusCode::RESOURCE_EXHAUSTED, "");
     }
 
-    grpc_profiler_start("qps_client.prof");
+    ScopedProfile profile("qps_client.prof", false);
     Status ret = RunClientBody(ctx, stream);
-    grpc_profiler_stop();
     return ret;
   }
 
@@ -128,9 +140,8 @@ class WorkerServiceImpl GRPC_FINAL : public WorkerService::Service {
       return Status(StatusCode::RESOURCE_EXHAUSTED, "");
     }
 
-    grpc_profiler_start("qps_server.prof");
+    ScopedProfile profile("qps_server.prof", false);
     Status ret = RunServerBody(ctx, stream);
-    grpc_profiler_stop();
     return ret;
   }
 
diff --git a/tools/distrib/python/docgen.py b/tools/distrib/python/docgen.py
index 4ac8f9c64a847a1455b059bbced463db4f7be327..161d83e3b7f187665a10bc86e73c39756600852b 100755
--- a/tools/distrib/python/docgen.py
+++ b/tools/distrib/python/docgen.py
@@ -1,5 +1,5 @@
 #!/usr/bin/env python2.7
-# Copyright 2015, Google Inc.
+# Copyright 2015-2016, Google Inc.
 # All rights reserved.
 #
 # Redistribution and use in source and binary forms, with or without
@@ -51,29 +51,35 @@ SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__))
 PROJECT_ROOT = os.path.abspath(os.path.join(SCRIPT_DIR, '..', '..', '..'))
 
 CONFIG = args.config
-SETUP_PATH = os.path.join(PROJECT_ROOT, 'src/python/grpcio/setup.py')
-DOC_PATH = os.path.join(PROJECT_ROOT, 'src/python/grpcio/doc/build')
+SETUP_PATH = os.path.join(PROJECT_ROOT, 'setup.py')
+REQUIREMENTS_PATH = os.path.join(PROJECT_ROOT, 'requirements.txt')
+DOC_PATH = os.path.join(PROJECT_ROOT, 'doc/build')
 INCLUDE_PATH = os.path.join(PROJECT_ROOT, 'include')
 LIBRARY_PATH = os.path.join(PROJECT_ROOT, 'libs/{}'.format(CONFIG))
 VIRTUALENV_DIR = os.path.join(SCRIPT_DIR, 'distrib_virtualenv')
 VIRTUALENV_PYTHON_PATH = os.path.join(VIRTUALENV_DIR, 'bin', 'python')
+VIRTUALENV_PIP_PATH = os.path.join(VIRTUALENV_DIR, 'bin', 'pip')
 
 environment = os.environ.copy()
 environment.update({
     'CONFIG': CONFIG,
     'CFLAGS': '-I{}'.format(INCLUDE_PATH),
     'LDFLAGS': '-L{}'.format(LIBRARY_PATH),
-    'LD_LIBRARY_PATH': LIBRARY_PATH
+    'LD_LIBRARY_PATH': LIBRARY_PATH,
+    'GRPC_PYTHON_BUILD_WITH_CYTHON': '1',
 })
 
 subprocess_arguments_list = [
     {'args': ['make'], 'cwd': PROJECT_ROOT},
     {'args': ['virtualenv', VIRTUALENV_DIR], 'env': environment},
+    {'args': [VIRTUALENV_PIP_PATH, 'install', '-r', REQUIREMENTS_PATH],
+     'env': environment},
     {'args': [VIRTUALENV_PYTHON_PATH, SETUP_PATH, 'build'], 'env': environment},
     {'args': [VIRTUALENV_PYTHON_PATH, SETUP_PATH, 'doc'], 'env': environment},
 ]
 
 for subprocess_arguments in subprocess_arguments_list:
+  print('Running command: {}'.format(subprocess_arguments['args']))
   subprocess.check_call(**subprocess_arguments)
 
 if args.submit:
diff --git a/tools/dockerfile/test/cxx_ubuntu1404_x64/Dockerfile b/tools/dockerfile/test/cxx_ubuntu1404_x64/Dockerfile
new file mode 100644
index 0000000000000000000000000000000000000000..e8dab1b4712498f2341760f68901bd3f14400f90
--- /dev/null
+++ b/tools/dockerfile/test/cxx_ubuntu1404_x64/Dockerfile
@@ -0,0 +1,86 @@
+# Copyright 2015-2016, Google Inc.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+#     * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+#     * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+FROM ubuntu:14.04
+
+# Install Git and basic packages.
+RUN apt-get update && apt-get install -y \
+  autoconf \
+  autotools-dev \
+  build-essential \
+  bzip2 \
+  ccache \
+  curl \
+  gcc \
+  gcc-multilib \
+  git \
+  golang \
+  gyp \
+  lcov \
+  libc6 \
+  libc6-dbg \
+  libc6-dev \
+  libgtest-dev \
+  libtool \
+  make \
+  perl \
+  strace \
+  python-dev \
+  python-setuptools \
+  python-yaml \
+  telnet \
+  unzip \
+  wget \
+  zip && apt-get clean
+
+#================
+# Build profiling
+RUN apt-get update && apt-get install -y time && apt-get clean
+
+#=================
+# C++ dependencies
+RUN apt-get update && apt-get -y install libgflags-dev libgtest-dev libc++-dev clang && apt-get clean
+
+# Prepare ccache
+RUN ln -s /usr/bin/ccache /usr/local/bin/gcc
+RUN ln -s /usr/bin/ccache /usr/local/bin/g++
+RUN ln -s /usr/bin/ccache /usr/local/bin/cc
+RUN ln -s /usr/bin/ccache /usr/local/bin/c++
+RUN ln -s /usr/bin/ccache /usr/local/bin/clang
+RUN ln -s /usr/bin/ccache /usr/local/bin/clang++
+
+#======================
+# Zookeeper dependencies
+# TODO(jtattermusch): is zookeeper still needed?
+RUN apt-get install -y libzookeeper-mt-dev
+
+RUN mkdir /var/local/jenkins
+
+# Define the default command.
+CMD ["bash"]
diff --git a/tools/run_tests/artifact_targets.py b/tools/run_tests/artifact_targets.py
index 288a3f01542304b467ef94f69ef6242ea93cfcc1..e61c46d8b5aa2d9eba1ae427b947d6f45aabdc73 100644
--- a/tools/run_tests/artifact_targets.py
+++ b/tools/run_tests/artifact_targets.py
@@ -69,16 +69,6 @@ def create_jobspec(name, cmdline, environ=None, shell=False,
   return jobspec
 
 
-def macos_arch_env(arch):
-  """Returns environ specifying -arch arguments for make."""
-  if arch == 'x86':
-    arch_arg = '-arch i386'
-  elif arch == 'x64':
-    arch_arg = '-arch x86_64'
-  else:
-    raise Exception('Unsupported arch')
-  return {'CFLAGS': arch_arg, 'LDFLAGS': arch_arg}
-
 _MACOS_COMPAT_FLAG = '-mmacosx-version-min=10.7'
 
 _ARCH_FLAG_MAP = {
@@ -191,13 +181,17 @@ class CSharpExtArtifact:
       environ = {'CONFIG': 'opt',
                  'EMBED_OPENSSL': 'true',
                  'EMBED_ZLIB': 'true',
-                 'CFLAGS': '-DGPR_BACKWARDS_COMPATIBILITY_MODE'}
+                 'CFLAGS': '-DGPR_BACKWARDS_COMPATIBILITY_MODE',
+                 'LDFLAGS': ''}
       if self.platform == 'linux':
         return create_docker_jobspec(self.name,
             'tools/dockerfile/grpc_artifact_linux_%s' % self.arch,
-            'tools/run_tests/build_artifact_csharp.sh')
+            'tools/run_tests/build_artifact_csharp.sh',
+            environ=environ)
       else:
-        environ.update(macos_arch_env(self.arch))
+        archflag = _ARCH_FLAG_MAP[self.arch]
+        environ['CFLAGS'] += ' %s %s' % (archflag, _MACOS_COMPAT_FLAG)
+        environ['LDFLAGS'] += ' %s' % archflag
         return create_jobspec(self.name,
                               ['tools/run_tests/build_artifact_csharp.sh'],
                               environ=environ)
diff --git a/tools/run_tests/build_python.sh b/tools/run_tests/build_python.sh
index f120fc7ed6905ecc896d6dfcf2d7eaa82b9a9124..79a148faf1bfcf215330e2f42519a365de46d95b 100755
--- a/tools/run_tests/build_python.sh
+++ b/tools/run_tests/build_python.sh
@@ -40,7 +40,11 @@ export PATH=$ROOT/bins/$CONFIG:$ROOT/bins/$CONFIG/protobuf:$PATH
 export CFLAGS="-I$ROOT/include -std=gnu99"
 export LDFLAGS="-L$ROOT/libs/$CONFIG"
 export GRPC_PYTHON_BUILD_WITH_CYTHON=1
-export GRPC_PYTHON_ENABLE_CYTHON_TRACING=1
+
+if [ "$CONFIG" = "gcov" ]
+then
+  export GRPC_PYTHON_ENABLE_CYTHON_TRACING=1
+fi
 
 tox --notest
 
diff --git a/tools/run_tests/run_python.sh b/tools/run_tests/run_python.sh
index beb747a6169aca6a64380a29cf4e695ea070e474..d4b7250cbb7f22066aeb01f9c99b65630123a491 100755
--- a/tools/run_tests/run_python.sh
+++ b/tools/run_tests/run_python.sh
@@ -40,13 +40,13 @@ export PATH=$ROOT/bins/$CONFIG:$ROOT/bins/$CONFIG/protobuf:$PATH
 export CFLAGS="-I$ROOT/include -std=c89"
 export LDFLAGS="-L$ROOT/libs/$CONFIG"
 export GRPC_PYTHON_BUILD_WITH_CYTHON=1
-export GRPC_PYTHON_ENABLE_CYTHON_TRACING=1
 
 if [ "$CONFIG" = "gcov" ]
 then
+  export GRPC_PYTHON_ENABLE_CYTHON_TRACING=1
   tox
 else
-  $ROOT/.tox/py27/bin/python $ROOT/setup.py test
+  $ROOT/.tox/py27/bin/python $ROOT/setup.py test_lite
 fi
 
 mkdir -p $ROOT/reports
diff --git a/tools/run_tests/run_tests.py b/tools/run_tests/run_tests.py
index cc004f38d7f1852a578515d45bd260d7317d6d78..aa5073fbbd254dd77427ab710ae916460ed858d1 100755
--- a/tools/run_tests/run_tests.py
+++ b/tools/run_tests/run_tests.py
@@ -142,9 +142,8 @@ class CLanguage(object):
       self._make_options = [_windows_toolset_option(self.args.compiler),
                             _windows_arch_option(self.args.arch)]
     else:
-      self._make_options = []
-      self._docker_distro = self._get_docker_distro(self.args.use_docker,
-                                                    self.args.compiler)
+      self._docker_distro, self._make_options = self._compiler_options(self.args.use_docker,
+                                                                       self.args.compiler)
 
   def test_specs(self):
     out = []
@@ -229,18 +228,26 @@ class CLanguage(object):
   def makefile_name(self):
     return 'Makefile'
 
-  def _get_docker_distro(self, use_docker, compiler):
+  def _clang_make_options(self):
+    return ['CC=clang', 'CXX=clang++', 'LD=clang', 'LDXX=clang++']
+
+  def _compiler_options(self, use_docker, compiler):
+    """Returns docker distro and make options to use for given compiler."""
     if _is_use_docker_child():
-      return "already_under_docker"
+      return ("already_under_docker", [])
     if not use_docker:
       _check_compiler(compiler, ['default'])
 
     if compiler == 'gcc4.9' or compiler == 'default':
-      return 'jessie'
+      return ('jessie', [])
     elif compiler == 'gcc4.4':
-      return 'squeeze'
+      return ('squeeze', [])
     elif compiler == 'gcc5.3':
-      return 'ubuntu1604'
+      return ('ubuntu1604', [])
+    elif compiler == 'clang3.4':
+      return ('ubuntu1404', self._clang_make_options())
+    elif compiler == 'clang3.6':
+      return ('ubuntu1604', self._clang_make_options())
     else:
       raise Exception('Compiler %s not supported.' % compiler)
 
@@ -360,7 +367,7 @@ class PythonLanguage(object):
           ['tools/run_tests/run_python.sh'],
           None,
           environ=dict(environment.items() +
-                       [('GPRC_PYTHON_TESTRUNNER_FILTER', suite_name)]),
+                       [('GRPC_PYTHON_TESTRUNNER_FILTER', suite_name)]),
           shortname='py.test.%s' % suite_name,
           timeout_seconds=5*60)
           for suite_name in tests_json]
@@ -774,6 +781,7 @@ argp.add_argument('--arch',
 argp.add_argument('--compiler',
                   choices=['default',
                            'gcc4.4', 'gcc4.9', 'gcc5.3',
+                           'clang3.4', 'clang3.6',
                            'vs2010', 'vs2013', 'vs2015'],
                   default='default',
                   help='Selects compiler to use. Allowed values depend on the platform and language.')
diff --git a/tools/run_tests/sources_and_headers.json b/tools/run_tests/sources_and_headers.json
index 0c7a6c7b5f34f277870ef17db4f1d4843033f620..0039b99a55edc0f0fc7f48df3c16bcf0be8a1fa8 100644
--- a/tools/run_tests/sources_and_headers.json
+++ b/tools/run_tests/sources_and_headers.json
@@ -189,6 +189,22 @@
     "third_party": false, 
     "type": "target"
   }, 
+  {
+    "deps": [
+      "gpr", 
+      "gpr_test_util", 
+      "grpc", 
+      "grpc_test_util"
+    ], 
+    "headers": [], 
+    "language": "c", 
+    "name": "dns_resolver_connectivity_test", 
+    "src": [
+      "test/core/client_config/resolvers/dns_resolver_connectivity_test.c"
+    ], 
+    "third_party": false, 
+    "type": "target"
+  }, 
   {
     "deps": [
       "gpr", 
diff --git a/tools/run_tests/tests.json b/tools/run_tests/tests.json
index d91245cd06ae73b3baa319cc92cb61b4337e852d..724cd64d19c73d333280090d424bb784addfa3ac 100644
--- a/tools/run_tests/tests.json
+++ b/tools/run_tests/tests.json
@@ -253,6 +253,27 @@
       "windows"
     ]
   }, 
+  {
+    "args": [], 
+    "ci_platforms": [
+      "linux", 
+      "mac", 
+      "posix", 
+      "windows"
+    ], 
+    "cpu_cost": 0.1, 
+    "exclude_configs": [], 
+    "flaky": false, 
+    "gtest": false, 
+    "language": "c", 
+    "name": "dns_resolver_connectivity_test", 
+    "platforms": [
+      "linux", 
+      "mac", 
+      "posix", 
+      "windows"
+    ]
+  }, 
   {
     "args": [], 
     "ci_platforms": [
diff --git a/vsprojects/buildtests_c.sln b/vsprojects/buildtests_c.sln
index 7cdc3b7ee8121c3ffc256cc89822bd93762e890d..be2c4a3bb1437621c8b5e8d44a57d1581a9f147c 100644
--- a/vsprojects/buildtests_c.sln
+++ b/vsprojects/buildtests_c.sln
@@ -251,6 +251,17 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "compression_test", "vcxproj
 		{B23D3D1A-9438-4EDA-BEB6-9A0A03D17792} = {B23D3D1A-9438-4EDA-BEB6-9A0A03D17792}
 	EndProjectSection
 EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "dns_resolver_connectivity_test", "vcxproj\test\dns_resolver_connectivity_test\dns_resolver_connectivity_test.vcxproj", "{F7B6FE68-E847-D7CA-4062-E737E542BCC3}"
+	ProjectSection(myProperties) = preProject
+        	lib = "False"
+	EndProjectSection
+	ProjectSection(ProjectDependencies) = postProject
+		{17BCAFC0-5FDC-4C94-AEB9-95F3E220614B} = {17BCAFC0-5FDC-4C94-AEB9-95F3E220614B}
+		{29D16885-7228-4C31-81ED-5F9187C7F2A9} = {29D16885-7228-4C31-81ED-5F9187C7F2A9}
+		{EAB0A629-17A9-44DB-B5FF-E91A721FE037} = {EAB0A629-17A9-44DB-B5FF-E91A721FE037}
+		{B23D3D1A-9438-4EDA-BEB6-9A0A03D17792} = {B23D3D1A-9438-4EDA-BEB6-9A0A03D17792}
+	EndProjectSection
+EndProject
 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "dns_resolver_test", "vcxproj\test\dns_resolver_test\dns_resolver_test.vcxproj", "{D06E10DC-272A-5203-7066-2698A247DF26}"
 	ProjectSection(myProperties) = preProject
         	lib = "False"
@@ -1736,6 +1747,22 @@ Global
 		{5AFE7D17-A4A7-D68E-4491-CBC852F9D2A0}.Release-DLL|Win32.Build.0 = Release|Win32
 		{5AFE7D17-A4A7-D68E-4491-CBC852F9D2A0}.Release-DLL|x64.ActiveCfg = Release|x64
 		{5AFE7D17-A4A7-D68E-4491-CBC852F9D2A0}.Release-DLL|x64.Build.0 = Release|x64
+		{F7B6FE68-E847-D7CA-4062-E737E542BCC3}.Debug|Win32.ActiveCfg = Debug|Win32
+		{F7B6FE68-E847-D7CA-4062-E737E542BCC3}.Debug|x64.ActiveCfg = Debug|x64
+		{F7B6FE68-E847-D7CA-4062-E737E542BCC3}.Release|Win32.ActiveCfg = Release|Win32
+		{F7B6FE68-E847-D7CA-4062-E737E542BCC3}.Release|x64.ActiveCfg = Release|x64
+		{F7B6FE68-E847-D7CA-4062-E737E542BCC3}.Debug|Win32.Build.0 = Debug|Win32
+		{F7B6FE68-E847-D7CA-4062-E737E542BCC3}.Debug|x64.Build.0 = Debug|x64
+		{F7B6FE68-E847-D7CA-4062-E737E542BCC3}.Release|Win32.Build.0 = Release|Win32
+		{F7B6FE68-E847-D7CA-4062-E737E542BCC3}.Release|x64.Build.0 = Release|x64
+		{F7B6FE68-E847-D7CA-4062-E737E542BCC3}.Debug-DLL|Win32.ActiveCfg = Debug|Win32
+		{F7B6FE68-E847-D7CA-4062-E737E542BCC3}.Debug-DLL|Win32.Build.0 = Debug|Win32
+		{F7B6FE68-E847-D7CA-4062-E737E542BCC3}.Debug-DLL|x64.ActiveCfg = Debug|x64
+		{F7B6FE68-E847-D7CA-4062-E737E542BCC3}.Debug-DLL|x64.Build.0 = Debug|x64
+		{F7B6FE68-E847-D7CA-4062-E737E542BCC3}.Release-DLL|Win32.ActiveCfg = Release|Win32
+		{F7B6FE68-E847-D7CA-4062-E737E542BCC3}.Release-DLL|Win32.Build.0 = Release|Win32
+		{F7B6FE68-E847-D7CA-4062-E737E542BCC3}.Release-DLL|x64.ActiveCfg = Release|x64
+		{F7B6FE68-E847-D7CA-4062-E737E542BCC3}.Release-DLL|x64.Build.0 = Release|x64
 		{D06E10DC-272A-5203-7066-2698A247DF26}.Debug|Win32.ActiveCfg = Debug|Win32
 		{D06E10DC-272A-5203-7066-2698A247DF26}.Debug|x64.ActiveCfg = Debug|x64
 		{D06E10DC-272A-5203-7066-2698A247DF26}.Release|Win32.ActiveCfg = Release|Win32
diff --git a/vsprojects/vcxproj/test/dns_resolver_connectivity_test/dns_resolver_connectivity_test.vcxproj b/vsprojects/vcxproj/test/dns_resolver_connectivity_test/dns_resolver_connectivity_test.vcxproj
new file mode 100644
index 0000000000000000000000000000000000000000..76ac196dda6ac7e2a8880ec7789a28c86bf31c89
--- /dev/null
+++ b/vsprojects/vcxproj/test/dns_resolver_connectivity_test/dns_resolver_connectivity_test.vcxproj
@@ -0,0 +1,199 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <Import Project="$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.1.0.204.1\build\native\grpc.dependencies.openssl.props" Condition="Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.1.0.204.1\build\native\1.0.204.1.props')" />
+  <ItemGroup Label="ProjectConfigurations">
+    <ProjectConfiguration Include="Debug|Win32">
+      <Configuration>Debug</Configuration>
+      <Platform>Win32</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Debug|x64">
+      <Configuration>Debug</Configuration>
+      <Platform>x64</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Release|Win32">
+      <Configuration>Release</Configuration>
+      <Platform>Win32</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Release|x64">
+      <Configuration>Release</Configuration>
+      <Platform>x64</Platform>
+    </ProjectConfiguration>
+  </ItemGroup>
+  <PropertyGroup Label="Globals">
+    <ProjectGuid>{F7B6FE68-E847-D7CA-4062-E737E542BCC3}</ProjectGuid>
+    <IgnoreWarnIntDirInTempDetected>true</IgnoreWarnIntDirInTempDetected>
+    <IntDir>$(SolutionDir)IntDir\$(MSBuildProjectName)\</IntDir>
+  </PropertyGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+  <PropertyGroup Condition="'$(VisualStudioVersion)' == '10.0'" Label="Configuration">
+    <PlatformToolset>v100</PlatformToolset>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(VisualStudioVersion)' == '11.0'" Label="Configuration">
+    <PlatformToolset>v110</PlatformToolset>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(VisualStudioVersion)' == '12.0'" Label="Configuration">
+    <PlatformToolset>v120</PlatformToolset>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(VisualStudioVersion)' == '14.0'" Label="Configuration">
+    <PlatformToolset>v140</PlatformToolset>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)'=='Debug'" Label="Configuration">
+    <ConfigurationType>Application</ConfigurationType>
+    <UseDebugLibraries>true</UseDebugLibraries>
+    <CharacterSet>Unicode</CharacterSet>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)'=='Release'" Label="Configuration">
+    <ConfigurationType>Application</ConfigurationType>
+    <UseDebugLibraries>false</UseDebugLibraries>
+    <WholeProgramOptimization>true</WholeProgramOptimization>
+    <CharacterSet>Unicode</CharacterSet>
+  </PropertyGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+  <ImportGroup Label="ExtensionSettings">
+  </ImportGroup>
+  <ImportGroup Label="PropertySheets">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+    <Import Project="$(SolutionDir)\..\vsprojects\global.props" />
+    <Import Project="$(SolutionDir)\..\vsprojects\openssl.props" />
+    <Import Project="$(SolutionDir)\..\vsprojects\winsock.props" />
+    <Import Project="$(SolutionDir)\..\vsprojects\zlib.props" />
+  </ImportGroup>
+  <PropertyGroup Label="UserMacros" />
+  <PropertyGroup Condition="'$(Configuration)'=='Debug'">
+    <TargetName>dns_resolver_connectivity_test</TargetName>
+    <Linkage-grpc_dependencies_zlib>static</Linkage-grpc_dependencies_zlib>
+    <Configuration-grpc_dependencies_zlib>Debug</Configuration-grpc_dependencies_zlib>
+    <Linkage-grpc_dependencies_openssl>static</Linkage-grpc_dependencies_openssl>
+    <Configuration-grpc_dependencies_openssl>Debug</Configuration-grpc_dependencies_openssl>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)'=='Release'">
+    <TargetName>dns_resolver_connectivity_test</TargetName>
+    <Linkage-grpc_dependencies_zlib>static</Linkage-grpc_dependencies_zlib>
+    <Configuration-grpc_dependencies_zlib>Release</Configuration-grpc_dependencies_zlib>
+    <Linkage-grpc_dependencies_openssl>static</Linkage-grpc_dependencies_openssl>
+    <Configuration-grpc_dependencies_openssl>Release</Configuration-grpc_dependencies_openssl>
+  </PropertyGroup>
+    <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+    <ClCompile>
+      <PrecompiledHeader>NotUsing</PrecompiledHeader>
+      <WarningLevel>Level3</WarningLevel>
+      <Optimization>Disabled</Optimization>
+      <PreprocessorDefinitions>WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <SDLCheck>true</SDLCheck>
+      <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
+      <TreatWarningAsError>true</TreatWarningAsError>
+      <DebugInformationFormat Condition="$(Jenkins)">None</DebugInformationFormat>
+      <MinimalRebuild Condition="$(Jenkins)">false</MinimalRebuild>
+    </ClCompile>
+    <Link>
+      <SubSystem>Console</SubSystem>
+      <GenerateDebugInformation Condition="!$(Jenkins)">true</GenerateDebugInformation>
+      <GenerateDebugInformation Condition="$(Jenkins)">false</GenerateDebugInformation>
+    </Link>
+  </ItemDefinitionGroup>
+
+    <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+    <ClCompile>
+      <PrecompiledHeader>NotUsing</PrecompiledHeader>
+      <WarningLevel>Level3</WarningLevel>
+      <Optimization>Disabled</Optimization>
+      <PreprocessorDefinitions>WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <SDLCheck>true</SDLCheck>
+      <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
+      <TreatWarningAsError>true</TreatWarningAsError>
+      <DebugInformationFormat Condition="$(Jenkins)">None</DebugInformationFormat>
+      <MinimalRebuild Condition="$(Jenkins)">false</MinimalRebuild>
+    </ClCompile>
+    <Link>
+      <SubSystem>Console</SubSystem>
+      <GenerateDebugInformation Condition="!$(Jenkins)">true</GenerateDebugInformation>
+      <GenerateDebugInformation Condition="$(Jenkins)">false</GenerateDebugInformation>
+    </Link>
+  </ItemDefinitionGroup>
+
+    <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+    <ClCompile>
+      <PrecompiledHeader>NotUsing</PrecompiledHeader>
+      <WarningLevel>Level3</WarningLevel>
+      <Optimization>MaxSpeed</Optimization>
+      <PreprocessorDefinitions>WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <FunctionLevelLinking>true</FunctionLevelLinking>
+      <IntrinsicFunctions>true</IntrinsicFunctions>
+      <SDLCheck>true</SDLCheck>
+      <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
+      <TreatWarningAsError>true</TreatWarningAsError>
+      <DebugInformationFormat Condition="$(Jenkins)">None</DebugInformationFormat>
+      <MinimalRebuild Condition="$(Jenkins)">false</MinimalRebuild>
+    </ClCompile>
+    <Link>
+      <SubSystem>Console</SubSystem>
+      <GenerateDebugInformation Condition="!$(Jenkins)">true</GenerateDebugInformation>
+      <GenerateDebugInformation Condition="$(Jenkins)">false</GenerateDebugInformation>
+      <EnableCOMDATFolding>true</EnableCOMDATFolding>
+      <OptimizeReferences>true</OptimizeReferences>
+    </Link>
+  </ItemDefinitionGroup>
+
+    <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+    <ClCompile>
+      <PrecompiledHeader>NotUsing</PrecompiledHeader>
+      <WarningLevel>Level3</WarningLevel>
+      <Optimization>MaxSpeed</Optimization>
+      <PreprocessorDefinitions>WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <FunctionLevelLinking>true</FunctionLevelLinking>
+      <IntrinsicFunctions>true</IntrinsicFunctions>
+      <SDLCheck>true</SDLCheck>
+      <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
+      <TreatWarningAsError>true</TreatWarningAsError>
+      <DebugInformationFormat Condition="$(Jenkins)">None</DebugInformationFormat>
+      <MinimalRebuild Condition="$(Jenkins)">false</MinimalRebuild>
+    </ClCompile>
+    <Link>
+      <SubSystem>Console</SubSystem>
+      <GenerateDebugInformation Condition="!$(Jenkins)">true</GenerateDebugInformation>
+      <GenerateDebugInformation Condition="$(Jenkins)">false</GenerateDebugInformation>
+      <EnableCOMDATFolding>true</EnableCOMDATFolding>
+      <OptimizeReferences>true</OptimizeReferences>
+    </Link>
+  </ItemDefinitionGroup>
+
+  <ItemGroup>
+    <ClCompile Include="$(SolutionDir)\..\test\core\client_config\resolvers\dns_resolver_connectivity_test.c">
+    </ClCompile>
+  </ItemGroup>
+  <ItemGroup>
+    <ProjectReference Include="$(SolutionDir)\..\vsprojects\vcxproj\.\grpc_test_util\grpc_test_util.vcxproj">
+      <Project>{17BCAFC0-5FDC-4C94-AEB9-95F3E220614B}</Project>
+    </ProjectReference>
+    <ProjectReference Include="$(SolutionDir)\..\vsprojects\vcxproj\.\grpc\grpc.vcxproj">
+      <Project>{29D16885-7228-4C31-81ED-5F9187C7F2A9}</Project>
+    </ProjectReference>
+    <ProjectReference Include="$(SolutionDir)\..\vsprojects\vcxproj\.\gpr_test_util\gpr_test_util.vcxproj">
+      <Project>{EAB0A629-17A9-44DB-B5FF-E91A721FE037}</Project>
+    </ProjectReference>
+    <ProjectReference Include="$(SolutionDir)\..\vsprojects\vcxproj\.\gpr\gpr.vcxproj">
+      <Project>{B23D3D1A-9438-4EDA-BEB6-9A0A03D17792}</Project>
+    </ProjectReference>
+  </ItemGroup>
+  <ItemGroup>
+    <None Include="packages.config" />
+  </ItemGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+  <ImportGroup Label="ExtensionTargets">
+  <Import Project="$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.zlib.redist.1.2.8.10\build\native\grpc.dependencies.zlib.redist.targets" Condition="Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.zlib.redist.1.2.8.10\build\native\grpc.dependencies\grpc.dependencies.zlib.targets')" />
+  <Import Project="$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.zlib.1.2.8.10\build\native\grpc.dependencies.zlib.targets" Condition="Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.zlib.1.2.8.10\build\native\grpc.dependencies\grpc.dependencies.zlib.targets')" />
+  <Import Project="$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.redist.1.0.204.1\build\native\grpc.dependencies.openssl.redist.targets" Condition="Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.redist.1.0.204.1\build\native\grpc.dependencies\grpc.dependencies.openssl.targets')" />
+  <Import Project="$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.1.0.204.1\build\native\grpc.dependencies.openssl.targets" Condition="Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.1.0.204.1\build\native\grpc.dependencies\grpc.dependencies.openssl.targets')" />
+  </ImportGroup>
+  <Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
+    <PropertyGroup>
+      <ErrorText>This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them.  For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
+    </PropertyGroup>
+    <Error Condition="!Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.zlib.redist.1.2.8.10\build\native\grpc.dependencies.zlib.redist.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.zlib.redist.1.2.8.10\build\native\grpc.dependencies.zlib.redist.targets')" />
+    <Error Condition="!Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.zlib.1.2.8.10\build\native\grpc.dependencies.zlib.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.zlib.1.2.8.10\build\native\grpc.dependencies.zlib.targets')" />
+    <Error Condition="!Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.redist.1.0.204.1\build\native\grpc.dependencies.openssl.redist.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.redist.1.0.204.1\build\native\grpc.dependencies.openssl.redist.targets')" />
+    <Error Condition="!Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.1.0.204.1\build\native\grpc.dependencies.openssl.props')" Text="$([System.String]::Format('$(ErrorText)', '$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.1.0.204.1\build\native\grpc.dependencies.openssl.props')" />
+    <Error Condition="!Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.1.0.204.1\build\native\grpc.dependencies.openssl.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.1.0.204.1\build\native\grpc.dependencies.openssl.targets')" />
+  </Target>
+</Project>
+
diff --git a/vsprojects/vcxproj/test/dns_resolver_connectivity_test/dns_resolver_connectivity_test.vcxproj.filters b/vsprojects/vcxproj/test/dns_resolver_connectivity_test/dns_resolver_connectivity_test.vcxproj.filters
new file mode 100644
index 0000000000000000000000000000000000000000..e49318df1104eb8c123d113f33e99fd3b79988ab
--- /dev/null
+++ b/vsprojects/vcxproj/test/dns_resolver_connectivity_test/dns_resolver_connectivity_test.vcxproj.filters
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <ItemGroup>
+    <ClCompile Include="$(SolutionDir)\..\test\core\client_config\resolvers\dns_resolver_connectivity_test.c">
+      <Filter>test\core\client_config\resolvers</Filter>
+    </ClCompile>
+  </ItemGroup>
+
+  <ItemGroup>
+    <Filter Include="test">
+      <UniqueIdentifier>{7743e287-3311-1206-2766-32381628ff07}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="test\core">
+      <UniqueIdentifier>{cc06b800-cd26-f7a8-7ecf-ec789e78881b}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="test\core\client_config">
+      <UniqueIdentifier>{4fbd5c0a-d1e3-6658-5788-2fc6f2cc9071}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="test\core\client_config\resolvers">
+      <UniqueIdentifier>{eab637a2-7ac1-f6be-4fc2-c8989c66070b}</UniqueIdentifier>
+    </Filter>
+  </ItemGroup>
+</Project>
+