Эх сурвалжийг харах

Merge remote-tracking branch 'upstream/master' into revert-9063-revert-8951-revert-8949-revert-8922-slice_cleanup

Mark D. Roth 8 жил өмнө
parent
commit
1311e3448c
52 өөрчлөгдсөн 638 нэмэгдсэн , 133 устгасан
  1. 29 0
      doc/cpp/perf_notes.md
  2. 3 1
      doc/interop-test-descriptions.md
  3. 4 0
      include/grpc++/grpc++.h
  4. 4 2
      include/grpc++/impl/codegen/completion_queue.h
  5. 5 0
      src/core/ext/README.md
  6. 4 1
      src/core/ext/client_channel/channel_connectivity.c
  7. 5 1
      src/core/ext/client_channel/subchannel.c
  8. 6 1
      src/core/ext/lb_policy/grpclb/grpclb.c
  9. 4 0
      src/core/ext/resolver/README.md
  10. 4 2
      src/core/ext/resolver/dns/native/dns_resolver.c
  11. 1 0
      src/core/ext/transport/README.md
  12. 1 0
      src/core/ext/transport/chttp2/README.md
  13. 6 0
      src/core/lib/README.md
  14. 4 0
      src/core/lib/channel/README.md
  15. 5 2
      src/core/lib/channel/deadline_filter.c
  16. 1 0
      src/core/lib/channel/deadline_filter.h
  17. 4 1
      src/core/lib/channel/handshaker.c
  18. 6 0
      src/core/lib/iomgr/README.md
  19. 3 1
      src/core/lib/iomgr/tcp_client_posix.c
  20. 4 1
      src/core/lib/iomgr/tcp_client_uv.c
  21. 3 1
      src/core/lib/iomgr/tcp_client_windows.c
  22. 8 8
      src/core/lib/iomgr/timer.h
  23. 7 8
      src/core/lib/iomgr/timer_generic.c
  24. 1 1
      src/core/lib/iomgr/timer_generic.h
  25. 6 7
      src/core/lib/iomgr/timer_uv.c
  26. 1 1
      src/core/lib/iomgr/timer_uv.h
  27. 4 0
      src/core/lib/surface/README.md
  28. 4 1
      src/core/lib/surface/alarm.c
  29. 7 0
      src/core/lib/transport/README.md
  30. 2 0
      src/core/lib/tsi/README.md
  31. 3 0
      src/node/interop/interop_client.js
  32. 11 0
      src/php/tests/interop/interop_client.php
  33. 11 1
      src/python/grpcio/grpc/_channel.py
  34. 8 8
      src/python/grpcio_tests/tests/reflection/_reflection_servicer_test.py
  35. 1 0
      src/python/grpcio_tests/tests/tests.json
  36. 1 1
      src/python/grpcio_tests/tests/unit/_compression_test.py
  37. 2 2
      src/python/grpcio_tests/tests/unit/_empty_message_test.py
  38. 1 1
      src/python/grpcio_tests/tests/unit/_exit_scenarios.py
  39. 247 0
      src/python/grpcio_tests/tests/unit/_invocation_defects_test.py
  40. 2 2
      src/python/grpcio_tests/tests/unit/_metadata_test.py
  41. 22 7
      templates/tools/doxygen/Doxyfile.include
  42. 10 8
      test/core/end2end/fuzzers/api_fuzzer.c
  43. 28 15
      test/core/iomgr/timer_list_test.c
  44. 29 1
      tools/doxygen/Doxyfile.c++
  45. 30 1
      tools/doxygen/Doxyfile.c++.internal
  46. 28 1
      tools/doxygen/Doxyfile.core
  47. 49 1
      tools/doxygen/Doxyfile.core.internal
  48. 4 0
      tools/run_tests/README.md
  49. 2 2
      tools/run_tests/run_interop_tests.py
  50. 1 1
      vsprojects/README.md
  51. 0 39
      vsprojects/build_vs2010.bat
  52. 2 2
      vsprojects/coapp/zlib/README.md

+ 29 - 0
doc/cpp/perf_notes.md

@@ -0,0 +1,29 @@
+# C++ Performance Notes
+
+## Streaming write buffering
+
+Generally, each write operation (Write(), WritesDone()) implies a syscall.
+gRPC will try to batch together separate write operations from different
+threads, but currently cannot automatically infer batching in a single stream.
+
+If message k+1 in a stream does not rely on responses from message k, it's
+possible to enable write batching by passing a WriteOptions argument to Write
+with the buffer_hint set:
+
+~~~{.cpp}
+stream_writer->Write(message, WriteOptions().set_buffer_hint());
+~~~
+
+The write will be buffered until one of the following is true:
+- the per-stream buffer is filled (controllable with the channel argument
+  GRPC_ARG_HTTP2_WRITE_BUFFER_SIZE) - this prevents infinite buffering leading
+  to OOM
+- a subsequent Write without buffer_hint set is posted
+- the call is finished for writing (WritesDone() called on the client,
+  or Finish() called on an async server stream, or the service handler returns
+  for a sync server stream)
+
+## Completion Queues and Threading in the Async API
+
+Right now, the best performance trade-off is having numcpu's threads and one
+completion queue per thread.

+ 3 - 1
doc/interop-test-descriptions.md

