1 /*
2 * Copyright (c) 2024 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #ifndef META_API_TIMER_H
17 #define META_API_TIMER_H
18
19 #include <meta/api/deferred_callback.h>
20 #include <meta/api/make_callback.h>
21 #include <meta/api/threading/mutex.h>
22 #include <meta/interface/intf_task_queue.h>
23 #include <meta/interface/intf_task_queue_registry.h>
24
META_BEGIN_NAMESPACE()25 META_BEGIN_NAMESPACE()
26
27 /**
28 * @brief Helper class to launch timers, this type is not copyable, only movable. Destructor will stop the timer.
29 */
30 class Timer {
31 public:
32 /**
33 * @brief Type of the timer, single shot happens only once when as recurring keeps triggering after given timeout
34 */
35 enum TimerType { SINGLE_SHOT, RECURRING };
36
37 Timer() = default;
38 Timer(const Timer&) = delete;
39 Timer(Timer&& t) : control_(BASE_NS::move(t.control_)) {}
40 ~Timer()
41 {
42 Stop();
43 }
44
45 /**
46 * @brief Constructor that calls corresponding Start function (See Start below).
47 */
48 template<typename Func>
49 Timer(const TimeSpan& interval, Func func, TimerType type, const ITaskQueue::Ptr& queue)
50 {
51 Start(interval, BASE_NS::move(func), type, queue);
52 }
53
54 /**
55 * @brief Constructor that calls corresponding Start function (See Start below).
56 */
57 template<typename Func>
58 Timer(const TimeSpan& interval, Func func, TimerType type, const BASE_NS::Uid& queueId)
59 {
60 Start(interval, BASE_NS::move(func), type, queueId);
61 }
62
63 Timer& operator=(const Timer&) = delete;
64 Timer& operator=(Timer&& t)
65 {
66 Stop();
67 control_ = BASE_NS::move(t.control_);
68 return *this;
69 }
70
71 /**
72 * @brief Start timer.
73 * @param interval Time interval which after this timer triggers.
74 * @param func Callable entity (e.g. lambda) which is called.
75 * @param type Type of the timer.
76 * @param queue Queue to which the timer task is posted to (this dictates on what thread the func is called).
77 */
78 template<typename Func>
79 bool Start(const TimeSpan& interval, Func func, TimerType type, const ITaskQueue::Ptr& queue)
80 {
81 if (!queue) {
82 return false;
83 }
84 Stop();
85 control_ = CreateShared<Control>();
86 control_->queue = queue;
87 control_->token =
88 queue->AddTask(MakeCallback<ITaskQueueTask>([control = control_, type, callback = BASE_NS::move(func)] {
89 callback();
90 bool ret = type == RECURRING;
91 if (!ret) {
92 if (control) {
93 CORE_NS::UniqueLock lock { control->mutex };
94 control->token = {};
95 }
96 }
97 return ret;
98 }),
99 interval);
100 return true;
101 }
102
103 /**
104 * @brief Start timer.
105 * @param interval Time interval which after this timer triggers.
106 * @param func Callable entity (e.g. lambda) which is called.
107 * @param type Type of the timer.
108 * @param queueId Uid of queue to which the timer task is posted to (this dictates on what thread the func is
109 * called).
110 */
111 template<typename Func>
112 bool Start(const TimeSpan& interval, Func func, TimerType type, const BASE_NS::Uid& queueId)
113 {
114 return Start(interval, BASE_NS::move(func), type, GetTaskQueueRegistry().GetTaskQueue(queueId));
115 }
116
117 /**
118 * @brief Stop timer
119 */
120 void Stop()
121 {
122 if (control_) {
123 CORE_NS::UniqueLock lock { control_->mutex };
124 if (control_->queue && control_->token) {
125 control_->queue->CancelTask(control_->token);
126 }
127 }
128 control_.reset();
129 }
130
131 /**
132 * @brief Detach timer, this can be used if you don't want destructor to stop the timer
133 */
134 ITaskQueue::Token Detach()
135 {
136 ITaskQueue::Token ret {};
137 if (control_) {
138 CORE_NS::UniqueLock lock { control_->mutex };
139 ret = control_->token;
140 }
141 control_.reset();
142 return ret;
143 }
144
145 /**
146 * @brief Returns true if the timer is currently running
147 */
148 bool IsRunning() const
149 {
150 if (control_) {
151 CORE_NS::UniqueLock lock { control_->mutex };
152 return control_->token != ITaskQueue::Token {};
153 }
154 return false;
155 }
156
157 private:
158 struct Control {
159 mutable CORE_NS::Mutex mutex;
160 ITaskQueue::Ptr queue;
161 ITaskQueue::Token token {};
162 };
163 BASE_NS::shared_ptr<Control> control_;
164 };
165
166 /**
167 * @brief Start single shot timer, returns the token that can be used to cancel it (which can be just ignored).
168 * @param interval Time interval which after this timer triggers.
169 * @param func Callable entity (e.g. lambda) which is called.
170 * @param queue Queue to which the timer task is posted to (this dictates on what thread the func is called).
171 */
172 template<typename Func>
SingleShotTimer(const TimeSpan & interval,Func func,const ITaskQueue::Ptr & queue)173 inline ITaskQueue::Token SingleShotTimer(const TimeSpan& interval, Func func, const ITaskQueue::Ptr& queue)
174 {
175 Timer t;
176 t.Start(interval, BASE_NS::move(func), Timer::SINGLE_SHOT, queue);
177 return t.Detach();
178 }
179
180 /**
181 * @brief Start single shot timer, returns the token that can be used to cancel it (which can be just ignored).
182 * @param interval Time interval which after this timer triggers.
183 * @param func Callable entity (e.g. lambda) which is called.
184 * @param queueId Uid of queue to which the timer task is posted to (this dictates on what thread the func is called).
185 */
186 template<typename Func>
SingleShotTimer(const TimeSpan & interval,Func func,const BASE_NS::Uid & queueId)187 inline ITaskQueue::Token SingleShotTimer(const TimeSpan& interval, Func func, const BASE_NS::Uid& queueId)
188 {
189 Timer t;
190 t.Start(interval, BASE_NS::move(func), Timer::SINGLE_SHOT, queueId);
191 return t.Detach();
192 }
193
194 META_END_NAMESPACE()
195
196 #endif
197