Bug: should_originate_on_cancel does not cancel certain awaiters or duplicated actions.

未关闭
#1,617 0 条评论 0 个 reaction 已指派 0 人 在 GitHub 查看

还没有人认领这个 Issue。

评估

难度
4/5
预计耗时
3-5 天
新手友好度
48/100
Issue 类型
缺陷
描述清晰度
基本清楚
活跃度
冷清
技术栈
cpp

调研方向

跟踪通过 impl::check_status_canceled、await_adapter::await_resume、timespan_awaiter::await_resume 和 signal_awaiter::await_resume 进行的取消处理。验证重复取消不会恢复 originate-on-cancel 设置,并且 resume_after 和 resume_on_signal 会遵循 originate_on_cancel(false);为重复的 awaiter 场景和列出的 awaiter 场景添加或更新覆盖。

由索引模型根据 Issue 内容生成。

描述

Version

3.0.260715.1

Summary
  1. #1512 introduced the setter originate_on_cancel and getter should_originate_on_cancel. The await_resume task would call originate_on_cancel (the setter) to check whether to RoOriginate the call. This is a bug, because the setter has a side effect. Its parameter defaults to true, so each call does std::exchange(m_originate_on_cancel, true): it returns the previous value, so the first check behaved correctly, and then wrote the flag back to true. Every later cancellation on that same promise originated again. A test that cancels only once passes even with the bug present.

IAsyncAction DoWork(HANDLE ready)
{
auto cancel = co_await get_cancellation_token();
cancel.originate_on_cancel(false); // "don't debug spew when I'm cancelled"

co_await resume_on_signal(ready);    // If cancelled before `ready`, doesn't originate.
                                     // The first Cancel() consumes the opt-out, re-arms the flag
co_await CleanupAsync();             // If cancelled after, then the next co_await will 
                                     // call Cancel() again, and since should_originate is true now
                                     // it will Originate, thus causing the debug spew.

}
In addition, there is a missing scenario in the previous PR, it did not account for winrt::resume_after, winrt::resume_on_signal, and
These three awaiter resume paths also threw hresult_canceled unconditionally, so originate_on_cancel(false) had no effect on them at all: impl::check_status_canceled (reached from await_adapter::await_resume for any coroutine awaiting a WinRT async that completes Canceled), timespan_awaiter::await_resume (resume_after) and signal_awaiter::await_resume (resume_on_signal).

Reproducible example
IAsyncAction PollStatusAsync()
{
    auto cancel = co_await get_cancellation_token();
    cancel.enable_propagation();
    cancel.originate_on_cancel(false);

    while (true)
    {
        co_await RefreshAsync();
        co_await resume_after(30s);   // cancelled here -> timespan_awaiter::await_resume
    }                                 //    throws hresult_canceled() -> originates
}
Expected behavior

No response

Actual behavior

No response

Additional comments

No response

主要语言
C++
星标
1.9k
派生
281
PR 合并指标
30 天内没有已合并 PR

贡献指南

打开贡献指南

从这里开始

  1. 先读完整个 Issue,再读项目的贡献指南。
  2. 在 Issue 下留言说明你要接手 —— 这能避免两个人做同样的事。
  3. Fork 仓库,在一个分支上完成修改。
  4. 提交 Pull Request,并在描述里引用这个 Issue 编号。

microsoft/cppwinrt 的其他 Issue

查看 microsoft/cppwinrt 的全部 Issue

相似的 Issue

更多 C++ Issue

把新 issue 发到你的邮箱

精选适合新手参与的 GitHub issue 摘要。