Repository: qpid-proton Updated Branches: refs/heads/master 188ce2806 -> 99564eb3c
PROTON-1830: [ruby] container sometimes fails to close listener Fix race condition where the container might not close a listener if stopped by an exception. Was causing this sporadic failure: ContainerTest#test_handler_raise [/home/travis/build/alanconway/qpid-proton/ruby/tests/test_container.rb:328]: Expected false to be truthy. Project: http://git-wip-us.apache.org/repos/asf/qpid-proton/repo Commit: http://git-wip-us.apache.org/repos/asf/qpid-proton/commit/57a22ca9 Tree: http://git-wip-us.apache.org/repos/asf/qpid-proton/tree/57a22ca9 Diff: http://git-wip-us.apache.org/repos/asf/qpid-proton/diff/57a22ca9 Branch: refs/heads/master Commit: 57a22ca99b90daa4544381fe190a3491388dfbbd Parents: 188ce28 Author: Alan Conway <acon...@redhat.com> Authored: Fri Apr 13 14:36:17 2018 -0400 Committer: Alan Conway <acon...@redhat.com> Committed: Fri Apr 13 15:01:06 2018 -0400 ---------------------------------------------------------------------- ruby/lib/core/container.rb | 33 ++++++++++++++++++++++----------- ruby/lib/core/listener.rb | 14 ++++++++++---- 2 files changed, 32 insertions(+), 15 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/57a22ca9/ruby/lib/core/container.rb ---------------------------------------------------------------------- diff --git a/ruby/lib/core/container.rb b/ruby/lib/core/container.rb index 7d9f2cb..fb0acdc 100644 --- a/ruby/lib/core/container.rb +++ b/ruby/lib/core/container.rb @@ -163,7 +163,7 @@ module Qpid::Proton not_stopped l = ListenTask.new(io, handler, self) add(l) - l + l.listener end # Run the container: wait for IO activity, dispatch events to handlers. @@ -275,8 +275,8 @@ module Qpid::Proton class ListenTask < Listener def initialize(io, handler, container) - super - @closing = @closed = nil + @io, @handler = io, handler + @listener = Listener.new(io, container) env = ENV['PN_TRACE_EVT'] if env && ["true", "1", "yes", "on"].include?(env.downcase) @log_prefix = "[0x#{object_id.to_s(16)}](PN_LISTENER_" @@ -286,28 +286,33 @@ module Qpid::Proton dispatch(:on_open); end + attr_reader :listener + def closing?() @listener.instance_variable_get(:@closing); end + def condition() @listener.instance_variable_get(:@condition); end + def closed?() @io.closed?; end + def process - return if @closed - unless @closing + return if closed? + unless closing? begin return @io.accept, dispatch(:on_accept) rescue IO::WaitReadable, Errno::EINTR - rescue IOError, SystemCallError => e - close e + rescue StandardError => e + @listener.close(e) end end ensure - if @closing + if closing? @io.close rescue nil - @closed = true - dispatch(:on_error, @condition) if @condition + @listener.instance_variable_set(:@closed, true) + dispatch(:on_error, condition) if condition dispatch(:on_close) end end def can_read?() !finished?; end def can_write?() false; end - def finished?() @closed; end + def finished?() closed?; end def dispatch(method, *args) # TODO aconway 2017-11-27: better logging @@ -316,6 +321,12 @@ module Qpid::Proton end def next_tick() nil; end + + # Close listener and force immediate close of socket + def close(e=nil) + @listener.close(e) + @io.close rescue nil + end end # Selectable object that can be used to wake IO.select from another thread http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/57a22ca9/ruby/lib/core/listener.rb ---------------------------------------------------------------------- diff --git a/ruby/lib/core/listener.rb b/ruby/lib/core/listener.rb index 82c711a..f7f7d67 100644 --- a/ruby/lib/core/listener.rb +++ b/ruby/lib/core/listener.rb @@ -63,12 +63,14 @@ module Qpid::Proton # @return [Condition] The error condition if there is one attr_reader :condition - # Close the listener + # Initiate closing the the listener. + # It will not be fully {#closed?} until its {Handler#on_close} is called by the {Container} # @param error [Condition] Optional error condition. def close(error=nil) + return if closed? || @closing @closing = true @condition ||= Condition.convert error - @io.close_read rescue nil # Cause listener to wake out of IO.select + @io.close_read rescue nil # Force Container IO.select to wake with listener readable. nil end @@ -78,11 +80,15 @@ module Qpid::Proton # Get the IP port used by the listener def port() to_io.addr[1]; end + # True if the listening socket is fully closed + def closed?() @io.closed?; end + private # Called by {Container} - def initialize(io, handler, container) - @io, @handler = io, handler + def initialize(io, container) + @io = io @container = container + @closing = nil end end end --------------------------------------------------------------------- To unsubscribe, e-mail: commits-unsubscr...@qpid.apache.org For additional commands, e-mail: commits-h...@qpid.apache.org