From: "jeremyevans0 (Jeremy Evans)" Date: 2022-04-13T23:20:53+00:00 Subject: [ruby-core:108223] [Ruby master Misc#18725] IO#write and IO#wait_writable block for write pipe if read pipe is closed in other thread on OpenBSD Issue #18725 has been reported by jeremyevans0 (Jeremy Evans). ---------------------------------------- Misc #18725: IO#write and IO#wait_writable block for write pipe if read pipe is closed in other thread on OpenBSD https://bugs.ruby-lang.org/issues/18725 * Author: jeremyevans0 (Jeremy Evans) * Status: Open * Priority: Normal ---------------------------------------- I'm not sure whether this is a Ruby issue, an OpenBSD issue, or something else, but @ioquatix asked me to post this here. The following program hangs on OpenBSD: ```ruby require 'io/wait' rd, wr = IO.pipe thread_pass = ARGV[0] == 'pass' write = ARGV[0] == 'write' thread = Thread.new do longer = "0" * 1024 * 1024 (1024 * 4).times do if write wr.write(longer) else while wr.write_nonblock(longer, :exception=>false) == :wait_writable thread_pass ? Thread.pass : wr.wait_writable end end end :finished rescue => e e end sleep 1 rd.close puts :rd_close puts thread.value ``` This program will also hang if `write` is given as the argument, using `wr.write` instead of `wr.write_nonblock`/`wr.wait_writable`. However, if `pass` is given as the argument, using `Thread.pass` instead of `wr.wait_writable`, the program will not hang. From testing, the hang when called without an argument is in `wait_writable`, and the hang with a `write` argument is in `write`. Is Ruby supposed to guarantee that a closing the read end of a pipe in one thread causes a raise of EPIPE to the write end of the pipe in a different thread if already inside `IO#write`/`IO#wait_writable`? Or is this platform-specific behavior? This example was extracted from one of Rack's tests, which was causing non-deterministic hangs on OpenBSD. -- https://bugs.ruby-lang.org/ Unsubscribe: