Skip to content

async_execute behavior with cancellation #534

@jens-diewald

Description

@jens-diewald

Hi, I am trying to migrate from v1 to v2 (Boost 1.90).

I want to launch a child process, and terminate it, if it takes too long.
With v1, I used process::wait_for (currently only targeting windows, so that was fine).
The timeout example in the documentation for v2 hints at using something like async_execute(process(...)(asio::cancel_after(...))(some_handler).
That cancels the process fine, but I am having trouble to determine in the handler whether the process was terminated or exited okay.
Experimenting a bit, I found, that using proc.async_wait(boost::asio::cancel_after(...))(some_handler) behaves differently.

I am uncertain if that is a bug, or if I am missing something.
The behavior is as follows:

auto ctx  = boost::asio::io_context{};
auto proc = boost::process::process(ctx, executable_path);
auto handle_exit_code = [](boost::system::error_code ec, int exitcode) {/*something*/};
// variant (a)
proc.async_wait(boost::asio::cancel_after(std::chrono::nanoseconds(1)))(handle_exit_code);
// variant (b)
boost::process::async_execute(std::move(proc))(boost::asio::cancel_after(std::chrono::nanoseconds(1)))(handle_exit_code);
ctx.run();

If the process times out in handle_exit_code, I get

  • with variant (a): ec == boost::asio::error::operation_aborted and exitcode==259, which corresponds to boost::process::v2::detail::still_active, I guess..? This behavior is useful to me.
  • with variant (b): ec is not set (value==0) and exitcode==260. I have no idea what the 260 is, and it seems very unreliable to depend on it.

Sidenote: The comment at process::async_wait says

/// Asynchronously wait for the process to exit and deliver the native exit-code in the completion handler.

but the signature of the completion token is void(error_code, int), i.e. it uses int and not native_exit_code_type. So the comment is wrong and it is not the native exit-code, right?
There is no such comment at async_execute, so maybe it is supposed to behave differently? Either way, it would be nice if the behavior would be documented.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions