Add a test for what happens with concurent calls to waitpid

Ruby 3.1 and 3.2 have a bug in their _implementation_, for which I'm
backporting a fix. However, the current development branch doesn't have
the issue (because the MJIT -> RJIT change refactored how waitpid worked
substantially). I do however want to commit the test which verifies
that waitpid works properly on master.

[Fixes #19387]
This commit is contained in:
KJ Tsanaktsidis 2023-08-18 23:19:21 +10:00
parent 27688b6a1d
commit 76a8c963c7

View File

@ -2783,4 +2783,59 @@ EOS
assert_operator(GC.stat(:total_freed_pages), :>, 0)
end;
end
def test_concurrent_group_and_pid_wait
# 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
short_rpipe, short_wpipe = IO.pipe
# This process should run forever
long_pid = fork do
[short_rpipe, short_wpipe, long_wpipe].each(&:close)
long_rpipe.read
end
# This process will exit
short_pid = fork do
[long_rpipe, long_wpipe, short_wpipe].each(&:close)
short_rpipe.read
end
t1, t2, t3 = nil
EnvUtil.timeout(5) do
t1 = Thread.new do
Process.waitpid long_pid
end
# Wait for us to be blocking in a call to waitpid2
Thread.pass until t1.stop?
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)
# Terminate t1 for the next phase of the test.
t1.kill
t1.join
t2 = Thread.new do
Process.waitpid -1
rescue Errno::ECHILD
nil
end
Thread.pass until t2.stop?
t3 = Thread.new do
Process.waitpid long_pid
rescue Errno::ECHILD
nil
end
Thread.pass until t3.stop?
# it's actually nondeterministic which of t2 or t3 will receive the wait (this
# nondeterminism comes from the behaviour of the underlying system calls)
long_wpipe.close
assert_equal [long_pid], [t2, t3].map(&:value).compact
end
ensure
[t1, t2, t3].each { _1&.kill rescue nil }
[t1, t2, t3].each { _1&.join rescue nil }
[long_rpipe, long_wpipe, short_rpipe, short_wpipe].each { _1&.close rescue nil }
end if defined?(fork)
end