Merge master
diff --git a/test/core/tsi/transport_security_test_lib.cc b/test/core/tsi/transport_security_test_lib.cc
index 454b79c..b98ab9b 100644
--- a/test/core/tsi/transport_security_test_lib.cc
+++ b/test/core/tsi/transport_security_test_lib.cc
@@ -354,25 +354,28 @@
   tsi_handshaker_result *handshaker_result = NULL;
   unsigned char *bytes_to_send = NULL;
   size_t bytes_to_send_size = 0;
+  tsi_result result = TSI_OK;
   /* Receive data from peer, if available. */
-  size_t buf_size = args->handshake_buffer_size;
-  receive_bytes_from_peer(args->fixture, &args->handshake_buffer, &buf_size,
-                          args->is_client);
-  if (buf_size > 0) {
-    args->transferred_data = true;
-  }
-  /* Peform handshaker next. */
-  tsi_result result = tsi_handshaker_next(
-      handshaker, args->handshake_buffer, buf_size,
-      (const unsigned char **)&bytes_to_send, &bytes_to_send_size,
-      &handshaker_result, &on_handshake_next_done_wrapper, args);
-  if (result != TSI_ASYNC) {
-    args->error = on_handshake_next_done(result, args, bytes_to_send,
-                                         bytes_to_send_size, handshaker_result);
-    if (args->error != GRPC_ERROR_NONE) {
-      return;
+  do {
+    size_t buf_size = args->handshake_buffer_size;
+    receive_bytes_from_peer(args->fixture, &args->handshake_buffer, &buf_size,
+                            args->is_client);
+    if (buf_size > 0) {
+      args->transferred_data = true;
     }
-  }
+    /* Peform handshaker next. */
+    result = tsi_handshaker_next(handshaker, args->handshake_buffer, buf_size,
+                                 (const unsigned char **)&bytes_to_send,
+                                 &bytes_to_send_size, &handshaker_result,
+                                 &on_handshake_next_done_wrapper, args);
+    if (result != TSI_ASYNC) {
+      args->error = on_handshake_next_done(
+          result, args, bytes_to_send, bytes_to_send_size, handshaker_result);
+      if (args->error != GRPC_ERROR_NONE) {
+        return;
+      }
+    }
+  } while (result == TSI_INCOMPLETE_DATA);
   notification_wait(fixture);
 }
 
diff --git a/test/core/tsi/transport_security_test_lib.h b/test/core/tsi/transport_security_test_lib.h
index 1a04c1f..49a7a59 100644
--- a/test/core/tsi/transport_security_test_lib.h
+++ b/test/core/tsi/transport_security_test_lib.h
@@ -21,6 +21,8 @@
 
 #include "src/core/tsi/transport_security_interface.h"
 
+#include <grpc/support/sync.h>
+
 #define TSI_TEST_TINY_HANDSHAKE_BUFFER_SIZE 32
 #define TSI_TEST_SMALL_HANDSHAKE_BUFFER_SIZE 128
 #define TSI_TEST_SMALL_READ_BUFFER_ALLOCATED_SIZE 41
diff --git a/test/cpp/end2end/async_end2end_test.cc b/test/cpp/end2end/async_end2end_test.cc
index af3bdb2..cf1cc7e 100644
--- a/test/cpp/end2end/async_end2end_test.cc
+++ b/test/cpp/end2end/async_end2end_test.cc
@@ -461,7 +461,6 @@
   if (GetParam().inproc) {
     return;
   }
-  gpr_setenv("GRPC_CLIENT_CHANNEL_BACKUP_POLL_INTERVAL_MS", "200");
   int poller_slowdown_factor = 1;
   // It needs 2 pollset_works to reconnect the channel with polling engine
   // "poll"