@@ -716,7 +716,9 @@ Procedure:
 
 
     ```
     ```
     {
     {
-      response_size: 314159
+      response_parameters:{
+        size: 314159
+      }
       payload:{
       payload:{
         body: 271828 bytes of zeros
         body: 271828 bytes of zeros
       }
       }

+ 4 - 0
include/grpc++/grpc++.h

@@ -44,6 +44,10 @@
 /// peer, compression settings, authentication, etc.
 /// peer, compression settings, authentication, etc.
 /// - grpc::Server, representing a gRPC server, created by grpc::ServerBuilder.
 /// - grpc::Server, representing a gRPC server, created by grpc::ServerBuilder.
 ///
 ///
+/// Streaming calls are handled with the streaming classes in
+/// \ref sync_stream.h and
+/// \ref async_stream.h.
+///
 /// Refer to the
 /// Refer to the
 /// [examples](https://github.com/grpc/grpc/blob/master/examples/cpp)
 /// [examples](https://github.com/grpc/grpc/blob/master/examples/cpp)
 /// for code putting these pieces into play.
 /// for code putting these pieces into play.

+ 4 - 2
include/grpc++/impl/codegen/completion_queue.h

@@ -94,8 +94,10 @@ class ServerContext;
 
 
 extern CoreCodegenInterface* g_core_codegen_interface;
 extern CoreCodegenInterface* g_core_codegen_interface;
 
 
-/// A thin wrapper around \a grpc_completion_queue (see / \a
-/// src/core/surface/completion_queue.h).
+/// A thin wrapper around \ref grpc_completion_queue (see \ref
+/// src/core/lib/surface/completion_queue.h).
+/// See \ref doc/cpp/perf_notes.md for notes on best practices for high
+/// performance servers.
 class CompletionQueue : private GrpcLibraryCodegen {
 class CompletionQueue : private GrpcLibraryCodegen {
  public:
  public:
   /// Default constructor. Implicitly creates a \a grpc_completion_queue
   /// Default constructor. Implicitly creates a \a grpc_completion_queue

+ 5 - 0
src/core/ext/README.md

@@ -0,0 +1,5 @@
+Optional plugins for gRPC Core: Modules in this directory extend gRPC Core in
+useful ways. All optional code belongs here.
+
+NOTE: The movement of code between lib and ext is an ongoing effort, so this
+directory currently contains too much of the core library.

+ 4 - 1
src/core/ext/client_channel/channel_connectivity.c

@@ -76,6 +76,7 @@ typedef struct {
   gpr_mu mu;
   gpr_mu mu;
   callback_phase phase;
   callback_phase phase;
   grpc_closure on_complete;
   grpc_closure on_complete;
+  grpc_closure on_timeout;
   grpc_timer alarm;
   grpc_timer alarm;
   grpc_connectivity_state state;
   grpc_connectivity_state state;
   grpc_completion_queue *cq;
   grpc_completion_queue *cq;
@@ -200,6 +201,8 @@ void grpc_channel_watch_connectivity_state(
   gpr_mu_init(&w->mu);
   gpr_mu_init(&w->mu);
   grpc_closure_init(&w->on_complete, watch_complete, w,
   grpc_closure_init(&w->on_complete, watch_complete, w,
                     grpc_schedule_on_exec_ctx);
                     grpc_schedule_on_exec_ctx);
+  grpc_closure_init(&w->on_timeout, timeout_complete, w,
+                    grpc_schedule_on_exec_ctx);
   w->phase = WAITING;
   w->phase = WAITING;
   w->state = last_observed_state;
   w->state = last_observed_state;
   w->cq = cq;
   w->cq = cq;
@@ -208,7 +211,7 @@ void grpc_channel_watch_connectivity_state(
 
 
   grpc_timer_init(&exec_ctx, &w->alarm,
   grpc_timer_init(&exec_ctx, &w->alarm,
                   gpr_convert_clock_type(deadline, GPR_CLOCK_MONOTONIC),
                   gpr_convert_clock_type(deadline, GPR_CLOCK_MONOTONIC),
-                  timeout_complete, w, gpr_now(GPR_CLOCK_MONOTONIC));
+                  &w->on_timeout, gpr_now(GPR_CLOCK_MONOTONIC));
 
 
   if (client_channel_elem->filter == &grpc_client_channel_filter) {
   if (client_channel_elem->filter == &grpc_client_channel_filter) {
     GRPC_CHANNEL_INTERNAL_REF(channel, "watch_channel_connectivity");
     GRPC_CHANNEL_INTERNAL_REF(channel, "watch_channel_connectivity");

+ 5 - 1
src/core/ext/client_channel/subchannel.c

@@ -109,6 +109,9 @@ struct grpc_subchannel {
   /** callback for connection finishing */
   /** callback for connection finishing */
   grpc_closure connected;
   grpc_closure connected;
 
 
+  /** callback for our alarm */
+  grpc_closure on_alarm;
+
   /** pollset_set tracking who's interested in a connection
   /** pollset_set tracking who's interested in a connection
       being setup */
       being setup */
   grpc_pollset_set *pollset_set;
   grpc_pollset_set *pollset_set;
@@ -483,7 +486,8 @@ static void maybe_start_connecting_locked(grpc_exec_ctx *exec_ctx,
       gpr_log(GPR_INFO, "Retry in %" PRId64 ".%09d seconds",
       gpr_log(GPR_INFO, "Retry in %" PRId64 ".%09d seconds",
               time_til_next.tv_sec, time_til_next.tv_nsec);
               time_til_next.tv_sec, time_til_next.tv_nsec);
     }
     }
-    grpc_timer_init(exec_ctx, &c->alarm, c->next_attempt, on_alarm, c, now);
+    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, now);
   }
   }
 }
 }
 
 

+ 6 - 1
src/core/ext/lb_policy/grpclb/grpclb.c

@@ -327,6 +327,9 @@ typedef struct glb_lb_policy {
   /* A response from the LB server has been received. Process it */
   /* A response from the LB server has been received. Process it */
   grpc_closure lb_on_response_received;
   grpc_closure lb_on_response_received;
 
 
+  /* LB call retry timer callback. */
+  grpc_closure lb_on_call_retry;
+
   grpc_call *lb_call; /* streaming call to the LB server, */
   grpc_call *lb_call; /* streaming call to the LB server, */
 
 
   grpc_metadata_array lb_initial_metadata_recv; /* initial MD from LB server */
   grpc_metadata_array lb_initial_metadata_recv; /* initial MD from LB server */
@@ -1364,8 +1367,10 @@ static void lb_on_server_status_received(grpc_exec_ctx *exec_ctx, void *arg,
       }
       }
     }
     }
     GRPC_LB_POLICY_WEAK_REF(&glb_policy->base, "grpclb_retry_timer");
     GRPC_LB_POLICY_WEAK_REF(&glb_policy->base, "grpclb_retry_timer");
+    grpc_closure_init(&glb_policy->lb_on_call_retry, lb_call_on_retry_timer,
+                      glb_policy, grpc_schedule_on_exec_ctx);
     grpc_timer_init(exec_ctx, &glb_policy->lb_call_retry_timer, next_try,
     grpc_timer_init(exec_ctx, &glb_policy->lb_call_retry_timer, next_try,
-                    lb_call_on_retry_timer, glb_policy, now);
+                    &glb_policy->lb_on_call_retry, now);
   }
   }
   gpr_mu_unlock(&glb_policy->mu);
   gpr_mu_unlock(&glb_policy->mu);
   GRPC_LB_POLICY_WEAK_UNREF(exec_ctx, &glb_policy->base,
   GRPC_LB_POLICY_WEAK_UNREF(exec_ctx, &glb_policy->base,

+ 4 - 0
src/core/ext/resolver/README.md

@@ -0,0 +1,4 @@
+# Resolver
+
+Implementations of various name resolution schemes.
+See the [naming spec](/doc/naming.md).

+ 4 - 2
src/core/ext/resolver/dns/native/dns_resolver.c

@@ -81,6 +81,7 @@ typedef struct {
   /** retry timer */
   /** retry timer */
   bool have_retry_timer;
   bool have_retry_timer;
   grpc_timer retry_timer;
   grpc_timer retry_timer;
+  grpc_closure on_retry;
   /** retry backoff state */
   /** retry backoff state */
   gpr_backoff backoff_state;
   gpr_backoff backoff_state;
 
 
@@ -199,8 +200,9 @@ static void dns_on_resolved(grpc_exec_ctx *exec_ctx, void *arg,
     } else {
     } else {
       gpr_log(GPR_DEBUG, "retrying immediately");
       gpr_log(GPR_DEBUG, "retrying immediately");
     }
     }
-    grpc_timer_init(exec_ctx, &r->retry_timer, next_try, dns_on_retry_timer, r,
-                    now);
+    grpc_closure_init(&r->on_retry, dns_on_retry_timer, r,
+                      grpc_schedule_on_exec_ctx);
+    grpc_timer_init(exec_ctx, &r->retry_timer, next_try, &r->on_retry, now);
   }
   }
   if (r->resolved_result != NULL) {
   if (r->resolved_result != NULL) {
     grpc_channel_args_destroy(exec_ctx, r->resolved_result);
     grpc_channel_args_destroy(exec_ctx, r->resolved_result);

+ 1 - 0
src/core/ext/transport/README.md

@@ -0,0 +1 @@
+Transports for gRPC

+ 1 - 0
src/core/ext/transport/chttp2/README.md

@@ -0,0 +1 @@
+CHTTP2 - gRPC's implementation of a HTTP2 based transport

+ 6 - 0
src/core/lib/README.md

@@ -0,0 +1,6 @@
+Required elements of gRPC Core: Each module in this directory is required to
+build gRPC. If it's possible to envisage a configuration where code is not
+required, then that code belongs in ext/ instead.
+
+NOTE: The movement of code between lib and ext is an ongoing effort, so this
+directory currently contains too much of the core library.

+ 4 - 0
src/core/lib/channel/README.md

@@ -0,0 +1,4 @@
+# Channel
+
+Provides channel/call stack implementation, and implementation of common filters
+for that implementation.

+ 5 - 2
src/core/lib/channel/deadline_filter.c

@@ -83,8 +83,11 @@ static void start_timer_if_needed_locked(grpc_exec_ctx* exec_ctx,
     // Take a reference to the call stack, to be owned by the timer.
     // Take a reference to the call stack, to be owned by the timer.
     GRPC_CALL_STACK_REF(deadline_state->call_stack, "deadline_timer");
     GRPC_CALL_STACK_REF(deadline_state->call_stack, "deadline_timer");
     deadline_state->timer_pending = true;
     deadline_state->timer_pending = true;
-    grpc_timer_init(exec_ctx, &deadline_state->timer, deadline, timer_callback,
-                    elem, gpr_now(GPR_CLOCK_MONOTONIC));
+    grpc_closure_init(&deadline_state->timer_callback, timer_callback, elem,
+                      grpc_schedule_on_exec_ctx);
+    grpc_timer_init(exec_ctx, &deadline_state->timer, deadline,
+                    &deadline_state->timer_callback,
+                    gpr_now(GPR_CLOCK_MONOTONIC));
   }
   }
 }
 }
 static void start_timer_if_needed(grpc_exec_ctx* exec_ctx,
 static void start_timer_if_needed(grpc_exec_ctx* exec_ctx,

+ 1 - 0
src/core/lib/channel/deadline_filter.h

@@ -46,6 +46,7 @@ typedef struct grpc_deadline_state {
   bool timer_pending;
   bool timer_pending;
   // The deadline timer.
   // The deadline timer.
   grpc_timer timer;
   grpc_timer timer;
+  grpc_closure timer_callback;
   // Closure to invoke when the call is complete.
   // Closure to invoke when the call is complete.
   // We use this to cancel the timer.
   // We use this to cancel the timer.
   grpc_closure on_complete;
   grpc_closure on_complete;

+ 4 - 1
src/core/lib/channel/handshaker.c

@@ -86,6 +86,7 @@ struct grpc_handshake_manager {
   grpc_tcp_server_acceptor* acceptor;
   grpc_tcp_server_acceptor* acceptor;
   // Deadline timer across all handshakers.
   // Deadline timer across all handshakers.
   grpc_timer deadline_timer;
   grpc_timer deadline_timer;
+  grpc_closure on_timeout;
   // The final callback and user_data to invoke after the last handshaker.
   // The final callback and user_data to invoke after the last handshaker.
   grpc_closure on_handshake_done;
   grpc_closure on_handshake_done;
   void* user_data;
   void* user_data;
@@ -224,9 +225,11 @@ void grpc_handshake_manager_do_handshake(
                     grpc_schedule_on_exec_ctx);
                     grpc_schedule_on_exec_ctx);
   // Start deadline timer, which owns a ref.
   // Start deadline timer, which owns a ref.
   gpr_ref(&mgr->refs);
   gpr_ref(&mgr->refs);
+  grpc_closure_init(&mgr->on_timeout, on_timeout, mgr,
+                    grpc_schedule_on_exec_ctx);
   grpc_timer_init(exec_ctx, &mgr->deadline_timer,
   grpc_timer_init(exec_ctx, &mgr->deadline_timer,
                   gpr_convert_clock_type(deadline, GPR_CLOCK_MONOTONIC),
                   gpr_convert_clock_type(deadline, GPR_CLOCK_MONOTONIC),
-                  on_timeout, mgr, gpr_now(GPR_CLOCK_MONOTONIC));
+                  &mgr->on_timeout, gpr_now(GPR_CLOCK_MONOTONIC));
   // Start first handshaker, which also owns a ref.
   // Start first handshaker, which also owns a ref.
   gpr_ref(&mgr->refs);
   gpr_ref(&mgr->refs);
   bool done = call_next_handshaker_locked(exec_ctx, mgr, GRPC_ERROR_NONE);
   bool done = call_next_handshaker_locked(exec_ctx, mgr, GRPC_ERROR_NONE);

+ 6 - 0
src/core/lib/iomgr/README.md

@@ -0,0 +1,6 @@
+# iomgr
+
+Platform abstractions for I/O (mostly network).
+
+Provides abstractions over TCP/UDP I/O, file loading, polling, and concurrency
+management for various operating systems.

+ 3 - 1
src/core/lib/iomgr/tcp_client_posix.c

@@ -65,6 +65,7 @@ typedef struct {
   grpc_fd *fd;
   grpc_fd *fd;
   gpr_timespec deadline;
   gpr_timespec deadline;
   grpc_timer alarm;
   grpc_timer alarm;
+  grpc_closure on_alarm;
   int refs;
   int refs;
   grpc_closure write_closure;
   grpc_closure write_closure;
   grpc_pollset_set *interested_parties;
   grpc_pollset_set *interested_parties;
@@ -352,9 +353,10 @@ static void tcp_client_connect_impl(grpc_exec_ctx *exec_ctx,
   }
   }
 
 
   gpr_mu_lock(&ac->mu);
   gpr_mu_lock(&ac->mu);
+  grpc_closure_init(&ac->on_alarm, tc_on_alarm, ac, grpc_schedule_on_exec_ctx);
   grpc_timer_init(exec_ctx, &ac->alarm,
   grpc_timer_init(exec_ctx, &ac->alarm,
                   gpr_convert_clock_type(deadline, GPR_CLOCK_MONOTONIC),
                   gpr_convert_clock_type(deadline, GPR_CLOCK_MONOTONIC),
-                  tc_on_alarm, ac, gpr_now(GPR_CLOCK_MONOTONIC));
+                  &ac->on_alarm, gpr_now(GPR_CLOCK_MONOTONIC));
   grpc_fd_notify_on_write(exec_ctx, ac->fd, &ac->write_closure);
   grpc_fd_notify_on_write(exec_ctx, ac->fd, &ac->write_closure);
   gpr_mu_unlock(&ac->mu);
   gpr_mu_unlock(&ac->mu);
 
 

+ 4 - 1
src/core/lib/iomgr/tcp_client_uv.c

@@ -49,6 +49,7 @@
 typedef struct grpc_uv_tcp_connect {
 typedef struct grpc_uv_tcp_connect {
   uv_connect_t connect_req;
   uv_connect_t connect_req;
   grpc_timer alarm;
   grpc_timer alarm;
+  grpc_closure on_alarm;
   uv_tcp_t *tcp_handle;
   uv_tcp_t *tcp_handle;
   grpc_closure *closure;
   grpc_closure *closure;
   grpc_endpoint **endpoint;
   grpc_endpoint **endpoint;
@@ -148,9 +149,11 @@ static void tcp_client_connect_impl(grpc_exec_ctx *exec_ctx,
   uv_tcp_connect(&connect->connect_req, connect->tcp_handle,
   uv_tcp_connect(&connect->connect_req, connect->tcp_handle,
                  (const struct sockaddr *)resolved_addr->addr,
                  (const struct sockaddr *)resolved_addr->addr,
                  uv_tc_on_connect);
                  uv_tc_on_connect);
+  grpc_closure_init(&connect->on_alarm, uv_tc_on_alarm, connect,
+                    grpc_schedule_on_exec_ctx);
   grpc_timer_init(exec_ctx, &connect->alarm,
   grpc_timer_init(exec_ctx, &connect->alarm,
                   gpr_convert_clock_type(deadline, GPR_CLOCK_MONOTONIC),
                   gpr_convert_clock_type(deadline, GPR_CLOCK_MONOTONIC),
-                  uv_tc_on_alarm, connect, gpr_now(GPR_CLOCK_MONOTONIC));
+                  &connect->on_alarm, gpr_now(GPR_CLOCK_MONOTONIC));
 }
 }
 
 
 // overridden by api_fuzzer.c
 // overridden by api_fuzzer.c

+ 3 - 1
src/core/lib/iomgr/tcp_client_windows.c

@@ -58,6 +58,7 @@ typedef struct {
   grpc_winsocket *socket;
   grpc_winsocket *socket;
   gpr_timespec deadline;
   gpr_timespec deadline;
   grpc_timer alarm;
   grpc_timer alarm;
+  grpc_closure on_alarm;
   char *addr_name;
   char *addr_name;
   int refs;
   int refs;
   grpc_closure on_connect;
   grpc_closure on_connect;
@@ -229,7 +230,8 @@ void grpc_tcp_client_connect(grpc_exec_ctx *exec_ctx, grpc_closure *on_done,
   ac->resource_quota = resource_quota;
   ac->resource_quota = resource_quota;
   grpc_closure_init(&ac->on_connect, on_connect, ac, grpc_schedule_on_exec_ctx);
   grpc_closure_init(&ac->on_connect, on_connect, ac, grpc_schedule_on_exec_ctx);
 
 
-  grpc_timer_init(exec_ctx, &ac->alarm, deadline, on_alarm, ac,
+  grpc_closure_init(&ac->on_alarm, on_alarm, ac, grpc_schedule_on_exec_ctx);
+  grpc_timer_init(exec_ctx, &ac->alarm, deadline, &ac->on_alarm,
                   gpr_now(GPR_CLOCK_MONOTONIC));
                   gpr_now(GPR_CLOCK_MONOTONIC));
   grpc_socket_notify_on_write(exec_ctx, socket, &ac->on_connect);
   grpc_socket_notify_on_write(exec_ctx, socket, &ac->on_connect);
   return;
   return;

+ 8 - 8
src/core/lib/iomgr/timer.h

@@ -49,15 +49,15 @@
 
 
 typedef struct grpc_timer grpc_timer;
 typedef struct grpc_timer grpc_timer;
 
 
-/* Initialize *timer. When expired or canceled, timer_cb will be called with
-   *timer_cb_arg and error set to indicate if it expired (GRPC_ERROR_NONE) or
-   was canceled (GRPC_ERROR_CANCELLED). timer_cb is guaranteed to be called
-   exactly once, and application code should check the error to determine
-   how it was invoked. The application callback is also responsible for
-   maintaining information about when to free up any user-level state. */
+/* Initialize *timer. When expired or canceled, closure will be called with
+   error set to indicate if it expired (GRPC_ERROR_NONE) or was canceled
+   (GRPC_ERROR_CANCELLED). timer_cb is guaranteed to be called exactly once, and
+   application code should check the error to determine how it was invoked. The
+   application callback is also responsible for maintaining information about
+   when to free up any user-level state. */
 void grpc_timer_init(grpc_exec_ctx *exec_ctx, grpc_timer *timer,
 void grpc_timer_init(grpc_exec_ctx *exec_ctx, grpc_timer *timer,
-                     gpr_timespec deadline, grpc_iomgr_cb_func timer_cb,
-                     void *timer_cb_arg, gpr_timespec now);
+                     gpr_timespec deadline, grpc_closure *closure,
+                     gpr_timespec now);
 
 
 /* Note that there is no timer destroy function. This is because the
 /* Note that there is no timer destroy function. This is because the
    timer is a one-time occurrence with a guarantee that the callback will
    timer is a one-time occurrence with a guarantee that the callback will

+ 7 - 8
src/core/lib/iomgr/timer_generic.c

@@ -178,28 +178,27 @@ static void note_deadline_change(shard_type *shard) {
 }
 }
 
 
 void grpc_timer_init(grpc_exec_ctx *exec_ctx, grpc_timer *timer,
 void grpc_timer_init(grpc_exec_ctx *exec_ctx, grpc_timer *timer,
-                     gpr_timespec deadline, grpc_iomgr_cb_func timer_cb,
-                     void *timer_cb_arg, gpr_timespec now) {
+                     gpr_timespec deadline, grpc_closure *closure,
+                     gpr_timespec now) {
   int is_first_timer = 0;
   int is_first_timer = 0;
   shard_type *shard = &g_shards[shard_idx(timer)];
   shard_type *shard = &g_shards[shard_idx(timer)];
   GPR_ASSERT(deadline.clock_type == g_clock_type);
   GPR_ASSERT(deadline.clock_type == g_clock_type);
   GPR_ASSERT(now.clock_type == g_clock_type);
   GPR_ASSERT(now.clock_type == g_clock_type);
-  grpc_closure_init(&timer->closure, timer_cb, timer_cb_arg,
-                    grpc_schedule_on_exec_ctx);
+  timer->closure = closure;
   timer->deadline = deadline;
   timer->deadline = deadline;
   timer->triggered = 0;
   timer->triggered = 0;
 
 
   if (!g_initialized) {
   if (!g_initialized) {
     timer->triggered = 1;
     timer->triggered = 1;
     grpc_closure_sched(
     grpc_closure_sched(
-        exec_ctx, &timer->closure,
+        exec_ctx, timer->closure,
         GRPC_ERROR_CREATE("Attempt to create timer before initialization"));
         GRPC_ERROR_CREATE("Attempt to create timer before initialization"));
     return;
     return;
   }
   }
 
 
   if (gpr_time_cmp(deadline, now) <= 0) {
   if (gpr_time_cmp(deadline, now) <= 0) {
     timer->triggered = 1;
     timer->triggered = 1;
-    grpc_closure_sched(exec_ctx, &timer->closure, GRPC_ERROR_NONE);
+    grpc_closure_sched(exec_ctx, timer->closure, GRPC_ERROR_NONE);
     return;
     return;
   }
   }
 
 
@@ -251,7 +250,7 @@ void grpc_timer_cancel(grpc_exec_ctx *exec_ctx, grpc_timer *timer) {
   shard_type *shard = &g_shards[shard_idx(timer)];
   shard_type *shard = &g_shards[shard_idx(timer)];
   gpr_mu_lock(&shard->mu);
   gpr_mu_lock(&shard->mu);
   if (!timer->triggered) {
   if (!timer->triggered) {
-    grpc_closure_sched(exec_ctx, &timer->closure, GRPC_ERROR_CANCELLED);
+    grpc_closure_sched(exec_ctx, timer->closure, GRPC_ERROR_CANCELLED);
     timer->triggered = 1;
     timer->triggered = 1;
     if (timer->heap_index == INVALID_HEAP_INDEX) {
     if (timer->heap_index == INVALID_HEAP_INDEX) {
       list_remove(timer);
       list_remove(timer);
@@ -317,7 +316,7 @@ static size_t pop_timers(grpc_exec_ctx *exec_ctx, shard_type *shard,
   grpc_timer *timer;
   grpc_timer *timer;
   gpr_mu_lock(&shard->mu);
   gpr_mu_lock(&shard->mu);
   while ((timer = pop_one(shard, now))) {
   while ((timer = pop_one(shard, now))) {
-    grpc_closure_sched(exec_ctx, &timer->closure, GRPC_ERROR_REF(error));
+    grpc_closure_sched(exec_ctx, timer->closure, GRPC_ERROR_REF(error));
     n++;
     n++;
   }
   }
   *new_min_deadline = compute_min_deadline(shard);
   *new_min_deadline = compute_min_deadline(shard);

+ 1 - 1
src/core/lib/iomgr/timer_generic.h

@@ -43,7 +43,7 @@ struct grpc_timer {
   int triggered;
   int triggered;
   struct grpc_timer *next;
   struct grpc_timer *next;
   struct grpc_timer *prev;
   struct grpc_timer *prev;
-  grpc_closure closure;
+  grpc_closure *closure;
 };
 };
 
 
 #endif /* GRPC_CORE_LIB_IOMGR_TIMER_GENERIC_H */
 #endif /* GRPC_CORE_LIB_IOMGR_TIMER_GENERIC_H */

+ 6 - 7
src/core/lib/iomgr/timer_uv.c

@@ -55,21 +55,20 @@ void run_expired_timer(uv_timer_t *handle) {
   grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
   grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
   GPR_ASSERT(!timer->triggered);
   GPR_ASSERT(!timer->triggered);
   timer->triggered = 1;
   timer->triggered = 1;
-  grpc_closure_sched(&exec_ctx, &timer->closure, GRPC_ERROR_NONE);
+  grpc_closure_sched(&exec_ctx, timer->closure, GRPC_ERROR_NONE);
   stop_uv_timer(handle);
   stop_uv_timer(handle);
   grpc_exec_ctx_finish(&exec_ctx);
   grpc_exec_ctx_finish(&exec_ctx);
 }
 }
 
 
 void grpc_timer_init(grpc_exec_ctx *exec_ctx, grpc_timer *timer,
 void grpc_timer_init(grpc_exec_ctx *exec_ctx, grpc_timer *timer,
-                     gpr_timespec deadline, grpc_iomgr_cb_func timer_cb,
-                     void *timer_cb_arg, gpr_timespec now) {
+                     gpr_timespec deadline, grpc_closure *closure,
+                     gpr_timespec now) {
   uint64_t timeout;
   uint64_t timeout;
   uv_timer_t *uv_timer;
   uv_timer_t *uv_timer;
-  grpc_closure_init(&timer->closure, timer_cb, timer_cb_arg,
-                    grpc_schedule_on_exec_ctx);
+  timer->closure = closure;
   if (gpr_time_cmp(deadline, now) <= 0) {
   if (gpr_time_cmp(deadline, now) <= 0) {
     timer->triggered = 1;
     timer->triggered = 1;
-    grpc_closure_sched(exec_ctx, &timer->closure, GRPC_ERROR_NONE);
+    grpc_closure_sched(exec_ctx, timer->closure, GRPC_ERROR_NONE);
     return;
     return;
   }
   }
   timer->triggered = 0;
   timer->triggered = 0;
@@ -84,7 +83,7 @@ void grpc_timer_init(grpc_exec_ctx *exec_ctx, grpc_timer *timer,
 void grpc_timer_cancel(grpc_exec_ctx *exec_ctx, grpc_timer *timer) {
 void grpc_timer_cancel(grpc_exec_ctx *exec_ctx, grpc_timer *timer) {
   if (!timer->triggered) {
   if (!timer->triggered) {
     timer->triggered = 1;
     timer->triggered = 1;
-    grpc_closure_sched(exec_ctx, &timer->closure, GRPC_ERROR_CANCELLED);
+    grpc_closure_sched(exec_ctx, timer->closure, GRPC_ERROR_CANCELLED);
     stop_uv_timer((uv_timer_t *)timer->uv_timer);
     stop_uv_timer((uv_timer_t *)timer->uv_timer);
   }
   }
 }
 }

+ 1 - 1
src/core/lib/iomgr/timer_uv.h

@@ -37,7 +37,7 @@
 #include "src/core/lib/iomgr/exec_ctx.h"
 #include "src/core/lib/iomgr/exec_ctx.h"
 
 
 struct grpc_timer {
 struct grpc_timer {
-  grpc_closure closure;
+  grpc_closure *closure;
   /* This is actually a uv_timer_t*, but we want to keep platform-specific
   /* This is actually a uv_timer_t*, but we want to keep platform-specific
      types out of headers */
      types out of headers */
   void *uv_timer;
   void *uv_timer;

+ 4 - 0
src/core/lib/surface/README.md

@@ -0,0 +1,4 @@
+# Surface
+
+Surface provides the bulk of the gRPC Core public API, and translates it into
+calls against core components.

+ 4 - 1
src/core/lib/surface/alarm.c

@@ -38,6 +38,7 @@
 
 
 struct grpc_alarm {
 struct grpc_alarm {
   grpc_timer alarm;
   grpc_timer alarm;
+  grpc_closure on_alarm;
   grpc_cq_completion completion;
   grpc_cq_completion completion;
   /** completion queue where events about this alarm will be posted */
   /** completion queue where events about this alarm will be posted */
   grpc_completion_queue *cq;
   grpc_completion_queue *cq;
@@ -64,9 +65,11 @@ grpc_alarm *grpc_alarm_create(grpc_completion_queue *cq, gpr_timespec deadline,
   alarm->tag = tag;
   alarm->tag = tag;
 
 
   grpc_cq_begin_op(cq, tag);
   grpc_cq_begin_op(cq, tag);
+  grpc_closure_init(&alarm->on_alarm, alarm_cb, alarm,
+                    grpc_schedule_on_exec_ctx);
   grpc_timer_init(&exec_ctx, &alarm->alarm,
   grpc_timer_init(&exec_ctx, &alarm->alarm,
                   gpr_convert_clock_type(deadline, GPR_CLOCK_MONOTONIC),
                   gpr_convert_clock_type(deadline, GPR_CLOCK_MONOTONIC),
-                  alarm_cb, alarm, gpr_now(GPR_CLOCK_MONOTONIC));
+                  &alarm->on_alarm, gpr_now(GPR_CLOCK_MONOTONIC));
   grpc_exec_ctx_finish(&exec_ctx);
   grpc_exec_ctx_finish(&exec_ctx);
   return alarm;
   return alarm;
 }
 }

+ 7 - 0
src/core/lib/transport/README.md

@@ -0,0 +1,7 @@
+# Transport
+
+Common implementation details for gRPC Transports.
+
+Transports multiplex messages across some single connection. In ext/ there are
+implementations atop [a custom http2 implementation](/src/core/ext/transport/chttp2/README.md)
+and atop [cronet](/src/core/ext/transport/cronet/README.md).

+ 2 - 0
src/core/lib/tsi/README.md

@@ -0,0 +1,2 @@
+# Transport Security Interface
+An abstraction library over crypto and auth modules (typically OpenSSL)

+ 3 - 0
src/node/interop/interop_client.js

@@ -312,6 +312,9 @@ function customMetadata(client, done) {
     }
     }
   };
   };
   var streaming_arg = {
   var streaming_arg = {
+    response_parameters: [
+     {size: 314159}
+    ],
     payload: {
     payload: {
       body: zeroBuffer(271828)
       body: zeroBuffer(271828)
     }
     }

+ 11 - 0
src/php/tests/interop/interop_client.php

@@ -451,11 +451,22 @@ function customMetadata($stub)
 
 
     $streaming_request = new grpc\testing\StreamingOutputCallRequest();
     $streaming_request = new grpc\testing\StreamingOutputCallRequest();
     $streaming_request->setPayload($payload);
     $streaming_request->setPayload($payload);
+    $response_parameters = new grpc\testing\ResponseParameters();
+    $response_parameters->setSize($response_len);
+    $streaming_request->getResponseParameters()[] = $response_parameters;
     $streaming_call->write($streaming_request);
     $streaming_call->write($streaming_request);
     $streaming_call->writesDone();
     $streaming_call->writesDone();
+    $result = $streaming_call->read();
 
 
     hardAssertIfStatusOk($streaming_call->getStatus());
     hardAssertIfStatusOk($streaming_call->getStatus());
 
 
+    $streaming_initial_metadata = $streaming_call->getMetadata();
+    hardAssert(array_key_exists($ECHO_INITIAL_KEY, $streaming_initial_metadata),
+               'Initial metadata does not contain expected key');
+    hardAssert(
+        $streaming_initial_metadata[$ECHO_INITIAL_KEY][0] === $ECHO_INITIAL_VALUE,
+        'Incorrect initial metadata value');
+
     $streaming_trailing_metadata = $streaming_call->getTrailingMetadata();
     $streaming_trailing_metadata = $streaming_call->getTrailingMetadata();
     hardAssert(array_key_exists($ECHO_TRAILING_KEY,
     hardAssert(array_key_exists($ECHO_TRAILING_KEY,
                                 $streaming_trailing_metadata),
                                 $streaming_trailing_metadata),

+ 11 - 1
src/python/grpcio/grpc/_channel.py

@@ -32,6 +32,7 @@
 import sys
 import sys
 import threading
 import threading
 import time
 import time
+import logging
 
 
 import grpc
 import grpc
 from grpc import _common
 from grpc import _common
@@ -197,7 +198,16 @@ def _consume_request_iterator(
   event_handler = _event_handler(state, call, None)
   event_handler = _event_handler(state, call, None)
 
 
   def consume_request_iterator():
   def consume_request_iterator():
-    for request in request_iterator:
+    while True:
+      try:
+        request = next(request_iterator)
+      except StopIteration:
+        break
+      except Exception as e:
+        logging.exception("Exception iterating requests!")
+        call.cancel()
+        _abort(state, grpc.StatusCode.UNKNOWN, "Exception iterating requests!")
+        return
       serialized_request = _common.serialize(request, request_serializer)
       serialized_request = _common.serialize(request, request_serializer)
       with state.condition:
       with state.condition:
         if state.code is None and not state.cancelled:
         if state.code is None and not state.cancelled:

+ 8 - 8
src/python/grpcio_tests/tests/reflection/_reflection_servicer_test.py

@@ -75,7 +75,7 @@ class ReflectionServicerTest(unittest.TestCase):
         file_by_filename='i-donut-exist'
         file_by_filename='i-donut-exist'
       ),
       ),
     )
     )
-    responses = tuple(self._stub.ServerReflectionInfo(requests))
+    responses = tuple(self._stub.ServerReflectionInfo(iter(requests)))
     expected_responses = (
     expected_responses = (
       reflection_pb2.ServerReflectionResponse(
       reflection_pb2.ServerReflectionResponse(
         valid_host='',
         valid_host='',
@@ -93,7 +93,7 @@ class ReflectionServicerTest(unittest.TestCase):
         )
         )
       ),
       ),
     )
     )
-    self.assertEqual(expected_responses, responses)
+    self.assertSequenceEqual(expected_responses, responses)
 
 
   def testFileBySymbol(self):
   def testFileBySymbol(self):
     requests = (
     requests = (
@@ -104,7 +104,7 @@ class ReflectionServicerTest(unittest.TestCase):
         file_containing_symbol='i.donut.exist.co.uk.org.net.me.name.foo'
         file_containing_symbol='i.donut.exist.co.uk.org.net.me.name.foo'
       ),
       ),
     )
     )
-    responses = tuple(self._stub.ServerReflectionInfo(requests))
+    responses = tuple(self._stub.ServerReflectionInfo(iter(requests)))
     expected_responses = (
     expected_responses = (
       reflection_pb2.ServerReflectionResponse(
       reflection_pb2.ServerReflectionResponse(
         valid_host='',
         valid_host='',
@@ -122,7 +122,7 @@ class ReflectionServicerTest(unittest.TestCase):
         )
         )
       ),
       ),
     )
     )
-    self.assertEqual(expected_responses, responses)
+    self.assertSequenceEqual(expected_responses, responses)
 
 
   @unittest.skip('TODO(atash): implement file-containing-extension reflection '
   @unittest.skip('TODO(atash): implement file-containing-extension reflection '
                  '(see https://github.com/google/protobuf/issues/2248)')
                  '(see https://github.com/google/protobuf/issues/2248)')
@@ -141,7 +141,7 @@ class ReflectionServicerTest(unittest.TestCase):
         ),
         ),
       ),
       ),
     )
     )
