Skip to content

Ops that co_await in initiate() do not cancel when executable receives a signal #270

Description

@Hyper-AU

Thankyou for your work on this library.

Any op that calls co_await in initiate() does not cancel as the result of a signal handled by co_main.

This appears to affect acceptor::accept(), read()/read_at(), and write()/write_at().

Tested against develop and 1.90.0 tag, on Linux using gcc 14.2.0, -std=c++23.

Simple reproducer:

  #include <boost/cobalt.hpp>
  #include <boost/cobalt/io.hpp>
  #include <iostream>

  using namespace boost;
  
  cobalt::main co_main(int, char *[]) {
  
      std::cout << "Starting co_main\n";
  
      cobalt::io::acceptor acceptor(cobalt::io::endpoint{cobalt::io::tcp_v4, "0.0.0.0", 55555});
      auto [ec, sock] = co_await as_tuple(acceptor.accept());
      if (ec) {
          std::cout << "Error: " << ec.what() << std::endl;
      } else {
          std::cout << "Socket accepted\n";
      }
  
      co_return 0;
  }
  

Run that and try Ctrl-C while it is waiting for a connection: there is no response and the executable needs to be SIGKILLed (or connect to 55555 to make it exit).

I'm still trying to grok the cobalt internals and doco, so I am unsure if this is by design or if there is logic missing in op and/or composite_promise to support forwarding of the main promise's cancellation signal through to the op.

This inability to be cancelled also breaks the recommended timeout approach, eg:

auto result = co_await race(read(stream, buffer), timer.wait()); will not continue until the buffer is full, even if the timer expires first.

Is there a simple workaround I can use, or some other pattern I should be following?

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions