Boost logo

Boost :

Subject: Re: [boost] [ASIO] Issue with epoll reactor? Callback handler not executed.
From: Arpan Sen (arpansen_at_[hidden])
Date: 2013-05-30 13:44:02


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_at_[hidden]> 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_read_until/overload1.html
>
> 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.

Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk