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