diff options
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.h | 315 |
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 | |||
| 17 | namespace kodi | ||
| 18 | { | ||
| 19 | namespace 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 | ///@{ | ||
| 58 | class CTimer : protected CThread | ||
| 59 | { | ||
| 60 | public: | ||
| 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 | |||
| 272 | protected: | ||
| 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 | |||
| 302 | private: | ||
| 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 */ | ||
