Merge branch 'master' into debug_qps_stream

pull/5444/head
vjpai 9 years ago
commit b7117e409b
  1. 2
      BUILD
  2. 2
      Makefile
  3. 1
      build.yaml
  4. 3
      config.m4
  5. 4
      doc/health-checking.md
  6. 1
      grpc.def
  7. 17
      include/grpc++/alarm.h
  8. 82
      include/grpc/census.h
  9. 4
      include/grpc/impl/codegen/sync.h
  10. 25
      package.xml
  11. 149
      src/core/census/context.c
  12. 31
      src/core/channel/client_channel.c
  13. 21
      src/core/client_config/lb_policies/pick_first.c
  14. 15
      src/core/client_config/lb_policies/round_robin.c
  15. 6
      src/core/client_config/lb_policy.c
  16. 5
      src/core/client_config/lb_policy.h
  17. 24
      src/core/client_config/subchannel.c
  18. 24
      src/core/httpcli/httpcli.c
  19. 5
      src/core/httpcli/httpcli.h
  20. 14
      src/core/httpcli/httpcli_security_connector.c
  21. 6
      src/core/iomgr/fd_posix.c
  22. 16
      src/core/iomgr/iomgr.c
  23. 6
      src/core/iomgr/iomgr_internal.h
  24. 19
      src/core/iomgr/pollset.h
  25. 1
      src/core/iomgr/pollset_multipoller_with_epoll.c
  26. 8
      src/core/iomgr/pollset_multipoller_with_poll_posix.c
  27. 54
      src/core/iomgr/pollset_posix.c
  28. 12
      src/core/iomgr/pollset_posix.h
  29. 12
      src/core/iomgr/pollset_set.h
  30. 26
      src/core/iomgr/pollset_set_posix.c
  31. 20
      src/core/iomgr/pollset_set_posix.h
  32. 6
      src/core/iomgr/pollset_set_windows.c
  33. 4
      src/core/iomgr/pollset_set_windows.h
  34. 41
      src/core/iomgr/pollset_windows.c
  35. 6
      src/core/iomgr/pollset_windows.h
  36. 12
      src/core/iomgr/tcp_client_posix.c
  37. 6
      src/core/iomgr/tcp_posix.c
  38. 1
      src/core/iomgr/udp_server.h
  39. 1
      src/core/iomgr/workqueue_posix.c
  40. 4
      src/core/iomgr/workqueue_posix.h
  41. 1
      src/core/security/client_auth_filter.c
  42. 6
      src/core/security/credentials.c
  43. 6
      src/core/security/credentials.h
  44. 41
      src/core/security/google_default_credentials.c
  45. 22
      src/core/security/handshake.c
  46. 3
      src/core/security/handshake.h
  47. 125
      src/core/security/security_connector.c
  48. 64
      src/core/security/security_connector.h
  49. 14
      src/core/security/server_secure_chttp2.c
  50. 7
      src/core/support/sync.c
  51. 5
      src/core/surface/alarm.c
  52. 96
      src/core/surface/completion_queue.c
  53. 11
      src/core/surface/secure_channel_create.c
  54. 18
      src/core/transport/chttp2/internal.h
  55. 6
      src/core/transport/chttp2/parsing.c
  56. 38
      src/core/transport/chttp2/stream_lists.c
  57. 37
      src/core/transport/chttp2/writing.c
  58. 43
      src/core/transport/chttp2_transport.c
  59. 8
      src/core/transport/metadata.c
  60. 2
      src/core/transport/transport.c
  61. 51
      src/cpp/common/alarm.cc
  62. 10
      src/csharp/Grpc.Core/Internal/AsyncCallServer.cs
  63. 14
      src/csharp/Grpc.HealthCheck.Tests/HealthClientServerTest.cs
  64. 48
      src/csharp/Grpc.HealthCheck.Tests/HealthServiceImplTest.cs
  65. 2
      src/csharp/Grpc.HealthCheck/Grpc.HealthCheck.nuspec
  66. 72
      src/csharp/Grpc.HealthCheck/Health.cs
  67. 30
      src/csharp/Grpc.HealthCheck/HealthGrpc.cs
  68. 46
      src/csharp/Grpc.HealthCheck/HealthServiceImpl.cs
  69. 4
      src/csharp/Grpc.IntegrationTesting/InteropClientServerTest.cs
  70. 17
      src/csharp/Grpc.Tools.nuspec
  71. 17
      src/csharp/build_packages.bat
  72. 2
      src/csharp/generate_proto_csharp.sh
  73. 6
      src/node/health_check/health.js
  74. 31
      src/objective-c/tests/GRPCClientTests.m
  75. 36
      src/php/README.md
  76. 7
      src/proto/grpc/health/v1/health.proto
  77. 14
      src/python/grpcio/README.rst
  78. 9
      src/python/grpcio/grpc/_cython/_cygrpc/channel.pyx.pxi
  79. 7
      src/python/grpcio/grpc/_cython/_cygrpc/completion_queue.pxd.pxi
  80. 52
      src/python/grpcio/grpc/_cython/_cygrpc/completion_queue.pyx.pxi
  81. 2
      src/python/grpcio/grpc/_cython/_cygrpc/grpc.pxi
  82. 3
      src/python/grpcio/grpc/_cython/_cygrpc/server.pxd.pxi
  83. 23
      src/python/grpcio/grpc/_cython/_cygrpc/server.pyx.pxi
  84. 2
      src/python/grpcio/grpc/_cython/imports.generated.c
  85. 7
      src/python/grpcio/grpc/_cython/imports.generated.h
  86. 2
      src/python/grpcio_health_checking/grpc/health/v1/__init__.py
  87. 4
      src/python/grpcio_health_checking/grpc/health/v1/health.proto
  88. 6
      src/python/grpcio_health_checking/grpc/health/v1/health.py
  89. 2
      src/ruby/.rubocop.yml
  90. 2
      src/ruby/ext/grpc/rb_grpc_imports.generated.c
  91. 7
      src/ruby/ext/grpc/rb_grpc_imports.generated.h
  92. 4
      src/ruby/pb/README.md
  93. 4
      src/ruby/pb/generate_proto_ruby.sh
  94. 22
      src/ruby/pb/grpc/health/checker.rb
  95. 28
      src/ruby/pb/grpc/health/v1/health.rb
  96. 8
      src/ruby/pb/grpc/health/v1/health_services.rb
  97. 29
      src/ruby/pb/grpc/health/v1alpha/health.rb
  98. 58
      src/ruby/spec/pb/health/checker_spec.rb
  99. 111
      templates/README.md
  100. 3
      templates/config.m4.template
  101. Some files were not shown because too many files have changed in this diff Show More

@ -818,7 +818,6 @@ cc_library(
"src/cpp/client/credentials.cc", "src/cpp/client/credentials.cc",
"src/cpp/client/generic_stub.cc", "src/cpp/client/generic_stub.cc",
"src/cpp/client/insecure_credentials.cc", "src/cpp/client/insecure_credentials.cc",
"src/cpp/common/alarm.cc",
"src/cpp/common/call.cc", "src/cpp/common/call.cc",
"src/cpp/common/channel_arguments.cc", "src/cpp/common/channel_arguments.cc",
"src/cpp/common/completion_queue.cc", "src/cpp/common/completion_queue.cc",
@ -942,7 +941,6 @@ cc_library(
"src/cpp/client/credentials.cc", "src/cpp/client/credentials.cc",
"src/cpp/client/generic_stub.cc", "src/cpp/client/generic_stub.cc",
"src/cpp/client/insecure_credentials.cc", "src/cpp/client/insecure_credentials.cc",
"src/cpp/common/alarm.cc",
"src/cpp/common/call.cc", "src/cpp/common/call.cc",
"src/cpp/common/channel_arguments.cc", "src/cpp/common/channel_arguments.cc",
"src/cpp/common/completion_queue.cc", "src/cpp/common/completion_queue.cc",

@ -2990,7 +2990,6 @@ LIBGRPC++_SRC = \
src/cpp/client/credentials.cc \ src/cpp/client/credentials.cc \
src/cpp/client/generic_stub.cc \ src/cpp/client/generic_stub.cc \
src/cpp/client/insecure_credentials.cc \ src/cpp/client/insecure_credentials.cc \
src/cpp/common/alarm.cc \
src/cpp/common/call.cc \ src/cpp/common/call.cc \
src/cpp/common/channel_arguments.cc \ src/cpp/common/channel_arguments.cc \
src/cpp/common/completion_queue.cc \ src/cpp/common/completion_queue.cc \
@ -3271,7 +3270,6 @@ LIBGRPC++_UNSECURE_SRC = \
src/cpp/client/credentials.cc \ src/cpp/client/credentials.cc \
src/cpp/client/generic_stub.cc \ src/cpp/client/generic_stub.cc \
src/cpp/client/insecure_credentials.cc \ src/cpp/client/insecure_credentials.cc \
src/cpp/common/alarm.cc \
src/cpp/common/call.cc \ src/cpp/common/call.cc \
src/cpp/common/channel_arguments.cc \ src/cpp/common/channel_arguments.cc \
src/cpp/common/completion_queue.cc \ src/cpp/common/completion_queue.cc \

@ -184,7 +184,6 @@ filegroups:
- src/cpp/client/credentials.cc - src/cpp/client/credentials.cc
- src/cpp/client/generic_stub.cc - src/cpp/client/generic_stub.cc
- src/cpp/client/insecure_credentials.cc - src/cpp/client/insecure_credentials.cc
- src/cpp/common/alarm.cc
- src/cpp/common/call.cc - src/cpp/common/call.cc
- src/cpp/common/channel_arguments.cc - src/cpp/common/channel_arguments.cc
- src/cpp/common/completion_queue.cc - src/cpp/common/completion_queue.cc

@ -533,7 +533,8 @@ if test "$PHP_GRPC" != "no"; then
third_party/boringssl/ssl/t1_enc.c \ third_party/boringssl/ssl/t1_enc.c \
third_party/boringssl/ssl/t1_lib.c \ third_party/boringssl/ssl/t1_lib.c \
third_party/boringssl/ssl/tls_record.c \ third_party/boringssl/ssl/tls_record.c \
, $ext_shared, , -Wall -Werror -std=c11 \ , $ext_shared, , -Wall -Werror \
-Wno-parentheses-equality -Wno-unused-value -std=c11 \
-fvisibility=hidden -DOPENSSL_NO_ASM -D_GNU_SOURCE -DWIN32_LEAN_AND_MEAN \ -fvisibility=hidden -DOPENSSL_NO_ASM -D_GNU_SOURCE -DWIN32_LEAN_AND_MEAN \
-D_HAS_EXCEPTIONS=0 -DNOMINMAX) -D_HAS_EXCEPTIONS=0 -DNOMINMAX)

