From be933ef2241d79558f91796cc5b3a161f72ebf9c Mon Sep 17 00:00:00 2001 From: manuel Date: Mon, 19 Oct 2020 00:52:24 +0200 Subject: sync with upstream --- .../addons/kodi-dev-kit/include/kodi/tools/Timer.h | 315 +++++++++++++++++++++ 1 file changed, 315 insertions(+) create mode 100644 xbmc/addons/kodi-dev-kit/include/kodi/tools/Timer.h (limited to 'xbmc/addons/kodi-dev-kit/include/kodi/tools/Timer.h') 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 @@ +/* + * Copyright (C) 2005-2020 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +#ifdef __cplusplus + +#include "Thread.h" + +#include + +namespace kodi +{ +namespace tools +{ + +//============================================================================== +/// @defgroup cpp_kodi_tools_CTimer class CTimer +/// @ingroup cpp_kodi_tools +/// @brief **Time interval management**\n +/// Class which enables a time interval to be called up by a given function or +/// class by means of a thread. +/// +/// His code uses the support of platform-independent thread system introduced +/// with C++11. +/// +/// +/// ---------------------------------------------------------------------------- +/// +/// **Example:** +/// ~~~~~~~~~~~~~{.cpp} +/// #include +/// +/// class ATTRIBUTE_HIDDEN CExample +/// { +/// public: +/// CExample() : m_timer([this](){TimerCall();}) +/// { +/// m_timer.Start(5000, true); // let call continuously all 5 seconds +/// } +/// +/// void TimerCall() +/// { +/// fprintf(stderr, "Hello World\n"); +/// } +/// +/// private: +/// kodi::tools::CTimer m_timer; +/// }; +/// ~~~~~~~~~~~~~ +/// +///@{ +class CTimer : protected CThread +{ +public: + class ITimerCallback; + + //============================================================================ + /// @ingroup cpp_kodi_tools_CTimer + /// @brief Class constructor to pass individual other class as callback. + /// + /// @param[in] callback Child class of parent @ref ITimerCallback with + /// implemented function @ref ITimerCallback::OnTimeout(). + /// + explicit CTimer(kodi::tools::CTimer::ITimerCallback* callback) + : CTimer(std::bind(&ITimerCallback::OnTimeout, callback)) + { + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @ingroup cpp_kodi_tools_CTimer + /// @brief Class constructor to pass individual function as callback. + /// + /// @param[in] callback Function to pass as callback about timeout. + /// + /// **Callback function style:** + /// ~~~~~~~~~~~~~{.cpp} + /// void TimerCallback() + /// { + /// } + /// ~~~~~~~~~~~~~ + explicit CTimer(std::function const& callback) : m_callback(callback) {} + //---------------------------------------------------------------------------- + + //============================================================================ + /// @ingroup cpp_kodi_tools_CTimer + /// @brief Class destructor. + /// + ~CTimer() override { Stop(true); } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @ingroup cpp_kodi_tools_CTimer + /// @brief Start the timer by given time in milliseconds to make his call + /// by arrive of them. + /// + /// If interval is activated, it calls the associated callback function + /// continuously in the given interval. + /// + /// @param[in] timeout Timeout in milliseconds + /// @param[in] interval [opt] To run continuously if true, false only one time + /// and default + /// @return True if successfully done, false if not (callback missing, + /// timeout = 0 or was already running. + /// + bool Start(uint64_t timeout, bool interval = false) + { + using namespace std::chrono; + + if (m_callback == nullptr || timeout == 0 || IsRunning()) + return false; + + m_timeout = milliseconds(timeout); + m_interval = interval; + + CreateThread(); + return true; + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @ingroup cpp_kodi_tools_CTimer + /// @brief Stop the timer if it is active. + /// + /// @param[in] wait [opt] Wait until timer is stopped, false is default and + /// call unblocked + /// @return True if timer was active and was stopped, false if already was + /// stopped. + /// + bool Stop(bool wait = false) + { + if (!IsRunning()) + return false; + + m_threadStop = true; + m_eventTimeout.notify_all(); + StopThread(wait); + + return true; + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @ingroup cpp_kodi_tools_CTimer + /// @brief Restart timer complete by stop and restart his thread again. + /// + /// @note Restart only possible as long the timer was running and not done his + /// work. + /// + /// @return True if start was successfully done, on error, or if was already + /// finished returned as false + /// + bool Restart() + { + using namespace std::chrono; + + if (!IsRunning()) + return false; + + Stop(true); + return Start(duration_cast(m_timeout).count(), m_interval); + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @ingroup cpp_kodi_tools_CTimer + /// @brief Restart the timer with new timeout without touch of his thread. + /// + /// @param[in] timeout Time as milliseconds to wait for next call + /// + void RestartAsync(uint64_t timeout) + { + using namespace std::chrono; + + m_timeout = milliseconds(timeout); + const auto now = system_clock::now(); + m_endTime = now.time_since_epoch() + m_timeout; + m_eventTimeout.notify_all(); + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @ingroup cpp_kodi_tools_CTimer + /// @brief Check timer is still active to wait for next call. + /// + /// @return True if active, false if all his work done and no more running + /// + bool IsRunning() const { return CThread::IsRunning(); } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @ingroup cpp_kodi_tools_CTimer + /// @brief Get elapsed time as floating point of timer as seconds. + /// + /// @return Elapsed time + /// + float GetElapsedSeconds() const { return GetElapsedMilliseconds() / 1000.0f; } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @ingroup cpp_kodi_tools_CTimer + /// @brief Get elapsed time as floating point of timer as milliseconds. + /// + /// @return Elapsed time + /// + float GetElapsedMilliseconds() const + { + using namespace std::chrono; + + if (!IsRunning()) + return 0.0f; + + const auto now = system_clock::now(); + return static_cast(duration_cast(now.time_since_epoch() - (m_endTime - m_timeout)).count()); + } + //---------------------------------------------------------------------------- + + //============================================================================ + /// @defgroup cpp_kodi_tools_CTimer_CB class ITimerCallback + /// @ingroup cpp_kodi_tools_CTimer + /// @brief **Callback class of timer**\n + /// To give on contructor by @ref CTimer(kodi::tools::CTimer::ITimerCallback* callback) + /// + class ITimerCallback + { + public: + //========================================================================== + /// @ingroup cpp_kodi_tools_CTimer_CB + /// @brief Class destructor. + /// + virtual ~ITimerCallback() = default; + //-------------------------------------------------------------------------- + + //========================================================================== + /// @ingroup cpp_kodi_tools_CTimer_CB + /// @brief Callback function to implement if constuctor @ref CTimer(kodi::tools::CTimer::ITimerCallback* callback) + /// is used and this as parent on related class + /// + /// ---------------------------------------------------------------------------- + /// + /// **Example:** + /// ~~~~~~~~~~~~~{.cpp} + /// #include + /// + /// class CExample : public kodi::tools::CTimer, + /// private kodi::tools::CTimer::ITimerCallback + /// { + /// public: + /// CExample() : kodi::tools::CTimer(this) + /// { + /// } + /// + /// void OnTimeout() override + /// { + /// // Some work + /// } + /// }; + /// + /// ~~~~~~~~~~~~~ + /// + virtual void OnTimeout() = 0; + //-------------------------------------------------------------------------- + }; + //---------------------------------------------------------------------------- + +protected: + void Process() override + { + using namespace std::chrono; + + while (!m_threadStop) + { + auto currentTime = system_clock::now(); + m_endTime = currentTime.time_since_epoch() + m_timeout; + + // wait the necessary time + std::mutex mutex; + std::unique_lock lock(mutex); + const auto waitTime = duration_cast(m_endTime - currentTime.time_since_epoch()); + if (m_eventTimeout.wait_for(lock, waitTime) == std::cv_status::timeout) + { + currentTime = system_clock::now(); + if (m_endTime.count() <= currentTime.time_since_epoch().count()) + { + // execute OnTimeout() callback + m_callback(); + + // continue if this is an interval timer, or if it was restarted during callback + if (!m_interval && m_endTime.count() <= currentTime.time_since_epoch().count()) + break; + } + } + } + } + +private: + bool m_interval = false; + std::function m_callback; + std::chrono::system_clock::duration m_timeout; + std::chrono::system_clock::duration m_endTime; + std::condition_variable_any m_eventTimeout; +}; +///@} +//------------------------------------------------------------------------------ + +} /* namespace tools */ +} /* namespace kodi */ + +#endif /* __cplusplus */ -- cgit v1.2.3