[前][次][番号順一覧][スレッド一覧]

ruby-changes:58959

From: Koichi <ko1@a...>
Date: Fri, 29 Nov 2019 18:24:47 +0900 (JST)
Subject: [ruby-changes:58959] 36da0b3da1 (master): check interrupts at each frame pop timing.

https://git.ruby-lang.org/ruby.git/commit/?id=36da0b3da1

From 36da0b3da1aed77e0dffb3f54038f01ff574972b Mon Sep 17 00:00:00 2001
From: Koichi Sasada <ko1@a...>
Date: Fri, 29 Nov 2019 17:39:06 +0900
Subject: check interrupts at each frame pop timing.

Asynchronous events such as signal trap, finalization timing,
thread switching and so on are managed by "interrupt_flag".
Ruby's threads check this flag periodically and if a thread
does not check this flag, above events doesn't happen.

This checking is CHECK_INTS() (related) macro and it is placed
at some places (laeve instruction and so on). However, at the end
of C methods, C blocks (IMEMO_IFUNC) etc there are no checking
and it can introduce uninterruptible thread.

To modify this situation, we decide to place CHECK_INTS() at
vm_pop_frame(). It increases interrupt checking points.
[Bug #16366]

This patch can introduce unexpected events...

diff --git a/enum.c b/enum.c
index a411449..7606e58 100644
--- a/enum.c
+++ b/enum.c
@@ -543,7 +543,6 @@ collect_i(RB_BLOCK_CALL_FUNC_ARGLIST(i, ary)) https://github.com/ruby/ruby/blob/trunk/enum.c#L543
 static VALUE
 collect_all(RB_BLOCK_CALL_FUNC_ARGLIST(i, ary))
 {
-    rb_thread_check_ints();
     rb_ary_push(ary, rb_enum_values_pack(argc, argv));
 
     return Qnil;
@@ -663,14 +662,12 @@ static VALUE https://github.com/ruby/ruby/blob/trunk/enum.c#L662
 enum_to_h_i(RB_BLOCK_CALL_FUNC_ARGLIST(i, hash))
 {
     ENUM_WANT_SVALUE();
-    rb_thread_check_ints();
     return rb_hash_set_pair(hash, i);
 }
 
 static VALUE
 enum_to_h_ii(RB_BLOCK_CALL_FUNC_ARGLIST(i, hash))
 {
-    rb_thread_check_ints();
     return rb_hash_set_pair(hash, rb_yield_values2(argc, argv));
 }
 
diff --git a/ext/-test-/postponed_job/postponed_job.c b/ext/-test-/postponed_job/postponed_job.c
index 157230e..d8684d4 100644
--- a/ext/-test-/postponed_job/postponed_job.c
+++ b/ext/-test-/postponed_job/postponed_job.c
@@ -1,19 +1,28 @@ https://github.com/ruby/ruby/blob/trunk/ext/-test-/postponed_job/postponed_job.c#L1
 #include "ruby.h"
 #include "ruby/debug.h"
 
+static int counter;
+
 static void
 pjob_callback(void *data)
 {
     VALUE ary = (VALUE)data;
     Check_Type(ary, T_ARRAY);
 
-    rb_ary_replace(ary, rb_funcall(Qnil, rb_intern("caller"), 0));
+    rb_ary_push(ary, INT2FIX(counter));
 }
 
 static VALUE
 pjob_register(VALUE self, VALUE obj)
 {
+    counter = 0;
     rb_postponed_job_register(0, pjob_callback, (void *)obj);
+    rb_gc_start();
+    counter++;
+    rb_gc_start();
+    counter++;
+    rb_gc_start();
+    counter++;
     return self;
 }
 
@@ -38,7 +47,14 @@ pjob_register_one(VALUE self, VALUE obj) https://github.com/ruby/ruby/blob/trunk/ext/-test-/postponed_job/postponed_job.c#L47
 static VALUE
 pjob_call_direct(VALUE self, VALUE obj)
 {
+    counter = 0;
     pjob_callback((void *)obj);
+    rb_gc_start();
+    counter++;
+    rb_gc_start();
+    counter++;
+    rb_gc_start();
+    counter++;
     return self;
 }
 
diff --git a/insns.def b/insns.def
index 39b0554..9bad676 100644
--- a/insns.def
+++ b/insns.def
@@ -935,8 +935,6 @@ leave https://github.com/ruby/ruby/blob/trunk/insns.def#L935
 	}
     }
 
