summaryrefslogtreecommitdiffstats
path: root/xbmc/addons/kodi-dev-kit/include/kodi/tools/Timer.h
diff options
context:
space:
mode:
Diffstat (limited to 'xbmc/addons/kodi-dev-kit/include/kodi/tools/Timer.h')
-rw-r--r--xbmc/addons/kodi-dev-kit/include/kodi/tools/Timer.h315
1 files changed, 315 insertions, 0 deletions
diff --git a/xbmc/addons/kodi-dev-kit/include/kodi/tools/Timer.h b/xbmc/addons/kodi-dev-kit/include/kodi/tools/Timer.h
new file mode 100644
index 0000000..0e0ced7
--- /dev/null
+++ b/xbmc/addons/kodi-dev-kit/include/kodi/tools/Timer.h
@@ -0,0 +1,315 @@
1/*
2 * Copyright (C) 2005-2020 Team Kodi
3 * This file is part of Kodi - https://kodi.tv
4 *
5 * SPDX-License-Identifier: GPL-2.0-or-later
6 * See LICENSES/README.md for more information.
7 */
8
9#pragma once
10
11#ifdef __cplusplus
12
13#include "Thread.h"
14
15#include <functional>
16
17namespace kodi
18{
19namespace tools
20{
21
22//==============================================================================
23/// @defgroup cpp_kodi_tools_CTimer class CTimer
24/// @ingroup cpp_kodi_tools
25/// @brief **Time interval management**\n
26/// Class which enables a time interval to be called up by a given function or
27/// class by means of a thread.
28///
29/// His code uses the support of platform-independent thread system introduced
30/// with C++11.
31///
32///
33/// ----------------------------------------------------------------------------
34///
35/// **Example:**
36/// ~~~~~~~~~~~~~{.cpp}
37/// #include <kodi/tools/Timer.h>
38///
39/// class ATTRIBUTE_HIDDEN CExample
40/// {
41/// public:
42/// CExample() : m_timer([this](){TimerCall();})
43/// {
44/// m_timer.Start(5000, true); // let call continuously all 5 seconds
45/// }
46///
47/// void TimerCall()
48/// {
49/// fprintf(stderr, "Hello World\n");
50/// }
51///
52/// private:
53/// kodi::tools::CTimer m_timer;
54/// };
55/// ~~~~~~~~~~~~~
56///
57///@{
58class CTimer : protected CThread
59{
60public:
61 class ITimerCallback;
62
63 //============================================================================
64 /// @ingroup cpp_kodi_tools_CTimer
65 /// @brief Class constructor to pass individual other class as callback.
66 ///
67 /// @param[in] callback Child class of parent @ref ITimerCallback with
68 /// implemented function @ref ITimerCallback::OnTimeout().
69 ///
70 explicit CTimer(kodi::tools::CTimer::ITimerCallback* callback)
71 : CTimer(std::bind(&ITimerCallback::OnTimeout, callback))
72 {
73 }
74 //----------------------------------------------------------------------------
75
76 //============================================================================
77 /// @ingroup cpp_kodi_tools_CTimer
78 /// @brief Class constructor to pass individual function as callback.
79 ///
80 /// @param[in] callback Function to pass as callback about timeout.
81 ///
82 /// **Callback function style:**
83 /// ~~~~~~~~~~~~~{.cpp}
84 /// void TimerCallback()
85 /// {
86 /// }
87 /// ~~~~~~~~~~~~~
88 explicit CTimer(std::function<void()> const& callback) : m_callback(callback) {}
89 //----------------------------------------------------------------------------
90
91 //============================================================================
92 /// @ingroup cpp_kodi_tools_CTimer
93 /// @brief Class destructor.
94 ///
95 ~CTimer() override { Stop(true); }
96 //----------------------------------------------------------------------------
97
98 //============================================================================
99 /// @ingroup cpp_kodi_tools_CTimer
100 /// @brief Start the timer by given time in milliseconds to make his call
101 /// by arrive of them.
102 ///
103 /// If interval is activated, it calls the associated callback function
104 /// continuously in the given interval.
105 ///
106 /// @param[in] timeout Timeout in milliseconds
107 /// @param[in] interval [opt] To run continuously if true, false only one time
108 /// and default
109 /// @return True if successfully done, false if not (callback missing,
110 /// timeout = 0 or was already running.
111 ///
112 bool Start(uint64_t timeout, bool interval = false)
113 {
114 using namespace std::chrono;
115
116 if (m_callback == nullptr || timeout == 0 || IsRunning())
117 return false;
118
119 m_timeout = milliseconds(timeout);
120 m_interval = interval;
121
122 CreateThread();
123 return true;
124 }
125 //----------------------------------------------------------------------------
126
127 //============================================================================
128 /// @ingroup cpp_kodi_tools_CTimer
129 /// @brief Stop the timer if it is active.
130 ///
131 /// @param[in] wait [opt] Wait until timer is stopped, false is default and
132 /// call unblocked
133 /// @return True if timer was active and was stopped, false if already was
134 /// stopped.
135 ///
136 bool Stop(bool wait = false)
137 {
138 if (!IsRunning())
139 return false;
140
141 m_threadStop = true;
142 m_eventTimeout.notify_all();
143 StopThread(wait);
144
145 return true;
146 }
147 //----------------------------------------------------------------------------
148
149 //============================================================================
150 /// @ingroup cpp_kodi_tools_CTimer
151 /// @brief Restart timer complete by stop and restart his thread again.
152 ///
153 /// @note Restart only possible as long the timer was running and not done his
154 /// work.
155 ///
156 /// @return True if start was successfully done, on error, or if was already
157 /// finished returned as false
158 ///
159 bool Restart()
160 {
161 using namespace std::chrono;
162
163 if (!IsRunning())
164 return false;
165
166 Stop(true);
167 return Start(duration_cast<milliseconds>(m_timeout).count(), m_interval);
168 }
169 //----------------------------------------------------------------------------
170
171 //============================================================================
172 /// @ingroup cpp_kodi_tools_CTimer
173 /// @brief Restart the timer with new timeout without touch of his thread.
174 ///
175 /// @param[in] timeout Time as milliseconds to wait for next call
176 ///
177 void RestartAsync(uint64_t timeout)
178 {
179 using namespace std::chrono;
180
181 m_timeout = milliseconds(timeout);
182 const auto now = system_clock::now();
183 m_endTime = now.time_since_epoch() + m_timeout;
184 m_eventTimeout.notify_all();
185 }
186 //----------------------------------------------------------------------------
187
188 //============================================================================
189 /// @ingroup cpp_kodi_tools_CTimer
190 /// @brief Check timer is still active to wait for next call.
191 ///
192 /// @return True if active, false if all his work done and no more running
193 ///
194 bool IsRunning() const { return CThread::IsRunning(); }
195 //----------------------------------------------------------------------------
196
197 //============================================================================
198 /// @ingroup cpp_kodi_tools_CTimer
199 /// @brief Get elapsed time as floating point of timer as seconds.
200 ///
201 /// @return Elapsed time
202 ///
203 float GetElapsedSeconds() const { return GetElapsedMilliseconds() / 1000.0f; }
204 //----------------------------------------------------------------------------
205
206 //============================================================================
207 /// @ingroup cpp_kodi_tools_CTimer
208 /// @brief Get elapsed time as floating point of timer as milliseconds.
209 ///
210 /// @return Elapsed time
211 ///
212 float GetElapsedMilliseconds() const
213 {
214 using namespace std::chrono;
215
216 if (!IsRunning())
217 return 0.0f;
218
219 const auto now = system_clock::now();
220 return static_cast<float>(duration_cast<milliseconds>(now.time_since_epoch() - (m_endTime - m_timeout)).count());
221 }
222 //----------------------------------------------------------------------------
223
224 //============================================================================
225 /// @defgroup cpp_kodi_tools_CTimer_CB class ITimerCallback
226 /// @ingroup cpp_kodi_tools_CTimer
227 /// @brief **Callback class of timer**\n
228 /// To give on contructor by @ref CTimer(kodi::tools::CTimer::ITimerCallback* callback)
229 ///
230 class ITimerCallback
231 {
232 public:
233 //==========================================================================
234 /// @ingroup cpp_kodi_tools_CTimer_CB
235 /// @brief Class destructor.
236 ///
237 virtual ~ITimerCallback() = default;
238 //--------------------------------------------------------------------------
239
240 //==========================================================================
241 /// @ingroup cpp_kodi_tools_CTimer_CB
242 /// @brief Callback function to implement if constuctor @ref CTimer(kodi::tools::CTimer::ITimerCallback* callback)
243 /// is used and this as parent on related class
244 ///
245 /// ----------------------------------------------------------------------------
246 ///
247 /// **Example:**
248 /// ~~~~~~~~~~~~~{.cpp}
249 /// #include <kodi/tools/Timer.h>
250 ///
251 /// class CExample : public kodi::tools::CTimer,
252 /// private kodi::tools::CTimer::ITimerCallback
253 /// {
254 /// public:
255 /// CExample() : kodi::tools::CTimer(this)
256 /// {
257 /// }
258 ///
259 /// void OnTimeout() override
260 /// {
261 /// // Some work
262 /// }
263 /// };
264 ///
265 /// ~~~~~~~~~~~~~
266 ///
267 virtual void OnTimeout() = 0;
268 //--------------------------------------------------------------------------
269 };
270 //----------------------------------------------------------------------------
271
272protected:
273 void Process() override
274 {
275 using namespace std::chrono;
276
277 while (!m_threadStop)
278 {
279 auto currentTime = system_clock::now();
280 m_endTime = currentTime.time_since_epoch() + m_timeout;
281
282 // wait the necessary time
283 std::mutex mutex;
284 std::unique_lock<std::mutex> lock(mutex);
285 const auto waitTime = duration_cast<milliseconds>(m_endTime - currentTime.time_since_epoch());
286 if (m_eventTimeout.wait_for(lock, waitTime) == std::cv_status::timeout)
287 {
288 currentTime = system_clock::now();
289 if (m_endTime.count() <= currentTime.time_since_epoch().count())
290 {
291 // execute OnTimeout() callback
292 m_callback();
293
294 // continue if this is an interval timer, or if it was restarted during callback
295 if (!m_interval && m_endTime.count() <= currentTime.time_since_epoch().count())
296 break;
297 }
298 }
299 }
300 }
301
302private:
303 bool m_interval = false;
304 std::function<void()> m_callback;
305 std::chrono::system_clock::duration m_timeout;
306 std::chrono::system_clock::duration m_endTime;
307 std::condition_variable_any m_eventTimeout;
308};
309///@}
310//------------------------------------------------------------------------------
311
312} /* namespace tools */
313} /* namespace kodi */
314
315#endif /* __cplusplus */