boostorg / boostorg/cobalt

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

Open
#270 0 comments 0 reactions 0 assignees View on GitHub
Dominant language
C++
Stars
347
Forks
47
Avg merge
3d 8h
Merged PRs (30d)
1

Description

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
#include
#include

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?

Contributor guide

No contributing guide indexed for this repository

Research direction

Start with the supplied co_main reproducer and trace cancellation through op and composite_promise while an accept, read, or write is suspended. Compare that path with race(read(stream, buffer), timer.wait()) and verify that Ctrl-C and an expired timer both let the operation return; done means the executable responds to the signal and the timeout race completes.

Written by the indexing model from the issue text.

Assessment

Tech stack
cpp
Domain
backend
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
42/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.