-    RUBY_VM_CHECK_INTS(ec);
-
     if (vm_pop_frame(ec, GET_CFP(), GET_EP())) {
 #if OPT_CALL_THREADED_CODE
 	rb_ec_thread_ptr(ec)->retval = val;
@@ -963,7 +961,6 @@ throw https://github.com/ruby/ruby/blob/trunk/insns.def#L961
 /* Same discussion as leave. */
 // attr bool leaf = false; /* has rb_threadptr_execute_interrupts() */
 {
-    RUBY_VM_CHECK_INTS(ec);
     val = vm_throw(ec, GET_CFP(), throw_state, throwobj);
     THROW_EXCEPTION(val);
     /* unreachable */
diff --git a/spec/ruby/core/thread/raise_spec.rb b/spec/ruby/core/thread/raise_spec.rb
index 3857185..88a96d5 100644
--- a/spec/ruby/core/thread/raise_spec.rb
+++ b/spec/ruby/core/thread/raise_spec.rb
@@ -138,11 +138,14 @@ describe "Thread#raise on a running thread" do https://github.com/ruby/ruby/blob/trunk/spec/ruby/core/thread/raise_spec.rb#L138
   end
 
   it "can go unhandled" do
+    q = Queue.new
     t = Thread.new do
       Thread.current.report_on_exception = false
+      q << true
       loop { Thread.pass }
     end
 
+    q.pop # wait for `report_on_exception = false`.
     t.raise
     -> { t.value }.should raise_error(RuntimeError)
   end
diff --git a/test/-ext-/postponed_job/test_postponed_job.rb b/test/-ext-/postponed_job/test_postponed_job.rb
index 978b728..7dc2877 100644
--- a/test/-ext-/postponed_job/test_postponed_job.rb
+++ b/test/-ext-/postponed_job/test_postponed_job.rb
@@ -19,8 +19,8 @@ class TestPostponed_job < Test::Unit::TestCase https://github.com/ruby/ruby/blob/trunk/test/-ext-/postponed_job/test_postponed_job.rb#L19
     Bug.postponed_job_call_direct_wrapper(direct)
     Bug.postponed_job_register_wrapper(registered)
 
-    assert_match(     /postponed_job_call_direct_wrapper/, direct.join)
-    assert_not_match( /postponed_job_register_wrapper/, registered.join)
+    assert_equal([0], direct)
+    assert_equal([3], registered)
 
     Bug.postponed_job_register_one(ary = [])
     assert_equal [1], ary
diff --git a/test/ruby/test_thread.rb b/test/ruby/test_thread.rb
index adfad7e..9d62059 100644
--- a/test/ruby/test_thread.rb
+++ b/test/ruby/test_thread.rb
@@ -816,17 +816,19 @@ class TestThread < Test::Unit::TestCase https://github.com/ruby/ruby/blob/trunk/test/ruby/test_thread.rb#L816
   def test_handle_interrupt_and_io
     assert_in_out_err([], <<-INPUT, %w(ok), [])
       th_waiting = true
+      q = Queue.new
 
       t = Thread.new {
         Thread.current.report_on_exception = false
         Thread.handle_interrupt(RuntimeError => :on_blocking) {
+          q << true
           nil while th_waiting
           # async interrupt should be raised _before_ writing puts arguments
           puts "ng"
         }
       }
 
-      Thread.pass while t.stop?
+      q.pop
       t.raise RuntimeError
       th_waiting = false
       t.join rescue nil
diff --git a/vm_insnhelper.c b/vm_insnhelper.c
index 9eb349d..1c54de6 100644
--- a/vm_insnhelper.c
+++ b/vm_insnhelper.c
@@ -354,6 +354,7 @@ vm_pop_frame(rb_execution_context_t *ec, rb_control_frame_t *cfp, const VALUE *e https://github.com/ruby/ruby/blob/trunk/vm_insnhelper.c#L354
     if (VM_CHECK_MODE >= 4) rb_gc_verify_internal_consistency();
     if (VMDEBUG == 2)       SDR();
 
+    RUBY_VM_CHECK_INTS(ec);
     ec->cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(cfp);
 
     return flags & VM_FRAME_FLAG_FINISH;
@@ -2318,7 +2319,6 @@ vm_call_iseq_setup_tailcall(rb_execution_context_t *ec, rb_control_frame_t *cfp, https://github.com/ruby/ruby/blob/trunk/vm_insnhelper.c#L2319
 		  iseq->body->stack_max);
 
     cfp->sp = sp_orig;
-    RUBY_VM_CHECK_INTS(ec);
 
     return Qundef;
 }
-- 
cgit v0.10.2


--
ML: ruby-changes@q...
Info: http://www.atdot.net/~ko1/quickml/

[前][次][番号順一覧][スレッド一覧]