Boost logo

Boost Users :

Subject: Re: [Boost-users] [asio] Error code by io_service.run(ec) not the same as in async_read_handler
From: Thomas Markwalder (tmark_at_[hidden])
Date: 2016-04-06 10:34:40


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_at_[hidden]
> 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



Boost-users list run by williamkempf at hotmail.com, kalb at libertysoft.com, bjorn.karlsson at readsoft.com, gregod at cs.rpi.edu, wekempf at cox.net