C++ Logo

std-proposals

Advanced search

Re: [std-proposals] Specify behavior of coroutine_handle::destroy

From: Marcin Jaczewski <marcinjaczewski86_at_[hidden]>
Date: Wed, 21 Feb 2024 11:12:11 +0100
(btw please reply to std-proposals too)

śr., 21 lut 2024 o 10:50 Nikl Kelbon <kelbonage_at_[hidden]> napisał(a):
>
> > Would this overhead be pushed simply to the coroutine frame?
> > Same flag but outside our control
>
> As i understand - no, pseudocode for this is like
> frame.suspend_point = -1;
> promise.~promise();
>
> order of '= -1' and calling destructor is not specified
>

Ok, right.

> > Could you show the full code that "should" work after the proposed change.
>
> Same as i wrote, creating handle in destructor and checking if it done, then, in my case, i will skip destroyed leaf of async generator, so it will not destroyed twice
> https://github.com/kelbon/kelcoro

Ok, I miss that you ask for un-UB `from_promise(*this)` in destructor too.
But then, aside from `done()` what do you need this handle there?
Was not leaf generators stored in promise?
And if its true and you need to support old compilers you need use
`bool flag` anyway.
Probably only DR against C++20 would help you there.


>
> ср, 21 февр. 2024 г. в 13:38, Marcin Jaczewski <marcinjaczewski86_at_[hidden]>:
>>
>> śr., 21 lut 2024 o 10:22 Nikl Kelbon <kelbonage_at_[hidden]> napisał(a):
>> >
>> > it is overhead, obviously. And creating handle in destructor still undefined behavior
>> >
>>
>> Would this overhead be pushed simply to the coroutine frame?
>> Same flag but outside our control.
>> Another, what "creating handle"? I only add `bool flag` and check it
>> in the same place where you check `done()`.
>> Did I miss something from your example?
>> Could you show the full code that "should" work after the proposed change.
>>
>>
>> > ср, 21 февр. 2024 г. в 13:20, Marcin Jaczewski <marcinjaczewski86_at_[hidden]>:
>> >>
>> >> śr., 21 lut 2024 o 09:58 Nikl Kelbon via Std-Proposals
>> >> <std-proposals_at_[hidden]> napisał(a):
>> >> >
>> >> > I will start with use-case:
>> >> >
>> >> > Let we have recursive generator (C++23 have one...), imagine we call .destroy on handle of one leaf of generator, then, top-level generator destroyed, in dctor it calls .destroy, etc etc until last leaf destroyed, but it has been already destroyed, undefined behavior.
>> >> >
>> >> > What can implementation do?
>> >> > Important note, we cannot just forbid this operation, in my particular use case thread pool when destroyed calls .destroy on handles, because it is only good way to not leak memory (coroutines suspended and waiting for execution, thread pool destroyed, so they will just leak => thread poll calls .destroy)
>> >> >
>> >> > PROBLEM:
>> >> >
>> >> > How coroutine frame can detect, that .destroy called and coroutine is not just ended?
>> >> > What .destroy do underspecified or i dont find this in standard
>> >> >
>> >> > Good way - detect it in 'promise' destructor. If final_suspend was not invoked and we are in promise::destructor, then, must be, .destroy on handle invoked
>> >> >
>> >> > But now there are no good way to do it
>> >> >
>> >> > https://godbolt.org/z/7qzn6zG9x
>> >> >
>> >> > PROPOSAL:
>> >> > change wording so, that creating handle from promise in promise::destructor is valid and specify, that .done() returns true if await_suspend was called and false if not
>> >> >
>> >>
>> >> Why not add a custom flag in the promise? like:
>> >> https://godbolt.org/z/fohMoveKr
>> >>
>> >> ```
>> >>
>> >> struct job_promise {
>> >> bool flag = false;
>> >> constexpr std::suspend_never initial_suspend() noexcept {
>> >> return {};
>> >> }
>> >> constexpr std::suspend_never final_suspend() noexcept {
>> >> flag = true;
>> >> return {};
>> >> }
>> >> ~job_promise() {
>> >> std::cout << flag << "\n";
>> >> std::cout << std::coroutine_handle<job_promise>::from_promise(*this).done();
>> >> }
>> >> job get_return_object() noexcept {
>> >> return job{std::coroutine_handle<job_promise>::from_promise(*this)};
>> >> }
>> >> static constexpr void return_void() noexcept {
>> >> }
>> >> static void unhandled_exception() noexcept {
>> >> ;
>> >> }
>> >> };
>> >>
>> >> ```
>> >> Both compilers return `1` for the first output line.
>> >>
>> >> >
>> >> > --
>> >> > Std-Proposals mailing list
>> >> > Std-Proposals_at_[hidden]
>> >> > https://lists.isocpp.org/mailman/listinfo.cgi/std-proposals

Received on 2024-02-21 10:12:30