In article <17383D97-991D-4947-AB88-85758AB964FB / reverberate.org>, Joshua Haberman <joshua / reverberate.org> writes: > - by default, ruby i/o operations block, but only block the calling > Ruby thread. Ruby does this by scheduling a thread out if the fd is > not read-ready/write-ready. If there is more than one Ruby thread, > Ruby won't do a read(2) or write(2) on an fd unless select() says it > is ready, to prevent blocking the entire process. Right. > - the one flaw with this scheme is that write(2) can block even if an > fd is write-ready, if you try to write too much data. This will > cause such a write to lock the entire process and all Ruby threads > therein ([0] is a simple test program that displays the problem). Right. > - You can try setting O_NONBLOCK on your IO objects with fcntl. That > will help you in the case where you only have one Ruby thread -- now > read and write will raise Errno::EAGAIN if the fd isn't ready. No. IO#write doesn't raise Errno::EAGAIN but retry until all data is written. IO#read also retry since Ruby 1.9. So IO#write and IO#read may block calling thread. > But > in the case where there is more than one Ruby thread, this won't work > because Ruby won't perform the read(2) or write(2) until the fd is > ready. So even though you have O_NONBLOCK set, you block your Ruby > thread. (See [1] for an example]). Right. > One other question: are the buffered fread()/fwrite() functions > guaranteed to work correctly if O_NONBLOCK is set on the underlying > descriptor? I have not been able to find a good answer to this. fwrite(3) may lost data. So Ruby 1.8 may lost data. % ruby-1.8.3 -v ruby 1.8.3 (2005-09-21) [i686-linux] % ruby-1.8.3 -rfcntl -e ' w = STDOUT w.fcntl(Fcntl::F_SETFL, w.fcntl(Fcntl::F_GETFL) | Fcntl::O_NONBLOCK) w << "a" * 4096 w.flush w << "b" w.flush ' | ruby -e 'sleep 1; p STDIN.read.length' 4096 However no data is lost if IO#sync = true since Ruby 1.8.2. It's because stdio is bypassed. % ruby-1.8.3 -rfcntl -e ' w = STDOUT w.sync = true w.fcntl(Fcntl::F_SETFL, w.fcntl(Fcntl::F_GETFL) | Fcntl::O_NONBLOCK) w << "a" * 4096 w.flush w << "b" w.flush ' | ruby -e 'sleep 1; p STDIN.read.length' 4097 Ruby 1.9 doesn't have the problem because it has its own buffering mechanism. > # this will block our thread, even though the fd is set to nonblocking. > # however, if you eliminate the background thread, this call with > give you EAGAIN, > # which is what you want. > read_pipe.read If you want to test some data available, use IO.select. -- Tanaka Akira