diff options
| author | Stan Hu <stanhu@gmail.com> | 2024-05-17 17:05:48 +0900 |
|---|---|---|
| committer | nagachika <nagachika@ruby-lang.org> | 2024-08-18 18:02:09 +0900 |
| commit | 65fed1c3e439bc47bcf6ec884431a86cb9ebd1dc (patch) | |
| tree | 236e877de69232fc2b0adc30bf959d680b8eac46 /test/ruby/test_process.rb | |
| parent | 50399eebd96c76ce808ea4d84fe39693f585a531 (diff) | |
Allow waitpid(-1, Process::WNOHANG) to be woken if a waitpid(pid) is
...pending
If two threads are running, with one calling waitpid(-1, Process::WNOHANG),
and another calling waitpid($some_pid), and then
$some_other_pid exits, we would expect the waitpid(-1,
Process::WNOHANG) call to retrieve that exit status. However, it
cannot actually do so until $some_pid _also_ exits.
This patch fixes the issue by calling do_waitpid unconditionally in
waitpid_wait; this will ensure that a waitpid -1 actually reaps
something (after first checking that no PID-directed call wants the
process).
[Bug #20490]
Diffstat (limited to 'test/ruby/test_process.rb')
| -rw-r--r-- | test/ruby/test_process.rb | 30 |
1 files changed, 27 insertions, 3 deletions
diff --git a/test/ruby/test_process.rb b/test/ruby/test_process.rb index 1228f2c0b1..8e1c3a0d47 100644 --- a/test/ruby/test_process.rb +++ b/test/ruby/test_process.rb @@ -2659,7 +2659,7 @@ EOS end; end if Process.respond_to?(:_fork) - def test_concurrent_group_and_pid_wait + def _test_concurrent_group_and_pid_wait(nohang) # Use a pair of pipes that will make long_pid exit when this test exits, to avoid # leaking temp processes. long_rpipe, long_wpipe = IO.pipe @@ -2681,10 +2681,26 @@ EOS end # Wait for us to be blocking in a call to waitpid2 Thread.pass until t1.stop? + assert_nil Process.waitpid(-1, Process::WNOHANG) short_wpipe.close # Make short_pid exit - # The short pid has exited, so -1 should pick that up. - assert_equal short_pid, Process.waitpid(-1) + # The short pid has exited, so waitpid(-1) should pick that up. + exited_pid = + unless nohang + Process.waitpid(-1) + else + EnvUtil.timeout(5) do + loop do + pid = Process.waitpid(-1, Process::WNOHANG) + + break pid if pid + + sleep 0.1 + end + end + end + + assert_equal short_pid, exited_pid # Terminate t1 for the next phase of the test. t1.kill @@ -2714,6 +2730,14 @@ EOS [long_rpipe, long_wpipe, short_rpipe, short_wpipe].each { _1&.close rescue nil } end if defined?(fork) + def test_concurrent_group_and_pid_wait + _test_concurrent_group_and_pid_wait(false) + end if defined?(fork) + + def test_concurrent_group_and_pid_wait_nohang + _test_concurrent_group_and_pid_wait(true) + end if defined?(fork) + def test_handle_interrupt_with_fork Thread.handle_interrupt(RuntimeError => :never) do Thread.current.raise(RuntimeError, "Queued error") |
