Boost C++ Libraries: Ticket #3627: boost::asio::async_read() cannot be used with null_buffers() https://svn.boost.org/trac10/ticket/3627 <p> An attempt to use async_read() with null_buffers() causes the handler to be invoked even when the underlying file descriptor is not yet available for reading. </p> <p> The following test demonstrates the problem </p> <p> void test_async_read() { </p> <blockquote> <p> struct local { </p> <blockquote> <p> static void on_ready(boost::system::error_code const&amp; error, int* invoked) { </p> <blockquote> <p> BOOST_CHECK(!error); *invoked = 1; </p> </blockquote> <p> } </p> </blockquote> <p> }; </p> </blockquote> <blockquote> <p> int p<a class="changeset" href="https://svn.boost.org/trac10/changeset/2" title="Add Boost Disclaimer">[2]</a>; int const s = pipe(p); BOOST_CHECK(0 == s); </p> </blockquote> <blockquote> <p> boost::asio::io_service ios; boost::asio::posix::stream_descriptor sd(ios, p<a class="missing changeset" title="No changeset 0 in the repository">[0]</a>); ios.reset(); int invoked = 0; boost::asio::async_read(sd, boost::asio::null_buffers(), boost::bind(&amp;local::on_ready, _1, &amp;invoked)); ios.poll_one(); BOOST_CHECK(!invoked); <em> doesn't pass </em></p> </blockquote> <p> } </p> <p> This test doesn't pass on linux using either epoll or select multiplexing mechanism. This test also doesn't pass on freebsd using either kqueue or select multiplexing mechanism. </p> en-us Boost C++ Libraries /htdocs/site/boost.png https://svn.boost.org/trac10/ticket/3627 Trac 1.4.3 jkp@… Tue, 12 Jan 2010 14:16:27 GMT severity changed https://svn.boost.org/trac10/ticket/3627#comment:1 https://svn.boost.org/trac10/ticket/3627#comment:1 <ul> <li><strong>severity</strong> <span class="trac-field-old">Problem</span> → <span class="trac-field-new">Regression</span> </li> </ul> <p> I can also confirm that this is the case on OS X. The question I have is whether the change is intended? The new documentation seems to imply it is: </p> <pre class="wiki">If the total size of all buffers in the sequence mb is 0, the asynchronous read operation shall complete immediately and pass 0 as the argument to the handler that specifies the number of bytes read. </pre><p> Also, the changelist for 1.40.0 says the following: </p> <pre class="wiki">Changed the buffered*_stream&lt;&gt; templates to treat 0-byte reads and writes as no-ops, to comply with the documented type requirements for SyncReadStream, AsyncReadStream, SyncWriteStream and AsyncWriteStream. </pre><p> It's unclear what the intendended behaviour is from these two snippets. Certainly pre 1.40.0 you could call async_read with null_buffers and get a callback when some new data had arrived. This is extremely useful functionality, esp for code that has layered other streams on-top of the asio ones. Right now I have no way to check for data (async) without reading it off the socket. </p> Ticket chris_kohlhoff Tue, 12 Jan 2010 21:28:45 GMT severity changed https://svn.boost.org/trac10/ticket/3627#comment:2 https://svn.boost.org/trac10/ticket/3627#comment:2 <ul> <li><strong>severity</strong> <span class="trac-field-old">Regression</span> → <span class="trac-field-new">Problem</span> </li> </ul> <p> Not a regression. The null_buffers() type never worked with async_read(). </p> <p> You may confirm that it doesn't work by making the following changes to the nonblocking example: </p> <p> @@ -117,7 +117,8 @@ </p> <blockquote> <p> if (session_impl_.want_read() &amp;&amp; !read_in_progress_) { </p> <blockquote> <p> read_in_progress_ = true; </p> </blockquote> </blockquote> <ul><li> socket_.async_read_some( </li></ul><p> + boost::asio::async_read(socket_, + <em>socket_.async_read_some( </em></p> <blockquote> <p> boost::asio::null_buffers(), boost::bind(&amp;connection::handle_read, </p> <blockquote> <p> shared_from_this(), </p> </blockquote> </blockquote> <p> @@ -138,6 +139,8 @@ </p> <blockquote> <p> void handle_read(boost::system::error_code ec) { </p> </blockquote> <p> + printf("handle_read\n"); + </p> <blockquote> <p> read_in_progress_ = false; </p> </blockquote> <blockquote> <p> <em> Notify third party library that it can perform a read. </em></p> </blockquote> <p> I just checked against 1.39. </p> Ticket chris_kohlhoff Tue, 12 Jan 2010 21:46:23 GMT type, severity, milestone changed https://svn.boost.org/trac10/ticket/3627#comment:3 https://svn.boost.org/trac10/ticket/3627#comment:3 <ul> <li><strong>type</strong> <span class="trac-field-old">Bugs</span> → <span class="trac-field-new">Feature Requests</span> </li> <li><strong>severity</strong> <span class="trac-field-old">Problem</span> → <span class="trac-field-new">Not Applicable</span> </li> <li><strong>milestone</strong> <span class="trac-field-old">Boost 1.41.0</span> → <span class="trac-field-new">To Be Determined</span> </li> </ul> <p> The null_buffers type is only intended for use with async_read_some() and async_write_some() on the "lowest layer", i.e. the socket or descriptor. It is not part of any of the stream type requirements, and so not supported by composed operations such as async_read. </p> <p> If it worked with the buffered*_stream&lt;&gt; templates then that was just a side effect of the 0-byte read/write bug. </p> <p> It may or may not be useful to support null_buffers as part of the stream type requirements. I'm reclassifying this as a feature request as something to think about in the future. </p> <p> In any case: </p> <pre class="wiki">Right now I have no way to check for data (async) without reading it off the socket. </pre><p> is not correct. It works just fine if you use async_read_some() on the socket. </p> Ticket