ruby-changes:30924
From: akr <ko1@a...>
Date: Sat, 21 Sep 2013 12:51:00 +0900 (JST)
Subject: [ruby-changes:30924] akr:r43003 (trunk): [DOC]
akr 2013-09-21 12:50:54 +0900 (Sat, 21 Sep 2013) New Revision: 43003 http://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=rev&revision=43003 Log: [DOC] Modified files: trunk/io.c Index: io.c =================================================================== --- io.c (revision 43002) +++ io.c (revision 43003) @@ -8485,6 +8485,69 @@ rb_io_advise(int argc, VALUE *argv, VALU https://github.com/ruby/ruby/blob/trunk/io.c#L8485 * if optional <i>timeout</i> value is given and no <code>IO</code> object * is ready in <i>timeout</i> seconds. * + * The best way to use <code>IO.select</code> is invoking it + * after nonblocking methods such as <code>read_nonblock</code>. + * The methods raises an exception which is extended by + * <code>IO::WaitReadable</code> or <code>IO::WaitWritable</code>. + * The modules notify how the caller should wait with <code>IO.select</code>. + * If <code>IO::WaitReadable</code> is raised, the caller should wait for reading. + * If <code>IO::WaitWritable</code> is raised, the caller should wait for writing. + * + * So, blocking read (<code>readpartial</code>) can be emulated using + * <code>read_nonblock</code> and <code>IO.select</code> as follows: + * + * begin + * result = io_like.read_nonblock(maxlen) + * rescue IO::WaitReadable + * IO.select([io_like]) + * retry + * rescue IO::WaitWritable + * IO.select(nil, [io_like]) + * retry + * end + * + * Especially, the combination of nonblocking methods and + * <code>IO.select</code> is preferred for <code>IO</code> like + * objects such as <code>OpenSSL::SSL::SSLSocket</code>. + * It has <code>to_io</code> method to return underlying <code>IO</code> object. + * <code>IO.select</code> calls <code>to_io</code> to obtain the file descriptor to wait. + * + * This means that readability notified by <code>IO.select</code> doesn't mean + * readability from <code>OpenSSL::SSL::SSLSocket</code> object. + * + * Most possible situation is <code>OpenSSL::SSL::SSLSocket</code> buffers some data. + * <code>IO.select</code> doesn't see the buffer. + * So <code>IO.select</code> can block when <code>OpenSSL::SSL::SSLSocket#readpartial</code> doesn't block. + * + * However several more complicated situation exists. + * + * SSL is a protocol which is sequence of records. + * The record consists multiple bytes. + * So, the remote side of SSL sends a partial record, + * <code>IO.select</code> notifies readability but + * <code>OpenSSL::SSL::SSLSocket</code> cannot decrypt a byte and + * <code>OpenSSL::SSL::SSLSocket#readpartial</code> will blocks. + * + * Also, the remote side can request SSL renegotiation which forces + * the local SSL engine writes some data. + * This means <code>OpenSSL::SSL::SSLSocket#readpartial</code> may + * invoke <code>write</code> system call and it can block. + * In such situation, <code>OpenSSL::SSL::SSLSocket#read_nonblock</code> + * raises IO::WaitWritable instead of blocking. + * So, the caller should wait for ready for writability as above example. + * + * The combination of nonblocking methods and <code>IO.select</code> is + * also useful for streams such as tty, pipe socket socket when + * multiple process read form a stream. + * + * Finally, Linux kernel developers doesn't guarantee that + * readability of select(2) means readability of following read(2) even + * for single process. + * See select(2) manual on GNU/Linux system. + * + * Invoking <code>IO.select</code> before <code>IO#readpartial</code> works well in usual. + * However it is not the best way to use <code>IO.select</code>. + * * === Parameters * read_array:: an array of <code>IO</code> objects that wait until ready for read * write_array:: an array of <code>IO</code> objects that wait until ready for write @@ -8496,6 +8559,7 @@ rb_io_advise(int argc, VALUE *argv, VALU https://github.com/ruby/ruby/blob/trunk/io.c#L8559 * rp, wp = IO.pipe * mesg = "ping " * 100.times { + * # IO.select follows IO#read. Not the best way to use IO.select. * rs, ws, = IO.select([rp], [wp]) * if r = rs[0] * ret = r.read(5) -- ML: ruby-changes@q... Info: http://www.atdot.net/~ko1/quickml/