Opened 13 years ago

Last modified 13 years ago

#3627 new Feature Requests

boost::asio::async_read() cannot be used with null_buffers()

Reported by: Dmitry Goncharov <dgoncharov@…> Owned by: chris_kohlhoff
Milestone: To Be Determined Component: asio
Version: Boost 1.40.0 Severity: Not Applicable
Keywords: asio async_read null_buffers Cc:

Description

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.

The following test demonstrates the problem

void test_async_read() {

struct local {

static void on_ready(boost::system::error_code const& error, int* invoked) {

BOOST_CHECK(!error); *invoked = 1;

}

};

int p[2]; int const s = pipe(p); BOOST_CHECK(0 == s);

boost::asio::io_service ios; boost::asio::posix::stream_descriptor sd(ios, p[0]); ios.reset(); int invoked = 0; boost::asio::async_read(sd, boost::asio::null_buffers(), boost::bind(&local::on_ready, _1, &invoked)); ios.poll_one(); BOOST_CHECK(!invoked); doesn't pass

}

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.

Change History (3)

comment:1 by jkp@…, 13 years ago

Severity: ProblemRegression

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:

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.

Also, the changelist for 1.40.0 says the following:

Changed the buffered*_stream<> templates to treat 0-byte reads and writes as no-ops, to comply with the documented type requirements for SyncReadStream, AsyncReadStream, SyncWriteStream and AsyncWriteStream.

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.

comment:2 by chris_kohlhoff, 13 years ago

Severity: RegressionProblem

Not a regression. The null_buffers() type never worked with async_read().

You may confirm that it doesn't work by making the following changes to the nonblocking example:

@@ -117,7 +117,8 @@

if (session_impl_.want_read() && !read_in_progress_) {

read_in_progress_ = true;

  • socket_.async_read_some(

+ boost::asio::async_read(socket_, + socket_.async_read_some(

boost::asio::null_buffers(), boost::bind(&connection::handle_read,

shared_from_this(),

@@ -138,6 +139,8 @@

void handle_read(boost::system::error_code ec) {

+ printf("handle_read\n"); +

read_in_progress_ = false;

Notify third party library that it can perform a read.

I just checked against 1.39.

comment:3 by chris_kohlhoff, 13 years ago

Milestone: Boost 1.41.0To Be Determined
Severity: ProblemNot Applicable
Type: BugsFeature Requests

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.

If it worked with the buffered*_stream<> templates then that was just a side effect of the 0-byte read/write bug.

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.

In any case:

Right now I have no way to check for data (async) without reading it off the socket.

is not correct. It works just fine if you use async_read_some() on the socket.

Note: See TracTickets for help on using tickets.