Skip to content

Commit c5c0c7d

Browse files
committed
zjit_bisect.rb: Fix pipe deadlock; log when timed out
I spent a long time bisecting some largish program before realising that failure was in fact coming from the child timing out due to zjit_bisect.rb not clearing the stdout and stderr pipe. Fix the pipe dead lock by redirecting to /dev/null. This sacrifices the debug output during boot, but for that we also get to remove a lot of code and the dependency on Open3.
1 parent 38558dd commit c5c0c7d

1 file changed

Lines changed: 19 additions & 25 deletions

File tree

tool/zjit_bisect.rb

Lines changed: 19 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -73,26 +73,22 @@ def run_bisect(command, items)
7373
end
7474

7575
def run_ruby *cmd
76-
stdout_data = nil
77-
stderr_data = nil
78-
status = nil
79-
Open3.popen3(*cmd) do |stdin, stdout, stderr, wait_thr|
80-
pid = wait_thr.pid
81-
begin
82-
Timeout.timeout(ARGS[:timeout]) do
83-
stdout_data = stdout.read
84-
stderr_data = stderr.read
85-
status = wait_thr.value
86-
end
87-
rescue Timeout::Error
88-
Process.kill("KILL", pid)
89-
stderr_data = "(killed due to timeout)"
90-
# Wait for the process to be reaped
91-
wait_thr.value
92-
status = 1
76+
pid = Process.spawn(*cmd, {
77+
in: :close,
78+
out: [File::NULL, File::RDWR],
79+
err: [File::NULL, File::RDWR],
80+
})
81+
begin
82+
status = Timeout.timeout(ARGS[:timeout]) do
83+
Process::Status.wait(pid)
9384
end
85+
rescue Timeout::Error
86+
Process.kill("KILL", pid)
87+
LOGGER.warn("timedout")
88+
status = Process::Status.wait(pid)
9489
end
95-
[stdout_data, stderr_data, status]
90+
91+
status
9692
end
9793

9894
def run_with_jit_list(ruby, options, jit_list)
@@ -107,9 +103,8 @@ def run_with_jit_list(ruby, options, jit_list)
107103
end
108104

109105
# Try running with no JIT list to get a stable baseline
110-
_, stderr, exitcode = run_with_jit_list(RUBY, OPTIONS, [])
111-
if exitcode != 0
112-
raise "Command failed with empty JIT list: #{stderr}"
106+
unless run_with_jit_list(RUBY, OPTIONS, []).success?
107+
raise "Command failed with empty JIT list"
113108
end
114109
# Collect the JIT list from the failing Ruby process
115110
jit_list = nil
@@ -119,14 +114,13 @@ def run_with_jit_list(ruby, options, jit_list)
119114
end
120115
LOGGER.info("Starting with JIT list of #{jit_list.length} items.")
121116
# Try running without the optimizer
122-
_, stderr, exitcode = run_with_jit_list(RUBY, ["--zjit-disable-hir-opt", *OPTIONS], jit_list)
123-
if exitcode == 0
117+
status = run_with_jit_list(RUBY, ["--zjit-disable-hir-opt", *OPTIONS], jit_list)
118+
if status.success?
124119
LOGGER.warn "*** Command suceeded with HIR optimizer disabled. HIR optimizer is probably at fault. ***"
125120
end
126121
# Now narrow it down
127122
command = lambda do |items|
128-
_, _, exitcode = run_with_jit_list(RUBY, OPTIONS, items)
129-
exitcode == 0
123+
run_with_jit_list(RUBY, OPTIONS, items).success?
130124
end
131125
result = run_bisect(command, jit_list)
132126
File.open("jitlist.txt", "w") do |file|

0 commit comments

Comments
 (0)