summaryrefslogtreecommitdiff
path: root/src/components/include/utils/timer_thread.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/components/include/utils/timer_thread.h')
-rw-r--r--src/components/include/utils/timer_thread.h484
1 files changed, 276 insertions, 208 deletions
diff --git a/src/components/include/utils/timer_thread.h b/src/components/include/utils/timer_thread.h
index a3481e4b4..4236c4e46 100644
--- a/src/components/include/utils/timer_thread.h
+++ b/src/components/include/utils/timer_thread.h
@@ -1,5 +1,5 @@
-/**
- * Copyright (c) 2013, Ford Motor Company
+/*
+ * Copyright (c) 2015, Ford Motor Company
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -28,15 +28,16 @@
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
-*/
+ */
-#ifndef SRC_COMPONENTS_UTILS_INCLUDE_UTILS_TIMER_THREAD
-#define SRC_COMPONENTS_UTILS_INCLUDE_UTILS_TIMER_THREAD
+#ifndef SRC_COMPONENTS_INCLUDE_UTILS_TIMER_THREAD_H_
+#define SRC_COMPONENTS_INCLUDE_UTILS_TIMER_THREAD_H_
#include <time.h>
#include <inttypes.h>
#include <cstdint>
#include <limits>
+#include <string>
#include "utils/conditional_variable.h"
#include "utils/lock.h"
@@ -52,8 +53,9 @@ CREATE_LOGGERPTR_GLOBAL(logger_, "Utils")
class TimerDelegate;
-/*
- * The TimerThread class provide possibility to run timer in a separate thread.
+/**
+ * \class TimerThread
+ * \brief TimerThread class provide possibility to run timer in a separate thread.
* The client should specify callee and const callback function.
* Example usage:
*
@@ -67,315 +69,381 @@ class TimerDelegate;
* To stop timer call timer.stop();
*
*/
-template <class T>
+template<class T>
class TimerThread {
- public:
-
- friend class TimerDelegate;
- friend class TimerLooperDelegate;
-
+ public:
+ friend class TimerDelegate;
+ friend class TimerLooperDelegate;
+
+ /**
+ * @brief Default constructor
+ *
+ * @param name - display string to identify the thread.
+ * @param callee A class that use timer
+ * @param f CallBackFunction which will be called on timeout
+ * Attention! "f()" will be called not in main thread but in timer thread
+ * Never use stop() and start() methods inside f
+ * @param is_looper Define this timer as looper,
+ * if true, TimerThread will call "f()" function every time out
+ * until stop()
+ */
+ TimerThread(const char* name, T* callee, void (T::*f)(), bool is_looper =
+ false);
+
+ /**
+ * @brief Destructor
+ */
+ virtual ~TimerThread();
+
+ /**
+ * @brief Starts timer for specified timeout.
+ * Previously started timeout will be set to new value.
+ * On timeout TimerThread::onTimeOut interface will be called.
+ * Must not be used in callback function!
+ *
+ * @param timeout_seconds Timeout in seconds to be set
+ */
+ virtual void start(uint32_t timeout_seconds);
+
+ /**
+ * @brief Starts timer for specified timeout.
+ * Previously started timeout will be set to new value.
+ * On timeout TimerThread::onTimeOut interface will be called.
+ * Must not be used in callback function!
+ *
+ * @param timeout_seconds Timeout in seconds to be set
+ *
+ * @param callee A class that use timer
+ *
+ * @param allBackFunction which will be called on timeout
+ * Attention! "f()" will be called not in main thread but in timer thread
+ * Never use stop() and start() methods inside f
+ */
+ virtual void start(uint32_t timeout_seconds, T* callee, void (T::*f)());
+
+ /**
+ * @brief Stops timer execution
+ * Must not be used in callback function!
+ */
+ virtual void stop();
+
+ /**
+ * @brief Tell timer status
+ * @return true if timer is currently running, otherwise return false
+ */
+ virtual bool isRunning();
+
+ /**
+ * @brief Suspends timer execution after next loop.
+ */
+ virtual void suspend();
+
+ /**
+ * @brief Stop timer update timeout and start timer again
+ * Note that it cancel thread of timer, If you use it from callback,
+ * it probably will stop execution of callback function
+ * @param timeout_seconds new timeout value
+ *
+ */
+ virtual void updateTimeOut(const uint32_t timeout_seconds);
+
+ protected:
+ /**
+ * @brief Interface called by delegator on timeout
+ */
+ void onTimeOut() const;
+
+ private:
+ /**
+ * @brief Delegate release timer, will call callback function one time
+ */
+ class TimerDelegate : public threads::ThreadDelegate {
+ public:
/**
* @brief Default constructor
*
- * @param name - display string to identify the thread.
- * @param callee A class that use timer
- * @param f CallBackFunction which will be called on timeout
- * Attention! "f()" will be called not in main thread but in timer thread
- * Never use stop() and start() methods inside f
- * @param is_looper Define this timer as looper,
- * if true, TimerThread will call "f()" function every time out
- * until stop()
+ * @param timer_thread The Timer_thread pointer
*/
- TimerThread(const char* name, T* callee , void (T::*f)(), bool is_looper = false);
+ explicit TimerDelegate(TimerThread* timer_thread);
/**
* @brief Destructor
*/
- virtual ~TimerThread();
+ virtual ~TimerDelegate();
/**
- * @brief Starts timer for specified timeout.
- * Previously started timeout will be set to new value.
- * On timeout TimerThread::onTimeOut interface will be called.
- * Must not be used in callback function!
- *
- * @param timeout_seconds Timeout in seconds to be set
+ * @brief Thread main function.
*/
- virtual void start(uint32_t timeout_seconds);
+ virtual void threadMain();
/**
- * @brief Stops timer execution
- * Must not be used in callback function!
+ * @brief Called by thread::thread to free all allocated resources.
*/
- virtual void stop();
+ virtual void exitThreadMain();
/**
- * @brief Tell tmer status
- * @return true if timer is currently running, otherwise return false
+ * @brief Set new Timeout
+ * @param timeout_seconds New timeout to be set
*/
- virtual bool isRunning();
+ virtual void setTimeOut(const uint32_t timeout_seconds);
- /*
- * @brief Stop timer update timeout and start timer again
- * Note that it cancel thread of timer, If you use it from callback,
- * it probably will stop execution of callback function
- * @param timeout_seconds new timeout value
- *
+ /**
+ * @brief Quits threadMain function after next loop.
*/
- virtual void updateTimeOut(const uint32_t timeout_seconds);
- threads::Thread* thread_;
- protected:
+ virtual void shouldBeStoped();
/**
- * @brief Interface called by delegator on timeout
+ * @brief Restarts non-loop timer after current iteration.
*/
- void onTimeOut() const;
-
- private:
-
+ virtual void shouldBeRestarted();
+
+ protected:
+ TimerThread* timer_thread_;
+ uint32_t timeout_seconds_;
+ sync_primitives::Lock state_lock_;
+ sync_primitives::ConditionalVariable termination_condition_;
+ volatile bool stop_flag_;
+ sync_primitives::Lock restart_flag_lock_;
+ volatile bool restart_flag_;
+ int32_t calculateMillisecondsLeft();
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(TimerDelegate);
+ };
+
+ /**
+ * @brief Delegate release looper timer.
+ * Will call delegate every timeout function while stop()
+ * won't be called
+ */
+ class TimerLooperDelegate : public TimerDelegate {
+ public:
/**
- * @brief Delegate release timer, will call callback function one time
+ * @brief Default constructor
+ *
+ * @param timer_thread The Timer_thread pointer
+ * @param timeout Timeout to be set
*/
- class TimerDelegate : public threads::ThreadDelegate {
- public:
-
- /**
- * @brief Default constructor
- *
- * @param timer_thread The Timer_thread pointer
- */
- TimerDelegate(TimerThread* timer_thread);
-
- /**
- * @brief Destructor
- */
- virtual ~TimerDelegate();
-
- /**
- * @brief Thread main function.
- */
- virtual void threadMain();
-
- /**
- * @brief Called by thread::thread to free all allocated resources.
- */
- virtual bool exitThreadMain();
-
- /**
- * @brief Set new Timeout
- * @param timeout_seconds New timeout to be set
- */
- virtual void setTimeOut(const uint32_t timeout_seconds);
-
- protected:
- TimerThread* timer_thread_;
- uint32_t timeout_seconds_;
- sync_primitives::Lock state_lock_;
- sync_primitives::ConditionalVariable termination_condition_;
- volatile bool stop_flag_;
- int32_t calculateMillisecondsLeft();
- private:
- DISALLOW_COPY_AND_ASSIGN(TimerDelegate);
- };
-
+ explicit TimerLooperDelegate(TimerThread* timer_thread);
/**
- * @brief Delegate release looper timer.
- * Will call delegate every timeout function while stop()
- * won't be called
+ * @brief Thread main function.
*/
- class TimerLooperDelegate : public TimerDelegate {
- public:
-
- /**
- * @brief Default constructor
- *
- * @param timer_thread The Timer_thread pointer
- * @param timeout Timeout to be set
- */
- TimerLooperDelegate(TimerThread* timer_thread);
-
- /**
- * @brief Thread main function.
- */
- virtual void threadMain();
- private:
- DISALLOW_COPY_AND_ASSIGN(TimerLooperDelegate);
- };
- void (T::*callback_)();
- T* callee_;
- TimerDelegate* delegate_;
- //threads::Thread* thread_;
- std::string name_;
- mutable bool is_running_;
- bool is_looper_;
-
- DISALLOW_COPY_AND_ASSIGN(TimerThread);
+ virtual void threadMain();
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(TimerLooperDelegate);
+ };
+ threads::Thread* thread_;
+ void (T::*callback_)();
+ T* callee_;
+ TimerDelegate* delegate_;
+ std::string name_;
+ volatile bool is_looper_;
+
+ DISALLOW_COPY_AND_ASSIGN(TimerThread);
};
-template <class T>
-TimerThread<T>::TimerThread(const char* name, T* callee, void (T::*f)(), bool is_looper)
- : thread_(NULL),
- callback_(f),
- callee_(callee),
- delegate_(NULL),
- is_running_(false),
- is_looper_(is_looper) {
+template<class T>
+TimerThread<T>::TimerThread(const char* name, T* callee, void (T::*f)(),
+ bool is_looper)
+ : thread_(NULL),
+ callback_(f),
+ callee_(callee),
+ delegate_(NULL),
+ name_(name),
+ is_looper_(is_looper) {
+ delegate_ =
+ is_looper_ ? new TimerLooperDelegate(this) : new TimerDelegate(this);
+
+ thread_ = threads::CreateThread(name_.c_str(), delegate_);
}
-template <class T>
+template<class T>
TimerThread<T>::~TimerThread() {
- LOG4CXX_INFO(logger_, "TimerThread is to destroy " << name_);
- stop();
+ LOG4CXX_DEBUG(logger_, "TimerThread is to be destroyed " << name_);
+ thread_->join();
+ delete delegate_;
+ threads::DeleteThread(thread_);
callback_ = NULL;
callee_ = NULL;
}
-template <class T>
+template<class T>
void TimerThread<T>::start(uint32_t timeout_seconds) {
- LOG4CXX_TRACE(logger_, "Starting timer " << this);
- if (is_running_) {
- LOG4CXX_INFO(logger_, "TimerThread start needs stop " << name_);
- stop();
- }
-
- delegate_ = is_looper_ ?
- new TimerLooperDelegate(this) :
- new TimerDelegate(this);
- delegate_->setTimeOut(timeout_seconds);
-
- thread_ = threads::CreateThread("TimerThread", delegate_);
- if (delegate_ && thread_) {
- is_running_ = true;
+ LOG4CXX_AUTO_TRACE(logger_);
+ if (isRunning()) {
+ LOG4CXX_INFO(logger_, "Restart timer in thread " << name_);
+ delegate_->shouldBeRestarted();
+ updateTimeOut(timeout_seconds);
+ } else {
+ updateTimeOut(timeout_seconds);
thread_->start();
}
}
-template <class T>
+template<class T>
+void TimerThread<T>::start(uint32_t timeout_seconds, T* callee,
+ void (T::*f)()) {
+ callee_ = callee;
+ callback_ = f;
+ start(timeout_seconds);
+}
+
+template<class T>
void TimerThread<T>::stop() {
- LOG4CXX_TRACE(logger_, "Stopping timer " << this);
- if (is_running_ && delegate_ && thread_) {
- LOG4CXX_INFO(logger_, "TimerThread thread_ stop " << name_);
- thread_->stop();
- is_running_ = false;
- } else {
- LOG4CXX_INFO(logger_, "TimerThread thread_ not stop " << name_);
- }
+ LOG4CXX_AUTO_TRACE(logger_);
+ DCHECK(thread_);
+ LOG4CXX_DEBUG(logger_, "Stopping timer " << name_);
+ thread_->join();
}
-template <class T>
+template<class T>
bool TimerThread<T>::isRunning() {
- return is_running_;
+ DCHECK(thread_);
+ return thread_->is_running();
}
-template <class T>
+template<class T>
+void TimerThread<T>::suspend() {
+ LOG4CXX_DEBUG(logger_, "Suspend timer " << name_ << " after next loop");
+ delegate_->shouldBeStoped();
+}
+
+template<class T>
void TimerThread<T>::updateTimeOut(const uint32_t timeout_seconds) {
delegate_->setTimeOut(timeout_seconds);
}
-template <class T>
-void TimerThread<T>::onTimeOut() const {
+template<class T> void TimerThread<T>::onTimeOut() const {
if (callee_ && callback_) {
(callee_->*callback_)();
- /*
- if (!is_looper_) {
- stop();
- }
- */
}
}
-template <class T>
+template<class T>
TimerThread<T>::TimerDelegate::TimerDelegate(TimerThread* timer_thread)
- : timer_thread_(timer_thread),
- timeout_seconds_(0),
- state_lock_(true),
- stop_flag_(false) {
+ : timer_thread_(timer_thread),
+ timeout_seconds_(0),
+ state_lock_(true),
+ stop_flag_(false),
+ restart_flag_(false) {
DCHECK(timer_thread_);
}
-template <class T>
-TimerThread<T>::TimerLooperDelegate::TimerLooperDelegate(TimerThread* timer_thread)
- : TimerDelegate(timer_thread) {
+template<class T>
+TimerThread<T>::TimerLooperDelegate::TimerLooperDelegate(
+ TimerThread* timer_thread)
+ : TimerDelegate(timer_thread) {
}
-template <class T>
+template<class T>
TimerThread<T>::TimerDelegate::~TimerDelegate() {
timer_thread_ = NULL;
}
-template <class T>
+template<class T>
void TimerThread<T>::TimerDelegate::threadMain() {
using sync_primitives::ConditionalVariable;
sync_primitives::AutoLock auto_lock(state_lock_);
+ stop_flag_ = false;
while (!stop_flag_) {
// Sleep
- int32_t wait_milliseconds_left = TimerDelegate::calculateMillisecondsLeft();
+ int32_t wait_milliseconds_left = TimerDelegate::calculateMillisecondsLeft();
ConditionalVariable::WaitStatus wait_status =
termination_condition_.WaitFor(auto_lock, wait_milliseconds_left);
// Quit sleeping or continue sleeping in case of spurious wake up
- if (ConditionalVariable::kTimeout == wait_status ||
- wait_milliseconds_left <= 0) {
- break;
+ if (ConditionalVariable::kTimeout == wait_status
+ || wait_milliseconds_left <= 0) {
+ LOG4CXX_TRACE(logger_,
+ "Timer timeout " << wait_milliseconds_left << " ms");
+ timer_thread_->onTimeOut();
+ } else {
+ LOG4CXX_DEBUG(logger_,
+ "Timeout reset force: " << TimerDelegate::timeout_seconds_);
+ }
+ {
+ sync_primitives::AutoLock auto_lock(restart_flag_lock_);
+ if (!restart_flag_) {
+ return;
+ }
+ restart_flag_ = false;
}
- }
- if (!stop_flag_) {
- timer_thread_->onTimeOut();
- timer_thread_->stop();
}
}
-template <class T>
+template<class T>
void TimerThread<T>::TimerLooperDelegate::threadMain() {
using sync_primitives::ConditionalVariable;
sync_primitives::AutoLock auto_lock(TimerDelegate::state_lock_);
+ TimerDelegate::stop_flag_ = false;
while (!TimerDelegate::stop_flag_) {
- int32_t wait_milliseconds_left = TimerDelegate::calculateMillisecondsLeft();
+ int32_t wait_milliseconds_left = TimerDelegate::calculateMillisecondsLeft();
ConditionalVariable::WaitStatus wait_status =
- TimerDelegate::termination_condition_.WaitFor(auto_lock, wait_milliseconds_left);
+ TimerDelegate::termination_condition_.WaitFor(auto_lock,
+ wait_milliseconds_left);
// Quit sleeping or continue sleeping in case of spurious wake up
- if (ConditionalVariable::kTimeout == wait_status ||
- wait_milliseconds_left <= 0) {
- LOG4CXX_TRACE(logger_, "Timer timeout " << wait_milliseconds_left);
+ if (ConditionalVariable::kTimeout == wait_status
+ || wait_milliseconds_left <= 0) {
+ LOG4CXX_TRACE(logger_,
+ "Timer timeout " << wait_milliseconds_left << " ms");
TimerDelegate::timer_thread_->onTimeOut();
} else {
- LOG4CXX_DEBUG(logger_, "Timeout reset force: " << TimerDelegate::timeout_seconds_);
+ LOG4CXX_DEBUG(logger_,
+ "Timeout reset force: " << TimerDelegate::timeout_seconds_);
}
}
}
-
-template <class T>
-bool TimerThread<T>::TimerDelegate::exitThreadMain() {
- sync_primitives::AutoLock auto_lock(state_lock_);
- stop_flag_ = true;
+template<class T>
+void TimerThread<T>::TimerDelegate::exitThreadMain() {
+ shouldBeStoped();
termination_condition_.NotifyOne();
- return true;
}
-template <class T>
+template<class T>
void TimerThread<T>::TimerDelegate::setTimeOut(const uint32_t timeout_seconds) {
timeout_seconds_ = timeout_seconds;
termination_condition_.NotifyOne();
}
-template <class T>
+template<class T>
+void TimerThread<T>::TimerDelegate::shouldBeStoped() {
+ {
+ sync_primitives::AutoLock auto_lock(state_lock_);
+ stop_flag_ = true;
+ }
+ {
+ sync_primitives::AutoLock auto_lock(restart_flag_lock_);
+ restart_flag_ = false;
+ }
+}
+
+template<class T>
+void TimerThread<T>::TimerDelegate::shouldBeRestarted() {
+ sync_primitives::AutoLock auto_lock(restart_flag_lock_);
+ restart_flag_ = true;
+}
+
+template<class T>
int32_t TimerThread<T>::TimerThread::TimerDelegate::calculateMillisecondsLeft() {
time_t cur_time = time(NULL);
time_t end_time = std::numeric_limits<time_t>::max();
- if (TimerDelegate::timeout_seconds_ + cur_time > TimerDelegate::timeout_seconds_) { // no overflow occurred
+ if (TimerDelegate::timeout_seconds_ + cur_time
+ > TimerDelegate::timeout_seconds_) { // no overflow occurred
end_time = cur_time + TimerDelegate::timeout_seconds_;
}
- int64_t wait_seconds_left = static_cast<int64_t>(difftime(end_time, cur_time));
- int32_t wait_milliseconds_left = std::numeric_limits<int32_t>::max();
- const int32_t millisecconds_in_second = 1000;
- if (wait_seconds_left < std::numeric_limits<int32_t>::max() / millisecconds_in_second) {
- wait_milliseconds_left = millisecconds_in_second * wait_seconds_left;
+ int64_t wait_seconds_left = static_cast<int64_t>(difftime(end_time, cur_time));
+ int32_t wait_milliseconds_left = std::numeric_limits<int32_t>::max();
+ const int32_t milliseconds_in_second = 1000;
+ if (wait_seconds_left
+ < std::numeric_limits<int32_t>::max() / milliseconds_in_second) {
+ wait_milliseconds_left = milliseconds_in_second * wait_seconds_left;
}
return wait_milliseconds_left;
}
} // namespace timer
-#endif // SRC_COMPONENTS_UTILS_INCLUDE_UTILS_TIMER_THREAD
+#endif // SRC_COMPONENTS_INCLUDE_UTILS_TIMER_THREAD_H_