Merge pull request #13246 from yashykt/testlinkage1

Remove grpc_slice_buf_cmp and change public_headers_must_be_c89 to pr…
diff --git a/src/core/ext/filters/client_channel/client_channel.cc b/src/core/ext/filters/client_channel/client_channel.cc
index 00c51ba..9eae6e0 100644
--- a/src/core/ext/filters/client_channel/client_channel.cc
+++ b/src/core/ext/filters/client_channel/client_channel.cc
@@ -88,7 +88,12 @@
   }
 }
 
-static void method_parameters_free(grpc_exec_ctx *exec_ctx, void *value) {
+// Wrappers to pass to grpc_service_config_create_method_config_table().
+static void *method_parameters_ref_wrapper(void *value) {
+  return method_parameters_ref((method_parameters *)value);
+}
+static void method_parameters_unref_wrapper(grpc_exec_ctx *exec_ctx,
+                                            void *value) {
   method_parameters_unref((method_parameters *)value);
 }
 
@@ -117,24 +122,16 @@
       gpr_free(buf);
       return false;
     }
-    // There should always be exactly 3, 6, or 9 fractional digits.
-    int multiplier = 1;
-    switch (strlen(decimal_point + 1)) {
-      case 9:
-        break;
-      case 6:
-        multiplier *= 1000;
-        break;
-      case 3:
-        multiplier *= 1000000;
-        break;
-      default:  // Unsupported number of digits.
-        gpr_free(buf);
-        return false;
+    int num_digits = (int)strlen(decimal_point + 1);
+    if (num_digits > 9) {  // We don't accept greater precision than nanos.
+      gpr_free(buf);
+      return false;
     }
-    nanos *= multiplier;
+    for (int i = 0; i < (9 - num_digits); ++i) {
+      nanos *= 10;
+    }
   }
-  int seconds = gpr_parse_nonnegative_int(buf);
+  int seconds = decimal_point == buf ? 0 : gpr_parse_nonnegative_int(buf);
   gpr_free(buf);
   if (seconds == -1) return false;
   *timeout = seconds * GPR_MS_PER_SEC + nanos / GPR_NS_PER_MS;
@@ -473,7 +470,7 @@
         retry_throttle_data = parsing_state.retry_throttle_data;
         method_params_table = grpc_service_config_create_method_config_table(
             exec_ctx, service_config, method_parameters_create_from_json,
-            method_parameters_free);
+            method_parameters_ref_wrapper, method_parameters_unref_wrapper);
         grpc_service_config_destroy(service_config);
       }
     }
diff --git a/src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb.cc b/src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb.cc
index 85e76e6..03116b4 100644
--- a/src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb.cc
+++ b/src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb.cc
@@ -1266,7 +1266,8 @@
   } else if (!glb_policy->shutting_down) {
     /* if we aren't shutting down, restart the LB client call after some time */
     grpc_millis next_try =
-        grpc_backoff_step(exec_ctx, &glb_policy->lb_call_backoff_state);
+        grpc_backoff_step(exec_ctx, &glb_policy->lb_call_backoff_state)
+            .next_attempt_start_time;
     if (GRPC_TRACER_ON(grpc_lb_glb_trace)) {
       gpr_log(GPR_DEBUG, "Connection to LB server lost (grpclb: %p)...",
               (void *)glb_policy);
@@ -1431,7 +1432,7 @@
                     grpc_combiner_scheduler(glb_policy->base.combiner));
 
   grpc_backoff_init(&glb_policy->lb_call_backoff_state,
-                    GRPC_GRPCLB_INITIAL_CONNECT_BACKOFF_SECONDS,
+                    GRPC_GRPCLB_INITIAL_CONNECT_BACKOFF_SECONDS * 1000,
                     GRPC_GRPCLB_RECONNECT_BACKOFF_MULTIPLIER,
                     GRPC_GRPCLB_RECONNECT_JITTER,
                     GRPC_GRPCLB_MIN_CONNECT_TIMEOUT_SECONDS * 1000,
diff --git a/src/core/ext/filters/client_channel/resolver/dns/c_ares/dns_resolver_ares.cc b/src/core/ext/filters/client_channel/resolver/dns/c_ares/dns_resolver_ares.cc
index 5f7ab98..a1ddaee 100644
--- a/src/core/ext/filters/client_channel/resolver/dns/c_ares/dns_resolver_ares.cc
+++ b/src/core/ext/filters/client_channel/resolver/dns/c_ares/dns_resolver_ares.cc
@@ -271,7 +271,8 @@
   } else {
     const char *msg = grpc_error_string(error);
     gpr_log(GPR_DEBUG, "dns resolution failed: %s", msg);
-    grpc_millis next_try = grpc_backoff_step(exec_ctx, &r->backoff_state);
+    grpc_millis next_try =
+        grpc_backoff_step(exec_ctx, &r->backoff_state).next_attempt_start_time;
     grpc_millis timeout = next_try - grpc_exec_ctx_now(exec_ctx);
     gpr_log(GPR_INFO, "dns resolution failed (will retry): %s",
             grpc_error_string(error));
@@ -379,11 +380,11 @@
     grpc_pollset_set_add_pollset_set(exec_ctx, r->interested_parties,
                                      args->pollset_set);
   }
-  grpc_backoff_init(&r->backoff_state, GRPC_DNS_INITIAL_CONNECT_BACKOFF_SECONDS,
-                    GRPC_DNS_RECONNECT_BACKOFF_MULTIPLIER,
-                    GRPC_DNS_RECONNECT_JITTER,
-                    GRPC_DNS_MIN_CONNECT_TIMEOUT_SECONDS * 1000,
-                    GRPC_DNS_RECONNECT_MAX_BACKOFF_SECONDS * 1000);
+  grpc_backoff_init(
+      &r->backoff_state, GRPC_DNS_INITIAL_CONNECT_BACKOFF_SECONDS * 1000,
+      GRPC_DNS_RECONNECT_BACKOFF_MULTIPLIER, GRPC_DNS_RECONNECT_JITTER,
+      GRPC_DNS_MIN_CONNECT_TIMEOUT_SECONDS * 1000,
+      GRPC_DNS_RECONNECT_MAX_BACKOFF_SECONDS * 1000);
   GRPC_CLOSURE_INIT(&r->dns_ares_on_retry_timer_locked,
                     dns_ares_on_retry_timer_locked, r,
                     grpc_combiner_scheduler(r->base.combiner));
diff --git a/src/core/ext/filters/client_channel/resolver/dns/native/dns_resolver.cc b/src/core/ext/filters/client_channel/resolver/dns/native/dns_resolver.cc
index e669b6d..62aead5 100644
--- a/src/core/ext/filters/client_channel/resolver/dns/native/dns_resolver.cc
+++ b/src/core/ext/filters/client_channel/resolver/dns/native/dns_resolver.cc
@@ -170,7 +170,8 @@
     grpc_resolved_addresses_destroy(r->addresses);
     grpc_lb_addresses_destroy(exec_ctx, addresses);
   } else {
-    grpc_millis next_try = grpc_backoff_step(exec_ctx, &r->backoff_state);
+    grpc_millis next_try =
+        grpc_backoff_step(exec_ctx, &r->backoff_state).next_attempt_start_time;
     grpc_millis timeout = next_try - grpc_exec_ctx_now(exec_ctx);
     gpr_log(GPR_INFO, "dns resolution failed (will retry): %s",
             grpc_error_string(error));
@@ -256,11 +257,11 @@
     grpc_pollset_set_add_pollset_set(exec_ctx, r->interested_parties,
                                      args->pollset_set);
   }
