Merge pull request #10738 from apolcyn/bump_12x_to_125
bumpy v1.2.x branch to v 1.2.5
diff --git a/src/ruby/end2end/README.md b/src/ruby/end2end/README.md
index ea5ab6d..08b9b98 100644
--- a/src/ruby/end2end/README.md
+++ b/src/ruby/end2end/README.md
@@ -1,3 +1,6 @@
+TODO: during upmerge from v1.2.x to master, no changes from this
+directory should go into master.
+
This directory contains some grpc-ruby end to end tests.
Each test here involves two files: a "driver" and a "client". For example,
diff --git a/src/ruby/end2end/channel_closing_client.rb b/src/ruby/end2end/channel_closing_client.rb
deleted file mode 100755
index 8449797..0000000
--- a/src/ruby/end2end/channel_closing_client.rb
+++ /dev/null
@@ -1,84 +0,0 @@
-#!/usr/bin/env ruby
-
-# Copyright 2015, 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.
-
-require_relative './end2end_common'
-
-# Calls '#close' on a Channel when "shutdown" called. This tries to
-# trigger a hang or crash bug by closing a channel actively being watched
-class ChannelClosingClientController < ClientControl::ClientController::Service
- def initialize(ch)
- @ch = ch
- end
-
- def shutdown(_, _)
- @ch.close
- ClientControl::Void.new
- end
-end
-
-def main
- client_control_port = ''
- server_port = ''
- OptionParser.new do |opts|
- opts.on('--client_control_port=P', String) do |p|
- client_control_port = p
- end
- opts.on('--server_port=P', String) do |p|
- server_port = p
- end
- end.parse!
-
- ch = GRPC::Core::Channel.new("localhost:#{server_port}", {},
- :this_channel_is_insecure)
-
- srv = GRPC::RpcServer.new
- thd = Thread.new do
- srv.add_http2_port("0.0.0.0:#{client_control_port}", :this_port_is_insecure)
- srv.handle(ChannelClosingClientController.new(ch))
- srv.run
- end
-
- # this should break out with an exception once the channel is closed
- loop do
- begin
- state = ch.connectivity_state(true)
- ch.watch_connectivity_state(state, Time.now + 360)
- rescue RuntimeError => e
- STDERR.puts "(expected) error occurred: #{e.inspect}"
- break
- end
- end
-
- srv.stop
- thd.join
-end
-
-main
diff --git a/src/ruby/end2end/channel_closing_driver.rb b/src/ruby/end2end/channel_closing_driver.rb
deleted file mode 100755
index d3e5373..0000000
--- a/src/ruby/end2end/channel_closing_driver.rb
+++ /dev/null
@@ -1,67 +0,0 @@
-#!/usr/bin/env ruby
-
-# Copyright 2016, Google Inc.
-# All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions are
-# met:
-#
-# * Redistributions of source code must retain the above copyright
-# notice, this list of conditions and the following disclaimer.
-# * Redistributions in binary form must reproduce the above
-# copyright notice, this list of conditions and the following disclaimer
-# in the documentation and/or other materials provided with the
-# distribution.
-# * Neither the name of Google Inc. nor the names of its
-# contributors may be used to endorse or promote products derived from
-# this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-# make sure that the client doesn't hang when channel is closed
-# explictly while it's used
-
-require_relative './end2end_common'
-
-def main
- STDERR.puts 'start server'
- server_runner = ServerRunner.new(EchoServerImpl)
- server_port = server_runner.run
-
- sleep 1
-
- STDERR.puts 'start client'
- control_stub, client_pid = start_client('channel_closing_client.rb',
- server_port)
-
- sleep 3
-
- begin
- Timeout.timeout(10) do
- control_stub.shutdown(ClientControl::Void.new)
- Process.wait(client_pid)
- end
- rescue Timeout::Error
- STDERR.puts "timeout wait for client pid #{client_pid}"
- Process.kill('SIGKILL', client_pid)
- Process.wait(client_pid)
- STDERR.puts 'killed client child'
- raise 'Timed out waiting for client process. It likely hangs when a ' \
- 'channel is closed while connectivity is watched'
- end
-
- server_runner.stop
-end
-
-main
diff --git a/src/ruby/end2end/channel_state_client.rb b/src/ruby/end2end/channel_state_client.rb
deleted file mode 100755
index 08c21bb..0000000
--- a/src/ruby/end2end/channel_state_client.rb
+++ /dev/null
@@ -1,54 +0,0 @@
-#!/usr/bin/env ruby
-
-# Copyright 2015, 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.
-
-require_relative './end2end_common'
-
-def main
- server_port = ''
- OptionParser.new do |opts|
- opts.on('--client_control_port=P', String) do
- STDERR.puts 'client_control_port ignored'
- end
- opts.on('--server_port=P', String) do |p|
- server_port = p
- end
- end.parse!
-
- ch = GRPC::Core::Channel.new("localhost:#{server_port}", {},
- :this_channel_is_insecure)
-
- loop do
- state = ch.connectivity_state
- ch.watch_connectivity_state(state, Time.now + 360)
- end
-end
-
-main
diff --git a/src/ruby/end2end/channel_state_driver.rb b/src/ruby/end2end/channel_state_driver.rb
deleted file mode 100755
index 80fb628..0000000
--- a/src/ruby/end2end/channel_state_driver.rb
+++ /dev/null
@@ -1,64 +0,0 @@
-#!/usr/bin/env ruby
-
-# Copyright 2016, Google Inc.
-# All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions are
-# met:
-#
-# * Redistributions of source code must retain the above copyright
-# notice, this list of conditions and the following disclaimer.
-# * Redistributions in binary form must reproduce the above
-# copyright notice, this list of conditions and the following disclaimer
-# in the documentation and/or other materials provided with the
-# distribution.
-# * Neither the name of Google Inc. nor the names of its
-# contributors may be used to endorse or promote products derived from
-# this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-# make sure that the client doesn't hang when process ended abruptly
-
-require_relative './end2end_common'
-
-def main
- STDERR.puts 'start server'
- server_runner = ServerRunner.new(EchoServerImpl)
- server_port = server_runner.run
-
- sleep 1
-
- STDERR.puts 'start client'
- _, client_pid = start_client('channel_state_client.rb', server_port)
-
- sleep 3
-
- Process.kill('SIGTERM', client_pid)
-
- begin
- Timeout.timeout(10) { Process.wait(client_pid) }
- rescue Timeout::Error
- STDERR.puts "timeout wait for client pid #{client_pid}"
- Process.kill('SIGKILL', client_pid)
- Process.wait(client_pid)
- STDERR.puts 'killed client child'
- raise 'Timed out waiting for client process. ' \
- 'It likely hangs when ended abruptly'
- end
-
- server_runner.stop
-end
-
-main
diff --git a/src/ruby/end2end/sig_int_during_channel_watch_client.rb b/src/ruby/end2end/sig_int_during_channel_watch_client.rb
deleted file mode 100755
index 389fc5b..0000000
--- a/src/ruby/end2end/sig_int_during_channel_watch_client.rb
+++ /dev/null
@@ -1,70 +0,0 @@
-#!/usr/bin/env ruby
-
-# Copyright 2015, 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.
-
-require_relative './end2end_common'
-
-# Start polling the channel state in both the main thread
-# and a child thread. Try to get the driver to send process-ending
-# interrupt while both a child thread and the main thread are in the
-# middle of a blocking connectivity_state call.
-def main
- server_port = ''
- OptionParser.new do |opts|
- opts.on('--client_control_port=P', String) do
- STDERR.puts 'client_control_port not used'
- end
- opts.on('--server_port=P', String) do |p|
- server_port = p
- end
- end.parse!
-
- thd = Thread.new do
- child_thread_channel = GRPC::Core::Channel.new("localhost:#{server_port}",
- {},
- :this_channel_is_insecure)
- loop do
- state = child_thread_channel.connectivity_state(false)
- child_thread_channel.watch_connectivity_state(state, Time.now + 360)
- end
- end
-
- main_channel = GRPC::Core::Channel.new("localhost:#{server_port}",
- {},
- :this_channel_is_insecure)
- loop do
- state = main_channel.connectivity_state(false)
- main_channel.watch_connectivity_state(state, Time.now + 360)
- end
-
- thd.join
-end
-
-main
diff --git a/src/ruby/end2end/sig_int_during_channel_watch_driver.rb b/src/ruby/end2end/sig_int_during_channel_watch_driver.rb
deleted file mode 100755
index 670cda0..0000000
--- a/src/ruby/end2end/sig_int_during_channel_watch_driver.rb
+++ /dev/null
@@ -1,69 +0,0 @@
-#!/usr/bin/env ruby
-
-# Copyright 2016, Google Inc.
-# All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions are
-# met:
-#
-# * Redistributions of source code must retain the above copyright
-# notice, this list of conditions and the following disclaimer.
-# * Redistributions in binary form must reproduce the above
-# copyright notice, this list of conditions and the following disclaimer
-# in the documentation and/or other materials provided with the
-# distribution.
-# * Neither the name of Google Inc. nor the names of its
-# contributors may be used to endorse or promote products derived from
-# this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-# abruptly end a process that has active calls to
-# Channel.watch_connectivity_state
-
-require_relative './end2end_common'
-
-def main
- STDERR.puts 'start server'
- server_runner = ServerRunner.new(EchoServerImpl)
- server_port = server_runner.run
-
- sleep 1
-
- STDERR.puts 'start client'
- _, client_pid = start_client('sig_int_during_channel_watch_client.rb',
- server_port)
-
- # give time for the client to get into the middle
- # of a channel state watch call
- sleep 1
- Process.kill('SIGINT', client_pid)
-
- begin
- Timeout.timeout(10) do
- Process.wait(client_pid)
- end
- rescue Timeout::Error
- STDERR.puts "timeout wait for client pid #{client_pid}"
- Process.kill('SIGKILL', client_pid)
- Process.wait(client_pid)
- STDERR.puts 'killed client child'
- raise 'Timed out waiting for client process. It likely hangs when a ' \
- 'SIGINT is sent while there is an active connectivity_state call'
- end
-
- server_runner.stop
-end
-
-main
diff --git a/src/ruby/ext/grpc/rb_channel.c b/src/ruby/ext/grpc/rb_channel.c
index 1c20c88..7200252 100644
--- a/src/ruby/ext/grpc/rb_channel.c
+++ b/src/ruby/ext/grpc/rb_channel.c
@@ -32,24 +32,26 @@
*/
#include <ruby/ruby.h>
-#include <ruby/thread.h>
#include "rb_grpc_imports.generated.h"
-#include "rb_byte_buffer.h"
#include "rb_channel.h"
+#include "rb_byte_buffer.h"
#include <grpc/grpc.h>
#include <grpc/grpc_security.h>
#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
#include <grpc/support/time.h>
+#include "rb_grpc.h"
#include "rb_call.h"
#include "rb_channel_args.h"
#include "rb_channel_credentials.h"
#include "rb_completion_queue.h"
-#include "rb_grpc.h"
#include "rb_server.h"
+// TODO: During v1.2.x upmerge to master, no changes from this file should go
+// in to master. This is reverted for 1.2.x only.
+
/* id_channel is the name of the hidden ivar that preserves a reference to the
* channel on a call, so that calls are not GCed before their channel. */
static ID id_channel;
@@ -74,26 +76,9 @@
/* The actual channel */
grpc_channel *wrapped;
- int request_safe_destroy;
- int safe_to_destroy;
- grpc_connectivity_state current_connectivity_state;
-
- int mu_init_done;
- int abort_watch_connectivity_state;
- gpr_mu channel_mu;
- gpr_cv channel_cv;
+ grpc_completion_queue *queue;
} grpc_rb_channel;
-/* Forward declarations of functions involved in temporary fix to
- * https://github.com/grpc/grpc/issues/9941 */
-static void grpc_rb_channel_try_register_connection_polling(
- grpc_rb_channel *wrapper);
-static void grpc_rb_channel_safe_destroy(grpc_rb_channel *wrapper);
-
-static grpc_completion_queue *channel_polling_cq;
-static gpr_mu global_connection_polling_mu;
-static int abort_channel_polling = 0;
-
/* Destroys Channel instances. */
static void grpc_rb_channel_free(void *p) {
grpc_rb_channel *ch = NULL;
@@ -103,13 +88,8 @@
ch = (grpc_rb_channel *)p;
if (ch->wrapped != NULL) {
- grpc_rb_channel_safe_destroy(ch);
- ch->wrapped = NULL;
- }
-
- if (ch->mu_init_done) {
- gpr_mu_destroy(&ch->channel_mu);
- gpr_cv_destroy(&ch->channel_cv);
+ grpc_channel_destroy(ch->wrapped);
+ grpc_rb_completion_queue_destroy(ch->queue);
}
xfree(p);
@@ -127,15 +107,13 @@
}
}
-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}},
- NULL,
- NULL,
+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}},
+ NULL, NULL,
#ifdef RUBY_TYPED_FREE_IMMEDIATELY
- RUBY_TYPED_FREE_IMMEDIATELY
+ RUBY_TYPED_FREE_IMMEDIATELY
#endif
};
@@ -170,7 +148,6 @@
rb_scan_args(argc, argv, "3", &target, &channel_args, &credentials);
TypedData_Get_Struct(self, grpc_rb_channel, &grpc_channel_data_type, wrapper);
- wrapper->mu_init_done = 0;
target_chars = StringValueCStr(target);
grpc_rb_hash_convert_to_channel_args(channel_args, &args);
if (TYPE(credentials) == T_SYMBOL) {
@@ -185,27 +162,6 @@
creds = grpc_rb_get_wrapped_channel_credentials(credentials);
ch = grpc_secure_channel_create(creds, target_chars, &args, NULL);
}
-
- GPR_ASSERT(ch);
-
- wrapper->wrapped = ch;
-
- gpr_mu_init(&wrapper->channel_mu);
- gpr_cv_init(&wrapper->channel_cv);
- wrapper->mu_init_done = 1;
-
- gpr_mu_lock(&wrapper->channel_mu);
- wrapper->abort_watch_connectivity_state = 0;
- wrapper->current_connectivity_state = grpc_channel_check_connectivity_state(wrapper->wrapped, 0);
- wrapper->safe_to_destroy = 0;
- wrapper->request_safe_destroy = 0;
-
- gpr_cv_broadcast(&wrapper->channel_cv);
- gpr_mu_unlock(&wrapper->channel_mu);
-
-
- grpc_rb_channel_try_register_connection_polling(wrapper);
-
if (args.args != NULL) {
xfree(args.args); /* Allocated by grpc_rb_hash_convert_to_channel_args */
}
@@ -216,28 +172,25 @@
}
rb_ivar_set(self, id_target, target);
wrapper->wrapped = ch;
+ wrapper->queue = grpc_completion_queue_create(NULL);
return self;
}
/*
call-seq:
- ch.connectivity_state -> state
- ch.connectivity_state(true) -> state
+ insecure_channel = Channel:new("myhost:8080", {'arg1': 'value1'})
+ creds = ...
+ secure_channel = Channel:new("myhost:443", {'arg1': 'value1'}, creds)
- Indicates the current state of the channel, whose value is one of the
- constants defined in GRPC::Core::ConnectivityStates.
-
- It also tries to connect if the chennel is idle in the second form. */
+ Creates channel instances. */
static VALUE grpc_rb_channel_get_connectivity_state(int argc, VALUE *argv,
VALUE self) {
- VALUE try_to_connect_param = Qfalse;
- int grpc_try_to_connect = 0;
+ VALUE try_to_connect = Qfalse;
grpc_rb_channel *wrapper = NULL;
grpc_channel *ch = NULL;
/* "01" == 0 mandatory args, 1 (try_to_connect) is optional */
- rb_scan_args(argc, argv, "01", &try_to_connect_param);
- grpc_try_to_connect = RTEST(try_to_connect_param) ? 1 : 0;
+ rb_scan_args(argc, argv, "01", try_to_connect);
TypedData_Get_Struct(self, grpc_rb_channel, &grpc_channel_data_type, wrapper);
ch = wrapper->wrapped;
@@ -245,88 +198,57 @@
rb_raise(rb_eRuntimeError, "closed!");
return Qnil;
}
- return LONG2NUM(grpc_channel_check_connectivity_state(wrapper->wrapped, grpc_try_to_connect));
+ return NUM2LONG(
+ grpc_channel_check_connectivity_state(ch, (int)try_to_connect));
}
-typedef struct watch_state_stack {
- grpc_rb_channel *wrapper;
- gpr_timespec deadline;
- int last_state;
-} watch_state_stack;
+/* Watch for a change in connectivity state.
-static void *watch_channel_state_without_gvl(void *arg) {
- watch_state_stack *stack = (watch_state_stack*)arg;
- gpr_timespec deadline = stack->deadline;
- grpc_rb_channel *wrapper = stack->wrapper;
- int last_state = stack->last_state;
- void *return_value = (void*)0;
+ Once the channel connectivity state is different from the last observed
+ state, tag will be enqueued on cq with success=1
- gpr_mu_lock(&wrapper->channel_mu);
- while(wrapper->current_connectivity_state == last_state &&
- !wrapper->request_safe_destroy &&
- !wrapper->safe_to_destroy &&
- !wrapper->abort_watch_connectivity_state &&
- gpr_time_cmp(deadline, gpr_now(GPR_CLOCK_REALTIME)) > 0) {
- gpr_cv_wait(&wrapper->channel_cv, &wrapper->channel_mu, deadline);
- }
- if (wrapper->current_connectivity_state != last_state) {
- return_value = (void*)1;
- }
- gpr_mu_unlock(&wrapper->channel_mu);
-
- return return_value;
-}
-
-static void watch_channel_state_unblocking_func(void *arg) {
- grpc_rb_channel *wrapper = (grpc_rb_channel*)arg;
- gpr_log(GPR_DEBUG, "GRPC_RUBY: watch channel state unblocking func called");
- gpr_mu_lock(&wrapper->channel_mu);
- wrapper->abort_watch_connectivity_state = 1;
- gpr_cv_broadcast(&wrapper->channel_cv);
- gpr_mu_unlock(&wrapper->channel_mu);
-}
-
-/* Wait until the channel's connectivity state becomes different from
- * "last_state", or "deadline" expires.
- * Returns true if the the channel's connectivity state becomes
- * different from "last_state" within "deadline".
- * Returns false if "deadline" expires before the channel's connectivity
- * state changes from "last_state".
- * */
+ If deadline expires BEFORE the state is changed, tag will be enqueued on
+ the completion queue with success=0 */
static VALUE grpc_rb_channel_watch_connectivity_state(VALUE self,
VALUE last_state,
VALUE deadline) {
grpc_rb_channel *wrapper = NULL;
- watch_state_stack stack;
- void* out;
+ grpc_channel *ch = NULL;
+ grpc_completion_queue *cq = NULL;
+
+ void *tag = wrapper;
+
+ grpc_event event;
TypedData_Get_Struct(self, grpc_rb_channel, &grpc_channel_data_type, wrapper);
-
- if (wrapper->wrapped == NULL) {
+ ch = wrapper->wrapped;
+ cq = wrapper->queue;
+ if (ch == NULL) {
rb_raise(rb_eRuntimeError, "closed!");
return Qnil;
}
+ grpc_channel_watch_connectivity_state(
+ ch,
+ (grpc_connectivity_state)NUM2LONG(last_state),
+ grpc_rb_time_timeval(deadline, /* absolute time */ 0),
+ cq,
+ tag);
- if (!FIXNUM_P(last_state)) {
- rb_raise(rb_eTypeError, "bad type for last_state. want a GRPC::Core::ChannelState constant");
- return Qnil;
- }
+ event = rb_completion_queue_pluck(cq, tag,
+ gpr_inf_future(GPR_CLOCK_REALTIME), NULL);
- stack.wrapper = wrapper;
- stack.deadline = grpc_rb_time_timeval(deadline, 0);
- stack.last_state = NUM2LONG(last_state);
- out = rb_thread_call_without_gvl(watch_channel_state_without_gvl, &stack, watch_channel_state_unblocking_func, wrapper);
- if (out) {
+ if (event.success) {
return Qtrue;
+ } else {
+ return Qfalse;
}
- return Qfalse;
}
/* Create a call given a grpc_channel, in order to call method. The request
is not sent until grpc_call_invoke is called. */
-static VALUE grpc_rb_channel_create_call(VALUE self, VALUE parent, VALUE mask,
- VALUE method, VALUE host,
- VALUE deadline) {
+static VALUE grpc_rb_channel_create_call(VALUE self, VALUE parent,
+ VALUE mask, VALUE method,
+ VALUE host, VALUE deadline) {
VALUE res = Qnil;
grpc_rb_channel *wrapper = NULL;
grpc_call *call = NULL;
@@ -337,11 +259,10 @@
grpc_slice method_slice;
grpc_slice host_slice;
grpc_slice *host_slice_ptr = NULL;
- char *tmp_str = NULL;
+ char* tmp_str = NULL;
if (host != Qnil) {
- host_slice =
- grpc_slice_from_copied_buffer(RSTRING_PTR(host), RSTRING_LEN(host));
+ host_slice = grpc_slice_from_copied_buffer(RSTRING_PTR(host), RSTRING_LEN(host));
host_slice_ptr = &host_slice;
}
if (mask != Qnil) {
@@ -359,18 +280,17 @@
return Qnil;
}
- method_slice =
- grpc_slice_from_copied_buffer(RSTRING_PTR(method), RSTRING_LEN(method));
+ method_slice = grpc_slice_from_copied_buffer(RSTRING_PTR(method), RSTRING_LEN(method));
call = grpc_channel_create_call(ch, parent_call, flags, cq, method_slice,
- host_slice_ptr,
- grpc_rb_time_timeval(deadline,
- /* absolute time */ 0),
- NULL);
+ host_slice_ptr, grpc_rb_time_timeval(
+ deadline,
+ /* absolute time */ 0), NULL);
if (call == NULL) {
tmp_str = grpc_slice_to_c_string(method_slice);
- rb_raise(rb_eRuntimeError, "cannot create call with method %s", tmp_str);
+ rb_raise(rb_eRuntimeError, "cannot create call with method %s",
+ tmp_str);
return Qnil;
}
@@ -387,6 +307,7 @@
return res;
}
+
/* Closes the channel, calling it's destroy method */
static VALUE grpc_rb_channel_destroy(VALUE self) {
grpc_rb_channel *wrapper = NULL;
@@ -395,18 +316,19 @@
TypedData_Get_Struct(self, grpc_rb_channel, &grpc_channel_data_type, wrapper);
ch = wrapper->wrapped;
if (ch != NULL) {
- grpc_rb_channel_safe_destroy(wrapper);
+ grpc_channel_destroy(ch);
wrapper->wrapped = NULL;
}
return Qnil;
}
+
/* Called to obtain the target that this channel accesses. */
static VALUE grpc_rb_channel_get_target(VALUE self) {
grpc_rb_channel *wrapper = NULL;
VALUE res = Qnil;
- char *target = NULL;
+ char* target = NULL;
TypedData_Get_Struct(self, grpc_rb_channel, &grpc_channel_data_type, wrapper);
target = grpc_channel_get_target(wrapper->wrapped);
@@ -416,122 +338,10 @@
return res;
}
-// Either start polling channel connection state or signal that it's free to
-// destroy.
-// Not safe to call while a channel's connection state is polled.
-static void grpc_rb_channel_try_register_connection_polling(
- grpc_rb_channel *wrapper) {
- grpc_connectivity_state conn_state;
- gpr_timespec sleep_time = gpr_time_add(
- gpr_now(GPR_CLOCK_REALTIME), gpr_time_from_millis(20, GPR_TIMESPAN));
-
- GPR_ASSERT(wrapper);
- GPR_ASSERT(wrapper->wrapped);
- gpr_mu_lock(&wrapper->channel_mu);
- if (wrapper->request_safe_destroy) {
- wrapper->safe_to_destroy = 1;
- gpr_cv_broadcast(&wrapper->channel_cv);
- gpr_mu_unlock(&wrapper->channel_mu);
- return;
- }
- gpr_mu_lock(&global_connection_polling_mu);
-
- conn_state = grpc_channel_check_connectivity_state(wrapper->wrapped, 0);
- if (conn_state != wrapper->current_connectivity_state) {
- wrapper->current_connectivity_state = conn_state;
- gpr_cv_broadcast(&wrapper->channel_cv);
- }
- // avoid posting work to the channel polling cq if it's been shutdown
- if (!abort_channel_polling && conn_state != GRPC_CHANNEL_SHUTDOWN) {
- grpc_channel_watch_connectivity_state(
- wrapper->wrapped, conn_state, sleep_time, channel_polling_cq, wrapper);
- } else {
- wrapper->safe_to_destroy = 1;
- gpr_cv_broadcast(&wrapper->channel_cv);
- }
- gpr_mu_unlock(&global_connection_polling_mu);
- gpr_mu_unlock(&wrapper->channel_mu);
-}
-
-// Note requires wrapper->wrapped, wrapper->channel_mu/cv initialized
-static void grpc_rb_channel_safe_destroy(grpc_rb_channel *wrapper) {
- gpr_mu_lock(&wrapper->channel_mu);
- wrapper->request_safe_destroy = 1;
-
- while (!wrapper->safe_to_destroy) {
- gpr_cv_wait(&wrapper->channel_cv, &wrapper->channel_mu,
- gpr_inf_future(GPR_CLOCK_REALTIME));
- }
- GPR_ASSERT(wrapper->safe_to_destroy);
- gpr_mu_unlock(&wrapper->channel_mu);
-
- grpc_channel_destroy(wrapper->wrapped);
-}
-
-// Note this loop breaks out with a single call of
-// "grpc_rb_event_unblocking_func".
-// This assumes that a ruby call the unblocking func
-// indicates process shutdown.
-// In the worst case, this stops polling channel connectivity
-// early and falls back to current behavior.
-static void *run_poll_channels_loop_no_gil(void *arg) {
- grpc_event event;
- (void)arg;
- for (;;) {
- event = grpc_completion_queue_next(
- channel_polling_cq, gpr_inf_future(GPR_CLOCK_REALTIME), NULL);
- if (event.type == GRPC_QUEUE_SHUTDOWN) {
- break;
- }
- if (event.type == GRPC_OP_COMPLETE) {
- grpc_rb_channel_try_register_connection_polling((grpc_rb_channel *)event.tag);
- }
- }
- grpc_completion_queue_destroy(channel_polling_cq);
- gpr_log(GPR_DEBUG, "GRPC_RUBY: run_poll_channels_loop_no_gil - exit connection polling loop");
- return NULL;
-}
-
-// Notify the channel polling loop to cleanup and shutdown.
-static void grpc_rb_event_unblocking_func(void *arg) {
- (void)arg;
- gpr_mu_lock(&global_connection_polling_mu);
- gpr_log(GPR_DEBUG, "GRPC_RUBY: grpc_rb_event_unblocking_func - begin aborting connection polling");
- abort_channel_polling = 1;
- grpc_completion_queue_shutdown(channel_polling_cq);
- gpr_mu_unlock(&global_connection_polling_mu);
-}
-
-// Poll channel connectivity states in background thread without the GIL.
-static VALUE run_poll_channels_loop(VALUE arg) {
- (void)arg;
- gpr_log(GPR_DEBUG, "GRPC_RUBY: run_poll_channels_loop - create connection polling thread");
- rb_thread_call_without_gvl(run_poll_channels_loop_no_gil, NULL,
- grpc_rb_event_unblocking_func, NULL);
- return Qnil;
-}
-
-/* Temporary fix for
- * https://github.com/GoogleCloudPlatform/google-cloud-ruby/issues/899.
- * Transports in idle channels can get destroyed. Normally c-core re-connects,
- * but in grpc-ruby core never gets a thread until an RPC is made, because ruby
- * only calls c-core's "completion_queu_pluck" API.
- * This uses a global background thread that calls
- * "completion_queue_next" on registered "watch_channel_connectivity_state"
- * calls - so that c-core can reconnect if needed, when there aren't any RPC's.
- * TODO(apolcyn) remove this when core handles new RPCs on dead connections.
- */
-static void start_poll_channels_loop() {
- channel_polling_cq = grpc_completion_queue_create(NULL);
- gpr_mu_init(&global_connection_polling_mu);
- abort_channel_polling = 0;
- rb_thread_create(run_poll_channels_loop, NULL);
-}
-
static void Init_grpc_propagate_masks() {
/* Constants representing call propagation masks in grpc.h */
- VALUE grpc_rb_mPropagateMasks =
- rb_define_module_under(grpc_rb_mGrpcCore, "PropagateMasks");
+ VALUE grpc_rb_mPropagateMasks = rb_define_module_under(
+ grpc_rb_mGrpcCore, "PropagateMasks");
rb_define_const(grpc_rb_mPropagateMasks, "DEADLINE",
UINT2NUM(GRPC_PROPAGATE_DEADLINE));
rb_define_const(grpc_rb_mPropagateMasks, "CENSUS_STATS_CONTEXT",
@@ -546,8 +356,8 @@
static void Init_grpc_connectivity_states() {
/* Constants representing call propagation masks in grpc.h */
- VALUE grpc_rb_mConnectivityStates =
- rb_define_module_under(grpc_rb_mGrpcCore, "ConnectivityStates");
+ VALUE grpc_rb_mConnectivityStates = rb_define_module_under(
+ grpc_rb_mGrpcCore, "ConnectivityStates");
rb_define_const(grpc_rb_mConnectivityStates, "IDLE",
LONG2NUM(GRPC_CHANNEL_IDLE));
rb_define_const(grpc_rb_mConnectivityStates, "CONNECTING",
@@ -575,11 +385,12 @@
/* Add ruby analogues of the Channel methods. */
rb_define_method(grpc_rb_cChannel, "connectivity_state",
- grpc_rb_channel_get_connectivity_state, -1);
+ grpc_rb_channel_get_connectivity_state,
+ -1);
rb_define_method(grpc_rb_cChannel, "watch_connectivity_state",
- grpc_rb_channel_watch_connectivity_state, 2);
- rb_define_method(grpc_rb_cChannel, "create_call", grpc_rb_channel_create_call,
- 5);
+ grpc_rb_channel_watch_connectivity_state, 4);
+ rb_define_method(grpc_rb_cChannel, "create_call",
+ grpc_rb_channel_create_call, 5);
rb_define_method(grpc_rb_cChannel, "target", grpc_rb_channel_get_target, 0);
rb_define_method(grpc_rb_cChannel, "destroy", grpc_rb_channel_destroy, 0);
rb_define_alias(grpc_rb_cChannel, "close", "destroy");
@@ -597,7 +408,6 @@
id_insecure_channel = rb_intern("this_channel_is_insecure");
Init_grpc_propagate_masks();
Init_grpc_connectivity_states();
- start_poll_channels_loop();
}
/* Gets the wrapped channel from the ruby wrapper */
diff --git a/src/ruby/spec/channel_connection_spec.rb b/src/ruby/spec/channel_connection_spec.rb
deleted file mode 100644
index 940d68b..0000000
--- a/src/ruby/spec/channel_connection_spec.rb
+++ /dev/null
@@ -1,141 +0,0 @@
-# Copyright 2015, 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.
-
-require 'grpc'
-
-# A test message
-class EchoMsg
- def self.marshal(_o)
- ''
- end
-
- def self.unmarshal(_o)
- EchoMsg.new
- end
-end
-
-# A test service with an echo implementation.
-class EchoService
- include GRPC::GenericService
- rpc :an_rpc, EchoMsg, EchoMsg
- attr_reader :received_md
-
- def initialize(**kw)
- @trailing_metadata = kw
- @received_md = []
- end
-
- def an_rpc(req, call)
- GRPC.logger.info('echo service received a request')
- call.output_metadata.update(@trailing_metadata)
- @received_md << call.metadata unless call.metadata.nil?
- req
- end
-end
-
-EchoStub = EchoService.rpc_stub_class
-
-def start_server(port = 0)
- @srv = GRPC::RpcServer.new
- server_port = @srv.add_http2_port("localhost:#{port}", :this_port_is_insecure)
- @srv.handle(EchoService)
- @server_thd = Thread.new { @srv.run }
- @srv.wait_till_running
- server_port
-end
-
-def stop_server
- expect(@srv.stopped?).to be(false)
- @srv.stop
- @server_thd.join
- expect(@srv.stopped?).to be(true)
-end
-
-describe 'channel connection behavior' do
- it 'the client channel handles temporary loss of a transport' do
- port = start_server
- stub = EchoStub.new("localhost:#{port}", :this_channel_is_insecure)
- req = EchoMsg.new
- expect(stub.an_rpc(req)).to be_a(EchoMsg)
- stop_server
- sleep 1
- # TODO(apolcyn) grabbing the same port might fail, is this stable enough?
- start_server(port)
- expect(stub.an_rpc(req)).to be_a(EchoMsg)
- stop_server
- end
-
- it 'observably connects and reconnects to transient server' \
- ' when using the channel state API' do
- port = start_server
- ch = GRPC::Core::Channel.new("localhost:#{port}", {},
- :this_channel_is_insecure)
-
- expect(ch.connectivity_state).to be(GRPC::Core::ConnectivityStates::IDLE)
-
- state = ch.connectivity_state(true)
-
- count = 0
- while count < 20 && state != GRPC::Core::ConnectivityStates::READY
- ch.watch_connectivity_state(state, Time.now + 60)
- state = ch.connectivity_state(true)
- count += 1
- end
-
- expect(state).to be(GRPC::Core::ConnectivityStates::READY)
-
- stop_server
-
- state = ch.connectivity_state
-
- count = 0
- while count < 20 && state == GRPC::Core::ConnectivityStates::READY
- ch.watch_connectivity_state(state, Time.now + 60)
- state = ch.connectivity_state
- count += 1
- end
-
- expect(state).to_not be(GRPC::Core::ConnectivityStates::READY)
-
- start_server(port)
-
- state = ch.connectivity_state(true)
-
- count = 0
- while count < 20 && state != GRPC::Core::ConnectivityStates::READY
- ch.watch_connectivity_state(state, Time.now + 60)
- state = ch.connectivity_state(true)
- count += 1
- end
-
- expect(state).to be(GRPC::Core::ConnectivityStates::READY)
-
- stop_server
- end
-end
diff --git a/src/ruby/spec/channel_spec.rb b/src/ruby/spec/channel_spec.rb
index a289a00..740eac6 100644
--- a/src/ruby/spec/channel_spec.rb
+++ b/src/ruby/spec/channel_spec.rb
@@ -153,35 +153,6 @@
end
end
- describe '#connectivity_state' do
- it 'returns an enum' do
- ch = GRPC::Core::Channel.new(fake_host, nil, :this_channel_is_insecure)
- valid_states = [
- GRPC::Core::ConnectivityStates::IDLE,
- GRPC::Core::ConnectivityStates::CONNECTING,
- GRPC::Core::ConnectivityStates::READY,
- GRPC::Core::ConnectivityStates::TRANSIENT_FAILURE,
- GRPC::Core::ConnectivityStates::FATAL_FAILURE
- ]
-
- expect(valid_states).to include(ch.connectivity_state)
- end
-
- it 'returns an enum when trying to connect' do
- ch = GRPC::Core::Channel.new(fake_host, nil, :this_channel_is_insecure)
- ch.connectivity_state(true)
- valid_states = [
- GRPC::Core::ConnectivityStates::IDLE,
- GRPC::Core::ConnectivityStates::CONNECTING,
- GRPC::Core::ConnectivityStates::READY,
- GRPC::Core::ConnectivityStates::TRANSIENT_FAILURE,
- GRPC::Core::ConnectivityStates::FATAL_FAILURE
- ]
-
- expect(valid_states).to include(ch.connectivity_state)
- end
- end
-
describe '::SSL_TARGET' do
it 'is a symbol' do
expect(GRPC::Core::Channel::SSL_TARGET).to be_a(Symbol)
diff --git a/tools/run_tests/helper_scripts/run_ruby_end2end_tests.sh b/tools/run_tests/helper_scripts/run_ruby_end2end_tests.sh
index 92d6975..b3a7336 100755
--- a/tools/run_tests/helper_scripts/run_ruby_end2end_tests.sh
+++ b/tools/run_tests/helper_scripts/run_ruby_end2end_tests.sh
@@ -35,8 +35,5 @@
EXIT_CODE=0
ruby src/ruby/end2end/sig_handling_driver.rb || EXIT_CODE=1
-ruby src/ruby/end2end/channel_state_driver.rb || EXIT_CODE=1
-ruby src/ruby/end2end/channel_closing_driver.rb || EXIT_CODE=1
-ruby src/ruby/end2end/sig_int_during_channel_watch_driver.rb || EXIT_CODE=1
ruby src/ruby/end2end/killed_client_thread_driver.rb || EXIT_CODE=1
exit $EXIT_CODE