-    responses = tuple(self._stub.ServerReflectionInfo(requests))
+    responses = tuple(self._stub.ServerReflectionInfo(iter(requests)))
     expected_responses = (
     expected_responses = (
       reflection_pb2.ServerReflectionResponse(
       reflection_pb2.ServerReflectionResponse(
         valid_host='',
         valid_host='',
@@ -159,7 +159,7 @@ class ReflectionServicerTest(unittest.TestCase):
         )
         )
       ),
       ),
     )
     )
-    self.assertEqual(expected_responses, responses)
+    self.assertSequenceEqual(expected_responses, responses)
 
 
   def testListServices(self):
   def testListServices(self):
     requests = (
     requests = (
@@ -167,7 +167,7 @@ class ReflectionServicerTest(unittest.TestCase):
         list_services='',
         list_services='',
       ),
       ),
     )
     )
-    responses = tuple(self._stub.ServerReflectionInfo(requests))
+    responses = tuple(self._stub.ServerReflectionInfo(iter(requests)))
     expected_responses = (
     expected_responses = (
       reflection_pb2.ServerReflectionResponse(
       reflection_pb2.ServerReflectionResponse(
         valid_host='',
         valid_host='',
@@ -179,7 +179,7 @@ class ReflectionServicerTest(unittest.TestCase):
         )
         )
       ),
       ),
     )
     )