@@ -2013,6 +2012,9 @@
 }  // namespace grpc
 
 int main(int argc, char** argv) {
+  // Change the backup poll interval from 5s to 200ms to speed up the
+  // ReconnectChannel test
+  gpr_setenv("GRPC_CLIENT_CHANNEL_BACKUP_POLL_INTERVAL_MS", "200");
   grpc_test_init(argc, argv);
   gpr_tls_init(&g_is_async_end2end_test);
   ::testing::InitGoogleTest(&argc, argv);
diff --git a/test/cpp/end2end/thread_stress_test.cc b/test/cpp/end2end/thread_stress_test.cc
index f990a7e..90b2edd 100644
--- a/test/cpp/end2end/thread_stress_test.cc
+++ b/test/cpp/end2end/thread_stress_test.cc
@@ -50,23 +50,6 @@
 namespace grpc {
 namespace testing {
 
-namespace {
-
-// When echo_deadline is requested, deadline seen in the ServerContext is set in
-// the response in seconds.
-void MaybeEchoDeadline(ServerContext* context, const EchoRequest* request,
-                       EchoResponse* response) {
-  if (request->has_param() && request->param().echo_deadline()) {
-    gpr_timespec deadline = gpr_inf_future(GPR_CLOCK_REALTIME);
-    if (context->deadline() != system_clock::time_point::max()) {
-      Timepoint2Timespec(context->deadline(), &deadline);
-    }
-    response->mutable_param()->set_request_deadline(deadline.tv_sec);
-  }
-}
-
-}  // namespace
-
 class TestServiceImpl : public ::grpc::testing::EchoTestService::Service {
  public:
   TestServiceImpl() : signal_client_(false) {}
@@ -74,29 +57,6 @@
   Status Echo(ServerContext* context, const EchoRequest* request,
               EchoResponse* response) override {
     response->set_message(request->message());
-    MaybeEchoDeadline(context, request, response);
-    if (request->has_param() && request->param().client_cancel_after_us()) {
-      {
-        std::unique_lock<std::mutex> lock(mu_);
-        signal_client_ = true;
-      }
-      while (!context->IsCancelled()) {
-        gpr_sleep_until(gpr_time_add(
-            gpr_now(GPR_CLOCK_REALTIME),
-            gpr_time_from_micros(request->param().client_cancel_after_us(),
-                                 GPR_TIMESPAN)));
-      }
-      return Status::CANCELLED;
-    } else if (request->has_param() &&
-               request->param().server_cancel_after_us()) {
-      gpr_sleep_until(gpr_time_add(
-          gpr_now(GPR_CLOCK_REALTIME),
-          gpr_time_from_micros(request->param().server_cancel_after_us(),
-                               GPR_TIMESPAN)));
-      return Status::CANCELLED;
-    } else {
-      EXPECT_FALSE(context->IsCancelled());
-    }
     return Status::OK;
   }
 
diff --git a/test/cpp/microbenchmarks/fullstack_streaming_ping_pong.h b/test/cpp/microbenchmarks/fullstack_streaming_ping_pong.h
index 6df044f..06d18b8 100644
--- a/test/cpp/microbenchmarks/fullstack_streaming_ping_pong.h
+++ b/test/cpp/microbenchmarks/fullstack_streaming_ping_pong.h
@@ -278,7 +278,7 @@
 
       void* t;
       bool ok;
-      int need_tags;
+      int expect_tags;
 
       // Send 'max_ping_pongs' number of ping pong messages
       int ping_pong_cnt = 0;
@@ -289,7 +289,7 @@
           request_rw->Write(send_request, tag(2));  // Start client send
         }
 
-        need_tags = (1 << 2) | (1 << 3) | (1 << 4) | (1 << 5);
+        int await_tags = (1 << 2);
 
         if (ping_pong_cnt == 0) {
           // wait for the server call structure (call_hook, etc.) to be
@@ -301,8 +301,8 @@
             // In some cases tag:2 comes before tag:0 (write tag comes out
             // first), this while loop is to make sure get tag:0.
             int i = (int)(intptr_t)t;
-            GPR_ASSERT(need_tags & (1 << i));
-            need_tags &= ~(1 << i);
+            GPR_ASSERT(await_tags & (1 << i));
+            await_tags &= ~(1 << i);
             GPR_ASSERT(fixture->cq()->Next(&t, &ok));
           }
         }
@@ -310,7 +310,11 @@
         response_rw.Read(&recv_request, tag(3));   // Start server recv
         request_rw->Read(&recv_response, tag(4));  // Start client recv
 
-        while (need_tags) {
+        await_tags |= (1 << 3) | (1 << 4);
+        expect_tags = await_tags;
+        await_tags |= (1 << 5);
+
+        while (await_tags != 0) {
           GPR_ASSERT(fixture->cq()->Next(&t, &ok));
           GPR_ASSERT(ok);
           int i = (int)(intptr_t)t;
@@ -321,34 +325,39 @@
               if (write_and_finish == 1) {
                 response_rw.WriteAndFinish(send_response, WriteOptions(),
                                            Status::OK, tag(5));
+                expect_tags |= (1 << 5);
               } else {
                 response_rw.WriteLast(send_response, WriteOptions(), tag(5));
-                // WriteLast buffers the write, so neither server write op nor
-                // client read op will finish inside the while loop.
-                need_tags &= ~(1 << 4);
-                need_tags &= ~(1 << 5);
+                // WriteLast buffers the write, so it's possible neither server
+                // write op nor client read op will finish inside the while
+                // loop.
+                await_tags &= ~(1 << 4);
+                await_tags &= ~(1 << 5);
+                expect_tags |= (1 << 5);
               }
             } else {
               response_rw.Write(send_response, tag(5));
+              expect_tags |= (1 << 5);
             }
           }
 
-          GPR_ASSERT(need_tags & (1 << i));
-          need_tags &= ~(1 << i);
+          GPR_ASSERT(expect_tags & (1 << i));
+          expect_tags &= ~(1 << i);
+          await_tags &= ~(1 << i);
         }
 
         ping_pong_cnt++;
       }
 
       if (max_ping_pongs == 0) {
-        need_tags = (1 << 6) | (1 << 7) | (1 << 8);
+        expect_tags |= (1 << 6) | (1 << 7) | (1 << 8);
       } else {
         if (write_and_finish == 1) {
-          need_tags = (1 << 8);
+          expect_tags |= (1 << 8);
         } else {
           // server's buffered write and the client's read of the buffered write
           // tags should come up.
-          need_tags = (1 << 4) | (1 << 5) | (1 << 7) | (1 << 8);
+          expect_tags |= (1 << 7) | (1 << 8);
         }
       }
 
