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>
9
10#include <boost/smart_ptr/intrusive_ptr.hpp>
11
12#include <userver/engine/deadline.hpp>
13#include <userver/engine/exception.hpp>
14#include <userver/engine/task/cancel.hpp>
15#include <userver/engine/task/task_processor_fwd.hpp>
16
17USERVER_NAMESPACE_BEGIN
18
19namespace utils::impl {
20class WrappedCallBase;
21} // namespace utils::impl
22
23namespace engine {
24namespace ev {
25class ThreadControl;
26} // namespace ev
27namespace impl {
28class TaskContextHolder;
29class TaskContext;
30class DetachedTasksSyncBlock;
31class ContextAccessor;
32} // namespace impl
33
34/// @brief Base class for all the asynchronous tasks
35/// (engine::Task, engine::SharedTask, engine::SharedTaskWithResult,
36/// engine::TaskWithResult, dist_lock::DistLockedTask, ...).
37class [[nodiscard]] TaskBase {
38 public:
39 /// Task importance
40 enum class Importance {
41 /// Normal task
42 kNormal,
43
44 /// Critical task. The task will be started regardless of cancellations,
45 /// e.g. due to user request, deadline or TaskProcessor overload. After the
46 /// task starts, it may be cancelled. In particular, if it received any
47 /// cancellation requests before starting, then it will start as cancelled.
49 };
50
51 /// Task state
52 enum class State {
53 kInvalid, ///< Unusable
54 kNew, ///< just created, not registered with task processor
55 kQueued, ///< awaits execution
56 kRunning, ///< executing user code
57 kSuspended, ///< suspended, e.g. waiting for blocking call to complete
58 kCancelled, ///< exited user code because of external request
59 kCompleted, ///< exited user code with return or throw
60 };
61
62 /// Task wait mode
63 enum class WaitMode {
64 /// Can be awaited by at most one task at a time
66 /// Can be awaited by multiple tasks simultaneously
68 };
69
70 /// @brief Checks whether this object owns
71 /// an actual task (not `State::kInvalid`)
72 ///
73 /// An invalid task cannot be used. The task becomes invalid
74 /// after each of the following calls:
75 ///
76 /// 1. the default constructor
77 /// 2. `Detach()`
78 /// 3. `Get()` (see `engine::TaskWithResult`)
79 bool IsValid() const;
80
81 /// Gets the task State
82 State GetState() const;
83
84 static const std::string& GetStateName(State state);
85
86 /// Returns whether the task finished execution
87 bool IsFinished() const;
88
89 /// @brief Suspends execution until the task finishes or caller is cancelled.
90 /// Can be called from coroutine context only. For non-coroutine context use
91 /// BlockingWait().
92 /// @throws WaitInterruptedException when `current_task::IsCancelRequested()`
93 /// and no TaskCancellationBlockers are present.
94 void Wait() const noexcept(false);
95
96 /// @brief Suspends execution until the task finishes or after the specified
97 /// timeout or until caller is cancelled
98 /// @throws WaitInterruptedException when `current_task::IsCancelRequested()`
99 /// and no TaskCancellationBlockers are present.
100 template <typename Rep, typename Period>
101 void WaitFor(const std::chrono::duration<Rep, Period>&) const noexcept(false);
102
103 /// @brief Suspends execution until the task finishes or until the specified
104 /// time point is reached or until caller is cancelled
105 /// @throws WaitInterruptedException when `current_task::IsCancelRequested()`
106 /// and no TaskCancellationBlockers are present.
107 template <typename Clock, typename Duration>
108 void WaitUntil(const std::chrono::time_point<Clock, Duration>&) const
109 noexcept(false);
110
111 /// @brief Suspends execution until the task finishes or until the specified
112 /// deadline is reached or until caller is cancelled
113 /// @throws WaitInterruptedException when `current_task::IsCancelRequested()`
114 /// and no TaskCancellationBlockers are present.
115 void WaitUntil(Deadline) const;
116
117 /// Queues task cancellation request
119
120 /// @brief Cancels the task and suspends execution until it is finished.
121 /// Can be called from coroutine context only. For non-coroutine context use
122 /// RequestCancel() + BlockingWait().
123 void SyncCancel() noexcept;
124
125 /// Gets task cancellation reason
127
128 /// Waits for the task in non-coroutine context
129 /// (e.g. non-TaskProcessor's std::thread).
130 void BlockingWait() const;
131
132 protected:
133 /// @cond
134 // For internal use only.
135 TaskBase();
136
137 // For internal use only.
138 explicit TaskBase(impl::TaskContextHolder&& context);
139
140 // The following special functions must remain protected to forbid slicing
141 // and force those methods implementation in derived classes.
142 TaskBase(TaskBase&&) noexcept;
143 TaskBase& operator=(TaskBase&&) noexcept;
144 TaskBase(const TaskBase&) noexcept;
145 TaskBase& operator=(const TaskBase&) noexcept;
146 ~TaskBase();
147
148 // For internal use only.
149 impl::TaskContext& GetContext() const noexcept;
150
151 // For internal use only.
152 bool HasSameContext(const TaskBase& other) const noexcept;
153
154 // For internal use only.
155 utils::impl::WrappedCallBase& GetPayload() const noexcept;
156
157 // Marks task as invalid. For internal use only.
158 void Invalidate() noexcept;
159
160 void Terminate(TaskCancellationReason) noexcept;
161 /// @endcond
162
163 private:
164 friend class impl::DetachedTasksSyncBlock;
165 friend class TaskCancellationToken;
166
167 boost::intrusive_ptr<impl::TaskContext> context_;
168};
169
170/// @brief Namespace with functions to work with current task from within it
171namespace current_task {
172
173/// Returns true only when running in userver coroutine environment,
174/// i.e. in an engine::TaskProcessor thread.
175bool IsTaskProcessorThread() noexcept;
176
177/// Returns reference to the task processor executing the caller
178TaskProcessor& GetTaskProcessor();
179
180/// Returns task coroutine stack size
181std::size_t GetStackSize();
182
183/// @cond
184// Returns ev thread handle, internal use only
185ev::ThreadControl& GetEventThread();
186/// @endcond
187
188} // namespace current_task
189
190template <typename Rep, typename Period>
191void TaskBase::WaitFor(const std::chrono::duration<Rep, Period>& duration) const
192 noexcept(false) {
193 WaitUntil(Deadline::FromDuration(duration));
194}
195
196template <typename Clock, typename Duration>
197void TaskBase::WaitUntil(const std::chrono::time_point<Clock, Duration>& until)
198 const noexcept(false) {
199 WaitUntil(Deadline::FromTimePoint(until));
200}
201
202} // namespace engine
203
204USERVER_NAMESPACE_END