diff --git a/mjit.c b/mjit.c index 3ae9410179..69dc23442b 100644 --- a/mjit.c +++ b/mjit.c @@ -802,7 +802,9 @@ mjit_pause(bool wait_p) } } + mjit_pause_wait_p = wait_p; // Avoid cancelling the last compilation after the unit fetch if wait_p. stop_worker(); + mjit_pause_wait_p = false; return Qtrue; } diff --git a/mjit_worker.c b/mjit_worker.c index 516dd87422..cc19e2760b 100644 --- a/mjit_worker.c +++ b/mjit_worker.c @@ -210,6 +210,8 @@ static bool in_jit; static bool stop_worker_p; // Set to true if worker is stopped. static bool worker_stopped; +// Set to true only when worker is being stopped for `RubyVM::MJIT.pause(wait: true)`. +static bool mjit_pause_wait_p; // Path of "/tmp", which can be changed to $TMP in MinGW. static char *tmp_dir; @@ -1225,9 +1227,10 @@ mjit_worker(void) mjit_func_t func = convert_unit_to_func(unit); (void)RB_DEBUG_COUNTER_INC_IF(mjit_compile_failures, func == (mjit_func_t)NOT_COMPILED_JIT_ISEQ_FUNC); - // `mjit_copy_cache_from_main_thread` in `mjit_compile` may wait for a long time - // and worker may be stopped during the compilation. - if (stop_worker_p) + // Checking `stop_worker_p` here because `mjit_copy_cache_from_main_thread` in `mjit_compile` may wait + // for a long time and worker may be stopped during the compilation. + // However, we do not want to stop here when the `stop_worker()` is from `MJIT.pause(wait: true)`. + if (stop_worker_p && !mjit_pause_wait_p) break; CRITICAL_SECTION_START(3, "in jit func replace"); diff --git a/test/lib/jit_support.rb b/test/lib/jit_support.rb index acda166eb2..fc5c12e871 100644 --- a/test/lib/jit_support.rb +++ b/test/lib/jit_support.rb @@ -3,6 +3,7 @@ require 'rbconfig' module JITSupport JIT_TIMEOUT = 600 # 10min for each... JIT_SUCCESS_PREFIX = 'JIT success \(\d+\.\dms\)' + JIT_COMPACTION_PREFIX = 'JIT compaction \(\d+\.\dms\)' UNSUPPORTED_COMPILERS = [ %r[\Aicc\b], %r[\A/opt/developerstudio\d+\.\d+/bin/cc\z], diff --git a/test/ruby/test_rubyvm_mjit.rb b/test/ruby/test_rubyvm_mjit.rb index 12772320f5..ef7475670c 100644 --- a/test/ruby/test_rubyvm_mjit.rb +++ b/test/ruby/test_rubyvm_mjit.rb @@ -35,6 +35,22 @@ class TestRubyVMMJIT < Test::Unit::TestCase ) end + def test_pause_waits_until_compaction + out, err = eval_with_jit(<<~'EOS', verbose: 1, min_calls: 1, wait: false) + def a() end; a + def b() end; b + RubyVM::MJIT.pause + EOS + assert_equal( + 2, err.scan(/#{JITSupport::JIT_SUCCESS_PREFIX}/).size, + "unexpected stdout:\n```\n#{out}```\n\nstderr:\n```\n#{err}```", + ) + assert_equal( + 1, err.scan(/#{JITSupport::JIT_COMPACTION_PREFIX}/).size, + "unexpected stdout:\n```\n#{out}```\n\nstderr:\n```\n#{err}```", + ) unless RUBY_PLATFORM.match?(/mswin|mingw/) # compaction is not supported on Windows yet + end + def test_pause_does_not_hang_on_full_units out, _ = eval_with_jit(<<~'EOS', verbose: 1, min_calls: 1, max_cache: 10, wait: false) i = 0