-    self.assertEqual(expected_responses, responses)
+    self.assertSequenceEqual(expected_responses, responses)
 
 
 if __name__ == '__main__':
 if __name__ == '__main__':
   unittest.main(verbosity=2)
   unittest.main(verbosity=2)

+ 1 - 0
src/python/grpcio_tests/tests/tests.json

@@ -28,6 +28,7 @@
   "unit._empty_message_test.EmptyMessageTest",
   "unit._empty_message_test.EmptyMessageTest",
   "unit._exit_test.ExitTest",
   "unit._exit_test.ExitTest",
   "unit._invalid_metadata_test.InvalidMetadataTest",
   "unit._invalid_metadata_test.InvalidMetadataTest",
+  "unit._invocation_defects_test.InvocationDefectsTest",
   "unit._metadata_code_details_test.MetadataCodeDetailsTest",
   "unit._metadata_code_details_test.MetadataCodeDetailsTest",
   "unit._metadata_test.MetadataTest",
   "unit._metadata_test.MetadataTest",
   "unit._rpc_test.RPCTest",
   "unit._rpc_test.RPCTest",

+ 1 - 1
src/python/grpcio_tests/tests/unit/_compression_test.py

@@ -125,7 +125,7 @@ class CompressionTest(unittest.TestCase):
     compressed_channel = grpc.insecure_channel('localhost:%d' % self._port,
     compressed_channel = grpc.insecure_channel('localhost:%d' % self._port,
         options=[('grpc.default_compression_algorithm', 1)])
         options=[('grpc.default_compression_algorithm', 1)])
     multi_callable = compressed_channel.stream_stream(_STREAM_STREAM)
     multi_callable = compressed_channel.stream_stream(_STREAM_STREAM)