-  grpc_backoff_init(&r->backoff_state, GRPC_DNS_INITIAL_CONNECT_BACKOFF_SECONDS,
-                    GRPC_DNS_RECONNECT_BACKOFF_MULTIPLIER,
-                    GRPC_DNS_RECONNECT_JITTER,
-                    GRPC_DNS_MIN_CONNECT_TIMEOUT_SECONDS * 1000,
-                    GRPC_DNS_RECONNECT_MAX_BACKOFF_SECONDS * 1000);
+  grpc_backoff_init(
+      &r->backoff_state, GRPC_DNS_INITIAL_CONNECT_BACKOFF_SECONDS * 1000,
+      GRPC_DNS_RECONNECT_BACKOFF_MULTIPLIER, GRPC_DNS_RECONNECT_JITTER,
+      GRPC_DNS_MIN_CONNECT_TIMEOUT_SECONDS * 1000,
+      GRPC_DNS_RECONNECT_MAX_BACKOFF_SECONDS * 1000);
   return &r->base;
 }
 
diff --git a/src/core/ext/filters/client_channel/subchannel.cc b/src/core/ext/filters/client_channel/subchannel.cc
index 5710a22..b954e1b 100644
--- a/src/core/ext/filters/client_channel/subchannel.cc
+++ b/src/core/ext/filters/client_channel/subchannel.cc
@@ -117,10 +117,10 @@
 
   external_state_watcher root_external_state_watcher;
 
-  /** next connect attempt time */
-  grpc_millis next_attempt;
   /** backoff state */
   grpc_backoff backoff_state;
+  grpc_backoff_result backoff_result;
+
   /** do we have an active alarm? */
   bool have_alarm;
   /** have we started the backoff loop */
@@ -380,7 +380,7 @@
   grpc_connect_in_args args;
 
   args.interested_parties = c->pollset_set;
-  args.deadline = c->next_attempt;
+  args.deadline = c->backoff_result.current_deadline;
   args.channel_args = c->args;
 
   grpc_connectivity_state_set(exec_ctx, &c->state_tracker,
@@ -428,7 +428,7 @@
   }
   if (error == GRPC_ERROR_NONE) {
     gpr_log(GPR_INFO, "Failed to connect to channel, retrying");
-    c->next_attempt = grpc_backoff_step(exec_ctx, &c->backoff_state);
+    c->backoff_result = grpc_backoff_step(exec_ctx, &c->backoff_state);
     continue_connect_locked(exec_ctx, c);
     gpr_mu_unlock(&c->mu);
   } else {
@@ -465,20 +465,21 @@
 
   if (!c->backoff_begun) {
     c->backoff_begun = true;
-    c->next_attempt = grpc_backoff_begin(exec_ctx, &c->backoff_state);
+    c->backoff_result = grpc_backoff_begin(exec_ctx, &c->backoff_state);
     continue_connect_locked(exec_ctx, c);
   } else {
     GPR_ASSERT(!c->have_alarm);
     c->have_alarm = true;
     const grpc_millis time_til_next =
-        c->next_attempt - grpc_exec_ctx_now(exec_ctx);
+        c->backoff_result.next_attempt_start_time - grpc_exec_ctx_now(exec_ctx);
     if (time_til_next <= 0) {
       gpr_log(GPR_INFO, "Retry immediately");
     } else {
       gpr_log(GPR_INFO, "Retry in %" PRIdPTR " milliseconds", time_til_next);
     }
     GRPC_CLOSURE_INIT(&c->on_alarm, on_alarm, c, grpc_schedule_on_exec_ctx);
-    grpc_timer_init(exec_ctx, &c->alarm, c->next_attempt, &c->on_alarm);
+    grpc_timer_init(exec_ctx, &c->alarm,
+                    c->backoff_result.next_attempt_start_time, &c->on_alarm);
   }
 }
 
diff --git a/src/core/ext/filters/message_size/message_size_filter.cc b/src/core/ext/filters/message_size/message_size_filter.cc
index 5dc131b..9376d97 100644
--- a/src/core/ext/filters/message_size/message_size_filter.cc
+++ b/src/core/ext/filters/message_size/message_size_filter.cc
@@ -30,16 +30,34 @@
 #include "src/core/lib/surface/channel_init.h"
 #include "src/core/lib/transport/service_config.h"
 
