summaryrefslogtreecommitdiff
path: root/test
diff options
context:
space:
mode:
authorStan Hu <stanhu@gmail.com>2024-05-17 17:05:48 +0900
committernagachika <nagachika@ruby-lang.org>2024-08-18 18:02:09 +0900
commit65fed1c3e439bc47bcf6ec884431a86cb9ebd1dc (patch)
tree236e877de69232fc2b0adc30bf959d680b8eac46 /test
parent50399eebd96c76ce808ea4d84fe39693f585a531 (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')
-rw-r--r--test/ruby/test_process.rb30
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")