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
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.htmlhttp://www.boost.org/doc/libs/1_53_0/doc/html/boost_asio/reference/async_re%... ): ... 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.htmlhttp://www.boost.org/doc/libs/1_53_0/doc/html/boost_asio/reference/asynchro%...) 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
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
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