From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on dcvr.yhbt.net X-Spam-Level: X-Spam-ASN: AS12876 163.172.0.0/16 X-Spam-Status: No, score=0.3 required=3.0 tests=AWL,BAYES_00,RCVD_IN_MSPIKE_BL, RCVD_IN_MSPIKE_ZBI,RCVD_IN_XBL,SPF_FAIL,SPF_HELO_FAIL shortcircuit=no autolearn=no autolearn_force=no version=3.4.0 Received: from 80x24.org (tor-exit-readme.memcpy.io [163.172.67.180]) by dcvr.yhbt.net (Postfix) with ESMTP id A041B1FAEB for ; Wed, 7 Jun 2017 19:59:16 +0000 (UTC) From: Eric Wong To: spew@80x24.org Subject: [PATCH 2/2] IO#close: do not enqueue redundant interrupts (take #2) Date: Wed, 7 Jun 2017 19:59:01 +0000 Message-Id: <20170607195901.18958-3-e@80x24.org> In-Reply-To: <20170607195901.18958-1-e@80x24.org> References: <20170607195901.18958-1-e@80x24.org> List-Id: From: normal 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. * 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 This is a backport of r59028 from trunk. --- test/ruby/test_io.rb | 22 ++++++++++++++++++++++ thread.c | 10 ++++++++-- 2 files changed, 30 insertions(+), 2 deletions(-) diff --git a/test/ruby/test_io.rb b/test/ruby/test_io.rb index 61dfba3180..034dac570c 100644 --- a/test/ruby/test_io.rb +++ b/test/ruby/test_io.rb @@ -2809,6 +2809,28 @@ def test_cross_thread_close_stdio 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]' diff --git a/thread.c b/thread.c index 2a82d33c42..cf70f59f3e 100644 --- a/thread.c +++ b/thread.c @@ -2210,10 +2210,16 @@ rb_notify_fd_close(int fd) 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_closed_stream]; + VALUE err; + + busy = 1; + if (!th) { + continue; + } + wfd->th = 0; + err = th->vm->special_exceptions[ruby_error_closed_stream]; rb_threadptr_pending_interrupt_enque(th, err); rb_threadptr_interrupt(th); - busy = 1; } } return busy; -- EW