| 65 | |
| 66 | STDEXEC_ATTRIBUTE(host, device) |
| 67 | void finish() noexcept |
| 68 | { |
| 69 | // Increment our task count to avoid lifetime issues. This is preventing |
| 70 | // a use-after-free issue if finish is called from a different thread. |
| 71 | // We increment the task counter by two to prevent the run loop from |
| 72 | // exiting before we schedule the noop task. |
| 73 | __task_count_.fetch_add(2, __std::memory_order_release); |
| 74 | if (!__finishing_.exchange(true, __std::memory_order_acq_rel)) |
| 75 | { |
| 76 | // push an empty work item to the queue to wake up the consuming thread |
| 77 | // and let it finish. |
| 78 | // The count will be decremented once the tasks executes. |
| 79 | __queue_.push(&__noop_task); |
| 80 | // If the task got pushed, simply subtract one again, the other decrement |
| 81 | // happens when the noop task got executed. |
| 82 | __task_count_.fetch_sub(1, __std::memory_order_release); |
| 83 | return; |
| 84 | } |
| 85 | // We are done finishing. Decrement the count by two, which signals final completion. |
| 86 | __task_count_.fetch_sub(2, __std::memory_order_release); |
| 87 | } |
| 88 | |
| 89 | struct __task |
| 90 | { |
no test coverage detected