Re: [boost] [ASIO] Issue with epoll reactor? Callback handler not executed.

Hi, Arpan.
Everything works fine till async_write.
async_write(socket, buffer(command.c_str()), &write_handler); io_service.reset(); io_service.run_one(); will implement only one completions handler. That completion handler may be
You forgot that free functions like asio::async_write(_until)/asio::async_read(_until)/etc. are composed operations (http://www.boost.org/doc/libs/1_53_0/doc/html/boost_asio/reference/async_re ad/overload1.html): ... This operation is implemented in terms of zero or more calls to the stream's async_read_some function, and is known as a composed operation. ... Any composed operation (failed to find documentation for this) is implemented by means of multiple simple asynchronous operations. For example asio::async_read is implemented in terms of multiple calls of AsyncStream::async_read_some. So during any composed operation there are multiple (>=1) completions of simple asynchronous operations each of those has its own (intermediate) completion handler. Each of such intermediate completion handlers is dispatched like bound completion handler (http://www.boost.org/doc/libs/1_53_0/doc/html/boost_asio/reference/asynchro nous_operations.html) by the means of the same instance of asio::io_service as AsyncStream provides. So this code: the intermediate completion handler if async_write needs to make more than one call to async_write_some (may be this needs to be explicitly described in Boost.Asio documentation?). That is the reason why your write_handler is not called sometimes. May be this can solve the problem: async_write(socket, buffer(command.c_str()), &write_handler); io_service.reset(); io_service.run(); async_read_until(socket, response, '\n', &read_handler); io_service.reset(); io_service.run(); Regards, Marat Abrarov.

Thanks for the response Marat. There are lots of things I do not explain here - let me list them down: 1. same code works in boost 1.44 - the async-write and epoll work exactly as i expect them to. I have run these pieces with 1.44 1000s of times, and never had a need to execute run_one to get data multiple times. 2. the quantum of data i am looking at is <30 bytes 3. the socket in my code is not a busy one at all - exchanges 10-30 bytes only once in a while 4. Marat's code is using io_service.run - why should I not be using run_one? 5. with boost 1.44 the completion handler would get called from the same thread after i invoke run_one. I debugged boost headers. With 1.53 that's not the case - the streambuf does have the data but the completion handler is not getting called. 6. same code works fine with select but not epoll. Any thoughts on debugging or setting epoll options from asio interface to see what is going on? On Fri, May 24, 2013 at 3:17 PM, Marat Abrarov <abrarov@mail.ru> wrote:
Hi, Arpan.
Everything works fine till async_write.
You forgot that free functions like asio::async_write(_until)/asio::async_read(_until)/etc. are composed operations ( http://www.boost.org/doc/libs/1_53_0/doc/html/boost_asio/reference/async_re ad/overload1.html<http://www.boost.org/doc/libs/1_53_0/doc/html/boost_asio/reference/async_re%0Aad/overload1.html> ): ... This operation is implemented in terms of zero or more calls to the stream's async_read_some function, and is known as a composed operation. ...
Any composed operation (failed to find documentation for this) is implemented by means of multiple simple asynchronous operations. For example asio::async_read is implemented in terms of multiple calls of AsyncStream::async_read_some. So during any composed operation there are multiple (>=1) completions of simple asynchronous operations each of those has its own (intermediate) completion handler. Each of such intermediate completion handlers is dispatched like bound completion handler ( http://www.boost.org/doc/libs/1_53_0/doc/html/boost_asio/reference/asynchro nous_operations.html<http://www.boost.org/doc/libs/1_53_0/doc/html/boost_asio/reference/asynchro%0Anous_operations.html>) by the means of the same instance of asio::io_service as AsyncStream provides.
async_write(socket, buffer(command.c_str()), &write_handler); io_service.reset(); io_service.run_one(); will implement only one completions handler. That completion handler may be
So this code: the intermediate completion handler if async_write needs to make more than one call to async_write_some (may be this needs to be explicitly described in Boost.Asio documentation?). That is the reason why your write_handler is not called sometimes.
May be this can solve the problem: async_write(socket, buffer(command.c_str()), &write_handler); io_service.reset(); io_service.run(); async_read_until(socket, response, '\n', &read_handler); io_service.reset(); io_service.run();
Regards, Marat Abrarov.
_______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
-- Regards, Arpan ----------------------------------------------------------------------------------------------------------------- Reality is merely an illusion, albeit a very persistent one.

Hi Arpan, Read Marat's response again. The likely issue here is not epoll or asio, but rather with your code trying to use composed operations like async_write() and async_read_until() with io_service.run_one().
4. Marat's code is using io_service.run - why should I not be using run_one?
run_one() will run until the io_service is stopped (and return 0), or until at most 1 completion handler is called (and return 1). As Marat notes, async_read_until() is a composed operation - it may result in multiple async_read_some() operations internally, each with their own completion handler. Since you use run_one(), you haven't allowed async_read_until() to complete in cases in which it needs to call multiple internal handlers.
Any thoughts on debugging or setting epoll options from asio interface to see what is going on?
Use io_service.run(). You can check its return value to see how many handlers it called. Thanks, Brad

Thanks Brad. This is likely what is happening since 2 consecutive calls to io_service.run_one fixed the problem. Note that a single call to io_service.run did NOT fix the problem. I do have follow up questions here: 1. What are internal handlers? 2. Where in boost documentation do we mention internal handlers? 3. Is this internal handler business new to boost asio? The 1.44 version always calls my handler after the call to run_one. If yes, since which version has this been around? 4. In async-read-until my handler will only get called after the 2nd call to io_service.run_one. Are there any indications after io_service.run_one the first time that I need to call the method a second time? 5. What's a clean way to do async-read-until? Calling run_one twice looks genuinely messy. 6. Why does the single call to io_service.run not fix the problem? It too returns 1. Many thanks for all the help here people. Appreciate it. Arpan On Sat, May 25, 2013 at 6:38 PM, Brad Higgins <bhiggins@arbor.net> wrote:
Hi Arpan, Read Marat's response again. The likely issue here is not epoll or asio, but rather with your code trying to use composed operations like async_write() and async_read_until() with io_service.run_one().
4. Marat's code is using io_service.run - why should I not be using run_one?
run_one() will run until the io_service is stopped (and return 0), or until at most 1 completion handler is called (and return 1). As Marat notes, async_read_until() is a composed operation - it may result in multiple async_read_some() operations internally, each with their own completion handler. Since you use run_one(), you haven't allowed async_read_until() to complete in cases in which it needs to call multiple internal handlers.
Any thoughts on debugging or setting epoll options from asio interface to see what is going on?
Use io_service.run(). You can check its return value to see how many handlers it called.
Thanks, Brad
_______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
-- Regards, Arpan ----------------------------------------------------------------------------------------------------------------- Reality is merely an illusion, albeit a very persistent one.

Arpan,
Thanks Brad. This is likely what is happening since 2 consecutive calls to io_service.run_one fixed the problem. Note that a single call to io_service.run did NOT fix the problem.
I do have follow up questions here: What are internal handlers? Where in boost documentation do we mention internal handlers? Is this internal handler business new to boost asio? The 1.44 version always calls my handler after the call to run_one. If yes, since which version has this been around? see http://www.boost.org/doc/libs/1_53_0/doc/html/boost_asio/reference/async_rea...
This isn't new.
In async-read-until my handler will only get called after the 2nd call to io_service.run_one. Are there any indications after io_service.run_one the first time that I need to call the method a second time? What's a clean way to do async-read-until? Calling run_one twice looks genuinely messy. Why does the single call to io_service.run not fix the problem? It too returns 1.
I'm not sure why your io_service.run() fails to fix the problem. The io_service.run() method will run until there is no more work, or until the io_service is stopped. Are you stopping the io_service? Are you sure your handler wasn't called, when it returns 1? -Brad

Brad, Here's my code below. Couple of observations: 1. The code is being run on Suse11 but on RHEL6 the behavior is inconsistent as well. 2. If I run the code disabling epoll things work fine. If I don't there's an additional reset + run_one required right after async_write call. This is counter intuitive. 3. Internal handlers, in my humble opinion, should not be something users should be asked to bother with. From their perspective, it should only be their completion handlers that they need to think about. In the code below, the io_service.run_one returns after the call to async_read_until but it is extremely difficult to understand whose handler got executed, mine in application code didn't. 4. My compiler is g++-4.3.4. I think Linux kernel version is 2.5+. #include <iostream> #include <boost/asio.hpp> #include <boost/bind.hpp> #include <boost/asio/streambuf.hpp> template <typename T> T execute_command( std::string const & host, std::string const & port, int timeout, std::string const & command, T const & test_value); void execute_command_impl( std::string const & host, std::string const & port, int timeout, std::string const & command, boost::asio::streambuf& response); template <typename T> T execute_command( std::string const & host, std::string const & port, int timeout, std::string const & command, T const & test_value) { if (host.find("test") == 0 && port == "test") { return host == "test_ERROR" ? throw std::runtime_error("Intentional test error") : test_value; } std::string current_action; try { std::cout << "parsing response: "; boost::asio::streambuf response; execute_command_impl( host, port, timeout, command, response); std::istream is(&response); T ans; is >> ans; if (is.fail()) { throw std::runtime_error("Invalid response"); } return ans; } catch (std::exception const & e) { void io_handler( boost::system::error_code const & error, std::size_t /* bytes_transferred */) { if (error) { throw std::runtime_error(error.message()); } } void execute_command_impl( std::string const & host, std::string const & port, int timeout, std::string const & command, boost::asio::streambuf& response) { std::string current_action("initializing asio"); try { using namespace boost::asio; using boost::asio::ip::tcp; io_service io_service; deadline_timer timer(io_service); timer.expires_from_now(boost::posix_time::seconds(timeout)); timer.async_wait(&timer_handler); std::cout << "resolving " << host << ":" << port << "\n"; tcp::resolver resolver(io_service); tcp::resolver::query query(tcp::v4(), host, port); tcp::resolver::iterator iterator; resolver.async_resolve( query, boost::bind(&resolve_handler, boost::ref(iterator), _1, _2)); io_service.reset(); io_service.run_one(); std::cout << "connecting to " << host << ":" << port << "\n"; tcp::socket socket(io_service); socket.async_connect(*iterator, &connect_handler); io_service.reset(); io_service.run_one(); std::cout << "writing to " << host << ":" << port << "\n"; async_write(socket, buffer(command), &io_handler); io_service.reset(); io_service.run_one(); std::cout << "reading from " << host << ":" << port << "\n"; async_read_until(socket, response, '\n', &io_handler); io_service.reset(); io_service.run_one(); } catch (std::exception const & e) { throw std::runtime_error(current_action + ": " + e.what()); } } int main() { boost::asio::streambuf response; std::string host = "localhost"; std::string port = "8977"; int timeout = 50; std::string command = "login,remote\n"; execute_command( host, port, timeout, command, std::string("test")); std::cout << "" << std::endl; } throw std::runtime_error( "Error performing \"" + command + current_action + ": " + e.what()); } } using namespace boost::asio; using boost::asio::ip::tcp; void timer_handler( boost::system::error_code const & /* error */) { throw std::runtime_error("Operation timed out"); } void resolve_handler( tcp::resolver::iterator & iterator, boost::system::error_code const & error, tcp::resolver::iterator resolved) { if (error) { throw std::runtime_error(error.message()); } iterator = resolved; } void connect_handler( boost::system::error_code const & error) { if (error) { throw std::runtime_error(error.message()); } } On Thu, May 30, 2013 at 1:56 AM, Brad Higgins <bhiggins@arbor.net> wrote:
Arpan,
Thanks Brad. This is likely what is happening since 2 consecutive calls to io_service.run_one fixed the problem. Note that a single call to io_service.run did NOT fix the problem.
I do have follow up questions here:
1. What are internal handlers? 2. Where in boost documentation do we mention internal handlers? 3. Is this internal handler business new to boost asio? The 1.44 version always calls my handler after the call to run_one. If yes, since which version has this been around?
see http://www.boost.org/doc/libs/1_53_0/doc/html/boost_asio/reference/async_rea...
This isn't new.
1. In async-read-until my handler will only get called after the 2nd call to io_service.run_one. Are there any indications after io_service.run_one the first time that I need to call the method a second time? 2. What's a clean way to do async-read-until? Calling run_one twice looks genuinely messy. 3. Why does the single call to io_service.run not fix the problem? It too returns 1.
I'm not sure why your io_service.run() fails to fix the problem. The io_service.run() method will run until there is no more work, or until the io_service is stopped. Are you stopping the io_service? Are you sure your handler wasn't called, when it returns 1?
-Brad
-- Regards, Arpan ----------------------------------------------------------------------------------------------------------------- Reality is merely an illusion, albeit a very persistent one.

Hi Arpan,
Internal handlers, in my humble opinion, should not be something users should be asked to bother with. From their perspective, it should only be their completion handlers that they need to think about. In the code below, the io_service.run_one returns after the call to async_read_until but it is extremely difficult to understand whose handler got executed, mine in application code didn't. async_write() and async_read_until() are just helper functions. If you don't like them, then don't use them. Re-implement your program with socket.async_write_some() and socket.async_read_some(), and you can tightly control which async operations are passed to the io_service.
-Brad
participants (3)
-
Arpan Sen
-
Brad Higgins
-
Marat Abrarov