diff options
author | Jean Boussier <jean.boussier@gmail.com> | 2022-07-07 15:20:35 +0200 |
---|---|---|
committer | Jean Boussier <jean.boussier@gmail.com> | 2022-07-07 17:49:00 +0200 |
commit | 587d2d199b3f783d03266d42d066949f8a4824d3 (patch) | |
tree | 6977cca9dc954a2fa4a87dc1b7f1f0aa5bc8786b /test/-ext- | |
parent | 61c7ae4d27d44b19b39fa240cf7edda2eeefc92d (diff) | |
download | ruby-587d2d199b3f783d03266d42d066949f8a4824d3.tar.gz |
thread_pthread.c: call SUSPENDED event when entering native_sleep
[Bug #18900]
Thread#join and a few other codepaths are using native sleep as
a way to suspend the current thread. So we should call the relevant
hook when this happen, otherwise some thread may transition
directly from `RESUMED` to `READY`.
Diffstat (limited to 'test/-ext-')
-rw-r--r-- | test/-ext-/thread/test_instrumentation_api.rb | 102 |
1 files changed, 54 insertions, 48 deletions
diff --git a/test/-ext-/thread/test_instrumentation_api.rb b/test/-ext-/thread/test_instrumentation_api.rb index fe91c942c7..78e499c473 100644 --- a/test/-ext-/thread/test_instrumentation_api.rb +++ b/test/-ext-/thread/test_instrumentation_api.rb @@ -3,76 +3,82 @@ require 'envutil' class TestThreadInstrumentation < Test::Unit::TestCase def setup - pend("TODO: No windows support yet") if /mswin|mingw|bccwin/ =~ RUBY_PLATFORM - end - - THREADS_COUNT = 3 + pend("No windows support") if /mswin|mingw|bccwin/ =~ RUBY_PLATFORM - def test_thread_instrumentation require '-test-/thread/instrumentation' Bug::ThreadInstrumentation.reset_counters Bug::ThreadInstrumentation::register_callback + end - begin - threads = threaded_cpu_work - assert_equal [false] * THREADS_COUNT, threads.map(&:status) - counters = Bug::ThreadInstrumentation.counters - counters.each do |c| - assert_predicate c, :nonzero?, "Call counters: #{counters.inspect}" - end - - assert_equal THREADS_COUNT, counters.first - assert_in_delta THREADS_COUNT, counters.last, 1 # It's possible that a thread didn't execute its EXIT hook yet. - ensure - Bug::ThreadInstrumentation::unregister_callback + def teardown + return if /mswin|mingw|bccwin/ =~ RUBY_PLATFORM + Bug::ThreadInstrumentation::unregister_callback + end + + THREADS_COUNT = 3 + + def test_thread_instrumentation + threads = threaded_cpu_work + assert_equal [false] * THREADS_COUNT, threads.map(&:status) + counters = Bug::ThreadInstrumentation.counters + counters.each do |c| + assert_predicate c, :nonzero?, "Call counters: #{counters.inspect}" end + + assert_equal THREADS_COUNT, counters.first + assert_in_delta THREADS_COUNT, counters.last, 1 # It's possible that a thread didn't execute its EXIT hook yet. + end + + def test_join_counters # Bug #18900 + thr = Thread.new { fib(30) } + Bug::ThreadInstrumentation.reset_counters + thr.join + assert_equal [1, 1, 1], Bug::ThreadInstrumentation.local_counters end def test_thread_instrumentation_fork_safe skip "No fork()" unless Process.respond_to?(:fork) - require '-test-/thread/instrumentation' - Bug::ThreadInstrumentation::register_callback - read_pipe, write_pipe = IO.pipe - begin - pid = fork do - Bug::ThreadInstrumentation.reset_counters - threads = threaded_cpu_work - write_pipe.write(Marshal.dump(threads.map(&:status))) - write_pipe.write(Marshal.dump(Bug::ThreadInstrumentation.counters)) - write_pipe.close - exit!(0) - end + pid = fork do + Bug::ThreadInstrumentation.reset_counters + threads = threaded_cpu_work + write_pipe.write(Marshal.dump(threads.map(&:status))) + write_pipe.write(Marshal.dump(Bug::ThreadInstrumentation.counters)) write_pipe.close - _, status = Process.wait2(pid) - assert_predicate status, :success? - - thread_statuses = Marshal.load(read_pipe) - assert_equal [false] * THREADS_COUNT, thread_statuses - - counters = Marshal.load(read_pipe) - read_pipe.close - counters.each do |c| - assert_predicate c, :nonzero?, "Call counters: #{counters.inspect}" - end - - assert_equal THREADS_COUNT, counters.first - assert_in_delta THREADS_COUNT, counters.last, 1 # It's possible that a thread didn't execute its EXIT hook yet. - ensure - Bug::ThreadInstrumentation::unregister_callback + exit!(0) end + write_pipe.close + _, status = Process.wait2(pid) + assert_predicate status, :success? + + thread_statuses = Marshal.load(read_pipe) + assert_equal [false] * THREADS_COUNT, thread_statuses + + counters = Marshal.load(read_pipe) + read_pipe.close + counters.each do |c| + assert_predicate c, :nonzero?, "Call counters: #{counters.inspect}" + end + + assert_equal THREADS_COUNT, counters.first + assert_in_delta THREADS_COUNT, counters.last, 1 # It's possible that a thread didn't execute its EXIT hook yet. end def test_thread_instrumentation_unregister - require '-test-/thread/instrumentation' + Bug::ThreadInstrumentation::unregister_callback assert Bug::ThreadInstrumentation::register_and_unregister_callbacks end private - def threaded_cpu_work - THREADS_COUNT.times.map { Thread.new { 100.times { |i| i + i } } }.each(&:join) + def fib(n = 20) + return n if n <= 1 + fib(n-1) + fib(n-2) + end + + def threaded_cpu_work(size = 20) + THREADS_COUNT.times.map { Thread.new { fib(size) } }.each(&:join) end end |