diff options
author | Craig Tiller <ctiller@google.com> | 2015-04-20 09:04:57 -0700 |
---|---|---|
committer | Craig Tiller <ctiller@google.com> | 2015-04-20 09:04:57 -0700 |
commit | c8a2299fe88a2e9325e07e6a8579bdb07b85b349 (patch) | |
tree | 3298194be904f974fcbb64b1f155332c350b3725 /src/ruby | |
parent | 9c9d4e0cd9025f3ff7aaf7cacfd2e24dfd6aa58e (diff) | |
parent | b572fcba35fd66cce102b29389a5892d3d45e651 (diff) |
Merge github.com:grpc/grpc into batch-metadata
Diffstat (limited to 'src/ruby')
-rw-r--r-- | src/ruby/.rubocop_todo.yml | 8 | ||||
-rwxr-xr-x | src/ruby/bin/interop/interop_server.rb | 2 | ||||
-rwxr-xr-x | src/ruby/bin/math_server.rb | 2 | ||||
-rwxr-xr-x | src/ruby/bin/noproto_server.rb | 2 | ||||
-rw-r--r-- | src/ruby/ext/grpc/rb_call.c | 50 | ||||
-rw-r--r-- | src/ruby/ext/grpc/rb_channel.c | 22 | ||||
-rw-r--r-- | src/ruby/ext/grpc/rb_channel_args.c | 15 | ||||
-rw-r--r-- | src/ruby/ext/grpc/rb_completion_queue.c | 31 | ||||
-rw-r--r-- | src/ruby/ext/grpc/rb_credentials.c | 47 | ||||
-rw-r--r-- | src/ruby/ext/grpc/rb_grpc.c | 46 | ||||
-rw-r--r-- | src/ruby/ext/grpc/rb_grpc.h | 8 | ||||
-rw-r--r-- | src/ruby/ext/grpc/rb_server.c | 33 | ||||
-rw-r--r-- | src/ruby/ext/grpc/rb_server_credentials.c | 24 | ||||
-rwxr-xr-x | src/ruby/grpc.gemspec | 6 | ||||
-rw-r--r-- | src/ruby/lib/grpc/generic/client_stub.rb | 1 | ||||
-rw-r--r-- | src/ruby/lib/grpc/generic/rpc_server.rb | 75 | ||||
-rw-r--r-- | src/ruby/spec/credentials_spec.rb | 4 | ||||
-rw-r--r-- | src/ruby/spec/generic/client_stub_spec.rb | 1 | ||||
-rw-r--r-- | src/ruby/spec/generic/rpc_server_pool_spec.rb | 1 | ||||
-rw-r--r-- | src/ruby/spec/generic/rpc_server_spec.rb | 1 |
20 files changed, 271 insertions, 108 deletions
diff --git a/src/ruby/.rubocop_todo.yml b/src/ruby/.rubocop_todo.yml index b4d66c517c..02136a81a9 100644 --- a/src/ruby/.rubocop_todo.yml +++ b/src/ruby/.rubocop_todo.yml @@ -1,18 +1,18 @@ # This configuration was generated by `rubocop --auto-gen-config` -# on 2015-04-15 18:43:23 -0700 using RuboCop version 0.30.0. +# on 2015-04-16 12:30:09 -0700 using RuboCop version 0.30.0. # The point is for the user to remove these configuration records # one by one as the offenses are removed from the code base. # Note that changes in the inspected code, or installation of new # versions of RuboCop, may require this file to be generated again. -# Offense count: 32 +# Offense count: 34 Metrics/AbcSize: Max: 36 # Offense count: 3 # Configuration parameters: CountComments. Metrics/ClassLength: - Max: 183 + Max: 185 # Offense count: 35 # Configuration parameters: CountComments. @@ -24,7 +24,7 @@ Metrics/MethodLength: Metrics/ParameterLists: Max: 8 -# Offense count: 6 +# Offense count: 9 # Configuration parameters: AllowedVariables. Style/GlobalVars: Enabled: false diff --git a/src/ruby/bin/interop/interop_server.rb b/src/ruby/bin/interop/interop_server.rb index 0819ba9bbc..72570d92f3 100755 --- a/src/ruby/bin/interop/interop_server.rb +++ b/src/ruby/bin/interop/interop_server.rb @@ -185,7 +185,7 @@ def main logger.info("... running insecurely on #{host}") end s.handle(TestTarget) - s.run + s.run_till_terminated end main diff --git a/src/ruby/bin/math_server.rb b/src/ruby/bin/math_server.rb index 5cc7613489..1bfe253b85 100755 --- a/src/ruby/bin/math_server.rb +++ b/src/ruby/bin/math_server.rb @@ -183,7 +183,7 @@ def main end s.handle(Calculator) - s.run + s.run_till_terminated end main diff --git a/src/ruby/bin/noproto_server.rb b/src/ruby/bin/noproto_server.rb index 9979cb7ebb..f71daeadb3 100755 --- a/src/ruby/bin/noproto_server.rb +++ b/src/ruby/bin/noproto_server.rb @@ -105,7 +105,7 @@ def main end s.handle(NoProto) - s.run + s.run_till_terminated end main diff --git a/src/ruby/ext/grpc/rb_call.c b/src/ruby/ext/grpc/rb_call.c index b0963411d1..6da7d3c830 100644 --- a/src/ruby/ext/grpc/rb_call.c +++ b/src/ruby/ext/grpc/rb_call.c @@ -117,6 +117,37 @@ static void grpc_rb_call_destroy(void *p) { } } +static size_t md_ary_datasize(const void *p) { + const grpc_metadata_array* const ary = (grpc_metadata_array*)p; + size_t i, datasize = sizeof(grpc_metadata_array); + for (i = 0; i < ary->count; ++i) { + const grpc_metadata* const md = &ary->metadata[i]; + datasize += strlen(md->key); + datasize += md->value_length; + } + datasize += ary->capacity * sizeof(grpc_metadata); + return datasize; +} + +static const rb_data_type_t grpc_rb_md_ary_data_type = { + "grpc_metadata_array", + {GRPC_RB_GC_NOT_MARKED, GRPC_RB_GC_DONT_FREE, md_ary_datasize}, + NULL, NULL, + 0 +}; + +/* Describes grpc_call struct for RTypedData */ +static const rb_data_type_t grpc_call_data_type = { + "grpc_call", + {GRPC_RB_GC_NOT_MARKED, grpc_rb_call_destroy, GRPC_RB_MEMSIZE_UNAVAILABLE}, + NULL, NULL, + /* it is unsafe to specify RUBY_TYPED_FREE_IMMEDIATELY because grpc_rb_call_destroy + * touches a hash object. + * TODO(yugui) Directly use st_table and call the free function earlier? + */ + 0 +}; + /* Error code details is a hash containing text strings describing errors */ VALUE rb_error_code_details; @@ -135,7 +166,7 @@ const char *grpc_call_error_detail_of(grpc_call_error err) { static VALUE grpc_rb_call_cancel(VALUE self) { grpc_call *call = NULL; grpc_call_error err; - Data_Get_Struct(self, grpc_call, call); + TypedData_Get_Struct(self, grpc_call, &grpc_call_data_type, call); err = grpc_call_cancel(call); if (err != GRPC_CALL_OK) { rb_raise(grpc_rb_eCallError, "cancel failed: %s (code=%d)", @@ -205,7 +236,8 @@ static int grpc_rb_md_ary_fill_hash_cb(VALUE key, VALUE val, VALUE md_ary_obj) { int i; /* Construct a metadata object from key and value and add it */ - Data_Get_Struct(md_ary_obj, grpc_metadata_array, md_ary); + TypedData_Get_Struct(md_ary_obj, grpc_metadata_array, + &grpc_rb_md_ary_data_type, md_ary); if (TYPE(val) == T_ARRAY) { /* If the value is an array, add capacity for each value in the array */ @@ -243,7 +275,8 @@ static int grpc_rb_md_ary_capacity_hash_cb(VALUE key, VALUE val, grpc_metadata_array *md_ary = NULL; /* Construct a metadata object from key and value and add it */ - Data_Get_Struct(md_ary_obj, grpc_metadata_array, md_ary); + TypedData_Get_Struct(md_ary_obj, grpc_metadata_array, + &grpc_rb_md_ary_data_type, md_ary); if (TYPE(val) == T_ARRAY) { /* If the value is an array, add capacity for each value in the array */ @@ -270,8 +303,8 @@ static void grpc_rb_md_ary_convert(VALUE md_ary_hash, grpc_metadata_array *md_ar /* Initialize the array, compute it's capacity, then fill it. */ grpc_metadata_array_init(md_ary); - md_ary_obj = - Data_Wrap_Struct(grpc_rb_cMdAry, GC_NOT_MARKED, GC_DONT_FREE, md_ary); + md_ary_obj = TypedData_Wrap_Struct(grpc_rb_cMdAry, &grpc_rb_md_ary_data_type, + md_ary); rb_hash_foreach(md_ary_hash, grpc_rb_md_ary_capacity_hash_cb, md_ary_obj); md_ary->metadata = gpr_malloc(md_ary->capacity * sizeof(grpc_metadata)); rb_hash_foreach(md_ary_hash, grpc_rb_md_ary_fill_hash_cb, md_ary_obj); @@ -556,7 +589,7 @@ static VALUE grpc_rb_call_run_batch(VALUE self, VALUE cqueue, VALUE tag, grpc_event *ev = NULL; grpc_call_error err; VALUE result = Qnil; - Data_Get_Struct(self, grpc_call, call); + TypedData_Get_Struct(self, grpc_call, &grpc_call_data_type, call); /* Validate the ops args, adding them to a ruby array */ if (TYPE(ops_hash) != T_HASH) { @@ -736,7 +769,7 @@ void Init_grpc_call() { /* Gets the call from the ruby object */ grpc_call *grpc_rb_get_wrapped_call(VALUE v) { grpc_call *c = NULL; - Data_Get_Struct(v, grpc_call, c); + TypedData_Get_Struct(v, grpc_call, &grpc_call_data_type, c); return c; } @@ -753,6 +786,5 @@ VALUE grpc_rb_wrap_call(grpc_call *c) { rb_hash_aset(hash_all_calls, OFFT2NUM((VALUE)c), UINT2NUM(NUM2UINT(obj) + 1)); } - return Data_Wrap_Struct(grpc_rb_cCall, GC_NOT_MARKED, - grpc_rb_call_destroy, c); + return TypedData_Wrap_Struct(grpc_rb_cCall, &grpc_call_data_type, c); } diff --git a/src/ruby/ext/grpc/rb_channel.c b/src/ruby/ext/grpc/rb_channel.c index 9bd7c2edf9..214675af92 100644 --- a/src/ruby/ext/grpc/rb_channel.c +++ b/src/ruby/ext/grpc/rb_channel.c @@ -105,13 +105,19 @@ static void grpc_rb_channel_mark(void *p) { } } +static rb_data_type_t grpc_channel_data_type = { + "grpc_channel", + {grpc_rb_channel_mark, grpc_rb_channel_free, GRPC_RB_MEMSIZE_UNAVAILABLE}, + NULL, NULL, + RUBY_TYPED_FREE_IMMEDIATELY +}; + /* Allocates grpc_rb_channel instances. */ static VALUE grpc_rb_channel_alloc(VALUE cls) { grpc_rb_channel *wrapper = ALLOC(grpc_rb_channel); wrapper->wrapped = NULL; wrapper->mark = Qnil; - return Data_Wrap_Struct(cls, grpc_rb_channel_mark, grpc_rb_channel_free, - wrapper); + return TypedData_Wrap_Struct(cls, &grpc_channel_data_type, wrapper); } /* @@ -135,7 +141,7 @@ static VALUE grpc_rb_channel_init(int argc, VALUE *argv, VALUE self) { /* "21" == 2 mandatory args, 1 (credentials) is optional */ rb_scan_args(argc, argv, "21", &target, &channel_args, &credentials); - Data_Get_Struct(self, grpc_rb_channel, wrapper); + TypedData_Get_Struct(self, grpc_rb_channel, &grpc_channel_data_type, wrapper); target_chars = StringValueCStr(target); grpc_rb_hash_convert_to_channel_args(channel_args, &args); if (credentials == Qnil) { @@ -176,8 +182,8 @@ static VALUE grpc_rb_channel_init_copy(VALUE copy, VALUE orig) { return Qnil; } - Data_Get_Struct(orig, grpc_rb_channel, orig_ch); - Data_Get_Struct(copy, grpc_rb_channel, copy_ch); + TypedData_Get_Struct(orig, grpc_rb_channel, &grpc_channel_data_type, orig_ch); + TypedData_Get_Struct(copy, grpc_rb_channel, &grpc_channel_data_type, copy_ch); /* use ruby's MEMCPY to make a byte-for-byte copy of the channel wrapper * object. */ @@ -198,7 +204,7 @@ static VALUE grpc_rb_channel_create_call(VALUE self, VALUE cqueue, VALUE method, char *host_chars = StringValueCStr(host); cq = grpc_rb_get_wrapped_completion_queue(cqueue); - Data_Get_Struct(self, grpc_rb_channel, wrapper); + TypedData_Get_Struct(self, grpc_rb_channel, &grpc_channel_data_type, wrapper); ch = wrapper->wrapped; if (ch == NULL) { rb_raise(rb_eRuntimeError, "closed!"); @@ -231,7 +237,7 @@ static VALUE grpc_rb_channel_destroy(VALUE self) { grpc_rb_channel *wrapper = NULL; grpc_channel *ch = NULL; - Data_Get_Struct(self, grpc_rb_channel, wrapper); + TypedData_Get_Struct(self, grpc_rb_channel, &grpc_channel_data_type, wrapper); ch = wrapper->wrapped; if (ch != NULL) { grpc_channel_destroy(ch); @@ -277,6 +283,6 @@ void Init_grpc_channel() { /* Gets the wrapped channel from the ruby wrapper */ grpc_channel *grpc_rb_get_wrapped_channel(VALUE v) { grpc_rb_channel *wrapper = NULL; - Data_Get_Struct(v, grpc_rb_channel, wrapper); + TypedData_Get_Struct(v, grpc_rb_channel, &grpc_channel_data_type, wrapper); return wrapper->wrapped; } diff --git a/src/ruby/ext/grpc/rb_channel_args.c b/src/ruby/ext/grpc/rb_channel_args.c index 9b92ec1514..acd545f5d2 100644 --- a/src/ruby/ext/grpc/rb_channel_args.c +++ b/src/ruby/ext/grpc/rb_channel_args.c @@ -38,6 +38,13 @@ #include "rb_grpc.h" +static rb_data_type_t grpc_rb_channel_args_data_type = { + "grpc_channel_args", + {GRPC_RB_GC_NOT_MARKED, GRPC_RB_GC_DONT_FREE, GRPC_RB_MEMSIZE_UNAVAILABLE}, + NULL, NULL, + RUBY_TYPED_FREE_IMMEDIATELY +}; + /* A callback the processes the hash key values in channel_args hash */ static int grpc_rb_channel_create_in_process_add_args_hash_cb(VALUE key, VALUE val, @@ -60,7 +67,8 @@ static int grpc_rb_channel_create_in_process_add_args_hash_cb(VALUE key, return ST_STOP; } - Data_Get_Struct(args_obj, grpc_channel_args, args); + TypedData_Get_Struct(args_obj, grpc_channel_args, + &grpc_rb_channel_args_data_type, args); if (args->num_args <= 0) { rb_raise(rb_eRuntimeError, "hash_cb bug: num_args is %lu for key:%s", args->num_args, StringValueCStr(key)); @@ -126,8 +134,9 @@ static VALUE grpc_rb_hash_convert_to_channel_args0(VALUE as_value) { MEMZERO(params->dst->args, grpc_arg, num_args); rb_hash_foreach(params->src_hash, grpc_rb_channel_create_in_process_add_args_hash_cb, - Data_Wrap_Struct(grpc_rb_cChannelArgs, GC_NOT_MARKED, - GC_DONT_FREE, params->dst)); + TypedData_Wrap_Struct(grpc_rb_cChannelArgs, + &grpc_rb_channel_args_data_type, + params->dst)); /* reset num_args as grpc_rb_channel_create_in_process_add_args_hash_cb * decrements it during has processing */ params->dst->num_args = num_args; diff --git a/src/ruby/ext/grpc/rb_completion_queue.c b/src/ruby/ext/grpc/rb_completion_queue.c index a72f01ffb8..3cf6c313ee 100644 --- a/src/ruby/ext/grpc/rb_completion_queue.c +++ b/src/ruby/ext/grpc/rb_completion_queue.c @@ -33,7 +33,8 @@ #include "rb_completion_queue.h" -#include <ruby.h> +#include <ruby/ruby.h> +#include <ruby/thread.h> #include <grpc/grpc.h> #include <grpc/support/time.h> @@ -52,14 +53,16 @@ typedef struct next_call_stack { } next_call_stack; /* Calls grpc_completion_queue_next without holding the ruby GIL */ -static void *grpc_rb_completion_queue_next_no_gil(next_call_stack *next_call) { +static void *grpc_rb_completion_queue_next_no_gil(void *param) { + next_call_stack *const next_call = (next_call_stack*)param; next_call->event = grpc_completion_queue_next(next_call->cq, next_call->timeout); return NULL; } /* Calls grpc_completion_queue_pluck without holding the ruby GIL */ -static void *grpc_rb_completion_queue_pluck_no_gil(next_call_stack *next_call) { +static void *grpc_rb_completion_queue_pluck_no_gil(void *param) { + next_call_stack *const next_call = (next_call_stack*)param; next_call->event = grpc_completion_queue_pluck(next_call->cq, next_call->tag, next_call->timeout); return NULL; @@ -116,21 +119,31 @@ static void grpc_rb_completion_queue_destroy(void *p) { grpc_completion_queue_destroy(cq); } +static rb_data_type_t grpc_rb_completion_queue_data_type = { + "grpc_completion_queue", + {GRPC_RB_GC_NOT_MARKED, grpc_rb_completion_queue_destroy, + GRPC_RB_MEMSIZE_UNAVAILABLE}, + NULL, NULL, + /* cannot immediately free because grpc_rb_completion_queue_shutdown_drain + * calls rb_thread_call_without_gvl. */ + 0 +}; + /* Allocates a completion queue. */ static VALUE grpc_rb_completion_queue_alloc(VALUE cls) { grpc_completion_queue *cq = grpc_completion_queue_create(); if (cq == NULL) { rb_raise(rb_eArgError, "could not create a completion queue: not sure why"); } - return Data_Wrap_Struct(cls, GC_NOT_MARKED, grpc_rb_completion_queue_destroy, - cq); + return TypedData_Wrap_Struct(cls, &grpc_rb_completion_queue_data_type, cq); } /* Blocks until the next event is available, and returns the event. */ static VALUE grpc_rb_completion_queue_next(VALUE self, VALUE timeout) { next_call_stack next_call; MEMZERO(&next_call, next_call_stack, 1); - Data_Get_Struct(self, grpc_completion_queue, next_call.cq); + TypedData_Get_Struct(self, grpc_completion_queue, + &grpc_rb_completion_queue_data_type, next_call.cq); next_call.timeout = grpc_rb_time_timeval(timeout, /* absolute time*/ 0); next_call.event = NULL; rb_thread_call_without_gvl(grpc_rb_completion_queue_next_no_gil, @@ -158,7 +171,8 @@ grpc_event* grpc_rb_completion_queue_pluck_event(VALUE self, VALUE tag, VALUE timeout) { next_call_stack next_call; MEMZERO(&next_call, next_call_stack, 1); - Data_Get_Struct(self, grpc_completion_queue, next_call.cq); + TypedData_Get_Struct(self, grpc_completion_queue, + &grpc_rb_completion_queue_data_type, next_call.cq); next_call.timeout = grpc_rb_time_timeval(timeout, /* absolute time*/ 0); next_call.tag = ROBJECT(tag); next_call.event = NULL; @@ -192,6 +206,7 @@ void Init_grpc_completion_queue() { /* Gets the wrapped completion queue from the ruby wrapper */ grpc_completion_queue *grpc_rb_get_wrapped_completion_queue(VALUE v) { grpc_completion_queue *cq = NULL; - Data_Get_Struct(v, grpc_completion_queue, cq); + TypedData_Get_Struct(v, grpc_completion_queue, + &grpc_rb_completion_queue_data_type, cq); return cq; } diff --git a/src/ruby/ext/grpc/rb_credentials.c b/src/ruby/ext/grpc/rb_credentials.c index 122cffc92f..1ec88914e4 100644 --- a/src/ruby/ext/grpc/rb_credentials.c +++ b/src/ruby/ext/grpc/rb_credentials.c @@ -86,14 +86,21 @@ static void grpc_rb_credentials_mark(void *p) { } } +static rb_data_type_t grpc_rb_credentials_data_type = { + "grpc_credentials", + {grpc_rb_credentials_mark, grpc_rb_credentials_free, + GRPC_RB_MEMSIZE_UNAVAILABLE}, + NULL, + NULL, + RUBY_TYPED_FREE_IMMEDIATELY}; + /* Allocates Credential instances. Provides safe initial defaults for the instance fields. */ static VALUE grpc_rb_credentials_alloc(VALUE cls) { grpc_rb_credentials *wrapper = ALLOC(grpc_rb_credentials); wrapper->wrapped = NULL; wrapper->mark = Qnil; - return Data_Wrap_Struct(cls, grpc_rb_credentials_mark, - grpc_rb_credentials_free, wrapper); + return TypedData_Wrap_Struct(cls, &grpc_rb_credentials_data_type, wrapper); } /* Clones Credentials instances. @@ -113,8 +120,10 @@ static VALUE grpc_rb_credentials_init_copy(VALUE copy, VALUE orig) { rb_raise(rb_eTypeError, "not a %s", rb_obj_classname(grpc_rb_cCredentials)); } - Data_Get_Struct(orig, grpc_rb_credentials, orig_cred); - Data_Get_Struct(copy, grpc_rb_credentials, copy_cred); + TypedData_Get_Struct(orig, grpc_rb_credentials, + &grpc_rb_credentials_data_type, orig_cred); + TypedData_Get_Struct(copy, grpc_rb_credentials, + &grpc_rb_credentials_data_type, copy_cred); /* use ruby's MEMCPY to make a byte-for-byte copy of the credentials * wrapper object. */ @@ -136,8 +145,7 @@ static VALUE grpc_rb_default_credentials_create(VALUE cls) { } wrapper->mark = Qnil; - return Data_Wrap_Struct(cls, grpc_rb_credentials_mark, - grpc_rb_credentials_free, wrapper); + return TypedData_Wrap_Struct(cls, &grpc_rb_credentials_data_type, wrapper); } /* @@ -154,8 +162,7 @@ static VALUE grpc_rb_compute_engine_credentials_create(VALUE cls) { } wrapper->mark = Qnil; - return Data_Wrap_Struct(cls, grpc_rb_credentials_mark, - grpc_rb_credentials_free, wrapper); + return TypedData_Wrap_Struct(cls, &grpc_rb_credentials_data_type, wrapper); } /* @@ -169,8 +176,10 @@ static VALUE grpc_rb_composite_credentials_create(VALUE self, VALUE other) { grpc_rb_credentials *other_wrapper = NULL; grpc_rb_credentials *wrapper = NULL; - Data_Get_Struct(self, grpc_rb_credentials, self_wrapper); - Data_Get_Struct(other, grpc_rb_credentials, other_wrapper); + TypedData_Get_Struct(self, grpc_rb_credentials, + &grpc_rb_credentials_data_type, self_wrapper); + TypedData_Get_Struct(other, grpc_rb_credentials, + &grpc_rb_credentials_data_type, other_wrapper); wrapper = ALLOC(grpc_rb_credentials); wrapper->wrapped = grpc_composite_credentials_create(self_wrapper->wrapped, other_wrapper->wrapped); @@ -181,8 +190,8 @@ static VALUE grpc_rb_composite_credentials_create(VALUE self, VALUE other) { } wrapper->mark = Qnil; - return Data_Wrap_Struct(grpc_rb_cCredentials, grpc_rb_credentials_mark, - grpc_rb_credentials_free, wrapper); + return TypedData_Wrap_Struct(grpc_rb_cCredentials, + &grpc_rb_credentials_data_type, wrapper); } /* The attribute used on the mark object to hold the pem_root_certs. */ @@ -217,7 +226,8 @@ static VALUE grpc_rb_credentials_init(int argc, VALUE *argv, VALUE self) { rb_scan_args(argc, argv, "12", &pem_root_certs, &pem_private_key, &pem_cert_chain); - Data_Get_Struct(self, grpc_rb_credentials, wrapper); + TypedData_Get_Struct(self, grpc_rb_credentials, + &grpc_rb_credentials_data_type, wrapper); if (pem_root_certs == Qnil) { rb_raise(rb_eRuntimeError, "could not create a credential: nil pem_root_certs"); @@ -228,8 +238,8 @@ static VALUE grpc_rb_credentials_init(int argc, VALUE *argv, VALUE self) { } else { key_cert_pair.private_key = RSTRING_PTR(pem_private_key); key_cert_pair.cert_chain = RSTRING_PTR(pem_cert_chain); - creds = grpc_ssl_credentials_create( - RSTRING_PTR(pem_root_certs), &key_cert_pair); + creds = grpc_ssl_credentials_create(RSTRING_PTR(pem_root_certs), + &key_cert_pair); } if (creds == NULL) { rb_raise(rb_eRuntimeError, "could not create a credentials, not sure why"); @@ -253,8 +263,8 @@ void Init_grpc_credentials() { rb_define_alloc_func(grpc_rb_cCredentials, grpc_rb_credentials_alloc); /* Provides a ruby constructor and support for dup/clone. */ - rb_define_method(grpc_rb_cCredentials, "initialize", - grpc_rb_credentials_init, -1); + rb_define_method(grpc_rb_cCredentials, "initialize", grpc_rb_credentials_init, + -1); rb_define_method(grpc_rb_cCredentials, "initialize_copy", grpc_rb_credentials_init_copy, 1); @@ -277,6 +287,7 @@ void Init_grpc_credentials() { /* Gets the wrapped grpc_credentials from the ruby wrapper */ grpc_credentials *grpc_rb_get_wrapped_credentials(VALUE v) { grpc_rb_credentials *wrapper = NULL; - Data_Get_Struct(v, grpc_rb_credentials, wrapper); + TypedData_Get_Struct(v, grpc_rb_credentials, &grpc_rb_credentials_data_type, + wrapper); return wrapper->wrapped; } diff --git a/src/ruby/ext/grpc/rb_grpc.c b/src/ruby/ext/grpc/rb_grpc.c index 1cbd1aa8bd..699548b940 100644 --- a/src/ruby/ext/grpc/rb_grpc.c +++ b/src/ruby/ext/grpc/rb_grpc.c @@ -34,7 +34,8 @@ #include "rb_grpc.h" #include <math.h> -#include <ruby.h> +#include <ruby/ruby.h> +#include <ruby/vm.h> #include <sys/time.h> #include <grpc/grpc.h> @@ -46,12 +47,15 @@ #include "rb_credentials.h" #include "rb_server_credentials.h" -/* Define common vars and funcs declared in rb.h */ -const RUBY_DATA_FUNC GC_NOT_MARKED = NULL; -const RUBY_DATA_FUNC GC_DONT_FREE = NULL; - static VALUE grpc_rb_cTimeVal = Qnil; +static rb_data_type_t grpc_rb_timespec_data_type = { + "gpr_timespec", + {GRPC_RB_GC_NOT_MARKED, GRPC_RB_GC_DONT_FREE, GRPC_RB_MEMSIZE_UNAVAILABLE}, + NULL, + NULL, + RUBY_TYPED_FREE_IMMEDIATELY}; + /* Alloc func that blocks allocation of a given object by raising an * exception. */ VALUE grpc_rb_cannot_alloc(VALUE cls) { @@ -97,7 +101,8 @@ gpr_timespec grpc_rb_time_timeval(VALUE time, int interval) { switch (TYPE(time)) { case T_DATA: if (CLASS_OF(time) == grpc_rb_cTimeVal) { - Data_Get_Struct(time, gpr_timespec, time_const); + TypedData_Get_Struct(time, gpr_timespec, &grpc_rb_timespec_data_type, + time_const); t = *time_const; } else if (CLASS_OF(time) == rb_cTime) { t.tv_sec = NUM2INT(rb_funcall(time, id_tv_sec, 0)); @@ -201,7 +206,8 @@ static ID id_to_s; /* Converts a wrapped time constant to a standard time. */ static VALUE grpc_rb_time_val_to_time(VALUE self) { gpr_timespec *time_const = NULL; - Data_Get_Struct(self, gpr_timespec, time_const); + TypedData_Get_Struct(self, gpr_timespec, &grpc_rb_timespec_data_type, + time_const); return rb_funcall(rb_cTime, id_at, 2, INT2NUM(time_const->tv_sec), INT2NUM(time_const->tv_nsec)); } @@ -222,18 +228,18 @@ static void Init_grpc_time_consts() { rb_define_module_under(grpc_rb_mGrpcCore, "TimeConsts"); grpc_rb_cTimeVal = rb_define_class_under(grpc_rb_mGrpcCore, "TimeSpec", rb_cObject); - rb_define_const(grpc_rb_mTimeConsts, "ZERO", - Data_Wrap_Struct(grpc_rb_cTimeVal, - GC_NOT_MARKED, GC_DONT_FREE, - (void *)&gpr_time_0)); - rb_define_const(grpc_rb_mTimeConsts, "INFINITE_FUTURE", - Data_Wrap_Struct(grpc_rb_cTimeVal, - GC_NOT_MARKED, GC_DONT_FREE, - (void *)&gpr_inf_future)); - rb_define_const(grpc_rb_mTimeConsts, "INFINITE_PAST", - Data_Wrap_Struct(grpc_rb_cTimeVal, - GC_NOT_MARKED, GC_DONT_FREE, - (void *)&gpr_inf_past)); + rb_define_const( + grpc_rb_mTimeConsts, "ZERO", + TypedData_Wrap_Struct(grpc_rb_cTimeVal, &grpc_rb_timespec_data_type, + (void *)&gpr_time_0)); + rb_define_const( + grpc_rb_mTimeConsts, "INFINITE_FUTURE", + TypedData_Wrap_Struct(grpc_rb_cTimeVal, &grpc_rb_timespec_data_type, + (void *)&gpr_inf_future)); + rb_define_const( + grpc_rb_mTimeConsts, "INFINITE_PAST", + TypedData_Wrap_Struct(grpc_rb_cTimeVal, &grpc_rb_timespec_data_type, + (void *)&gpr_inf_past)); rb_define_method(grpc_rb_cTimeVal, "to_time", grpc_rb_time_val_to_time, 0); rb_define_method(grpc_rb_cTimeVal, "inspect", grpc_rb_time_val_inspect, 0); rb_define_method(grpc_rb_cTimeVal, "to_s", grpc_rb_time_val_to_s, 0); @@ -244,7 +250,7 @@ static void Init_grpc_time_consts() { id_tv_nsec = rb_intern("tv_nsec"); } -static void grpc_rb_shutdown(void *vm) { grpc_shutdown(); } +static void grpc_rb_shutdown(ruby_vm_t *vm) { grpc_shutdown(); } /* Initialize the GRPC module structs */ diff --git a/src/ruby/ext/grpc/rb_grpc.h b/src/ruby/ext/grpc/rb_grpc.h index 1d411baf5b..a502273de1 100644 --- a/src/ruby/ext/grpc/rb_grpc.h +++ b/src/ruby/ext/grpc/rb_grpc.h @@ -58,12 +58,16 @@ extern VALUE sym_metadata; /* GC_NOT_MARKED is used in calls to Data_Wrap_Struct to indicate that the wrapped struct does not need to participate in ruby gc. */ -extern const RUBY_DATA_FUNC GC_NOT_MARKED; +#define GRPC_RB_GC_NOT_MARKED (RUBY_DATA_FUNC)(NULL) /* GC_DONT_FREED is used in calls to Data_Wrap_Struct to indicate that the wrapped struct should not be freed the wrapped ruby object is released by the garbage collector. */ -extern const RUBY_DATA_FUNC GC_DONT_FREE; +#define GRPC_RB_GC_DONT_FREE (RUBY_DATA_FUNC)(NULL) + +/* GRPC_RB_MEMSIZE_UNAVAILABLE is used in rb_data_type_t to indicate that the + * number of bytes used by the wrapped struct is not available. */ +#define GRPC_RB_MEMSIZE_UNAVAILABLE (size_t (*)(const void*))(NULL) /* A ruby object alloc func that fails by raising an exception. */ VALUE grpc_rb_cannot_alloc(VALUE cls); diff --git a/src/ruby/ext/grpc/rb_server.c b/src/ruby/ext/grpc/rb_server.c index 80f7760ebb..bc0878af05 100644 --- a/src/ruby/ext/grpc/rb_server.c +++ b/src/ruby/ext/grpc/rb_server.c @@ -88,13 +88,23 @@ static void grpc_rb_server_mark(void *p) { } } +static const rb_data_type_t grpc_rb_server_data_type = { + "grpc_server", + {grpc_rb_server_mark, grpc_rb_server_free, GRPC_RB_MEMSIZE_UNAVAILABLE}, + NULL, + NULL, + /* It is unsafe to specify RUBY_TYPED_FREE_IMMEDIATELY because the free function would block + * and we might want to unlock GVL + * TODO(yugui) Unlock GVL? + */ + 0}; + /* Allocates grpc_rb_server instances. */ static VALUE grpc_rb_server_alloc(VALUE cls) { grpc_rb_server *wrapper = ALLOC(grpc_rb_server); wrapper->wrapped = NULL; wrapper->mark = Qnil; - return Data_Wrap_Struct(cls, grpc_rb_server_mark, grpc_rb_server_free, - wrapper); + return TypedData_Wrap_Struct(cls, &grpc_rb_server_data_type, wrapper); } /* @@ -110,7 +120,8 @@ static VALUE grpc_rb_server_init(VALUE self, VALUE cqueue, VALUE channel_args) { grpc_channel_args args; MEMZERO(&args, grpc_channel_args, 1); cq = grpc_rb_get_wrapped_completion_queue(cqueue); - Data_Get_Struct(self, grpc_rb_server, wrapper); + TypedData_Get_Struct(self, grpc_rb_server, &grpc_rb_server_data_type, + wrapper); grpc_rb_hash_convert_to_channel_args(channel_args, &args); srv = grpc_server_create(cq, &args); @@ -146,8 +157,10 @@ static VALUE grpc_rb_server_init_copy(VALUE copy, VALUE orig) { rb_raise(rb_eTypeError, "not a %s", rb_obj_classname(grpc_rb_cServer)); } - Data_Get_Struct(orig, grpc_rb_server, orig_srv); - Data_Get_Struct(copy, grpc_rb_server, copy_srv); + TypedData_Get_Struct(orig, grpc_rb_server, &grpc_rb_server_data_type, + orig_srv); + TypedData_Get_Struct(copy, grpc_rb_server, &grpc_rb_server_data_type, + copy_srv); /* use ruby's MEMCPY to make a byte-for-byte copy of the server wrapper object. */ @@ -194,7 +207,7 @@ static VALUE grpc_rb_server_request_call(VALUE self, VALUE cqueue, grpc_call_error err; request_call_stack st; VALUE result; - Data_Get_Struct(self, grpc_rb_server, s); + TypedData_Get_Struct(self, grpc_rb_server, &grpc_rb_server_data_type, s); if (s->wrapped == NULL) { rb_raise(rb_eRuntimeError, "closed!"); return Qnil; @@ -245,7 +258,7 @@ static VALUE grpc_rb_server_request_call(VALUE self, VALUE cqueue, static VALUE grpc_rb_server_start(VALUE self) { grpc_rb_server *s = NULL; - Data_Get_Struct(self, grpc_rb_server, s); + TypedData_Get_Struct(self, grpc_rb_server, &grpc_rb_server_data_type, s); if (s->wrapped == NULL) { rb_raise(rb_eRuntimeError, "closed!"); } else { @@ -256,7 +269,7 @@ static VALUE grpc_rb_server_start(VALUE self) { static VALUE grpc_rb_server_destroy(VALUE self) { grpc_rb_server *s = NULL; - Data_Get_Struct(self, grpc_rb_server, s); + TypedData_Get_Struct(self, grpc_rb_server, &grpc_rb_server_data_type, s); if (s->wrapped != NULL) { grpc_server_shutdown(s->wrapped); grpc_server_destroy(s->wrapped); @@ -288,7 +301,7 @@ static VALUE grpc_rb_server_add_http2_port(int argc, VALUE *argv, VALUE self) { /* "11" == 1 mandatory args, 1 (rb_creds) is optional */ rb_scan_args(argc, argv, "11", &port, &rb_creds); - Data_Get_Struct(self, grpc_rb_server, s); + TypedData_Get_Struct(self, grpc_rb_server, &grpc_rb_server_data_type, s); if (s->wrapped == NULL) { rb_raise(rb_eRuntimeError, "closed!"); return Qnil; @@ -340,6 +353,6 @@ void Init_grpc_server() { /* Gets the wrapped server from the ruby wrapper */ grpc_server *grpc_rb_get_wrapped_server(VALUE v) { grpc_rb_server *wrapper = NULL; - Data_Get_Struct(v, grpc_rb_server, wrapper); + TypedData_Get_Struct(v, grpc_rb_server, &grpc_rb_server_data_type, wrapper); return wrapper->wrapped; } diff --git a/src/ruby/ext/grpc/rb_server_credentials.c b/src/ruby/ext/grpc/rb_server_credentials.c index 5109b96b5f..a86389445f 100644 --- a/src/ruby/ext/grpc/rb_server_credentials.c +++ b/src/ruby/ext/grpc/rb_server_credentials.c @@ -86,6 +86,14 @@ static void grpc_rb_server_credentials_mark(void *p) { } } +static const rb_data_type_t grpc_rb_server_credentials_data_type = { + "grpc_server_credentials", + {grpc_rb_server_credentials_mark, grpc_rb_server_credentials_free, + GRPC_RB_MEMSIZE_UNAVAILABLE}, + NULL, NULL, + RUBY_TYPED_FREE_IMMEDIATELY +}; + /* Allocates ServerCredential instances. Provides safe initial defaults for the instance fields. */ @@ -93,8 +101,8 @@ static VALUE grpc_rb_server_credentials_alloc(VALUE cls) { grpc_rb_server_credentials *wrapper = ALLOC(grpc_rb_server_credentials); wrapper->wrapped = NULL; wrapper->mark = Qnil; - return Data_Wrap_Struct(cls, grpc_rb_server_credentials_mark, - grpc_rb_server_credentials_free, wrapper); + return TypedData_Wrap_Struct(cls, &grpc_rb_server_credentials_data_type, + wrapper); } /* Clones ServerCredentials instances. @@ -116,8 +124,10 @@ static VALUE grpc_rb_server_credentials_init_copy(VALUE copy, VALUE orig) { rb_obj_classname(grpc_rb_cServerCredentials)); } - Data_Get_Struct(orig, grpc_rb_server_credentials, orig_ch); - Data_Get_Struct(copy, grpc_rb_server_credentials, copy_ch); + TypedData_Get_Struct(orig, grpc_rb_server_credentials, + &grpc_rb_server_credentials_data_type, orig_ch); + TypedData_Get_Struct(copy, grpc_rb_server_credentials, + &grpc_rb_server_credentials_data_type, copy_ch); /* use ruby's MEMCPY to make a byte-for-byte copy of the server_credentials wrapper object. */ @@ -153,7 +163,8 @@ static VALUE grpc_rb_server_credentials_init(VALUE self, VALUE pem_root_certs, grpc_rb_server_credentials *wrapper = NULL; grpc_server_credentials *creds = NULL; grpc_ssl_pem_key_cert_pair key_cert_pair = {NULL, NULL}; - Data_Get_Struct(self, grpc_rb_server_credentials, wrapper); + TypedData_Get_Struct(self, grpc_rb_server_credentials, + &grpc_rb_server_credentials_data_type, wrapper); if (pem_cert_chain == Qnil) { rb_raise(rb_eRuntimeError, "could not create a server credential: nil pem_cert_chain"); @@ -206,6 +217,7 @@ void Init_grpc_server_credentials() { /* Gets the wrapped grpc_server_credentials from the ruby wrapper */ grpc_server_credentials *grpc_rb_get_wrapped_server_credentials(VALUE v) { grpc_rb_server_credentials *wrapper = NULL; - Data_Get_Struct(v, grpc_rb_server_credentials, wrapper); + TypedData_Get_Struct(v, grpc_rb_server_credentials, + &grpc_rb_server_credentials_data_type, wrapper); return wrapper->wrapped; } diff --git a/src/ruby/grpc.gemspec b/src/ruby/grpc.gemspec index 12d4ab17f2..ae48213c8f 100755 --- a/src/ruby/grpc.gemspec +++ b/src/ruby/grpc.gemspec @@ -13,6 +13,9 @@ Gem::Specification.new do |s| s.description = 'Send RPCs from Ruby using GRPC' s.license = 'BSD-3-Clause' + s.required_ruby_version = '>= 2.0.0' + s.requirements << 'libgrpc ~> 0.6.0 needs to be installed' + s.files = `git ls-files`.split("\n") s.test_files = `git ls-files -- spec/*`.split("\n") s.executables = `git ls-files -- bin/*.rb`.split("\n").map do |f| @@ -25,13 +28,12 @@ Gem::Specification.new do |s| s.add_dependency 'googleauth', '~> 0.4' # reqd for interop tests s.add_dependency 'logging', '~> 1.8' s.add_dependency 'minitest', '~> 5.4' # reqd for interop tests - s.add_dependency 'xray', '~> 1.1' s.add_development_dependency 'bundler', '~> 1.9' s.add_development_dependency 'rake', '~> 10.4' s.add_development_dependency 'rake-compiler', '~> 0.9' - s.add_development_dependency 'rubocop', '~> 0.30' s.add_development_dependency 'rspec', '~> 3.2' + s.add_development_dependency 'rubocop', '~> 0.30' s.extensions = %w(ext/grpc/extconf.rb) end diff --git a/src/ruby/lib/grpc/generic/client_stub.rb b/src/ruby/lib/grpc/generic/client_stub.rb index dc7672d359..7b2c04aa22 100644 --- a/src/ruby/lib/grpc/generic/client_stub.rb +++ b/src/ruby/lib/grpc/generic/client_stub.rb @@ -28,7 +28,6 @@ # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. require 'grpc/generic/active_call' -require 'xray/thread_dump_signal_handler' # GRPC contains the General RPC module. module GRPC diff --git a/src/ruby/lib/grpc/generic/rpc_server.rb b/src/ruby/lib/grpc/generic/rpc_server.rb index 30a4bf1532..c7c8267fa3 100644 --- a/src/ruby/lib/grpc/generic/rpc_server.rb +++ b/src/ruby/lib/grpc/generic/rpc_server.rb @@ -31,7 +31,9 @@ require 'grpc/grpc' require 'grpc/generic/active_call' require 'grpc/generic/service' require 'thread' -require 'xray/thread_dump_signal_handler' + +# A global that contains signals the gRPC servers should respond to. +$grpc_signals = [] # GRPC contains the General RPC module. module GRPC @@ -50,6 +52,23 @@ module GRPC # Default max_waiting_requests size is 20 DEFAULT_MAX_WAITING_REQUESTS = 20 + # Default poll period is 1s + DEFAULT_POLL_PERIOD = 1 + + # Signal check period is 0.25s + SIGNAL_CHECK_PERIOD = 0.25 + + # Sets up a signal handler that adds signals to the signal handling global. + # + # Signal handlers should do as little as humanly possible. + # Here, they just add themselves to $grpc_signals + # + # RpcServer (and later other parts of gRPC) monitors the signals + # $grpc_signals in its own non-signal context. + def self.trap_signals + %w(INT TERM).each { |sig| trap(sig) { $grpc_signals << sig } } + end + # Creates a new RpcServer. # # The RPC server is configured using keyword arguments. @@ -79,7 +98,7 @@ module GRPC # with not available to new requests def initialize(pool_size:DEFAULT_POOL_SIZE, max_waiting_requests:DEFAULT_MAX_WAITING_REQUESTS, - poll_period:INFINITE_FUTURE, + poll_period:DEFAULT_POLL_PERIOD, completion_queue_override:nil, server_override:nil, **kw) @@ -117,6 +136,13 @@ module GRPC return unless @running @stopped = true @pool.stop + + # TODO: uncomment this: + # + # This segfaults in the c layer, so its commented out for now. Shutdown + # still occurs, but the c layer has to do the cleanup. + # + # @server.close end # determines if the server is currently running @@ -139,7 +165,37 @@ module GRPC running? end - # determines if the server is currently stopped + # Runs the server in its own thread, then waits for signal INT or TERM on + # the current thread to terminate it. + def run_till_terminated + self.class.trap_signals + t = Thread.new { run } + wait_till_running + loop do + sleep SIGNAL_CHECK_PERIOD + break unless handle_signals + end + stop + t.join + end + + # Handles the signals in $grpc_signals. + # + # @return false if the server should exit, true if not. + def handle_signals + loop do + sig = $grpc_signals.shift + case sig + when 'INT' + return false + when 'TERM' + return false + end + end + true + end + + # Determines if the server is currently stopped def stopped? @stopped ||= false end @@ -265,7 +321,10 @@ module GRPC # Pool is a simple thread pool for running server requests. class Pool - def initialize(size) + # Default keep alive period is 1s + DEFAULT_KEEP_ALIVE = 1 + + def initialize(size, keep_alive: DEFAULT_KEEP_ALIVE) fail 'pool size must be positive' unless size > 0 @jobs = Queue.new @size = size @@ -273,6 +332,7 @@ module GRPC @stop_mutex = Mutex.new @stop_cond = ConditionVariable.new @workers = [] + @keep_alive = keep_alive end # Returns the number of jobs waiting @@ -325,15 +385,13 @@ module GRPC @workers.size.times { schedule { throw :exit } } @stopped = true - # TODO: allow configuration of the keepalive period - keep_alive = 5 @stop_mutex.synchronize do - @stop_cond.wait(@stop_mutex, keep_alive) if @workers.size > 0 + @stop_cond.wait(@stop_mutex, @keep_alive) if @workers.size > 0 end # Forcibly shutdown any threads that are still alive. if @workers.size > 0 - logger.warn("forcibly terminating #{@workers.size} worker(s)") + logger.info("forcibly terminating #{@workers.size} worker(s)") @workers.each do |t| next unless t.alive? begin @@ -344,7 +402,6 @@ module GRPC end end end - logger.info('stopped, all workers are shutdown') end end diff --git a/src/ruby/spec/credentials_spec.rb b/src/ruby/spec/credentials_spec.rb index fc97d11a87..8e72e85d54 100644 --- a/src/ruby/spec/credentials_spec.rb +++ b/src/ruby/spec/credentials_spec.rb @@ -61,11 +61,11 @@ describe Credentials do end describe '#compose' do - it 'can be completed OK' do + it 'cannot be completed OK with 2 SSL creds' do certs = load_test_certs cred1 = Credentials.new(*certs) cred2 = Credentials.new(*certs) - expect { cred1.compose(cred2) }.to_not raise_error + expect { cred1.compose(cred2) }.to raise_error end end end diff --git a/src/ruby/spec/generic/client_stub_spec.rb b/src/ruby/spec/generic/client_stub_spec.rb index 193c5f2a03..88c6b44c22 100644 --- a/src/ruby/spec/generic/client_stub_spec.rb +++ b/src/ruby/spec/generic/client_stub_spec.rb @@ -28,7 +28,6 @@ # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. require 'grpc' -require 'xray/thread_dump_signal_handler' # Notifier is useful high-level synchronization primitive. class Notifier diff --git a/src/ruby/spec/generic/rpc_server_pool_spec.rb b/src/ruby/spec/generic/rpc_server_pool_spec.rb index 8383dc1533..3bbc71b822 100644 --- a/src/ruby/spec/generic/rpc_server_pool_spec.rb +++ b/src/ruby/spec/generic/rpc_server_pool_spec.rb @@ -28,7 +28,6 @@ # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. require 'grpc' -require 'xray/thread_dump_signal_handler' Pool = GRPC::RpcServer::Pool diff --git a/src/ruby/spec/generic/rpc_server_spec.rb b/src/ruby/spec/generic/rpc_server_spec.rb index 1323bacfa6..e091c589f5 100644 --- a/src/ruby/spec/generic/rpc_server_spec.rb +++ b/src/ruby/spec/generic/rpc_server_spec.rb @@ -28,7 +28,6 @@ # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. require 'grpc' -require 'xray/thread_dump_signal_handler' def load_test_certs test_root = File.join(File.dirname(File.dirname(__FILE__)), 'testdata') |