-    call = multi_callable([request] * test_constants.STREAM_LENGTH)
+    call = multi_callable(iter([request] * test_constants.STREAM_LENGTH))
     for response in call:
     for response in call:
       self.assertEqual(request, response)
       self.assertEqual(request, response)
 
 

+ 2 - 2
src/python/grpcio_tests/tests/unit/_empty_message_test.py

@@ -123,12 +123,12 @@ class EmptyMessageTest(unittest.TestCase):
 
 
   def testStreamUnary(self):
   def testStreamUnary(self):
     response = self._channel.stream_unary(_STREAM_UNARY)(
     response = self._channel.stream_unary(_STREAM_UNARY)(
-        [_REQUEST] * test_constants.STREAM_LENGTH)
+        iter([_REQUEST] * test_constants.STREAM_LENGTH))
     self.assertEqual(_RESPONSE, response)
     self.assertEqual(_RESPONSE, response)
 
 
   def testStreamStream(self):
   def testStreamStream(self):
     response_iterator = self._channel.stream_stream(_STREAM_STREAM)(
     response_iterator = self._channel.stream_stream(_STREAM_STREAM)(
-        [_REQUEST] * test_constants.STREAM_LENGTH)
+        iter([_REQUEST] * test_constants.STREAM_LENGTH))
     self.assertSequenceEqual(
     self.assertSequenceEqual(
         [_RESPONSE] * test_constants.STREAM_LENGTH, list(response_iterator))
         [_RESPONSE] * test_constants.STREAM_LENGTH, list(response_iterator))
 
 

+ 1 - 1
src/python/grpcio_tests/tests/unit/_exit_scenarios.py

@@ -240,7 +240,7 @@ if __name__ == '__main__':
       multi_callable = channel.stream_unary(method)
       multi_callable = channel.stream_unary(method)
       future = multi_callable.future(infinite_request_iterator())
       future = multi_callable.future(infinite_request_iterator())
       result, call = multi_callable.with_call(
       result, call = multi_callable.with_call(
-          [REQUEST] * test_constants.STREAM_LENGTH)
+          iter([REQUEST] * test_constants.STREAM_LENGTH))
     elif (args.scenario == IN_FLIGHT_STREAM_STREAM_CALL or
     elif (args.scenario == IN_FLIGHT_STREAM_STREAM_CALL or
           args.scenario == IN_FLIGHT_PARTIAL_STREAM_STREAM_CALL):
           args.scenario == IN_FLIGHT_PARTIAL_STREAM_STREAM_CALL):
       multi_callable = channel.stream_stream(method)
       multi_callable = channel.stream_stream(method)

+ 247 - 0
src/python/grpcio_tests/tests/unit/_invocation_defects_test.py

