diff options
| author | Luke Gruber <luke.gruber@shopify.com> | 2026-02-06 14:26:07 -0500 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2026-02-06 14:26:07 -0500 |
| commit | 7b3370a5579956404d742a2e104d72e7c89480e4 (patch) | |
| tree | aef21dbdc1071771da877a752d9e8a25bdf315a5 /test/ruby | |
| parent | 130c37d6e60b0b654b93cb09c37b18718e35c0b9 (diff) | |
Wake timer to create new SNT when needed for dedicated task (#16009)
When removing a thread from `running_threads`, if we're on a shared
native thread and we're running a dedicated task, we need to wake
the timer thread so it can create a new SNT if necessary. We only
do this if it's waiting forever without the 10ms quantum timeout
for now, because max 10ms of wait is considered "good enough".
In the future, perhaps we can force the timer thread to wake if this
becomes an issue (`timer_thread_wakeup_force`).
Fixes [Bug #21504]
Diffstat (limited to 'test/ruby')
| -rw-r--r-- | test/ruby/test_ractor.rb | 39 |
1 files changed, 39 insertions, 0 deletions
diff --git a/test/ruby/test_ractor.rb b/test/ruby/test_ractor.rb index 6ae511217a..d449f9f814 100644 --- a/test/ruby/test_ractor.rb +++ b/test/ruby/test_ractor.rb @@ -201,6 +201,45 @@ class TestRactor < Test::Unit::TestCase RUBY end + def test_timer_thread_create_snt_for_dedicated_task + omit "timer thread works differently" if windows? + omit "test relies on this as a best-effort safety mechanism" unless defined?(Process::WNOHANG) + assert_separately([{ "RUBY_MAX_CPU" => "2" }], <<~'RUBY', timeout: 30) + $VERBOSE = nil + CHILD_PID = 0 + + rs = [] + 2.times do |i| + rs << Ractor.new(i) do |j| + if j == 0 + pid = spawn("sleep 60", close_others: true) + Object.const_set(:CHILD_PID, pid) + Process.waitpid(pid) # block forever (dedicated task) + else + while CHILD_PID == 0 + sleep 1 # make sure first ractor blocks forever first (this is what we're testing) + end + 1_000.times do + [nil] * 100 + end + end + end + end + + rs.last.join + begin + result = Process.waitpid(CHILD_PID, Process::WNOHANG) + rescue Errno::ECHILD, Errno::ESRCH + # If it's somehow not a child (not running?), don't send it a signal + else + if result.nil? + Process.kill('KILL', CHILD_PID) rescue nil + end + end + rs.first.join # reap + RUBY + end + def test_symbol_proc_is_shareable pr = :symbol.to_proc assert_make_shareable(pr) |
