Uni20
Asynchronous tensor and runtime library.
Loading...
Searching...
No Matches
async_task_impl.hpp
Go to the documentation of this file.
1
6#pragma once
7
8namespace uni20::async
9{
10
12{
13 TRACE_MODULE(ASYNC, "BasicTask::reschedule", &task, task.coroutine_handle());
14 task = BasicTask::make_sole_owner(std::move(task));
15 if (task)
16 {
17 auto* scheduler = task.handle_.promise().scheduler();
18 DEBUG_CHECK(scheduler, "unexpected: task scheduler is not set!");
19 scheduler->reschedule(std::move(task));
20 }
21}
22
24{
25 DEBUG_CHECK(task.handle_);
26 auto& promise = task.handle_.promise();
27 if (promise.release_awaiter())
28 {
29 promise.add_awaiter();
30 }
31 else
32 {
33 task.handle_ = {};
34 }
35 return std::move(task);
36}
37
38inline bool BasicTask::can_destroy_coroutine(TaskHandle handle) const noexcept
39{
40 if (!handle) return true;
41 return handle.promise().is_cancel_on_resume() || handle.done();
42}
43
44inline TaskHandle BasicTask::release_ownership()
45{
46 CHECK(handle_);
47 CHECK(handle_.promise().release_awaiter(), "coroutine handle was not exclusively owned!");
48 return std::exchange(handle_, {});
49}
50
52{
53 TRACE_MODULE(ASYNC, "BasicTask::release_handle", this->coroutine_handle());
54 CHECK(handle_);
55 if (!handle_.promise().release_awaiter()) PANIC("Attempt to resume() a non-exclusive BasicTask");
56
57 bool const destroy_on_resume = handle_.promise().is_cancel_on_resume();
58 auto handle = std::exchange(handle_, {});
59
60 if (destroy_on_resume)
61 {
62 CHECK(this->can_destroy_coroutine(handle), "unexpected destruction of an active task without cancellation",
64 while (handle)
65 {
66 TRACE_MODULE(ASYNC, "Destroying task due to cancellation", handle.coroutine());
68 }
69 }
70 else
71 {
73 }
74 return handle;
75}
76
77inline void BasicTask::resume()
78{
79 auto handle = this->release_handle();
80 TRACE_MODULE(ASYNC, "Resuming task", handle.coroutine());
82}
83
85{
86 auto handle = this->release_handle();
88 TRACE_MODULE(ASYNC, "Abandoning task handle", handle.coroutine());
89}
90
91inline void BasicTask::set_cancel_on_resume() noexcept
92{
93 TRACE_MODULE(ASYNC, "Setting cancel flag on coroutine", this, this->coroutine_handle());
94 handle_.promise().set_cancel_on_resume();
95}
96
97inline void BasicTask::exception_on_resume(std::exception_ptr error) noexcept
98{
99 handle_.promise().set_exception(error);
100}
101
102inline BasicTask& BasicTask::operator=(BasicTask&& other) noexcept
103{
104 TRACE_MODULE(ASYNC, "BasicTask move assignment", this, this->coroutine_handle(), &other, other.coroutine_handle());
105 if (this != &other)
106 {
107 if (handle_ && handle_.promise().release_awaiter()) this->destroy_owned_coroutine();
108 handle_ = std::exchange(other.handle_, {});
109 await_exception_ = std::exchange(other.await_exception_, {});
110 }
111 return *this;
112}
113
114inline void BasicTask::destroy_owned_coroutine() noexcept
115{
116 auto handle = handle_;
117 CHECK(this->can_destroy_coroutine(handle), "unexpected destruction of an active task without cancellation", this,
118 handle.coroutine());
119 while (handle)
120 {
121 DEBUG_TRACE_MODULE(ASYNC, "BasicTask destructor is destroying the coroutine", this, handle.coroutine());
123 }
124 handle_ = {};
125}
126
127inline void BasicTask::release() noexcept
128{
129 TRACE_MODULE(ASYNC, "BasicTask::release", this, this->coroutine_handle());
130 if (handle_ && handle_.promise().release_awaiter()) this->destroy_owned_coroutine();
131}
132
133inline BasicTask::~BasicTask() noexcept { this->release(); }
134
135inline void BasicTask::destroy() noexcept
136{
137 CHECK(handle_);
138 CHECK(handle_.promise().release_awaiter(), "Attempt to destroy a non-exclusive BasicTask");
139 this->destroy_owned_coroutine();
140}
141
143{
144 if (!handle_) return false;
146 handle_.promise().sched_ = scheduler;
147 return true;
148}
149
150inline std::optional<int> BasicTask::preferred_numa_node() const noexcept
151{
152 if (!handle_) return std::nullopt;
153 return handle_.promise().preferred_numa_node();
154}
155
156inline void BasicTask::set_preferred_numa_node(std::optional<int> node) noexcept
157{
158 if (handle_) handle_.promise().set_preferred_numa_node(node);
159}
160
161template <TaskPromise ParentPromise>
162std::coroutine_handle<> BasicTask::await_suspend(std::coroutine_handle<ParentPromise> parent_handle)
163{
164 DEBUG_CHECK(handle_);
166
167 auto parent = TaskHandle::from(parent_handle);
169
171 handle_.promise().continuation_ = parent;
172 handle_.promise().continuation_exception_ = &await_exception_;
173
174 if (!TaskPromiseBase::can_transfer_directly(parent, handle_))
175 {
176 BasicTask::reschedule(std::move(*this));
177 return std::noop_coroutine();
178 }
179
180 handle_.promise().mark_started();
181 auto transfer = this->release_ownership();
183 return transfer.coroutine();
184}
185
187{
188 if (auto error = std::exchange(await_exception_, {})) std::rethrow_exception(error);
189 if (handle_) handle_.promise().rethrow_exception();
190}
191
192} // namespace uni20::async
Move-only promise-neutral ownership claim for a Uni20 coroutine.
Definition async_task.hpp:103
bool set_scheduler(IScheduler *scheduler)
Install the scheduler used for later resumption.
Definition async_task_impl.hpp:142
static void reschedule(BasicTask task)
Reschedule a task when it becomes the sole ownership claimant.
Definition async_task_impl.hpp:11
~BasicTask() noexcept
Release the ownership claim and destroy the frame when appropriate.
Definition async_task_impl.hpp:133
void await_resume()
Definition async_task_impl.hpp:186
std::coroutine_handle coroutine_handle() const noexcept
Return the generic coroutine handle for diagnostics.
Definition async_task.hpp:128
void abandon_leak()
Intentionally leak the coroutine during emergency unwinding.
Definition async_task_impl.hpp:84
void exception_on_resume(std::exception_ptr error) noexcept
Store an exception for delivery on the next resume.
Definition async_task_impl.hpp:97
void resume()
Resume the coroutine and transfer this ownership claim.
Definition async_task_impl.hpp:77
TaskHandle release_handle()
Release this ownership claim to a scheduler activation.
Definition async_task_impl.hpp:51
void set_preferred_numa_node(std::optional< int > node) noexcept
Definition async_task_impl.hpp:156
BasicTask & operator=(BasicTask const &)=delete
static BasicTask make_sole_owner(BasicTask &&task)
Retain a task only when it is the sole ownership claimant.
Definition async_task_impl.hpp:23
void destroy() noexcept
Destroy an exclusively owned coroutine.
Definition async_task_impl.hpp:135
TaskHandle handle() const noexcept
Return the erased task identity.
Definition async_task.hpp:125
void set_cancel_on_resume() noexcept
Request cancellation before the next resume.
Definition async_task_impl.hpp:91
std::optional< int > preferred_numa_node() const noexcept
Definition async_task_impl.hpp:150
std::coroutine_handle await_suspend(std::coroutine_handle< ParentPromise > parent)
Await a nested task from any Uni20 task promise type.
Definition async_task_impl.hpp:162
Internal route for resuming an already-bound coroutine task.
Definition scheduler.hpp:64
Non-owning erased identity for one Uni20 coroutine frame.
Definition async_task.hpp:59
constexpr std::coroutine_handle coroutine() const noexcept
Definition async_task.hpp:67
TaskPromiseBase & promise() const noexcept
Definition async_task_promise.hpp:998
static TaskHandle from(std::coroutine_handle< Promise > handle) noexcept
Definition async_task_promise.hpp:991
IScheduler * scheduler() const noexcept
Return the scheduler currently recorded for this task.
Definition async_task_promise.hpp:357
static void prepare_nested_route(TaskHandle parent, TaskHandle child)
Complete an unbound child's route before nested execution.
Definition async_task_promise.hpp:723
bool is_cancel_on_resume() const noexcept
Reports whether cancellation-on-resume is currently set.
Definition async_task_promise.hpp:302
static void note_running(TaskHandle handle) noexcept
Record that a coroutine has transitioned into a runnable/running state.
Definition async_task_promise.hpp:367
bool release_awaiter() noexcept
Decrease the number of active awaiters by one.
Definition async_task_promise.hpp:206
static bool can_transfer_directly(TaskHandle from, TaskHandle to) noexcept
Report whether symmetric transfer is valid for two prepared task routes.
Definition async_task_promise.hpp:746
void set_cancel_on_resume() noexcept
Mark the coroutine for cancellation at next resume.
Definition async_task_promise.hpp:298
void mark_started() noexcept
Mark the coroutine as having been scheduled to start executing.
Definition async_task_promise.hpp:351
TaskHandle destroy_with_continuation() noexcept
safely destroy this coroutine, returning the continuation_ (which also must now be destroyed)
Definition async_task_promise.hpp:188
std::exception_ptr * continuation_exception_
Destination for an exception returned by a directly awaited task.
Definition async_task_promise.hpp:122
static void validate_scheduler_route(IScheduler *scheduler, TaskRoute route)
Validate a prospective task route without changing promise state.
Definition async_task_promise.hpp:615
static void note_leaked(TaskHandle handle) noexcept
Record that a coroutine has been intentionally leaked.
Definition async_task_promise.hpp:397
static void note_suspended(TaskHandle handle) noexcept
Record that a coroutine has suspended and is waiting for resumption.
Definition async_task_promise.hpp:370
std::optional< int > preferred_numa_node() const noexcept
Retrieve the preferred NUMA node for this coroutine.
Definition async_task_promise.hpp:343
void rethrow_exception()
Throw the current exception, if there is one.
Definition async_task_promise.hpp:292
static void resume_and_track(TaskHandle handle)
Resume a coroutine handle while recording the running transition.
Definition async_task_promise.hpp:400
TaskHandle continuation_
Uni20 task coroutines are nestable.
Definition async_task_promise.hpp:117
cuda::ResourceLease< HandleSlot > handle
Definition cublas/execution.cpp:33
This represents the reverse-mode adjoint for functions of complex variables, assuming a real-valued s...
Definition async/async.hpp:26
TaskRoute task_route(TaskHandle handle) noexcept
Return the current scheduling requirements recorded by a task.
Definition async_task_promise.hpp:715
#define CHECK(cond,...)
Definition trace.hpp:299
#define DEBUG_CHECK(cond,...)
Definition trace.hpp:608
#define TRACE_MODULE(m,...)
Definition trace.hpp:149
#define DEBUG_TRACE_MODULE(m,...)
Definition trace.hpp:511
#define PANIC(...)
Definition trace.hpp:382