# IO#close hangs forever when the thread writing to that IO is running a trap handler.
# Usage: ruby repro.rb [trap|thread]
mode = ARGV[0] || "trap"

r, w = IO.pipe
begin
  loop { w.write_nonblock("x" * 4096) } # fill the pipe so the next write blocks
rescue IO::WaitWritable
end

closer = nil
write = lambda do
  closer = Thread.new { sleep 0.3; w.close; :closed } # close while the other thread is blocked writing
  begin
    w.syswrite("y")
    puts "write: returned"
  rescue Exception => e
    puts "write: #{e.class}: #{e.message}"
  end
end

if mode == "trap"
  Signal.trap("USR1") { write.call }
  Process.kill("USR1", Process.pid)
  sleep 0.1 until closer
else
  write.call
end

result = closer.join(3)
puts "#{RUBY_DESCRIPTION}, #{mode}: " +
  (result ? "IO#close returned" : "IO#close HANGS (#{closer.status}) at #{closer.backtrace&.first}")
