diff --git a/test/ruby/test_sleep.rb b/test/ruby/test_sleep.rb index 991b73ebd50757..7ef962db4a3b6b 100644 --- a/test/ruby/test_sleep.rb +++ b/test/ruby/test_sleep.rb @@ -1,6 +1,7 @@ # frozen_string_literal: false require 'test/unit' require 'etc' +require 'timeout' class TestSleep < Test::Unit::TestCase def test_sleep_5sec @@ -13,4 +14,21 @@ def test_sleep_5sec assert_operator(slept, :<=, 6.0, "[ruby-core:18015]: longer than expected") end end + + def test_sleep_forever_not_woken_by_sigchld + begin + t = Thread.new do + sleep 0.5 + `echo hello` + end + + assert_raise Timeout::Error do + Timeout.timeout 2 do + sleep # Should block forever + end + end + ensure + t.join + end + end end diff --git a/thread_pthread.c b/thread_pthread.c index a2e42da13e70b1..9c7754067bcdf9 100644 --- a/thread_pthread.c +++ b/thread_pthread.c @@ -1109,10 +1109,9 @@ thread_sched_to_waiting_until_wakeup(struct rb_thread_sched *sched, rb_thread_t { if (!RUBY_VM_INTERRUPTED(th->ec)) { bool can_direct_transfer = !th_has_dedicated_nt(th); - th->status = THREAD_STOPPED_FOREVER; + // NOTE: th->status is set before and after this sleep outside of this function in `sleep_forever` thread_sched_wakeup_next_thread(sched, th, can_direct_transfer); thread_sched_wait_running_turn(sched, th, can_direct_transfer); - th->status = THREAD_RUNNABLE; } else { RUBY_DEBUG_LOG("th:%u interrupted", rb_th_serial(th));