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:
parent
27688b6a1d
commit
76a8c963c7
@ -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
|
||||
|
Loading…
x
Reference in New Issue
Block a user