ruby-changes:46914
From: normal <ko1@a...>
Date: Wed, 7 Jun 2017 07:55:43 +0900 (JST)
Subject: [ruby-changes:46914] normal:r59028 (trunk): IO#close: do not enqueue redundant interrupts (take #2)
normal 2017-06-07 07:55:35 +0900 (Wed, 07 Jun 2017) New Revision: 59028 https://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=revision&revision=59028 Log: IO#close: do not enqueue redundant interrupts (take #2) Enqueuing multiple errors for one event causes spurious errors down the line, as reported by Nikolay Vashchenko in https://bugs.ruby-lang.org/issues/13632 This should fix bad interactions with test_race_gets_and_close in test/ruby/test_io.rb since we ensure rb_notify_fd_close continues returning the busy flag after enqueuing the interrupt. Backporting changes to 2.4 and earlier releases will be more challenging... * thread.c (rb_notify_fd_close): do not enqueue multiple interrupts [ruby-core:81581] [Bug #13632] * test/ruby/test_io.rb (test_single_exception_on_close): new test based on script from Nikolay Modified files: trunk/test/ruby/test_io.rb trunk/thread.c Index: test/ruby/test_io.rb =================================================================== --- test/ruby/test_io.rb (revision 59027) +++ test/ruby/test_io.rb (revision 59028) @@ -2823,6 +2823,28 @@ __END__ https://github.com/ruby/ruby/blob/trunk/test/ruby/test_io.rb#L2823 end; end + def test_single_exception_on_close + a = [] + t = [] + 10.times do + r, w = IO.pipe + a << [r, w] + t << Thread.new do + while r.gets + end rescue IOError + Thread.current.pending_interrupt? + end + end + a.each do |r, w| + w.write -"\n" + w.close + r.close + end + t.each do |th| + assert_equal false, th.value, '[ruby-core:81581] [Bug #13632]' + end + end + def test_open_mode feature4742 = "[ruby-core:36338]" bug6055 = '[ruby-dev:45268]' Index: thread.c =================================================================== --- thread.c (revision 59027) +++ thread.c (revision 59028) @@ -2212,10 +2212,16 @@ rb_notify_fd_close(int fd) https://github.com/ruby/ruby/blob/trunk/thread.c#L2212 list_for_each(&vm->waiting_fds, wfd, wfd_node) { if (wfd->fd == fd) { rb_thread_t *th = wfd->th; - VALUE err = th->vm->special_exceptions[ruby_error_stream_closed]; + VALUE err; + + busy = 1; + if (!th) { + continue; + } + wfd->th = 0; + err = th->vm->special_exceptions[ruby_error_stream_closed]; rb_threadptr_pending_interrupt_enque(th, err); rb_threadptr_interrupt(th); - busy = 1; } } return busy; -- ML: ruby-changes@q... Info: http://www.atdot.net/~ko1/quickml/