Project

General

Profile

Actions

Misc #18725

open

IO#write and IO#wait_writable block for write pipe if read pipe is closed in other thread on OpenBSD

Added by jeremyevans0 (Jeremy Evans) 2 months ago.

Status:
Open
Priority:
Normal
Assignee:
-
[ruby-core:108223]

Description

I'm not sure whether this is a Ruby issue, an OpenBSD issue, or something else, but @ioquatix (Samuel Williams) asked me to post this here. The following program hangs on OpenBSD:

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.

No data to display

Actions

Also available in: Atom PDF