@ -26,7 +26,7 @@ The server should export a service defined in the following proto:
``` ```
syntax = "proto3"; syntax = "proto3";
package grpc.health.v1alpha; package grpc.health.v1;
message HealthCheckRequest { message HealthCheckRequest {
string service = 1; string service = 1;
@ -49,7 +49,7 @@ service Health {
A client can query the server’s health status by calling the `Check` method, and A client can query the server’s health status by calling the `Check` method, and
a deadline should be set on the rpc. The client can optionally set the service a deadline should be set on the rpc. The client can optionally set the service
name it wants to query for health status. The suggested format of service name name it wants to query for health status. The suggested format of service name
is `package_names.ServiceName`, such as `grpc.health.v1alpha.Health`. is `package_names.ServiceName`, such as `grpc.health.v1.Health`.
The server should register all the services manually and set The server should register all the services manually and set
the individual status, including an empty service name and its status. For each the individual status, including an empty service name and its status. For each

@ -182,6 +182,7 @@ EXPORTS
gpr_event_wait gpr_event_wait
gpr_ref_init gpr_ref_init
gpr_ref gpr_ref
gpr_ref_non_zero
gpr_refn gpr_refn
gpr_unref gpr_unref
gpr_stats_init gpr_stats_init

@ -36,9 +36,12 @@
#ifndef GRPCXX_ALARM_H #ifndef GRPCXX_ALARM_H
#define GRPCXX_ALARM_H #define GRPCXX_ALARM_H
#include <grpc++/impl/codegen/completion_queue.h>
#include <grpc++/impl/codegen/completion_queue_tag.h> #include <grpc++/impl/codegen/completion_queue_tag.h>
#include <grpc++/impl/codegen/grpc_library.h> #include <grpc++/impl/codegen/grpc_library.h>
#include <grpc++/impl/codegen/time.h> #include <grpc++/impl/codegen/time.h>
#include <grpc++/impl/grpc_library.h>
#include <grpc/grpc.h>
struct grpc_alarm; struct grpc_alarm;
@ -54,14 +57,22 @@ class Alarm : private GrpcLibrary {
/// Once the alarm expires (at \a deadline) or it's cancelled (see \a Cancel), /// Once the alarm expires (at \a deadline) or it's cancelled (see \a Cancel),
/// an event with tag \a tag will be added to \a cq. If the alarm expired, the /// an event with tag \a tag will be added to \a cq. If the alarm expired, the
/// event's success bit will be true, false otherwise (ie, upon cancellation). /// event's success bit will be true, false otherwise (ie, upon cancellation).
Alarm(CompletionQueue* cq, gpr_timespec deadline, void* tag); /// \internal We rely on the presence of \a cq for grpc initialization. If \a
/// cq were ever to be removed, a reference to a static
/// internal::GrpcLibraryInitializer instance would need to be introduced
/// here. \endinternal.
template <typename T>
Alarm(CompletionQueue* cq, const T& deadline, void* tag)
: tag_(tag),
alarm_(grpc_alarm_create(cq->cq(), TimePoint<T>(deadline).raw_time(),
static_cast<void*>(&tag_))) {}
/// Destroy the given completion queue alarm, cancelling it in the process. /// Destroy the given completion queue alarm, cancelling it in the process.
~Alarm(); ~Alarm() { grpc_alarm_destroy(alarm_); }
/// Cancel a completion queue alarm. Calling this function over an alarm that /// Cancel a completion queue alarm. Calling this function over an alarm that
/// has already fired has no effect. /// has already fired has no effect.
void Cancel(); void Cancel() { grpc_alarm_cancel(alarm_); }
private: private:
class AlarmEntry : public CompletionQueueTag { class AlarmEntry : public CompletionQueueTag {

@ -80,18 +80,18 @@ CENSUSAPI int census_enabled(void);
metrics will be recorded. Keys are unique within a context. */ metrics will be recorded. Keys are unique within a context. */
typedef struct census_context census_context; typedef struct census_context census_context;
/* A tag is a key:value pair. The key is a non-empty, printable (UTF-8 /* A tag is a key:value pair. Both keys and values are nil-terminated strings,
encoded), nil-terminated string. The value is a binary string, that may be containing printable ASCII characters (decimal 32-126). Keys must be at
printable. There are limits on the sizes of both keys and values (see least one character in length. Both keys and values can have at most
CENSUS_MAX_TAG_KB_LEN definition below), and the number of tags that can be CENSUS_MAX_TAG_KB_LEN characters (including the terminating nil). The
propagated (CENSUS_MAX_PROPAGATED_TAGS). Users should also remember that maximum number of tags that can be propagated is
some systems may have limits on, e.g., the number of bytes that can be CENSUS_MAX_PROPAGATED_TAGS. Users should also remember that some systems
transmitted as metadata, and that larger tags means more memory consumed may have limits on, e.g., the number of bytes that can be transmitted as
and time in processing. */ metadata, and that larger tags means more memory consumed and time in
processing. */
typedef struct { typedef struct {
const char *key; const char *key;
const char *value; const char *value;
size_t value_len;
uint8_t flags; uint8_t flags;
} census_tag; } census_tag;
@ -103,28 +103,25 @@ typedef struct {
/* Tag flags. */ /* Tag flags. */
#define CENSUS_TAG_PROPAGATE 1 /* Tag should be propagated over RPC */ #define CENSUS_TAG_PROPAGATE 1 /* Tag should be propagated over RPC */
#define CENSUS_TAG_STATS 2 /* Tag will be used for statistics aggregation */ #define CENSUS_TAG_STATS 2 /* Tag will be used for statistics aggregation */
#define CENSUS_TAG_BINARY 4 /* Tag value is not printable */ #define CENSUS_TAG_RESERVED 4 /* Reserved for internal use. */
#define CENSUS_TAG_RESERVED 8 /* Reserved for internal use. */ /* Flag values 4,8,16,32,64,128 are reserved for future/internal use. Clients
/* Flag values 8,16,32,64,128 are reserved for future/internal use. Clients
should not use or rely on their values. */ should not use or rely on their values. */
#define CENSUS_TAG_IS_PROPAGATED(flags) (flags & CENSUS_TAG_PROPAGATE) #define CENSUS_TAG_IS_PROPAGATED(flags) (flags & CENSUS_TAG_PROPAGATE)
#define CENSUS_TAG_IS_STATS(flags) (flags & CENSUS_TAG_STATS) #define CENSUS_TAG_IS_STATS(flags) (flags & CENSUS_TAG_STATS)
#define CENSUS_TAG_IS_BINARY(flags) (flags & CENSUS_TAG_BINARY)
/* An instance of this structure is kept by every context, and records the /* An instance of this structure is kept by every context, and records the
basic information associated with the creation of that context. */ basic information associated with the creation of that context. */
typedef struct { typedef struct {
int n_propagated_tags; /* number of propagated printable tags */ int n_propagated_tags; /* number of propagated tags */
int n_propagated_binary_tags; /* number of propagated binary tags */ int n_local_tags; /* number of non-propagated (local) tags */
int n_local_tags; /* number of non-propagated (local) tags */ int n_deleted_tags; /* number of tags that were deleted */
int n_deleted_tags; /* number of tags that were deleted */ int n_added_tags; /* number of tags that were added */
int n_added_tags; /* number of tags that were added */ int n_modified_tags; /* number of tags that were modified */
int n_modified_tags; /* number of tags that were modified */ int n_invalid_tags; /* number of tags with bad keys or values (e.g.
int n_invalid_tags; /* number of tags with bad keys or values (e.g. longer than CENSUS_MAX_TAG_KV_LEN) */
longer than CENSUS_MAX_TAG_KV_LEN) */ int n_ignored_tags; /* number of tags ignored because of
int n_ignored_tags; /* number of tags ignored because of CENSUS_MAX_PROPAGATED_TAGS limit. */
CENSUS_MAX_PROPAGATED_TAGS limit. */
} census_context_status; } census_context_status;
/* Create a new context, adding and removing tags from an existing context. /* Create a new context, adding and removing tags from an existing context.
@ -132,10 +129,10 @@ typedef struct {
to add as many tags in a single operation as is practical for the client. to add as many tags in a single operation as is practical for the client.
@param base Base context to build upon. Can be NULL. @param base Base context to build upon. Can be NULL.
@param tags A set of tags to be added/changed/deleted. Tags with keys that @param tags A set of tags to be added/changed/deleted. Tags with keys that
are in 'tags', but not 'base', are added to the tag set. Keys that are in are in 'tags', but not 'base', are added to the context. Keys that are in
both 'tags' and 'base' will have their value/flags modified. Tags with keys both 'tags' and 'base' will have their value/flags modified. Tags with keys
in both, but with NULL or zero-length values, will be deleted from the tag in both, but with NULL values, will be deleted from the context. Tags with
set. Tags with invalid (too long or short) keys or values will be ignored. invalid (too long or short) keys or values will be ignored.
If adding a tag will result in more than CENSUS_MAX_PROPAGATED_TAGS in either If adding a tag will result in more than CENSUS_MAX_PROPAGATED_TAGS in either
binary or non-binary tags, they will be ignored, as will deletions of binary or non-binary tags, they will be ignored, as will deletions of
tags that don't exist. tags that don't exist.
@ -185,32 +182,19 @@ CENSUSAPI int census_context_get_tag(const census_context *context,
for use by RPC systems only, for purposes of transmitting/receiving contexts. for use by RPC systems only, for purposes of transmitting/receiving contexts.
*/ */
/* Encode a context into a buffer. The propagated tags are encoded into the /* Encode a context into a buffer.
buffer in two regions: one for printable tags, and one for binary tags.
@param context context to be encoded @param context context to be encoded
@param buffer pointer to buffer. This address will be used to encode the @param buffer buffer into which the context will be encoded.
printable tags.
@param buf_size number of available bytes in buffer. @param buf_size number of available bytes in buffer.
@param print_buf_size Will be set to the number of bytes consumed by @return The number of buffer bytes consumed for the encoded context, or
printable tags. zero if the buffer was of insufficient size. */
@param bin_buf_size Will be set to the number of bytes used to encode the CENSUSAPI size_t census_context_encode(const census_context *context,
binary tags. char *buffer, size_t buf_size);
@return A pointer to the binary tag's encoded, or NULL if the buffer was
insufficiently large to hold the encoded tags. Thus, if successful, /* Decode context buffer encoded with census_context_encode(). Returns NULL
printable tags are encoded into
[buffer, buffer + *print_buf_size) and binary tags into
[returned-ptr, returned-ptr + *bin_buf_size) (and the returned
pointer should be buffer + *print_buf_size) */
CENSUSAPI char *census_context_encode(const census_context *context,
char *buffer, size_t buf_size,
size_t *print_buf_size,
size_t *bin_buf_size);
/* Decode context buffers encoded with census_context_encode(). Returns NULL
if there is an error in parsing either buffer. */ if there is an error in parsing either buffer. */
CENSUSAPI census_context *census_context_decode(const char *buffer, size_t size, CENSUSAPI census_context *census_context_decode(const char *buffer,
const char *bin_buffer, size_t size);
size_t bin_size);
/* Distributed traces can have a number of options. */ /* Distributed traces can have a number of options. */
enum census_trace_mask_values { enum census_trace_mask_values {

@ -182,6 +182,10 @@ GPRAPI void gpr_ref_init(gpr_refcount *r, int n);
/* Increment the reference count *r. Requires *r initialized. */ /* Increment the reference count *r. Requires *r initialized. */
GPRAPI void gpr_ref(gpr_refcount *r); GPRAPI void gpr_ref(gpr_refcount *r);
/* Increment the reference count *r. Requires *r initialized.
Crashes if refcount is zero */
GPRAPI void gpr_ref_non_zero(gpr_refcount *r);
/* Increment the reference count *r by n. Requires *r initialized, n > 0. */ /* Increment the reference count *r by n. Requires *r initialized, n > 0. */
GPRAPI void gpr_refn(gpr_refcount *r, int n); GPRAPI void gpr_refn(gpr_refcount *r, int n);

@ -10,11 +10,11 @@
<email>grpc-packages@google.com</email> <email>grpc-packages@google.com</email>
<active>yes</active> <active>yes</active>
</lead> </lead>
<date>2016-02-25</date> <date>2016-03-01</date>
<time>16:06:07</time> <time>16:06:07</time>
<version> <version>
<release>0.8.0</release> <release>0.14.0</release>
<api>0.8.0</api> <api>0.14.0</api>
</version> </version>
<stability> <stability>
<release>beta</release> <release>beta</release>
@ -22,7 +22,7 @@
</stability> </stability>
<license>BSD</license> <license>BSD</license>
<notes> <notes>
- Simplify gRPC PHP installation #4517 - Increase unit test code coverage #5225
</notes> </notes>
<contents> <contents>
<dir baseinstalldir="/" name="/"> <dir baseinstalldir="/" name="/">
@ -963,11 +963,26 @@ Update to wrap gRPC C Core version 0.10.0
<release>beta</release> <release>beta</release>
<api>beta</api> <api>beta</api>
</stability> </stability>
<date>2016-02-25</date> <date>2016-02-24</date>
<license>BSD</license> <license>BSD</license>
<notes> <notes>
- Simplify gRPC PHP installation #4517 - Simplify gRPC PHP installation #4517
</notes> </notes>
</release> </release>
<release>
<version>
<release>0.14.0</release>
<api>0.14.0</api>
</version>
<stability>
<release>beta</release>
<api>beta</api>
</stability>
<date>2016-03-01</date>
<license>BSD</license>
<notes>
- Increase unit test code coverage #5225
</notes>
</release>
</changelog> </changelog>
</package> </package>

@ -60,10 +60,10 @@
// limit of 255 for both CENSUS_MAX_TAG_KV_LEN and CENSUS_MAX_PROPAGATED_TAGS. // limit of 255 for both CENSUS_MAX_TAG_KV_LEN and CENSUS_MAX_PROPAGATED_TAGS.
// * Keep all tag information (keys/values/flags) in a single memory buffer, // * Keep all tag information (keys/values/flags) in a single memory buffer,
// that can be directly copied to the wire. // that can be directly copied to the wire.
// * Binary tags share the same structure as, but are encoded separately from,
// non-binary tags. This is primarily because non-binary tags are far more // min and max valid chars in tag keys and values. All printable ASCII is OK.
// likely to be repeated across multiple RPC calls, so are more efficiently #define MIN_VALID_TAG_CHAR 32 // ' '
// cached and compressed in any metadata schemes. #define MAX_VALID_TAG_CHAR 126 // '~'
// Structure representing a set of tags. Essentially a count of number of tags // Structure representing a set of tags. Essentially a count of number of tags
// present, and pointer to a chunk of memory that contains the per-tag details. // present, and pointer to a chunk of memory that contains the per-tag details.
@ -77,7 +77,7 @@ struct tag_set {
char *kvm; // key/value memory. Consists of repeated entries of: char *kvm; // key/value memory. Consists of repeated entries of:
// Offset Size Description // Offset Size Description
// 0 1 Key length, including trailing 0. (K) // 0 1 Key length, including trailing 0. (K)
// 1 1 Value length. (V) // 1 1 Value length, including trailing 0 (V)
// 2 1 Flags // 2 1 Flags
// 3 K Key bytes // 3 K Key bytes
// 3 + K V Value bytes // 3 + K V Value bytes
@ -108,19 +108,36 @@ struct raw_tag {
#define CENSUS_TAG_DELETED CENSUS_TAG_RESERVED #define CENSUS_TAG_DELETED CENSUS_TAG_RESERVED
#define CENSUS_TAG_IS_DELETED(flags) (flags & CENSUS_TAG_DELETED) #define CENSUS_TAG_IS_DELETED(flags) (flags & CENSUS_TAG_DELETED)
// Primary (external) representation of a context. Composed of 3 underlying // Primary representation of a context. Composed of 2 underlying tag_set
// tag_set structs, one for each of the binary/printable propagated tags, and // structs, one each for propagated and local (non-propagated) tags. This is
// one for everything else. This is to efficiently support tag // to efficiently support tag encoding/decoding.
// encoding/decoding. // TODO(aveitch): need to add tracing id's/structure.
struct census_context { struct census_context {
struct tag_set tags[3]; struct tag_set tags[2];
census_context_status status; census_context_status status;
}; };
// Indices into the tags member of census_context // Indices into the tags member of census_context
#define PROPAGATED_TAGS 0 #define PROPAGATED_TAGS 0
#define PROPAGATED_BINARY_TAGS 1 #define LOCAL_TAGS 1
#define LOCAL_TAGS 2
// Validate (check all characters are in range and size is less than limit) a
// key or value string. Returns 0 if the string is invalid, or the length
// (including terminator) if valid.
static size_t validate_tag(const char *kv) {
size_t len = 1;
char ch;
while ((ch = *kv++) != 0) {
if (ch < MIN_VALID_TAG_CHAR || ch > MAX_VALID_TAG_CHAR) {
return 0;
}
len++;
}
if (len > CENSUS_MAX_TAG_KV_LEN) {
return 0;
}
return len;
}
// Extract a raw tag given a pointer (raw) to the tag header. Allow for some // Extract a raw tag given a pointer (raw) to the tag header. Allow for some
// extra bytes in the tag header (see encode/decode functions for usage: this // extra bytes in the tag header (see encode/decode functions for usage: this
@ -166,9 +183,7 @@ static bool context_delete_tag(census_context *context, const census_tag *tag,
size_t key_len) { size_t key_len) {
return ( return (
tag_set_delete_tag(&context->tags[LOCAL_TAGS], tag->key, key_len) || tag_set_delete_tag(&context->tags[LOCAL_TAGS], tag->key, key_len) ||
tag_set_delete_tag(&context->tags[PROPAGATED_TAGS], tag->key, key_len) || tag_set_delete_tag(&context->tags[PROPAGATED_TAGS], tag->key, key_len));
tag_set_delete_tag(&context->tags[PROPAGATED_BINARY_TAGS], tag->key,
key_len));
} }
// Add a tag to a tag_set. Return true on success, false if the tag could // Add a tag to a tag_set. Return true on success, false if the tag could
@ -176,11 +191,11 @@ static bool context_delete_tag(census_context *context, const census_tag *tag,
// not be called if the tag may already exist (in a non-deleted state) in // not be called if the tag may already exist (in a non-deleted state) in
// the tag_set, as that would result in two tags with the same key. // the tag_set, as that would result in two tags with the same key.
static bool tag_set_add_tag(struct tag_set *tags, const census_tag *tag, static bool tag_set_add_tag(struct tag_set *tags, const census_tag *tag,
size_t key_len) { size_t key_len, size_t value_len) {
if (tags->ntags == CENSUS_MAX_PROPAGATED_TAGS) { if (tags->ntags == CENSUS_MAX_PROPAGATED_TAGS) {
return false; return false;
} }
const size_t tag_size = key_len + tag->value_len + TAG_HEADER_SIZE; const size_t tag_size = key_len + value_len + TAG_HEADER_SIZE;
if (tags->kvm_used + tag_size > tags->kvm_size) { if (tags->kvm_used + tag_size > tags->kvm_size) {
// allocate new memory if needed // allocate new memory if needed
tags->kvm_size += 2 * CENSUS_MAX_TAG_KV_LEN + TAG_HEADER_SIZE; tags->kvm_size += 2 * CENSUS_MAX_TAG_KV_LEN + TAG_HEADER_SIZE;
@ -191,13 +206,12 @@ static bool tag_set_add_tag(struct tag_set *tags, const census_tag *tag,
} }
char *kvp = tags->kvm + tags->kvm_used; char *kvp = tags->kvm + tags->kvm_used;
*kvp++ = (char)key_len; *kvp++ = (char)key_len;
*kvp++ = (char)tag->value_len; *kvp++ = (char)value_len;
// ensure reserved flags are not used. // ensure reserved flags are not used.
*kvp++ = (char)(tag->flags & (CENSUS_TAG_PROPAGATE | CENSUS_TAG_STATS | *kvp++ = (char)(tag->flags & (CENSUS_TAG_PROPAGATE | CENSUS_TAG_STATS));
CENSUS_TAG_BINARY));
memcpy(kvp, tag->key, key_len); memcpy(kvp, tag->key, key_len);
kvp += key_len; kvp += key_len;
memcpy(kvp, tag->value, tag->value_len); memcpy(kvp, tag->value, value_len);
tags->kvm_used += tag_size; tags->kvm_used += tag_size;
tags->ntags++; tags->ntags++;
tags->ntags_alloc++; tags->ntags_alloc++;
@ -207,30 +221,20 @@ static bool tag_set_add_tag(struct tag_set *tags, const census_tag *tag,
// Add/modify/delete a tag to/in a context. Caller must validate that tag key // Add/modify/delete a tag to/in a context. Caller must validate that tag key
// etc. are valid. // etc. are valid.
static void context_modify_tag(census_context *context, const census_tag *tag, static void context_modify_tag(census_context *context, const census_tag *tag,
size_t key_len) { size_t key_len, size_t value_len) {
// First delete the tag if it is already present. // First delete the tag if it is already present.
bool deleted = context_delete_tag(context, tag, key_len); bool deleted = context_delete_tag(context, tag, key_len);
// Determine if we need to add it back.
bool call_add = tag->value != NULL && tag->value_len != 0;
bool added = false; bool added = false;
if (call_add) { if (CENSUS_TAG_IS_PROPAGATED(tag->flags)) {
if (CENSUS_TAG_IS_PROPAGATED(tag->flags)) { added = tag_set_add_tag(&context->tags[PROPAGATED_TAGS], tag, key_len,
if (CENSUS_TAG_IS_BINARY(tag->flags)) { value_len);
added = tag_set_add_tag(&context->tags[PROPAGATED_BINARY_TAGS], tag, } else {
key_len); added =
} else { tag_set_add_tag(&context->tags[LOCAL_TAGS], tag, key_len, value_len);
added = tag_set_add_tag(&context->tags[PROPAGATED_TAGS], tag, key_len);
}
} else {
added = tag_set_add_tag(&context->tags[LOCAL_TAGS], tag, key_len);
}
} }
if (deleted) { if (deleted) {
if (call_add) { context->status.n_modified_tags++;
context->status.n_modified_tags++;
} else {
context->status.n_deleted_tags++;
}
} else { } else {
if (added) { if (added) {
context->status.n_added_tags++; context->status.n_added_tags++;
@ -292,8 +296,6 @@ census_context *census_context_create(const census_context *base,
memset(context, 0, sizeof(census_context)); memset(context, 0, sizeof(census_context));
} else { } else {
tag_set_copy(&context->tags[PROPAGATED_TAGS], &base->tags[PROPAGATED_TAGS]); tag_set_copy(&context->tags[PROPAGATED_TAGS], &base->tags[PROPAGATED_TAGS]);
tag_set_copy(&context->tags[PROPAGATED_BINARY_TAGS],
&base->tags[PROPAGATED_BINARY_TAGS]);
tag_set_copy(&context->tags[LOCAL_TAGS], &base->tags[LOCAL_TAGS]); tag_set_copy(&context->tags[LOCAL_TAGS], &base->tags[LOCAL_TAGS]);
memset(&context->status, 0, sizeof(context->status)); memset(&context->status, 0, sizeof(context->status));
} }
@ -301,22 +303,29 @@ census_context *census_context_create(const census_context *base,
// the context to add/replace/delete as required. // the context to add/replace/delete as required.
for (int i = 0; i < ntags; i++) { for (int i = 0; i < ntags; i++) {
const census_tag *tag = &tags[i]; const census_tag *tag = &tags[i];
size_t key_len = strlen(tag->key) + 1; size_t key_len = validate_tag(tag->key);
// ignore the tag if it is too long/short. // ignore the tag if it is invalid or too short.
if (key_len != 1 && key_len <= CENSUS_MAX_TAG_KV_LEN && if (key_len <= 1) {
tag->value_len <= CENSUS_MAX_TAG_KV_LEN) {
context_modify_tag(context, tag, key_len);
} else {
context->status.n_invalid_tags++; context->status.n_invalid_tags++;
} else {
if (tag->value != NULL) {
size_t value_len = validate_tag(tag->value);
if (value_len != 0) {
context_modify_tag(context, tag, key_len, value_len);
} else {
context->status.n_invalid_tags++;
}
} else {
if (context_delete_tag(context, tag, key_len)) {
context->status.n_deleted_tags++;
}
}
} }
} }
// Remove any deleted tags, update status if needed, and return. // Remove any deleted tags, update status if needed, and return.
tag_set_flatten(&context->tags[PROPAGATED_TAGS]); tag_set_flatten(&context->tags[PROPAGATED_TAGS]);
tag_set_flatten(&context->tags[PROPAGATED_BINARY_TAGS]);
tag_set_flatten(&context->tags[LOCAL_TAGS]); tag_set_flatten(&context->tags[LOCAL_TAGS]);
context->status.n_propagated_tags = context->tags[PROPAGATED_TAGS].ntags; context->status.n_propagated_tags = context->tags[PROPAGATED_TAGS].ntags;
context->status.n_propagated_binary_tags =
context->tags[PROPAGATED_BINARY_TAGS].ntags;
context->status.n_local_tags = context->tags[LOCAL_TAGS].ntags; context->status.n_local_tags = context->tags[LOCAL_TAGS].ntags;
if (status) { if (status) {
*status = &context->status; *status = &context->status;
@ -331,7 +340,6 @@ const census_context_status *census_context_get_status(
void census_context_destroy(census_context *context) { void census_context_destroy(census_context *context) {
gpr_free(context->tags[PROPAGATED_TAGS].kvm); gpr_free(context->tags[PROPAGATED_TAGS].kvm);
gpr_free(context->tags[PROPAGATED_BINARY_TAGS].kvm);
gpr_free(context->tags[LOCAL_TAGS].kvm); gpr_free(context->tags[LOCAL_TAGS].kvm);
gpr_free(context); gpr_free(context);
} }
@ -343,9 +351,6 @@ void census_context_initialize_iterator(const census_context *context,
if (context->tags[PROPAGATED_TAGS].ntags != 0) { if (context->tags[PROPAGATED_TAGS].ntags != 0) {
iterator->base = PROPAGATED_TAGS; iterator->base = PROPAGATED_TAGS;
iterator->kvm = context->tags[PROPAGATED_TAGS].kvm; iterator->kvm = context->tags[PROPAGATED_TAGS].kvm;
} else if (context->tags[PROPAGATED_BINARY_TAGS].ntags != 0) {
iterator->base = PROPAGATED_BINARY_TAGS;
iterator->kvm = context->tags[PROPAGATED_BINARY_TAGS].kvm;
} else if (context->tags[LOCAL_TAGS].ntags != 0) { } else if (context->tags[LOCAL_TAGS].ntags != 0) {
iterator->base = LOCAL_TAGS; iterator->base = LOCAL_TAGS;
iterator->kvm = context->tags[LOCAL_TAGS].kvm; iterator->kvm = context->tags[LOCAL_TAGS].kvm;
@ -363,7 +368,6 @@ int census_context_next_tag(census_context_iterator *iterator,
iterator->kvm = decode_tag(&raw, iterator->kvm, 0); iterator->kvm = decode_tag(&raw, iterator->kvm, 0);
tag->key = raw.key; tag->key = raw.key;
tag->value = raw.value; tag->value = raw.value;
tag->value_len = raw.value_len;
tag->flags = raw.flags; tag->flags = raw.flags;
if (++iterator->index == iterator->context->tags[iterator->base].ntags) { if (++iterator->index == iterator->context->tags[iterator->base].ntags) {
do { do {
@ -388,7 +392,6 @@ static bool tag_set_get_tag(const struct tag_set *tags, const char *key,
if (key_len == raw.key_len && memcmp(raw.key, key, key_len) == 0) { if (key_len == raw.key_len && memcmp(raw.key, key, key_len) == 0) {
tag->key = raw.key; tag->key = raw.key;
tag->value = raw.value; tag->value = raw.value;
tag->value_len = raw.value_len;
tag->flags = raw.flags; tag->flags = raw.flags;
return true; return true;
} }
@ -403,8 +406,6 @@ int census_context_get_tag(const census_context *context, const char *key,
return 0; return 0;
} }
if (tag_set_get_tag(&context->tags[PROPAGATED_TAGS], key, key_len, tag) || if (tag_set_get_tag(&context->tags[PROPAGATED_TAGS], key, key_len, tag) ||
tag_set_get_tag(&context->tags[PROPAGATED_BINARY_TAGS], key, key_len,
tag) ||
tag_set_get_tag(&context->tags[LOCAL_TAGS], key, key_len, tag)) { tag_set_get_tag(&context->tags[LOCAL_TAGS], key, key_len, tag)) {
return 1; return 1;
} }
@ -447,21 +448,9 @@ static size_t tag_set_encode(const struct tag_set *tags, char *buffer,
return ENCODED_HEADER_SIZE + tags->kvm_used; return ENCODED_HEADER_SIZE + tags->kvm_used;
} }
char *census_context_encode(const census_context *context, char *buffer, size_t census_context_encode(const census_context *context, char *buffer,
size_t buf_size, size_t *print_buf_size, size_t buf_size) {
size_t *bin_buf_size) { return tag_set_encode(&context->tags[PROPAGATED_TAGS], buffer, buf_size);
*print_buf_size =
tag_set_encode(&context->tags[PROPAGATED_TAGS], buffer, buf_size);
if (*print_buf_size == 0) {
return NULL;
}
char *b_buffer = buffer + *print_buf_size;
*bin_buf_size = tag_set_encode(&context->tags[PROPAGATED_BINARY_TAGS],
b_buffer, buf_size - *print_buf_size);
if (*bin_buf_size == 0) {
return NULL;
}
return b_buffer;
} }
// Decode a tag set. // Decode a tag set.
@ -506,8 +495,7 @@ static void tag_set_decode(struct tag_set *tags, const char *buffer,
} }
} }
census_context *census_context_decode(const char *buffer, size_t size, census_context *census_context_decode(const char *buffer, size_t size) {
const char *bin_buffer, size_t bin_size) {
census_context *context = gpr_malloc(sizeof(census_context)); census_context *context = gpr_malloc(sizeof(census_context));
memset(&context->tags[LOCAL_TAGS], 0, sizeof(struct tag_set)); memset(&context->tags[LOCAL_TAGS], 0, sizeof(struct tag_set));
if (buffer == NULL) { if (buffer == NULL) {
@ -515,16 +503,7 @@ census_context *census_context_decode(const char *buffer, size_t size,
} else { } else {
tag_set_decode(&context->tags[PROPAGATED_TAGS], buffer, size); tag_set_decode(&context->tags[PROPAGATED_TAGS], buffer, size);
} }
if (bin_buffer == NULL) {
memset(&context->tags[PROPAGATED_BINARY_TAGS], 0, sizeof(struct tag_set));
} else {
tag_set_decode(&context->tags[PROPAGATED_BINARY_TAGS], bin_buffer,
bin_size);
}
memset(&context->status, 0, sizeof(context->status)); memset(&context->status, 0, sizeof(context->status));
context->status.n_propagated_tags = context->tags[PROPAGATED_TAGS].ntags; context->status.n_propagated_tags = context->tags[PROPAGATED_TAGS].ntags;
context->status.n_propagated_binary_tags =
context->tags[PROPAGATED_BINARY_TAGS].ntags;
// TODO(aveitch): check that BINARY flag is correct for each type.
return context; return context;
} }

@ -78,8 +78,8 @@ typedef struct client_channel_channel_data {
int exit_idle_when_lb_policy_arrives; int exit_idle_when_lb_policy_arrives;
/** owning stack */ /** owning stack */
grpc_channel_stack *owning_stack; grpc_channel_stack *owning_stack;
/** interested parties */ /** interested parties (owned) */
grpc_pollset_set interested_parties; grpc_pollset_set *interested_parties;
} channel_data; } channel_data;
/** We create one watcher for each new lb_policy that is returned from a /** We create one watcher for each new lb_policy that is returned from a
@ -183,8 +183,8 @@ static void cc_on_config_changed(grpc_exec_ctx *exec_ctx, void *arg,
chand->incoming_configuration = NULL; chand->incoming_configuration = NULL;
if (lb_policy != NULL) { if (lb_policy != NULL) {
grpc_pollset_set_add_pollset_set(exec_ctx, &lb_policy->interested_parties, grpc_pollset_set_add_pollset_set(exec_ctx, lb_policy->interested_parties,
&chand->interested_parties); chand->interested_parties);
} }
gpr_mu_lock(&chand->mu_config); gpr_mu_lock(&chand->mu_config);
@ -231,9 +231,8 @@ static void cc_on_config_changed(grpc_exec_ctx *exec_ctx, void *arg,
} }
if (old_lb_policy != NULL) { if (old_lb_policy != NULL) {
grpc_pollset_set_del_pollset_set(exec_ctx, grpc_pollset_set_del_pollset_set(
&old_lb_policy->interested_parties, exec_ctx, old_lb_policy->interested_parties, chand->interested_parties);
&chand->interested_parties);
GRPC_LB_POLICY_UNREF(exec_ctx, old_lb_policy, "channel"); GRPC_LB_POLICY_UNREF(exec_ctx, old_lb_policy, "channel");
} }
@ -254,7 +253,7 @@ static void cc_start_transport_op(grpc_exec_ctx *exec_ctx,
GPR_ASSERT(op->set_accept_stream == NULL); GPR_ASSERT(op->set_accept_stream == NULL);
if (op->bind_pollset != NULL) { if (op->bind_pollset != NULL) {
grpc_pollset_set_add_pollset(exec_ctx, &chand->interested_parties, grpc_pollset_set_add_pollset(exec_ctx, chand->interested_parties,
op->bind_pollset); op->bind_pollset);
} }
@ -284,8 +283,8 @@ static void cc_start_transport_op(grpc_exec_ctx *exec_ctx,
chand->resolver = NULL; chand->resolver = NULL;
if (chand->lb_policy != NULL) { if (chand->lb_policy != NULL) {
grpc_pollset_set_del_pollset_set(exec_ctx, grpc_pollset_set_del_pollset_set(exec_ctx,
&chand->lb_policy->interested_parties, chand->lb_policy->interested_parties,
&chand->interested_parties); chand->interested_parties);
GRPC_LB_POLICY_UNREF(exec_ctx, chand->lb_policy, "channel"); GRPC_LB_POLICY_UNREF(exec_ctx, chand->lb_policy, "channel");
chand->lb_policy = NULL; chand->lb_policy = NULL;
} }
@ -411,7 +410,7 @@ static void init_channel_elem(grpc_exec_ctx *exec_ctx,
grpc_connectivity_state_init(&chand->state_tracker, GRPC_CHANNEL_IDLE, grpc_connectivity_state_init(&chand->state_tracker, GRPC_CHANNEL_IDLE,
"client_channel"); "client_channel");
grpc_pollset_set_init(&chand->interested_parties); chand->interested_parties = grpc_pollset_set_create();
} }
/* Destructor for channel_data */ /* Destructor for channel_data */
@ -425,12 +424,12 @@ static void destroy_channel_elem(grpc_exec_ctx *exec_ctx,
} }
if (chand->lb_policy != NULL) { if (chand->lb_policy != NULL) {
grpc_pollset_set_del_pollset_set(exec_ctx, grpc_pollset_set_del_pollset_set(exec_ctx,
&chand->lb_policy->interested_parties, chand->lb_policy->interested_parties,
&chand->interested_parties); chand->interested_parties);
GRPC_LB_POLICY_UNREF(exec_ctx, chand->lb_policy, "channel"); GRPC_LB_POLICY_UNREF(exec_ctx, chand->lb_policy, "channel");
} }
grpc_connectivity_state_destroy(exec_ctx, &chand->state_tracker); grpc_connectivity_state_destroy(exec_ctx, &chand->state_tracker);
grpc_pollset_set_destroy(&chand->interested_parties); grpc_pollset_set_destroy(chand->interested_parties);
gpr_mu_destroy(&chand->mu_config); gpr_mu_destroy(&chand->mu_config);
} }
@ -501,7 +500,7 @@ static void on_external_watch_complete(grpc_exec_ctx *exec_ctx, void *arg,
bool iomgr_success) { bool iomgr_success) {
external_connectivity_watcher *w = arg; external_connectivity_watcher *w = arg;
grpc_closure *follow_up = w->on_complete; grpc_closure *follow_up = w->on_complete;
grpc_pollset_set_del_pollset(exec_ctx, &w->chand->interested_parties, grpc_pollset_set_del_pollset(exec_ctx, w->chand->interested_parties,
w->pollset); w->pollset);
GRPC_CHANNEL_STACK_UNREF(exec_ctx, w->chand->owning_stack, GRPC_CHANNEL_STACK_UNREF(exec_ctx, w->chand->owning_stack,
"external_connectivity_watcher"); "external_connectivity_watcher");
@ -517,7 +516,7 @@ void grpc_client_channel_watch_connectivity_state(
w->chand = chand; w->chand = chand;
w->pollset = pollset; w->pollset = pollset;
w->on_complete = on_complete; w->on_complete = on_complete;
grpc_pollset_set_add_pollset(exec_ctx, &chand->interested_parties, pollset); grpc_pollset_set_add_pollset(exec_ctx, chand->interested_parties, pollset);
grpc_closure_init(&w->my_closure, on_external_watch_complete, w); grpc_closure_init(&w->my_closure, on_external_watch_complete, w);
GRPC_CHANNEL_STACK_REF(w->chand->owning_stack, GRPC_CHANNEL_STACK_REF(w->chand->owning_stack,
"external_connectivity_watcher"); "external_connectivity_watcher");

@ -31,8 +31,8 @@
* *
*/ */
#include "src/core/client_config/lb_policy_factory.h"
#include "src/core/client_config/lb_policies/pick_first.h" #include "src/core/client_config/lb_policies/pick_first.h"
#include "src/core/client_config/lb_policy_factory.h"
#include <string.h> #include <string.h>
@ -119,7 +119,7 @@ void pf_shutdown(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol) {
while (pp != NULL) { while (pp != NULL) {
pending_pick *next = pp->next; pending_pick *next = pp->next;
*pp->target = NULL; *pp->target = NULL;
grpc_pollset_set_del_pollset(exec_ctx, &p->base.interested_parties, grpc_pollset_set_del_pollset(exec_ctx, p->base.interested_parties,
pp->pollset); pp->pollset);
grpc_exec_ctx_enqueue(exec_ctx, pp->on_complete, true, NULL); grpc_exec_ctx_enqueue(exec_ctx, pp->on_complete, true, NULL);
gpr_free(pp); gpr_free(pp);
@ -137,7 +137,7 @@ static void pf_cancel_pick(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol,
while (pp != NULL) { while (pp != NULL) {
pending_pick *next = pp->next; pending_pick *next = pp->next;
if (pp->target == target) { if (pp->target == target) {
grpc_pollset_set_del_pollset(exec_ctx, &p->base.interested_parties, grpc_pollset_set_del_pollset(exec_ctx, p->base.interested_parties,
pp->pollset); pp->pollset);
*target = NULL; *target = NULL;
grpc_exec_ctx_enqueue(exec_ctx, pp->on_complete, false, NULL); grpc_exec_ctx_enqueue(exec_ctx, pp->on_complete, false, NULL);
@ -158,7 +158,7 @@ static void start_picking(grpc_exec_ctx *exec_ctx, pick_first_lb_policy *p) {
GRPC_LB_POLICY_WEAK_REF(&p->base, "pick_first_connectivity"); GRPC_LB_POLICY_WEAK_REF(&p->base, "pick_first_connectivity");
grpc_subchannel_notify_on_state_change( grpc_subchannel_notify_on_state_change(
exec_ctx, p->subchannels[p->checking_subchannel], exec_ctx, p->subchannels[p->checking_subchannel],
&p->base.interested_parties, &p->checking_connectivity, p->base.interested_parties, &p->checking_connectivity,
&p->connectivity_changed); &p->connectivity_changed);
} }
@ -195,8 +195,7 @@ int pf_pick(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol, grpc_pollset *pollset,
if (!p->started_picking) { if (!p->started_picking) {
start_picking(exec_ctx, p); start_picking(exec_ctx, p);
} }
grpc_pollset_set_add_pollset(exec_ctx, &p->base.interested_parties, grpc_pollset_set_add_pollset(exec_ctx, p->base.interested_parties, pollset);
pollset);
pp = gpr_malloc(sizeof(*pp)); pp = gpr_malloc(sizeof(*pp));
pp->next = p->pending_picks; pp->next = p->pending_picks;
pp->pollset = pollset; pp->pollset = pollset;
@ -253,7 +252,7 @@ static void pf_connectivity_changed(grpc_exec_ctx *exec_ctx, void *arg,
p->checking_connectivity, "selected_changed"); p->checking_connectivity, "selected_changed");
if (p->checking_connectivity != GRPC_CHANNEL_FATAL_FAILURE) { if (p->checking_connectivity != GRPC_CHANNEL_FATAL_FAILURE) {
grpc_connected_subchannel_notify_on_state_change( grpc_connected_subchannel_notify_on_state_change(
exec_ctx, selected, &p->base.interested_parties, exec_ctx, selected, p->base.interested_parties,
&p->checking_connectivity, &p->connectivity_changed); &p->checking_connectivity, &p->connectivity_changed);
} else { } else {
GRPC_LB_POLICY_WEAK_UNREF(exec_ctx, &p->base, "pick_first_connectivity"); GRPC_LB_POLICY_WEAK_UNREF(exec_ctx, &p->base, "pick_first_connectivity");
@ -278,13 +277,13 @@ static void pf_connectivity_changed(grpc_exec_ctx *exec_ctx, void *arg,
while ((pp = p->pending_picks)) { while ((pp = p->pending_picks)) {
p->pending_picks = pp->next; p->pending_picks = pp->next;
*pp->target = selected; *pp->target = selected;
grpc_pollset_set_del_pollset(exec_ctx, &p->base.interested_parties, grpc_pollset_set_del_pollset(exec_ctx, p->base.interested_parties,
pp->pollset); pp->pollset);
grpc_exec_ctx_enqueue(exec_ctx, pp->on_complete, true, NULL); grpc_exec_ctx_enqueue(exec_ctx, pp->on_complete, true, NULL);
gpr_free(pp); gpr_free(pp);
} }
grpc_connected_subchannel_notify_on_state_change( grpc_connected_subchannel_notify_on_state_change(
exec_ctx, selected, &p->base.interested_parties, exec_ctx, selected, p->base.interested_parties,
&p->checking_connectivity, &p->connectivity_changed); &p->checking_connectivity, &p->connectivity_changed);
break; break;
case GRPC_CHANNEL_TRANSIENT_FAILURE: case GRPC_CHANNEL_TRANSIENT_FAILURE:
@ -298,7 +297,7 @@ static void pf_connectivity_changed(grpc_exec_ctx *exec_ctx, void *arg,
if (p->checking_connectivity == GRPC_CHANNEL_TRANSIENT_FAILURE) { if (p->checking_connectivity == GRPC_CHANNEL_TRANSIENT_FAILURE) {
grpc_subchannel_notify_on_state_change( grpc_subchannel_notify_on_state_change(
exec_ctx, p->subchannels[p->checking_subchannel], exec_ctx, p->subchannels[p->checking_subchannel],
&p->base.interested_parties, &p->checking_connectivity, p->base.interested_parties, &p->checking_connectivity,
&p->connectivity_changed); &p->connectivity_changed);
} else { } else {
goto loop; goto loop;
@ -311,7 +310,7 @@ static void pf_connectivity_changed(grpc_exec_ctx *exec_ctx, void *arg,
"connecting_changed"); "connecting_changed");
grpc_subchannel_notify_on_state_change( grpc_subchannel_notify_on_state_change(
exec_ctx, p->subchannels[p->checking_subchannel], exec_ctx, p->subchannels[p->checking_subchannel],
&p->base.interested_parties, &p->checking_connectivity, p->base.interested_parties, &p->checking_connectivity,
&p->connectivity_changed); &p->connectivity_changed);
break; break;
case GRPC_CHANNEL_FATAL_FAILURE: case GRPC_CHANNEL_FATAL_FAILURE:

@ -260,7 +260,7 @@ static void rr_cancel_pick(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol,
while (pp != NULL) { while (pp != NULL) {
pending_pick *next = pp->next; pending_pick *next = pp->next;
if (pp->target == target) { if (pp->target == target) {
grpc_pollset_set_del_pollset(exec_ctx, &p->base.interested_parties, grpc_pollset_set_del_pollset(exec_ctx, p->base.interested_parties,
pp->pollset); pp->pollset);
*target = NULL; *target = NULL;
grpc_exec_ctx_enqueue(exec_ctx, pp->on_complete, false, NULL); grpc_exec_ctx_enqueue(exec_ctx, pp->on_complete, false, NULL);
@ -285,7 +285,7 @@ static void start_picking(grpc_exec_ctx *exec_ctx, round_robin_lb_policy *p) {
subchannel_data *sd = p->subchannels[i]; subchannel_data *sd = p->subchannels[i];
sd->connectivity_state = GRPC_CHANNEL_IDLE; sd->connectivity_state = GRPC_CHANNEL_IDLE;
grpc_subchannel_notify_on_state_change( grpc_subchannel_notify_on_state_change(
exec_ctx, sd->subchannel, &p->base.interested_parties, exec_ctx, sd->subchannel, p->base.interested_parties,
&sd->connectivity_state, &sd->connectivity_changed_closure); &sd->connectivity_state, &sd->connectivity_changed_closure);
GRPC_LB_POLICY_WEAK_REF(&p->base, "round_robin_connectivity"); GRPC_LB_POLICY_WEAK_REF(&p->base, "round_robin_connectivity");
} }
@ -322,8 +322,7 @@ int rr_pick(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol, grpc_pollset *pollset,
if (!p->started_picking) { if (!p->started_picking) {
start_picking(exec_ctx, p); start_picking(exec_ctx, p);
} }
grpc_pollset_set_add_pollset(exec_ctx, &p->base.interested_parties, grpc_pollset_set_add_pollset(exec_ctx, p->base.interested_parties, pollset);
pollset);
pp = gpr_malloc(sizeof(*pp)); pp = gpr_malloc(sizeof(*pp));
pp->next = p->pending_picks; pp->next = p->pending_picks;
pp->pollset = pollset; pp->pollset = pollset;
@ -374,13 +373,13 @@ static void rr_connectivity_changed(grpc_exec_ctx *exec_ctx, void *arg,
"[RR CONN CHANGED] TARGET <-- SUBCHANNEL %p (NODE %p)", "[RR CONN CHANGED] TARGET <-- SUBCHANNEL %p (NODE %p)",
selected->subchannel, selected); selected->subchannel, selected);
} }
grpc_pollset_set_del_pollset(exec_ctx, &p->base.interested_parties, grpc_pollset_set_del_pollset(exec_ctx, p->base.interested_parties,
pp->pollset); pp->pollset);
grpc_exec_ctx_enqueue(exec_ctx, pp->on_complete, true, NULL); grpc_exec_ctx_enqueue(exec_ctx, pp->on_complete, true, NULL);
gpr_free(pp); gpr_free(pp);
} }
grpc_subchannel_notify_on_state_change( grpc_subchannel_notify_on_state_change(
exec_ctx, sd->subchannel, &p->base.interested_parties, exec_ctx, sd->subchannel, p->base.interested_parties,
&sd->connectivity_state, &sd->connectivity_changed_closure); &sd->connectivity_state, &sd->connectivity_changed_closure);
break; break;
case GRPC_CHANNEL_CONNECTING: case GRPC_CHANNEL_CONNECTING:
@ -389,13 +388,13 @@ static void rr_connectivity_changed(grpc_exec_ctx *exec_ctx, void *arg,
sd->connectivity_state, sd->connectivity_state,
"connecting_changed"); "connecting_changed");
grpc_subchannel_notify_on_state_change( grpc_subchannel_notify_on_state_change(
exec_ctx, sd->subchannel, &p->base.interested_parties, exec_ctx, sd->subchannel, p->base.interested_parties,
&sd->connectivity_state, &sd->connectivity_changed_closure); &sd->connectivity_state, &sd->connectivity_changed_closure);
break; break;
case GRPC_CHANNEL_TRANSIENT_FAILURE: case GRPC_CHANNEL_TRANSIENT_FAILURE:
/* renew state notification */ /* renew state notification */
grpc_subchannel_notify_on_state_change( grpc_subchannel_notify_on_state_change(
exec_ctx, sd->subchannel, &p->base.interested_parties, exec_ctx, sd->subchannel, p->base.interested_parties,
&sd->connectivity_state, &sd->connectivity_changed_closure); &sd->connectivity_state, &sd->connectivity_changed_closure);
/* remove from ready list if still present */ /* remove from ready list if still present */

@ -1,6 +1,6 @@
/* /*
* *
* Copyright 2015, Google Inc. * Copyright 2015-2016, Google Inc.
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
@ -39,7 +39,7 @@ void grpc_lb_policy_init(grpc_lb_policy *policy,
const grpc_lb_policy_vtable *vtable) { const grpc_lb_policy_vtable *vtable) {
policy->vtable = vtable; policy->vtable = vtable;
gpr_atm_no_barrier_store(&policy->ref_pair, 1 << WEAK_REF_BITS); gpr_atm_no_barrier_store(&policy->ref_pair, 1 << WEAK_REF_BITS);
grpc_pollset_set_init(&policy->interested_parties); policy->interested_parties = grpc_pollset_set_create();
} }
#ifdef GRPC_LB_POLICY_REFCOUNT_DEBUG #ifdef GRPC_LB_POLICY_REFCOUNT_DEBUG
@ -93,7 +93,7 @@ void grpc_lb_policy_weak_unref(grpc_exec_ctx *exec_ctx,
gpr_atm old_val = gpr_atm old_val =
ref_mutate(policy, -(gpr_atm)1, 1 REF_MUTATE_PASS_ARGS("WEAK_UNREF")); ref_mutate(policy, -(gpr_atm)1, 1 REF_MUTATE_PASS_ARGS("WEAK_UNREF"));
if (old_val == 1) { if (old_val == 1) {
grpc_pollset_set_destroy(&policy->interested_parties); grpc_pollset_set_destroy(policy->interested_parties);
policy->vtable->destroy(exec_ctx, policy); policy->vtable->destroy(exec_ctx, policy);
} }
} }

@ -1,6 +1,6 @@
/* /*
* *
* Copyright 2015, Google Inc. * Copyright 2015-2016, Google Inc.
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
@ -48,7 +48,8 @@ typedef void (*grpc_lb_completion)(void *cb_arg, grpc_subchannel *subchannel,
struct grpc_lb_policy { struct grpc_lb_policy {
const grpc_lb_policy_vtable *vtable; const grpc_lb_policy_vtable *vtable;
gpr_atm ref_pair; gpr_atm ref_pair;
grpc_pollset_set interested_parties; /* owned pointer to interested parties in load balancing decisions */
grpc_pollset_set *interested_parties;
}; };
struct grpc_lb_policy_vtable { struct grpc_lb_policy_vtable {

@ -108,7 +108,7 @@ struct grpc_subchannel {
/** 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;
/** active connection, or null; of type grpc_connected_subchannel */ /** active connection, or null; of type grpc_connected_subchannel */
gpr_atm connected_subchannel; gpr_atm connected_subchannel;
@ -209,7 +209,7 @@ static void subchannel_destroy(grpc_exec_ctx *exec_ctx, void *arg,
gpr_slice_unref(c->initial_connect_string); gpr_slice_unref(c->initial_connect_string);
grpc_connectivity_state_destroy(exec_ctx, &c->state_tracker); grpc_connectivity_state_destroy(exec_ctx, &c->state_tracker);
grpc_connector_unref(exec_ctx, c->connector); grpc_connector_unref(exec_ctx, c->connector);
grpc_pollset_set_destroy(&c->pollset_set); grpc_pollset_set_destroy(c->pollset_set);
grpc_subchannel_key_destroy(exec_ctx, c->key); grpc_subchannel_key_destroy(exec_ctx, c->key);
gpr_free(c); gpr_free(c);
} }
@ -326,7 +326,7 @@ grpc_subchannel *grpc_subchannel_create(grpc_exec_ctx *exec_ctx,
} }
c->addr = gpr_malloc(args->addr_len); c->addr = gpr_malloc(args->addr_len);
memcpy(c->addr, args->addr, args->addr_len); memcpy(c->addr, args->addr, args->addr_len);
grpc_pollset_set_init(&c->pollset_set); c->pollset_set = grpc_pollset_set_create();
c->addr_len = args->addr_len; c->addr_len = args->addr_len;
grpc_set_initial_connect_string(&c->addr, &c->addr_len, grpc_set_initial_connect_string(&c->addr, &c->addr_len,
&c->initial_connect_string); &c->initial_connect_string);
@ -345,7 +345,7 @@ grpc_subchannel *grpc_subchannel_create(grpc_exec_ctx *exec_ctx,
static void continue_connect(grpc_exec_ctx *exec_ctx, grpc_subchannel *c) { static void continue_connect(grpc_exec_ctx *exec_ctx, grpc_subchannel *c) {
grpc_connect_in_args args; grpc_connect_in_args args;
args.interested_parties = &c->pollset_set; args.interested_parties = c->pollset_set;
args.addr = c->addr; args.addr = c->addr;
args.addr_len = c->addr_len; args.addr_len = c->addr_len;
args.deadline = compute_connect_deadline(c); args.deadline = compute_connect_deadline(c);
@ -379,7 +379,7 @@ static void on_external_state_watcher_done(grpc_exec_ctx *exec_ctx, void *arg,
external_state_watcher *w = arg; external_state_watcher *w = arg;
grpc_closure *follow_up = w->notify; grpc_closure *follow_up = w->notify;
if (w->pollset_set != NULL) { if (w->pollset_set != NULL) {
grpc_pollset_set_del_pollset_set(exec_ctx, &w->subchannel->pollset_set, grpc_pollset_set_del_pollset_set(exec_ctx, w->subchannel->pollset_set,
w->pollset_set); w->pollset_set);
} }
gpr_mu_lock(&w->subchannel->mu); gpr_mu_lock(&w->subchannel->mu);
@ -395,7 +395,6 @@ void grpc_subchannel_notify_on_state_change(
grpc_exec_ctx *exec_ctx, grpc_subchannel *c, grpc_exec_ctx *exec_ctx, grpc_subchannel *c,
grpc_pollset_set *interested_parties, grpc_connectivity_state *state, grpc_pollset_set *interested_parties, grpc_connectivity_state *state,
grpc_closure *notify) { grpc_closure *notify) {
int do_connect = 0;
external_state_watcher *w; external_state_watcher *w;
if (state == NULL) { if (state == NULL) {
@ -415,7 +414,7 @@ void grpc_subchannel_notify_on_state_change(
w->notify = notify; w->notify = notify;
grpc_closure_init(&w->closure, on_external_state_watcher_done, w); grpc_closure_init(&w->closure, on_external_state_watcher_done, w);
if (interested_parties != NULL) { if (interested_parties != NULL) {
grpc_pollset_set_add_pollset_set(exec_ctx, &c->pollset_set, grpc_pollset_set_add_pollset_set(exec_ctx, c->pollset_set,
interested_parties); interested_parties);
} }
GRPC_SUBCHANNEL_WEAK_REF(c, "external_state_watcher"); GRPC_SUBCHANNEL_WEAK_REF(c, "external_state_watcher");
@ -425,17 +424,13 @@ void grpc_subchannel_notify_on_state_change(
w->next->prev = w->prev->next = w; w->next->prev = w->prev->next = w;
if (grpc_connectivity_state_notify_on_state_change( if (grpc_connectivity_state_notify_on_state_change(
exec_ctx, &c->state_tracker, state, &w->closure)) { exec_ctx, &c->state_tracker, state, &w->closure)) {
do_connect = 1;
c->connecting = 1; c->connecting = 1;
/* released by connection */ /* released by connection */
GRPC_SUBCHANNEL_WEAK_REF(c, "connecting"); GRPC_SUBCHANNEL_WEAK_REF(c, "connecting");
start_connect(exec_ctx, c);
} }
gpr_mu_unlock(&c->mu); gpr_mu_unlock(&c->mu);
} }
if (do_connect) {
start_connect(exec_ctx, c);
}
} }
void grpc_connected_subchannel_process_transport_op( void grpc_connected_subchannel_process_transport_op(
@ -573,7 +568,7 @@ static void publish_transport(grpc_exec_ctx *exec_ctx, grpc_subchannel *c) {
GRPC_SUBCHANNEL_WEAK_REF(c, "state_watcher"); GRPC_SUBCHANNEL_WEAK_REF(c, "state_watcher");
GRPC_SUBCHANNEL_WEAK_UNREF(exec_ctx, c, "connecting"); GRPC_SUBCHANNEL_WEAK_UNREF(exec_ctx, c, "connecting");
grpc_connected_subchannel_notify_on_state_change( grpc_connected_subchannel_notify_on_state_change(
exec_ctx, con, &c->pollset_set, &sw_subchannel->connectivity_state, exec_ctx, con, c->pollset_set, &sw_subchannel->connectivity_state,
&sw_subchannel->closure); &sw_subchannel->closure);
/* signal completion */ /* signal completion */
@ -635,11 +630,12 @@ static void on_alarm(grpc_exec_ctx *exec_ctx, void *arg, bool iomgr_success) {
if (c->disconnected) { if (c->disconnected) {
iomgr_success = 0; iomgr_success = 0;
} }
gpr_mu_unlock(&c->mu);
if (iomgr_success) { if (iomgr_success) {
update_reconnect_parameters(c); update_reconnect_parameters(c);
continue_connect(exec_ctx, c); continue_connect(exec_ctx, c);
gpr_mu_unlock(&c->mu);
} else { } else {
gpr_mu_unlock(&c->mu);
GRPC_SUBCHANNEL_WEAK_UNREF(exec_ctx, c, "connecting"); GRPC_SUBCHANNEL_WEAK_UNREF(exec_ctx, c, "connecting");
} }
} }

@ -31,20 +31,22 @@
* *
*/ */
#include "src/core/iomgr/sockaddr.h"
#include "src/core/httpcli/httpcli.h" #include "src/core/httpcli/httpcli.h"
#include "src/core/iomgr/sockaddr.h"
#include <string.h> #include <string.h>
#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
#include <grpc/support/string_util.h>
#include "src/core/httpcli/format_request.h"
#include "src/core/httpcli/parser.h"
#include "src/core/iomgr/endpoint.h" #include "src/core/iomgr/endpoint.h"
#include "src/core/iomgr/iomgr_internal.h"
#include "src/core/iomgr/resolve_address.h" #include "src/core/iomgr/resolve_address.h"
#include "src/core/iomgr/tcp_client.h" #include "src/core/iomgr/tcp_client.h"
#include "src/core/httpcli/format_request.h"
#include "src/core/httpcli/parser.h"
#include "src/core/support/string.h" #include "src/core/support/string.h"
#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
#include <grpc/support/string_util.h>
typedef struct { typedef struct {
gpr_slice request_text; gpr_slice request_text;
@ -84,18 +86,18 @@ const grpc_httpcli_handshaker grpc_httpcli_plaintext = {"http",
plaintext_handshake}; plaintext_handshake};
void grpc_httpcli_context_init(grpc_httpcli_context *context) { void grpc_httpcli_context_init(grpc_httpcli_context *context) {
grpc_pollset_set_init(&context->pollset_set); context->pollset_set = grpc_pollset_set_create();
} }
void grpc_httpcli_context_destroy(grpc_httpcli_context *context) { void grpc_httpcli_context_destroy(grpc_httpcli_context *context) {
grpc_pollset_set_destroy(&context->pollset_set); grpc_pollset_set_destroy(context->pollset_set);
} }
static void next_address(grpc_exec_ctx *exec_ctx, internal_request *req); static void next_address(grpc_exec_ctx *exec_ctx, internal_request *req);
static void finish(grpc_exec_ctx *exec_ctx, internal_request *req, static void finish(grpc_exec_ctx *exec_ctx, internal_request *req,
int success) { int success) {
grpc_pollset_set_del_pollset(exec_ctx, &req->context->pollset_set, grpc_pollset_set_del_pollset(exec_ctx, req->context->pollset_set,
req->pollset); req->pollset);
req->on_response(exec_ctx, req->user_data, success ? &req->parser.r : NULL); req->on_response(exec_ctx, req->user_data, success ? &req->parser.r : NULL);
grpc_httpcli_parser_destroy(&req->parser); grpc_httpcli_parser_destroy(&req->parser);
@ -197,7 +199,7 @@ static void next_address(grpc_exec_ctx *exec_ctx, internal_request *req) {
addr = &req->addresses->addrs[req->next_address++]; addr = &req->addresses->addrs[req->next_address++];
grpc_closure_init(&req->connected, on_connected, req); grpc_closure_init(&req->connected, on_connected, req);
grpc_tcp_client_connect( grpc_tcp_client_connect(
exec_ctx, &req->connected, &req->ep, &req->context->pollset_set, exec_ctx, &req->connected, &req->ep, req->context->pollset_set,
(struct sockaddr *)&addr->addr, addr->len, req->deadline); (struct sockaddr *)&addr->addr, addr->len, req->deadline);
} }
@ -237,7 +239,7 @@ static void internal_request_begin(
req->host = gpr_strdup(request->host); req->host = gpr_strdup(request->host);
req->ssl_host_override = gpr_strdup(request->ssl_host_override); req->ssl_host_override = gpr_strdup(request->ssl_host_override);
grpc_pollset_set_add_pollset(exec_ctx, &req->context->pollset_set, grpc_pollset_set_add_pollset(exec_ctx, req->context->pollset_set,
req->pollset); req->pollset);
grpc_resolve_address(request->host, req->handshaker->default_port, grpc_resolve_address(request->host, req->handshaker->default_port,
on_resolved, req); on_resolved, req);

@ -1,6 +1,6 @@
/* /*
* *
* Copyright 2015, Google Inc. * Copyright 2015-2016, Google Inc.
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
@ -39,6 +39,7 @@
#include <grpc/support/time.h> #include <grpc/support/time.h>
#include "src/core/iomgr/endpoint.h" #include "src/core/iomgr/endpoint.h"
#include "src/core/iomgr/iomgr_internal.h"
#include "src/core/iomgr/pollset_set.h" #include "src/core/iomgr/pollset_set.h"
/* User agent this library reports */ /* User agent this library reports */
@ -56,7 +57,7 @@ typedef struct grpc_httpcli_header {
TODO(ctiller): allow caching and capturing multiple requests for the TODO(ctiller): allow caching and capturing multiple requests for the
same content and combining them */ same content and combining them */
typedef struct grpc_httpcli_context { typedef struct grpc_httpcli_context {
grpc_pollset_set pollset_set; grpc_pollset_set *pollset_set;
} grpc_httpcli_context; } grpc_httpcli_context;
typedef struct { typedef struct {

@ -59,7 +59,7 @@ static void httpcli_ssl_destroy(grpc_security_connector *sc) {
} }
static void httpcli_ssl_do_handshake(grpc_exec_ctx *exec_ctx, static void httpcli_ssl_do_handshake(grpc_exec_ctx *exec_ctx,
grpc_security_connector *sc, grpc_channel_security_connector *sc,
grpc_endpoint *nonsecure_endpoint, grpc_endpoint *nonsecure_endpoint,
grpc_security_handshake_done_cb cb, grpc_security_handshake_done_cb cb,
void *user_data) { void *user_data) {
@ -78,8 +78,8 @@ static void httpcli_ssl_do_handshake(grpc_exec_ctx *exec_ctx,
tsi_result_to_string(result)); tsi_result_to_string(result));
cb(exec_ctx, user_data, GRPC_SECURITY_ERROR, NULL, NULL); cb(exec_ctx, user_data, GRPC_SECURITY_ERROR, NULL, NULL);
} else { } else {
grpc_do_security_handshake(exec_ctx, handshaker, sc, nonsecure_endpoint, cb, grpc_do_security_handshake(exec_ctx, handshaker, &sc->base, true,
user_data); nonsecure_endpoint, cb, user_data);
} }
} }
@ -103,7 +103,7 @@ static void httpcli_ssl_check_peer(grpc_exec_ctx *exec_ctx,
} }
static grpc_security_connector_vtable httpcli_ssl_vtable = { static grpc_security_connector_vtable httpcli_ssl_vtable = {
httpcli_ssl_destroy, httpcli_ssl_do_handshake, httpcli_ssl_check_peer}; httpcli_ssl_destroy, httpcli_ssl_check_peer};
static grpc_security_status httpcli_ssl_channel_security_connector_create( static grpc_security_status httpcli_ssl_channel_security_connector_create(
const unsigned char *pem_root_certs, size_t pem_root_certs_size, const unsigned char *pem_root_certs, size_t pem_root_certs_size,
@ -121,7 +121,6 @@ static grpc_security_status httpcli_ssl_channel_security_connector_create(
memset(c, 0, sizeof(grpc_httpcli_ssl_channel_security_connector)); memset(c, 0, sizeof(grpc_httpcli_ssl_channel_security_connector));
gpr_ref_init(&c->base.base.refcount, 1); gpr_ref_init(&c->base.base.refcount, 1);
c->base.base.is_client_side = 1;
c->base.base.vtable = &httpcli_ssl_vtable; c->base.base.vtable = &httpcli_ssl_vtable;
if (secure_peer_name != NULL) { if (secure_peer_name != NULL) {
c->secure_peer_name = gpr_strdup(secure_peer_name); c->secure_peer_name = gpr_strdup(secure_peer_name);
@ -136,6 +135,7 @@ static grpc_security_status httpcli_ssl_channel_security_connector_create(
*sc = NULL; *sc = NULL;
return GRPC_SECURITY_ERROR; return GRPC_SECURITY_ERROR;
} }
c->base.do_handshake = httpcli_ssl_do_handshake;
*sc = &c->base; *sc = &c->base;
return GRPC_SECURITY_OK; return GRPC_SECURITY_OK;
} }
@ -180,8 +180,8 @@ static void ssl_handshake(grpc_exec_ctx *exec_ctx, void *arg,
GPR_ASSERT(httpcli_ssl_channel_security_connector_create( GPR_ASSERT(httpcli_ssl_channel_security_connector_create(
pem_root_certs, pem_root_certs_size, host, &sc) == pem_root_certs, pem_root_certs_size, host, &sc) ==
GRPC_SECURITY_OK); GRPC_SECURITY_OK);
grpc_security_connector_do_handshake(exec_ctx, &sc->base, tcp, grpc_channel_security_connector_do_handshake(
on_secure_transport_setup_done, c); exec_ctx, sc, tcp, on_secure_transport_setup_done, c);
GRPC_SECURITY_CONNECTOR_UNREF(&sc->base, "httpcli"); GRPC_SECURITY_CONNECTOR_UNREF(&sc->base, "httpcli");
} }

@ -46,6 +46,8 @@
#include <grpc/support/string_util.h> #include <grpc/support/string_util.h>
#include <grpc/support/useful.h> #include <grpc/support/useful.h>
#include "src/core/iomgr/pollset_posix.h"
#define CLOSURE_NOT_READY ((grpc_closure *)0) #define CLOSURE_NOT_READY ((grpc_closure *)0)
#define CLOSURE_READY ((grpc_closure *)1) #define CLOSURE_READY ((grpc_closure *)1)
@ -175,11 +177,11 @@ int grpc_fd_is_orphaned(grpc_fd *fd) {
} }
static void pollset_kick_locked(grpc_fd_watcher *watcher) { static void pollset_kick_locked(grpc_fd_watcher *watcher) {
gpr_mu_lock(GRPC_POLLSET_MU(watcher->pollset)); gpr_mu_lock(&watcher->pollset->mu);
GPR_ASSERT(watcher->worker); GPR_ASSERT(watcher->worker);
grpc_pollset_kick_ext(watcher->pollset, watcher->worker, grpc_pollset_kick_ext(watcher->pollset, watcher->worker,
GRPC_POLLSET_REEVALUATE_POLLING_ON_WAKEUP); GRPC_POLLSET_REEVALUATE_POLLING_ON_WAKEUP);
gpr_mu_unlock(GRPC_POLLSET_MU(watcher->pollset)); gpr_mu_unlock(&watcher->pollset->mu);
} }
static void maybe_wake_one_watcher_locked(grpc_fd *fd) { static void maybe_wake_one_watcher_locked(grpc_fd *fd) {

@ -41,9 +41,11 @@
#include <grpc/support/string_util.h> #include <grpc/support/string_util.h>
#include <grpc/support/sync.h> #include <grpc/support/sync.h>
#include <grpc/support/thd.h> #include <grpc/support/thd.h>
#include <grpc/support/useful.h>
#include "src/core/iomgr/iomgr_internal.h" #include "src/core/iomgr/iomgr_internal.h"
#include "src/core/iomgr/timer.h" #include "src/core/iomgr/timer.h"
#include "src/core/support/env.h"
#include "src/core/support/string.h" #include "src/core/support/string.h"
static gpr_mu g_mu; static gpr_mu g_mu;
@ -116,6 +118,9 @@ void grpc_iomgr_shutdown(void) {
"memory leaks are likely", "memory leaks are likely",
count_objects()); count_objects());
dump_objects("LEAKED"); dump_objects("LEAKED");
if (grpc_iomgr_abort_on_leaks()) {
abort();
}
} }
break; break;
} }
@ -154,3 +159,14 @@ void grpc_iomgr_unregister_object(grpc_iomgr_object *obj) {
gpr_mu_unlock(&g_mu); gpr_mu_unlock(&g_mu);
gpr_free(obj->name); gpr_free(obj->name);
} }
bool grpc_iomgr_abort_on_leaks(void) {
char *env = gpr_getenv("GRPC_ABORT_ON_LEAKS");
if (env == NULL) return false;
static const char *truthy[] = {"yes", "Yes", "YES", "true",
"True", "TRUE", "1"};
for (size_t i = 0; i < GPR_ARRAY_SIZE(truthy); i++) {
if (0 == strcmp(env, truthy[i])) return true;
}
return false;
}

@ -1,6 +1,6 @@
/* /*
* *
* Copyright 2015, Google Inc. * Copyright 2015-2016, Google Inc.
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
@ -34,6 +34,8 @@
#ifndef GRPC_INTERNAL_CORE_IOMGR_IOMGR_INTERNAL_H #ifndef GRPC_INTERNAL_CORE_IOMGR_IOMGR_INTERNAL_H
#define GRPC_INTERNAL_CORE_IOMGR_IOMGR_INTERNAL_H #define GRPC_INTERNAL_CORE_IOMGR_IOMGR_INTERNAL_H
#include <stdbool.h>
#include "src/core/iomgr/iomgr.h" #include "src/core/iomgr/iomgr.h"
#include <grpc/support/sync.h> #include <grpc/support/sync.h>
@ -55,4 +57,6 @@ void grpc_iomgr_platform_flush(void);
/** tear down all platform specific global iomgr structures */ /** tear down all platform specific global iomgr structures */
void grpc_iomgr_platform_shutdown(void); void grpc_iomgr_platform_shutdown(void);
bool grpc_iomgr_abort_on_leaks(void);
#endif /* GRPC_INTERNAL_CORE_IOMGR_IOMGR_INTERNAL_H */ #endif /* GRPC_INTERNAL_CORE_IOMGR_IOMGR_INTERNAL_H */

@ -1,6 +1,6 @@
/* /*
* *
* Copyright 2015, Google Inc. * Copyright 2015-2016, Google Inc.
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
@ -35,8 +35,11 @@
#define GRPC_INTERNAL_CORE_IOMGR_POLLSET_H #define GRPC_INTERNAL_CORE_IOMGR_POLLSET_H
#include <grpc/support/port_platform.h> #include <grpc/support/port_platform.h>
#include <grpc/support/sync.h>
#include <grpc/support/time.h> #include <grpc/support/time.h>
#include "src/core/iomgr/exec_ctx.h"
#define GRPC_POLLSET_KICK_BROADCAST ((grpc_pollset_worker *)1) #define GRPC_POLLSET_KICK_BROADCAST ((grpc_pollset_worker *)1)
/* A grpc_pollset is a set of file descriptors that a higher level item is /* A grpc_pollset is a set of file descriptors that a higher level item is
@ -46,15 +49,11 @@
- a completion queue might keep a pollset with an entry for each transport - a completion queue might keep a pollset with an entry for each transport
that is servicing a call that it's tracking */ that is servicing a call that it's tracking */
#ifdef GPR_POSIX_SOCKET typedef struct grpc_pollset grpc_pollset;
#include "src/core/iomgr/pollset_posix.h" typedef struct grpc_pollset_worker grpc_pollset_worker;
#endif
#ifdef GPR_WIN32
#include "src/core/iomgr/pollset_windows.h"
#endif
void grpc_pollset_init(grpc_pollset *pollset); size_t grpc_pollset_size(void);
void grpc_pollset_init(grpc_pollset *pollset, gpr_mu **mu);
/* Begin shutting down the pollset, and call closure when done. /* Begin shutting down the pollset, and call closure when done.
* GRPC_POLLSET_MU(pollset) must be held */ * GRPC_POLLSET_MU(pollset) must be held */
void grpc_pollset_shutdown(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset, void grpc_pollset_shutdown(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset,
@ -83,7 +82,7 @@ void grpc_pollset_destroy(grpc_pollset *pollset);
pollset pollset
lock */ lock */
void grpc_pollset_work(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset, void grpc_pollset_work(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset,
grpc_pollset_worker *worker, gpr_timespec now, grpc_pollset_worker **worker, gpr_timespec now,
gpr_timespec deadline); gpr_timespec deadline);
/* Break one polling thread out of polling work for this pollset. /* Break one polling thread out of polling work for this pollset.

@ -45,6 +45,7 @@
#include <grpc/support/log.h> #include <grpc/support/log.h>
#include <grpc/support/useful.h> #include <grpc/support/useful.h>
#include "src/core/iomgr/fd_posix.h" #include "src/core/iomgr/fd_posix.h"
#include "src/core/iomgr/pollset_posix.h"
#include "src/core/profiling/timers.h" #include "src/core/profiling/timers.h"
#include "src/core/support/block_annotate.h" #include "src/core/support/block_annotate.h"

@ -42,13 +42,15 @@
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include "src/core/iomgr/fd_posix.h"
#include "src/core/iomgr/iomgr_internal.h"
#include "src/core/support/block_annotate.h"
#include <grpc/support/alloc.h> #include <grpc/support/alloc.h>
#include <grpc/support/log.h> #include <grpc/support/log.h>
#include <grpc/support/useful.h> #include <grpc/support/useful.h>
#include "src/core/iomgr/fd_posix.h"
#include "src/core/iomgr/iomgr_internal.h"
#include "src/core/iomgr/pollset_posix.h"
#include "src/core/support/block_annotate.h"
typedef struct { typedef struct {
/* all polled fds */ /* all polled fds */
size_t fd_count; size_t fd_count;

@ -42,16 +42,16 @@
#include <string.h> #include <string.h>
#include <unistd.h> #include <unistd.h>
#include "src/core/iomgr/fd_posix.h"
#include "src/core/iomgr/iomgr_internal.h"
#include "src/core/iomgr/socket_utils_posix.h"
#include "src/core/profiling/timers.h"
#include "src/core/support/block_annotate.h"
#include <grpc/support/alloc.h> #include <grpc/support/alloc.h>
#include <grpc/support/log.h> #include <grpc/support/log.h>
#include <grpc/support/thd.h> #include <grpc/support/thd.h>
#include <grpc/support/tls.h> #include <grpc/support/tls.h>
#include <grpc/support/useful.h> #include <grpc/support/useful.h>
#include "src/core/iomgr/fd_posix.h"
#include "src/core/iomgr/iomgr_internal.h"
#include "src/core/iomgr/socket_utils_posix.h"
#include "src/core/profiling/timers.h"
#include "src/core/support/block_annotate.h"
GPR_TLS_DECL(g_current_thread_poller); GPR_TLS_DECL(g_current_thread_poller);
GPR_TLS_DECL(g_current_thread_worker); GPR_TLS_DECL(g_current_thread_worker);
@ -97,6 +97,8 @@ static void push_front_worker(grpc_pollset *p, grpc_pollset_worker *worker) {
worker->prev->next = worker->next->prev = worker; worker->prev->next = worker->next->prev = worker;
} }
size_t grpc_pollset_size(void) { return sizeof(grpc_pollset); }
void grpc_pollset_kick_ext(grpc_pollset *p, void grpc_pollset_kick_ext(grpc_pollset *p,
grpc_pollset_worker *specific_worker, grpc_pollset_worker *specific_worker,
uint32_t flags) { uint32_t flags) {
@ -186,8 +188,9 @@ void grpc_kick_poller(void) { grpc_wakeup_fd_wakeup(&grpc_global_wakeup_fd); }
static void become_basic_pollset(grpc_pollset *pollset, grpc_fd *fd_or_null); static void become_basic_pollset(grpc_pollset *pollset, grpc_fd *fd_or_null);
void grpc_pollset_init(grpc_pollset *pollset) { void grpc_pollset_init(grpc_pollset *pollset, gpr_mu **mu) {
gpr_mu_init(&pollset->mu); gpr_mu_init(&pollset->mu);
*mu = &pollset->mu;
pollset->root_worker.next = pollset->root_worker.prev = &pollset->root_worker; pollset->root_worker.next = pollset->root_worker.prev = &pollset->root_worker;
pollset->in_flight_cbs = 0; pollset->in_flight_cbs = 0;
pollset->shutting_down = 0; pollset->shutting_down = 0;
@ -204,7 +207,6 @@ void grpc_pollset_destroy(grpc_pollset *pollset) {
GPR_ASSERT(!grpc_pollset_has_workers(pollset)); GPR_ASSERT(!grpc_pollset_has_workers(pollset));
GPR_ASSERT(pollset->idle_jobs.head == pollset->idle_jobs.tail); GPR_ASSERT(pollset->idle_jobs.head == pollset->idle_jobs.tail);
pollset->vtable->destroy(pollset); pollset->vtable->destroy(pollset);
gpr_mu_destroy(&pollset->mu);
while (pollset->local_wakeup_cache) { while (pollset->local_wakeup_cache) {
grpc_cached_wakeup_fd *next = pollset->local_wakeup_cache->next; grpc_cached_wakeup_fd *next = pollset->local_wakeup_cache->next;
grpc_wakeup_fd_destroy(&pollset->local_wakeup_cache->fd); grpc_wakeup_fd_destroy(&pollset->local_wakeup_cache->fd);
@ -246,8 +248,11 @@ static void finish_shutdown(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset) {
} }
void grpc_pollset_work(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset, void grpc_pollset_work(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset,
grpc_pollset_worker *worker, gpr_timespec now, grpc_pollset_worker **worker_hdl, gpr_timespec now,
gpr_timespec deadline) { gpr_timespec deadline) {
grpc_pollset_worker worker;
*worker_hdl = &worker;
/* pollset->mu already held */ /* pollset->mu already held */
int added_worker = 0; int added_worker = 0;
int locked = 1; int locked = 1;
@ -255,16 +260,16 @@ void grpc_pollset_work(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset,
int keep_polling = 0; int keep_polling = 0;
GPR_TIMER_BEGIN("grpc_pollset_work", 0); GPR_TIMER_BEGIN("grpc_pollset_work", 0);
/* this must happen before we (potentially) drop pollset->mu */ /* this must happen before we (potentially) drop pollset->mu */
worker->next = worker->prev = NULL; worker.next = worker.prev = NULL;
worker->reevaluate_polling_on_wakeup = 0; worker.reevaluate_polling_on_wakeup = 0;
if (pollset->local_wakeup_cache != NULL) { if (pollset->local_wakeup_cache != NULL) {
worker->wakeup_fd = pollset->local_wakeup_cache; worker.wakeup_fd = pollset->local_wakeup_cache;
pollset->local_wakeup_cache = worker->wakeup_fd->next; pollset->local_wakeup_cache = worker.wakeup_fd->next;
} else { } else {
worker->wakeup_fd = gpr_malloc(sizeof(*worker->wakeup_fd)); worker.wakeup_fd = gpr_malloc(sizeof(*worker.wakeup_fd));
grpc_wakeup_fd_init(&worker->wakeup_fd->fd); grpc_wakeup_fd_init(&worker.wakeup_fd->fd);
} }
worker->kicked_specifically = 0; worker.kicked_specifically = 0;
/* If there's work waiting for the pollset to be idle, and the /* If there's work waiting for the pollset to be idle, and the
pollset is idle, then do that work */ pollset is idle, then do that work */
if (!grpc_pollset_has_workers(pollset) && if (!grpc_pollset_has_workers(pollset) &&
@ -293,13 +298,13 @@ void grpc_pollset_work(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset,
keep_polling = 0; keep_polling = 0;
if (!pollset->kicked_without_pollers) { if (!pollset->kicked_without_pollers) {
if (!added_worker) { if (!added_worker) {
push_front_worker(pollset, worker); push_front_worker(pollset, &worker);
added_worker = 1; added_worker = 1;
gpr_tls_set(&g_current_thread_worker, (intptr_t)worker); gpr_tls_set(&g_current_thread_worker, (intptr_t)&worker);
} }
gpr_tls_set(&g_current_thread_poller, (intptr_t)pollset); gpr_tls_set(&g_current_thread_poller, (intptr_t)pollset);
GPR_TIMER_BEGIN("maybe_work_and_unlock", 0); GPR_TIMER_BEGIN("maybe_work_and_unlock", 0);
pollset->vtable->maybe_work_and_unlock(exec_ctx, pollset, worker, pollset->vtable->maybe_work_and_unlock(exec_ctx, pollset, &worker,
deadline, now); deadline, now);
GPR_TIMER_END("maybe_work_and_unlock", 0); GPR_TIMER_END("maybe_work_and_unlock", 0);
locked = 0; locked = 0;
@ -321,10 +326,10 @@ void grpc_pollset_work(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset,
/* If we're forced to re-evaluate polling (via grpc_pollset_kick with /* If we're forced to re-evaluate polling (via grpc_pollset_kick with
GRPC_POLLSET_REEVALUATE_POLLING_ON_WAKEUP) then we land here and force GRPC_POLLSET_REEVALUATE_POLLING_ON_WAKEUP) then we land here and force
a loop */ a loop */
if (worker->reevaluate_polling_on_wakeup) { if (worker.reevaluate_polling_on_wakeup) {
worker->reevaluate_polling_on_wakeup = 0; worker.reevaluate_polling_on_wakeup = 0;
pollset->kicked_without_pollers = 0; pollset->kicked_without_pollers = 0;
if (queued_work || worker->kicked_specifically) { if (queued_work || worker.kicked_specifically) {
/* If there's queued work on the list, then set the deadline to be /* If there's queued work on the list, then set the deadline to be
immediate so we get back out of the polling loop quickly */ immediate so we get back out of the polling loop quickly */
deadline = gpr_inf_past(GPR_CLOCK_MONOTONIC); deadline = gpr_inf_past(GPR_CLOCK_MONOTONIC);
@ -333,12 +338,12 @@ void grpc_pollset_work(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset,
} }
} }
if (added_worker) { if (added_worker) {
remove_worker(pollset, worker); remove_worker(pollset, &worker);
gpr_tls_set(&g_current_thread_worker, 0); gpr_tls_set(&g_current_thread_worker, 0);
} }
/* release wakeup fd to the local pool */ /* release wakeup fd to the local pool */
worker->wakeup_fd->next = pollset->local_wakeup_cache; worker.wakeup_fd->next = pollset->local_wakeup_cache;
pollset->local_wakeup_cache = worker->wakeup_fd; pollset->local_wakeup_cache = worker.wakeup_fd;
/* check shutdown conditions */ /* check shutdown conditions */
if (pollset->shutting_down) { if (pollset->shutting_down) {
if (grpc_pollset_has_workers(pollset)) { if (grpc_pollset_has_workers(pollset)) {
@ -360,6 +365,7 @@ void grpc_pollset_work(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset,
gpr_mu_lock(&pollset->mu); gpr_mu_lock(&pollset->mu);
} }
} }
*worker_hdl = NULL;
GPR_TIMER_END("grpc_pollset_work", 0); GPR_TIMER_END("grpc_pollset_work", 0);
} }

@ -37,8 +37,10 @@
#include <poll.h> #include <poll.h>
#include <grpc/support/sync.h> #include <grpc/support/sync.h>
#include "src/core/iomgr/exec_ctx.h" #include "src/core/iomgr/exec_ctx.h"
#include "src/core/iomgr/iomgr.h" #include "src/core/iomgr/iomgr.h"
#include "src/core/iomgr/pollset.h"
#include "src/core/iomgr/wakeup_fd_posix.h" #include "src/core/iomgr/wakeup_fd_posix.h"
typedef struct grpc_pollset_vtable grpc_pollset_vtable; typedef struct grpc_pollset_vtable grpc_pollset_vtable;
@ -53,15 +55,15 @@ typedef struct grpc_cached_wakeup_fd {
struct grpc_cached_wakeup_fd *next; struct grpc_cached_wakeup_fd *next;
} grpc_cached_wakeup_fd; } grpc_cached_wakeup_fd;
typedef struct grpc_pollset_worker { struct grpc_pollset_worker {
grpc_cached_wakeup_fd *wakeup_fd; grpc_cached_wakeup_fd *wakeup_fd;
int reevaluate_polling_on_wakeup; int reevaluate_polling_on_wakeup;
int kicked_specifically; int kicked_specifically;
struct grpc_pollset_worker *next; struct grpc_pollset_worker *next;
struct grpc_pollset_worker *prev; struct grpc_pollset_worker *prev;
} grpc_pollset_worker; };
typedef struct grpc_pollset { struct grpc_pollset {
/* pollsets under posix can mutate representation as fds are added and /* pollsets under posix can mutate representation as fds are added and
removed. removed.
For example, we may choose a poll() based implementation on linux for For example, we may choose a poll() based implementation on linux for
@ -81,7 +83,7 @@ typedef struct grpc_pollset {
} data; } data;
/* Local cache of eventfds for workers */ /* Local cache of eventfds for workers */
grpc_cached_wakeup_fd *local_wakeup_cache; grpc_cached_wakeup_fd *local_wakeup_cache;
} grpc_pollset; };
struct grpc_pollset_vtable { struct grpc_pollset_vtable {
void (*add_fd)(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset, void (*add_fd)(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset,
@ -93,8 +95,6 @@ struct grpc_pollset_vtable {
void (*destroy)(grpc_pollset *pollset); void (*destroy)(grpc_pollset *pollset);
}; };
#define GRPC_POLLSET_MU(pollset) (&(pollset)->mu)
/* Add an fd to a pollset */ /* Add an fd to a pollset */
void grpc_pollset_add_fd(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset, void grpc_pollset_add_fd(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset,
struct grpc_fd *fd); struct grpc_fd *fd);

@ -1,6 +1,6 @@
/* /*
* *
* Copyright 2015, Google Inc. * Copyright 2015-2016, Google Inc.
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
@ -41,15 +41,9 @@
fd's (etc) that have been registered with the set_set to that pollset. fd's (etc) that have been registered with the set_set to that pollset.
Registering fd's automatically adds them to all current pollsets. */ Registering fd's automatically adds them to all current pollsets. */
#ifdef GPR_POSIX_SOCKET typedef struct grpc_pollset_set grpc_pollset_set;
#include "src/core/iomgr/pollset_set_posix.h"
#endif
#ifdef GPR_WIN32 grpc_pollset_set *grpc_pollset_set_create(void);
#include "src/core/iomgr/pollset_set_windows.h"
#endif
void grpc_pollset_set_init(grpc_pollset_set *pollset_set);
void grpc_pollset_set_destroy(grpc_pollset_set *pollset_set); void grpc_pollset_set_destroy(grpc_pollset_set *pollset_set);
void grpc_pollset_set_add_pollset(grpc_exec_ctx *exec_ctx, void grpc_pollset_set_add_pollset(grpc_exec_ctx *exec_ctx,
grpc_pollset_set *pollset_set, grpc_pollset_set *pollset_set,

@ -1,6 +1,6 @@
/* /*
* *
* Copyright 2015, Google Inc. * Copyright 2015-2016, Google Inc.
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
@ -41,11 +41,30 @@
#include <grpc/support/alloc.h> #include <grpc/support/alloc.h>
#include <grpc/support/useful.h> #include <grpc/support/useful.h>
#include "src/core/iomgr/pollset_set.h" #include "src/core/iomgr/pollset_posix.h"
#include "src/core/iomgr/pollset_set_posix.h"
void grpc_pollset_set_init(grpc_pollset_set *pollset_set) { struct grpc_pollset_set {
gpr_mu mu;
size_t pollset_count;
size_t pollset_capacity;
grpc_pollset **pollsets;
size_t pollset_set_count;
size_t pollset_set_capacity;
struct grpc_pollset_set **pollset_sets;
size_t fd_count;
size_t fd_capacity;
grpc_fd **fds;
};
grpc_pollset_set *grpc_pollset_set_create(void) {
grpc_pollset_set *pollset_set = gpr_malloc(sizeof(*pollset_set));
memset(pollset_set, 0, sizeof(*pollset_set)); memset(pollset_set, 0, sizeof(*pollset_set));
gpr_mu_init(&pollset_set->mu); gpr_mu_init(&pollset_set->mu);
return pollset_set;
} }
void grpc_pollset_set_destroy(grpc_pollset_set *pollset_set) { void grpc_pollset_set_destroy(grpc_pollset_set *pollset_set) {
@ -57,6 +76,7 @@ void grpc_pollset_set_destroy(grpc_pollset_set *pollset_set) {
gpr_free(pollset_set->pollsets); gpr_free(pollset_set->pollsets);
gpr_free(pollset_set->pollset_sets); gpr_free(pollset_set->pollset_sets);
gpr_free(pollset_set->fds); gpr_free(pollset_set->fds);
gpr_free(pollset_set);
} }
void grpc_pollset_set_add_pollset(grpc_exec_ctx *exec_ctx, void grpc_pollset_set_add_pollset(grpc_exec_ctx *exec_ctx,

@ -1,6 +1,6 @@
/* /*
* *
* Copyright 2015, Google Inc. * Copyright 2015-2016, Google Inc.
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
@ -35,23 +35,7 @@
#define GRPC_INTERNAL_CORE_IOMGR_POLLSET_SET_POSIX_H #define GRPC_INTERNAL_CORE_IOMGR_POLLSET_SET_POSIX_H
#include "src/core/iomgr/fd_posix.h" #include "src/core/iomgr/fd_posix.h"
#include "src/core/iomgr/pollset_posix.h" #include "src/core/iomgr/pollset_set.h"
typedef struct grpc_pollset_set {
gpr_mu mu;
size_t pollset_count;
size_t pollset_capacity;
grpc_pollset **pollsets;
size_t pollset_set_count;
size_t pollset_set_capacity;
struct grpc_pollset_set **pollset_sets;
size_t fd_count;
size_t fd_capacity;
grpc_fd **fds;
} grpc_pollset_set;
void grpc_pollset_set_add_fd(grpc_exec_ctx *exec_ctx, void grpc_pollset_set_add_fd(grpc_exec_ctx *exec_ctx,
grpc_pollset_set *pollset_set, grpc_fd *fd); grpc_pollset_set *pollset_set, grpc_fd *fd);

@ -1,6 +1,6 @@
/* /*
* *
* Copyright 2015, Google Inc. * Copyright 2015-2016, Google Inc.
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
@ -35,9 +35,9 @@
#ifdef GPR_WINSOCK_SOCKET #ifdef GPR_WINSOCK_SOCKET
#include "src/core/iomgr/pollset_set.h" #include "src/core/iomgr/pollset_set_windows.h"
void grpc_pollset_set_init(grpc_pollset_set* pollset_set) {} grpc_pollset_set* grpc_pollset_set_create(pollset_set) { return NULL; }
void grpc_pollset_set_destroy(grpc_pollset_set* pollset_set) {} void grpc_pollset_set_destroy(grpc_pollset_set* pollset_set) {}

@ -1,6 +1,6 @@
/* /*
* *
* Copyright 2015, Google Inc. * Copyright 2015-2016, Google Inc.
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
@ -34,6 +34,6 @@
#ifndef GRPC_INTERNAL_CORE_IOMGR_POLLSET_SET_WINDOWS_H #ifndef GRPC_INTERNAL_CORE_IOMGR_POLLSET_SET_WINDOWS_H
#define GRPC_INTERNAL_CORE_IOMGR_POLLSET_SET_WINDOWS_H #define GRPC_INTERNAL_CORE_IOMGR_POLLSET_SET_WINDOWS_H
typedef struct grpc_pollset_set { void *unused; } grpc_pollset_set; #include "src/core/iomgr/pollset_set.h"
#endif /* GRPC_INTERNAL_CORE_IOMGR_POLLSET_WINDOWS_H */ #endif /* GRPC_INTERNAL_CORE_IOMGR_POLLSET_WINDOWS_H */

@ -89,12 +89,15 @@ static void push_front_worker(grpc_pollset_worker *root,
worker->links[type].next->links[type].prev = worker; worker->links[type].next->links[type].prev = worker;
} }
size_t grpc_pollset_size(void) { return sizeof(grpc_pollset); }
/* There isn't really any such thing as a pollset under Windows, due to the /* There isn't really any such thing as a pollset under Windows, due to the
nature of the IO completion ports. We're still going to provide a minimal nature of the IO completion ports. We're still going to provide a minimal
set of features for the sake of the rest of grpc. But grpc_pollset_work set of features for the sake of the rest of grpc. But grpc_pollset_work
won't actually do any polling, and return as quickly as possible. */ won't actually do any polling, and return as quickly as possible. */
void grpc_pollset_init(grpc_pollset *pollset) { void grpc_pollset_init(grpc_pollset *pollset, gpr_mu **mu) {
*mu = &grpc_polling_mu;
memset(pollset, 0, sizeof(*pollset)); memset(pollset, 0, sizeof(*pollset));
pollset->root_worker.links[GRPC_POLLSET_WORKER_LINK_POLLSET].next = pollset->root_worker.links[GRPC_POLLSET_WORKER_LINK_POLLSET].next =
pollset->root_worker.links[GRPC_POLLSET_WORKER_LINK_POLLSET].prev = pollset->root_worker.links[GRPC_POLLSET_WORKER_LINK_POLLSET].prev =
@ -125,22 +128,25 @@ void grpc_pollset_reset(grpc_pollset *pollset) {
} }
void grpc_pollset_work(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset, void grpc_pollset_work(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset,
grpc_pollset_worker *worker, gpr_timespec now, grpc_pollset_worker **worker_hdl, gpr_timespec now,
gpr_timespec deadline) { gpr_timespec deadline) {
grpc_pollset_worker worker;
*worker_hdl = &worker;
int added_worker = 0; int added_worker = 0;
worker->links[GRPC_POLLSET_WORKER_LINK_POLLSET].next = worker.links[GRPC_POLLSET_WORKER_LINK_POLLSET].next =
worker->links[GRPC_POLLSET_WORKER_LINK_POLLSET].prev = worker.links[GRPC_POLLSET_WORKER_LINK_POLLSET].prev =
worker->links[GRPC_POLLSET_WORKER_LINK_GLOBAL].next = worker.links[GRPC_POLLSET_WORKER_LINK_GLOBAL].next =
worker->links[GRPC_POLLSET_WORKER_LINK_GLOBAL].prev = NULL; worker.links[GRPC_POLLSET_WORKER_LINK_GLOBAL].prev = NULL;
worker->kicked = 0; worker.kicked = 0;
worker->pollset = pollset; worker.pollset = pollset;
gpr_cv_init(&worker->cv); gpr_cv_init(&worker.cv);
if (!pollset->kicked_without_pollers && !pollset->shutting_down) { if (!pollset->kicked_without_pollers && !pollset->shutting_down) {
if (g_active_poller == NULL) { if (g_active_poller == NULL) {
grpc_pollset_worker *next_worker; grpc_pollset_worker *next_worker;
/* become poller */ /* become poller */
pollset->is_iocp_worker = 1; pollset->is_iocp_worker = 1;
g_active_poller = worker; g_active_poller = &worker;
gpr_mu_unlock(&grpc_polling_mu); gpr_mu_unlock(&grpc_polling_mu);
grpc_iocp_work(exec_ctx, deadline); grpc_iocp_work(exec_ctx, deadline);
grpc_exec_ctx_flush(exec_ctx); grpc_exec_ctx_flush(exec_ctx);
@ -167,12 +173,12 @@ void grpc_pollset_work(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset,
goto done; goto done;
} }
push_front_worker(&g_global_root_worker, GRPC_POLLSET_WORKER_LINK_GLOBAL, push_front_worker(&g_global_root_worker, GRPC_POLLSET_WORKER_LINK_GLOBAL,
worker); &worker);
push_front_worker(&pollset->root_worker, GRPC_POLLSET_WORKER_LINK_POLLSET, push_front_worker(&pollset->root_worker, GRPC_POLLSET_WORKER_LINK_POLLSET,
worker); &worker);
added_worker = 1; added_worker = 1;
while (!worker->kicked) { while (!worker.kicked) {
if (gpr_cv_wait(&worker->cv, &grpc_polling_mu, deadline)) { if (gpr_cv_wait(&worker.cv, &grpc_polling_mu, deadline)) {
break; break;
} }
} }
@ -186,10 +192,11 @@ done:
gpr_mu_lock(&grpc_polling_mu); gpr_mu_lock(&grpc_polling_mu);
} }
if (added_worker) { if (added_worker) {
remove_worker(worker, GRPC_POLLSET_WORKER_LINK_GLOBAL); remove_worker(&worker, GRPC_POLLSET_WORKER_LINK_GLOBAL);
remove_worker(worker, GRPC_POLLSET_WORKER_LINK_POLLSET); remove_worker(&worker, GRPC_POLLSET_WORKER_LINK_POLLSET);
} }
gpr_cv_destroy(&worker->cv); gpr_cv_destroy(&worker.cv);
*worker_hdl = NULL;
} }
void grpc_pollset_kick(grpc_pollset *p, grpc_pollset_worker *specific_worker) { void grpc_pollset_kick(grpc_pollset *p, grpc_pollset_worker *specific_worker) {

@ -1,6 +1,6 @@
/* /*
* *
* Copyright 2015, Google Inc. * Copyright 2015-2016, Google Inc.
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
@ -72,8 +72,4 @@ struct grpc_pollset {
grpc_closure *on_shutdown; grpc_closure *on_shutdown;
}; };
extern gpr_mu grpc_polling_mu;
#define GRPC_POLLSET_MU(pollset) (&grpc_polling_mu)
#endif /* GRPC_INTERNAL_CORE_IOMGR_POLLSET_WINDOWS_H */ #endif /* GRPC_INTERNAL_CORE_IOMGR_POLLSET_WINDOWS_H */

@ -42,17 +42,19 @@
#include <string.h> #include <string.h>
#include <unistd.h> #include <unistd.h>
#include "src/core/iomgr/timer.h" #include <grpc/support/alloc.h>
#include <grpc/support/log.h>
#include <grpc/support/string_util.h>
#include <grpc/support/time.h>
#include "src/core/iomgr/iomgr_posix.h" #include "src/core/iomgr/iomgr_posix.h"
#include "src/core/iomgr/pollset_posix.h" #include "src/core/iomgr/pollset_posix.h"
#include "src/core/iomgr/pollset_set_posix.h"
#include "src/core/iomgr/sockaddr_utils.h" #include "src/core/iomgr/sockaddr_utils.h"
#include "src/core/iomgr/socket_utils_posix.h" #include "src/core/iomgr/socket_utils_posix.h"
#include "src/core/iomgr/tcp_posix.h" #include "src/core/iomgr/tcp_posix.h"
#include "src/core/iomgr/timer.h"
#include "src/core/support/string.h" #include "src/core/support/string.h"
#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
#include <grpc/support/string_util.h>
#include <grpc/support/time.h>
extern int grpc_tcp_trace; extern int grpc_tcp_trace;

@ -40,8 +40,8 @@
#include <errno.h> #include <errno.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <sys/types.h>
#include <sys/socket.h> #include <sys/socket.h>
#include <sys/types.h>
#include <unistd.h> #include <unistd.h>
#include <grpc/support/alloc.h> #include <grpc/support/alloc.h>
@ -51,9 +51,11 @@
#include <grpc/support/sync.h> #include <grpc/support/sync.h>
#include <grpc/support/time.h> #include <grpc/support/time.h>
#include "src/core/support/string.h"
#include "src/core/debug/trace.h" #include "src/core/debug/trace.h"
#include "src/core/iomgr/pollset_posix.h"
#include "src/core/iomgr/pollset_set_posix.h"
#include "src/core/profiling/timers.h" #include "src/core/profiling/timers.h"
#include "src/core/support/string.h"
#ifdef GPR_HAVE_MSG_NOSIGNAL #ifdef GPR_HAVE_MSG_NOSIGNAL
#define SENDMSG_FLAGS MSG_NOSIGNAL #define SENDMSG_FLAGS MSG_NOSIGNAL

@ -35,6 +35,7 @@
#define GRPC_INTERNAL_CORE_IOMGR_UDP_SERVER_H #define GRPC_INTERNAL_CORE_IOMGR_UDP_SERVER_H
#include "src/core/iomgr/endpoint.h" #include "src/core/iomgr/endpoint.h"
#include "src/core/iomgr/fd_posix.h"
/* Forward decl of grpc_server */ /* Forward decl of grpc_server */
typedef struct grpc_server grpc_server; typedef struct grpc_server grpc_server;

@ -44,6 +44,7 @@
#include <grpc/support/useful.h> #include <grpc/support/useful.h>
#include "src/core/iomgr/fd_posix.h" #include "src/core/iomgr/fd_posix.h"
#include "src/core/iomgr/pollset_posix.h"
static void on_readable(grpc_exec_ctx *exec_ctx, void *arg, bool success); static void on_readable(grpc_exec_ctx *exec_ctx, void *arg, bool success);

@ -1,6 +1,6 @@
/* /*
* *
* Copyright 2015, Google Inc. * Copyright 2015-2016, Google Inc.
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
@ -34,6 +34,8 @@
#ifndef GRPC_INTERNAL_CORE_IOMGR_WORKQUEUE_POSIX_H #ifndef GRPC_INTERNAL_CORE_IOMGR_WORKQUEUE_POSIX_H
#define GRPC_INTERNAL_CORE_IOMGR_WORKQUEUE_POSIX_H #define GRPC_INTERNAL_CORE_IOMGR_WORKQUEUE_POSIX_H
#include "src/core/iomgr/wakeup_fd_posix.h"
struct grpc_fd; struct grpc_fd;
struct grpc_workqueue { struct grpc_workqueue {

@ -310,7 +310,6 @@ static void init_channel_elem(grpc_exec_ctx *exec_ctx,
GPR_ASSERT(auth_context != NULL); GPR_ASSERT(auth_context != NULL);
/* initialize members */ /* initialize members */
GPR_ASSERT(sc->is_client_side);
chand->security_connector = chand->security_connector =
(grpc_channel_security_connector *)GRPC_SECURITY_CONNECTOR_REF( (grpc_channel_security_connector *)GRPC_SECURITY_CONNECTOR_REF(
sc, "client_auth_filter"); sc, "client_auth_filter");

@ -166,7 +166,7 @@ void grpc_server_credentials_release(grpc_server_credentials *creds) {
} }
grpc_security_status grpc_server_credentials_create_security_connector( grpc_security_status grpc_server_credentials_create_security_connector(
grpc_server_credentials *creds, grpc_security_connector **sc) { grpc_server_credentials *creds, grpc_server_security_connector **sc) {
if (creds == NULL || creds->vtable->create_security_connector == NULL) { if (creds == NULL || creds->vtable->create_security_connector == NULL) {
gpr_log(GPR_ERROR, "Server credentials cannot create security context."); gpr_log(GPR_ERROR, "Server credentials cannot create security context.");
return GRPC_SECURITY_ERROR; return GRPC_SECURITY_ERROR;
@ -298,7 +298,7 @@ static grpc_security_status ssl_create_security_connector(
} }
static grpc_security_status ssl_server_create_security_connector( static grpc_security_status ssl_server_create_security_connector(
grpc_server_credentials *creds, grpc_security_connector **sc) { grpc_server_credentials *creds, grpc_server_security_connector **sc) {
grpc_ssl_server_credentials *c = (grpc_ssl_server_credentials *)creds; grpc_ssl_server_credentials *c = (grpc_ssl_server_credentials *)creds;
return grpc_ssl_server_security_connector_create(&c->config, sc); return grpc_ssl_server_security_connector_create(&c->config, sc);
} }
@ -894,7 +894,7 @@ static grpc_security_status fake_transport_security_create_security_connector(
static grpc_security_status static grpc_security_status
fake_transport_security_server_create_security_connector( fake_transport_security_server_create_security_connector(
grpc_server_credentials *c, grpc_security_connector **sc) { grpc_server_credentials *c, grpc_server_security_connector **sc) {
*sc = grpc_fake_server_security_connector_create(); *sc = grpc_fake_server_security_connector_create();
return GRPC_SECURITY_OK; return GRPC_SECURITY_OK;
} }

@ -1,6 +1,6 @@
/* /*
* *
* Copyright 2015, Google Inc. * Copyright 2015-2016, Google Inc.
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
@ -234,7 +234,7 @@ grpc_refresh_token_credentials_create_from_auth_refresh_token(
typedef struct { typedef struct {
void (*destruct)(grpc_server_credentials *c); void (*destruct)(grpc_server_credentials *c);
grpc_security_status (*create_security_connector)( grpc_security_status (*create_security_connector)(
grpc_server_credentials *c, grpc_security_connector **sc); grpc_server_credentials *c, grpc_server_security_connector **sc);
} grpc_server_credentials_vtable; } grpc_server_credentials_vtable;
struct grpc_server_credentials { struct grpc_server_credentials {
@ -245,7 +245,7 @@ struct grpc_server_credentials {
}; };
grpc_security_status grpc_server_credentials_create_security_connector( grpc_security_status grpc_server_credentials_create_security_connector(
grpc_server_credentials *creds, grpc_security_connector **sc); grpc_server_credentials *creds, grpc_server_security_connector **sc);
grpc_server_credentials *grpc_server_credentials_ref( grpc_server_credentials *grpc_server_credentials_ref(
grpc_server_credentials *creds); grpc_server_credentials *creds);

@ -52,13 +52,14 @@
static grpc_channel_credentials *default_credentials = NULL; static grpc_channel_credentials *default_credentials = NULL;
static int compute_engine_detection_done = 0; static int compute_engine_detection_done = 0;
static gpr_mu g_mu; static gpr_mu g_state_mu;
static gpr_mu *g_polling_mu;
static gpr_once g_once = GPR_ONCE_INIT; static gpr_once g_once = GPR_ONCE_INIT;
static void init_default_credentials(void) { gpr_mu_init(&g_mu); } static void init_default_credentials(void) { gpr_mu_init(&g_state_mu); }
typedef struct { typedef struct {
grpc_pollset pollset; grpc_pollset *pollset;
int is_done; int is_done;
int success; int success;
} compute_engine_detector; } compute_engine_detector;
@ -80,10 +81,10 @@ static void on_compute_engine_detection_http_response(
} }
} }
} }
gpr_mu_lock(GRPC_POLLSET_MU(&detector->pollset)); gpr_mu_lock(g_polling_mu);
detector->is_done = 1; detector->is_done = 1;
grpc_pollset_kick(&detector->pollset, NULL); grpc_pollset_kick(detector->pollset, NULL);
gpr_mu_unlock(GRPC_POLLSET_MU(&detector->pollset)); gpr_mu_unlock(g_polling_mu);
} }
static void destroy_pollset(grpc_exec_ctx *exec_ctx, void *p, bool s) { static void destroy_pollset(grpc_exec_ctx *exec_ctx, void *p, bool s) {
@ -101,7 +102,8 @@ static int is_stack_running_on_compute_engine(void) {
on compute engine. */ on compute engine. */
gpr_timespec max_detection_delay = gpr_time_from_seconds(1, GPR_TIMESPAN); gpr_timespec max_detection_delay = gpr_time_from_seconds(1, GPR_TIMESPAN);
grpc_pollset_init(&detector.pollset); detector.pollset = gpr_malloc(grpc_pollset_size());
grpc_pollset_init(detector.pollset, &g_polling_mu);
detector.is_done = 0; detector.is_done = 0;
detector.success = 0; detector.success = 0;
@ -112,7 +114,7 @@ static int is_stack_running_on_compute_engine(void) {
grpc_httpcli_context_init(&context); grpc_httpcli_context_init(&context);
grpc_httpcli_get( grpc_httpcli_get(
&exec_ctx, &context, &detector.pollset, &request, &exec_ctx, &context, detector.pollset, &request,
gpr_time_add(gpr_now(GPR_CLOCK_REALTIME), max_detection_delay), gpr_time_add(gpr_now(GPR_CLOCK_REALTIME), max_detection_delay),
on_compute_engine_detection_http_response, &detector); on_compute_engine_detection_http_response, &detector);
@ -120,19 +122,22 @@ static int is_stack_running_on_compute_engine(void) {
/* Block until we get the response. This is not ideal but this should only be /* Block until we get the response. This is not ideal but this should only be
called once for the lifetime of the process by the default credentials. */ called once for the lifetime of the process by the default credentials. */
gpr_mu_lock(GRPC_POLLSET_MU(&detector.pollset)); gpr_mu_lock(g_polling_mu);
while (!detector.is_done) { while (!detector.is_done) {
grpc_pollset_worker worker; grpc_pollset_worker *worker = NULL;
grpc_pollset_work(&exec_ctx, &detector.pollset, &worker, grpc_pollset_work(&exec_ctx, detector.pollset, &worker,
gpr_now(GPR_CLOCK_MONOTONIC), gpr_now(GPR_CLOCK_MONOTONIC),
gpr_inf_future(GPR_CLOCK_MONOTONIC)); gpr_inf_future(GPR_CLOCK_MONOTONIC));
} }
gpr_mu_unlock(GRPC_POLLSET_MU(&detector.pollset)); gpr_mu_unlock(g_polling_mu);
grpc_httpcli_context_destroy(&context); grpc_httpcli_context_destroy(&context);
grpc_closure_init(&destroy_closure, destroy_pollset, &detector.pollset); grpc_closure_init(&destroy_closure, destroy_pollset, detector.pollset);
grpc_pollset_shutdown(&exec_ctx, &detector.pollset, &destroy_closure); grpc_pollset_shutdown(&exec_ctx, detector.pollset, &destroy_closure);
grpc_exec_ctx_finish(&exec_ctx); grpc_exec_ctx_finish(&exec_ctx);
g_polling_mu = NULL;
gpr_free(detector.pollset);
return detector.success; return detector.success;
} }
@ -184,7 +189,7 @@ grpc_channel_credentials *grpc_google_default_credentials_create(void) {
gpr_once_init(&g_once, init_default_credentials); gpr_once_init(&g_once, init_default_credentials);
gpr_mu_lock(&g_mu); gpr_mu_lock(&g_state_mu);
if (default_credentials != NULL) { if (default_credentials != NULL) {
result = grpc_channel_credentials_ref(default_credentials); result = grpc_channel_credentials_ref(default_credentials);
@ -230,19 +235,19 @@ end:
gpr_log(GPR_ERROR, "Could not create google default credentials."); gpr_log(GPR_ERROR, "Could not create google default credentials.");
} }
} }
gpr_mu_unlock(&g_mu); gpr_mu_unlock(&g_state_mu);
return result; return result;
} }
void grpc_flush_cached_google_default_credentials(void) { void grpc_flush_cached_google_default_credentials(void) {
gpr_once_init(&g_once, init_default_credentials); gpr_once_init(&g_once, init_default_credentials);
gpr_mu_lock(&g_mu); gpr_mu_lock(&g_state_mu);
if (default_credentials != NULL) { if (default_credentials != NULL) {
grpc_channel_credentials_unref(default_credentials); grpc_channel_credentials_unref(default_credentials);
default_credentials = NULL; default_credentials = NULL;
} }
compute_engine_detection_done = 0; compute_engine_detection_done = 0;
gpr_mu_unlock(&g_mu); gpr_mu_unlock(&g_state_mu);
} }
/* -- Well known credentials path. -- */ /* -- Well known credentials path. -- */

@ -33,6 +33,7 @@
#include "src/core/security/handshake.h" #include "src/core/security/handshake.h"
#include <stdbool.h>
#include <string.h> #include <string.h>
#include "src/core/security/security_context.h" #include "src/core/security/security_context.h"
@ -46,6 +47,7 @@
typedef struct { typedef struct {
grpc_security_connector *connector; grpc_security_connector *connector;
tsi_handshaker *handshaker; tsi_handshaker *handshaker;
bool is_client_side;
unsigned char *handshake_buffer; unsigned char *handshake_buffer;
size_t handshake_buffer_size; size_t handshake_buffer_size;
grpc_endpoint *wrapped_endpoint; grpc_endpoint *wrapped_endpoint;
@ -67,9 +69,11 @@ static void on_handshake_data_sent_to_peer(grpc_exec_ctx *exec_ctx, void *setup,
bool success); bool success);
static void security_connector_remove_handshake(grpc_security_handshake *h) { static void security_connector_remove_handshake(grpc_security_handshake *h) {
GPR_ASSERT(!h->is_client_side);
grpc_security_connector_handshake_list *node; grpc_security_connector_handshake_list *node;
grpc_security_connector_handshake_list *tmp; grpc_security_connector_handshake_list *tmp;
grpc_security_connector *sc = h->connector; grpc_server_security_connector *sc =
(grpc_server_security_connector *)h->connector;
gpr_mu_lock(&sc->mu); gpr_mu_lock(&sc->mu);
node = sc->handshaking_handshakes; node = sc->handshaking_handshakes;
if (node && node->handshake == h) { if (node && node->handshake == h) {
@ -94,7 +98,7 @@ static void security_connector_remove_handshake(grpc_security_handshake *h) {
static void security_handshake_done(grpc_exec_ctx *exec_ctx, static void security_handshake_done(grpc_exec_ctx *exec_ctx,
grpc_security_handshake *h, grpc_security_handshake *h,
int is_success) { int is_success) {
if (!h->connector->is_client_side) { if (!h->is_client_side) {
security_connector_remove_handshake(h); security_connector_remove_handshake(h);
} }
if (is_success) { if (is_success) {
@ -290,6 +294,7 @@ static void on_handshake_data_sent_to_peer(grpc_exec_ctx *exec_ctx,
void grpc_do_security_handshake(grpc_exec_ctx *exec_ctx, void grpc_do_security_handshake(grpc_exec_ctx *exec_ctx,
tsi_handshaker *handshaker, tsi_handshaker *handshaker,
grpc_security_connector *connector, grpc_security_connector *connector,
bool is_client_side,
grpc_endpoint *nonsecure_endpoint, grpc_endpoint *nonsecure_endpoint,
grpc_security_handshake_done_cb cb, grpc_security_handshake_done_cb cb,
void *user_data) { void *user_data) {
@ -298,6 +303,7 @@ void grpc_do_security_handshake(grpc_exec_ctx *exec_ctx,
memset(h, 0, sizeof(grpc_security_handshake)); memset(h, 0, sizeof(grpc_security_handshake));
h->handshaker = handshaker; h->handshaker = handshaker;
h->connector = GRPC_SECURITY_CONNECTOR_REF(connector, "handshake"); h->connector = GRPC_SECURITY_CONNECTOR_REF(connector, "handshake");
h->is_client_side = is_client_side;
h->handshake_buffer_size = GRPC_INITIAL_HANDSHAKE_BUFFER_SIZE; h->handshake_buffer_size = GRPC_INITIAL_HANDSHAKE_BUFFER_SIZE;
h->handshake_buffer = gpr_malloc(h->handshake_buffer_size); h->handshake_buffer = gpr_malloc(h->handshake_buffer_size);
h->wrapped_endpoint = nonsecure_endpoint; h->wrapped_endpoint = nonsecure_endpoint;
@ -310,13 +316,15 @@ void grpc_do_security_handshake(grpc_exec_ctx *exec_ctx,
gpr_slice_buffer_init(&h->left_overs); gpr_slice_buffer_init(&h->left_overs);
gpr_slice_buffer_init(&h->outgoing); gpr_slice_buffer_init(&h->outgoing);
gpr_slice_buffer_init(&h->incoming); gpr_slice_buffer_init(&h->incoming);
if (!connector->is_client_side) { if (!is_client_side) {
grpc_server_security_connector *server_connector =
(grpc_server_security_connector *)connector;
handshake_node = gpr_malloc(sizeof(grpc_security_connector_handshake_list)); handshake_node = gpr_malloc(sizeof(grpc_security_connector_handshake_list));
handshake_node->handshake = h; handshake_node->handshake = h;
gpr_mu_lock(&connector->mu); gpr_mu_lock(&server_connector->mu);
handshake_node->next = connector->handshaking_handshakes; handshake_node->next = server_connector->handshaking_handshakes;
connector->handshaking_handshakes = handshake_node; server_connector->handshaking_handshakes = handshake_node;
gpr_mu_unlock(&connector->mu); gpr_mu_unlock(&server_connector->mu);
} }
send_handshake_bytes_to_peer(exec_ctx, h); send_handshake_bytes_to_peer(exec_ctx, h);
} }

@ -1,6 +1,6 @@
/* /*
* *
* Copyright 2015, Google Inc. * Copyright 2015-2016, Google Inc.
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
@ -41,6 +41,7 @@
void grpc_do_security_handshake(grpc_exec_ctx *exec_ctx, void grpc_do_security_handshake(grpc_exec_ctx *exec_ctx,
tsi_handshaker *handshaker, tsi_handshaker *handshaker,
grpc_security_connector *connector, grpc_security_connector *connector,
bool is_client_side,
grpc_endpoint *nonsecure_endpoint, grpc_endpoint *nonsecure_endpoint,
grpc_security_handshake_done_cb cb, grpc_security_handshake_done_cb cb,
void *user_data); void *user_data);

@ -33,6 +33,7 @@
#include "src/core/security/security_connector.h" #include "src/core/security/security_connector.h"
#include <stdbool.h>
#include <string.h> #include <string.h>
#include <grpc/support/alloc.h> #include <grpc/support/alloc.h>
@ -110,31 +111,39 @@ const tsi_peer_property *tsi_peer_get_property_by_name(const tsi_peer *peer,
return NULL; return NULL;
} }
void grpc_security_connector_shutdown(grpc_exec_ctx *exec_ctx, void grpc_server_security_connector_shutdown(
grpc_security_connector *connector) { grpc_exec_ctx *exec_ctx, grpc_server_security_connector *connector) {
grpc_security_connector_handshake_list *tmp; grpc_security_connector_handshake_list *tmp;
if (!connector->is_client_side) { gpr_mu_lock(&connector->mu);
gpr_mu_lock(&connector->mu); while (connector->handshaking_handshakes) {
while (connector->handshaking_handshakes) { tmp = connector->handshaking_handshakes;
tmp = connector->handshaking_handshakes; grpc_security_handshake_shutdown(
grpc_security_handshake_shutdown( exec_ctx, connector->handshaking_handshakes->handshake);
exec_ctx, connector->handshaking_handshakes->handshake); connector->handshaking_handshakes = tmp->next;
connector->handshaking_handshakes = tmp->next; gpr_free(tmp);
gpr_free(tmp); }
} gpr_mu_unlock(&connector->mu);
gpr_mu_unlock(&connector->mu); }
void grpc_channel_security_connector_do_handshake(
grpc_exec_ctx *exec_ctx, grpc_channel_security_connector *sc,
grpc_endpoint *nonsecure_endpoint, grpc_security_handshake_done_cb cb,
void *user_data) {
if (sc == NULL || nonsecure_endpoint == NULL) {
cb(exec_ctx, user_data, GRPC_SECURITY_ERROR, NULL, NULL);
} else {
sc->do_handshake(exec_ctx, sc, nonsecure_endpoint, cb, user_data);
} }
} }
void grpc_security_connector_do_handshake(grpc_exec_ctx *exec_ctx, void grpc_server_security_connector_do_handshake(
grpc_security_connector *sc, grpc_exec_ctx *exec_ctx, grpc_server_security_connector *sc,
grpc_endpoint *nonsecure_endpoint, grpc_tcp_server_acceptor *acceptor, grpc_endpoint *nonsecure_endpoint,
grpc_security_handshake_done_cb cb, grpc_security_handshake_done_cb cb, void *user_data) {
void *user_data) {
if (sc == NULL || nonsecure_endpoint == NULL) { if (sc == NULL || nonsecure_endpoint == NULL) {
cb(exec_ctx, user_data, GRPC_SECURITY_ERROR, NULL, NULL); cb(exec_ctx, user_data, GRPC_SECURITY_ERROR, NULL, NULL);
} else { } else {
sc->vtable->do_handshake(exec_ctx, sc, nonsecure_endpoint, cb, user_data); sc->do_handshake(exec_ctx, sc, acceptor, nonsecure_endpoint, cb, user_data);
} }
} }
@ -248,7 +257,8 @@ static void fake_channel_destroy(grpc_security_connector *sc) {
} }
static void fake_server_destroy(grpc_security_connector *sc) { static void fake_server_destroy(grpc_security_connector *sc) {
gpr_mu_destroy(&sc->mu); grpc_server_security_connector *c = (grpc_server_security_connector *)sc;
gpr_mu_destroy(&c->mu);
gpr_free(sc); gpr_free(sc);
} }
@ -298,49 +308,52 @@ static void fake_channel_check_call_host(grpc_exec_ctx *exec_ctx,
} }
static void fake_channel_do_handshake(grpc_exec_ctx *exec_ctx, static void fake_channel_do_handshake(grpc_exec_ctx *exec_ctx,
grpc_security_connector *sc, grpc_channel_security_connector *sc,
grpc_endpoint *nonsecure_endpoint, grpc_endpoint *nonsecure_endpoint,
grpc_security_handshake_done_cb cb, grpc_security_handshake_done_cb cb,
void *user_data) { void *user_data) {
grpc_do_security_handshake(exec_ctx, tsi_create_fake_handshaker(1), sc, grpc_do_security_handshake(exec_ctx, tsi_create_fake_handshaker(1), &sc->base,
nonsecure_endpoint, cb, user_data); true, nonsecure_endpoint, cb, user_data);
} }
static void fake_server_do_handshake(grpc_exec_ctx *exec_ctx, static void fake_server_do_handshake(grpc_exec_ctx *exec_ctx,
grpc_security_connector *sc, grpc_server_security_connector *sc,
grpc_tcp_server_acceptor *acceptor,
grpc_endpoint *nonsecure_endpoint, grpc_endpoint *nonsecure_endpoint,
grpc_security_handshake_done_cb cb, grpc_security_handshake_done_cb cb,
void *user_data) { void *user_data) {
grpc_do_security_handshake(exec_ctx, tsi_create_fake_handshaker(0), sc, grpc_do_security_handshake(exec_ctx, tsi_create_fake_handshaker(0), &sc->base,
nonsecure_endpoint, cb, user_data); false, nonsecure_endpoint, cb, user_data);
} }
static grpc_security_connector_vtable fake_channel_vtable = { static grpc_security_connector_vtable fake_channel_vtable = {
fake_channel_destroy, fake_channel_do_handshake, fake_check_peer}; fake_channel_destroy, fake_check_peer};
static grpc_security_connector_vtable fake_server_vtable = { static grpc_security_connector_vtable fake_server_vtable = {fake_server_destroy,
fake_server_destroy, fake_server_do_handshake, fake_check_peer}; fake_check_peer};
grpc_channel_security_connector *grpc_fake_channel_security_connector_create( grpc_channel_security_connector *grpc_fake_channel_security_connector_create(
grpc_call_credentials *request_metadata_creds) { grpc_call_credentials *request_metadata_creds) {
grpc_channel_security_connector *c = gpr_malloc(sizeof(*c)); grpc_channel_security_connector *c = gpr_malloc(sizeof(*c));
memset(c, 0, sizeof(*c)); memset(c, 0, sizeof(*c));
gpr_ref_init(&c->base.refcount, 1); gpr_ref_init(&c->base.refcount, 1);
c->base.is_client_side = 1;
c->base.url_scheme = GRPC_FAKE_SECURITY_URL_SCHEME; c->base.url_scheme = GRPC_FAKE_SECURITY_URL_SCHEME;
c->base.vtable = &fake_channel_vtable; c->base.vtable = &fake_channel_vtable;
c->request_metadata_creds = grpc_call_credentials_ref(request_metadata_creds); c->request_metadata_creds = grpc_call_credentials_ref(request_metadata_creds);
c->check_call_host = fake_channel_check_call_host; c->check_call_host = fake_channel_check_call_host;
c->do_handshake = fake_channel_do_handshake;
return c; return c;
} }
grpc_security_connector *grpc_fake_server_security_connector_create(void) { grpc_server_security_connector *grpc_fake_server_security_connector_create(
grpc_security_connector *c = gpr_malloc(sizeof(grpc_security_connector)); void) {
memset(c, 0, sizeof(grpc_security_connector)); grpc_server_security_connector *c =
gpr_ref_init(&c->refcount, 1); gpr_malloc(sizeof(grpc_server_security_connector));
c->is_client_side = 0; memset(c, 0, sizeof(*c));
c->vtable = &fake_server_vtable; gpr_ref_init(&c->base.refcount, 1);
c->url_scheme = GRPC_FAKE_SECURITY_URL_SCHEME; c->base.vtable = &fake_server_vtable;
c->base.url_scheme = GRPC_FAKE_SECURITY_URL_SCHEME;
c->do_handshake = fake_server_do_handshake;
gpr_mu_init(&c->mu); gpr_mu_init(&c->mu);
return c; return c;
} }
@ -355,7 +368,7 @@ typedef struct {
} grpc_ssl_channel_security_connector; } grpc_ssl_channel_security_connector;
typedef struct { typedef struct {
grpc_security_connector base; grpc_server_security_connector base;
tsi_ssl_handshaker_factory *handshaker_factory; tsi_ssl_handshaker_factory *handshaker_factory;
} grpc_ssl_server_security_connector; } grpc_ssl_server_security_connector;
@ -378,12 +391,12 @@ static void ssl_server_destroy(grpc_security_connector *sc) {
if (c->handshaker_factory != NULL) { if (c->handshaker_factory != NULL) {
tsi_ssl_handshaker_factory_destroy(c->handshaker_factory); tsi_ssl_handshaker_factory_destroy(c->handshaker_factory);
} }
gpr_mu_destroy(&sc->mu); gpr_mu_destroy(&c->base.mu);
gpr_free(sc); gpr_free(sc);
} }
static grpc_security_status ssl_create_handshaker( static grpc_security_status ssl_create_handshaker(
tsi_ssl_handshaker_factory *handshaker_factory, int is_client, tsi_ssl_handshaker_factory *handshaker_factory, bool is_client,
const char *peer_name, tsi_handshaker **handshaker) { const char *peer_name, tsi_handshaker **handshaker) {
tsi_result result = TSI_OK; tsi_result result = TSI_OK;
if (handshaker_factory == NULL) return GRPC_SECURITY_ERROR; if (handshaker_factory == NULL) return GRPC_SECURITY_ERROR;
@ -398,7 +411,7 @@ static grpc_security_status ssl_create_handshaker(
} }
static void ssl_channel_do_handshake(grpc_exec_ctx *exec_ctx, static void ssl_channel_do_handshake(grpc_exec_ctx *exec_ctx,
grpc_security_connector *sc, grpc_channel_security_connector *sc,
grpc_endpoint *nonsecure_endpoint, grpc_endpoint *nonsecure_endpoint,
grpc_security_handshake_done_cb cb, grpc_security_handshake_done_cb cb,
void *user_data) { void *user_data) {
@ -406,20 +419,21 @@ static void ssl_channel_do_handshake(grpc_exec_ctx *exec_ctx,
(grpc_ssl_channel_security_connector *)sc; (grpc_ssl_channel_security_connector *)sc;
tsi_handshaker *handshaker; tsi_handshaker *handshaker;
grpc_security_status status = ssl_create_handshaker( grpc_security_status status = ssl_create_handshaker(
c->handshaker_factory, 1, c->handshaker_factory, true,
c->overridden_target_name != NULL ? c->overridden_target_name c->overridden_target_name != NULL ? c->overridden_target_name
: c->target_name, : c->target_name,
&handshaker); &handshaker);
if (status != GRPC_SECURITY_OK) { if (status != GRPC_SECURITY_OK) {
cb(exec_ctx, user_data, status, NULL, NULL); cb(exec_ctx, user_data, status, NULL, NULL);
} else { } else {
grpc_do_security_handshake(exec_ctx, handshaker, sc, nonsecure_endpoint, cb, grpc_do_security_handshake(exec_ctx, handshaker, &sc->base, true,
user_data); nonsecure_endpoint, cb, user_data);
} }
} }
static void ssl_server_do_handshake(grpc_exec_ctx *exec_ctx, static void ssl_server_do_handshake(grpc_exec_ctx *exec_ctx,
grpc_security_connector *sc, grpc_server_security_connector *sc,
grpc_tcp_server_acceptor *acceptor,
grpc_endpoint *nonsecure_endpoint, grpc_endpoint *nonsecure_endpoint,
grpc_security_handshake_done_cb cb, grpc_security_handshake_done_cb cb,
void *user_data) { void *user_data) {
@ -427,12 +441,12 @@ static void ssl_server_do_handshake(grpc_exec_ctx *exec_ctx,
(grpc_ssl_server_security_connector *)sc; (grpc_ssl_server_security_connector *)sc;
tsi_handshaker *handshaker; tsi_handshaker *handshaker;
grpc_security_status status = grpc_security_status status =
ssl_create_handshaker(c->handshaker_factory, 0, NULL, &handshaker); ssl_create_handshaker(c->handshaker_factory, false, NULL, &handshaker);
if (status != GRPC_SECURITY_OK) { if (status != GRPC_SECURITY_OK) {
cb(exec_ctx, user_data, status, NULL, NULL); cb(exec_ctx, user_data, status, NULL, NULL);
} else { } else {
grpc_do_security_handshake(exec_ctx, handshaker, sc, nonsecure_endpoint, cb, grpc_do_security_handshake(exec_ctx, handshaker, &sc->base, false,
user_data); nonsecure_endpoint, cb, user_data);
} }
} }
@ -603,10 +617,10 @@ static void ssl_channel_check_call_host(grpc_exec_ctx *exec_ctx,
} }
static grpc_security_connector_vtable ssl_channel_vtable = { static grpc_security_connector_vtable ssl_channel_vtable = {
ssl_channel_destroy, ssl_channel_do_handshake, ssl_channel_check_peer}; ssl_channel_destroy, ssl_channel_check_peer};
static grpc_security_connector_vtable ssl_server_vtable = { static grpc_security_connector_vtable ssl_server_vtable = {
ssl_server_destroy, ssl_server_do_handshake, ssl_server_check_peer}; ssl_server_destroy, ssl_server_check_peer};
static gpr_slice compute_default_pem_root_certs_once(void) { static gpr_slice compute_default_pem_root_certs_once(void) {
gpr_slice result = gpr_empty_slice(); gpr_slice result = gpr_empty_slice();
@ -700,11 +714,11 @@ grpc_security_status grpc_ssl_channel_security_connector_create(
gpr_ref_init(&c->base.base.refcount, 1); gpr_ref_init(&c->base.base.refcount, 1);
c->base.base.vtable = &ssl_channel_vtable; c->base.base.vtable = &ssl_channel_vtable;
c->base.base.is_client_side = 1;
c->base.base.url_scheme = GRPC_SSL_URL_SCHEME; c->base.base.url_scheme = GRPC_SSL_URL_SCHEME;
c->base.request_metadata_creds = c->base.request_metadata_creds =
grpc_call_credentials_ref(request_metadata_creds); grpc_call_credentials_ref(request_metadata_creds);
c->base.check_call_host = ssl_channel_check_call_host; c->base.check_call_host = ssl_channel_check_call_host;
c->base.do_handshake = ssl_channel_do_handshake;
gpr_split_host_port(target_name, &c->target_name, &port); gpr_split_host_port(target_name, &c->target_name, &port);
gpr_free(port); gpr_free(port);
if (overridden_target_name != NULL) { if (overridden_target_name != NULL) {
@ -735,7 +749,7 @@ error:
} }
grpc_security_status grpc_ssl_server_security_connector_create( grpc_security_status grpc_ssl_server_security_connector_create(
const grpc_ssl_server_config *config, grpc_security_connector **sc) { const grpc_ssl_server_config *config, grpc_server_security_connector **sc) {
size_t num_alpn_protocols = grpc_chttp2_num_alpn_versions(); size_t num_alpn_protocols = grpc_chttp2_num_alpn_versions();
const unsigned char **alpn_protocol_strings = const unsigned char **alpn_protocol_strings =
gpr_malloc(sizeof(const char *) * num_alpn_protocols); gpr_malloc(sizeof(const char *) * num_alpn_protocols);
@ -759,9 +773,9 @@ grpc_security_status grpc_ssl_server_security_connector_create(
c = gpr_malloc(sizeof(grpc_ssl_server_security_connector)); c = gpr_malloc(sizeof(grpc_ssl_server_security_connector));
memset(c, 0, sizeof(grpc_ssl_server_security_connector)); memset(c, 0, sizeof(grpc_ssl_server_security_connector));
gpr_ref_init(&c->base.refcount, 1); gpr_ref_init(&c->base.base.refcount, 1);
c->base.url_scheme = GRPC_SSL_URL_SCHEME; c->base.base.url_scheme = GRPC_SSL_URL_SCHEME;
c->base.vtable = &ssl_server_vtable; c->base.base.vtable = &ssl_server_vtable;
result = tsi_create_ssl_server_handshaker_factory( result = tsi_create_ssl_server_handshaker_factory(
(const unsigned char **)config->pem_private_keys, (const unsigned char **)config->pem_private_keys,
config->pem_private_keys_sizes, config->pem_private_keys_sizes,
@ -774,11 +788,12 @@ grpc_security_status grpc_ssl_server_security_connector_create(
if (result != TSI_OK) { if (result != TSI_OK) {
gpr_log(GPR_ERROR, "Handshaker factory creation failed with %s.", gpr_log(GPR_ERROR, "Handshaker factory creation failed with %s.",
tsi_result_to_string(result)); tsi_result_to_string(result));
ssl_server_destroy(&c->base); ssl_server_destroy(&c->base.base);
*sc = NULL; *sc = NULL;
goto error; goto error;
} }
gpr_mu_init(&c->base.mu); gpr_mu_init(&c->base.mu);
c->base.do_handshake = ssl_server_do_handshake;
*sc = &c->base; *sc = &c->base;
gpr_free((void *)alpn_protocol_strings); gpr_free((void *)alpn_protocol_strings);
gpr_free(alpn_protocol_string_lengths); gpr_free(alpn_protocol_string_lengths);

@ -36,6 +36,7 @@
#include <grpc/grpc_security.h> #include <grpc/grpc_security.h>
#include "src/core/iomgr/endpoint.h" #include "src/core/iomgr/endpoint.h"
#include "src/core/iomgr/tcp_server.h"
#include "src/core/tsi/transport_security_interface.h" #include "src/core/tsi/transport_security_interface.h"
/* --- status enum. --- */ /* --- status enum. --- */
@ -68,9 +69,6 @@ typedef void (*grpc_security_handshake_done_cb)(
typedef struct { typedef struct {
void (*destroy)(grpc_security_connector *sc); void (*destroy)(grpc_security_connector *sc);
void (*do_handshake)(grpc_exec_ctx *exec_ctx, grpc_security_connector *sc,
grpc_endpoint *nonsecure_endpoint,
grpc_security_handshake_done_cb cb, void *user_data);
void (*check_peer)(grpc_exec_ctx *exec_ctx, grpc_security_connector *sc, void (*check_peer)(grpc_exec_ctx *exec_ctx, grpc_security_connector *sc,
tsi_peer peer, grpc_security_peer_check_cb cb, tsi_peer peer, grpc_security_peer_check_cb cb,
void *user_data); void *user_data);
@ -84,13 +82,7 @@ typedef struct grpc_security_connector_handshake_list {
struct grpc_security_connector { struct grpc_security_connector {
const grpc_security_connector_vtable *vtable; const grpc_security_connector_vtable *vtable;
gpr_refcount refcount; gpr_refcount refcount;
int is_client_side;
const char *url_scheme; const char *url_scheme;
/* Used on server side only. */
/* TODO(yangg): Create a grpc_server_security_connector with these. */
gpr_mu mu;
grpc_security_connector_handshake_list *handshaking_handshakes;
const grpc_channel_args *channel_args;
}; };
/* Refcounting. */ /* Refcounting. */
@ -113,13 +105,6 @@ grpc_security_connector *grpc_security_connector_ref(
void grpc_security_connector_unref(grpc_security_connector *policy); void grpc_security_connector_unref(grpc_security_connector *policy);
#endif #endif
/* Handshake. */
void grpc_security_connector_do_handshake(grpc_exec_ctx *exec_ctx,
grpc_security_connector *connector,
grpc_endpoint *nonsecure_endpoint,
grpc_security_handshake_done_cb cb,
void *user_data);
/* Check the peer. Callee takes ownership of the peer object. /* Check the peer. Callee takes ownership of the peer object.
The callback will include the resulting auth_context. */ The callback will include the resulting auth_context. */
void grpc_security_connector_check_peer(grpc_exec_ctx *exec_ctx, void grpc_security_connector_check_peer(grpc_exec_ctx *exec_ctx,
@ -128,9 +113,6 @@ void grpc_security_connector_check_peer(grpc_exec_ctx *exec_ctx,
grpc_security_peer_check_cb cb, grpc_security_peer_check_cb cb,
void *user_data); void *user_data);
void grpc_security_connector_shutdown(grpc_exec_ctx *exec_ctx,
grpc_security_connector *connector);
/* Util to encapsulate the connector in a channel arg. */ /* Util to encapsulate the connector in a channel arg. */
grpc_arg grpc_security_connector_to_arg(grpc_security_connector *sc); grpc_arg grpc_security_connector_to_arg(grpc_security_connector *sc);
@ -153,12 +135,16 @@ typedef void (*grpc_security_call_host_check_cb)(grpc_exec_ctx *exec_ctx,
grpc_security_status status); grpc_security_status status);
struct grpc_channel_security_connector { struct grpc_channel_security_connector {
grpc_security_connector base; /* requires is_client_side to be non 0. */ grpc_security_connector base;
grpc_call_credentials *request_metadata_creds; grpc_call_credentials *request_metadata_creds;
void (*check_call_host)(grpc_exec_ctx *exec_ctx, void (*check_call_host)(grpc_exec_ctx *exec_ctx,
grpc_channel_security_connector *sc, const char *host, grpc_channel_security_connector *sc, const char *host,
grpc_auth_context *auth_context, grpc_auth_context *auth_context,
grpc_security_call_host_check_cb cb, void *user_data); grpc_security_call_host_check_cb cb, void *user_data);
void (*do_handshake)(grpc_exec_ctx *exec_ctx,
grpc_channel_security_connector *sc,
grpc_endpoint *nonsecure_endpoint,
grpc_security_handshake_done_cb cb, void *user_data);
}; };
/* Checks that the host that will be set for a call is acceptable. */ /* Checks that the host that will be set for a call is acceptable. */
@ -167,6 +153,39 @@ void grpc_channel_security_connector_check_call_host(
const char *host, grpc_auth_context *auth_context, const char *host, grpc_auth_context *auth_context,
grpc_security_call_host_check_cb cb, void *user_data); grpc_security_call_host_check_cb cb, void *user_data);
/* Handshake. */
void grpc_channel_security_connector_do_handshake(
grpc_exec_ctx *exec_ctx, grpc_channel_security_connector *connector,
grpc_endpoint *nonsecure_endpoint, grpc_security_handshake_done_cb cb,
void *user_data);
/* --- server_security_connector object. ---
A server security connector object represents away to configure the
underlying transport security mechanism on the server side. */
typedef struct grpc_server_security_connector grpc_server_security_connector;
struct grpc_server_security_connector {
grpc_security_connector base;
gpr_mu mu;
grpc_security_connector_handshake_list *handshaking_handshakes;
const grpc_channel_args *channel_args;
void (*do_handshake)(grpc_exec_ctx *exec_ctx,
grpc_server_security_connector *sc,
grpc_tcp_server_acceptor *acceptor,
grpc_endpoint *nonsecure_endpoint,
grpc_security_handshake_done_cb cb, void *user_data);
};
void grpc_server_security_connector_do_handshake(
grpc_exec_ctx *exec_ctx, grpc_server_security_connector *sc,
grpc_tcp_server_acceptor *acceptor, grpc_endpoint *nonsecure_endpoint,
grpc_security_handshake_done_cb cb, void *user_data);
void grpc_server_security_connector_shutdown(
grpc_exec_ctx *exec_ctx, grpc_server_security_connector *connector);
/* --- Creation security connectors. --- */ /* --- Creation security connectors. --- */
/* For TESTING ONLY! /* For TESTING ONLY!
@ -176,7 +195,8 @@ grpc_channel_security_connector *grpc_fake_channel_security_connector_create(
/* For TESTING ONLY! /* For TESTING ONLY!
Creates a fake connector that emulates real server security. */ Creates a fake connector that emulates real server security. */
grpc_security_connector *grpc_fake_server_security_connector_create(void); grpc_server_security_connector *grpc_fake_server_security_connector_create(
void);
/* Config for ssl clients. */ /* Config for ssl clients. */
typedef struct { typedef struct {
@ -231,7 +251,7 @@ typedef struct {
specific error code otherwise. specific error code otherwise.
*/ */
grpc_security_status grpc_ssl_server_security_connector_create( grpc_security_status grpc_ssl_server_security_connector_create(
const grpc_ssl_server_config *config, grpc_security_connector **sc); const grpc_ssl_server_config *config, grpc_server_security_connector **sc);
/* Util. */ /* Util. */
const tsi_peer_property *tsi_peer_get_property_by_name(const tsi_peer *peer, const tsi_peer_property *tsi_peer_get_property_by_name(const tsi_peer *peer,

@ -55,7 +55,7 @@
typedef struct grpc_server_secure_state { typedef struct grpc_server_secure_state {
grpc_server *server; grpc_server *server;
grpc_tcp_server *tcp; grpc_tcp_server *tcp;
grpc_security_connector *sc; grpc_server_security_connector *sc;
grpc_server_credentials *creds; grpc_server_credentials *creds;
int is_shutdown; int is_shutdown;
gpr_mu mu; gpr_mu mu;
@ -74,7 +74,7 @@ static void state_unref(grpc_server_secure_state *state) {
gpr_mu_lock(&state->mu); gpr_mu_lock(&state->mu);
gpr_mu_unlock(&state->mu); gpr_mu_unlock(&state->mu);
/* clean up */ /* clean up */
GRPC_SECURITY_CONNECTOR_UNREF(state->sc, "server"); GRPC_SECURITY_CONNECTOR_UNREF(&state->sc->base, "server");
grpc_server_credentials_unref(state->creds); grpc_server_credentials_unref(state->creds);
gpr_free(state); gpr_free(state);
} }
@ -130,8 +130,8 @@ static void on_accept(grpc_exec_ctx *exec_ctx, void *statep, grpc_endpoint *tcp,
grpc_tcp_server_acceptor *acceptor) { grpc_tcp_server_acceptor *acceptor) {
grpc_server_secure_state *state = statep; grpc_server_secure_state *state = statep;
state_ref(state); state_ref(state);
grpc_security_connector_do_handshake(exec_ctx, state->sc, tcp, grpc_server_security_connector_do_handshake(
on_secure_handshake_done, state); exec_ctx, state->sc, acceptor, tcp, on_secure_handshake_done, state);
} }
/* Server callback: start listening on our ports */ /* Server callback: start listening on our ports */
@ -148,7 +148,7 @@ static void destroy_done(grpc_exec_ctx *exec_ctx, void *statep, bool success) {
state->destroy_callback->cb(exec_ctx, state->destroy_callback->cb_arg, state->destroy_callback->cb(exec_ctx, state->destroy_callback->cb_arg,
success); success);
} }
grpc_security_connector_shutdown(exec_ctx, state->sc); grpc_server_security_connector_shutdown(exec_ctx, state->sc);
state_unref(state); state_unref(state);
} }
@ -176,7 +176,7 @@ int grpc_server_add_secure_http2_port(grpc_server *server, const char *addr,
int port_num = -1; int port_num = -1;
int port_temp; int port_temp;
grpc_security_status status = GRPC_SECURITY_ERROR; grpc_security_status status = GRPC_SECURITY_ERROR;
grpc_security_connector *sc = NULL; grpc_server_security_connector *sc = NULL;
grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
GRPC_API_TRACE( GRPC_API_TRACE(
@ -256,7 +256,7 @@ error:
grpc_tcp_server_unref(&exec_ctx, tcp); grpc_tcp_server_unref(&exec_ctx, tcp);
} else { } else {
if (sc) { if (sc) {
GRPC_SECURITY_CONNECTOR_UNREF(sc, "server"); GRPC_SECURITY_CONNECTOR_UNREF(&sc->base, "server");
} }
if (state) { if (state) {
gpr_free(state); gpr_free(state);

@ -1,6 +1,6 @@
/* /*
* *
* Copyright 2015, Google Inc. * Copyright 2015-2016, Google Inc.
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
@ -98,6 +98,11 @@ void gpr_ref_init(gpr_refcount *r, int n) { gpr_atm_rel_store(&r->count, n); }
void gpr_ref(gpr_refcount *r) { gpr_atm_no_barrier_fetch_add(&r->count, 1); } void gpr_ref(gpr_refcount *r) { gpr_atm_no_barrier_fetch_add(&r->count, 1); }
void gpr_ref_non_zero(gpr_refcount *r) {
gpr_atm prior = gpr_atm_no_barrier_fetch_add(&r->count, 1);
GPR_ASSERT(prior > 0);
}
void gpr_refn(gpr_refcount *r, int n) { void gpr_refn(gpr_refcount *r, int n) {
gpr_atm_no_barrier_fetch_add(&r->count, n); gpr_atm_no_barrier_fetch_add(&r->count, n);
} }

@ -64,8 +64,9 @@ 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_timer_init(&exec_ctx, &alarm->alarm, deadline, alarm_cb, alarm, grpc_timer_init(&exec_ctx, &alarm->alarm,
gpr_now(GPR_CLOCK_MONOTONIC)); gpr_convert_clock_type(deadline, GPR_CLOCK_MONOTONIC),
alarm_cb, alarm, gpr_now(GPR_CLOCK_MONOTONIC));
grpc_exec_ctx_finish(&exec_ctx); grpc_exec_ctx_finish(&exec_ctx);
return alarm; return alarm;
} }

@ -36,26 +36,29 @@
#include <stdio.h> #include <stdio.h>
#include <string.h> #include <string.h>
#include "src/core/iomgr/timer.h" #include <grpc/support/alloc.h>
#include <grpc/support/atm.h>
#include <grpc/support/log.h>
#include <grpc/support/time.h>
#include "src/core/iomgr/pollset.h" #include "src/core/iomgr/pollset.h"
#include "src/core/iomgr/timer.h"
#include "src/core/profiling/timers.h"
#include "src/core/support/string.h" #include "src/core/support/string.h"
#include "src/core/surface/api_trace.h" #include "src/core/surface/api_trace.h"
#include "src/core/surface/call.h" #include "src/core/surface/call.h"
#include "src/core/surface/event_string.h" #include "src/core/surface/event_string.h"
#include "src/core/surface/surface_trace.h" #include "src/core/surface/surface_trace.h"
#include "src/core/profiling/timers.h"
#include <grpc/support/alloc.h>
#include <grpc/support/atm.h>
#include <grpc/support/log.h>
#include <grpc/support/time.h>
typedef struct { typedef struct {
grpc_pollset_worker *worker; grpc_pollset_worker **worker;
void *tag; void *tag;
} plucker; } plucker;
/* Completion queue structure */ /* Completion queue structure */
struct grpc_completion_queue { struct grpc_completion_queue {
/** owned by pollset */
gpr_mu *mu;
/** completed events */ /** completed events */
grpc_cq_completion completed_head; grpc_cq_completion completed_head;
grpc_cq_completion *completed_tail; grpc_cq_completion *completed_tail;
@ -63,8 +66,6 @@ struct grpc_completion_queue {
gpr_refcount pending_events; gpr_refcount pending_events;
/** Once owning_refs drops to zero, we will destroy the cq */ /** Once owning_refs drops to zero, we will destroy the cq */
gpr_refcount owning_refs; gpr_refcount owning_refs;
/** the set of low level i/o things that concern this cq */
grpc_pollset pollset;
/** 0 initially, 1 once we've begun shutting down */ /** 0 initially, 1 once we've begun shutting down */
int shutdown; int shutdown;
int shutdown_called; int shutdown_called;
@ -82,6 +83,8 @@ struct grpc_completion_queue {
grpc_completion_queue *next_free; grpc_completion_queue *next_free;
}; };
#define POLLSET_FROM_CQ(cq) ((grpc_pollset *)(cq + 1))
static gpr_mu g_freelist_mu; static gpr_mu g_freelist_mu;
grpc_completion_queue *g_freelist; grpc_completion_queue *g_freelist;
@ -94,7 +97,7 @@ void grpc_cq_global_shutdown(void) {
gpr_mu_destroy(&g_freelist_mu); gpr_mu_destroy(&g_freelist_mu);
while (g_freelist) { while (g_freelist) {
grpc_completion_queue *next = g_freelist->next_free; grpc_completion_queue *next = g_freelist->next_free;
grpc_pollset_destroy(&g_freelist->pollset); grpc_pollset_destroy(POLLSET_FROM_CQ(g_freelist));
#ifndef NDEBUG #ifndef NDEBUG
gpr_free(g_freelist->outstanding_tags); gpr_free(g_freelist->outstanding_tags);
#endif #endif
@ -124,8 +127,8 @@ grpc_completion_queue *grpc_completion_queue_create(void *reserved) {
if (g_freelist == NULL) { if (g_freelist == NULL) {
gpr_mu_unlock(&g_freelist_mu); gpr_mu_unlock(&g_freelist_mu);
cc = gpr_malloc(sizeof(grpc_completion_queue)); cc = gpr_malloc(sizeof(grpc_completion_queue) + grpc_pollset_size());
grpc_pollset_init(&cc->pollset); grpc_pollset_init(POLLSET_FROM_CQ(cc), &cc->mu);
#ifndef NDEBUG #ifndef NDEBUG
cc->outstanding_tags = NULL; cc->outstanding_tags = NULL;
cc->outstanding_tag_capacity = 0; cc->outstanding_tag_capacity = 0;
@ -184,7 +187,7 @@ void grpc_cq_internal_unref(grpc_completion_queue *cc) {
#endif #endif
if (gpr_unref(&cc->owning_refs)) { if (gpr_unref(&cc->owning_refs)) {
GPR_ASSERT(cc->completed_head.next == (uintptr_t)&cc->completed_head); GPR_ASSERT(cc->completed_head.next == (uintptr_t)&cc->completed_head);
grpc_pollset_reset(&cc->pollset); grpc_pollset_reset(POLLSET_FROM_CQ(cc));
gpr_mu_lock(&g_freelist_mu); gpr_mu_lock(&g_freelist_mu);
cc->next_free = g_freelist; cc->next_free = g_freelist;
g_freelist = cc; g_freelist = cc;
@ -194,7 +197,7 @@ void grpc_cq_internal_unref(grpc_completion_queue *cc) {
void grpc_cq_begin_op(grpc_completion_queue *cc, void *tag) { void grpc_cq_begin_op(grpc_completion_queue *cc, void *tag) {
#ifndef NDEBUG #ifndef NDEBUG
gpr_mu_lock(GRPC_POLLSET_MU(&cc->pollset)); gpr_mu_lock(cc->mu);
GPR_ASSERT(!cc->shutdown_called); GPR_ASSERT(!cc->shutdown_called);
if (cc->outstanding_tag_count == cc->outstanding_tag_capacity) { if (cc->outstanding_tag_count == cc->outstanding_tag_capacity) {
cc->outstanding_tag_capacity = GPR_MAX(4, 2 * cc->outstanding_tag_capacity); cc->outstanding_tag_capacity = GPR_MAX(4, 2 * cc->outstanding_tag_capacity);
@ -203,7 +206,7 @@ void grpc_cq_begin_op(grpc_completion_queue *cc, void *tag) {
cc->outstanding_tag_capacity); cc->outstanding_tag_capacity);
} }
cc->outstanding_tags[cc->outstanding_tag_count++] = tag; cc->outstanding_tags[cc->outstanding_tag_count++] = tag;
gpr_mu_unlock(GRPC_POLLSET_MU(&cc->pollset)); gpr_mu_unlock(cc->mu);
#endif #endif
gpr_ref(&cc->pending_events); gpr_ref(&cc->pending_events);
} }
@ -231,7 +234,7 @@ void grpc_cq_end_op(grpc_exec_ctx *exec_ctx, grpc_completion_queue *cc,
storage->next = storage->next =
((uintptr_t)&cc->completed_head) | ((uintptr_t)(success != 0)); ((uintptr_t)&cc->completed_head) | ((uintptr_t)(success != 0));
gpr_mu_lock(GRPC_POLLSET_MU(&cc->pollset)); gpr_mu_lock(cc->mu);
#ifndef NDEBUG #ifndef NDEBUG
for (i = 0; i < (int)cc->outstanding_tag_count; i++) { for (i = 0; i < (int)cc->outstanding_tag_count; i++) {
if (cc->outstanding_tags[i] == tag) { if (cc->outstanding_tags[i] == tag) {
@ -252,12 +255,12 @@ void grpc_cq_end_op(grpc_exec_ctx *exec_ctx, grpc_completion_queue *cc,
pluck_worker = NULL; pluck_worker = NULL;
for (i = 0; i < cc->num_pluckers; i++) { for (i = 0; i < cc->num_pluckers; i++) {
if (cc->pluckers[i].tag == tag) { if (cc->pluckers[i].tag == tag) {
pluck_worker = cc->pluckers[i].worker; pluck_worker = *cc->pluckers[i].worker;
break; break;
} }
} }
grpc_pollset_kick(&cc->pollset, pluck_worker); grpc_pollset_kick(POLLSET_FROM_CQ(cc), pluck_worker);
gpr_mu_unlock(GRPC_POLLSET_MU(&cc->pollset)); gpr_mu_unlock(cc->mu);
} else { } else {
cc->completed_tail->next = cc->completed_tail->next =
((uintptr_t)storage) | (1u & (uintptr_t)cc->completed_tail->next); ((uintptr_t)storage) | (1u & (uintptr_t)cc->completed_tail->next);
@ -265,8 +268,9 @@ void grpc_cq_end_op(grpc_exec_ctx *exec_ctx, grpc_completion_queue *cc,
GPR_ASSERT(!cc->shutdown); GPR_ASSERT(!cc->shutdown);
GPR_ASSERT(cc->shutdown_called); GPR_ASSERT(cc->shutdown_called);
cc->shutdown = 1; cc->shutdown = 1;
grpc_pollset_shutdown(exec_ctx, &cc->pollset, &cc->pollset_shutdown_done); grpc_pollset_shutdown(exec_ctx, POLLSET_FROM_CQ(cc),
gpr_mu_unlock(GRPC_POLLSET_MU(&cc->pollset)); &cc->pollset_shutdown_done);
gpr_mu_unlock(cc->mu);
} }
GPR_TIMER_END("grpc_cq_end_op", 0); GPR_TIMER_END("grpc_cq_end_op", 0);
@ -275,7 +279,7 @@ void grpc_cq_end_op(grpc_exec_ctx *exec_ctx, grpc_completion_queue *cc,
grpc_event grpc_completion_queue_next(grpc_completion_queue *cc, grpc_event grpc_completion_queue_next(grpc_completion_queue *cc,
gpr_timespec deadline, void *reserved) { gpr_timespec deadline, void *reserved) {
grpc_event ret; grpc_event ret;
grpc_pollset_worker worker; grpc_pollset_worker *worker = NULL;
int first_loop = 1; int first_loop = 1;
gpr_timespec now; gpr_timespec now;
grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
@ -294,7 +298,7 @@ grpc_event grpc_completion_queue_next(grpc_completion_queue *cc,
deadline = gpr_convert_clock_type(deadline, GPR_CLOCK_MONOTONIC); deadline = gpr_convert_clock_type(deadline, GPR_CLOCK_MONOTONIC);
GRPC_CQ_INTERNAL_REF(cc, "next"); GRPC_CQ_INTERNAL_REF(cc, "next");
gpr_mu_lock(GRPC_POLLSET_MU(&cc->pollset)); gpr_mu_lock(cc->mu);
for (;;) { for (;;) {
if (cc->completed_tail != &cc->completed_head) { if (cc->completed_tail != &cc->completed_head) {
grpc_cq_completion *c = (grpc_cq_completion *)cc->completed_head.next; grpc_cq_completion *c = (grpc_cq_completion *)cc->completed_head.next;
@ -302,7 +306,7 @@ grpc_event grpc_completion_queue_next(grpc_completion_queue *cc,
if (c == cc->completed_tail) { if (c == cc->completed_tail) {
cc->completed_tail = &cc->completed_head; cc->completed_tail = &cc->completed_head;
} }
gpr_mu_unlock(GRPC_POLLSET_MU(&cc->pollset)); gpr_mu_unlock(cc->mu);
ret.type = GRPC_OP_COMPLETE; ret.type = GRPC_OP_COMPLETE;
ret.success = c->next & 1u; ret.success = c->next & 1u;
ret.tag = c->tag; ret.tag = c->tag;
@ -310,14 +314,14 @@ grpc_event grpc_completion_queue_next(grpc_completion_queue *cc,
break; break;
} }
if (cc->shutdown) { if (cc->shutdown) {
gpr_mu_unlock(GRPC_POLLSET_MU(&cc->pollset)); gpr_mu_unlock(cc->mu);
memset(&ret, 0, sizeof(ret)); memset(&ret, 0, sizeof(ret));
ret.type = GRPC_QUEUE_SHUTDOWN; ret.type = GRPC_QUEUE_SHUTDOWN;
break; break;
} }
now = gpr_now(GPR_CLOCK_MONOTONIC); now = gpr_now(GPR_CLOCK_MONOTONIC);
if (!first_loop && gpr_time_cmp(now, deadline) >= 0) { if (!first_loop && gpr_time_cmp(now, deadline) >= 0) {
gpr_mu_unlock(GRPC_POLLSET_MU(&cc->pollset)); gpr_mu_unlock(cc->mu);
memset(&ret, 0, sizeof(ret)); memset(&ret, 0, sizeof(ret));
ret.type = GRPC_QUEUE_TIMEOUT; ret.type = GRPC_QUEUE_TIMEOUT;
break; break;
@ -330,11 +334,12 @@ grpc_event grpc_completion_queue_next(grpc_completion_queue *cc,
gpr_timespec iteration_deadline = deadline; gpr_timespec iteration_deadline = deadline;
if (grpc_timer_check(&exec_ctx, now, &iteration_deadline)) { if (grpc_timer_check(&exec_ctx, now, &iteration_deadline)) {
GPR_TIMER_MARK("alarm_triggered", 0); GPR_TIMER_MARK("alarm_triggered", 0);
gpr_mu_unlock(GRPC_POLLSET_MU(&cc->pollset)); gpr_mu_unlock(cc->mu);
grpc_exec_ctx_flush(&exec_ctx); grpc_exec_ctx_flush(&exec_ctx);
gpr_mu_lock(GRPC_POLLSET_MU(&cc->pollset)); gpr_mu_lock(cc->mu);
continue;
} else { } else {
grpc_pollset_work(&exec_ctx, &cc->pollset, &worker, now, grpc_pollset_work(&exec_ctx, POLLSET_FROM_CQ(cc), &worker, now,
iteration_deadline); iteration_deadline);
} }
} }
@ -348,7 +353,7 @@ grpc_event grpc_completion_queue_next(grpc_completion_queue *cc,
} }
static int add_plucker(grpc_completion_queue *cc, void *tag, static int add_plucker(grpc_completion_queue *cc, void *tag,
grpc_pollset_worker *worker) { grpc_pollset_worker **worker) {
if (cc->num_pluckers == GRPC_MAX_COMPLETION_QUEUE_PLUCKERS) { if (cc->num_pluckers == GRPC_MAX_COMPLETION_QUEUE_PLUCKERS) {
return 0; return 0;
} }
@ -359,7 +364,7 @@ static int add_plucker(grpc_completion_queue *cc, void *tag,
} }
static void del_plucker(grpc_completion_queue *cc, void *tag, static void del_plucker(grpc_completion_queue *cc, void *tag,
grpc_pollset_worker *worker) { grpc_pollset_worker **worker) {
int i; int i;
for (i = 0; i < cc->num_pluckers; i++) { for (i = 0; i < cc->num_pluckers; i++) {
if (cc->pluckers[i].tag == tag && cc->pluckers[i].worker == worker) { if (cc->pluckers[i].tag == tag && cc->pluckers[i].worker == worker) {
@ -376,7 +381,7 @@ grpc_event grpc_completion_queue_pluck(grpc_completion_queue *cc, void *tag,
grpc_event ret; grpc_event ret;
grpc_cq_completion *c; grpc_cq_completion *c;
grpc_cq_completion *prev; grpc_cq_completion *prev;
grpc_pollset_worker worker; grpc_pollset_worker *worker = NULL;
gpr_timespec now; gpr_timespec now;
int first_loop = 1; int first_loop = 1;
grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
@ -395,7 +400,7 @@ grpc_event grpc_completion_queue_pluck(grpc_completion_queue *cc, void *tag,
deadline = gpr_convert_clock_type(deadline, GPR_CLOCK_MONOTONIC); deadline = gpr_convert_clock_type(deadline, GPR_CLOCK_MONOTONIC);
GRPC_CQ_INTERNAL_REF(cc, "pluck"); GRPC_CQ_INTERNAL_REF(cc, "pluck");
gpr_mu_lock(GRPC_POLLSET_MU(&cc->pollset)); gpr_mu_lock(cc->mu);
for (;;) { for (;;) {
prev = &cc->completed_head; prev = &cc->completed_head;
while ((c = (grpc_cq_completion *)(prev->next & ~(uintptr_t)1)) != while ((c = (grpc_cq_completion *)(prev->next & ~(uintptr_t)1)) !=
@ -405,7 +410,7 @@ grpc_event grpc_completion_queue_pluck(grpc_completion_queue *cc, void *tag,
if (c == cc->completed_tail) { if (c == cc->completed_tail) {
cc->completed_tail = prev; cc->completed_tail = prev;
} }
gpr_mu_unlock(GRPC_POLLSET_MU(&cc->pollset)); gpr_mu_unlock(cc->mu);
ret.type = GRPC_OP_COMPLETE; ret.type = GRPC_OP_COMPLETE;
ret.success = c->next & 1u; ret.success = c->next & 1u;
ret.tag = c->tag; ret.tag = c->tag;
@ -415,7 +420,7 @@ grpc_event grpc_completion_queue_pluck(grpc_completion_queue *cc, void *tag,
prev = c; prev = c;
} }
if (cc->shutdown) { if (cc->shutdown) {
gpr_mu_unlock(GRPC_POLLSET_MU(&cc->pollset)); gpr_mu_unlock(cc->mu);
memset(&ret, 0, sizeof(ret)); memset(&ret, 0, sizeof(ret));
ret.type = GRPC_QUEUE_SHUTDOWN; ret.type = GRPC_QUEUE_SHUTDOWN;
break; break;
@ -425,7 +430,7 @@ grpc_event grpc_completion_queue_pluck(grpc_completion_queue *cc, void *tag,
"Too many outstanding grpc_completion_queue_pluck calls: maximum " "Too many outstanding grpc_completion_queue_pluck calls: maximum "
"is %d", "is %d",
GRPC_MAX_COMPLETION_QUEUE_PLUCKERS); GRPC_MAX_COMPLETION_QUEUE_PLUCKERS);
gpr_mu_unlock(GRPC_POLLSET_MU(&cc->pollset)); gpr_mu_unlock(cc->mu);
memset(&ret, 0, sizeof(ret)); memset(&ret, 0, sizeof(ret));
/* TODO(ctiller): should we use a different result here */ /* TODO(ctiller): should we use a different result here */
ret.type = GRPC_QUEUE_TIMEOUT; ret.type = GRPC_QUEUE_TIMEOUT;
@ -434,7 +439,7 @@ grpc_event grpc_completion_queue_pluck(grpc_completion_queue *cc, void *tag,
now = gpr_now(GPR_CLOCK_MONOTONIC); now = gpr_now(GPR_CLOCK_MONOTONIC);
if (!first_loop && gpr_time_cmp(now, deadline) >= 0) { if (!first_loop && gpr_time_cmp(now, deadline) >= 0) {
del_plucker(cc, tag, &worker); del_plucker(cc, tag, &worker);
gpr_mu_unlock(GRPC_POLLSET_MU(&cc->pollset)); gpr_mu_unlock(cc->mu);
memset(&ret, 0, sizeof(ret)); memset(&ret, 0, sizeof(ret));
ret.type = GRPC_QUEUE_TIMEOUT; ret.type = GRPC_QUEUE_TIMEOUT;
break; break;
@ -447,11 +452,11 @@ grpc_event grpc_completion_queue_pluck(grpc_completion_queue *cc, void *tag,
gpr_timespec iteration_deadline = deadline; gpr_timespec iteration_deadline = deadline;
if (grpc_timer_check(&exec_ctx, now, &iteration_deadline)) { if (grpc_timer_check(&exec_ctx, now, &iteration_deadline)) {
GPR_TIMER_MARK("alarm_triggered", 0); GPR_TIMER_MARK("alarm_triggered", 0);
gpr_mu_unlock(GRPC_POLLSET_MU(&cc->pollset)); gpr_mu_unlock(cc->mu);
grpc_exec_ctx_flush(&exec_ctx); grpc_exec_ctx_flush(&exec_ctx);
gpr_mu_lock(GRPC_POLLSET_MU(&cc->pollset)); gpr_mu_lock(cc->mu);
} else { } else {
grpc_pollset_work(&exec_ctx, &cc->pollset, &worker, now, grpc_pollset_work(&exec_ctx, POLLSET_FROM_CQ(cc), &worker, now,
iteration_deadline); iteration_deadline);
} }
del_plucker(cc, tag, &worker); del_plucker(cc, tag, &worker);
@ -472,9 +477,9 @@ void grpc_completion_queue_shutdown(grpc_completion_queue *cc) {
grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
GPR_TIMER_BEGIN("grpc_completion_queue_shutdown", 0); GPR_TIMER_BEGIN("grpc_completion_queue_shutdown", 0);
GRPC_API_TRACE("grpc_completion_queue_shutdown(cc=%p)", 1, (cc)); GRPC_API_TRACE("grpc_completion_queue_shutdown(cc=%p)", 1, (cc));
gpr_mu_lock(GRPC_POLLSET_MU(&cc->pollset)); gpr_mu_lock(cc->mu);
if (cc->shutdown_called) { if (cc->shutdown_called) {
gpr_mu_unlock(GRPC_POLLSET_MU(&cc->pollset)); gpr_mu_unlock(cc->mu);
GPR_TIMER_END("grpc_completion_queue_shutdown", 0); GPR_TIMER_END("grpc_completion_queue_shutdown", 0);
return; return;
} }
@ -482,9 +487,10 @@ void grpc_completion_queue_shutdown(grpc_completion_queue *cc) {
if (gpr_unref(&cc->pending_events)) { if (gpr_unref(&cc->pending_events)) {
GPR_ASSERT(!cc->shutdown); GPR_ASSERT(!cc->shutdown);
cc->shutdown = 1; cc->shutdown = 1;
grpc_pollset_shutdown(&exec_ctx, &cc->pollset, &cc->pollset_shutdown_done); grpc_pollset_shutdown(&exec_ctx, POLLSET_FROM_CQ(cc),
&cc->pollset_shutdown_done);
} }
gpr_mu_unlock(GRPC_POLLSET_MU(&cc->pollset)); gpr_mu_unlock(cc->mu);
grpc_exec_ctx_finish(&exec_ctx); grpc_exec_ctx_finish(&exec_ctx);
GPR_TIMER_END("grpc_completion_queue_shutdown", 0); GPR_TIMER_END("grpc_completion_queue_shutdown", 0);
} }
@ -498,7 +504,7 @@ void grpc_completion_queue_destroy(grpc_completion_queue *cc) {
} }
grpc_pollset *grpc_cq_pollset(grpc_completion_queue *cc) { grpc_pollset *grpc_cq_pollset(grpc_completion_queue *cc) {
return &cc->pollset; return POLLSET_FROM_CQ(cc);
} }
void grpc_cq_mark_server_cq(grpc_completion_queue *cc) { cc->is_server_cq = 1; } void grpc_cq_mark_server_cq(grpc_completion_queue *cc) { cc->is_server_cq = 1; }

@ -130,9 +130,9 @@ static void on_secure_handshake_done(grpc_exec_ctx *exec_ctx, void *arg,
static void on_initial_connect_string_sent(grpc_exec_ctx *exec_ctx, void *arg, static void on_initial_connect_string_sent(grpc_exec_ctx *exec_ctx, void *arg,
bool success) { bool success) {
connector *c = arg; connector *c = arg;
grpc_security_connector_do_handshake(exec_ctx, &c->security_connector->base, grpc_channel_security_connector_do_handshake(exec_ctx, c->security_connector,
c->connecting_endpoint, c->connecting_endpoint,
on_secure_handshake_done, c); on_secure_handshake_done, c);
} }
static void connected(grpc_exec_ctx *exec_ctx, void *arg, bool success) { static void connected(grpc_exec_ctx *exec_ctx, void *arg, bool success) {
@ -153,9 +153,8 @@ static void connected(grpc_exec_ctx *exec_ctx, void *arg, bool success) {
grpc_endpoint_write(exec_ctx, tcp, &c->initial_string_buffer, grpc_endpoint_write(exec_ctx, tcp, &c->initial_string_buffer,
&c->initial_string_sent); &c->initial_string_sent);
} else { } else {
grpc_security_connector_do_handshake(exec_ctx, grpc_channel_security_connector_do_handshake(
&c->security_connector->base, tcp, exec_ctx, c->security_connector, tcp, on_secure_handshake_done, c);
on_secure_handshake_done, c);
} }
} else { } else {
memset(c->result, 0, sizeof(*c->result)); memset(c->result, 0, sizeof(*c->result));

@ -417,7 +417,7 @@ typedef struct {
/** HTTP2 stream id for this stream, or zero if one has not been assigned */ /** HTTP2 stream id for this stream, or zero if one has not been assigned */
uint32_t id; uint32_t id;
uint8_t fetching; uint8_t fetching;
uint8_t sent_initial_metadata; bool sent_initial_metadata;
uint8_t sent_message; uint8_t sent_message;
uint8_t sent_trailing_metadata; uint8_t sent_trailing_metadata;
uint8_t read_closed; uint8_t read_closed;
@ -509,7 +509,7 @@ void grpc_chttp2_publish_reads(grpc_exec_ctx *exec_ctx,
grpc_chttp2_transport_global *global, grpc_chttp2_transport_global *global,
grpc_chttp2_transport_parsing *parsing); grpc_chttp2_transport_parsing *parsing);
void grpc_chttp2_list_add_writable_stream( bool grpc_chttp2_list_add_writable_stream(
grpc_chttp2_transport_global *transport_global, grpc_chttp2_transport_global *transport_global,
grpc_chttp2_stream_global *stream_global); grpc_chttp2_stream_global *stream_global);
/** Get a writable stream /** Get a writable stream
@ -519,14 +519,13 @@ int grpc_chttp2_list_pop_writable_stream(
grpc_chttp2_transport_writing *transport_writing, grpc_chttp2_transport_writing *transport_writing,
grpc_chttp2_stream_global **stream_global, grpc_chttp2_stream_global **stream_global,
grpc_chttp2_stream_writing **stream_writing); grpc_chttp2_stream_writing **stream_writing);
void grpc_chttp2_list_remove_writable_stream( bool grpc_chttp2_list_remove_writable_stream(
grpc_chttp2_transport_global *transport_global, grpc_chttp2_transport_global *transport_global,
grpc_chttp2_stream_global *stream_global); grpc_chttp2_stream_global *stream_global) GRPC_MUST_USE_RESULT;
/* returns 1 if stream added, 0 if it was already present */ void grpc_chttp2_list_add_writing_stream(
int grpc_chttp2_list_add_writing_stream(
grpc_chttp2_transport_writing *transport_writing, grpc_chttp2_transport_writing *transport_writing,
grpc_chttp2_stream_writing *stream_writing) GRPC_MUST_USE_RESULT; grpc_chttp2_stream_writing *stream_writing);
int grpc_chttp2_list_have_writing_streams( int grpc_chttp2_list_have_writing_streams(
grpc_chttp2_transport_writing *transport_writing); grpc_chttp2_transport_writing *transport_writing);
int grpc_chttp2_list_pop_writing_stream( int grpc_chttp2_list_pop_writing_stream(
@ -770,4 +769,9 @@ void grpc_chttp2_ack_ping(grpc_exec_ctx *exec_ctx,
grpc_chttp2_transport_parsing *parsing, grpc_chttp2_transport_parsing *parsing,
const uint8_t *opaque_8bytes); const uint8_t *opaque_8bytes);
/** add a ref to the stream and add it to the writable list;
ref will be dropped in writing.c */
void grpc_chttp2_become_writable(grpc_chttp2_transport_global *transport_global,
grpc_chttp2_stream_global *stream_global);
#endif #endif

@ -1,6 +1,6 @@
/* /*
* *
* Copyright 2015, Google Inc. * Copyright 2015-2016, Google Inc.
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
@ -149,7 +149,7 @@ void grpc_chttp2_publish_reads(
if (was_zero && !is_zero) { if (was_zero && !is_zero) {
while (grpc_chttp2_list_pop_stalled_by_transport(transport_global, while (grpc_chttp2_list_pop_stalled_by_transport(transport_global,
&stream_global)) { &stream_global)) {
grpc_chttp2_list_add_writable_stream(transport_global, stream_global); grpc_chttp2_become_writable(transport_global, stream_global);
} }
} }
@ -178,7 +178,7 @@ void grpc_chttp2_publish_reads(
outgoing_window); outgoing_window);
is_zero = stream_global->outgoing_window <= 0; is_zero = stream_global->outgoing_window <= 0;
if (was_zero && !is_zero) { if (was_zero && !is_zero) {
grpc_chttp2_list_add_writable_stream(transport_global, stream_global); grpc_chttp2_become_writable(transport_global, stream_global);
} }
stream_global->max_recv_bytes -= (uint32_t)GPR_MIN( stream_global->max_recv_bytes -= (uint32_t)GPR_MIN(

@ -100,11 +100,14 @@ static void stream_list_remove(grpc_chttp2_transport *t, grpc_chttp2_stream *s,
} }
} }
static void stream_list_maybe_remove(grpc_chttp2_transport *t, static bool stream_list_maybe_remove(grpc_chttp2_transport *t,
grpc_chttp2_stream *s, grpc_chttp2_stream *s,
grpc_chttp2_stream_list_id id) { grpc_chttp2_stream_list_id id) {
if (s->included[id]) { if (s->included[id]) {
stream_list_remove(t, s, id); stream_list_remove(t, s, id);
return true;
} else {
return false;
} }
} }
@ -125,23 +128,24 @@ static void stream_list_add_tail(grpc_chttp2_transport *t,
s->included[id] = 1; s->included[id] = 1;
} }
static int stream_list_add(grpc_chttp2_transport *t, grpc_chttp2_stream *s, static bool stream_list_add(grpc_chttp2_transport *t, grpc_chttp2_stream *s,
grpc_chttp2_stream_list_id id) { grpc_chttp2_stream_list_id id) {
if (s->included[id]) { if (s->included[id]) {
return 0; return false;
} }
stream_list_add_tail(t, s, id); stream_list_add_tail(t, s, id);
return 1; return true;
} }
/* wrappers for specializations */ /* wrappers for specializations */
void grpc_chttp2_list_add_writable_stream( bool grpc_chttp2_list_add_writable_stream(
grpc_chttp2_transport_global *transport_global, grpc_chttp2_transport_global *transport_global,
grpc_chttp2_stream_global *stream_global) { grpc_chttp2_stream_global *stream_global) {
GPR_ASSERT(stream_global->id != 0); GPR_ASSERT(stream_global->id != 0);
stream_list_add(TRANSPORT_FROM_GLOBAL(transport_global), return stream_list_add(TRANSPORT_FROM_GLOBAL(transport_global),
STREAM_FROM_GLOBAL(stream_global), GRPC_CHTTP2_LIST_WRITABLE); STREAM_FROM_GLOBAL(stream_global),
GRPC_CHTTP2_LIST_WRITABLE);
} }
int grpc_chttp2_list_pop_writable_stream( int grpc_chttp2_list_pop_writable_stream(
@ -159,20 +163,20 @@ int grpc_chttp2_list_pop_writable_stream(
return r; return r;
} }
void grpc_chttp2_list_remove_writable_stream( bool grpc_chttp2_list_remove_writable_stream(
grpc_chttp2_transport_global *transport_global, grpc_chttp2_transport_global *transport_global,
grpc_chttp2_stream_global *stream_global) { grpc_chttp2_stream_global *stream_global) {
stream_list_maybe_remove(TRANSPORT_FROM_GLOBAL(transport_global), return stream_list_maybe_remove(TRANSPORT_FROM_GLOBAL(transport_global),
STREAM_FROM_GLOBAL(stream_global), STREAM_FROM_GLOBAL(stream_global),
GRPC_CHTTP2_LIST_WRITABLE); GRPC_CHTTP2_LIST_WRITABLE);
} }
int grpc_chttp2_list_add_writing_stream( void grpc_chttp2_list_add_writing_stream(
grpc_chttp2_transport_writing *transport_writing, grpc_chttp2_transport_writing *transport_writing,
grpc_chttp2_stream_writing *stream_writing) { grpc_chttp2_stream_writing *stream_writing) {
return stream_list_add(TRANSPORT_FROM_WRITING(transport_writing), GPR_ASSERT(stream_list_add(TRANSPORT_FROM_WRITING(transport_writing),
STREAM_FROM_WRITING(stream_writing), STREAM_FROM_WRITING(stream_writing),
GRPC_CHTTP2_LIST_WRITING); GRPC_CHTTP2_LIST_WRITING));
} }
int grpc_chttp2_list_have_writing_streams( int grpc_chttp2_list_have_writing_streams(
@ -332,7 +336,7 @@ void grpc_chttp2_list_flush_writing_stalled_by_transport(
while (stream_list_pop(transport, &stream, while (stream_list_pop(transport, &stream,
GRPC_CHTTP2_LIST_WRITING_STALLED_BY_TRANSPORT)) { GRPC_CHTTP2_LIST_WRITING_STALLED_BY_TRANSPORT)) {
if (is_window_available) { if (is_window_available) {
grpc_chttp2_list_add_writable_stream(&transport->global, &stream->global); grpc_chttp2_become_writable(&transport->global, &stream->global);
} else { } else {
grpc_chttp2_list_add_stalled_by_transport(transport_writing, grpc_chttp2_list_add_stalled_by_transport(transport_writing,
&stream->writing); &stream->writing);

@ -83,7 +83,8 @@ int grpc_chttp2_unlocking_check_writes(
(according to available window sizes) and add to the output buffer */ (according to available window sizes) and add to the output buffer */
while (grpc_chttp2_list_pop_writable_stream( while (grpc_chttp2_list_pop_writable_stream(
transport_global, transport_writing, &stream_global, &stream_writing)) { transport_global, transport_writing, &stream_global, &stream_writing)) {
uint8_t sent_initial_metadata; bool sent_initial_metadata = stream_writing->sent_initial_metadata;
bool become_writable = false;
stream_writing->id = stream_global->id; stream_writing->id = stream_global->id;
stream_writing->read_closed = stream_global->read_closed; stream_writing->read_closed = stream_global->read_closed;
@ -92,16 +93,12 @@ int grpc_chttp2_unlocking_check_writes(
outgoing_window, stream_global, outgoing_window, stream_global,
outgoing_window); outgoing_window);
sent_initial_metadata = stream_writing->sent_initial_metadata;
if (!sent_initial_metadata && stream_global->send_initial_metadata) { if (!sent_initial_metadata && stream_global->send_initial_metadata) {
stream_writing->send_initial_metadata = stream_writing->send_initial_metadata =
stream_global->send_initial_metadata; stream_global->send_initial_metadata;
stream_global->send_initial_metadata = NULL; stream_global->send_initial_metadata = NULL;
if (grpc_chttp2_list_add_writing_stream(transport_writing, become_writable = true;
stream_writing)) { sent_initial_metadata = true;
GRPC_CHTTP2_STREAM_REF(stream_global, "chttp2_writing");
}
sent_initial_metadata = 1;
} }
if (sent_initial_metadata) { if (sent_initial_metadata) {
if (stream_global->send_message != NULL) { if (stream_global->send_message != NULL) {
@ -128,10 +125,7 @@ int grpc_chttp2_unlocking_check_writes(
stream_writing->flow_controlled_buffer.length > 0) && stream_writing->flow_controlled_buffer.length > 0) &&
stream_writing->outgoing_window > 0) { stream_writing->outgoing_window > 0) {
if (transport_writing->outgoing_window > 0) { if (transport_writing->outgoing_window > 0) {
if (grpc_chttp2_list_add_writing_stream(transport_writing, become_writable = true;
stream_writing)) {
GRPC_CHTTP2_STREAM_REF(stream_global, "chttp2_writing");
}
} else { } else {
grpc_chttp2_list_add_stalled_by_transport(transport_writing, grpc_chttp2_list_add_stalled_by_transport(transport_writing,
stream_writing); stream_writing);
@ -141,10 +135,7 @@ int grpc_chttp2_unlocking_check_writes(
stream_writing->send_trailing_metadata = stream_writing->send_trailing_metadata =
stream_global->send_trailing_metadata; stream_global->send_trailing_metadata;
stream_global->send_trailing_metadata = NULL; stream_global->send_trailing_metadata = NULL;
if (grpc_chttp2_list_add_writing_stream(transport_writing, become_writable = true;
stream_writing)) {
GRPC_CHTTP2_STREAM_REF(stream_global, "chttp2_writing");
}
} }
} }
@ -153,10 +144,13 @@ int grpc_chttp2_unlocking_check_writes(
GRPC_CHTTP2_FLOW_MOVE_STREAM("write", transport_global, stream_writing, GRPC_CHTTP2_FLOW_MOVE_STREAM("write", transport_global, stream_writing,
announce_window, stream_global, announce_window, stream_global,
unannounced_incoming_window_for_writing); unannounced_incoming_window_for_writing);
if (grpc_chttp2_list_add_writing_stream(transport_writing, become_writable = true;
stream_writing)) { }
GRPC_CHTTP2_STREAM_REF(stream_global, "chttp2_writing");
} if (become_writable) {
grpc_chttp2_list_add_writing_stream(transport_writing, stream_writing);
} else {
GRPC_CHTTP2_STREAM_UNREF(exec_ctx, stream_global, "chttp2_writing");
} }
} }
@ -310,10 +304,7 @@ static void finalize_outbuf(grpc_exec_ctx *exec_ctx,
(stream_writing->send_message && !stream_writing->fetching)) && (stream_writing->send_message && !stream_writing->fetching)) &&
stream_writing->outgoing_window > 0) { stream_writing->outgoing_window > 0) {
if (transport_writing->outgoing_window > 0) { if (transport_writing->outgoing_window > 0) {
if (grpc_chttp2_list_add_writing_stream(transport_writing, grpc_chttp2_list_add_writing_stream(transport_writing, stream_writing);
stream_writing)) {
/* do nothing - already reffed */
}
} else { } else {
grpc_chttp2_list_add_writing_stalled_by_transport(transport_writing, grpc_chttp2_list_add_writing_stalled_by_transport(transport_writing,
stream_writing); stream_writing);

@ -142,7 +142,7 @@ static void incoming_byte_stream_update_flow_control(
static void fail_pending_writes(grpc_exec_ctx *exec_ctx, static void fail_pending_writes(grpc_exec_ctx *exec_ctx,
grpc_chttp2_stream_global *stream_global); grpc_chttp2_stream_global *stream_global);
/* /*******************************************************************************
* CONSTRUCTION/DESTRUCTION/REFCOUNTING * CONSTRUCTION/DESTRUCTION/REFCOUNTING
*/ */
@ -521,7 +521,6 @@ static void destroy_stream(grpc_exec_ctx *exec_ctx, grpc_transport *gt,
s->global.id) == NULL); s->global.id) == NULL);
} }
grpc_chttp2_list_remove_writable_stream(&t->global, &s->global);
grpc_chttp2_list_remove_unannounced_incoming_window_available(&t->global, grpc_chttp2_list_remove_unannounced_incoming_window_available(&t->global,
&s->global); &s->global);
grpc_chttp2_list_remove_stalled_by_transport(&t->global, &s->global); grpc_chttp2_list_remove_stalled_by_transport(&t->global, &s->global);
@ -583,7 +582,7 @@ grpc_chttp2_stream_parsing *grpc_chttp2_parsing_accept_stream(
return &accepting->parsing; return &accepting->parsing;
} }
/* /*******************************************************************************
* LOCK MANAGEMENT * LOCK MANAGEMENT
*/ */
@ -611,10 +610,18 @@ static void unlock(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t) {
GPR_TIMER_END("unlock", 0); GPR_TIMER_END("unlock", 0);
} }
/* /*******************************************************************************
* OUTPUT PROCESSING * OUTPUT PROCESSING
*/ */
void grpc_chttp2_become_writable(grpc_chttp2_transport_global *transport_global,
grpc_chttp2_stream_global *stream_global) {
if (!TRANSPORT_FROM_GLOBAL(transport_global)->closed &&
grpc_chttp2_list_add_writable_stream(transport_global, stream_global)) {
GRPC_CHTTP2_STREAM_REF(stream_global, "chttp2_writing");
}
}
static void push_setting(grpc_chttp2_transport *t, grpc_chttp2_setting_id id, static void push_setting(grpc_chttp2_transport *t, grpc_chttp2_setting_id id,
uint32_t value) { uint32_t value) {
const grpc_chttp2_setting_parameters *sp = const grpc_chttp2_setting_parameters *sp =
@ -732,7 +739,7 @@ static void maybe_start_some_streams(
stream_global->id, STREAM_FROM_GLOBAL(stream_global)); stream_global->id, STREAM_FROM_GLOBAL(stream_global));
stream_global->in_stream_map = 1; stream_global->in_stream_map = 1;
transport_global->concurrent_stream_count++; transport_global->concurrent_stream_count++;
grpc_chttp2_list_add_writable_stream(transport_global, stream_global); grpc_chttp2_become_writable(transport_global, stream_global);
} }
/* cancel out streams that will never be started */ /* cancel out streams that will never be started */
while (transport_global->next_stream_id >= MAX_CLIENT_STREAM_ID && while (transport_global->next_stream_id >= MAX_CLIENT_STREAM_ID &&
@ -821,7 +828,7 @@ static void perform_stream_op_locked(
maybe_start_some_streams(exec_ctx, transport_global); maybe_start_some_streams(exec_ctx, transport_global);
} else { } else {
GPR_ASSERT(stream_global->id != 0); GPR_ASSERT(stream_global->id != 0);
grpc_chttp2_list_add_writable_stream(transport_global, stream_global); grpc_chttp2_become_writable(transport_global, stream_global);
} }
} else { } else {
grpc_chttp2_complete_closure_step( grpc_chttp2_complete_closure_step(
@ -838,7 +845,7 @@ static void perform_stream_op_locked(
exec_ctx, &stream_global->send_message_finished, 0); exec_ctx, &stream_global->send_message_finished, 0);
} else if (stream_global->id != 0) { } else if (stream_global->id != 0) {
stream_global->send_message = op->send_message; stream_global->send_message = op->send_message;
grpc_chttp2_list_add_writable_stream(transport_global, stream_global); grpc_chttp2_become_writable(transport_global, stream_global);
} }
} }
@ -858,7 +865,7 @@ static void perform_stream_op_locked(
} else if (stream_global->id != 0) { } else if (stream_global->id != 0) {
/* TODO(ctiller): check if there's flow control for any outstanding /* TODO(ctiller): check if there's flow control for any outstanding
bytes before going writable */ bytes before going writable */
grpc_chttp2_list_add_writable_stream(transport_global, stream_global); grpc_chttp2_become_writable(transport_global, stream_global);
} }
} }
@ -999,7 +1006,7 @@ static void perform_transport_op(grpc_exec_ctx *exec_ctx, grpc_transport *gt,
} }
} }
/* /*******************************************************************************
* INPUT PROCESSING * INPUT PROCESSING
*/ */
@ -1064,7 +1071,6 @@ static void remove_stream(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t,
if (!s) { if (!s) {
s = grpc_chttp2_stream_map_delete(&t->new_stream_map, id); s = grpc_chttp2_stream_map_delete(&t->new_stream_map, id);
} }
grpc_chttp2_list_remove_writable_stream(&t->global, &s->global);
GPR_ASSERT(s); GPR_ASSERT(s);
s->global.in_stream_map = 0; s->global.in_stream_map = 0;
if (t->parsing.incoming_stream == &s->parsing) { if (t->parsing.incoming_stream == &s->parsing) {
@ -1080,6 +1086,9 @@ static void remove_stream(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t,
if (grpc_chttp2_unregister_stream(t, s) && t->global.sent_goaway) { if (grpc_chttp2_unregister_stream(t, s) && t->global.sent_goaway) {
close_transport_locked(exec_ctx, t); close_transport_locked(exec_ctx, t);
} }
if (grpc_chttp2_list_remove_writable_stream(&t->global, &s->global)) {
GRPC_CHTTP2_STREAM_UNREF(exec_ctx, &s->global, "chttp2_writing");
}
new_stream_count = grpc_chttp2_stream_map_size(&t->parsing_stream_map) + new_stream_count = grpc_chttp2_stream_map_size(&t->parsing_stream_map) +
grpc_chttp2_stream_map_size(&t->new_stream_map); grpc_chttp2_stream_map_size(&t->new_stream_map);
@ -1331,7 +1340,7 @@ static void update_global_window(void *args, uint32_t id, void *stream) {
is_zero = stream_global->outgoing_window <= 0; is_zero = stream_global->outgoing_window <= 0;
if (was_zero && !is_zero) { if (was_zero && !is_zero) {
grpc_chttp2_list_add_writable_stream(transport_global, stream_global); grpc_chttp2_become_writable(transport_global, stream_global);
} }
} }
@ -1426,7 +1435,7 @@ static void recv_data(grpc_exec_ctx *exec_ctx, void *tp, bool success) {
GPR_TIMER_END("recv_data", 0); GPR_TIMER_END("recv_data", 0);
} }
/* /*******************************************************************************
* CALLBACK LOOP * CALLBACK LOOP
*/ */
@ -1440,7 +1449,7 @@ static void connectivity_state_set(
state, reason); state, reason);
} }
/* /*******************************************************************************
* POLLSET STUFF * POLLSET STUFF
*/ */
@ -1468,7 +1477,7 @@ static void set_pollset(grpc_exec_ctx *exec_ctx, grpc_transport *gt,
unlock(exec_ctx, t); unlock(exec_ctx, t);
} }
/* /*******************************************************************************
* BYTE STREAM * BYTE STREAM
*/ */
@ -1508,7 +1517,7 @@ static void incoming_byte_stream_update_flow_control(
add_max_recv_bytes); add_max_recv_bytes);
grpc_chttp2_list_add_unannounced_incoming_window_available(transport_global, grpc_chttp2_list_add_unannounced_incoming_window_available(transport_global,
stream_global); stream_global);
grpc_chttp2_list_add_writable_stream(transport_global, stream_global); grpc_chttp2_become_writable(transport_global, stream_global);
} }
} }
@ -1623,7 +1632,7 @@ grpc_chttp2_incoming_byte_stream *grpc_chttp2_incoming_byte_stream_create(
return incoming_byte_stream; return incoming_byte_stream;
} }
/* /*******************************************************************************
* TRACING * TRACING
*/ */
@ -1709,7 +1718,7 @@ void grpc_chttp2_flowctl_trace(const char *file, int line, const char *phase,
gpr_free(prefix); gpr_free(prefix);
} }
/* /*******************************************************************************
* INTEGRATION GLUE * INTEGRATION GLUE
*/ */

@ -43,11 +43,13 @@
#include <grpc/support/log.h> #include <grpc/support/log.h>
#include <grpc/support/string_util.h> #include <grpc/support/string_util.h>
#include <grpc/support/time.h> #include <grpc/support/time.h>
#include "src/core/profiling/timers.h" #include "src/core/profiling/timers.h"
#include "src/core/support/murmur_hash.h" #include "src/core/support/murmur_hash.h"
#include "src/core/support/string.h" #include "src/core/support/string.h"
#include "src/core/transport/chttp2/bin_encoder.h" #include "src/core/transport/chttp2/bin_encoder.h"
#include "src/core/transport/static_metadata.h" #include "src/core/transport/static_metadata.h"
#include "src/core/iomgr/iomgr_internal.h"
/* There are two kinds of mdelem and mdstr instances. /* There are two kinds of mdelem and mdstr instances.
* Static instances are declared in static_metadata.{h,c} and * Static instances are declared in static_metadata.{h,c} and
@ -227,6 +229,9 @@ void grpc_mdctx_global_shutdown(void) {
if (shard->count != 0) { if (shard->count != 0) {
gpr_log(GPR_DEBUG, "WARNING: %d metadata elements were leaked", gpr_log(GPR_DEBUG, "WARNING: %d metadata elements were leaked",
shard->count); shard->count);
if (grpc_iomgr_abort_on_leaks()) {
abort();
}
} }
gpr_free(shard->elems); gpr_free(shard->elems);
} }
@ -237,6 +242,9 @@ void grpc_mdctx_global_shutdown(void) {
if (shard->count != 0) { if (shard->count != 0) {
gpr_log(GPR_DEBUG, "WARNING: %d metadata strings were leaked", gpr_log(GPR_DEBUG, "WARNING: %d metadata strings were leaked",
shard->count); shard->count);
if (grpc_iomgr_abort_on_leaks()) {
abort();
}
} }
gpr_free(shard->strs); gpr_free(shard->strs);
} }

@ -45,7 +45,7 @@ void grpc_stream_ref(grpc_stream_refcount *refcount, const char *reason) {
#else #else
void grpc_stream_ref(grpc_stream_refcount *refcount) { void grpc_stream_ref(grpc_stream_refcount *refcount) {
#endif #endif
gpr_ref(&refcount->refs); gpr_ref_non_zero(&refcount->refs);
} }
#ifdef GRPC_STREAM_REFCOUNT_DEBUG #ifdef GRPC_STREAM_REFCOUNT_DEBUG

@ -1,51 +0,0 @@
/*
* Copyright 2015-2016, Google Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#include <grpc++/alarm.h>
#include <grpc++/completion_queue.h>
#include <grpc++/impl/grpc_library.h>
#include <grpc/grpc.h>
namespace grpc {
static internal::GrpcLibraryInitializer g_gli_initializer;
Alarm::Alarm(CompletionQueue* cq, gpr_timespec deadline, void* tag)
: tag_(tag),
alarm_(grpc_alarm_create(cq->cq(), deadline, static_cast<void*>(&tag_))) {
g_gli_initializer.summon();
}
Alarm::~Alarm() { grpc_alarm_destroy(alarm_); }
void Alarm::Cancel() { grpc_alarm_cancel(alarm_); }
} // namespace grpc

@ -193,16 +193,6 @@ namespace Grpc.Core.Internal
lock (myLock) lock (myLock)
{ {
finished = true; finished = true;
if (cancelled)
{
// Once we cancel, we don't have to care that much
// about reads and writes.
// TODO(jtattermusch): is this still necessary?
Cancel();
}
ReleaseResourcesIfPossible(); ReleaseResourcesIfPossible();
} }
// TODO(jtattermusch): handle error // TODO(jtattermusch): handle error

@ -36,7 +36,7 @@ using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using Grpc.Core; using Grpc.Core;
using Grpc.Health.V1Alpha; using Grpc.Health.V1;
using NUnit.Framework; using NUnit.Framework;
namespace Grpc.HealthCheck.Tests namespace Grpc.HealthCheck.Tests
@ -49,7 +49,7 @@ namespace Grpc.HealthCheck.Tests
const string Host = "localhost"; const string Host = "localhost";
Server server; Server server;
Channel channel; Channel channel;
Grpc.Health.V1Alpha.Health.IHealthClient client; Grpc.Health.V1.Health.IHealthClient client;
Grpc.HealthCheck.HealthServiceImpl serviceImpl; Grpc.HealthCheck.HealthServiceImpl serviceImpl;
[TestFixtureSetUp] [TestFixtureSetUp]
@ -59,13 +59,13 @@ namespace Grpc.HealthCheck.Tests
server = new Server server = new Server
{ {
Services = { Grpc.Health.V1Alpha.Health.BindService(serviceImpl) }, Services = { Grpc.Health.V1.Health.BindService(serviceImpl) },
Ports = { { Host, ServerPort.PickUnused, ServerCredentials.Insecure } } Ports = { { Host, ServerPort.PickUnused, ServerCredentials.Insecure } }
}; };
server.Start(); server.Start();
channel = new Channel(Host, server.Ports.Single().BoundPort, ChannelCredentials.Insecure); channel = new Channel(Host, server.Ports.Single().BoundPort, ChannelCredentials.Insecure);
client = Grpc.Health.V1Alpha.Health.NewClient(channel); client = Grpc.Health.V1.Health.NewClient(channel);
} }
[TestFixtureTearDown] [TestFixtureTearDown]
@ -79,16 +79,16 @@ namespace Grpc.HealthCheck.Tests
[Test] [Test]
public void ServiceIsRunning() public void ServiceIsRunning()
{ {
serviceImpl.SetStatus("", "", HealthCheckResponse.Types.ServingStatus.SERVING); serviceImpl.SetStatus("", HealthCheckResponse.Types.ServingStatus.SERVING);
var response = client.Check(new HealthCheckRequest { Host = "", Service = "" }); var response = client.Check(new HealthCheckRequest { Service = "" });
Assert.AreEqual(HealthCheckResponse.Types.ServingStatus.SERVING, response.Status); Assert.AreEqual(HealthCheckResponse.Types.ServingStatus.SERVING, response.Status);
} }
[Test] [Test]
public void ServiceDoesntExist() public void ServiceDoesntExist()
{ {
Assert.Throws(Is.TypeOf(typeof(RpcException)).And.Property("Status").Property("StatusCode").EqualTo(StatusCode.NotFound), () => client.Check(new HealthCheckRequest { Host = "", Service = "nonexistent.service" })); Assert.Throws(Is.TypeOf(typeof(RpcException)).And.Property("Status").Property("StatusCode").EqualTo(StatusCode.NotFound), () => client.Check(new HealthCheckRequest { Service = "nonexistent.service" }));
} }
// TODO(jtattermusch): add test with timeout once timeouts are supported // TODO(jtattermusch): add test with timeout once timeouts are supported

@ -1,5 +1,5 @@
#region Copyright notice and license #region Copyright notice and license
// Copyright 2015, Google Inc. // Copyright 2015-2016, Google Inc.
// All rights reserved. // All rights reserved.
// //
// Redistribution and use in source and binary forms, with or without // Redistribution and use in source and binary forms, with or without
@ -36,7 +36,7 @@ using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using Grpc.Core; using Grpc.Core;
using Grpc.Health.V1Alpha; using Grpc.Health.V1;
using NUnit.Framework; using NUnit.Framework;
namespace Grpc.HealthCheck.Tests namespace Grpc.HealthCheck.Tests
@ -50,58 +50,56 @@ namespace Grpc.HealthCheck.Tests
public void SetStatus() public void SetStatus()
{ {
var impl = new HealthServiceImpl(); var impl = new HealthServiceImpl();
impl.SetStatus("", "", HealthCheckResponse.Types.ServingStatus.SERVING); impl.SetStatus("", HealthCheckResponse.Types.ServingStatus.SERVING);
Assert.AreEqual(HealthCheckResponse.Types.ServingStatus.SERVING, GetStatusHelper(impl, "", "")); Assert.AreEqual(HealthCheckResponse.Types.ServingStatus.SERVING, GetStatusHelper(impl, ""));
impl.SetStatus("", "", HealthCheckResponse.Types.ServingStatus.NOT_SERVING); impl.SetStatus("", HealthCheckResponse.Types.ServingStatus.NOT_SERVING);
Assert.AreEqual(HealthCheckResponse.Types.ServingStatus.NOT_SERVING, GetStatusHelper(impl, "", "")); Assert.AreEqual(HealthCheckResponse.Types.ServingStatus.NOT_SERVING, GetStatusHelper(impl, ""));
impl.SetStatus("virtual-host", "", HealthCheckResponse.Types.ServingStatus.UNKNOWN); impl.SetStatus("", HealthCheckResponse.Types.ServingStatus.UNKNOWN);
Assert.AreEqual(HealthCheckResponse.Types.ServingStatus.UNKNOWN, GetStatusHelper(impl, "virtual-host", "")); Assert.AreEqual(HealthCheckResponse.Types.ServingStatus.UNKNOWN, GetStatusHelper(impl, ""));
impl.SetStatus("virtual-host", "grpc.test.TestService", HealthCheckResponse.Types.ServingStatus.SERVING); impl.SetStatus("grpc.test.TestService", HealthCheckResponse.Types.ServingStatus.SERVING);
Assert.AreEqual(HealthCheckResponse.Types.ServingStatus.SERVING, GetStatusHelper(impl, "virtual-host", "grpc.test.TestService")); Assert.AreEqual(HealthCheckResponse.Types.ServingStatus.SERVING, GetStatusHelper(impl, "grpc.test.TestService"));
} }
[Test] [Test]
public void ClearStatus() public void ClearStatus()
{ {
var impl = new HealthServiceImpl(); var impl = new HealthServiceImpl();
impl.SetStatus("", "", HealthCheckResponse.Types.ServingStatus.SERVING); impl.SetStatus("", HealthCheckResponse.Types.ServingStatus.SERVING);
impl.SetStatus("virtual-host", "", HealthCheckResponse.Types.ServingStatus.UNKNOWN); impl.SetStatus("grpc.test.TestService", HealthCheckResponse.Types.ServingStatus.UNKNOWN);
impl.ClearStatus("", ""); impl.ClearStatus("");
Assert.Throws(Is.TypeOf(typeof(RpcException)).And.Property("Status").Property("StatusCode").EqualTo(StatusCode.NotFound), () => GetStatusHelper(impl, "", "")); Assert.Throws(Is.TypeOf(typeof(RpcException)).And.Property("Status").Property("StatusCode").EqualTo(StatusCode.NotFound), () => GetStatusHelper(impl, ""));
Assert.AreEqual(HealthCheckResponse.Types.ServingStatus.UNKNOWN, GetStatusHelper(impl, "virtual-host", "")); Assert.AreEqual(HealthCheckResponse.Types.ServingStatus.UNKNOWN, GetStatusHelper(impl, "grpc.test.TestService"));
} }
[Test] [Test]
public void ClearAll() public void ClearAll()
{ {
var impl = new HealthServiceImpl(); var impl = new HealthServiceImpl();
impl.SetStatus("", "", HealthCheckResponse.Types.ServingStatus.SERVING); impl.SetStatus("", HealthCheckResponse.Types.ServingStatus.SERVING);
impl.SetStatus("virtual-host", "", HealthCheckResponse.Types.ServingStatus.UNKNOWN); impl.SetStatus("grpc.test.TestService", HealthCheckResponse.Types.ServingStatus.UNKNOWN);
impl.ClearAll(); impl.ClearAll();
Assert.Throws(typeof(RpcException), () => GetStatusHelper(impl, "", "")); Assert.Throws(typeof(RpcException), () => GetStatusHelper(impl, ""));
Assert.Throws(typeof(RpcException), () => GetStatusHelper(impl, "virtual-host", "")); Assert.Throws(typeof(RpcException), () => GetStatusHelper(impl, "grpc.test.TestService"));
} }
[Test] [Test]
public void NullsRejected() public void NullsRejected()
{ {
var impl = new HealthServiceImpl(); var impl = new HealthServiceImpl();
Assert.Throws(typeof(ArgumentNullException), () => impl.SetStatus(null, "", HealthCheckResponse.Types.ServingStatus.SERVING)); Assert.Throws(typeof(ArgumentNullException), () => impl.SetStatus(null, HealthCheckResponse.Types.ServingStatus.SERVING));
Assert.Throws(typeof(ArgumentNullException), () => impl.SetStatus("", null, HealthCheckResponse.Types.ServingStatus.SERVING));
Assert.Throws(typeof(ArgumentNullException), () => impl.ClearStatus(null, "")); Assert.Throws(typeof(ArgumentNullException), () => impl.ClearStatus(null));
Assert.Throws(typeof(ArgumentNullException), () => impl.ClearStatus("", null));
} }
private static HealthCheckResponse.Types.ServingStatus GetStatusHelper(HealthServiceImpl impl, string host, string service) private static HealthCheckResponse.Types.ServingStatus GetStatusHelper(HealthServiceImpl impl, string service)
{ {
return impl.Check(new HealthCheckRequest { Host = host, Service = service }, null).Result.Status; return impl.Check(new HealthCheckRequest { Service = service }, null).Result.Status;
} }
} }
} }

@ -4,7 +4,7 @@
<id>Grpc.HealthCheck</id> <id>Grpc.HealthCheck</id>
<title>gRPC C# Healthchecking</title> <title>gRPC C# Healthchecking</title>
<summary>Implementation of gRPC health service</summary> <summary>Implementation of gRPC health service</summary>
<description>Example implementation of grpc.health.v1alpha service that can be used for health-checking.</description> <description>Example implementation of grpc.health.v1 service that can be used for health-checking.</description>
<version>$version$</version> <version>$version$</version>
<authors>Google Inc.</authors> <authors>Google Inc.</authors>
<owners>grpc-packages</owners> <owners>grpc-packages</owners>

@ -7,7 +7,7 @@ using pb = global::Google.Protobuf;
using pbc = global::Google.Protobuf.Collections; using pbc = global::Google.Protobuf.Collections;
using pbr = global::Google.Protobuf.Reflection; using pbr = global::Google.Protobuf.Reflection;
using scg = global::System.Collections.Generic; using scg = global::System.Collections.Generic;
namespace Grpc.Health.V1Alpha { namespace Grpc.Health.V1 {
/// <summary>Holder for reflection information generated from health.proto</summary> /// <summary>Holder for reflection information generated from health.proto</summary>
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()] [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
@ -23,20 +23,19 @@ namespace Grpc.Health.V1Alpha {
static HealthReflection() { static HealthReflection() {
byte[] descriptorData = global::System.Convert.FromBase64String( byte[] descriptorData = global::System.Convert.FromBase64String(
string.Concat( string.Concat(
"CgxoZWFsdGgucHJvdG8SE2dycGMuaGVhbHRoLnYxYWxwaGEiMwoSSGVhbHRo", "CgxoZWFsdGgucHJvdG8SDmdycGMuaGVhbHRoLnYxIiUKEkhlYWx0aENoZWNr",
"Q2hlY2tSZXF1ZXN0EgwKBGhvc3QYASABKAkSDwoHc2VydmljZRgCIAEoCSKZ", "UmVxdWVzdBIPCgdzZXJ2aWNlGAEgASgJIpQBChNIZWFsdGhDaGVja1Jlc3Bv",
"AQoTSGVhbHRoQ2hlY2tSZXNwb25zZRJGCgZzdGF0dXMYASABKA4yNi5ncnBj", "bnNlEkEKBnN0YXR1cxgBIAEoDjIxLmdycGMuaGVhbHRoLnYxLkhlYWx0aENo",
"LmhlYWx0aC52MWFscGhhLkhlYWx0aENoZWNrUmVzcG9uc2UuU2VydmluZ1N0", "ZWNrUmVzcG9uc2UuU2VydmluZ1N0YXR1cyI6Cg1TZXJ2aW5nU3RhdHVzEgsK",
"YXR1cyI6Cg1TZXJ2aW5nU3RhdHVzEgsKB1VOS05PV04QABILCgdTRVJWSU5H", "B1VOS05PV04QABILCgdTRVJWSU5HEAESDwoLTk9UX1NFUlZJTkcQAjJaCgZI",
"EAESDwoLTk9UX1NFUlZJTkcQAjJkCgZIZWFsdGgSWgoFQ2hlY2sSJy5ncnBj", "ZWFsdGgSUAoFQ2hlY2sSIi5ncnBjLmhlYWx0aC52MS5IZWFsdGhDaGVja1Jl",
"LmhlYWx0aC52MWFscGhhLkhlYWx0aENoZWNrUmVxdWVzdBooLmdycGMuaGVh", "cXVlc3QaIy5ncnBjLmhlYWx0aC52MS5IZWFsdGhDaGVja1Jlc3BvbnNlQhGq",
"bHRoLnYxYWxwaGEuSGVhbHRoQ2hlY2tSZXNwb25zZUIWqgITR3JwYy5IZWFs", "Ag5HcnBjLkhlYWx0aC5WMWIGcHJvdG8z"));
"dGguVjFBbHBoYWIGcHJvdG8z"));
descriptor = pbr::FileDescriptor.FromGeneratedCode(descriptorData, descriptor = pbr::FileDescriptor.FromGeneratedCode(descriptorData,
new pbr::FileDescriptor[] { }, new pbr::FileDescriptor[] { },
new pbr::GeneratedCodeInfo(null, new pbr::GeneratedCodeInfo[] { new pbr::GeneratedCodeInfo(null, new pbr::GeneratedCodeInfo[] {
new pbr::GeneratedCodeInfo(typeof(global::Grpc.Health.V1Alpha.HealthCheckRequest), global::Grpc.Health.V1Alpha.HealthCheckRequest.Parser, new[]{ "Host", "Service" }, null, null, null), new pbr::GeneratedCodeInfo(typeof(global::Grpc.Health.V1.HealthCheckRequest), global::Grpc.Health.V1.HealthCheckRequest.Parser, new[]{ "Service" }, null, null, null),
new pbr::GeneratedCodeInfo(typeof(global::Grpc.Health.V1Alpha.HealthCheckResponse), global::Grpc.Health.V1Alpha.HealthCheckResponse.Parser, new[]{ "Status" }, null, new[]{ typeof(global::Grpc.Health.V1Alpha.HealthCheckResponse.Types.ServingStatus) }, null) new pbr::GeneratedCodeInfo(typeof(global::Grpc.Health.V1.HealthCheckResponse), global::Grpc.Health.V1.HealthCheckResponse.Parser, new[]{ "Status" }, null, new[]{ typeof(global::Grpc.Health.V1.HealthCheckResponse.Types.ServingStatus) }, null)
})); }));
} }
#endregion #endregion
@ -49,7 +48,7 @@ namespace Grpc.Health.V1Alpha {
public static pb::MessageParser<HealthCheckRequest> Parser { get { return _parser; } } public static pb::MessageParser<HealthCheckRequest> Parser { get { return _parser; } }
public static pbr::MessageDescriptor Descriptor { public static pbr::MessageDescriptor Descriptor {
get { return global::Grpc.Health.V1Alpha.HealthReflection.Descriptor.MessageTypes[0]; } get { return global::Grpc.Health.V1.HealthReflection.Descriptor.MessageTypes[0]; }
} }
pbr::MessageDescriptor pb::IMessage.Descriptor { pbr::MessageDescriptor pb::IMessage.Descriptor {
@ -63,7 +62,6 @@ namespace Grpc.Health.V1Alpha {
partial void OnConstruction(); partial void OnConstruction();
public HealthCheckRequest(HealthCheckRequest other) : this() { public HealthCheckRequest(HealthCheckRequest other) : this() {
host_ = other.host_;
service_ = other.service_; service_ = other.service_;
} }
@ -71,18 +69,8 @@ namespace Grpc.Health.V1Alpha {
return new HealthCheckRequest(this); return new HealthCheckRequest(this);
} }
/// <summary>Field number for the "host" field.</summary>
public const int HostFieldNumber = 1;
private string host_ = "";
public string Host {
get { return host_; }
set {
host_ = pb::Preconditions.CheckNotNull(value, "value");
}
}
/// <summary>Field number for the "service" field.</summary> /// <summary>Field number for the "service" field.</summary>
public const int ServiceFieldNumber = 2; public const int ServiceFieldNumber = 1;
private string service_ = ""; private string service_ = "";
public string Service { public string Service {
get { return service_; } get { return service_; }
@ -102,14 +90,12 @@ namespace Grpc.Health.V1Alpha {
if (ReferenceEquals(other, this)) { if (ReferenceEquals(other, this)) {
return true; return true;
} }
if (Host != other.Host) return false;
if (Service != other.Service) return false; if (Service != other.Service) return false;
return true; return true;
} }
public override int GetHashCode() { public override int GetHashCode() {
int hash = 1; int hash = 1;
if (Host.Length != 0) hash ^= Host.GetHashCode();
if (Service.Length != 0) hash ^= Service.GetHashCode(); if (Service.Length != 0) hash ^= Service.GetHashCode();
return hash; return hash;
} }
@ -119,21 +105,14 @@ namespace Grpc.Health.V1Alpha {
} }
public void WriteTo(pb::CodedOutputStream output) { public void WriteTo(pb::CodedOutputStream output) {
if (Host.Length != 0) {
output.WriteRawTag(10);
output.WriteString(Host);
}
if (Service.Length != 0) { if (Service.Length != 0) {
output.WriteRawTag(18); output.WriteRawTag(10);
output.WriteString(Service); output.WriteString(Service);
} }
} }
public int CalculateSize() { public int CalculateSize() {
int size = 0; int size = 0;
if (Host.Length != 0) {
size += 1 + pb::CodedOutputStream.ComputeStringSize(Host);
}
if (Service.Length != 0) { if (Service.Length != 0) {
size += 1 + pb::CodedOutputStream.ComputeStringSize(Service); size += 1 + pb::CodedOutputStream.ComputeStringSize(Service);
} }
@ -144,9 +123,6 @@ namespace Grpc.Health.V1Alpha {
if (other == null) { if (other == null) {
return; return;
} }
if (other.Host.Length != 0) {
Host = other.Host;
}
if (other.Service.Length != 0) { if (other.Service.Length != 0) {
Service = other.Service; Service = other.Service;
} }
@ -160,10 +136,6 @@ namespace Grpc.Health.V1Alpha {
input.SkipLastField(); input.SkipLastField();
break; break;
case 10: { case 10: {
Host = input.ReadString();
break;
}
case 18: {
Service = input.ReadString(); Service = input.ReadString();
break; break;
} }
@ -179,7 +151,7 @@ namespace Grpc.Health.V1Alpha {
public static pb::MessageParser<HealthCheckResponse> Parser { get { return _parser; } } public static pb::MessageParser<HealthCheckResponse> Parser { get { return _parser; } }
public static pbr::MessageDescriptor Descriptor { public static pbr::MessageDescriptor Descriptor {
get { return global::Grpc.Health.V1Alpha.HealthReflection.Descriptor.MessageTypes[1]; } get { return global::Grpc.Health.V1.HealthReflection.Descriptor.MessageTypes[1]; }
} }
pbr::MessageDescriptor pb::IMessage.Descriptor { pbr::MessageDescriptor pb::IMessage.Descriptor {
@ -202,8 +174,8 @@ namespace Grpc.Health.V1Alpha {
/// <summary>Field number for the "status" field.</summary> /// <summary>Field number for the "status" field.</summary>
public const int StatusFieldNumber = 1; public const int StatusFieldNumber = 1;
private global::Grpc.Health.V1Alpha.HealthCheckResponse.Types.ServingStatus status_ = global::Grpc.Health.V1Alpha.HealthCheckResponse.Types.ServingStatus.UNKNOWN; private global::Grpc.Health.V1.HealthCheckResponse.Types.ServingStatus status_ = global::Grpc.Health.V1.HealthCheckResponse.Types.ServingStatus.UNKNOWN;
public global::Grpc.Health.V1Alpha.HealthCheckResponse.Types.ServingStatus Status { public global::Grpc.Health.V1.HealthCheckResponse.Types.ServingStatus Status {
get { return status_; } get { return status_; }
set { set {
status_ = value; status_ = value;
@ -227,7 +199,7 @@ namespace Grpc.Health.V1Alpha {
public override int GetHashCode() { public override int GetHashCode() {
int hash = 1; int hash = 1;
if (Status != global::Grpc.Health.V1Alpha.HealthCheckResponse.Types.ServingStatus.UNKNOWN) hash ^= Status.GetHashCode(); if (Status != global::Grpc.Health.V1.HealthCheckResponse.Types.ServingStatus.UNKNOWN) hash ^= Status.GetHashCode();
return hash; return hash;
} }
@ -236,7 +208,7 @@ namespace Grpc.Health.V1Alpha {
} }
public void WriteTo(pb::CodedOutputStream output) { public void WriteTo(pb::CodedOutputStream output) {
if (Status != global::Grpc.Health.V1Alpha.HealthCheckResponse.Types.ServingStatus.UNKNOWN) { if (Status != global::Grpc.Health.V1.HealthCheckResponse.Types.ServingStatus.UNKNOWN) {
output.WriteRawTag(8); output.WriteRawTag(8);
output.WriteEnum((int) Status); output.WriteEnum((int) Status);
} }
@ -244,7 +216,7 @@ namespace Grpc.Health.V1Alpha {
public int CalculateSize() { public int CalculateSize() {
int size = 0; int size = 0;
if (Status != global::Grpc.Health.V1Alpha.HealthCheckResponse.Types.ServingStatus.UNKNOWN) { if (Status != global::Grpc.Health.V1.HealthCheckResponse.Types.ServingStatus.UNKNOWN) {
size += 1 + pb::CodedOutputStream.ComputeEnumSize((int) Status); size += 1 + pb::CodedOutputStream.ComputeEnumSize((int) Status);
} }
return size; return size;
@ -254,7 +226,7 @@ namespace Grpc.Health.V1Alpha {
if (other == null) { if (other == null) {
return; return;
} }
if (other.Status != global::Grpc.Health.V1Alpha.HealthCheckResponse.Types.ServingStatus.UNKNOWN) { if (other.Status != global::Grpc.Health.V1.HealthCheckResponse.Types.ServingStatus.UNKNOWN) {
Status = other.Status; Status = other.Status;
} }
} }
@ -267,7 +239,7 @@ namespace Grpc.Health.V1Alpha {
input.SkipLastField(); input.SkipLastField();
break; break;
case 8: { case 8: {
status_ = (global::Grpc.Health.V1Alpha.HealthCheckResponse.Types.ServingStatus) input.ReadEnum(); status_ = (global::Grpc.Health.V1.HealthCheckResponse.Types.ServingStatus) input.ReadEnum();
break; break;
} }
} }

@ -7,15 +7,15 @@ using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using Grpc.Core; using Grpc.Core;
namespace Grpc.Health.V1Alpha { namespace Grpc.Health.V1 {
public static class Health public static class Health
{ {
static readonly string __ServiceName = "grpc.health.v1alpha.Health"; static readonly string __ServiceName = "grpc.health.v1.Health";
static readonly Marshaller<global::Grpc.Health.V1Alpha.HealthCheckRequest> __Marshaller_HealthCheckRequest = Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::Grpc.Health.V1Alpha.HealthCheckRequest.Parser.ParseFrom); static readonly Marshaller<global::Grpc.Health.V1.HealthCheckRequest> __Marshaller_HealthCheckRequest = Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::Grpc.Health.V1.HealthCheckRequest.Parser.ParseFrom);
static readonly Marshaller<global::Grpc.Health.V1Alpha.HealthCheckResponse> __Marshaller_HealthCheckResponse = Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::Grpc.Health.V1Alpha.HealthCheckResponse.Parser.ParseFrom); static readonly Marshaller<global::Grpc.Health.V1.HealthCheckResponse> __Marshaller_HealthCheckResponse = Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::Grpc.Health.V1.HealthCheckResponse.Parser.ParseFrom);
static readonly Method<global::Grpc.Health.V1Alpha.HealthCheckRequest, global::Grpc.Health.V1Alpha.HealthCheckResponse> __Method_Check = new Method<global::Grpc.Health.V1Alpha.HealthCheckRequest, global::Grpc.Health.V1Alpha.HealthCheckResponse>( static readonly Method<global::Grpc.Health.V1.HealthCheckRequest, global::Grpc.Health.V1.HealthCheckResponse> __Method_Check = new Method<global::Grpc.Health.V1.HealthCheckRequest, global::Grpc.Health.V1.HealthCheckResponse>(
MethodType.Unary, MethodType.Unary,
__ServiceName, __ServiceName,
"Check", "Check",
@ -25,22 +25,22 @@ namespace Grpc.Health.V1Alpha {
// service descriptor // service descriptor
public static global::Google.Protobuf.Reflection.ServiceDescriptor Descriptor public static global::Google.Protobuf.Reflection.ServiceDescriptor Descriptor
{ {
get { return global::Grpc.Health.V1Alpha.HealthReflection.Descriptor.Services[0]; } get { return global::Grpc.Health.V1.HealthReflection.Descriptor.Services[0]; }
} }
// client interface // client interface
public interface IHealthClient public interface IHealthClient
{ {
global::Grpc.Health.V1Alpha.HealthCheckResponse Check(global::Grpc.Health.V1Alpha.HealthCheckRequest request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken)); global::Grpc.Health.V1.HealthCheckResponse Check(global::Grpc.Health.V1.HealthCheckRequest request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken));
global::Grpc.Health.V1Alpha.HealthCheckResponse Check(global::Grpc.Health.V1Alpha.HealthCheckRequest request, CallOptions options); global::Grpc.Health.V1.HealthCheckResponse Check(global::Grpc.Health.V1.HealthCheckRequest request, CallOptions options);
AsyncUnaryCall<global::Grpc.Health.V1Alpha.HealthCheckResponse> CheckAsync(global::Grpc.Health.V1Alpha.HealthCheckRequest request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken)); AsyncUnaryCall<global::Grpc.Health.V1.HealthCheckResponse> CheckAsync(global::Grpc.Health.V1.HealthCheckRequest request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken));
AsyncUnaryCall<global::Grpc.Health.V1Alpha.HealthCheckResponse> CheckAsync(global::Grpc.Health.V1Alpha.HealthCheckRequest request, CallOptions options); AsyncUnaryCall<global::Grpc.Health.V1.HealthCheckResponse> CheckAsync(global::Grpc.Health.V1.HealthCheckRequest request, CallOptions options);
} }
// server-side interface // server-side interface
public interface IHealth public interface IHealth
{ {
Task<global::Grpc.Health.V1Alpha.HealthCheckResponse> Check(global::Grpc.Health.V1Alpha.HealthCheckRequest request, ServerCallContext context); Task<global::Grpc.Health.V1.HealthCheckResponse> Check(global::Grpc.Health.V1.HealthCheckRequest request, ServerCallContext context);
} }
// client stub // client stub
@ -49,22 +49,22 @@ namespace Grpc.Health.V1Alpha {
public HealthClient(Channel channel) : base(channel) public HealthClient(Channel channel) : base(channel)
{ {
} }
public global::Grpc.Health.V1Alpha.HealthCheckResponse Check(global::Grpc.Health.V1Alpha.HealthCheckRequest request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken)) public global::Grpc.Health.V1.HealthCheckResponse Check(global::Grpc.Health.V1.HealthCheckRequest request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
{ {
var call = CreateCall(__Method_Check, new CallOptions(headers, deadline, cancellationToken)); var call = CreateCall(__Method_Check, new CallOptions(headers, deadline, cancellationToken));
return Calls.BlockingUnaryCall(call, request); return Calls.BlockingUnaryCall(call, request);
} }
public global::Grpc.Health.V1Alpha.HealthCheckResponse Check(global::Grpc.Health.V1Alpha.HealthCheckRequest request, CallOptions options) public global::Grpc.Health.V1.HealthCheckResponse Check(global::Grpc.Health.V1.HealthCheckRequest request, CallOptions options)
{ {
var call = CreateCall(__Method_Check, options); var call = CreateCall(__Method_Check, options);
return Calls.BlockingUnaryCall(call, request); return Calls.BlockingUnaryCall(call, request);
} }
public AsyncUnaryCall<global::Grpc.Health.V1Alpha.HealthCheckResponse> CheckAsync(global::Grpc.Health.V1Alpha.HealthCheckRequest request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken)) public AsyncUnaryCall<global::Grpc.Health.V1.HealthCheckResponse> CheckAsync(global::Grpc.Health.V1.HealthCheckRequest request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken))
{ {
var call = CreateCall(__Method_Check, new CallOptions(headers, deadline, cancellationToken)); var call = CreateCall(__Method_Check, new CallOptions(headers, deadline, cancellationToken));
return Calls.AsyncUnaryCall(call, request); return Calls.AsyncUnaryCall(call, request);
} }
public AsyncUnaryCall<global::Grpc.Health.V1Alpha.HealthCheckResponse> CheckAsync(global::Grpc.Health.V1Alpha.HealthCheckRequest request, CallOptions options) public AsyncUnaryCall<global::Grpc.Health.V1.HealthCheckResponse> CheckAsync(global::Grpc.Health.V1.HealthCheckRequest request, CallOptions options)
{ {
var call = CreateCall(__Method_Check, options); var call = CreateCall(__Method_Check, options);
return Calls.AsyncUnaryCall(call, request); return Calls.AsyncUnaryCall(call, request);

@ -37,7 +37,7 @@ using System.Threading.Tasks;
using Grpc.Core; using Grpc.Core;
using Grpc.Core.Utils; using Grpc.Core.Utils;
using Grpc.Health.V1Alpha; using Grpc.Health.V1;
namespace Grpc.HealthCheck namespace Grpc.HealthCheck
{ {
@ -48,44 +48,42 @@ namespace Grpc.HealthCheck
/// <code> /// <code>
/// var serviceImpl = new HealthServiceImpl(); /// var serviceImpl = new HealthServiceImpl();
/// server = new Server(); /// server = new Server();
/// server.AddServiceDefinition(Grpc.Health.V1Alpha.Health.BindService(serviceImpl)); /// server.AddServiceDefinition(Grpc.Health.V1.Health.BindService(serviceImpl));
/// </code> /// </code>
/// </summary> /// </summary>
public class HealthServiceImpl : Grpc.Health.V1Alpha.Health.IHealth public class HealthServiceImpl : Grpc.Health.V1.Health.IHealth
{ {
private readonly object myLock = new object(); private readonly object myLock = new object();
private readonly Dictionary<Key, HealthCheckResponse.Types.ServingStatus> statusMap = private readonly Dictionary<string, HealthCheckResponse.Types.ServingStatus> statusMap =
new Dictionary<Key, HealthCheckResponse.Types.ServingStatus>(); new Dictionary<string, HealthCheckResponse.Types.ServingStatus>();
/// <summary> /// <summary>
/// Sets the health status for given host and service. /// Sets the health status for given service.
/// </summary> /// </summary>
/// <param name="host">The host. Cannot be null.</param>
/// <param name="service">The service. Cannot be null.</param> /// <param name="service">The service. Cannot be null.</param>
/// <param name="status">the health status</param> /// <param name="status">the health status</param>
public void SetStatus(string host, string service, HealthCheckResponse.Types.ServingStatus status) public void SetStatus(string service, HealthCheckResponse.Types.ServingStatus status)
{ {
lock (myLock) lock (myLock)
{ {
statusMap[CreateKey(host, service)] = status; statusMap[service] = status;
} }
} }
/// <summary> /// <summary>
/// Clears health status for given host and service. /// Clears health status for given service.
/// </summary> /// </summary>
/// <param name="host">The host. Cannot be null.</param>
/// <param name="service">The service. Cannot be null.</param> /// <param name="service">The service. Cannot be null.</param>
public void ClearStatus(string host, string service) public void ClearStatus(string service)
{ {
lock (myLock) lock (myLock)
{ {
statusMap.Remove(CreateKey(host, service)); statusMap.Remove(service);
} }
} }
/// <summary> /// <summary>
/// Clears statuses for all hosts and services. /// Clears statuses for all services.
/// </summary> /// </summary>
public void ClearAll() public void ClearAll()
{ {
@ -105,11 +103,10 @@ namespace Grpc.HealthCheck
{ {
lock (myLock) lock (myLock)
{ {
var host = request.Host;
var service = request.Service; var service = request.Service;
HealthCheckResponse.Types.ServingStatus status; HealthCheckResponse.Types.ServingStatus status;
if (!statusMap.TryGetValue(CreateKey(host, service), out status)) if (!statusMap.TryGetValue(service, out status))
{ {
// TODO(jtattermusch): returning specific status from server handler is not supported yet. // TODO(jtattermusch): returning specific status from server handler is not supported yet.
throw new RpcException(new Status(StatusCode.NotFound, "")); throw new RpcException(new Status(StatusCode.NotFound, ""));
@ -117,22 +114,5 @@ namespace Grpc.HealthCheck
return Task.FromResult(new HealthCheckResponse { Status = status }); return Task.FromResult(new HealthCheckResponse { Status = status });
} }
} }
private static Key CreateKey(string host, string service)
{
return new Key(host, service);
}
private struct Key
{
public Key(string host, string service)
{
this.Host = GrpcPreconditions.CheckNotNull(host);
this.Service = GrpcPreconditions.CheckNotNull(service);
}
readonly string Host;
readonly string Service;
}
} }
} }

@ -1,6 +1,6 @@
#region Copyright notice and license #region Copyright notice and license
// Copyright 2015, Google Inc. // Copyright 2015-2016, Google Inc.
// All rights reserved. // All rights reserved.
// //
// Redistribution and use in source and binary forms, with or without // Redistribution and use in source and binary forms, with or without
@ -140,14 +140,12 @@ namespace Grpc.IntegrationTesting
} }
[Test] [Test]
[Ignore("TODO: see #4427")]
public async Task StatusCodeAndMessage() public async Task StatusCodeAndMessage()
{ {
await InteropClient.RunStatusCodeAndMessageAsync(client); await InteropClient.RunStatusCodeAndMessageAsync(client);
} }
[Test] [Test]
[Ignore("TODO: see #4427")]
public void UnimplementedMethod() public void UnimplementedMethod()
{ {
InteropClient.RunUnimplementedMethod(UnimplementedService.NewClient(channel)); InteropClient.RunUnimplementedMethod(UnimplementedService.NewClient(channel));

@ -4,18 +4,29 @@
<id>Grpc.Tools</id> <id>Grpc.Tools</id>
<title>gRPC C# Tools</title> <title>gRPC C# Tools</title>
<summary>Tools for C# implementation of gRPC - an RPC library and framework</summary> <summary>Tools for C# implementation of gRPC - an RPC library and framework</summary>
<description>Precompiled Windows binary for generating gRPC client/server code</description> <description>Precompiled protobuf compiler and gRPC protobuf compiler plugin for generating gRPC client/server C# code. Binaries are available for Windows, Linux and MacOS.</description>
<version>$version$</version> <version>$version$</version>
<authors>Google Inc.</authors> <authors>Google Inc.</authors>
<owners>grpc-packages</owners> <owners>grpc-packages</owners>
<licenseUrl>https://github.com/grpc/grpc/blob/master/LICENSE</licenseUrl> <licenseUrl>https://github.com/grpc/grpc/blob/master/LICENSE</licenseUrl>
<projectUrl>https://github.com/grpc/grpc</projectUrl> <projectUrl>https://github.com/grpc/grpc</projectUrl>
<requireLicenseAcceptance>false</requireLicenseAcceptance> <requireLicenseAcceptance>false</requireLicenseAcceptance>
<releaseNotes>grpc_csharp_plugin.exe - gRPC C# protoc plugin version $version$</releaseNotes> <releaseNotes>Release $version$</releaseNotes>
<copyright>Copyright 2015, Google Inc.</copyright> <copyright>Copyright 2015, Google Inc.</copyright>
<tags>gRPC RPC Protocol HTTP/2</tags> <tags>gRPC RPC Protocol HTTP/2</tags>
</metadata> </metadata>
<files> <files>
<file src="..\..\vsprojects\Release\grpc_csharp_plugin.exe" target="tools" /> <file src="protoc_plugins\windows_x86\protoc.exe" target="tools\windows_x86\protoc.exe" />
<file src="protoc_plugins\windows_x86\grpc_csharp_plugin.exe" target="tools\windows_x86\grpc_csharp_plugin.exe" />
<file src="protoc_plugins\windows_x64\protoc.exe" target="tools\windows_x64\protoc.exe" />
<file src="protoc_plugins\windows_x64\grpc_csharp_plugin.exe" target="tools\windows_x64\grpc_csharp_plugin.exe" />
<file src="protoc_plugins\linux_x86\protoc" target="tools\linux_x86\protoc" />
<file src="protoc_plugins\linux_x86\grpc_csharp_plugin" target="tools\linux_x86\grpc_csharp_plugin" />
<file src="protoc_plugins\linux_x64\protoc" target="tools\linux_x64\protoc" />
<file src="protoc_plugins\linux_x64\grpc_csharp_plugin" target="tools\linux_x64\grpc_csharp_plugin" />
<file src="protoc_plugins\macosx_x86\protoc" target="tools\macosx_x86\protoc" />
<file src="protoc_plugins\macosx_x86\grpc_csharp_plugin" target="tools\macosx_x86\grpc_csharp_plugin" />
<file src="protoc_plugins\macosx_x64\protoc" target="tools\macosx_x64\protoc" />
<file src="protoc_plugins\macosx_x64\grpc_csharp_plugin" target="tools\macosx_x64\grpc_csharp_plugin" />
</files> </files>
</package> </package>

@ -19,6 +19,14 @@ xcopy /Y /I ..\..\architecture=x64,language=csharp,platform=linux\artifacts\* gr
xcopy /Y /I ..\..\architecture=x86,language=csharp,platform=macos\artifacts\* grpc.native.csharp\macosx_x86\ xcopy /Y /I ..\..\architecture=x86,language=csharp,platform=macos\artifacts\* grpc.native.csharp\macosx_x86\
xcopy /Y /I ..\..\architecture=x64,language=csharp,platform=macos\artifacts\* grpc.native.csharp\macosx_x64\ xcopy /Y /I ..\..\architecture=x64,language=csharp,platform=macos\artifacts\* grpc.native.csharp\macosx_x64\
@rem Collect protoc artifacts built by the previous build step
xcopy /Y /I ..\..\architecture=x86,language=protoc,platform=windows\artifacts\* protoc_plugins\windows_x86\
xcopy /Y /I ..\..\architecture=x64,language=protoc,platform=windows\artifacts\* protoc_plugins\windows_x64\
xcopy /Y /I ..\..\architecture=x86,language=protoc,platform=linux\artifacts\* protoc_plugins\linux_x86\
xcopy /Y /I ..\..\architecture=x64,language=protoc,platform=linux\artifacts\* protoc_plugins\linux_x64\
xcopy /Y /I ..\..\architecture=x86,language=protoc,platform=macos\artifacts\* protoc_plugins\macosx_x86\
xcopy /Y /I ..\..\architecture=x64,language=protoc,platform=macos\artifacts\* protoc_plugins\macosx_x64\
@rem Fetch all dependencies @rem Fetch all dependencies
%NUGET% restore ..\..\vsprojects\grpc_csharp_ext.sln || goto :error %NUGET% restore ..\..\vsprojects\grpc_csharp_ext.sln || goto :error
%NUGET% restore Grpc.sln || goto :error %NUGET% restore Grpc.sln || goto :error
@ -27,24 +35,19 @@ setlocal
@call "%VS120COMNTOOLS%\..\..\vc\vcvarsall.bat" x86 @call "%VS120COMNTOOLS%\..\..\vc\vcvarsall.bat" x86
@rem We won't use the native libraries from this step, but without this Grpc.sln will fail. @rem We won't use the native libraries from this step, but without this Grpc.sln will fail.
msbuild ..\..\vsprojects\grpc_csharp_ext.sln /p:Configuration=Release /p:PlatformToolset=v120 || goto :error msbuild ..\..\vsprojects\grpc_csharp_ext.sln /p:Configuration=Release /p:PlatformToolset=v120 || goto :error
msbuild Grpc.sln /p:Configuration=ReleaseSigned || goto :error msbuild Grpc.sln /p:Configuration=ReleaseSigned || goto :error
endlocal endlocal
@rem TODO(jtattermusch): re-enable protoc plugin building
@rem @call ..\..\vsprojects\build_plugins.bat || goto :error
%NUGET% pack grpc.native.csharp\grpc.native.csharp.nuspec -Version %VERSION% || goto :error %NUGET% pack grpc.native.csharp\grpc.native.csharp.nuspec -Version %VERSION% || goto :error
%NUGET% pack Grpc.Auth\Grpc.Auth.nuspec -Symbols -Version %VERSION% || goto :error %NUGET% pack Grpc.Auth\Grpc.Auth.nuspec -Symbols -Version %VERSION% || goto :error
%NUGET% pack Grpc.Core\Grpc.Core.nuspec -Symbols -Version %VERSION% || goto :error %NUGET% pack Grpc.Core\Grpc.Core.nuspec -Symbols -Version %VERSION% || goto :error
%NUGET% pack Grpc.HealthCheck\Grpc.HealthCheck.nuspec -Symbols -Version %VERSION_WITH_BETA% -Properties ProtobufVersion=%PROTOBUF_VERSION% || goto :error %NUGET% pack Grpc.HealthCheck\Grpc.HealthCheck.nuspec -Symbols -Version %VERSION_WITH_BETA% -Properties ProtobufVersion=%PROTOBUF_VERSION% || goto :error
%NUGET% pack Grpc.nuspec -Version %VERSION% || goto :error %NUGET% pack Grpc.nuspec -Version %VERSION% || goto :error
%NUGET% pack Grpc.Tools.nuspec -Version %VERSION% || goto :error
@rem TODO(jtattermusch): re-enable building Grpc.Tools package
@rem %NUGET% pack Grpc.Tools.nuspec -Version %VERSION% || goto :error
@rem copy resulting nuget packages to artifacts directory @rem copy resulting nuget packages to artifacts directory
xcopy /Y /I *.nupkg ..\..\artifacts\ xcopy /Y /I *.nupkg ..\..\artifacts\

@ -42,7 +42,7 @@ $PROTOC --plugin=$PLUGIN --csharp_out=$EXAMPLES_DIR --grpc_out=$EXAMPLES_DIR \
-I src/proto/math src/proto/math/math.proto -I src/proto/math src/proto/math/math.proto
$PROTOC --plugin=$PLUGIN --csharp_out=$HEALTHCHECK_DIR --grpc_out=$HEALTHCHECK_DIR \ $PROTOC --plugin=$PLUGIN --csharp_out=$HEALTHCHECK_DIR --grpc_out=$HEALTHCHECK_DIR \
-I src/proto/grpc/health/v1alpha src/proto/grpc/health/v1alpha/health.proto -I src/proto/grpc/health/v1 src/proto/grpc/health/v1/health.proto
$PROTOC --plugin=$PLUGIN --csharp_out=$TESTING_DIR --grpc_out=$TESTING_DIR \ $PROTOC --plugin=$PLUGIN --csharp_out=$TESTING_DIR --grpc_out=$TESTING_DIR \
-I . src/proto/grpc/testing/{control,empty,messages,payloads,services,stats,test}.proto -I . src/proto/grpc/testing/{control,empty,messages,payloads,services,stats,test}.proto

@ -1,6 +1,6 @@
/* /*
* *
* Copyright 2015, Google Inc. * Copyright 2015-2016, Google Inc.
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
@ -38,9 +38,9 @@ var grpc = require('../');
var _ = require('lodash'); var _ = require('lodash');
var health_proto = grpc.load(__dirname + var health_proto = grpc.load(__dirname +
'/../../proto/grpc/health/v1alpha/health.proto'); '/../../proto/grpc/health/v1/health.proto');
var HealthClient = health_proto.grpc.health.v1alpha.Health; var HealthClient = health_proto.grpc.health.v1.Health;
function HealthImplementation(statusMap) { function HealthImplementation(statusMap) {
this.statusMap = _.clone(statusMap); this.statusMap = _.clone(statusMap);

@ -103,6 +103,8 @@ static ProtoMethod *kUnaryCallMethod;
@implementation GRPCClientTests @implementation GRPCClientTests
- (void)setUp { - (void)setUp {
// Add a custom user agent prefix that will be used in test
[GRPCCall setUserAgentPrefix:@"Foo" forHost:kHostAddress];
// Register test server as non-SSL. // Register test server as non-SSL.
[GRPCCall useInsecureConnectionsForHost:kHostAddress]; [GRPCCall useInsecureConnectionsForHost:kHostAddress];
@ -257,6 +259,35 @@ static ProtoMethod *kUnaryCallMethod;
[self waitForExpectationsWithTimeout:8 handler:nil]; [self waitForExpectationsWithTimeout:8 handler:nil];
} }
- (void)testUserAgentPrefix {
__weak XCTestExpectation *response = [self expectationWithDescription:@"Empty response received."];
__weak XCTestExpectation *completion = [self expectationWithDescription:@"Empty RPC completed."];
GRPCCall *call = [[GRPCCall alloc] initWithHost:kHostAddress
path:kEmptyCallMethod.HTTPPath
requestsWriter:[GRXWriter writerWithValue:[NSData data]]];
// Setting this special key in the header will cause the interop server to echo back the
// user-agent value, which we confirm.
call.requestHeaders[@"x-grpc-test-echo-useragent"] = @"";
id<GRXWriteable> responsesWriteable = [[GRXWriteable alloc] initWithValueHandler:^(NSData *value) {
XCTAssertNotNil(value, @"nil value received as response.");
XCTAssertEqual([value length], 0, @"Non-empty response received: %@", value);
XCTAssertEqualObjects(call.responseHeaders[@"x-grpc-test-echo-useragent"],
@"Foo grpc-objc/0.13.0 grpc-c/0.14.0-dev (ios)",
@"Did not receive expected user agent %@",
call.responseHeaders[@"x-grpc-test-echo-useragent"]);
[response fulfill];
} completionHandler:^(NSError *errorOrNil) {
XCTAssertNil(errorOrNil, @"Finished with unexpected error: %@", errorOrNil);
[completion fulfill];
}];
[call startWithWriteable:responsesWriteable];
[self waitForExpectationsWithTimeout:8 handler:nil];
}
// TODO(makarandd): Move to a different file that contains only unit tests // TODO(makarandd): Move to a different file that contains only unit tests
- (void)testExceptions { - (void)testExceptions {
// Try to set userAgentPrefix for host that is nil. This should cause // Try to set userAgentPrefix for host that is nil. This should cause

@ -33,45 +33,12 @@ $ sudo mv phpunit.phar /usr/local/bin/phpunit
## Quick Install ## Quick Install
**Linux (Debian):**
Add [Debian jessie-backports][] to your `sources.list` file. Example:
```sh
echo "deb http://http.debian.net/debian jessie-backports main" | \
sudo tee -a /etc/apt/sources.list
```
Install the gRPC Debian package
```sh
sudo apt-get update
sudo apt-get install libgrpc-dev
```
Install the gRPC PHP extension Install the gRPC PHP extension
```sh ```sh
sudo pecl install grpc-beta sudo pecl install grpc-beta
``` ```
**Mac OS X:**
Install [homebrew][]. Example:
```sh
ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"
```
Install the gRPC core library and the PHP extension in one step
```sh
$ curl -fsSL https://goo.gl/getgrpc | bash -s php
```
This will download and run the [gRPC install script][] and compile the gRPC PHP extension.
## Build from Source ## Build from Source
Clone this repository Clone this repository
@ -297,7 +264,4 @@ Connect to `localhost/math_client.php` in your browser, or run this from command
$ curl localhost/math_client.php $ curl localhost/math_client.php
``` ```
[homebrew]:http://brew.sh
[gRPC install script]:https://raw.githubusercontent.com/grpc/homebrew-grpc/master/scripts/install
[Node]:https://github.com/grpc/grpc/tree/master/src/node/examples [Node]:https://github.com/grpc/grpc/tree/master/src/node/examples
[Debian jessie-backports]:http://backports.debian.org/Instructions/

@ -29,12 +29,11 @@
syntax = "proto3"; syntax = "proto3";
package grpc.health.v1alpha; package grpc.health.v1;
option csharp_namespace = "Grpc.Health.V1Alpha"; option csharp_namespace = "Grpc.Health.V1";
message HealthCheckRequest { message HealthCheckRequest {
string host = 1; string service = 1;
string service = 2;
} }
message HealthCheckResponse { message HealthCheckResponse {

@ -38,3 +38,17 @@ package named `python-dev`).
Note that `$REPO_ROOT` can be assigned to whatever directory name floats your Note that `$REPO_ROOT` can be assigned to whatever directory name floats your
fancy. fancy.
Troubleshooting
~~~~~~~~~~~~~~~
Help, I ...
* **... see a** :code:`pkg_resources.VersionConflict` **when I try to install
grpc!**
This is likely because :code:`pip` doesn't own the offending dependency,
which in turn is likely because your operating system's package manager owns
it. You'll need to force the installation of the dependency:
:code:`pip install --ignore-installed $OFFENDING_DEPENDENCY`

@ -1,4 +1,4 @@
# Copyright 2015, Google Inc. # Copyright 2015-2016, Google Inc.
# All rights reserved. # All rights reserved.
# #
# Redistribution and use in source and binary forms, with or without # Redistribution and use in source and binary forms, with or without
@ -89,12 +89,13 @@ cdef class Channel:
def check_connectivity_state(self, bint try_to_connect): def check_connectivity_state(self, bint try_to_connect):
return grpc_channel_check_connectivity_state(self.c_channel, return grpc_channel_check_connectivity_state(self.c_channel,
try_to_connect) try_to_connect)
def watch_connectivity_state( def watch_connectivity_state(
self, last_observed_state, Timespec deadline not None, self, grpc_connectivity_state last_observed_state,
CompletionQueue queue not None, tag): Timespec deadline not None, CompletionQueue queue not None, tag):
cdef OperationTag operation_tag = OperationTag(tag) cdef OperationTag operation_tag = OperationTag(tag)
operation_tag.references = [self, queue]
cpython.Py_INCREF(operation_tag) cpython.Py_INCREF(operation_tag)
grpc_channel_watch_connectivity_state( grpc_channel_watch_connectivity_state(
self.c_channel, last_observed_state, deadline.c_time, self.c_channel, last_observed_state, deadline.c_time,

@ -1,4 +1,4 @@
# Copyright 2015, Google Inc. # Copyright 2015-2016, Google Inc.
# All rights reserved. # All rights reserved.
# #
# Redistribution and use in source and binary forms, with or without # Redistribution and use in source and binary forms, with or without
@ -31,8 +31,9 @@
cdef class CompletionQueue: cdef class CompletionQueue:
cdef grpc_completion_queue *c_completion_queue cdef grpc_completion_queue *c_completion_queue
cdef object poll_condition cdef object pluck_condition
cdef bint is_polling cdef int num_plucking
cdef int num_polling
cdef bint is_shutting_down cdef bint is_shutting_down
cdef bint is_shutdown cdef bint is_shutdown

@ -1,4 +1,4 @@
# Copyright 2015, Google Inc. # Copyright 2015-2016, Google Inc.
# All rights reserved. # All rights reserved.
# #
# Redistribution and use in source and binary forms, with or without # Redistribution and use in source and binary forms, with or without
@ -39,8 +39,9 @@ cdef class CompletionQueue:
self.c_completion_queue = grpc_completion_queue_create(NULL) self.c_completion_queue = grpc_completion_queue_create(NULL)
self.is_shutting_down = False self.is_shutting_down = False
self.is_shutdown = False self.is_shutdown = False
self.poll_condition = threading.Condition() self.pluck_condition = threading.Condition()
self.is_polling = False self.num_plucking = 0
self.num_polling = 0
cdef _interpret_event(self, grpc_event event): cdef _interpret_event(self, grpc_event event):
cdef OperationTag tag = None cdef OperationTag tag = None
@ -87,19 +88,15 @@ cdef class CompletionQueue:
c_deadline = deadline.c_time c_deadline = deadline.c_time
cdef grpc_event event cdef grpc_event event
# Poll within a critical section # Poll within a critical section to detect contention
# TODO(atash) consider making queue polling contention a hard error to with self.pluck_condition:
# enable easier bug discovery assert self.num_plucking == 0, 'cannot simultaneously pluck and poll'
with self.poll_condition: self.num_polling += 1
while self.is_polling:
self.poll_condition.wait(float(deadline) - time.time())
self.is_polling = True
with nogil: with nogil:
event = grpc_completion_queue_next( event = grpc_completion_queue_next(
self.c_completion_queue, c_deadline, NULL) self.c_completion_queue, c_deadline, NULL)
with self.poll_condition: with self.pluck_condition:
self.is_polling = False self.num_polling -= 1
self.poll_condition.notify()
return self._interpret_event(event) return self._interpret_event(event)
def pluck(self, OperationTag tag, Timespec deadline=None): def pluck(self, OperationTag tag, Timespec deadline=None):
@ -111,19 +108,18 @@ cdef class CompletionQueue:
c_deadline = deadline.c_time c_deadline = deadline.c_time
cdef grpc_event event cdef grpc_event event
# Poll within a critical section # Pluck within a critical section to detect contention
# TODO(atash) consider making queue polling contention a hard error to with self.pluck_condition:
# enable easier bug discovery assert self.num_polling == 0, 'cannot simultaneously pluck and poll'
with self.poll_condition: assert self.num_plucking < GRPC_MAX_COMPLETION_QUEUE_PLUCKERS, (
while self.is_polling: 'cannot pluck more than {} times simultaneously'.format(
self.poll_condition.wait(float(deadline) - time.time()) GRPC_MAX_COMPLETION_QUEUE_PLUCKERS))
self.is_polling = True self.num_plucking += 1
with nogil: with nogil:
event = grpc_completion_queue_pluck( event = grpc_completion_queue_pluck(
self.c_completion_queue, <cpython.PyObject *>tag, c_deadline, NULL) self.c_completion_queue, <cpython.PyObject *>tag, c_deadline, NULL)
with self.poll_condition: with self.pluck_condition:
self.is_polling = False self.num_plucking -= 1
self.poll_condition.notify()
return self._interpret_event(event) return self._interpret_event(event)
def shutdown(self): def shutdown(self):
@ -137,10 +133,14 @@ cdef class CompletionQueue:
pass pass
def __dealloc__(self): def __dealloc__(self):
cdef gpr_timespec c_deadline = gpr_inf_future(GPR_CLOCK_REALTIME)
if self.c_completion_queue != NULL: if self.c_completion_queue != NULL:
# Ensure shutdown, pump the queue # Ensure shutdown
if not self.is_shutting_down: if not self.is_shutting_down:
self.shutdown() grpc_completion_queue_shutdown(self.c_completion_queue)
# Pump the queue
while not self.is_shutdown: while not self.is_shutdown:
self.poll() event = grpc_completion_queue_next(
self.c_completion_queue, c_deadline, NULL)
self._interpret_event(event)
grpc_completion_queue_destroy(self.c_completion_queue) grpc_completion_queue_destroy(self.c_completion_queue)

@ -138,6 +138,8 @@ cdef extern from "grpc/_cython/loader.h":
const int GRPC_WRITE_NO_COMPRESS const int GRPC_WRITE_NO_COMPRESS
const int GRPC_WRITE_USED_MASK const int GRPC_WRITE_USED_MASK
const int GRPC_MAX_COMPLETION_QUEUE_PLUCKERS
ctypedef struct grpc_completion_queue: ctypedef struct grpc_completion_queue:
# We don't care about the internals (and in fact don't know them) # We don't care about the internals (and in fact don't know them)
pass pass

@ -1,4 +1,4 @@
# Copyright 2015, Google Inc. # Copyright 2015-2016, Google Inc.
# All rights reserved. # All rights reserved.
# #
# Redistribution and use in source and binary forms, with or without # Redistribution and use in source and binary forms, with or without
@ -39,4 +39,5 @@ cdef class Server:
cdef list references cdef list references
cdef list registered_completion_queues cdef list registered_completion_queues
cdef _c_shutdown(self, CompletionQueue queue, tag)
cdef notify_shutdown_complete(self) cdef notify_shutdown_complete(self)

@ -1,4 +1,4 @@
# Copyright 2015, Google Inc. # Copyright 2015-2016, Google Inc.
# All rights reserved. # All rights reserved.
# #
# Redistribution and use in source and binary forms, with or without # Redistribution and use in source and binary forms, with or without
@ -102,6 +102,16 @@ cdef class Server:
else: else:
return grpc_server_add_insecure_http2_port(self.c_server, address) return grpc_server_add_insecure_http2_port(self.c_server, address)
cdef _c_shutdown(self, CompletionQueue queue, tag):
self.is_shutting_down = True
operation_tag = OperationTag(tag)
operation_tag.shutting_down_server = self
operation_tag.references.extend([self, queue])
cpython.Py_INCREF(operation_tag)
grpc_server_shutdown_and_notify(
self.c_server, queue.c_completion_queue,
<cpython.PyObject *>operation_tag)
def shutdown(self, CompletionQueue queue not None, tag): def shutdown(self, CompletionQueue queue not None, tag):
cdef OperationTag operation_tag cdef OperationTag operation_tag
if queue.is_shutting_down: if queue.is_shutting_down:
@ -113,14 +123,7 @@ cdef class Server:
elif queue not in self.registered_completion_queues: elif queue not in self.registered_completion_queues:
raise ValueError("expected registered completion queue") raise ValueError("expected registered completion queue")
else: else:
self.is_shutting_down = True self._c_shutdown(queue, tag)
operation_tag = OperationTag(tag)
operation_tag.shutting_down_server = self
operation_tag.references.extend([self, queue])
cpython.Py_INCREF(operation_tag)
grpc_server_shutdown_and_notify(
self.c_server, queue.c_completion_queue,
<cpython.PyObject *>operation_tag)
cdef notify_shutdown_complete(self): cdef notify_shutdown_complete(self):
# called only by a completion queue on receiving our shutdown operation tag # called only by a completion queue on receiving our shutdown operation tag
@ -142,7 +145,7 @@ cdef class Server:
pass pass
elif not self.is_shutting_down: elif not self.is_shutting_down:
# the user didn't call shutdown - use our backup queue # the user didn't call shutdown - use our backup queue
self.shutdown(self.backup_shutdown_queue, None) self._c_shutdown(self.backup_shutdown_queue, None)
# and now we wait # and now we wait
while not self.is_shutdown: while not self.is_shutdown:
self.backup_shutdown_queue.poll() self.backup_shutdown_queue.poll()

@ -220,6 +220,7 @@ gpr_event_get_type gpr_event_get_import;
gpr_event_wait_type gpr_event_wait_import; gpr_event_wait_type gpr_event_wait_import;
gpr_ref_init_type gpr_ref_init_import; gpr_ref_init_type gpr_ref_init_import;
gpr_ref_type gpr_ref_import; gpr_ref_type gpr_ref_import;
gpr_ref_non_zero_type gpr_ref_non_zero_import;
gpr_refn_type gpr_refn_import; gpr_refn_type gpr_refn_import;
gpr_unref_type gpr_unref_import; gpr_unref_type gpr_unref_import;
gpr_stats_init_type gpr_stats_init_import; gpr_stats_init_type gpr_stats_init_import;
@ -485,6 +486,7 @@ void pygrpc_load_imports(HMODULE library) {
gpr_event_wait_import = (gpr_event_wait_type) GetProcAddress(library, "gpr_event_wait"); gpr_event_wait_import = (gpr_event_wait_type) GetProcAddress(library, "gpr_event_wait");
gpr_ref_init_import = (gpr_ref_init_type) GetProcAddress(library, "gpr_ref_init"); gpr_ref_init_import = (gpr_ref_init_type) GetProcAddress(library, "gpr_ref_init");
gpr_ref_import = (gpr_ref_type) GetProcAddress(library, "gpr_ref"); gpr_ref_import = (gpr_ref_type) GetProcAddress(library, "gpr_ref");
gpr_ref_non_zero_import = (gpr_ref_non_zero_type) GetProcAddress(library, "gpr_ref_non_zero");
gpr_refn_import = (gpr_refn_type) GetProcAddress(library, "gpr_refn"); gpr_refn_import = (gpr_refn_type) GetProcAddress(library, "gpr_refn");
gpr_unref_import = (gpr_unref_type) GetProcAddress(library, "gpr_unref"); gpr_unref_import = (gpr_unref_type) GetProcAddress(library, "gpr_unref");
gpr_stats_init_import = (gpr_stats_init_type) GetProcAddress(library, "gpr_stats_init"); gpr_stats_init_import = (gpr_stats_init_type) GetProcAddress(library, "gpr_stats_init");

@ -91,10 +91,10 @@ extern census_context_next_tag_type census_context_next_tag_import;
typedef int(*census_context_get_tag_type)(const census_context *context, const char *key, census_tag *tag); typedef int(*census_context_get_tag_type)(const census_context *context, const char *key, census_tag *tag);
extern census_context_get_tag_type census_context_get_tag_import; extern census_context_get_tag_type census_context_get_tag_import;
#define census_context_get_tag census_context_get_tag_import #define census_context_get_tag census_context_get_tag_import
typedef char *(*census_context_encode_type)(const census_context *context, char *buffer, size_t buf_size, size_t *print_buf_size, size_t *bin_buf_size); typedef size_t(*census_context_encode_type)(const census_context *context, char *buffer, size_t buf_size);
extern census_context_encode_type census_context_encode_import; extern census_context_encode_type census_context_encode_import;
#define census_context_encode census_context_encode_import #define census_context_encode census_context_encode_import
typedef census_context *(*census_context_decode_type)(const char *buffer, size_t size, const char *bin_buffer, size_t bin_size); typedef census_context *(*census_context_decode_type)(const char *buffer, size_t size);
extern census_context_decode_type census_context_decode_import; extern census_context_decode_type census_context_decode_import;
#define census_context_decode census_context_decode_import #define census_context_decode census_context_decode_import
typedef int(*census_trace_mask_type)(const census_context *context); typedef int(*census_trace_mask_type)(const census_context *context);
@ -610,6 +610,9 @@ extern gpr_ref_init_type gpr_ref_init_import;
typedef void(*gpr_ref_type)(gpr_refcount *r); typedef void(*gpr_ref_type)(gpr_refcount *r);
extern gpr_ref_type gpr_ref_import; extern gpr_ref_type gpr_ref_import;
#define gpr_ref gpr_ref_import #define gpr_ref gpr_ref_import
typedef void(*gpr_ref_non_zero_type)(gpr_refcount *r);
extern gpr_ref_non_zero_type gpr_ref_non_zero_import;
#define gpr_ref_non_zero gpr_ref_non_zero_import
typedef void(*gpr_refn_type)(gpr_refcount *r, int n); typedef void(*gpr_refn_type)(gpr_refcount *r, int n);
extern gpr_refn_type gpr_refn_import; extern gpr_refn_type gpr_refn_import;
#define gpr_refn gpr_refn_import #define gpr_refn gpr_refn_import

@ -1,4 +1,4 @@
# Copyright 2015, Google Inc. # Copyright 2015-2016, Google Inc.
# All rights reserved. # All rights reserved.
# #
# Redistribution and use in source and binary forms, with or without # Redistribution and use in source and binary forms, with or without

@ -1,4 +1,4 @@
// Copyright 2015, Google Inc. // Copyright 2015-2016, Google Inc.
// All rights reserved. // All rights reserved.
// //
// Redistribution and use in source and binary forms, with or without // Redistribution and use in source and binary forms, with or without
@ -29,7 +29,7 @@
syntax = "proto3"; syntax = "proto3";
package grpc.health.v1alpha; package grpc.health.v1;
message HealthCheckRequest { message HealthCheckRequest {
string service = 1; string service = 1;

@ -1,4 +1,4 @@
# Copyright 2015, Google Inc. # Copyright 2015-2016, Google Inc.
# All rights reserved. # All rights reserved.
# #
# Redistribution and use in source and binary forms, with or without # Redistribution and use in source and binary forms, with or without
@ -33,7 +33,7 @@ import abc
import enum import enum
import threading import threading
from grpc.health.v1alpha import health_pb2 from grpc.health.v1 import health_pb2
@enum.unique @enum.unique
@ -64,7 +64,7 @@ class _HealthServicer(health_pb2.EarlyAdopterHealthServicer):
def set(service, status): def set(service, status):
if not isinstance(status, HealthStatus): if not isinstance(status, HealthStatus):
raise TypeError('expected grpc.health.v1alpha.health.HealthStatus ' raise TypeError('expected grpc.health.v1.health.HealthStatus '
'for argument `status` but got {}'.format(status)) 'for argument `status` but got {}'.format(status))
with self._server_status_lock: with self._server_status_lock:
self._server_status[service] = status self._server_status[service] = status

@ -7,7 +7,7 @@ AllCops:
- 'bin/apis/**/*' - 'bin/apis/**/*'
- 'bin/math.rb' - 'bin/math.rb'
- 'bin/math_services.rb' - 'bin/math_services.rb'
- 'pb/grpc/health/v1alpha/*' - 'pb/grpc/health/v1/*'
- 'pb/test/**/*' - 'pb/test/**/*'
Metrics/CyclomaticComplexity: Metrics/CyclomaticComplexity:

@ -220,6 +220,7 @@ gpr_event_get_type gpr_event_get_import;
gpr_event_wait_type gpr_event_wait_import; gpr_event_wait_type gpr_event_wait_import;
gpr_ref_init_type gpr_ref_init_import; gpr_ref_init_type gpr_ref_init_import;
gpr_ref_type gpr_ref_import; gpr_ref_type gpr_ref_import;
gpr_ref_non_zero_type gpr_ref_non_zero_import;
gpr_refn_type gpr_refn_import; gpr_refn_type gpr_refn_import;
gpr_unref_type gpr_unref_import; gpr_unref_type gpr_unref_import;
gpr_stats_init_type gpr_stats_init_import; gpr_stats_init_type gpr_stats_init_import;
@ -481,6 +482,7 @@ void grpc_rb_load_imports(HMODULE library) {
gpr_event_wait_import = (gpr_event_wait_type) GetProcAddress(library, "gpr_event_wait"); gpr_event_wait_import = (gpr_event_wait_type) GetProcAddress(library, "gpr_event_wait");
gpr_ref_init_import = (gpr_ref_init_type) GetProcAddress(library, "gpr_ref_init"); gpr_ref_init_import = (gpr_ref_init_type) GetProcAddress(library, "gpr_ref_init");
gpr_ref_import = (gpr_ref_type) GetProcAddress(library, "gpr_ref"); gpr_ref_import = (gpr_ref_type) GetProcAddress(library, "gpr_ref");
gpr_ref_non_zero_import = (gpr_ref_non_zero_type) GetProcAddress(library, "gpr_ref_non_zero");
gpr_refn_import = (gpr_refn_type) GetProcAddress(library, "gpr_refn"); gpr_refn_import = (gpr_refn_type) GetProcAddress(library, "gpr_refn");
gpr_unref_import = (gpr_unref_type) GetProcAddress(library, "gpr_unref"); gpr_unref_import = (gpr_unref_type) GetProcAddress(library, "gpr_unref");
gpr_stats_init_import = (gpr_stats_init_type) GetProcAddress(library, "gpr_stats_init"); gpr_stats_init_import = (gpr_stats_init_type) GetProcAddress(library, "gpr_stats_init");

@ -91,10 +91,10 @@ extern census_context_next_tag_type census_context_next_tag_import;
typedef int(*census_context_get_tag_type)(const census_context *context, const char *key, census_tag *tag); typedef int(*census_context_get_tag_type)(const census_context *context, const char *key, census_tag *tag);
extern census_context_get_tag_type census_context_get_tag_import; extern census_context_get_tag_type census_context_get_tag_import;
#define census_context_get_tag census_context_get_tag_import #define census_context_get_tag census_context_get_tag_import
typedef char *(*census_context_encode_type)(const census_context *context, char *buffer, size_t buf_size, size_t *print_buf_size, size_t *bin_buf_size); typedef size_t(*census_context_encode_type)(const census_context *context, char *buffer, size_t buf_size);
extern census_context_encode_type census_context_encode_import; extern census_context_encode_type census_context_encode_import;
#define census_context_encode census_context_encode_import #define census_context_encode census_context_encode_import
typedef census_context *(*census_context_decode_type)(const char *buffer, size_t size, const char *bin_buffer, size_t bin_size); typedef census_context *(*census_context_decode_type)(const char *buffer, size_t size);
extern census_context_decode_type census_context_decode_import; extern census_context_decode_type census_context_decode_import;
#define census_context_decode census_context_decode_import #define census_context_decode census_context_decode_import
typedef int(*census_trace_mask_type)(const census_context *context); typedef int(*census_trace_mask_type)(const census_context *context);
@ -610,6 +610,9 @@ extern gpr_ref_init_type gpr_ref_init_import;
typedef void(*gpr_ref_type)(gpr_refcount *r); typedef void(*gpr_ref_type)(gpr_refcount *r);
extern gpr_ref_type gpr_ref_import; extern gpr_ref_type gpr_ref_import;
#define gpr_ref gpr_ref_import #define gpr_ref gpr_ref_import
typedef void(*gpr_ref_non_zero_type)(gpr_refcount *r);
extern gpr_ref_non_zero_type gpr_ref_non_zero_import;
#define gpr_ref_non_zero gpr_ref_non_zero_import
typedef void(*gpr_refn_type)(gpr_refcount *r, int n); typedef void(*gpr_refn_type)(gpr_refcount *r, int n);
extern gpr_refn_type gpr_refn_import; extern gpr_refn_type gpr_refn_import;
#define gpr_refn gpr_refn_import #define gpr_refn gpr_refn_import

@ -11,7 +11,7 @@ The code is is generated using the protoc (> 3.0.0.alpha.1) and the
grpc_ruby_plugin. These must be installed to regenerate the IDL defined grpc_ruby_plugin. These must be installed to regenerate the IDL defined
classes, but that's not necessary just to use them. classes, but that's not necessary just to use them.
health_check/v1alpha health_check/v1
-------------------- --------------------
This package defines the surface of a simple health check service that gRPC This package defines the surface of a simple health check service that gRPC
@ -20,7 +20,7 @@ re-generate the surface.
```bash ```bash
$ # (from this directory) $ # (from this directory)
$ protoc -I ../../proto ../../proto/grpc/health/v1alpha/health.proto \ $ protoc -I ../../proto ../../proto/grpc/health/v1/health.proto \
--grpc_out=. \ --grpc_out=. \
--ruby_out=. \ --ruby_out=. \
--plugin=protoc-gen-grpc=`which grpc_ruby_plugin` --plugin=protoc-gen-grpc=`which grpc_ruby_plugin`

@ -1,5 +1,5 @@
#!/bin/sh #!/bin/sh
# Copyright 2015, Google Inc. # Copyright 2015-2016, Google Inc.
# All rights reserved. # All rights reserved.
# #
# Redistribution and use in source and binary forms, with or without # Redistribution and use in source and binary forms, with or without
@ -35,7 +35,7 @@ cd $(dirname $0)/../../..
PROTOC=bins/opt/protobuf/protoc PROTOC=bins/opt/protobuf/protoc
PLUGIN=protoc-gen-grpc=bins/opt/grpc_ruby_plugin PLUGIN=protoc-gen-grpc=bins/opt/grpc_ruby_plugin
$PROTOC -I src/proto src/proto/grpc/health/v1alpha/health.proto \ $PROTOC -I src/proto src/proto/grpc/health/v1/health.proto \
--grpc_out=src/ruby/pb \ --grpc_out=src/ruby/pb \
--ruby_out=src/ruby/pb \ --ruby_out=src/ruby/pb \
--plugin=$PLUGIN --plugin=$PLUGIN

@ -1,4 +1,4 @@
# Copyright 2015, Google Inc. # Copyright 2015-2016, Google Inc.
# All rights reserved. # All rights reserved.
# #
# Redistribution and use in source and binary forms, with or without # Redistribution and use in source and binary forms, with or without
@ -28,7 +28,7 @@
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
require 'grpc' require 'grpc'
require 'grpc/health/v1alpha/health_services' require 'grpc/health/v1/health_services'
require 'thread' require 'thread'
module Grpc module Grpc
@ -36,9 +36,9 @@ module Grpc
# service. # service.
module Health module Health
# Checker is implementation of the schema-specified health checking service. # Checker is implementation of the schema-specified health checking service.
class Checker < V1alpha::Health::Service class Checker < V1::Health::Service
StatusCodes = GRPC::Core::StatusCodes StatusCodes = GRPC::Core::StatusCodes
HealthCheckResponse = V1alpha::HealthCheckResponse HealthCheckResponse = V1::HealthCheckResponse
# Initializes the statuses of participating services # Initializes the statuses of participating services
def initialize def initialize
@ -50,20 +50,20 @@ module Grpc
def check(req, _call) def check(req, _call)
status = nil status = nil
@status_mutex.synchronize do @status_mutex.synchronize do
status = @statuses["#{req.host}/#{req.service}"] status = @statuses["#{req.service}"]
end end
fail GRPC::BadStatus, StatusCodes::NOT_FOUND if status.nil? fail GRPC::BadStatus, StatusCodes::NOT_FOUND if status.nil?
HealthCheckResponse.new(status: status) HealthCheckResponse.new(status: status)
end end
# Adds the health status for a given host and service. # Adds the health status for a given service.
def add_status(host, service, status) def add_status(service, status)
@status_mutex.synchronize { @statuses["#{host}/#{service}"] = status } @status_mutex.synchronize { @statuses["#{service}"] = status }
end end
# Clears the status for the given host or service. # Clears the status for the given service.
def clear_status(host, service) def clear_status(service)
@status_mutex.synchronize { @statuses.delete("#{host}/#{service}") } @status_mutex.synchronize { @statuses.delete("#{service}") }
end end
# Clears alls the statuses. # Clears alls the statuses.

@ -0,0 +1,28 @@
# Generated by the protocol buffer compiler. DO NOT EDIT!
# source: grpc/health/v1/health.proto
require 'google/protobuf'
Google::Protobuf::DescriptorPool.generated_pool.build do
add_message "grpc.health.v1.HealthCheckRequest" do
optional :service, :string, 1
end
add_message "grpc.health.v1.HealthCheckResponse" do
optional :status, :enum, 1, "grpc.health.v1.HealthCheckResponse.ServingStatus"
end
add_enum "grpc.health.v1.HealthCheckResponse.ServingStatus" do
value :UNKNOWN, 0
value :SERVING, 1
value :NOT_SERVING, 2
end
end
module Grpc
module Health
module V1
HealthCheckRequest = Google::Protobuf::DescriptorPool.generated_pool.lookup("grpc.health.v1.HealthCheckRequest").msgclass
HealthCheckResponse = Google::Protobuf::DescriptorPool.generated_pool.lookup("grpc.health.v1.HealthCheckResponse").msgclass
HealthCheckResponse::ServingStatus = Google::Protobuf::DescriptorPool.generated_pool.lookup("grpc.health.v1.HealthCheckResponse.ServingStatus").enummodule
end
end
end

@ -1,12 +1,12 @@
# Generated by the protocol buffer compiler. DO NOT EDIT! # Generated by the protocol buffer compiler. DO NOT EDIT!
# Source: grpc/health/v1alpha/health.proto for package 'grpc.health.v1alpha' # Source: grpc/health/v1/health.proto for package 'grpc.health.v1'
require 'grpc' require 'grpc'
require 'grpc/health/v1alpha/health' require 'grpc/health/v1/health'
module Grpc module Grpc
module Health module Health
module V1alpha module V1
module Health module Health
# TODO: add proto service documentation here # TODO: add proto service documentation here
@ -16,7 +16,7 @@ module Grpc
self.marshal_class_method = :encode self.marshal_class_method = :encode
self.unmarshal_class_method = :decode self.unmarshal_class_method = :decode
self.service_name = 'grpc.health.v1alpha.Health' self.service_name = 'grpc.health.v1.Health'
rpc :Check, HealthCheckRequest, HealthCheckResponse rpc :Check, HealthCheckRequest, HealthCheckResponse
end end

@ -1,29 +0,0 @@
# Generated by the protocol buffer compiler. DO NOT EDIT!
# source: grpc/health/v1alpha/health.proto
require 'google/protobuf'
Google::Protobuf::DescriptorPool.generated_pool.build do
add_message "grpc.health.v1alpha.HealthCheckRequest" do
optional :host, :string, 1
optional :service, :string, 2
end
add_message "grpc.health.v1alpha.HealthCheckResponse" do
optional :status, :enum, 1, "grpc.health.v1alpha.HealthCheckResponse.ServingStatus"
end
add_enum "grpc.health.v1alpha.HealthCheckResponse.ServingStatus" do
value :UNKNOWN, 0
value :SERVING, 1
value :NOT_SERVING, 2
end
end
module Grpc
module Health
module V1alpha
HealthCheckRequest = Google::Protobuf::DescriptorPool.generated_pool.lookup("grpc.health.v1alpha.HealthCheckRequest").msgclass
HealthCheckResponse = Google::Protobuf::DescriptorPool.generated_pool.lookup("grpc.health.v1alpha.HealthCheckResponse").msgclass
HealthCheckResponse::ServingStatus = Google::Protobuf::DescriptorPool.generated_pool.lookup("grpc.health.v1alpha.HealthCheckResponse.ServingStatus").enummodule
end
end
end

@ -28,7 +28,7 @@
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
require 'grpc' require 'grpc'
require 'grpc/health/v1alpha/health' require 'grpc/health/v1/health'
require 'grpc/health/checker' require 'grpc/health/checker'
require 'open3' require 'open3'
require 'tmpdir' require 'tmpdir'
@ -43,7 +43,7 @@ describe 'Health protobuf code generation' do
skip 'protoc || grpc_ruby_plugin missing, cannot verify health code-gen' skip 'protoc || grpc_ruby_plugin missing, cannot verify health code-gen'
else else
it 'should already be loaded indirectly i.e, used by the other specs' do it 'should already be loaded indirectly i.e, used by the other specs' do
expect(require('grpc/health/v1alpha/health_services')).to be(false) expect(require('grpc/health/v1/health_services')).to be(false)
end end
it 'should have the same content as created by code generation' do it 'should have the same content as created by code generation' do
@ -52,7 +52,7 @@ describe 'Health protobuf code generation' do
# Get the current content # Get the current content
service_path = File.join(root_dir, 'ruby', 'pb', 'grpc', service_path = File.join(root_dir, 'ruby', 'pb', 'grpc',
'health', 'v1alpha', 'health_services.rb') 'health', 'v1', 'health_services.rb')
want = nil want = nil
File.open(service_path) { |f| want = f.read } File.open(service_path) { |f| want = f.read }
@ -61,12 +61,12 @@ describe 'Health protobuf code generation' do
plugin = plugin.strip plugin = plugin.strip
got = nil got = nil
Dir.mktmpdir do |tmp_dir| Dir.mktmpdir do |tmp_dir|
gen_out = File.join(tmp_dir, 'grpc', 'health', 'v1alpha', gen_out = File.join(tmp_dir, 'grpc', 'health', 'v1',
'health_services.rb') 'health_services.rb')
pid = spawn( pid = spawn(
'protoc', 'protoc',
'-I.', '-I.',
'grpc/health/v1alpha/health.proto', 'grpc/health/v1/health.proto',
"--grpc_out=#{tmp_dir}", "--grpc_out=#{tmp_dir}",
"--plugin=protoc-gen-grpc=#{plugin}", "--plugin=protoc-gen-grpc=#{plugin}",
chdir: pb_dir) chdir: pb_dir)
@ -81,27 +81,17 @@ end
describe Grpc::Health::Checker do describe Grpc::Health::Checker do
StatusCodes = GRPC::Core::StatusCodes StatusCodes = GRPC::Core::StatusCodes
ServingStatus = Grpc::Health::V1alpha::HealthCheckResponse::ServingStatus ServingStatus = Grpc::Health::V1::HealthCheckResponse::ServingStatus
HCResp = Grpc::Health::V1alpha::HealthCheckResponse HCResp = Grpc::Health::V1::HealthCheckResponse
HCReq = Grpc::Health::V1alpha::HealthCheckRequest HCReq = Grpc::Health::V1::HealthCheckRequest
success_tests = success_tests =
[ [
{ {
desc: 'neither host or service are specified', desc: 'the service is not specified',
host: '',
service: '' service: ''
}, { }, {
desc: 'only the host is specified', desc: 'the service is specified',
host: 'test-fake-host',
service: ''
}, {
desc: 'the host and service are specified',
host: 'test-fake-host',
service: 'fake-service-1' service: 'fake-service-1'
}, {
desc: 'only the service is specified',
host: '',
service: 'fake-service-2'
} }
] ]
@ -114,9 +104,8 @@ describe Grpc::Health::Checker do
context 'method `add_status` and `check`' do context 'method `add_status` and `check`' do
success_tests.each do |t| success_tests.each do |t|
it "should succeed when #{t[:desc]}" do it "should succeed when #{t[:desc]}" do
subject.add_status(t[:host], t[:service], ServingStatus::NOT_SERVING) subject.add_status(t[:service], ServingStatus::NOT_SERVING)
got = subject.check(HCReq.new(host: t[:host], service: t[:service]), got = subject.check(HCReq.new(service: t[:service]), nil)
nil)
want = HCResp.new(status: ServingStatus::NOT_SERVING) want = HCResp.new(status: ServingStatus::NOT_SERVING)
expect(got).to eq(want) expect(got).to eq(want)
end end
@ -127,7 +116,7 @@ describe Grpc::Health::Checker do
success_tests.each do |t| success_tests.each do |t|
it "should fail with NOT_FOUND when #{t[:desc]}" do it "should fail with NOT_FOUND when #{t[:desc]}" do
blk = proc do blk = proc do
subject.check(HCReq.new(host: t[:host], service: t[:service]), nil) subject.check(HCReq.new(service: t[:service]), nil)
end end
expected_msg = /#{StatusCodes::NOT_FOUND}/ expected_msg = /#{StatusCodes::NOT_FOUND}/
expect(&blk).to raise_error GRPC::BadStatus, expected_msg expect(&blk).to raise_error GRPC::BadStatus, expected_msg
@ -138,16 +127,14 @@ describe Grpc::Health::Checker do
context 'method `clear_status`' do context 'method `clear_status`' do
success_tests.each do |t| success_tests.each do |t|
it "should fail after clearing status when #{t[:desc]}" do it "should fail after clearing status when #{t[:desc]}" do
subject.add_status(t[:host], t[:service], ServingStatus::NOT_SERVING) subject.add_status(t[:service], ServingStatus::NOT_SERVING)
got = subject.check(HCReq.new(host: t[:host], service: t[:service]), got = subject.check(HCReq.new(service: t[:service]), nil)
nil)
want = HCResp.new(status: ServingStatus::NOT_SERVING) want = HCResp.new(status: ServingStatus::NOT_SERVING)
expect(got).to eq(want) expect(got).to eq(want)
subject.clear_status(t[:host], t[:service]) subject.clear_status(t[:service])
blk = proc do blk = proc do
subject.check(HCReq.new(host: t[:host], service: t[:service]), subject.check(HCReq.new(service: t[:service]), nil)
nil)
end end
expected_msg = /#{StatusCodes::NOT_FOUND}/ expected_msg = /#{StatusCodes::NOT_FOUND}/
expect(&blk).to raise_error GRPC::BadStatus, expected_msg expect(&blk).to raise_error GRPC::BadStatus, expected_msg
@ -158,9 +145,8 @@ describe Grpc::Health::Checker do
context 'method `clear_all`' do context 'method `clear_all`' do
it 'should return NOT_FOUND after being invoked' do it 'should return NOT_FOUND after being invoked' do
success_tests.each do |t| success_tests.each do |t|
subject.add_status(t[:host], t[:service], ServingStatus::NOT_SERVING) subject.add_status(t[:service], ServingStatus::NOT_SERVING)
got = subject.check(HCReq.new(host: t[:host], service: t[:service]), got = subject.check(HCReq.new(service: t[:service]), nil)
nil)
want = HCResp.new(status: ServingStatus::NOT_SERVING) want = HCResp.new(status: ServingStatus::NOT_SERVING)
expect(got).to eq(want) expect(got).to eq(want)
end end
@ -169,7 +155,7 @@ describe Grpc::Health::Checker do
success_tests.each do |t| success_tests.each do |t|
blk = proc do blk = proc do
subject.check(HCReq.new(host: t[:host], service: t[:service]), nil) subject.check(HCReq.new(service: t[:service]), nil)
end end
expected_msg = /#{StatusCodes::NOT_FOUND}/ expected_msg = /#{StatusCodes::NOT_FOUND}/
expect(&blk).to raise_error GRPC::BadStatus, expected_msg expect(&blk).to raise_error GRPC::BadStatus, expected_msg
@ -203,7 +189,7 @@ describe Grpc::Health::Checker do
it 'should receive the correct status', server: true do it 'should receive the correct status', server: true do
@srv.handle(subject) @srv.handle(subject)
subject.add_status('', '', ServingStatus::NOT_SERVING) subject.add_status('', ServingStatus::NOT_SERVING)
t = Thread.new { @srv.run } t = Thread.new { @srv.run }
@srv.wait_till_running @srv.wait_till_running
@ -221,7 +207,7 @@ describe Grpc::Health::Checker do
@srv.wait_till_running @srv.wait_till_running
blk = proc do blk = proc do
stub = CheckerStub.new(@host, :this_channel_is_insecure, **@client_opts) stub = CheckerStub.new(@host, :this_channel_is_insecure, **@client_opts)
stub.check(HCReq.new(host: 'unknown', service: 'unknown')) stub.check(HCReq.new(service: 'unknown'))
end end
expected_msg = /#{StatusCodes::NOT_FOUND}/ expected_msg = /#{StatusCodes::NOT_FOUND}/
expect(&blk).to raise_error GRPC::BadStatus, expected_msg expect(&blk).to raise_error GRPC::BadStatus, expected_msg

@ -6,78 +6,92 @@ was going to single handedly cover all of our usage cases.
So instead we decided to work the following way: So instead we decided to work the following way:
* A build.json file at the root is the source of truth for listing all of the * A `build.yaml` file at the root is the source of truth for listing all the
target and files needed to build grpc and its tests, as well as basic system targets and files needed to build grpc and its tests, as well as a basic system
dependencies description. for dependency description.
* Each project file (Makefile, Visual Studio project files, Bazel's BUILD) is * Each project file (Makefile, Visual Studio project files, Bazel's BUILD) is
a plain-text template that uses the build.json file to generate the final a [YAML](http://yaml.org) file used by the `build.yaml` file to generate the
output file. final output file.
This way we can maintain as many project system as we see fit, without having This way we can maintain as many project system as we see fit, without having
to manually maintain them when we add or remove new code to the repository. to manually maintain them when we add or remove new code to the repository.
Only the structure of the project file is relevant to the template. The actual Only the structure of the project file is relevant to the template. The actual
list of source code and targets isn't. list of source code and targets isn't.
We currently have template files for GNU Make, Visual Studio 2010 to 2015, We currently have template files for GNU Make, Visual Studio 2013,
and Bazel. In the future, we would like to expand to generating gyp or cmake [Bazel](http://bazel.io) and [gyp](https://gyp.gsrc.io/) (albeit only for
project files (or potentially both), XCode project files, and an Android.mk Node.js). In the future, we
file to be able to compile gRPC using Android's NDK. would like to expand to also generate [cmake](https://cmake.org)
project files, XCode project files, and an Android.mk file allowing to compile
gRPC using Android's NDK.
We'll gladly accept contribution that'd create additional project files We'll gladly accept contribution that'd create additional project files
using that system. using that system.
# Structure of build.json # Structure of `build.yaml`
The build.json file has the following structure: The `build.yaml` file has the following structure:
``` ```
{ settings: # global settings, such as version number
"settings": { ... }, # global settings, such as version number ...
"filegroups": [ ... ], # groups of file that is automatically expanded filegroups: # groups of files that are automatically expanded
"libs": [ ... ], # list of libraries to build ...
"targets": [ ... ], # list of targets to build libs: # list of libraries to build
} ...
target: # list of targets to build
...
``` ```
The `filegroups` are helpful to re-use a subset of files in multiple targets. The `filegroups` are helpful to re-use a subset of files in multiple targets.
One `filegroups` entry has the following structure: One `filegroups` entry has the following structure:
``` ```
{ - name: "arbitrary string", # the name of the filegroup
"name": "arbitrary string", # the name of the filegroup public_headers: # list of public headers defined in that filegroup
"public_headers": [ ... ], # list of public headers defined in that filegroup - ...
"headers": [ ... ], # list of headers defined in that filegroup headers: # list of headers defined in that filegroup
"src": [ ... ], # list of source files defined in that filegroup - ...
} src: # list of source files defined in that filegroup
- ...
``` ```
The `libs` array contains the list of all the libraries we describe. Some may be The `libs` collection contains the list of all the libraries we describe. Some may be
helper libraries for the tests. Some may be installable libraries. Some may be helper libraries for the tests. Some may be installable libraries. Some may be
helper libraries for installable binaries. helper libraries for installable binaries.
The `targets` array contains the list of all the binary targets we describe. Some may The `targets` array contains the list of all the binary targets we describe. Some may
be installable binaries. be installable binaries.
One `libs` or `targets` entry has the following structure: One `libs` or `targets` entry has the following structure (see below for
details):
``` ```
{ name: "arbitrary string", # the name of the library
"name": "arbitrary string", # the name of the library build: "build type", # in which situation we want that library to be
"build": "build type", # in which situation we want that library to be # built and potentially installed (see below).
# built and potentially installed language: "...", # the language tag; "c" or "c++"
"language": "...", # the language tag; "c" or "c++" public_headers: # list of public headers to install
"public_headers": [ ... ], # list of public headers to install headers: # list of headers used by that target
"headers": [ ... ], # list of headers used by that target src: # list of files to compile
"src": [ ... ], # list of files to compile secure: boolean, # see below
"secure": "...", # "yes", "no" or "check" baselib: boolean, # this is a low level library that has system
"baselib": boolean, # this is a low level library that has system # dependencies
# dependencies vs_project_guid: '{...}', # Visual Studio's unique guid for that project
"vs_project_guid: "...", # Visual Studio's unique guid for that project filegroups: # list of filegroups to merge to that project
"filegroups": [ ... ], # list of filegroups to merge to that project # note that this will be expanded automatically
# note that this will be expanded automatically deps: # list of libraries this target depends on
"deps": [ ... ], # list of libraries this target depends on deps_linkage: "..." # "static" or "dynamic". Used by the Makefile only to
} # determine the way dependencies are linkned. Defaults
# to "dynamic".
dll: "..." # see below.
dll_def: "..." # Visual Studio's dll definition file.
vs_props: # List of property sheets to attach to that project.
vs_config_type: "..." # DynamicLibrary/StaticLibrary. Used only when
# creating a library. Specifies if we're building a
# static library or a dll. Use in conjunction with `dll_def`.
vs_packages: # List of nuget packages this project depends on.
``` ```
## The `"build"` tag ## The `"build"` tag
@ -86,8 +100,9 @@ Currently, the "`build`" tag have these meanings:
* `"all"`: library to build on `"make all"`, and install on the system. * `"all"`: library to build on `"make all"`, and install on the system.
* `"protoc"`: a protoc plugin to build on `"make all"` and install on the system. * `"protoc"`: a protoc plugin to build on `"make all"` and install on the system.
* `"priviate"`: a library to only build for tests. * `"private"`: a library to only build for tests.
* `"test"`: a test binary to run on `"make test"`. * `"test"`: a test binary to run on `"make test"`.
* `"tool"`: a binary to be built upon `"make tools"`.
All of the targets should always be present in the generated project file, if All of the targets should always be present in the generated project file, if
possible and applicable. But the build tag is what should group the targets possible and applicable. But the build tag is what should group the targets
@ -111,6 +126,18 @@ should merge OpenSSL, protobuf or zlib inside that library. That effect depends
on the `"language"` tag. OpenSSL and zlib are for `"c"` libraries, while on the `"language"` tag. OpenSSL and zlib are for `"c"` libraries, while
protobuf is for `"c++"` ones. protobuf is for `"c++"` ones.
## The `"dll"` tag
Used only by Visual Studio's project files. "true" means the project will be
built with both static and dynamic runtimes. "false" means it'll only be built
with static runtime. "only" means it'll only be built with the dll runtime.
## The `"dll_def"` tag
Specifies the visual studio's dll definition file. When creating a DLL, you
sometimes (not always) need a def file (see grpc.def).
# The template system # The template system
We're currently using the [mako templates](http://www.makotemplates.org/) We're currently using the [mako templates](http://www.makotemplates.org/)

@ -38,7 +38,8 @@
% endfor % endfor
% endif % endif
% endfor % endfor
, $ext_shared, , -Wall -Werror -std=c11 ${"\\"} , $ext_shared, , -Wall -Werror ${"\\"}
-Wno-parentheses-equality -Wno-unused-value -std=c11 ${"\\"}
-fvisibility=hidden -DOPENSSL_NO_ASM -D_GNU_SOURCE -DWIN32_LEAN_AND_MEAN ${"\\"} -fvisibility=hidden -DOPENSSL_NO_ASM -D_GNU_SOURCE -DWIN32_LEAN_AND_MEAN ${"\\"}
-D_HAS_EXCEPTIONS=0 -DNOMINMAX) -D_HAS_EXCEPTIONS=0 -DNOMINMAX)

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save