@@ -0,0 +1,247 @@
+# 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 itertools
+import threading
+import unittest
+from concurrent import futures
+
+import grpc
+from grpc.framework.foundation import logging_pool
+
+from tests.unit.framework.common import test_constants
+from tests.unit.framework.common import test_control
+
+_SERIALIZE_REQUEST = lambda bytestring: bytestring * 2
+_DESERIALIZE_REQUEST = lambda bytestring: bytestring[len(bytestring) // 2:]
+_SERIALIZE_RESPONSE = lambda bytestring: bytestring * 3
+_DESERIALIZE_RESPONSE = lambda bytestring: bytestring[:len(bytestring) // 3]
+
+_UNARY_UNARY = '/test/UnaryUnary'
+_UNARY_STREAM = '/test/UnaryStream'
+_STREAM_UNARY = '/test/StreamUnary'
+_STREAM_STREAM = '/test/StreamStream'
+
+
+class _Callback(object):
+  def __init__(self):
+    self._condition = threading.Condition()
+    self._value = None
+    self._called = False
+
+  def __call__(self, value):
+    with self._condition:
+      self._value = value
+      self._called = True
+      self._condition.notify_all()
+
+  def value(self):
+    with self._condition:
+      while not self._called:
+        self._condition.wait()
+      return self._value
+
+
+class _Handler(object):
+  def __init__(self, control):
+    self._control = control
+
+  def handle_unary_unary(self, request, servicer_context):
+    self._control.control()
+    if servicer_context is not None:
+      servicer_context.set_trailing_metadata((('testkey', 'testvalue',),))
+    return request
+
+  def handle_unary_stream(self, request, servicer_context):
+    for _ in range(test_constants.STREAM_LENGTH):
+      self._control.control()
+      yield request
+    self._control.control()
+    if servicer_context is not None:
+      servicer_context.set_trailing_metadata((('testkey', 'testvalue',),))
+
+  def handle_stream_unary(self, request_iterator, servicer_context):
+    if servicer_context is not None:
+      servicer_context.invocation_metadata()
+    self._control.control()
+    response_elements = []
+    for request in request_iterator:
+      self._control.control()
+      response_elements.append(request)
+    self._control.control()
+    if servicer_context is not None:
+      servicer_context.set_trailing_metadata((('testkey', 'testvalue',),))
+    return b''.join(response_elements)
+
+  def handle_stream_stream(self, request_iterator, servicer_context):
+    self._control.control()
+    if servicer_context is not None:
+      servicer_context.set_trailing_metadata((('testkey', 'testvalue',),))
+    for request in request_iterator:
+      self._control.control()
+      yield request
+    self._control.control()
+
+
+class _MethodHandler(grpc.RpcMethodHandler):
+  def __init__(
+    self, request_streaming, response_streaming, request_deserializer,
+    response_serializer, unary_unary, unary_stream, stream_unary,
+    stream_stream):
+    self.request_streaming = request_streaming
+    self.response_streaming = response_streaming
+    self.request_deserializer = request_deserializer
+    self.response_serializer = response_serializer
+    self.unary_unary = unary_unary
+    self.unary_stream = unary_stream
+    self.stream_unary = stream_unary
+    self.stream_stream = stream_stream
+
+
+class _GenericHandler(grpc.GenericRpcHandler):
+  def __init__(self, handler):
+    self._handler = handler
+
+  def service(self, handler_call_details):
+    if handler_call_details.method == _UNARY_UNARY:
+      return _MethodHandler(
+        False, False, None, None, self._handler.handle_unary_unary, None,
+        None, None)
+    elif handler_call_details.method == _UNARY_STREAM:
+      return _MethodHandler(
+        False, True, _DESERIALIZE_REQUEST, _SERIALIZE_RESPONSE, None,
+        self._handler.handle_unary_stream, None, None)
+    elif handler_call_details.method == _STREAM_UNARY:
+      return _MethodHandler(
+        True, False, _DESERIALIZE_REQUEST, _SERIALIZE_RESPONSE, None, None,
+        self._handler.handle_stream_unary, None)
+    elif handler_call_details.method == _STREAM_STREAM:
+      return _MethodHandler(
+        True, True, None, None, None, None, None,
+        self._handler.handle_stream_stream)
+    else:
+      return None
+
+
+class FailAfterFewIterationsCounter(object):
+    def __init__(self, high, bytestring):
+        self._current = 0
+        self._high = high
+        self._bytestring = bytestring
+
+    def __iter__(self):
+        return self
+
+    def __next__(self):
+        if self._current >= self._high:
+            raise Exception("This is a deliberate failure in a unit test.")
+        else:
+            self._current += 1
+            return self._bytestring
+
+
+def _unary_unary_multi_callable(channel):
+  return channel.unary_unary(_UNARY_UNARY)
+
+
+def _unary_stream_multi_callable(channel):
+  return channel.unary_stream(
+    _UNARY_STREAM,
+    request_serializer=_SERIALIZE_REQUEST,
+    response_deserializer=_DESERIALIZE_RESPONSE)
+
+
+def _stream_unary_multi_callable(channel):
+  return channel.stream_unary(
+    _STREAM_UNARY,
+    request_serializer=_SERIALIZE_REQUEST,
+    response_deserializer=_DESERIALIZE_RESPONSE)
+
+
+def _stream_stream_multi_callable(channel):
+  return channel.stream_stream(_STREAM_STREAM)
+
+
+class InvocationDefectsTest(unittest.TestCase):
+  def setUp(self):
+    self._control = test_control.PauseFailControl()
+    self._handler = _Handler(self._control)
+    self._server_pool = logging_pool.pool(test_constants.THREAD_CONCURRENCY)
+
+    self._server = grpc.server(self._server_pool)
+    port = self._server.add_insecure_port('[::]:0')
+    self._server.add_generic_rpc_handlers((_GenericHandler(self._handler),))
+    self._server.start()
+
+    self._channel = grpc.insecure_channel('localhost:%d' % port)
+
+  def tearDown(self):
+    self._server.stop(0)
+
+  def testIterableStreamRequestBlockingUnaryResponse(self):
+    requests = [b'\x07\x08' for _ in range(test_constants.STREAM_LENGTH)]
+    multi_callable = _stream_unary_multi_callable(self._channel)
+
+    with self.assertRaises(grpc.RpcError):
+      response = multi_callable(
+        requests,
+        metadata=(('test', 'IterableStreamRequestBlockingUnaryResponse'),))
+
+  def testIterableStreamRequestFutureUnaryResponse(self):
+    requests = [b'\x07\x08' for _ in range(test_constants.STREAM_LENGTH)]
+    multi_callable = _stream_unary_multi_callable(self._channel)
+    response_future = multi_callable.future(
+      requests,
+      metadata=(
+        ('test', 'IterableStreamRequestFutureUnaryResponse'),))
+
+    with self.assertRaises(grpc.RpcError):
+      response = response_future.result()
+
+  def testIterableStreamRequestStreamResponse(self):
+    requests = [b'\x77\x58' for _ in range(test_constants.STREAM_LENGTH)]
+    multi_callable = _stream_stream_multi_callable(self._channel)
+    response_iterator = multi_callable(
+      requests,
+      metadata=(('test', 'IterableStreamRequestStreamResponse'),))
+
+    with self.assertRaises(grpc.RpcError):
+      next(response_iterator)
+
+  def testIteratorStreamRequestStreamResponse(self):
+    requests_iterator = FailAfterFewIterationsCounter(
+      test_constants.STREAM_LENGTH // 2, b'\x07\x08')
+    multi_callable = _stream_stream_multi_callable(self._channel)
+    response_iterator = multi_callable(
+      requests_iterator,
+      metadata=(('test', 'IteratorStreamRequestStreamResponse'),))
+
+    with self.assertRaises(grpc.RpcError):
+      for _ in range(test_constants.STREAM_LENGTH // 2 + 1):
+        next(response_iterator)

+ 2 - 2
src/python/grpcio_tests/tests/unit/_metadata_test.py

@@ -193,7 +193,7 @@ class MetadataTest(unittest.TestCase):
   def testStreamUnary(self):
   def testStreamUnary(self):
     multi_callable = self._channel.stream_unary(_STREAM_UNARY)
     multi_callable = self._channel.stream_unary(_STREAM_UNARY)
     unused_response, call = multi_callable.with_call(
     unused_response, call = multi_callable.with_call(
-        [_REQUEST] * test_constants.STREAM_LENGTH,
+        iter([_REQUEST] * test_constants.STREAM_LENGTH),
         metadata=_CLIENT_METADATA)
         metadata=_CLIENT_METADATA)
     self.assertTrue(test_common.metadata_transmitted(
     self.assertTrue(test_common.metadata_transmitted(
         _SERVER_INITIAL_METADATA, call.initial_metadata()))
         _SERVER_INITIAL_METADATA, call.initial_metadata()))
@@ -202,7 +202,7 @@ class MetadataTest(unittest.TestCase):
 
 
   def testStreamStream(self):
   def testStreamStream(self):
     multi_callable = self._channel.stream_stream(_STREAM_STREAM)
     multi_callable = self._channel.stream_stream(_STREAM_STREAM)
-    call = multi_callable([_REQUEST] * test_constants.STREAM_LENGTH,
+    call = multi_callable(iter([_REQUEST] * test_constants.STREAM_LENGTH),
                           metadata=_CLIENT_METADATA)
                           metadata=_CLIENT_METADATA)
     self.assertTrue(test_common.metadata_transmitted(
     self.assertTrue(test_common.metadata_transmitted(
         _SERVER_INITIAL_METADATA, call.initial_metadata()))
         _SERVER_INITIAL_METADATA, call.initial_metadata()))

+ 22 - 7
templates/tools/doxygen/Doxyfile.include

@@ -8,7 +8,10 @@
 <%def name="gen_doxyfile(libnames, packagename, collection, internal)">
 <%def name="gen_doxyfile(libnames, packagename, collection, internal)">
 <%
 <%
   import itertools
   import itertools
+  import glob
+  import os
   targets = []
   targets = []
+  docpackage = packagename.replace('+', 'p').lower()
   for libname in libnames:
   for libname in libnames:
     target = None
     target = None
     for p in collection:
     for p in collection:
@@ -16,6 +19,11 @@
         target = p
         target = p
     assert(target)
     assert(target)
     targets.append(target)
     targets.append(target)
+  srcdoc = []
+  for dirpath, dirnames, filenames in os.walk('src/%s' % docpackage):
+    for filename in filenames:
+      if os.path.splitext(filename)[1] == '.md':
+        srcdoc.append(os.path.join(dirpath, filename))
 %>
 %>
 # Doxyfile 1.8.9.1
 # Doxyfile 1.8.9.1
 
 
@@ -778,13 +786,20 @@ WARN_LOGFILE           =
 # spaces.
 # spaces.
 # Note: If this tag is empty the current directory is searched.
 # Note: If this tag is empty the current directory is searched.
 
 
-INPUT                  = ${' \\\n'.join(
-                               itertools.chain.from_iterable(
-			           target.public_headers +
-				   ([]
-				    if not internal
-				    else target.headers + target.src)
-			       for target in targets))}
+INPUT                  = ${
+    ' \\\n'.join(
+        itertools.chain(
+            itertools.chain.from_iterable(
+    			      target.public_headers +
+    				    ([]
+    				     if not internal
+    				     else target.headers + target.src)
+    			      for target in targets),
+            glob.glob('doc/*.md'),
+            glob.glob('doc/%s/*.md' % docpackage),
+            [] if not internal else srcdoc)
+    )
+}
 
 
 # This tag can be used to specify the character encoding of the source files
 # This tag can be used to specify the character encoding of the source files
 # that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses
 # that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses

+ 10 - 8
test/core/end2end/fuzzers/api_fuzzer.c

@@ -369,10 +369,11 @@ void my_resolve_address(grpc_exec_ctx *exec_ctx, const char *addr,
   r->addr = gpr_strdup(addr);
   r->addr = gpr_strdup(addr);
   r->on_done = on_done;
   r->on_done = on_done;
   r->addrs = addresses;
   r->addrs = addresses;
-  grpc_timer_init(exec_ctx, &r->timer,
-                  gpr_time_add(gpr_now(GPR_CLOCK_MONOTONIC),
-                               gpr_time_from_seconds(1, GPR_TIMESPAN)),
-                  finish_resolve, r, gpr_now(GPR_CLOCK_MONOTONIC));
+  grpc_timer_init(
+      exec_ctx, &r->timer, gpr_time_add(gpr_now(GPR_CLOCK_MONOTONIC),
+                                        gpr_time_from_seconds(1, GPR_TIMESPAN)),
+      grpc_closure_create(finish_resolve, r, grpc_schedule_on_exec_ctx),
+      gpr_now(GPR_CLOCK_MONOTONIC));
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////////////////
@@ -430,10 +431,11 @@ static void sched_connect(grpc_exec_ctx *exec_ctx, grpc_closure *closure,
   fc->closure = closure;
   fc->closure = closure;
   fc->ep = ep;
   fc->ep = ep;
   fc->deadline = deadline;
   fc->deadline = deadline;
-  grpc_timer_init(exec_ctx, &fc->timer,
-                  gpr_time_add(gpr_now(GPR_CLOCK_MONOTONIC),
-                               gpr_time_from_millis(1, GPR_TIMESPAN)),
-                  do_connect, fc, gpr_now(GPR_CLOCK_MONOTONIC));
+  grpc_timer_init(
+      exec_ctx, &fc->timer, gpr_time_add(gpr_now(GPR_CLOCK_MONOTONIC),
+                                         gpr_time_from_millis(1, GPR_TIMESPAN)),
+      grpc_closure_create(do_connect, fc, grpc_schedule_on_exec_ctx),
+      gpr_now(GPR_CLOCK_MONOTONIC));
 }
 }
 
 
 static void my_tcp_client_connect(grpc_exec_ctx *exec_ctx,
 static void my_tcp_client_connect(grpc_exec_ctx *exec_ctx,

+ 28 - 15
test/core/iomgr/timer_list_test.c

@@ -57,17 +57,20 @@ static void add_test(void) {
 
 
   /* 10 ms timers.  will expire in the current epoch */
   /* 10 ms timers.  will expire in the current epoch */
   for (i = 0; i < 10; i++) {
   for (i = 0; i < 10; i++) {
-    grpc_timer_init(&exec_ctx, &timers[i],
-                    gpr_time_add(start, gpr_time_from_millis(10, GPR_TIMESPAN)),
-                    cb, (void *)(intptr_t)i, start);
+    grpc_timer_init(
+        &exec_ctx, &timers[i],
+        gpr_time_add(start, gpr_time_from_millis(10, GPR_TIMESPAN)),
+        grpc_closure_create(cb, (void *)(intptr_t)i, grpc_schedule_on_exec_ctx),
+        start);
   }
   }
 
 
   /* 1010 ms timers.  will expire in the next epoch */
   /* 1010 ms timers.  will expire in the next epoch */
   for (i = 10; i < 20; i++) {
   for (i = 10; i < 20; i++) {
     grpc_timer_init(
     grpc_timer_init(
         &exec_ctx, &timers[i],
         &exec_ctx, &timers[i],
-        gpr_time_add(start, gpr_time_from_millis(1010, GPR_TIMESPAN)), cb,
-        (void *)(intptr_t)i, start);
+        gpr_time_add(start, gpr_time_from_millis(1010, GPR_TIMESPAN)),
+        grpc_closure_create(cb, (void *)(intptr_t)i, grpc_schedule_on_exec_ctx),
+        start);
   }
   }
 
 
   /* collect timers.  Only the first batch should be ready. */
   /* collect timers.  Only the first batch should be ready. */
@@ -125,16 +128,26 @@ void destruction_test(void) {
   grpc_timer_list_init(gpr_time_0(GPR_CLOCK_REALTIME));
   grpc_timer_list_init(gpr_time_0(GPR_CLOCK_REALTIME));
   memset(cb_called, 0, sizeof(cb_called));
   memset(cb_called, 0, sizeof(cb_called));
 
 
-  grpc_timer_init(&exec_ctx, &timers[0], tfm(100), cb, (void *)(intptr_t)0,
-                  gpr_time_0(GPR_CLOCK_REALTIME));
-  grpc_timer_init(&exec_ctx, &timers[1], tfm(3), cb, (void *)(intptr_t)1,
-                  gpr_time_0(GPR_CLOCK_REALTIME));
-  grpc_timer_init(&exec_ctx, &timers[2], tfm(100), cb, (void *)(intptr_t)2,
-                  gpr_time_0(GPR_CLOCK_REALTIME));
-  grpc_timer_init(&exec_ctx, &timers[3], tfm(3), cb, (void *)(intptr_t)3,
-                  gpr_time_0(GPR_CLOCK_REALTIME));
-  grpc_timer_init(&exec_ctx, &timers[4], tfm(1), cb, (void *)(intptr_t)4,
-                  gpr_time_0(GPR_CLOCK_REALTIME));
+  grpc_timer_init(
+      &exec_ctx, &timers[0], tfm(100),
+      grpc_closure_create(cb, (void *)(intptr_t)0, grpc_schedule_on_exec_ctx),
+      gpr_time_0(GPR_CLOCK_REALTIME));
+  grpc_timer_init(
+      &exec_ctx, &timers[1], tfm(3),
+      grpc_closure_create(cb, (void *)(intptr_t)1, grpc_schedule_on_exec_ctx),
+      gpr_time_0(GPR_CLOCK_REALTIME));
+  grpc_timer_init(
+      &exec_ctx, &timers[2], tfm(100),
+      grpc_closure_create(cb, (void *)(intptr_t)2, grpc_schedule_on_exec_ctx),
+      gpr_time_0(GPR_CLOCK_REALTIME));
+  grpc_timer_init(
+      &exec_ctx, &timers[3], tfm(3),
+      grpc_closure_create(cb, (void *)(intptr_t)3, grpc_schedule_on_exec_ctx),
+      gpr_time_0(GPR_CLOCK_REALTIME));
+  grpc_timer_init(
+      &exec_ctx, &timers[4], tfm(1),
+      grpc_closure_create(cb, (void *)(intptr_t)4, grpc_schedule_on_exec_ctx),
+      gpr_time_0(GPR_CLOCK_REALTIME));
   GPR_ASSERT(1 == grpc_timer_check(&exec_ctx, tfm(2), NULL));
   GPR_ASSERT(1 == grpc_timer_check(&exec_ctx, tfm(2), NULL));
   grpc_exec_ctx_finish(&exec_ctx);
   grpc_exec_ctx_finish(&exec_ctx);
   GPR_ASSERT(1 == cb_called[4][1]);
   GPR_ASSERT(1 == cb_called[4][1]);

+ 29 - 1
tools/doxygen/Doxyfile.c++

@@ -848,7 +848,35 @@ include/grpc/impl/codegen/slice.h \
 include/grpc/impl/codegen/sync.h \
 include/grpc/impl/codegen/sync.h \
 include/grpc/impl/codegen/sync_generic.h \
 include/grpc/impl/codegen/sync_generic.h \
 include/grpc/impl/codegen/sync_posix.h \
 include/grpc/impl/codegen/sync_posix.h \
-include/grpc/impl/codegen/sync_windows.h
+include/grpc/impl/codegen/sync_windows.h \
+doc/fail_fast.md \
+doc/compression.md \
+doc/environment_variables.md \
+doc/stress_test_framework.md \
+doc/PROTOCOL-WEB.md \
+doc/cpp-style-guide.md \
+doc/http-grpc-status-mapping.md \
+doc/wait-for-ready.md \
+doc/command_line_tool.md \
+doc/c-style-guide.md \
+doc/server_reflection_tutorial.md \
+doc/health-checking.md \
+doc/connection-backoff-interop-test-description.md \
+doc/epoll-polling-engine.md \
+doc/naming.md \
+doc/binary-logging.md \
+doc/connectivity-semantics-and-api.md \
+doc/connection-backoff.md \
+doc/compression_cookbook.md \
+doc/PROTOCOL-HTTP2.md \
+doc/load-balancing.md \
+doc/negative-http2-interop-test-descriptions.md \
+doc/server-reflection.md \
+doc/interop-test-descriptions.md \
+doc/statuscodes.md \
+doc/g_stands_for.md \
+doc/cpp/perf_notes.md \
+doc/cpp/pending_api_cleanups.md
 
 
 # This tag can be used to specify the character encoding of the source files
 # This tag can be used to specify the character encoding of the source files
 # that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses
 # that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses

+ 30 - 1
tools/doxygen/Doxyfile.c++.internal

@@ -894,7 +894,36 @@ src/cpp/util/slice_cc.cc \
 src/cpp/util/status.cc \
 src/cpp/util/status.cc \
 src/cpp/util/string_ref.cc \
 src/cpp/util/string_ref.cc \
 src/cpp/util/time_cc.cc \
 src/cpp/util/time_cc.cc \
-src/cpp/codegen/codegen_init.cc
+src/cpp/codegen/codegen_init.cc \
+doc/fail_fast.md \
+doc/compression.md \
+doc/environment_variables.md \
+doc/stress_test_framework.md \
+doc/PROTOCOL-WEB.md \
+doc/cpp-style-guide.md \
+doc/http-grpc-status-mapping.md \
+doc/wait-for-ready.md \
+doc/command_line_tool.md \
+doc/c-style-guide.md \
+doc/server_reflection_tutorial.md \
+doc/health-checking.md \
+doc/connection-backoff-interop-test-description.md \
+doc/epoll-polling-engine.md \
+doc/naming.md \
+doc/binary-logging.md \
+doc/connectivity-semantics-and-api.md \
+doc/connection-backoff.md \
+doc/compression_cookbook.md \
+doc/PROTOCOL-HTTP2.md \
+doc/load-balancing.md \
+doc/negative-http2-interop-test-descriptions.md \
+doc/server-reflection.md \
+doc/interop-test-descriptions.md \
+doc/statuscodes.md \
+doc/g_stands_for.md \
+doc/cpp/perf_notes.md \
+doc/cpp/pending_api_cleanups.md \
+src/cpp/README.md
 
 
 # This tag can be used to specify the character encoding of the source files
 # This tag can be used to specify the character encoding of the source files
 # that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses
 # that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses

+ 28 - 1
tools/doxygen/Doxyfile.core

@@ -827,7 +827,34 @@ include/grpc/impl/codegen/slice.h \
 include/grpc/impl/codegen/sync.h \
 include/grpc/impl/codegen/sync.h \
 include/grpc/impl/codegen/sync_generic.h \
 include/grpc/impl/codegen/sync_generic.h \
 include/grpc/impl/codegen/sync_posix.h \
 include/grpc/impl/codegen/sync_posix.h \
-include/grpc/impl/codegen/sync_windows.h
+include/grpc/impl/codegen/sync_windows.h \
+doc/fail_fast.md \
+doc/compression.md \
+doc/environment_variables.md \
+doc/stress_test_framework.md \
+doc/PROTOCOL-WEB.md \
+doc/cpp-style-guide.md \
+doc/http-grpc-status-mapping.md \
+doc/wait-for-ready.md \
+doc/command_line_tool.md \
+doc/c-style-guide.md \
+doc/server_reflection_tutorial.md \
+doc/health-checking.md \
+doc/connection-backoff-interop-test-description.md \
+doc/epoll-polling-engine.md \
+doc/naming.md \
+doc/binary-logging.md \
+doc/connectivity-semantics-and-api.md \
+doc/connection-backoff.md \
+doc/compression_cookbook.md \
+doc/PROTOCOL-HTTP2.md \
+doc/load-balancing.md \
+doc/negative-http2-interop-test-descriptions.md \
+doc/server-reflection.md \
+doc/interop-test-descriptions.md \
+doc/statuscodes.md \
+doc/g_stands_for.md \
+doc/core/pending_api_cleanups.md
 
 
 # This tag can be used to specify the character encoding of the source files
 # This tag can be used to specify the character encoding of the source files
 # that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses
 # that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses

+ 49 - 1
tools/doxygen/Doxyfile.core.internal

@@ -1278,7 +1278,55 @@ src/core/lib/support/tls_pthread.c \
 src/core/lib/support/tmpfile_msys.c \
 src/core/lib/support/tmpfile_msys.c \
 src/core/lib/support/tmpfile_posix.c \
 src/core/lib/support/tmpfile_posix.c \
 src/core/lib/support/tmpfile_windows.c \
 src/core/lib/support/tmpfile_windows.c \
-src/core/lib/support/wrap_memcpy.c
+src/core/lib/support/wrap_memcpy.c \
+doc/fail_fast.md \
+doc/compression.md \
+doc/environment_variables.md \
+doc/stress_test_framework.md \
+doc/PROTOCOL-WEB.md \
+doc/cpp-style-guide.md \
+doc/http-grpc-status-mapping.md \
+doc/wait-for-ready.md \
+doc/command_line_tool.md \
+doc/c-style-guide.md \
+doc/server_reflection_tutorial.md \
+doc/health-checking.md \
+doc/connection-backoff-interop-test-description.md \
+doc/epoll-polling-engine.md \
+doc/naming.md \
+doc/binary-logging.md \
+doc/connectivity-semantics-and-api.md \
+doc/connection-backoff.md \
+doc/compression_cookbook.md \
+doc/PROTOCOL-HTTP2.md \
+doc/load-balancing.md \
+doc/negative-http2-interop-test-descriptions.md \
+doc/server-reflection.md \
+doc/interop-test-descriptions.md \
+doc/statuscodes.md \
+doc/g_stands_for.md \
+doc/core/pending_api_cleanups.md \
+src/core/README.md \
+src/core/ext/README.md \
+src/core/ext/transport/README.md \
+src/core/ext/transport/chttp2/README.md \
+src/core/ext/transport/chttp2/client/secure/README.md \
+src/core/ext/transport/chttp2/client/insecure/README.md \
+src/core/ext/transport/chttp2/transport/README.md \
+src/core/ext/transport/chttp2/server/secure/README.md \
+src/core/ext/transport/chttp2/server/insecure/README.md \
+src/core/ext/client_channel/README.md \
+src/core/ext/resolver/README.md \
+src/core/ext/resolver/sockaddr/README.md \
+src/core/ext/resolver/dns/native/README.md \
+src/core/ext/census/README.md \
+src/core/ext/census/gen/README.md \
+src/core/lib/README.md \
+src/core/lib/tsi/README.md \
+src/core/lib/channel/README.md \
+src/core/lib/transport/README.md \
+src/core/lib/iomgr/README.md \
+src/core/lib/surface/README.md
 
 
 # This tag can be used to specify the character encoding of the source files
 # This tag can be used to specify the character encoding of the source files
 # that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses
 # that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses

+ 4 - 0
tools/run_tests/README.md

@@ -22,6 +22,10 @@ The script is also capable of running interop tests for grpc-java and grpc-go, u
 ######Example
 ######Example
 `tools/run_tests/run_interop_tests.py -l csharp -s c++ --use_docker` (run interop tests with C# client and C++ server)
 `tools/run_tests/run_interop_tests.py -l csharp -s c++ --use_docker` (run interop tests with C# client and C++ server)
 
 
+Note: if you see an error like `no space left on device` when running the
+interop tests using Docker, make sure that Docker is building the image files in
+a location with sufficient disk space.
+
 #Performance benchmarks (run_performance_tests.py)
 #Performance benchmarks (run_performance_tests.py)
 
 
 Runs predefined benchmark scenarios for given languages. Besides the simple configuration of running all the scenarios locally,
 Runs predefined benchmark scenarios for given languages. Besides the simple configuration of running all the scenarios locally,

+ 2 - 2
tools/run_tests/run_interop_tests.py

@@ -179,10 +179,10 @@ class JavaLanguage:
     return {}
     return {}
 
 
   def unimplemented_test_cases(self):
   def unimplemented_test_cases(self):
-    return _SKIP_ADVANCED + _SKIP_COMPRESSION
+    return _SKIP_COMPRESSION
 
 
   def unimplemented_test_cases_server(self):
   def unimplemented_test_cases_server(self):
-    return _SKIP_ADVANCED + _SKIP_COMPRESSION
+    return _SKIP_COMPRESSION
 
 
   def __str__(self):
   def __str__(self):
     return 'java'
     return 'java'

+ 1 - 1
vsprojects/README.md

@@ -2,7 +2,7 @@ This directory contains MS Visual Studio project & solution files.
 
 
 #Supported Visual Studio versions
 #Supported Visual Studio versions
 
 
-Currently supported versions are Visual Studio 2013 (our primary focus) and 2010.
+Currently supported versions are Visual Studio 2013 (our primary focus).
 
 
 #Building
 #Building
 We are using [NuGet](http://www.nuget.org) to pull zlib and openssl dependencies.
 We are using [NuGet](http://www.nuget.org) to pull zlib and openssl dependencies.

+ 0 - 39
vsprojects/build_vs2010.bat

@@ -1,39 +0,0 @@
-@rem Copyright 2016, Google Inc.
-@rem All rights reserved.
-@rem
-@rem Redistribution and use in source and binary forms, with or without
-@rem modification, are permitted provided that the following conditions are
-@rem met:
-@rem
-@rem     * Redistributions of source code must retain the above copyright
-@rem notice, this list of conditions and the following disclaimer.
-@rem     * Redistributions in binary form must reproduce the above
-@rem copyright notice, this list of conditions and the following disclaimer
-@rem in the documentation and/or other materials provided with the
-@rem distribution.
-@rem     * Neither the name of Google Inc. nor the names of its
-@rem contributors may be used to endorse or promote products derived from
-@rem this software without specific prior written permission.
-@rem
-@rem THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-@rem "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-@rem LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-@rem A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-@rem OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-@rem SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-@rem LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-@rem DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-@rem THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-@rem (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-@rem OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-@rem Convenience wrapper that runs specified gRPC target using msbuild
-@rem Usage: build_vs2010.bat TARGET_NAME
-
-setlocal
-@rem Set VS variables (uses Visual Studio 2010)
-@call "%VS100COMNTOOLS%\..\..\vc\vcvarsall.bat" x86
-
-msbuild %*
-exit /b %ERRORLEVEL%
-endlocal

+ 2 - 2
vsprojects/coapp/zlib/README.md

@@ -10,7 +10,7 @@ Multiple versions of VS installed to be able to build all the targets:
 * Visual Studio 2013
 * Visual Studio 2013
 * Visual Studio 2010 (you might need SP1 to prevent LNK1123 error)
 * Visual Studio 2010 (you might need SP1 to prevent LNK1123 error)
 
 
-CoApp toolkit: http://downloads.coapp.org/files/CoApp.Tools.Powershell.msi
+CoApp toolkit: http://coapp.org/files/CoApp.Tools.Powershell.msi
 
 
 More details on installation: http://coapp.org/tutorials/installation.html
 More details on installation: http://coapp.org/tutorials/installation.html
 
 
@@ -33,4 +33,4 @@ This will create three NuGet packages:
 * the symbols package (debug symbols)
 * the symbols package (debug symbols)
 
 
 Later, you can push the package to NuGet.org repo.
 Later, you can push the package to NuGet.org repo.
-Attention: before pusing the resulting nuget package to public nuget repo, you have to be 100% sure it works correctly - theres no way how to delete or update an already existing package.
+Attention: before pusing the resulting nuget package to public nuget repo, you have to be 100% sure it works correctly - there’s no way how to delete or update an already existing package.