userver: userver/engine/task/task_base.hpp Source File
Loading...
Searching...
No Matches
task_base.hpp
Go to the documentation of this file.
1#pragma once
2
3/// @file userver/engine/task/task_base.hpp
4/// @brief @copybrief engine::TaskBase
5
6#include <chrono>
7#include <cstdint>
8#include <memory>
9#include <string_view>
10
11#include <userver/engine/deadline.hpp>
12#include <userver/engine/future_status.hpp>
13#include <userver/engine/task/cancel.hpp>
14#include <userver/engine/task/current_task.hpp>
15#include <userver/utils/fast_pimpl.hpp>
16
17USERVER_NAMESPACE_BEGIN
18
19namespace utils::impl {
20class WrappedCallBase;
21} // namespace utils::impl
22
23namespace engine {
24namespace impl {
25class TaskContextHolder;
26class TaskContext;
27class TaskContextAccessor;
28class AwaitableBase;
29} // namespace impl
30
31/// @brief Base class for all the asynchronous tasks
32/// (engine::Task, engine::SharedTask, engine::SharedTaskWithResult,
33/// engine::TaskWithResult, dist_lock::DistLockedTask, ...).
34class [[nodiscard]] TaskBase {
35public:
36 /// Task importance
37 enum class Importance {
38 /// Normal task
40
41 /// Critical task. The task will be started regardless of cancellations,
42 /// e.g. due to user request, deadline or TaskProcessor overload. After the
43 /// task starts, it may be cancelled. In particular, if it received any
44 /// cancellation requests before starting, then it will start as cancelled.
46 };
47
48 /// Task state
49 enum class State : std::uint8_t {
50 kInvalid, ///< Unusable
51 kNew, ///< just created, not registered with task processor
52 kQueued, ///< awaits execution
53 kRunning, ///< executing user code
54 kSuspended, ///< suspended, e.g. waiting for blocking call to complete
55
56 /// The task is cancelled and was finished without returning a value or throwing a user-provided exception.
57 ///
58 /// This can happen for two reasons:
59 ///
60 /// 1. When a non-critical task (see @ref Importance::kCritical, see @ref flavors_of_async) is cancelled before
61 /// it starts running, the task functor is skipped, only destructor is executed. This can be interpreted
62 /// as every non-critical task having an implicit cancellation point at its start.
63 /// See more details and examples in @ref task_cancellation_before_start.
64 ///
65 /// 2. When a task is cancelled because of a call to @ref engine::current_task::CancellationPoint.
66 /// This cancellation is implemented using a non-`std::exception`-based exception.
67 ///
68 /// In both cases, @ref engine::TaskWithResult::Get throws @ref engine::TaskCancelledException.
69 ///
70 /// Unintuitively, this status is not set when the task was cancelled after it started running,
71 /// which caused the user code to exit early.
72 ///
73 /// Use @ref TaskBase::CancellationReason instead to check whether the task was cancelled.
75
76 /// Exited user code with return or throw.
77 ///
78 /// This includes cases where the task was cancelled after it started running,
79 /// which caused the user code to exit early.
80 ///
81 /// Use @ref TaskBase::IsFinished instead to check whether the task finished execution.
83 };
84
85 /// Task wait mode
86 enum class WaitMode {
87 /// Can be awaited by at most one task at a time
89 /// Can be awaited by multiple tasks simultaneously
91 };
92
93 /// @brief Checks whether this object owns an actual task (not @ref State::kInvalid)
94 ///
95 /// An invalid task cannot be used. The task becomes invalid after each of the following calls:
96 ///
97 /// 1. the default constructor
98 /// 2. moving from this task object
99 /// 3. @ref engine::TaskWithResult::Get
100 /// 4. @ref concurrent::BackgroundTaskStorageCore::Detach
101 /// 5. @ref engine::DetachUnscopedUnsafe
102 ///
103 /// Notably, the task does *not* become invalid immediately after it finishes execution.
104 /// (That would always cause race conditions when trying to await a task.)
105 /// It means that some of the task's resources are held onto until the task object is invalidated or destroyed.
106 bool IsValid() const;
107
108 /// Gets the task State
110
111 static std::string_view GetStateName(State state);
112
113 /// Returns whether the task finished execution
114 bool IsFinished() const;
115
116 /// @brief Suspends execution until the task finishes or caller is cancelled.
117 /// Can be called from coroutine context only. For non-coroutine context use
118 /// BlockingWait().
119 /// @throws WaitInterruptedException when `current_task::IsCancelRequested()`
120 /// and no TaskCancellationBlockers are present.
121 void Wait() const noexcept(false);
122
123 /// @brief Suspends execution until the task finishes or after the specified
124 /// timeout or until caller is cancelled
125 /// @throws WaitInterruptedException when `current_task::IsCancelRequested()`
126 /// and no TaskCancellationBlockers are present.
127 template <typename Rep, typename Period>
128 void WaitFor(const std::chrono::duration<Rep, Period>&) const noexcept(false);
129
130 /// @brief Suspends execution until the task finishes or until the specified
131 /// time point is reached or until caller is cancelled
132 /// @throws WaitInterruptedException when `current_task::IsCancelRequested()`
133 /// and no TaskCancellationBlockers are present.
134 template <typename Clock, typename Duration>
135 void WaitUntil(const std::chrono::time_point<Clock, Duration>&) const noexcept(false);
136
137 /// @brief Suspends execution until the task finishes or until the specified
138 /// deadline is reached or until caller is cancelled
139 /// @throws WaitInterruptedException when `current_task::IsCancelRequested()`
140 /// and no TaskCancellationBlockers are present.
141 void WaitUntil(Deadline) const;
142
143 /// @brief Suspends execution until the task finishes or caller is cancelled.
144 /// Can be called from coroutine context only. For non-coroutine context use
145 /// BlockingWait().
146 /// @returns `false` when `current_task::IsCancelRequested()`
147 /// and no TaskCancellationBlockers are present.
148 [[nodiscard]] bool WaitNothrow() const noexcept;
149
150 /// @brief Suspends execution until the task finishes or until the specified
151 /// deadline is reached or until caller is cancelled
152 /// @returns FutureStatus::kCancelled when `current_task::IsCancelRequested()`
153 /// and no TaskCancellationBlockers are present.
154 [[nodiscard]] FutureStatus WaitNothrowUntil(Deadline) const noexcept;
155
156 /// Queues task cancellation request
158
159 /// @brief Cancels the task and suspends execution until it is finished.
160 /// Can be called from coroutine context only. For non-coroutine context use
161 /// RequestCancel() + BlockingWait().
162 void SyncCancel() noexcept;
163
164 /// Gets task cancellation reason
166
167 /// Waits for the task in non-coroutine context
168 /// (e.g. non-TaskProcessor's std::thread).
169 void BlockingWait() const noexcept;
170
171protected:
172 /// @cond
173 // For internal use only.
174 TaskBase();
175
176 // For internal use only.
177 explicit TaskBase(impl::TaskContextHolder&& context);
178
179 // The following special functions must remain protected to forbid slicing
180 // and force those methods implementation in derived classes.
181 TaskBase(TaskBase&&) noexcept;
182 TaskBase& operator=(TaskBase&&) noexcept;
183 TaskBase(const TaskBase&) noexcept;
184 TaskBase& operator=(const TaskBase&) noexcept;
185 ~TaskBase();
186
187 // For internal use only.
188 impl::TaskContext& GetContext() const noexcept;
189
190 // For internal use only.
191 bool HasSameContext(const TaskBase& other) const noexcept;
192
193 // For internal use only.
194 utils::impl::WrappedCallBase& GetPayload() const noexcept;
195
196 // Marks task as invalid. For internal use only.
197 void Invalidate() noexcept;
198
199 void Terminate(TaskCancellationReason) noexcept;
200 /// @endcond
201
202private:
203 friend class impl::TaskContextAccessor;
204
205 struct Impl;
206 utils::FastPimpl<Impl, 8, 8> pimpl_;
207};
208
209template <typename Rep, typename Period>
210void TaskBase::WaitFor(const std::chrono::duration<Rep, Period>& duration) const noexcept(false) {
211 WaitUntil(Deadline::FromDuration(duration));
212}
213
214template <typename Clock, typename Duration>
215void TaskBase::WaitUntil(const std::chrono::time_point<Clock, Duration>& until) const noexcept(false) {
216 WaitUntil(Deadline::FromTimePoint(until));
217}
218
219} // namespace engine
220
221USERVER_NAMESPACE_END