Date: Wed, 21 Feb 2024 10:38:15 +0100
ś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
>
> 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 09:38:27