On 4/6/16 5:58 AM, Michael Weise wrote:
Hello,

my question is about the error code returned by io_service.run_one.
I expect the error code returned by run_one to be the same as the one
in the handler - but they are not.


Inside my handler I check the error code, which is equal to operation
aborted:

void ConnectionBase::ReadUntilHandler(
    const boost::system::error_code & ec,
    std::size_t bytes_transferred)
{
   // ec == boost::asio::error::operation_aborted
   ...
}


At some other point I call io_service.run_one, which calls the above
handler:

    ...
    m_asioService.run_one(ec);
    assert(ec == boost::asio::error::operation_aborted);
    ...

The assertion fails - for some reason the error code is not the same as
in the handler.


What's the reason for this? Maybe my assumtion that run_one(ec) returns
the error code of the handler is simply wrong? If so, what error does
io_service.run(ec) actually report?

Thanks for help,
Michael


PS: boost::asio version is 1.56.0
_______________________________________________
Boost-users mailing list
Boost-users@lists.boost.org
http://lists.boost.org/mailman/listinfo.cgi/boost-users
Hi Michael:

Are you compiling header only and If so are you using GCC 5.2 or newer with optimization enabled (-O2) ?
If so then you may be hitting this issue:

The function boost:system:system_category() returns a reference to a local static variable, system_category_const. When built as header only (-DBOOST_ERROR_CODE_HEADER_ONLY) the function is declared as inlined and the optimizer fails to ensure a single value is returned by this function within a translation unit. It is conceptually the same as the issue discussed here:

http://processors.wiki.ti.com/index.php/C++_Inlining_Issues

under the section "Static Variables in Inline Functions".

This manifests itself in the following expression from boost:asio:detail:impl:socket_ops.ipp:non_blocking_recv():

    if (ec == boost::asio::error::would_block
       || ec == boost::asio::error::try_again)
      return false;

that evaluates to false when it should evaluate to true. Ultimately this causes the io_service to invoke the socket's ready handler rather than continuing to poll the socket waiting for data.

The inequality stems from the implicit conversion of the enumerates to error_code instances, during which calls to system_category() used to set error_code:m_cat, return differing values.

The problem disappears if either the error handling code is not built header only as this results in a single definition of system_category() supplied by libboost_system; or the error handling code is not optimized.

From testing it appears that the issue began in GCC 5.2.0 and exists through 5.3.1, the latest released version. GCC 6.0 is nearing release and will have to be tested.

We reported this both GCC and Boost:

https://gcc.gnu.org/bugzilla/show_bug.cgi?id=69789

https://svn.boost.org/trac/boost/ticket/11989


If this is indeed your issue you could try any of the following:

1. Change your handler's comparison to this:

  ec.value() == boost::asio::error::operation_aborted
By comparing ec.value() to the enum, you eliminate the implicit conversion of the enum to an error_code instance and thereby skirt the issue of the m_cat members not being equal when they should be.   In reality, you only care about the error value, error_code:m_val, anyway.

2. Rather than compile header only, link to boost system lib.

3. Do not compile with optimization, -gO0



Thomas Markwalder
ISC Software Engineering