From 08eaf7c5fab7b43f5ff1bbfd4ce1696a30ed802c Mon Sep 17 00:00:00 2001 From: Alan Wu Date: Tue, 21 Mar 2023 18:16:33 -0400 Subject: [PATCH] YJIT: Fix deadlock in tests due to pipe capacity Previously, when there is enough stats that the child process fills up the pipe capacity, the child process would block, with the parent process waiting forever as no one is reading to clear up the pipe. The test timed out in these situations. Use a separate thread in the parent to read from the pipe to unblock the child in these situation. EnvUtil also does this for handling stdout and stderr. I had the test suite deadlock on a Linux VM. --- test/ruby/test_yjit.rb | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/test/ruby/test_yjit.rb b/test/ruby/test_yjit.rb index 3d354bfc6c..703313f4ab 100644 --- a/test/ruby/test_yjit.rb +++ b/test/ruby/test_yjit.rb @@ -1336,13 +1336,24 @@ class TestYJIT < Test::Unit::TestCase args << "--yjit-exec-mem-size=#{mem_size}" if mem_size args << "-e" << script_shell_encode(script) stats_r, stats_w = IO.pipe + # Separate thread so we don't deadlock when + # the child ruby blocks writing the stats to fd 3 + stats = '' + stats_reader = Thread.new do + stats = stats_r.read + stats_r.close + end out, err, status = EnvUtil.invoke_ruby(args, '', true, true, timeout: timeout, ios: {3 => stats_w} ) stats_w.close - stats = stats_r.read + stats_reader.join(timeout) stats = Marshal.load(stats) if !stats.empty? - stats_r.close [status, out, err, stats] + ensure + stats_reader&.kill + stats_reader&.join(timeout) + stats_r&.close + stats_w&.close end end