-typedef struct message_size_limits {
+typedef struct {
   int max_send_size;
   int max_recv_size;
 } message_size_limits;
 
-static void message_size_limits_free(grpc_exec_ctx* exec_ctx, void* value) {
-  gpr_free(value);
+typedef struct {
+  gpr_refcount refs;
+  message_size_limits limits;
+} refcounted_message_size_limits;
+
+static void* refcounted_message_size_limits_ref(void* value) {
+  refcounted_message_size_limits* limits =
+      (refcounted_message_size_limits*)value;
+  gpr_ref(&limits->refs);
+  return value;
 }
 
-static void* message_size_limits_create_from_json(const grpc_json* json) {
+static void refcounted_message_size_limits_unref(grpc_exec_ctx* exec_ctx,
+                                                 void* value) {
+  refcounted_message_size_limits* limits =
+      (refcounted_message_size_limits*)value;
+  if (gpr_unref(&limits->refs)) {
+    gpr_free(value);
+  }
+}
+
+static void* refcounted_message_size_limits_create_from_json(
+    const grpc_json* json) {
   int max_request_message_bytes = -1;
   int max_response_message_bytes = -1;
   for (grpc_json* field = json->child; field != NULL; field = field->next) {
@@ -60,10 +78,12 @@
       if (max_response_message_bytes == -1) return NULL;
     }
   }
-  message_size_limits* value =
-      (message_size_limits*)gpr_malloc(sizeof(message_size_limits));
-  value->max_send_size = max_request_message_bytes;
-  value->max_recv_size = max_response_message_bytes;
+  refcounted_message_size_limits* value =
+      (refcounted_message_size_limits*)gpr_malloc(
+          sizeof(refcounted_message_size_limits));
+  gpr_ref_init(&value->refs, 1);
+  value->limits.max_send_size = max_request_message_bytes;
+  value->limits.max_recv_size = max_response_message_bytes;
   return value;
 }
 
@@ -82,7 +102,7 @@
 
 typedef struct channel_data {
   message_size_limits limits;
-  // Maps path names to message_size_limits structs.
+  // Maps path names to refcounted_message_size_limits structs.
   grpc_slice_hash_table* method_limit_table;
 } channel_data;
 
@@ -164,19 +184,19 @@
   // size to the receive limit.
   calld->limits = chand->limits;
   if (chand->method_limit_table != NULL) {
-    message_size_limits* limits =
-        (message_size_limits*)grpc_method_config_table_get(
+    refcounted_message_size_limits* limits =
+        (refcounted_message_size_limits*)grpc_method_config_table_get(
             exec_ctx, chand->method_limit_table, args->path);
     if (limits != NULL) {
-      if (limits->max_send_size >= 0 &&
-          (limits->max_send_size < calld->limits.max_send_size ||
+      if (limits->limits.max_send_size >= 0 &&
+          (limits->limits.max_send_size < calld->limits.max_send_size ||
            calld->limits.max_send_size < 0)) {
-        calld->limits.max_send_size = limits->max_send_size;
+        calld->limits.max_send_size = limits->limits.max_send_size;
       }
-      if (limits->max_recv_size >= 0 &&
-          (limits->max_recv_size < calld->limits.max_recv_size ||
+      if (limits->limits.max_recv_size >= 0 &&
+          (limits->limits.max_recv_size < calld->limits.max_recv_size ||
            calld->limits.max_recv_size < 0)) {
-        calld->limits.max_recv_size = limits->max_recv_size;
+        calld->limits.max_recv_size = limits->limits.max_recv_size;
       }
     }
   }
@@ -237,8 +257,10 @@
     if (service_config != NULL) {
       chand->method_limit_table =
           grpc_service_config_create_method_config_table(
-              exec_ctx, service_config, message_size_limits_create_from_json,
-              message_size_limits_free);
+              exec_ctx, service_config,
+              refcounted_message_size_limits_create_from_json,
+              refcounted_message_size_limits_ref,
+              refcounted_message_size_limits_unref);
       grpc_service_config_destroy(service_config);
     }
   }
diff --git a/src/core/lib/backoff/backoff.cc b/src/core/lib/backoff/backoff.cc
index fe0a751..5dd91da 100644
--- a/src/core/lib/backoff/backoff.cc
+++ b/src/core/lib/backoff/backoff.cc
@@ -20,23 +20,27 @@
 
 #include <grpc/support/useful.h>
 
-void grpc_backoff_init(grpc_backoff *backoff,
-                       grpc_millis initial_connect_timeout, double multiplier,
-                       double jitter, grpc_millis min_timeout_millis,
-                       grpc_millis max_timeout_millis) {
-  backoff->initial_connect_timeout = initial_connect_timeout;
+void grpc_backoff_init(grpc_backoff *backoff, grpc_millis initial_backoff,
+                       double multiplier, double jitter,
+                       grpc_millis min_connect_timeout,
+                       grpc_millis max_backoff) {
+  backoff->initial_backoff = initial_backoff;
   backoff->multiplier = multiplier;
   backoff->jitter = jitter;
-  backoff->min_timeout_millis = min_timeout_millis;
-  backoff->max_timeout_millis = max_timeout_millis;
+  backoff->min_connect_timeout = min_connect_timeout;
+  backoff->max_backoff = max_backoff;
   backoff->rng_state = (uint32_t)gpr_now(GPR_CLOCK_REALTIME).tv_nsec;
 }
 
-grpc_millis grpc_backoff_begin(grpc_exec_ctx *exec_ctx, grpc_backoff *backoff) {
-  backoff->current_timeout_millis = backoff->initial_connect_timeout;
-  const grpc_millis first_timeout =
-      GPR_MAX(backoff->current_timeout_millis, backoff->min_timeout_millis);
-  return grpc_exec_ctx_now(exec_ctx) + first_timeout;
+grpc_backoff_result grpc_backoff_begin(grpc_exec_ctx *exec_ctx,
+                                       grpc_backoff *backoff) {
+  backoff->current_backoff = backoff->initial_backoff;
+  const grpc_millis initial_timeout =
+      GPR_MAX(backoff->initial_backoff, backoff->min_connect_timeout);
+  const grpc_millis now = grpc_exec_ctx_now(exec_ctx);
+  const grpc_backoff_result result = {now + initial_timeout,
+                                      now + backoff->current_backoff};
+  return result;
 }
 
 /* Generate a random number between 0 and 1. */
@@ -45,29 +49,32 @@
   return *rng_state / (double)((uint32_t)1 << 31);
 }
 
-grpc_millis grpc_backoff_step(grpc_exec_ctx *exec_ctx, grpc_backoff *backoff) {
-  const double new_timeout_millis =
-      backoff->multiplier * (double)backoff->current_timeout_millis;
-  backoff->current_timeout_millis =
-      GPR_MIN((grpc_millis)new_timeout_millis, backoff->max_timeout_millis);
+static double generate_uniform_random_number_between(uint32_t *rng_state,
+                                                     double a, double b) {
+  if (a == b) return a;
+  if (a > b) GPR_SWAP(double, a, b);  // make sure a < b
+  const double range = b - a;
+  return a + generate_uniform_random_number(rng_state) * range;
+}
 
-  const double jitter_range_width = backoff->jitter * new_timeout_millis;
-  const double jitter =
-      (2 * generate_uniform_random_number(&backoff->rng_state) - 1) *
-      jitter_range_width;
-
-  backoff->current_timeout_millis =
-      (grpc_millis)((double)(backoff->current_timeout_millis) + jitter);
-
-  const grpc_millis current_deadline =
-      grpc_exec_ctx_now(exec_ctx) + backoff->current_timeout_millis;
-
-  const grpc_millis min_deadline =
-      grpc_exec_ctx_now(exec_ctx) + backoff->min_timeout_millis;
-
-  return GPR_MAX(current_deadline, min_deadline);
+grpc_backoff_result grpc_backoff_step(grpc_exec_ctx *exec_ctx,
+                                      grpc_backoff *backoff) {
+  backoff->current_backoff = (grpc_millis)(GPR_MIN(
+      backoff->current_backoff * backoff->multiplier, backoff->max_backoff));
+  const double jitter = generate_uniform_random_number_between(
+      &backoff->rng_state, -backoff->jitter * backoff->current_backoff,
+      backoff->jitter * backoff->current_backoff);
+  const grpc_millis current_timeout =
+      GPR_MAX((grpc_millis)(backoff->current_backoff + jitter),
+              backoff->min_connect_timeout);
+  const grpc_millis next_timeout = GPR_MIN(
+      (grpc_millis)(backoff->current_backoff + jitter), backoff->max_backoff);
+  const grpc_millis now = grpc_exec_ctx_now(exec_ctx);
+  const grpc_backoff_result result = {now + current_timeout,
+                                      now + next_timeout};
+  return result;
 }
 
 void grpc_backoff_reset(grpc_backoff *backoff) {
-  backoff->current_timeout_millis = backoff->initial_connect_timeout;
+  backoff->current_backoff = backoff->initial_backoff;
 }
diff --git a/src/core/lib/backoff/backoff.h b/src/core/lib/backoff/backoff.h
index 80e49ea..8becf4a 100644
--- a/src/core/lib/backoff/backoff.h
+++ b/src/core/lib/backoff/backoff.h
@@ -27,36 +27,53 @@
 
 typedef struct {
   /// const:  how long to wait after the first failure before retrying
-  grpc_millis initial_connect_timeout;
+  grpc_millis initial_backoff;
+
   /// const: factor with which to multiply backoff after a failed retry
   double multiplier;
+
   /// const: amount to randomize backoffs
   double jitter;
-  /// const: minimum time between retries in milliseconds
-  grpc_millis min_timeout_millis;
-  /// const: maximum time between retries in milliseconds
-  grpc_millis max_timeout_millis;
+
+  /// const: minimum time between retries
+  grpc_millis min_connect_timeout;
+
+  /// const: maximum time between retries
+  grpc_millis max_backoff;
+
+  /// current delay before retries
+  grpc_millis current_backoff;
 
   /// random number generator
   uint32_t rng_state;
-
-  /// current retry timeout in milliseconds
-  grpc_millis current_timeout_millis;
 } grpc_backoff;
 
-/// Initialize backoff machinery - does not need to be destroyed
-void grpc_backoff_init(grpc_backoff *backoff,
-                       grpc_millis initial_connect_timeout, double multiplier,
-                       double jitter, grpc_millis min_timeout_millis,
-                       grpc_millis max_timeout_millis);
+typedef struct {
+  /// Deadline to be used for the current attempt.
+  grpc_millis current_deadline;
 
-/// Begin retry loop: returns a timespec for the NEXT retry
-grpc_millis grpc_backoff_begin(grpc_exec_ctx *exec_ctx, grpc_backoff *backoff);
-/// Step a retry loop: returns a timespec for the NEXT retry
-grpc_millis grpc_backoff_step(grpc_exec_ctx *exec_ctx, grpc_backoff *backoff);
+  /// Deadline to be used for the next attempt, following the backoff strategy.
+  grpc_millis next_attempt_start_time;
+} grpc_backoff_result;
+
+/// Initialize backoff machinery - does not need to be destroyed
+void grpc_backoff_init(grpc_backoff *backoff, grpc_millis initial_backoff,
+                       double multiplier, double jitter,
+                       grpc_millis min_connect_timeout,
+                       grpc_millis max_backoff);
+
+/// Begin retry loop: returns the deadlines to be used for the current attempt
+/// and the subsequent retry, if any.
+grpc_backoff_result grpc_backoff_begin(grpc_exec_ctx *exec_ctx,
+                                       grpc_backoff *backoff);
+
+/// Step a retry loop: returns the deadlines to be used for the current attempt
+/// and the subsequent retry, if any.
+grpc_backoff_result grpc_backoff_step(grpc_exec_ctx *exec_ctx,
+                                      grpc_backoff *backoff);
+
 /// Reset the backoff, so the next grpc_backoff_step will be a
-/// grpc_backoff_begin
-/// instead
+/// grpc_backoff_begin.
 void grpc_backoff_reset(grpc_backoff *backoff);
 
 #ifdef __cplusplus
diff --git a/src/core/lib/iomgr/pollset_windows.cc b/src/core/lib/iomgr/pollset_windows.cc
index bb4df83..01aff02 100644
--- a/src/core/lib/iomgr/pollset_windows.cc
+++ b/src/core/lib/iomgr/pollset_windows.cc
@@ -161,8 +161,10 @@
     while (!worker.kicked) {
       if (gpr_cv_wait(&worker.cv, &grpc_polling_mu,
                       grpc_millis_to_timespec(deadline, GPR_CLOCK_REALTIME))) {
+        grpc_exec_ctx_invalidate_now(exec_ctx);
         break;
       }
+      grpc_exec_ctx_invalidate_now(exec_ctx);
     }
   } else {
     pollset->kicked_without_pollers = 0;
diff --git a/src/core/lib/transport/service_config.cc b/src/core/lib/transport/service_config.cc
index 070a13a..05907de 100644
--- a/src/core/lib/transport/service_config.cc
+++ b/src/core/lib/transport/service_config.cc
@@ -111,7 +111,13 @@
 static size_t count_names_in_method_config_json(grpc_json* json) {
   size_t num_names = 0;
   for (grpc_json* field = json->child; field != NULL; field = field->next) {
-    if (field->key != NULL && strcmp(field->key, "name") == 0) ++num_names;
+    if (field->key != NULL && strcmp(field->key, "name") == 0) {
+      if (field->type != GRPC_JSON_ARRAY) return -1;
+      for (grpc_json* name = field->child; name != NULL; name = name->next) {
+        if (name->type != GRPC_JSON_OBJECT) return -1;
+        ++num_names;
+      }
+    }
   }
   return num_names;
 }
@@ -148,6 +154,8 @@
 static bool parse_json_method_config(
     grpc_exec_ctx* exec_ctx, grpc_json* json,
     void* (*create_value)(const grpc_json* method_config_json),
+    void* (*ref_value)(void* value),
+    void (*unref_value)(grpc_exec_ctx* exec_ctx, void* value),
     grpc_slice_hash_table_entry* entries, size_t* idx) {
   // Construct value.
   void* method_config = create_value(json);
@@ -162,6 +170,7 @@
       if (child->type != GRPC_JSON_ARRAY) goto done;
       for (grpc_json* name = child->child; name != NULL; name = name->next) {
         char* path = parse_json_method_name(name);
+        if (path == NULL) goto done;
         gpr_strvec_add(&paths, path);
       }
     }
@@ -170,11 +179,12 @@
   // Add entry for each path.
   for (size_t i = 0; i < paths.count; ++i) {
     entries[*idx].key = grpc_slice_from_copied_string(paths.strs[i]);
-    entries[*idx].value = method_config;
+    entries[*idx].value = ref_value(method_config);
     ++*idx;
   }
   success = true;
 done:
+  unref_value(exec_ctx, method_config);
   gpr_strvec_destroy(&paths);
   return success;
 }
@@ -182,7 +192,8 @@
 grpc_slice_hash_table* grpc_service_config_create_method_config_table(
     grpc_exec_ctx* exec_ctx, const grpc_service_config* service_config,
     void* (*create_value)(const grpc_json* method_config_json),
-    void (*destroy_value)(grpc_exec_ctx* exec_ctx, void* value)) {
+    void* (*ref_value)(void* value),
+    void (*unref_value)(grpc_exec_ctx* exec_ctx, void* value)) {
   const grpc_json* json = service_config->json_tree;
   // Traverse parsed JSON tree.
   if (json->type != GRPC_JSON_OBJECT || json->key != NULL) return NULL;
@@ -196,7 +207,9 @@
       // Find number of entries.
       for (grpc_json* method = field->child; method != NULL;
            method = method->next) {
-        num_entries += count_names_in_method_config_json(method);
+        size_t count = count_names_in_method_config_json(method);
+        if (count <= 0) return NULL;
+        num_entries += count;
       }
       // Populate method config table entries.
       entries = (grpc_slice_hash_table_entry*)gpr_malloc(
@@ -204,8 +217,13 @@
       size_t idx = 0;
       for (grpc_json* method = field->child; method != NULL;
            method = method->next) {
-        if (!parse_json_method_config(exec_ctx, method, create_value, entries,
-                                      &idx)) {
+        if (!parse_json_method_config(exec_ctx, method, create_value, ref_value,
+                                      unref_value, entries, &idx)) {
+          for (size_t i = 0; i < idx; ++i) {
+            grpc_slice_unref_internal(exec_ctx, entries[i].key);
+            unref_value(exec_ctx, entries[i].value);
+          }
+          gpr_free(entries);
           return NULL;
         }
       }
@@ -216,7 +234,7 @@
   grpc_slice_hash_table* method_config_table = NULL;
   if (entries != NULL) {
     method_config_table =
-        grpc_slice_hash_table_create(num_entries, entries, destroy_value, NULL);
+        grpc_slice_hash_table_create(num_entries, entries, unref_value, NULL);
     gpr_free(entries);
   }
   return method_config_table;
diff --git a/src/core/lib/transport/service_config.h b/src/core/lib/transport/service_config.h
index 9c43093..405d0f5 100644
--- a/src/core/lib/transport/service_config.h
+++ b/src/core/lib/transport/service_config.h
@@ -46,12 +46,13 @@
 /// Creates a method config table based on the data in \a json.
 /// The table's keys are request paths.  The table's value type is
 /// returned by \a create_value(), based on data parsed from the JSON tree.
-/// \a destroy_value is used to clean up values.
+/// \a ref_value() and \a unref_value() are used to ref and unref values.
 /// Returns NULL on error.
 grpc_slice_hash_table* grpc_service_config_create_method_config_table(
     grpc_exec_ctx* exec_ctx, const grpc_service_config* service_config,
     void* (*create_value)(const grpc_json* method_config_json),
-    void (*destroy_value)(grpc_exec_ctx* exec_ctx, void* value));
+    void* (*ref_value)(void* value),
+    void (*unref_value)(grpc_exec_ctx* exec_ctx, void* value));
 
 /// A helper function for looking up values in the table returned by
 /// \a grpc_service_config_create_method_config_table().
diff --git a/test/core/backoff/backoff_test.c b/test/core/backoff/backoff_test.c
index a29cce6..e80e0b3 100644
--- a/test/core/backoff/backoff_test.c
+++ b/test/core/backoff/backoff_test.c
@@ -19,120 +19,157 @@
 #include "src/core/lib/backoff/backoff.h"
 
 #include <grpc/support/log.h>
+#include <grpc/support/useful.h>
 
 #include "test/core/util/test_config.h"
 
 static void test_constant_backoff(void) {
   grpc_backoff backoff;
-  grpc_backoff_init(&backoff, 200 /* initial timeout */, 1.0 /* multiplier */,
-                    0.0 /* jitter */, 100 /* min timeout */,
-                    1000 /* max timeout */);
-
+  const grpc_millis initial_backoff = 200;
+  const double multiplier = 1.0;
+  const double jitter = 0.0;
+  const grpc_millis min_connect_timeout = 100;
+  const grpc_millis max_backoff = 1000;
+  grpc_backoff_init(&backoff, initial_backoff, multiplier, jitter,
+                    min_connect_timeout, max_backoff);
   grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
-  grpc_millis next = grpc_backoff_begin(&exec_ctx, &backoff);
-  GPR_ASSERT(next - grpc_exec_ctx_now(&exec_ctx) == 200);
+  grpc_backoff_result next_deadlines = grpc_backoff_begin(&exec_ctx, &backoff);
+  GPR_ASSERT(next_deadlines.current_deadline - grpc_exec_ctx_now(&exec_ctx) ==
+             initial_backoff);
+  GPR_ASSERT(next_deadlines.next_attempt_start_time -
+                 grpc_exec_ctx_now(&exec_ctx) ==
+             initial_backoff);
   for (int i = 0; i < 10000; i++) {
-    next = grpc_backoff_step(&exec_ctx, &backoff);
-    GPR_ASSERT(next - grpc_exec_ctx_now(&exec_ctx) == 200);
-    exec_ctx.now = next;
+    next_deadlines = grpc_backoff_step(&exec_ctx, &backoff);
+    GPR_ASSERT(next_deadlines.current_deadline - grpc_exec_ctx_now(&exec_ctx) ==
+               initial_backoff);
+    GPR_ASSERT(next_deadlines.next_attempt_start_time -
+                   grpc_exec_ctx_now(&exec_ctx) ==
+               initial_backoff);
+    exec_ctx.now = next_deadlines.current_deadline;
   }
   grpc_exec_ctx_finish(&exec_ctx);
 }
 
 static void test_min_connect(void) {
   grpc_backoff backoff;
-  grpc_backoff_init(&backoff, 100 /* initial timeout */, 1.0 /* multiplier */,
-                    0.0 /* jitter */, 200 /* min timeout */,
-                    1000 /* max timeout */);
-
+  const grpc_millis initial_backoff = 100;
+  const double multiplier = 1.0;
+  const double jitter = 0.0;
+  const grpc_millis min_connect_timeout = 200;
+  const grpc_millis max_backoff = 1000;
+  grpc_backoff_init(&backoff, initial_backoff, multiplier, jitter,
+                    min_connect_timeout, max_backoff);
   grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
-  grpc_millis next = grpc_backoff_begin(&exec_ctx, &backoff);
-  GPR_ASSERT(next - grpc_exec_ctx_now(&exec_ctx) == 200);
+  grpc_backoff_result next = grpc_backoff_begin(&exec_ctx, &backoff);
+  // Because the min_connect_timeout > initial_backoff, current_deadline is used
+  // as the deadline for the current attempt.
+  GPR_ASSERT(next.current_deadline - grpc_exec_ctx_now(&exec_ctx) ==
+             min_connect_timeout);
+  // ... while, if the current attempt fails, the next one will happen after
+  // initial_backoff.
+  GPR_ASSERT(next.next_attempt_start_time - grpc_exec_ctx_now(&exec_ctx) ==
+             initial_backoff);
   grpc_exec_ctx_finish(&exec_ctx);
 }
 
 static void test_no_jitter_backoff(void) {
   grpc_backoff backoff;
-  grpc_backoff_init(&backoff, 2 /* initial timeout */, 2.0 /* multiplier */,
-                    0.0 /* jitter */, 1 /* min timeout */,
-                    513 /* max timeout */);
+  const grpc_millis initial_backoff = 2;
+  const double multiplier = 2.0;
+  const double jitter = 0.0;
+  const grpc_millis min_connect_timeout = 1;
+  const grpc_millis max_backoff = 513;
+  grpc_backoff_init(&backoff, initial_backoff, multiplier, jitter,
+                    min_connect_timeout, max_backoff);
   // x_1 = 2
   // x_n = 2**i + x_{i-1} ( = 2**(n+1) - 2 )
   grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
   exec_ctx.now = 0;
   exec_ctx.now_is_valid = true;
-  grpc_millis next = grpc_backoff_begin(&exec_ctx, &backoff);
-  GPR_ASSERT(next == 2);
-  exec_ctx.now = next;
-  next = grpc_backoff_step(&exec_ctx, &backoff);
-  GPR_ASSERT(next == 6);
-  exec_ctx.now = next;
-  next = grpc_backoff_step(&exec_ctx, &backoff);
-  GPR_ASSERT(next == 14);
-  exec_ctx.now = next;
-  next = grpc_backoff_step(&exec_ctx, &backoff);
-  GPR_ASSERT(next == 30);
-  exec_ctx.now = next;
-  next = grpc_backoff_step(&exec_ctx, &backoff);
-  GPR_ASSERT(next == 62);
-  exec_ctx.now = next;
-  next = grpc_backoff_step(&exec_ctx, &backoff);
-  GPR_ASSERT(next == 126);
-  exec_ctx.now = next;
-  next = grpc_backoff_step(&exec_ctx, &backoff);
-  GPR_ASSERT(next == 254);
-  exec_ctx.now = next;
-  next = grpc_backoff_step(&exec_ctx, &backoff);
-  GPR_ASSERT(next == 510);
-  exec_ctx.now = next;
-  next = grpc_backoff_step(&exec_ctx, &backoff);
-  GPR_ASSERT(next == 1022);
-  exec_ctx.now = next;
-  next = grpc_backoff_step(&exec_ctx, &backoff);
+  grpc_backoff_result next_deadlines = grpc_backoff_begin(&exec_ctx, &backoff);
+  GPR_ASSERT(next_deadlines.current_deadline ==
+             next_deadlines.next_attempt_start_time);
+  GPR_ASSERT(next_deadlines.current_deadline == 2);
+  exec_ctx.now = next_deadlines.current_deadline;
+  next_deadlines = grpc_backoff_step(&exec_ctx, &backoff);
+  GPR_ASSERT(next_deadlines.current_deadline == 6);
+  exec_ctx.now = next_deadlines.current_deadline;
+  next_deadlines = grpc_backoff_step(&exec_ctx, &backoff);
+  GPR_ASSERT(next_deadlines.current_deadline == 14);
+  exec_ctx.now = next_deadlines.current_deadline;
+  next_deadlines = grpc_backoff_step(&exec_ctx, &backoff);
+  GPR_ASSERT(next_deadlines.current_deadline == 30);
+  exec_ctx.now = next_deadlines.current_deadline;
+  next_deadlines = grpc_backoff_step(&exec_ctx, &backoff);
+  GPR_ASSERT(next_deadlines.current_deadline == 62);
+  exec_ctx.now = next_deadlines.current_deadline;
+  next_deadlines = grpc_backoff_step(&exec_ctx, &backoff);
+  GPR_ASSERT(next_deadlines.current_deadline == 126);
+  exec_ctx.now = next_deadlines.current_deadline;
+  next_deadlines = grpc_backoff_step(&exec_ctx, &backoff);
+  GPR_ASSERT(next_deadlines.current_deadline == 254);
+  exec_ctx.now = next_deadlines.current_deadline;
+  next_deadlines = grpc_backoff_step(&exec_ctx, &backoff);
+  GPR_ASSERT(next_deadlines.current_deadline == 510);
+  exec_ctx.now = next_deadlines.current_deadline;
+  next_deadlines = grpc_backoff_step(&exec_ctx, &backoff);
+  GPR_ASSERT(next_deadlines.current_deadline == 1022);
+  exec_ctx.now = next_deadlines.current_deadline;
+  next_deadlines = grpc_backoff_step(&exec_ctx, &backoff);
   // Hit the maximum timeout. From this point onwards, retries will increase
   // only by max timeout.
-  GPR_ASSERT(next == 1535);
-  exec_ctx.now = next;
-  next = grpc_backoff_step(&exec_ctx, &backoff);
-  GPR_ASSERT(next == 2048);
-  exec_ctx.now = next;
-  next = grpc_backoff_step(&exec_ctx, &backoff);
-  GPR_ASSERT(next == 2561);
+  GPR_ASSERT(next_deadlines.current_deadline == 1535);
+  exec_ctx.now = next_deadlines.current_deadline;
+  next_deadlines = grpc_backoff_step(&exec_ctx, &backoff);
+  GPR_ASSERT(next_deadlines.current_deadline == 2048);
+  exec_ctx.now = next_deadlines.current_deadline;
+  next_deadlines = grpc_backoff_step(&exec_ctx, &backoff);
+  GPR_ASSERT(next_deadlines.current_deadline == 2561);
   grpc_exec_ctx_finish(&exec_ctx);
 }
 
 static void test_jitter_backoff(void) {
-  const int64_t initial_timeout = 500;
+  const grpc_millis initial_backoff = 500;
+  grpc_millis current_backoff = initial_backoff;
+  const grpc_millis max_backoff = 1000;
+  const grpc_millis min_connect_timeout = 100;
+  const double multiplier = 1.0;
   const double jitter = 0.1;
   grpc_backoff backoff;
-  grpc_backoff_init(&backoff, (grpc_millis)initial_timeout,
-                    1.0 /* multiplier */, jitter, 100 /* min timeout */,
-                    1000 /* max timeout */);
+  grpc_backoff_init(&backoff, initial_backoff, multiplier, jitter,
+                    min_connect_timeout, max_backoff);
 
   backoff.rng_state = 0;  // force consistent PRNG
 
   grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
-  grpc_millis next = grpc_backoff_begin(&exec_ctx, &backoff);
-  GPR_ASSERT(next - grpc_exec_ctx_now(&exec_ctx) == 500);
+  grpc_backoff_result next_deadlines = grpc_backoff_begin(&exec_ctx, &backoff);
+  GPR_ASSERT(next_deadlines.current_deadline - grpc_exec_ctx_now(&exec_ctx) ==
+             initial_backoff);
+  GPR_ASSERT(next_deadlines.next_attempt_start_time -
+                 grpc_exec_ctx_now(&exec_ctx) ==
+             initial_backoff);
 
-  int64_t expected_next_lower_bound =
-      (int64_t)((double)initial_timeout * (1 - jitter));
-  int64_t expected_next_upper_bound =
-      (int64_t)((double)initial_timeout * (1 + jitter));
+  grpc_millis expected_next_lower_bound =
+      (grpc_millis)((double)current_backoff * (1 - jitter));
+  grpc_millis expected_next_upper_bound =
+      (grpc_millis)((double)current_backoff * (1 + jitter));
 
   for (int i = 0; i < 10000; i++) {
-    next = grpc_backoff_step(&exec_ctx, &backoff);
-
-    // next-now must be within (jitter*100)% of the previous timeout.
-    const int64_t timeout_millis = next - grpc_exec_ctx_now(&exec_ctx);
+    next_deadlines = grpc_backoff_step(&exec_ctx, &backoff);
+    // next-now must be within (jitter*100)% of the current backoff (which
+    // increases by * multiplier up to max_backoff).
+    const grpc_millis timeout_millis =
+        next_deadlines.current_deadline - grpc_exec_ctx_now(&exec_ctx);
     GPR_ASSERT(timeout_millis >= expected_next_lower_bound);
     GPR_ASSERT(timeout_millis <= expected_next_upper_bound);
-
+    current_backoff = GPR_MIN(
+        (grpc_millis)((double)current_backoff * multiplier), max_backoff);
     expected_next_lower_bound =
-        (int64_t)((double)timeout_millis * (1 - jitter));
+        (grpc_millis)((double)current_backoff * (1 - jitter));
     expected_next_upper_bound =
-        (int64_t)((double)timeout_millis * (1 + jitter));
-    exec_ctx.now = next;
+        (grpc_millis)((double)current_backoff * (1 + jitter));
+    exec_ctx.now = next_deadlines.current_deadline;
   }
   grpc_exec_ctx_finish(&exec_ctx);
 }
diff --git a/test/core/end2end/tests/cancel_after_accept.c b/test/core/end2end/tests/cancel_after_accept.c
index c3ac0c3..96262b1 100644
--- a/test/core/end2end/tests/cancel_after_accept.c
+++ b/test/core/end2end/tests/cancel_after_accept.c
@@ -130,7 +130,8 @@
         "{\n"
         "  \"methodConfig\": [ {\n"
         "    \"name\": [\n"
-        "      { \"service\": \"service\", \"method\": \"method\" }\n"
+        "      { \"service\": \"service\", \"method\": \"method\" },\n"
+        "      { \"service\": \"unused\" }\n"
         "    ],\n"
         "    \"timeout\": \"5s\"\n"
         "  } ]\n"
diff --git a/test/core/end2end/tests/max_message_length.c b/test/core/end2end/tests/max_message_length.c
index 01eb8d3..8925de9 100644
--- a/test/core/end2end/tests/max_message_length.c
+++ b/test/core/end2end/tests/max_message_length.c
@@ -138,7 +138,8 @@
             ? "{\n"
               "  \"methodConfig\": [ {\n"
               "    \"name\": [\n"
-              "      { \"service\": \"service\", \"method\": \"method\" }\n"
+              "      { \"service\": \"service\", \"method\": \"method\" },\n"
+              "      { \"service\": \"unused\" }\n"
               "    ],\n"
               "    \"maxRequestMessageBytes\": \"5\"\n"
               "  } ]\n"
diff --git a/test/cpp/microbenchmarks/fullstack_streaming_ping_pong.h b/test/cpp/microbenchmarks/fullstack_streaming_ping_pong.h
index 06d18b8..6df044f 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 expect_tags;
+      int need_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
         }
 
-        int await_tags = (1 << 2);
+        need_tags = (1 << 2) | (1 << 3) | (1 << 4) | (1 << 5);
 
         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(await_tags & (1 << i));
-            await_tags &= ~(1 << i);
+            GPR_ASSERT(need_tags & (1 << i));
+            need_tags &= ~(1 << i);
             GPR_ASSERT(fixture->cq()->Next(&t, &ok));
           }
         }
@@ -310,11 +310,7 @@
         response_rw.Read(&recv_request, tag(3));   // Start server recv
         request_rw->Read(&recv_response, tag(4));  // Start client recv
 
-        await_tags |= (1 << 3) | (1 << 4);
-        expect_tags = await_tags;
-        await_tags |= (1 << 5);
-
-        while (await_tags != 0) {
+        while (need_tags) {
           GPR_ASSERT(fixture->cq()->Next(&t, &ok));
           GPR_ASSERT(ok);
           int i = (int)(intptr_t)t;
@@ -325,39 +321,34 @@
               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 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);
+                // 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);
               }
             } else {
               response_rw.Write(send_response, tag(5));
-              expect_tags |= (1 << 5);
             }
           }
 
-          GPR_ASSERT(expect_tags & (1 << i));
-          expect_tags &= ~(1 << i);
-          await_tags &= ~(1 << i);
+          GPR_ASSERT(need_tags & (1 << i));
+          need_tags &= ~(1 << i);
         }
 
         ping_pong_cnt++;
       }
 
       if (max_ping_pongs == 0) {
-        expect_tags |= (1 << 6) | (1 << 7) | (1 << 8);
+        need_tags = (1 << 6) | (1 << 7) | (1 << 8);
       } else {
         if (write_and_finish == 1) {
-          expect_tags |= (1 << 8);
+          need_tags = (1 << 8);
         } else {
           // server's buffered write and the client's read of the buffered write
           // tags should come up.
-          expect_tags |= (1 << 7) | (1 << 8);
+          need_tags = (1 << 4) | (1 << 5) | (1 << 7) | (1 << 8);
         }
       }
 
@@ -369,8 +360,8 @@
         GPR_ASSERT(fixture->cq()->Next(&t, &ok));
         while ((int)(intptr_t)t != 0) {
           int i = (int)(intptr_t)t;
-          GPR_ASSERT(expect_tags & (1 << i));
-          expect_tags &= ~(1 << i);
+          GPR_ASSERT(need_tags & (1 << i));
+          need_tags &= ~(1 << i);
           GPR_ASSERT(fixture->cq()->Next(&t, &ok));
         }
         response_rw.Finish(Status::OK, tag(7));
@@ -383,11 +374,11 @@
       Status recv_status;
       request_rw->Finish(&recv_status, tag(8));
 
-      while (expect_tags) {
+      while (need_tags) {
         GPR_ASSERT(fixture->cq()->Next(&t, &ok));
         int i = (int)(intptr_t)t;
-        GPR_ASSERT(expect_tags & (1 << i));
-        expect_tags &= ~(1 << i);
+        GPR_ASSERT(need_tags & (1 << i));
+        need_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
index b56c8d9..da8050b 100755
--- a/tools/gce/create_windows_debug_worker.sh
+++ b/tools/gce/create_windows_debug_worker.sh
@@ -32,6 +32,17 @@
 fi
 
 MACHINE_TYPE=n1-standard-8
+TMP_DISK_NAME="$INSTANCE_NAME-temp-disk"
+
+gcloud compute disks create $TMP_DISK_NAME \
+    --project="$CLOUD_PROJECT" \
+    --zone "$ZONE" \
+    --image-project google.com:kokoro \
+    --image empty-100g-image \
+    --type pd-ssd
+
+echo 'Created scratch disk, waiting for it to become available.'
+sleep 15
 
 gcloud compute instances create $INSTANCE_NAME \
     --project="$CLOUD_PROJECT" \
@@ -41,4 +52,5 @@
     --image kokoro-win7build-v9-prod-debug \
     --boot-disk-size 500 \
     --boot-disk-type pd-ssd \
-    --tags=allow-ssh
+    --tags=allow-ssh \
+    --disk auto-delete=yes,boot=no,name=$TMP_DISK_NAME
diff --git a/tools/internal_ci/windows/grpc_basictests_dbg.cfg b/tools/internal_ci/windows/grpc_basictests_dbg.cfg
new file mode 100644
index 0000000..28d53cd
--- /dev/null
+++ b/tools/internal_ci/windows/grpc_basictests_dbg.cfg
@@ -0,0 +1,30 @@
+# 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.
+
+# Config file for the internal CI (in protobuf text format)
+
+# Location of the continuous shell script in repository.
+build_file: "grpc/tools/internal_ci/windows/grpc_run_tests_matrix.bat"
+timeout_mins: 240
+action {
+  define_artifacts {
+    regex: "**/*sponge_log.xml"
+    regex: "github/grpc/reports/**"
+  }
+}
+
+env_vars {
+  key: "RUN_TESTS_FLAGS"
+  value: "-f basictests windows dbg -j 1 --inner_jobs 8 --internal_ci --bq_result_table aggregate_results"
+}
diff --git a/tools/internal_ci/windows/grpc_basictests_opt.cfg b/tools/internal_ci/windows/grpc_basictests_opt.cfg
new file mode 100644
index 0000000..4b7a965
--- /dev/null
+++ b/tools/internal_ci/windows/grpc_basictests_opt.cfg
@@ -0,0 +1,30 @@
+# 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.
+
+# Config file for the internal CI (in protobuf text format)
+
+# Location of the continuous shell script in repository.
+build_file: "grpc/tools/internal_ci/windows/grpc_run_tests_matrix.bat"
+timeout_mins: 240
+action {
+  define_artifacts {
+    regex: "**/*sponge_log.xml"
+    regex: "github/grpc/reports/**"
+  }
+}
+
+env_vars {
+  key: "RUN_TESTS_FLAGS"
+  value: "-f basictests windows opt -j 1 --inner_jobs 8 --internal_ci --bq_result_table aggregate_results"
+}