@@ -360,8 +369,8 @@
         GPR_ASSERT(fixture->cq()->Next(&t, &ok));
         while ((int)(intptr_t)t != 0) {
           int i = (int)(intptr_t)t;
-          GPR_ASSERT(need_tags & (1 << i));
-          need_tags &= ~(1 << i);
+          GPR_ASSERT(expect_tags & (1 << i));
+          expect_tags &= ~(1 << i);
           GPR_ASSERT(fixture->cq()->Next(&t, &ok));
         }
         response_rw.Finish(Status::OK, tag(7));
@@ -374,11 +383,11 @@
       Status recv_status;
       request_rw->Finish(&recv_status, tag(8));
 
-      while (need_tags) {
+      while (expect_tags) {
         GPR_ASSERT(fixture->cq()->Next(&t, &ok));
         int i = (int)(intptr_t)t;
-        GPR_ASSERT(need_tags & (1 << i));
-        need_tags &= ~(1 << i);
+        GPR_ASSERT(expect_tags & (1 << i));
+        expect_tags &= ~(1 << i);
       }
 
       GPR_ASSERT(recv_status.ok());
diff --git a/tools/gce/create_windows_debug_worker.sh b/tools/gce/create_windows_debug_worker.sh
new file mode 100755
index 0000000..b56c8d9
--- /dev/null
+++ b/tools/gce/create_windows_debug_worker.sh
@@ -0,0 +1,44 @@
+#!/bin/bash
+# Copyright 2017 gRPC authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Creates a worker for debugging/experiments.
+# The worker will have all the prerequisites that are installed on kokoro
+# windows workers.
+
+set -ex
+
+cd $(dirname $0)
+
+CLOUD_PROJECT=grpc-testing
+ZONE=us-central1-b
+
+if [ "$1" != "" ]
+then
+  INSTANCE_NAME="$1"
+else
+  INSTANCE_NAME="${USER}-windows-kokoro-debug1"
+fi
+
+MACHINE_TYPE=n1-standard-8
+
+gcloud compute instances create $INSTANCE_NAME \
+    --project="$CLOUD_PROJECT" \
+    --zone "$ZONE" \
+    --machine-type $MACHINE_TYPE \
+    --image-project google.com:kokoro \
+    --image kokoro-win7build-v9-prod-debug \
+    --boot-disk-size 500 \
+    --boot-disk-type pd-ssd \
+    --tags=allow-ssh